diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..53fe1d7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,38 @@ +# Logs +logs +*.log +npm-debug.log* + +# Runtime data +pids +*.pid +*.seed + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage + +# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (http://nodejs.org/api/addons.html) +build/Release + +# Dependency directory +node_modules + +# Optional npm cache directory +.npm + +# Optional REPL history +.node_repl_history + +example/test.html + +.vscode +package-lock.json diff --git a/.jshintrc b/.jshintrc new file mode 100644 index 0000000..fd01957 --- /dev/null +++ b/.jshintrc @@ -0,0 +1,25 @@ +{ + "sub":true, + "laxbreak":true, + "laxcomma":true, + "regexp":true, + "asi": true, + "browser": true, + "loopfunc":true, + "expr":true, + "es3": true, + "esnext": true, + "curly": true, + "immed": true, + "latedef": false, + "expr": true, + "eqeqeq": false, + "eqnull": false, + "newcap": true, + "noarg": true, + "undef": true, + "unused": true, + "proto": true, + "strict": false, + "smarttabs": true +} diff --git a/LICENSE.md b/LICENSE.md index 5a1390e..70a0e7b 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2008-2015 http://hprose.com +Copyright (c) 2008-2018 http://hprose.com Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in diff --git a/README.md b/README.md index e9e101e..2eb9986 100644 --- a/README.md +++ b/README.md @@ -1,20 +1,21 @@ +

Hprose

+ - Promises/A+ logo - - - + Promises/A+ logo + # Hprose for HTML5 [![Join the chat at https://gitter.im/hprose/hprose-html5](https://img.shields.io/badge/GITTER-join%20chat-green.svg)](https://gitter.im/hprose/hprose-html5?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![bower version](https://img.shields.io/bower/v/hprose-html5.svg)](http://bower.io/search/?q=hprose-html5) +[![npm version](https://img.shields.io/npm/v/hprose-html5.svg)](https://www.npmjs.com/package/hprose-html5) [![GitHub release](https://img.shields.io/github/release/hprose/hprose-html5.svg)](https://github.com/hprose/hprose-html5/releases) [![License](https://img.shields.io/github/license/hprose/hprose-html5.svg)](http://opensource.org/licenses/MIT) >--- - **[Introduction](#introduction)** - **[Browser support](#browser-support)** + - **[Hybird app support](#hybird-app-support)** - **[Usage](#usage)** - **[Exception Handling](#exception-handling)** @@ -70,6 +71,17 @@ This project is the implementation of Hprose for HTML5. * Internet Explorer on Windows Phone * ... +### Hybird app support + +* ionic + cordova (http, tcp, websocket) +* Chrome extentions (http, tcp, websocket) +* APICloud (http, tcp*) +* DCloud (http) +* AppCan (http) +* ... (http, websocket) + +TCP is only available on iOS for APICloud, because there is a bug of APICloud Android SDK, and they don't want to fix this bug. + ## Usage You don't need use the javascript source files. You only need include `hprose-html5.js` in your html. diff --git a/README_zh_CN.md b/README_zh_CN.md index 9aafdde..7b5497b 100644 --- a/README_zh_CN.md +++ b/README_zh_CN.md @@ -1,21 +1,21 @@ +

Hprose

+ - Promises/A+ logo - - - + Promises/A+ logo # Hprose for HTML5 [![Join the chat at https://gitter.im/hprose/hprose-html5](https://img.shields.io/badge/GITTER-join%20chat-green.svg)](https://gitter.im/hprose/hprose-html5?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![bower version](https://img.shields.io/bower/v/hprose-html5.svg)](http://bower.io/search/?q=hprose-html5) +[![npm version](https://img.shields.io/npm/v/hprose-html5.svg)](https://www.npmjs.com/package/hprose-html5) [![GitHub release](https://img.shields.io/github/release/hprose/hprose-html5.svg)](https://github.com/hprose/hprose-html5/releases) [![License](https://img.shields.io/github/license/hprose/hprose-html5.svg)](http://opensource.org/licenses/MIT) >--- - **[简介](#简介)** - **[浏览器支持](#浏览器支持)** + - **[混合应用支持](#混合应用支持)** - **[使用](#使用)** - **[异常处理](#异常处理)** @@ -71,6 +71,17 @@ * Internet Explorer on Windows Phone * ... +### 混合应用支持 + +* ionic + cordova (http, tcp, websocket) +* Chrome extentions (http, tcp, websocket) +* APICloud (http, tcp*) +* DCloud (http) +* AppCan (http) +* ... (http, websocket) + +在 APICloud 平台上,TCP 只在 iOS 上有效,因为 APICloud 的 Android SDK 有个 bug,但是他们不肯修复,所以我也无能为力。 + ## 使用 你不需要使用 javascript 的源文件,你只需要在你的 html 中包含 `hprose-html5.js` 就够了。 diff --git a/bower.json b/bower.json index 0ce04a7..531cef3 100644 --- a/bower.json +++ b/bower.json @@ -1,8 +1,8 @@ { "author": "Ma Bingyao ", "name": "hprose-html5", - "version": "2.0.3", - "description": "Hprose is a High Performance Remote Object Service Engine. It is a modern, lightweight, cross-language, cross-platform, object-oriented, high performance, remote dynamic communication middleware.", + "version": "2.0.36", + "description": "Hprose is a High Performance Remote Object Service Engine.", "keywords": [ "hprose", "rpc", diff --git a/dist/hprose-html5.js b/dist/hprose-html5.js index d9519f1..0c6b7c0 100644 --- a/dist/hprose-html5.js +++ b/dist/hprose-html5.js @@ -1,7 +1,9 @@ -// Hprose for HTML5 v2.0.3 -// Copyright (c) 2008-2015 http://hprose.com +// Hprose for HTML5 v2.0.36 +// Copyright (c) 2008-2016 http://hprose.com // Hprose is freely distributable under the MIT license. // For all details and documentation: // https://github.com/hprose/hprose-html5 -eval(function(n){"use strict";function r(n){var r=[];return r[n-1]=void 0,r}function u(n,r){return f(n[0]+r[0],n[1]+r[1])}function t(n,r){var u,t;return n[0]==r[0]&&n[1]==r[1]?0:(u=0>n[1],t=0>r[1],u&&!t?-1:!u&&t?1:a(n,r)[1]<0?-1:1)}function f(n,r){var u,t;for(r%=0x10000000000000000,n%=0x10000000000000000,u=r%un,t=Math.floor(n/un)*un,r=r-u+t,n=n-t+u;0>n;)n+=un,r-=un;for(;n>4294967295;)n-=un,r+=un;for(r%=0x10000000000000000;r>0x7fffffff00000000;)r-=0x10000000000000000;for(;-0x8000000000000000>r;)r+=0x10000000000000000;return[n,r]}function i(n){return n>=0?[n,0]:[n+un,-un]}function c(n){return n[0]>=2147483648?~~Math.max(Math.min(n[0]-un,2147483647),-2147483648):~~Math.max(Math.min(n[0],2147483647),-2147483648)}function a(n,r){return f(n[0]-r[0],n[1]-r[1])}function o(n,r){return n.ab=r,n.cb=0,n.O=r.length,n}function e(n){return n.cb>=n.O?-1:255&n.ab[n.cb++]}function v(n){return n.ab=r(32),n.O=0,n}function s(n){var r=n.ab;return r.length=n.O,r}function g(n,r,u,t){l(r,u,n.ab,n.O,t),n.O+=t}function l(n,r,u,t,f){for(var i=0;f>i;++i)u[t+i]=n[r+i]}function C(n,r,u){var t,f,c,a,o="",v=[];for(f=0;5>f;++f){if(c=e(r),-1==c)throw Error("truncated input");v[f]=c<<24>>24}if(t=F({}),!V(t,v))throw Error("corrupted input");for(f=0;64>f;f+=8){if(c=e(r),-1==c)throw Error("truncated input");c=c.toString(16),1==c.length&&(c="0"+c),o=c+""+o}/^0+$|^f+$/i.test(o)?n.M=tn:(a=parseInt(o,16),n.M=a>4294967295?tn:i(a)),n.S=M(t,r,u,n.M)}function z(n,r){return n.Y=v({}),C(n,o({},r),n.Y),n}function p(n,r,u){var t=n.y-r-1;for(0>t&&(t+=n.c);0!=u;--u)t>=n.c&&(t=0),n.x[n.y++]=n.x[t++],n.y>=n.c&&N(n)}function x(n,u){(null==n.x||n.c!=u)&&(n.x=r(u)),n.c=u,n.y=0,n.w=0}function N(n){var r=n.y-n.w;r&&(g(n.T,n.x,n.w,r),n.y>=n.c&&(n.y=0),n.w=n.y)}function d(n,r){var u=n.y-r-1;return 0>u&&(u+=n.c),n.x[u]}function J(n,r){n.x[n.y++]=r,n.y>=n.c&&N(n)}function L(n){N(n),n.T=null}function j(n){return n-=2,4>n?n:3}function B(n){return 4>n?0:10>n?n-3:n-6}function b(n,r){return n.h=r,n.bb=null,n.V=1,n}function k(n){if(!n.V)throw Error("bad state");if(n.bb)throw Error("No encoding");return h(n),n.V}function h(n){var r=U(n.h);if(-1==r)throw Error("corrupted input");n.$=tn,n.Z=n.h.d,(r||t(n.h.U,fn)>=0&&t(n.h.d,n.h.U)>=0)&&(N(n.h.b),L(n.h.b),n.h.a.K=null,n.V=0)}function M(n,r,u,t){return n.a.K=r,L(n.b),n.b.T=u,A(n),n.f=0,n.l=0,n.Q=0,n.R=0,n._=0,n.U=t,n.d=fn,n.G=0,b({},n)}function U(n){var r,f,a,o,e,v;if(v=c(n.d)&n.P,Q(n.a,n.t,(n.f<<4)+v)){if(Q(n.a,n.E,n.f))a=0,Q(n.a,n.r,n.f)?(Q(n.a,n.u,n.f)?(Q(n.a,n.s,n.f)?(f=n._,n._=n.R):f=n.R,n.R=n.Q):f=n.Q,n.Q=n.l,n.l=f):Q(n.a,n.o,(n.f<<4)+v)||(n.f=7>n.f?9:11,a=1),a||(a=q(n.n,n.a,v)+2,n.f=7>n.f?8:11);else if(n._=n.R,n.R=n.Q,n.Q=n.l,a=2+q(n.D,n.a,v),n.f=7>n.f?7:10,e=S(n.k[j(a)],n.a),e>=4){if(o=(e>>1)-1,n.l=(2|1&e)<e)n.l+=X(n.J,n.l-e-1,n.a,o);else if(n.l+=T(n.a,o-4)<<4,n.l+=Y(n.q,n.a),0>n.l)return-1==n.l?1:-1}else n.l=e;if(t(i(n.l),n.d)>=0||n.l>=n.m)return-1;p(n.b,n.l,a),n.d=u(n.d,i(a)),n.G=d(n.b,0)}else r=D(n.j,c(n.d),n.G),n.G=7>n.f?E(r,n.a):R(r,n.a,d(n.b,n.l)),J(n.b,n.G),n.f=B(n.f),n.d=u(n.d,cn);return 0}function F(n){n.b={},n.a={},n.t=r(192),n.E=r(12),n.r=r(12),n.u=r(12),n.s=r(12),n.o=r(192),n.k=r(4),n.J=r(114),n.q=H({},4),n.D=m({}),n.n=m({}),n.j={};for(var u=0;4>u;++u)n.k[u]=H({},6);return n}function A(n){n.b.w=0,n.b.y=0,I(n.t),I(n.o),I(n.E),I(n.r),I(n.u),I(n.s),I(n.J),Z(n.j);for(var r=0;4>r;++r)I(n.k[r].z);w(n.D),w(n.n),I(n.q.z),K(n.a)}function V(n,r){var u,t,f,i,c,a,o;if(5>r.length)return 0;for(o=255&r[0],f=o%9,a=~~(o/9),i=a%5,c=~~(a/5),u=0,t=0;4>t;++t)u+=(255&r[1+t])<<8*t;return u>99999999||!W(n,f,i,c)?0:G(n,u)}function G(n,r){return 0>r?0:(n.A!=r&&(n.A=r,n.m=Math.max(n.A,1),x(n.b,Math.max(n.m,4096))),1)}function W(n,r,u,t){if(r>8||u>4||t>4)return 0;P(n.j,u,r);var f=1<n.e;++n.e)n.I[n.e]=H({},3),n.H[n.e]=H({},3)}function q(n,r,u){if(!Q(r,n.N,0))return S(n.I[u],r);var t=8;return t+=Q(r,n.N,1)?8+S(n.L,r):S(n.H[u],r)}function m(n){return n.N=r(2),n.I=r(16),n.H=r(16),n.L=H({},8),n.e=0,n}function w(n){I(n.N);for(var r=0;n.e>r;++r)I(n.I[r].z),I(n.H[r].z);I(n.L.z)}function P(n,u,t){var f,i;if(null==n.F||n.g!=t||n.B!=u)for(n.B=u,n.X=(1<f;++f)n.F[f]=y({})}function D(n,r,u){return n.F[((r&n.X)<>>8-n.g)]}function Z(n){var r,u;for(u=1<r;++r)I(n.F[r].v)}function E(n,r){var u=1;do u=u<<1|Q(r,n.v,u);while(256>u);return u<<24>>24}function R(n,r,u){var t,f,i=1;do if(f=u>>7&1,u<<=1,t=Q(r,n.v,(1+f<<8)+i),i=i<<1|t,f!=t){for(;256>i;)i=i<<1|Q(r,n.v,i);break}while(256>i);return i<<24>>24}function y(n){return n.v=r(768),n}function H(n,u){return n.C=u,n.z=r(1<t;++t)u=Q(r,n.z,f),f<<=1,f+=u,i|=u<i;++i)f=Q(u,n,r+c),c<<=1,c+=f,a|=f<>>11)*f,(-2147483648^t)>(-2147483648^n.p)?(n.i=t,r[u]=f+(2048-f>>>5)<<16>>16,-16777216&n.i||(n.p=n.p<<8|e(n.K),n.i<<=8),0):(n.i-=t,n.p-=t,r[u]=f-(f>>>5)<<16>>16,-16777216&n.i||(n.p=n.p<<8|e(n.K),n.i<<=8),1)}function T(n,r){var u,t,f=0;for(u=r;0!=u;--u)n.i>>>=1,t=n.p-n.i>>>31,n.p-=n.i&t-1,f=f<<1|1-t,-16777216&n.i||(n.p=n.p<<8|e(n.K),n.i<<=8);return f}function K(n){n.p=0,n.i=-1;for(var r=0;5>r;++r)n.p=n.p<<8|e(n.K)}function I(n){for(var r=n.length-1;r>=0;--r)n[r]=1024}function _(n){for(var r,u,t,f=0,i=0,c=n.length,a=[],o=[];c>f;++f,++i){if(r=255&n[f],128&r)if(192==(224&r)){if(f+1>=n.length)return n;if(u=255&n[++f],128!=(192&u))return n;o[i]=(31&r)<<6|63&u}else{if(224!=(240&r))return n;if(f+2>=n.length)return n;if(u=255&n[++f],128!=(192&u))return n;if(t=255&n[++f],128!=(192&t))return n;o[i]=(15&r)<<12|(63&u)<<6|63&t}else{if(!r)return n;o[i]=r}65535==i&&(a.push(String.fromCharCode.apply(String,o)),i=-1)}return i>0&&(o.length=i,a.push(String.fromCharCode.apply(String,o))),a.join("")}function $(n){return n>64&&91>n?n-65:n>96&&123>n?n-71:n>47&&58>n?n+4:43===n?62:47===n?63:0}function nn(r){for(var u,t,f=r.length,i=3*f+1>>>2,c=("Uint8Array"in n?new n.Uint8Array(i):new Array(i)),a=0,o=0,e=0;f>e;e++)if(t=3&e,a|=$(r.charCodeAt(e))<<18-6*t,3===t||f-e===1){for(u=0;3>u&&i>o;u++,o++)c[o]=a>>>(16>>>u&24)&255;a=0}return c}function rn(n){n=nn(n);var r={};for(r.d=z({},n);k(r.d.S););return _(s(r.d.Y))}var un=4294967296,tn=[4294967295,-un],fn=[0,0],cn=[1,0];return rn}(this)("XQAAAQCv5QAAAAAAAAAzHUn/qWH7EwabADPIOSfRKQfDP5PS/WIum7zHAeJQvA4d9n4POLH6lJgsLP5QlqVDZXChzavjIbyDu+IMZRgJjRkeO7Zf+8FbLd/v4y5knW31OfmeQj7s0YoUOMF6krkyS4BiP7mSKlmmHj541GqWqc+Kb6Vt+wR1/8GSKawin+FUylpP8v7CNFC+mDCtquIESHl3lqlmn2vSbLEtoXUZ3A+7utGq0GX6Y9XtB4VKcpyN9UQK4uPaSEtgFxZ1QqTYmBhiUtrpn2ErNUR4EN/1WcRPX74XOVKdB+GCyE84fay7OgS5D0c7TG2uAStvHjFbLCU8a4tNT3+kqmWzZiU6XC6u2tu4QQs00fG+SQy/gohCmibZFabzuvR2MARut90EW+1kNqB4WKAUz5Dt0Ch+Jk49JeAwOLRdn3sdfwGMaWTOB696kitzXNljKqEj/YnodG5z6//dcRw5+xFwXKgKJ0PZ9lGX0fMIomR/+QL7yRLw25OCV479jKDAqA7w1m9Snabrnz6E7rIK99YS8SixUmt4ntDKzYITs8JOKPpCCcYh8Tijfj6jPjqZo5MQpP1a4W/MMkSwB07nJjmYdMUREExR2VeZ055oxIKNmh/cTDiFqbcEW11xP240s1OviHtBmjYaJoIDjSG0Z+rY+pHYgR86oMFza0lfP740250xC+VEN5cVU9/wwyQuP1gMEaewxwSP5LATABdi67PvG2TS86UTBZDkrVRvF4n8RAgm2XUCEbelRIUTiBCfiDx0Q76Q8+Bv7Q8PzMDX5dFTIYINI2PJsjiAcfYFF8Q/ySQ/VoYPHg8WYKBTR0Y0OV6zPiseUpAfW0+c91o4lDx/zDGLsU12HaN6b7eLOvxDJR6cCQOHirdFvCo3dfbvcE/dqlj+BfcGH7onXyszYSjItUEAWfkqnHUW39sMgaV/qzkwIXiov5YnnXyw0XHrPf9Wd2tzZg+64JynOFU+QvEyDTHGblOxUrCdVdqSAANrwE/sZXZ/M1F4HN3WdTg3GQ/C3POQ9tCOn4y9EZC6JYtR4mnS9tkfRTroS1NKIDqqQqc3rpnVvB0Pdkd63uhDoym5mzrIeNHE8o/+fGgO8BSsmLTuJAPllClr/Tm7vCnZVenHyxzt59UFXxaRQ/1SZS6p6RACzhp3EHFok7E2bac2vyRwsxhelvryPkF2pjIDDJEhe5/Wegb/y+XLJuBqh7S8W9OSLYm4KGwGPzgSrryp7hFDlVV4+SWl0dkOkiw4bZX3NisYWsgbTQD2FNr0ygY5YaCs6WhOI4qvV14VycSFajJvL6kCj00pQKenlE6KzEsL4ER1nCfsAyvUfxqSVoBO/cRN3q+E4qizg7hl7plXgLzW/unWmoD6lmW7BmnFTX0dbpKcBhaK5YWWRifJC+/gJ4JogApFfke+U+0TMB7/nqdwW1Vw3IU1E6eYhauGFdj+e30JZEOMlJkKTQalUX12HvC/RPNsUIh85WGYQ1fv2wfrTUO6rhL4tK8Z2g+e5m4PglguGO5z5K6DB28P8rN4Y0YJN6J2ypizwcNQmxmmZ6PDF9pUU0XeLjTrPgJGTD+yALsTFP4zuvcEegvLB7joIKsMsKxxEnwHCfBXbSF8M46fRygc7YsFcOXCwk2+O9Xa0HFX1pT3ThMApYaXDyyo/+8vhc89o/362XyjRHLpsMSY16I5cpadkWEMZwCr9bDDxfE62jGJxrkkTAHOWvh1/WnNkGUH5Ith+gkI2A5hbtVGwMh4m5OkEZDzxsLY9FQ0sPCeE5apVq/f3r6kfD5boHvLfex/aQ4YDGHUpSNg48cnhfP4LIQU0b0kLx8/XoYB3VQ82w7fUVRMEyiVUvbskoTe5DdKv1ptSHGu3GWCsA1GR7NcuJ+gy0rtktmGGpQtLjzZVatcMqC7Dq/jkmm2tCGX9Eipfh2cvwFfU8qUwkXLDHmFAC0tHLNwvVNc5nh/b0W3OeRYxzcKVAvz8kDsBn3RnFftp2K32aFJhW4SzVOZXBd5Zg/aEG9vRgRsmWF98nF+OMPwBn3tvNqjDmWM/lbAKdZ8euV4/CKgxvB5lEhgXJp8DstRyCvpmPKDUti87x6XaGxhVt2BgZ8Jd6jg1g7J9b3sKwDnM4nScpam8tTvRTfxNRREBK03fGjFrfB9sh6fo3a+f59simw1P5Oetv7fRoyQa+dGf0rJSDwz2+7iHRnAgPZheoKUGKX9urZvr1RdErqpiio6B2yLOaL1p9KXYZk6U9bED41lJMIzHr/dMz7ZC0e29Mxg9hkWJJlJL2QXrmfpEMP2LRG6+h3ARTF3Ol4PuWEFtdSOecdX4J8CQ2SnvpTpTxpI2jt6ipKb+YhuYxUNx+UOpS9Ol8VFjGjpcYbyWZ4hFdAxsHoYywCQAAysqd43DguSWylCyKEOdmbmJUw49Z8N5gnD8lkP7zUmt1h/eYEOwX2cY+Qe5Q0rAb8MAgV0U5Waa1ghC1zafLSMSwsL232o63KaanBuIxEyje6ITxC8QgrqkyKacHFVRJ7mOP/eeCtLuq0AdD3SHxPIWi7uLhp4lh0Hp+7zSjm7ZDCxrGn0lgoznKzkDP7g7f94qYyj/AvjDkrLXaFY0o19d3jLovRweXh9p1abomahX+u64Fix+fGVloYsO2LoINH8vtDexCToiACKnq8BWyGMc0Z98RM9TgUilNMNub/k7UtadPRljyij/s44no+VPulIMmIpdZ72NpqN5usxy2AIP84UIpJl4Sdp04YcYiewApv+/Oy18+0SnYbgy2a/JX5etvES5QpJNq74gSToTnHjOUPxN6DpDtJ+nYcY6pjITX4JwM/W9MJvI7ZJb6MNML8navm4Hk3kqUKmY9XUUS7i8wpxMyZP9V/e0l4m6nuN7R7Xzp6/V7zeApdLTMPAhoCAJSSGlOoLHXaL/zXZGBKhrfkrecBT4VEhZ5fFtvpKewmX9iZkbEA/t77Ev/WCStAJ0dzuaZCJWDhAVoiMrhjttBp8N5+fxycXT9dHnYlMMLnYdKJKxFZkZWE8RzRqkk9iCPS2MpNIHpvFO2PSpt7wO5/cWqG2KwDs5Y0q6fh/5O2zoX60EAhqG3swsWpzpQzP8nT9oLcASB7kBEp/hLMSz41dsenRAhejDglocY1VnNCI3MNldv/Mjcb4Kn/Zd+vUC6BsGex8gH15FMictFX4SYwKy02RVY4SDfrp48qzegrvAPchpmVsBtRQSc1O8Kx3GhQZp7yzjGEZ7lpkIVpIOV2gvhZZjR4fy1XURvTbOX0VaQZD2ou+sgnlaK+NdqI5+JMQiethf3C+Q5XmRPpyGrARD+05EeVza6gO03L6QqPKQH9pCul+VicyYRLOymZ5HGVUITTo9qlEPFixwKgrmyueYpMqUZqomcpC5JjrGvQ6pY9hH9emQ5Yk81pmUOAQvR3PtxJLryv17zJRM5wV6IWVUIKR3ZcgKnywzNJAyYWDap/cT0TGeWPIH6sV686Rocy8s1nz0rTwB1PDpyjMaMeiL2CO3AX9YHsplTmCGxvzeH7eQ+/JcahWqVfUC9MvmW6D8VEEpvlSaLi3MY95dh5M1LjHyGWVnRl0mo4DpnVFgPndQUW4wvxhHBK6IRc+GeT97GGMYDxuhBjiQWPkPuAKQnXLglGjSlG24usnAgtdEJGrivnbKjwi154dW66Q7hQ1L6AvBQlI0ZcgtA8e8sGH3qLlebGon59nLuW8j58uhIs9XbtR9bLvp/ztSGRXtQHUjTAE7TqGcH+AmZd+IhEECnOrWijzmdlPAlV/5hMBs9ChWF9SfGMHRVthHuAum9PaFO+9632gxsDFdqg3MkgFkXmg7XZUsaVRChRE1GwQjNAPRbGdLtaUvH9lAbkdYQfLkWKxynjzZrFyU2s+tsI+1+V+cEzG65cGSzt3ZQ8d/yYBhOTeABc7rjU6gGTy4TrgdGYvfBydkIYGat1Yjm/GFwdXQgy5zEo3ByL+/mQqj6yxngdpLXnLN+J0l0bkeS03Vd/L4u12nPmOICq2bBjFFOcVESXYyDzYcuLQc5liKuraU0b4FQq8oMjpNvruWpfwNcjrupGgc+W4croFkAxKGondiwc/vUbGiIEDPwt/zJzM7Cx1zNxW8rngbyv6mGQKIYHSIPqJWGyCA8XATL0ufOeAaZmRJzrzZTOyPwTYhvgUrmavS8Eo6tF7SAOiDy/OXSSxer/wY+i49DqvoGfbkH55EALV+22CqZ7ctWK7fKmmRit4DwbdGtTa6BIFMykY1m4DCtH68SnrKSRZbxKOxlbpoNYoITEPWhLvaiRsb+1WiSVMKxZj3i/L1VzkjKz9nEvwa2g8q9Ov4kmkn6qroxnvmLDNiUTWKkjyILkCk4E4i8OVqHXXV9g1UY+pEF9secvQoe6PANcnsEk/Wo56aPjIdHdihyEC50Eu4a5UcBgjv6hCeT/xjOk78aYoHU40anwHKCUt7Wbdce1xQCYLrIGCtCdCtwrZ20pxQUpK8UHli4amCYhBNoD/cFpFlxSjs/hqhY5c/OEH0XJFN+tfNJHu4fYqE4oqV+Kl1YYdaQKjm+0R1IctshrB1vyFId4MP/EemD9276O302D/6DIryxDM3NoUnDXBSFHPVH6Mj5UCyrqWUEiMjNV++J+V20MTZlGkWtKWCeqtRDVFSx5+n01Jg81oh9e60R/QDu+hRrPwV32lKvM+rHFFhJFDCexJyMcLhTb5Yq1flO5ySeAwiYBeYcglyZm17df5glFDuGltriMfOlpGAaDEtzUNvgx6Nud82L/ArlUhkhx7hXpG33y3xs9wZ3B5Ef2O9vkDQyb1xvYjlvk3Zpirb79V5GGHEtQc7mA5yZ8VmgnlUDCfFyAoPv3pbHIcxlx/D1CpC+/18QTIRlZiukEZ3UuPSvvGmVNv0OlosJRDcWEHp0Up6pAmNQ/9SREBIj94Rz2ityQnilrkJtcfv7o5g9y1BqWeEtmib/APAj/dIx6K1mvS8ZrnH2Uft487kumDmnFfynjLwp++snHJP46vH+HQirVI9EXs1l820Vu7QdDw38DIbLtu497z9TT4FiKxI8wkIb9awTgyk3tW6wclF+KDQlWFwJSawuY4qPoTngvy5pNaziNhO3XfGXi5bosTr9Iavn5cytWGw6j9OxK5ml8emEXn+ivXRIwSY1IzuxAogQYEzoJKxoffQKc6f4WYyZaKEECQwiAw0N06MJCltx4q53bOMHbpWYPjk2tah4JK/B0lNfA8YFdOs0ZAlLgoHygoDsbFF4UuLZVeDJc0aFzcniPm/woDdczLn/claPZKrXKLi6pl67SvWiwkQUUnssAbJcIWOUr2Sesn7qXcqSWMRibTB2ghe24gpA0q188hgFNuybk5encnR+fOrPP+HnSLWMSkpHamLbS/JxIuY6phzhrjh0AnlEzDqku/NbCpOkSxFzmkri0TTssoxdI3wTfMwhtJ3KQJ5LJtWpAXbFvY/dnnHi2rC7j44l0RopGGlvvt0x18vGgdA+GPsfdXA/JiIESh3+HP8BeIEu54Pnxq5m9K73bqD3W/nyCMS0r0IjqI1l8qWs8BnMQOeQiUUF4wj9NuT1TNvMqmqURmK2RmLzuvUdb7awUI447rWzLBxFqPpxvX0JcaqD6ldGjxj0aMhB3oa0BGq7FlzCXcuT/DZcqg3mcVzC+G2EWjPdLA1g5iFZWazs7R1PbXKD9EoTEhcx9Lt7evdIHH9rRGiYJhO3Nd6Ir0kQif2BrN5Nb0vWdL6o09SUoMJPrwvHHyTE3NdRlN69ciDVZwHxd6/ErHTeK9ncbIK6gxjaOwg6VDS8tPVXDloyaJpDB2OKqCs9pE2bcI4NoxgipKB7rZuB5cnf6Gs8TGPCgTg+nUioN0J9T1FdKJwdBSO9lk/YcHkrfwvn2DJnVxTKdVfal+SOWmLRN7iU7uMSW6qyoGVhpOcP3hHMIvDuG5BgzGUVv1PZzbdOGcSI93wTWF+ha0PgFCSGiqUotxwcMJvNWRfCg9BZS9w/KDhcSCFhthxphuEZkkUai6pb8LMdc1H9hB6HoN1plfTFlxN3kw9dl3+B6jCErUGQm+kzq/+56GfAuTu9XndHy+gnVQepskdmOCzlKCCPoEV9YB0R6va3/BRbLhMO/02R9F8YnIPpFS5CBC6RDuq8ukjnMEdOBLjACYOPtvVLe2T4B8QDFtsdJi5FnfYrsRk0ikMd0ObppHYLjIh27ncE81MGdtGoolcl80Jw12p2qSt30/6SHmbbr854g8L7uhpasui3pM7iJhrjkUC9ohnczw6D5ExTlHOQbgqpo3QHiNsIWtqDjOgF88f0ajs29bOyN2jK5MDYkueCtyENSfbicvsDUairZYShYe8Unvc0TPG2enWEBvT0CJ5LRnEiRNiPBgyBtva7x9nR97fr6YrkfsDi8k/f9CcK6Xu5wz/G7zCCzWdLdkEVdgv7SbAHgEQ9aQvxoCYFOsWLJn8nOLT/Kn6Hd1SiIJrDcIKBNgpVrG1/PbeWFhoSSZbruGTrI2VqGPJcKRp0XOGwUaBEfVF0gsBBBhTpsoNg9FT7CLwriafEK9nZev1WzqI/SoCaLRuMcVWKz0+390RRBRkjyApDgGnQB9iQ1lEivouHGRgBdKX+/3nNy9K14lvTLFUlleYPN0LRuvoQdkwjGmfI26+uR2MuAKkiERzOrX9Ni+1V/KcoVWbVQ/ZRP/x6WpelrjgW0+W8dIbpgE8hYCeFLRJWG+5jLYh8ERKLdl9bIUirD1EFnxdKukjOutPyVHOz1sIUiMoe+0L96DFewzdKAsMxAlxkX8/QTu+04jKuEgELZ67Cj8z56zZ2W0q94iU+4L9a8f2BlOZISwLUbU/WZ/5CGDa3dQBxDc6AMmFao7x8HeKDApxM6gMCIF91ejR/qu0v0ZQoC7ZF0yzrdn5qynng5hoxRHcfWs43aEOyv0wSydpDEKAYPxjcRXgGSIy+2i5fcESrJz/per93ixKirRG79nbqB4hj+Ysoa5bQ1o0ViowyESe+Wb/l/8wa7NS7ANEpUGrspRpb5o4foLUAZnA/x558jG8WAuwnZAtcImFAqY/j7dR+GLb+VyyGX4gLBU+XjI1V2YxP/C9E5QL0TwChla0VhBpqcwJRwZDkuYgXQyJWR2NJDypWKLD4Ns86p8pZQJfqDFoaZkCqF8vdho6gBatMnzvQSFahWGPC7ONu50LPQr7fgcGzhm9Tvk2LcokRwc4uINoRjI55muFz0dh5jAee5SMi1W48HUzCJcU+sBARNJVn7zI2tJZbW0YMM3qgHwSNAonySBfhX+EwRNmr1uXENRXc5Wzlw8ehdLwk8IK65itwCuQ+2xCe7BYb2vsAZG4pLR7ETLqPZn2H8s2PhZAUsmoV1+YsAsvF7/yc+R24c7vKaG9sphyfumz6hpBVrzgdgOiVN9bcMUAzghTiJrxfwmnAgzZwaYGPxQtgoFtxGGP8vSto20CPEKvLmfWgweS+Fa/PLkaYvkqZFUWqrY2T1A/qozS448qXV4/UJMLzOKjcls1cFckHC+yWaiSl1E7bBxU2qmemSUjHfrX7FsWmd07sNcOH4/3nVI5e90txbmiCRREZawXnvKfvhSGV/twtVDJEdvj9V0nYFTp0yTLphBOqHWkI9CXPBpWg0X4SjQhRtUv0sD8tl/rs8e5A2tNSvhjA8KLPqYuDt5OPm8zYXovetTlDXjYDaO+kE8JfHEIXHV9o9bMjiocS2THei1YiJNLJuN1+kaCHdpiXvEDuBOO+pY7lMXHxksrthkbOI+KspqLfxRSOCc411Nt6xWzMKP2bbNP9CUW6zdcQ97Q4MJG7t8Hzo/SlS9nWl6GfiRy3gdxyC0tQtjJ8pAe52Bn6Tpg5p13X82eF5aWGTzsxBs10xR1TZb8gB4XYRxUIdt5YGXztkohfctEBLUBIg7rYyXvIoMlOh+Ro8Uij8yh8rLfO9inHRkY5gDaJjKqhky2LKcCcKVtSbZkB3GpJ7CwlnFs36Cvj21M2DzBlhxg/zYQFGPrvsK/fZ4pjkMoIMFDZmuaUXTbuGah/74x+O968AsSOKVIXBHjYplRYvVnbwM/2a//rErgmR6GnHppoQOvqG53mhlRpvMxFSL+MHg/u0MB/uD++jzFUE5waq+cHu98Br0txBhsluy4f+ciwHn4Wr2+AOUNjr8aLf4NOWTQiFE6EJjSf+yPRiFVD2V0mj4lXveddDnTdPYSpucnS+WrrTJEdVA6rNnTNFEfkOzfirbqMh+V0K8/7E6P+9CVUad+pNA6uP/36JTson9ySwP+R+Ixddg9u2v2/GMFNuSVENuXmNIIn6pzOyimmlidJZvot+aLyzA4VyDcCqiNqQ597zbGQbFD354+8WKXrIaP77KXE8tJNEutr7vxF/JcQHl97ay/bMc9PV97lutOI+NyNFfmyYtYc37Qc+OHdq9yyQcnZ5stdkPlvTDDfy/ilnwrFfjmAaVXl5+r2fGsQsaE6HIlaOZClXaLjOLdLCNNWC++nJvv3VoaFPETvpysFijg/1AyDg90MBexI74Z3F+jA2tl0mvq3fmOSFqVDyYaieaDVulB/A03clvJ3sX3p9uvVKiOxIDn+H9Va/sBTPhuIPttv02JuF8O4hdUi0YB9mJgVKKejU1DbmjaESyKhUBOk2GHH/yUo0N/6z+Fb0rCQljXYQwaXuRvtILwNufXLBhsR9A1/++aMkQ/Er9Ujx1g2kG9z7mU3iwrAWYky80XgOm/UEWfz/D/Woq0i1pIdpCXoGWC61QuDfUcxtOa5/n5y4qe4hZIyWbyjbVfXDSvifR8udgIUvp4C2Jijtn33Gh4BSdLyQool/WbkOn1pA07SH4MfIJ8HCpF2IRAd9jAH6Sg9LiIXkC6uAnevBv+bqh9jyW5V+iROxqtGyvzPSsjcH4YQ9V0KcBwBjsQ0YQzqzTu0Wi+z3C2a/N0/DM34qfcvYisk7WAyPKfNkJgAvFyCVXKEWmWiQSvjZnk4ldZ/08qdXYyBFeNmne2ApuLM2nM0jGiuuMNaEGxcxBFN3e/g3jmXSaVLCKXVRYUUqpOmI7iFRBJOrc7w+9FKY4KnopCTtKsBAIUzyWOYE2YGdJwYnxQT3t+zYY/txe8XT+XJd0PJUx2ebuN3MgStmiuJd1NRAkUJuvYZ7mUDtqnyenEaLCQfRrNjYYXgsbo5MONpsNGDN/9K2v+lqu6jPx6uEVgHqtiz6DavSgAvToy5uJPWjy6zRTFEKv5r2CrRFprlOIjHGk3OxTEil3DnQscqZP8Zd5kOYw8LTkdRJDch3Z8JHFSMPJg+PNHzSpH7q0x5VQKW6TPlboXlW9H11jEjbBsP1Fmz49gU1pjSDIjpv/Q0NfJlVugl1AqY7X7L3CVJhruw/x8Zi3VnVioMO9zQo5VLiBV4GdOBjVy7PMfUvVhlLoCgRVK+kfskv8SyHxaOAmFP7/7elFNbwGt0aab21uemjyGuvwIFPIXcFifdNZhkvpa/S/ov76recW8H7vJwpbj8+Zx3SU3M5ePSidOuHwJTQC1WohQRqUFCE2u5p+BHf9ajsyov/b2QKHX733vIX0Fs1apOFRKEzmZc9uOUj8wO9mS8W7uL1yWiFcZtHLESws0+OnPxeREsAm0RK+4u7551x1T7jGa6EPULyeEuyo/Nz+cK8oj4V3p2w4uxvKPnJ50eBnlUsdlUTCrOS/lMOpAe78Vh5H/Yh56OTg2daF9cUlJKYtRYmVosZ7uS/h03tfPXi84fQQC5zbms9u9L1AYY0A8pA59ew3gBaMBuo73H2/4RjnO+qp2h8I7xl1/qSGO2zqVUlF8JQSL3nys3tvPxKWEKd5o8y0uGhRw5X2LS6dNBlU99UQ+M2BifBqpV88C7iGaqmKZa63gW7ALEZ6hzbQXdVtRv3abAcWm+Sn4dUhggdnlqYTM8llT+u52NXnt+148yMFKSjoC5LJfg0GS/gZCzAjXOnMc+CAv6CdrFEQbKvmLvXG9KaB6Tvibkkw1QUPPYUYjDxEmxrh3xO4M4qYfuzFTYZGSrdZ2v3dA1Qy9uHHQ7lhjk95A7zb/arz6EoJBhcIfqPgqecbca3didR/hEBLpIT3qquA3bzgRk8iWD04VOTOlcY8VecYqbTFT8CF+JoufVTYRQ2zlFIhLIkfD4JXywFhEM00AN9cwGXGN29cNPGIqPnsAR4LHWrOE4UZz8ByTFYpgXOkMX3MyUZwEk4cx+kqyBJdq0Dp0h86LTN12wfSaPMRv1IKxgUiFs0pMXStno9wrjQANURBNM/Th8jUdqF8Yb9iLGmr4wDS6wbxdWxqh2axUvdu0UNQTyMfP5zHsn1gsKPvnKi3/LuHKpnSx/nJ/8J6YJuaMdh2cV41PDmK3s7ojNIIneakNXKU/jRqyCFQx9Wc8GxJUDRBp3XG6tLSI50LLYTizVKs0twLUqNHwY/1fJzFUSZj7MaeLfpMNPxRMsLnKTS7W+4L199vfXpW6bAjQOQ5Toyi7N5xhbRZvteA0PzlO5zt9zwigOFRxlXxEL7Vh7cIwNdz5+NlqZVWwNsQocLQ0HCgIzYWejabr64NSfn65c4zJCklcD9hbg60F/5BrNOuySnhNFv1Cfg+YOQhzItz9R+Buuwa9q9/mpBfVdvl1gAz9nj6BHqajN+nrFE3wTf5tAHtx5buMx2Cu40ZwfYAlGP4PDKyNTecOmAnNsVVcv4BEpWzb6W0qF498u/wrIiZF3wc+nY5ngcNsrpj+mBM8bOaj6Us90CefNYePprZGIx+KvyVA+dl4mJUMaJf+0oZWn05ISXpTC8ewCx9ks0WwLOXR3kaFYehHUK5x/tgLs3FpgOqieL05iJXNA5EgfTDiq58BDYF0jGsjQseMqlGd1VFAB6TVe19+96/XOOrdCVV4kZ/45lMLx8nnQ1yw55Qv5CP0n0Oft4dPbEzxCnbQukqREuMnrJdSpQyQPwyc6ir9UufEQQ0QCAY7Zf3qIBH+nf3GKc9wybo49ux0ha2U4tJYfFgTIxCmlgqpJXD3vbdJ3Re0aj/9IwblJiYIXSO1VXLwuymT0kAiW3F1w+yZ2MgdOCdIQ1pMydbkNzNgX4ip5Pfb+ym1AmRC7FI6sUgn2F8vhUbL284bJGFUTFnIXXhpT5qpWcMZLSxfBhzH7FtR0c/p9yeCJbGwZXuOQ5T60cFfxKi4F8zAjoUR3Xpxf3QfC0aN6iy6zE5+xEN6kfTsNpZ0VvxRr+DuUb63i4gHO/U5TaaMoQ/T7W5RozCl3Y6EcVXKkTcrGe299M8O+Hm3rHYgYwaiGsBGZm5BCm+5fo5mTu+GP+8aj8oKn+JuUmUP1cU0PbbPG38D5zqKN9SQLSZN9YxztSUqXB+BFeXIFu2WsFmbCZFlNrZFkvnUortZtzslzLnSwiUp3fHg+CzONvUMKM3y42QD0RBYDv5vrFZfzJJaAqssyrjJ00fFVtmewow5VWqZqhAc/t7uGVf8y55c2utXwR5LBzBYw6auk9Ck5PWIRlTpbTpQHS8hXeanwhbMAqUCCNZlBz+O07anR6epFpmiDrxPo7+IhOxUfE/P1ue67X83yfwLjyWbYHmUXSszmnxBSkA1zbrW48A9tJzgOLGOnqLW+aVthJRrtHnP3S4J6cG2ivlkor5hAPNU59e34zjhyIvCQ++xguT9cEsoZk4zLF/Qa+nIQPa/cwfyTkenHca5o47qSPeibDKP8SpkSVDsNGhBk7nzVU2DhtudzSUS8dF4CoHsH/GlhVQWySElPW+v90SDmZy1Q8ObNRT2kkHCqa4tNrn4YPcUsA3hXk0t+MCUrG4tU101ndP2w3J0EP80S7vMhbVdyE00BBbhvg2h+xltj3EBBaq11lkbsIQ46UBaR7ZA1Zc0JzU+JZEW4IDxzga7TGYrHfAKSzJ/mUSm0P63Mxjbb+w602GpCodLB/7m20XlccV76cltqV4nS8fKwNpXVmXPRUfMqW2MZrsSS0XN4RPl5Gd71WOq5ozOsMYMQ/ljlvllhlwVfmn4R1+o5N+iX6Zah0D2BlSFC86kHGgjeTGqOaPx/ruGidZRA75LfJkk1p/ZUipGJhzUQK8AkiqM5QQtlKqiOrfZL26M3zhUdrHO9XyDPV5/2kzpprWRWN1Av10zRvYkEo4VHowqjjDgWVo6ZSb6+nyGG+5UC3XHRdMSBIkcOKcCdzjnsJYZ9G/Fq8v53m87gC2TwUtaoHD5CvuY4zdiI+KxwlQGCf3eftoZFxR9s0DcL7isBIr2GLJcCzSe4s+wFxvhZkMINvQs7UKR85HqlrgpFhxb++yzAxkKkv83+7KmbwGThazKW6tiDxUS6cPWD9tO2XodYfcm5vC2LH3xi2Y3qpWkw3LVQFwPS1hV758iVnICn/DohB7O8gX0EdbU2YuGQelkyklUZz8w3kMzI6z8Vn2otG/cStNQg4RPBUi+v4TZbG88TC330R8zT8nbUo2zLj65I0s6ZeQXVWnfkMf6wz/YFmeIxF3d6gS7Babv7xAEwXCXFNwI9Y/AucrJ7eMSgoTOqjipmnFHttc5y7wcQzGfv+pbZ0wqFjgiD90rY/msUNDq7M2+xQ2bkmFU571bD+piNNa8xeqt16rOPpgMOqS9xcye7753/o6l26ei07wVJhTvwYrW8+Uo+b2dkAFneeYmvgaP7cTA4boD1x3+IpP2jn7j7wxjhtbGIYoQp8bdGzDtttgWxMNU4MwxZlAxD/c3i+OD9CsFTfGtsYHZhgNqSAnOa9IjFN5IzmBYSl7I0NiLdvEMeja8rk9QjQyBoSWLmjzXqyYzgLNR25/sxh3Z7gGVRfG8fC/pdo0hbI61bMQSaBchfArvOd/jL5GzAwe0Kwl14YIEFYKOa+nO9UQ3TyXMjU8R78oXk+UG3K9FijPiqKgWZy3sYqMS42vo2Xm0OnONO2TVWyPUz1IhEKuTPZn81dlX2lUTSzvP2DMKW6+SbZsjQZWtQfiTz6NECF1jGOKvbox9QD1ksrmeFnp0DXWaSlyTvC9f+FGPWSPaz4nEpHOKHEN4Ff6pXDnlP7Ntt1a3P/f4Z76k6m/3CBrP5XIyGdlXQ+yiMIZpzog1a26NQkQ2B4t5imAIXWhbPyj7ByuXyDtU/S2/ZsSqzNqlz3cVcwHtbTXRwSiZYVkmNny6tzcXibL3gJl6wtTfWbJoqpEZU19rfMT1jMNDZgXXrv5GsCDQlw/iSUApPA3JtzcYmVT807XvAuIKLy8Vua3+YCi3cJtTZ8nEtK98FYnjlTrq4UzRkyEKOwHLbmb5BkiISrhhpWhVoi12b7WBU8RKHDFjc/xJppD7NVyrcWt/Ty68j1XsTIQh3jGoKcFZ4Ljj9m4Ojl0Ml5hyA/UaadVzlo549Vfxnjo2LKx1YbFno92PwM13TsbygE3SWhXuEgxfyzdHLhSkESmdd/+FWrzSmjH/Tsd9B8W/ZS0L4PRMzjZUlm2g+0Y3SlvFp5liMcQW/RpYm0+nNQEw0JklnahHBtLw3ZfpEdCtoBPsHff6or0a07d2sVwFYhBcwoNZ/qzi6bejkA2iXQ7QdA6poolaAdtojzyen6Si/SVQ5e2cZb9PoNveEiWTYRPykIC0pJLmgeBgHSY7N55WKGGsLZLbCotEtxBRqr9G1ODn6ww5MbvPBAm0ozhSb3QLoN3svUgUBBxPCQh8+MLzUTxHAE/5PG48YlKWZvLO6n17QkLdOUKGalXWjbQvZh2aexruxleHuNe/Q8WokqWJD2Yap6dSiRmnaCaNfWMkA+SAgKZ9Yk7tdKE0pNKhpc4GNOGRR1J7bimjeySup6JEe9MF0EvJngdrbWrr3FHvrm2kPMpCOKvj30DQlZWPVgUUTOTtK4u39tVzmAr/mLFQG5LQ1TevE7zKb+lkZITxWN9Tu116OgLBGyl3jilOhGrBB3km36e4SUbp0iqtAIemg6Jv+C7K4NfZYMotQpftwdRblBOp5w34LONK1ipjhAdHc1yMLO6vzmwhWOzZR0jkQS3hoCl+xiLtQYQaLg/x1aVi6q5bzSLAmk3IDErJu1Qt0WqPiLH8YQ6fD7LmGBnzS/SXQjWn19iZORbP4tjMi3ymSd2ussrOG0lk8ZhdnOD2u649r+90mA4itJ+to6LtxxhvbhokOFIWn84w1o/Ek+gynwHv+X8jkpXtyMM7/W0r7tUvzHa+Fz6IqkHO6CIlSfnw3lFO/PNfphYxZ/DqdkaFfCEFmZNyGFD1GkFIzQSZt5sWTcRuZkXcG+MjCQQTAOAQXu8bLlc6T0DMou2eIqIUk21beN8EyYxnHeG/E5gdtsvyaIdHQoZDkzSkEN93co7P6NDymaqd5w+Xa+V9mXPmRrxoFMp82u3Rt33bbpzdjYawAmkT4t4I6jiQX4M9pK+Tu6sYQAnXWYe0d/VCV+djoQ8wku2q+IhJqDttnLG4Gh+R/PS8Ggx66pa72ZUJ9lUHf5FOoEFIgZLP2AMAmez7FCXDbRMWLKjUVBJz+UlQZo1oqL2Yjh7ABpr+KZ+kIADKJlmsf7F3IJtb0q88h5AqsYnNY5bDgzyVzZ5HaGVCySdo2XqP9hkqGjJeQtMUcGkACi+k5YXiPjj3NcKdOcmzHUITTlDMSrB88U16CSrC0bLTXAPfF0c8AxTJvLuyQzcFRs8OhQ9mHnn7uYOaXBYlh0frjO+bHJvYMOdePgfHabThGCAkHEK4BasPgAugMOMPoKZHmQ90q4z9vV8OumWJn3nfxcDYr0OvS7z8NmLRKfkW2wgKasO9n7LmAHhJZsg+BGnv2ZC29isKgyOQjulf4kH45eC1mbqns9lecBdmOzjxlQIvXqA88pFTuMLI0E87ivZWx+xyMs7b3JwMFJCd4fhcvKIC8wNvrcJMvveu3OB8zuPSw4C2JpfmupH3R7P90TXIjkC0JHK7FYcawJ1PJHqqPYXnhqI2i6KR8TnCxPr3m/Qg6ISlD84T2gCV0IqIjx0pzztGyNWaO7tUp0i9Puv94/X86ge8GPKeJsVqfFhfI9xr/kozRBCyHia1H2FtLNvXrHGg88CKBJP1PNaSmKTh6aMqlY5fULpZ8YitfTlw87/TFjbzYNJooLPw/k5pvHuItuxnIpw4NZIVGE1ihzXpcATNuA86F4eUhJV1Fu/xnC5aNfZ/RwUApKtn4HC1vxlpAMD7mvcAOG/gXgoAhNjERYHhJqPNKsZ97zlQtqrmhbqH8vfcFVVTJ45cZVQKwkMMJ1u/2vBIIqLCJQGeNNVdVcYC3cmQzrFoZsQYi/WTXtXFsa0sOZTsWWIHm8XouJgwn9x7jwAwOuLG/t8JkbCH8RFhroAgNkH0MjxG99urm6pAG9tTP5XlLTo8KlKgb0Omo137cFzqvdZVxf34vt6+3oiXjWf8hqn2BC7OE0EPJ/Qh07LAbU/OnJuVAPRwU/rvPIJQZnP/Gh0n6O8lB8HvNnNRCtc7psE2ZZKEK+eSfdFdCW8noHfem9TuH2FIW1C2u5CNb8S/YYEE3HfiFs4Eq3fmBg1Z8CCW7b6weiPsSFKytnnD7Z4Qnhu9+OJdHWyCFCyO5g0tcR2FyZwJSPDBTCOMDNdBX1Om/AdPXGBuiML7tLpq3kReeKpfVmMiHkNfPV7AYuKMc5KluXAsIMeIsx2FwEbMqOT/GiigZ566ILyJ2NBLto8acsIfrNItxRlPOWyZKRv7Qe1kSUUFvvuGyocbAwBE1lQi2/uguopeT6ddQ9V7EQcOy65TWdLf2YU3+LCjIgPjU3iaa+8O3CUU7SkPiOm+9nU6w3Yq73myN46bys/rd2LDGqGu0XC+o/PinmO6Vmum6V6hYtGCkIyCx4PY+xP0OcthY2moN+I9hd/NPPC9yGG67YFEGEE/L+sdrKHl2sLzIjFXiMnErDmgJ/+3iiYACz+qAjrZAfDa5qPZTusk9rwEsS8crrGww1HhBAeHQEAmsNFNnRryiongNMDVXJe5dqVXQ4+esBGb67F0zG4xpAJwtx9SlsMG0AqYUj9rLlrahtpWyeyN7NqqGHsmF745Fo6wsonYTrmIyUVFn3b4nVmoG/7jwl92MRyDh6ZunQypeawrRX4jcOmRap65d+LnyVdnuj8N/7lGQjv73FFX4ju37YojHw6DVQPhKbMYEzm4UXlBLCa2eM01s9eKZEs0kitKhOXtzJ1Dn4ykFd6fD9mPXCjWKyjjx/ObTtX0a1Z+SI8jiNYLkzw/fSLq0g4PWPqOh6Cq/sIxgOAbp2nIZttQSJ56P7swmv9Pf67766ibPFFrR8QZgvv9kIfKKXwiS5+6dttT2MTWg0Q4foHzR8WM1ntrwcdeRUv2+4WrreqyPFRVFzgNasb/04gdjPGsXmjyVqBWzPnPeUpiKT4RS3xEXWDT0fuODvsMT9yhmHS/Rkdy9hsxjo3jsQsVJCzrTfQUM57NFrZDtckdpTC1k9iQFxn1wqCVgBFvh7I4mAbaolnUCEFWZIqma5Jd59qE/mIKcpHQyIzlTEx/80F4A72pmhTgrjGFmYas1xom7q+KIQfTJLJ3xpa5fbJPqnSNKEUmHIB/OM2sawwew7suzYEUwfdsrF/MO7VFQTseYvfh/AnqzgwIqo0U35P+1mVLTQ1lE01E1WPd0LPnqAER+XyAALAm+KEdukKXD+BYbuv2Nc5DQIydyW8zrKDXCzUjbADSlvv4izkeMjgGcjogqaTVxYW7QWqLKIYTzJc8uaEYFonaNh8artZdxJSuD35CC2Km6dbUil43fsVqMS9BWlFzcNmnlzOeL8OJys0ve7tCjX7Ad8JOIjhvs8tohPOcGdcQ1p6pVXn1lEBft0Yabh+HVKigorl0c0HfjcpaDEm/WItM7p4zr/ujDvKpa+kVlQ/AEDXUq8w1FsM+Oj/Lsti7/pkQqW8FIMl09mh07pwyb1OvjVYv4XfXCcKRH9ittz3o9gghkb3DJ+YptKHTUlwSb+J/DIJDXeoIhzjM8dkJzow7MkdNewK3Spu0W8WN9HWVxkrYdBQ87X/zgDZX9R9DqHjaRJoc+0GCtZDlwfoxfiZB6HUH0+rG2qxNgkMUGAaM1v7CrcFvdxDnhaalJGUb4U3lp48yzcem18l+pI06ITONrYReOPWtG/iamq+bjGEcysBEUCTL6HLi9pOs+XqdWROwYARjgjbeRVJmnKUGY588jop/Gx7MCRo2No8Pi5RzphnRLScQjQiXceyjZpffYUUD3qRCO8YO4v2SsbP/o/P2GA760/s72y4K6mEk9Bcc45XBOBbOrXs7MRkJno50snkrqL23mLIC3CSCWW0kA48Sub1ShK53tdGCSiRYtF67n5k/XhmJMElgYbosG2aG17CYBYx/GFDg5t5Kp3RfHMwLAOCXjCUH710L5FbYl+C+TQ9+LHdM3zCL9HBP3hM4m4oiOC+KvnxaUd6mM4wnhMAVklzdc6DeGF3NgRWlCJ32wpV9IvGSsDEjLubKe8Ju2ynxy9u5sg2ozOkFGa59PR3iQ1EkdRlGXqlq/FLW9orLTDUmf586pEcEs5QM6YXOUKoaUPiFNmgS95eC2SCgtmr4FAWHbxvfJYxyNQfd1wt7PKLz91Qlhh57C2SIvBhoJ8RMq8x6X5KY6AZpGpvAReeziD8xLvYzS9G/j37bU2gUhR1bd/CfgAxq29UreBNvMDNRbIDt43DKWHzQ7x4OxRYEoQ+CAQT9Hv5zp9VBZvfvf98rlScFL11Pshuc0LTUmW+bVnJvsc5yBCqZPfucms000bdBu4cr9CsNQsXVLPr0BwxIIa+yTyUMiBqJBffq1CEaGwv5CvGINvzgegPupwzMIslH3dd7G9U88+yUuEV2vDBXLwqmd7MVxnYNKH9PG52w4xwTXr7egzBx4Jz+BYlTbsSw7QljwdqgNTpY51K3+2NqmBAq977joddgBhpJHwdc5fVFlS9zPn5TgVmkdeRfPahdxYJ93mMb/GJWtVtUeEKG68/xlSgT0aaP6bFGrNiuvvhyuUDIo4QlJ6wrRhFSvA9Vfh6MMav7YgWrTS5XEw463bbhlxu2tJhUUJJuyN5Fr6zxdcqZucVKbbGw8/4wug9vexa4T1MqQ605E48sGJo9c7jDsnxuIZFgA/pDvVFiCKlmqc78J/P1V8Pon7BnyFm7uQyULOylR1itMIqSvH7cPzVppjK4su6vSxHuQclck/MUKEv1SqaF97osF+l2OHLMKMM+FwAkG0qhn2j9BRZ4rWKF/sKYBlqjjvi64GKWsSt29bw3i8WR3hRxvKVV48A+6OOwl5nvRW6vTAyhJ+ToiTFa7jOTPE487hj9mdhCza9RMJJOhmDk6vLedRvXY+VxBGiYdZIHDuDxjmmJzrTBAEjWJmEhGpDYvekEoqL4ldkaQ9PeRiQlq7V3SHl454Dn2Y2UFAZvAuLL9ESG9xqsyVmaoEC5s2OW1R6TohW5nhZi3CyUBn4Kkhvj6urd9GAYZwe6hQ8GMrydS/Tf34vR6EpifYcWsga3DnBdnCweoD6rtWBuO+FWuLz3bg3i+sefZCsqEPKT5JRyP4LGL6BuBUtuEeVyObRmHErdNeLf/f5az8sA8Qm0RjkizUqkUiXdrCV9ttLkaqpilh7flYyjAicBt24guyEZ/6HIepErrwBCOXzrLKm9Twon73PN6sYBfKi3roamODyrc/fbDcJbk5zKN9lLf9+KG2vw94tAKbGCqqEWX6TJ/kluhD//Mx0qg==")); \ No newline at end of file +var hprose=Object.create(null);hprose.global="object"==typeof global?global:"object"==typeof window?window:"object"==typeof self?self:this,function(e,t){"use strict";function r(e){if("function"!=typeof e)throw new TypeError(e+" is not a function");return function(t){return e.apply(t,Array.prototype.slice.call(arguments,1))}}function n(e){for(var t=e.length,r=new Array(t),n=0;n>15,i=new Array(r?n+1:n),o=0;o=0?n=i:(n=r+i)<0&&(n=0);for(var o;n>>0,i=arguments[1],o=0;o>>0,i=arguments[1],o=0;o>>0,n=arguments[1],i=n>>0,o=i<0?Math.max(r+i,0):Math.min(i,r),a=arguments[2],u=void 0===a?r:a>>0,s=u<0?Math.max(r+u,0):Math.min(u,r);o>>0,i=e>>0,o=i<0?Math.max(n+i,0):Math.min(i,n),a=t>>0,u=a<0?Math.max(n+a,0):Math.min(a,n),s=arguments[2],c=void 0===s?n:s>>0,f=c<0?Math.max(n+c,0):Math.min(c,n),l=Math.min(f-u,n-o),h=1;for(u0;)u in r?r[o]=r[u]:delete r[o],u+=h,o+=h,l--;return r}}),Array.from||Object.defineProperty(Array,"from",{value:function(){var e=Object.prototype.toString,t=function(t){return"function"==typeof t||"[object Function]"===e.call(t)},r=function(e){var t=Number(e);return isNaN(t)?0:0!==t&&isFinite(t)?(t>0?1:-1)*Math.floor(Math.abs(t)):t},n=Math.pow(2,53)-1,i=function(e){var t=r(e);return Math.min(Math.max(t,0),n)};return function(e){var r=this,n=Object(e);if(null===e||void 0===e)throw new TypeError("Array.from requires an array-like object - not null or undefined");var o,a=arguments.length>1?arguments[1]:void 0;if(void 0!==a){if(!t(a))throw new TypeError("Array.from: when provided, the second argument must be a function");arguments.length>2&&(o=arguments[2])}for(var u,s=i(n.length),c=t(r)?Object(new r(s)):new Array(s),f=0;fr.length)&&(t=r.length),t-=e.length;var n=r.indexOf(e,t);return-1!==n&&n===t}}),String.prototype.includes||Object.defineProperty(String.prototype,"includes",{value:function(){return"number"==typeof arguments[1]?!(this.length=1<<28)throw new RangeError("repeat count must not overflow maximum string size");for(var r="";1==(1&e)&&(r+=t),0!==(e>>>=1);)t+=t;return r}}),String.prototype.trim||Object.defineProperty(String.prototype,"trim",{value:function(){return this.toString().replace(/^[\s\xa0]+|[\s\xa0]+$/g,"")}}),String.prototype.trimLeft||Object.defineProperty(String.prototype,"trimLeft",{value:function(){return this.toString().replace(/^[\s\xa0]+/,"")}}),String.prototype.trimRight||Object.defineProperty(String.prototype,"trimRight",{value:function(){return this.toString().replace(/[\s\xa0]+$/,"")}}),Object.keys||Object.defineProperty(Object,"keys",{value:function(){var e=Object.prototype.hasOwnProperty,t=!{toString:null}.propertyIsEnumerable("toString"),r=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"],n=r.length;return function(i){if("object"!=typeof i&&"function"!=typeof i||null===i)throw new TypeError("Object.keys called on non-object");var o=[];for(var a in i)e.call(i,a)&&o.push(a);if(t)for(var u=0;u0&&Array.isArray(arguments[0]))for(var s=arguments[0],c=0,f=s.length;c0&&Array.isArray(arguments[0]))for(var o=arguments[0],a=0,f=o.length;a0&&Array.isArray(arguments[0]))for(var o=arguments[0],a=0,u=o.length;a0;)i(e.shift())}).observe(t,{characterData:!0}),function(){var r=o(arguments);return e.push(r),t.data=1&r,r}},s.messageChannel=function(){var t=new e.MessageChannel;return t.port1.onmessage=function(e){i(Number(e.data))},function(){var e=o(arguments);return t.port2.postMessage(e),e}},s.nextTick=function(){return function(){var t=o(arguments);return e.process.nextTick(r(i,t)),t}},s.postMessage=function(){var e=a.createElement("iframe");e.style.display="none",a.documentElement.appendChild(e);var t=e.contentWindow;t.document.write(''); + iwin.document.close(); + var queue = []; + window.addEventListener('message', function() { + while (queue.length > 0) { + run(queue.shift()); + } + }); + return function() { + var handleId = create(arguments); + queue.push(handleId); + iwin.postMessage(1, "*"); + return handleId; + }; + }; + + polifill.readyStateChange = function() { + var html = doc.documentElement; + + return function() { + var handleId = create(arguments); + var script = doc.createElement('script'); + + script.onreadystatechange = function() { + run(handleId); + script.onreadystatechange = null; + html.removeChild(script); + script = null; + }; + + html.appendChild(script); + + return handleId; + }; + }; + + // If supported, we should attach to the prototype of global, since that is where setTimeout et al. live. + var attachTo = Object.getPrototypeOf && Object.getPrototypeOf(global); + attachTo = (attachTo && attachTo.setTimeout ? attachTo : global); + + polifill.setTimeout = function() { + return function() { + var handleId = create(arguments); + attachTo.setTimeout( wrap( run, handleId ), 0 ); + return handleId; + }; + }; + + // Don't get fooled by e.g. browserify environments. + // For Node.js before 0.9 + if (typeof(global.process) !== 'undefined' && + Object.prototype.toString.call(global.process) === '[object process]' && + !global.process.browser) { + attachTo.setImmediate = polifill.nextTick(); + } + // For IE 6–9 + else if (doc && ('onreadystatechange' in doc.createElement('script'))) { + attachTo.setImmediate = polifill.readyStateChange(); + } + // For MutationObserver, where supported + else if (doc && MutationObserver) { + attachTo.setImmediate = polifill.mutationObserver(); + } + // For web workers, where supported + else if (global.MessageChannel) { + attachTo.setImmediate = polifill.messageChannel(); + } + // For non-IE modern browsers + else if (doc && 'postMessage' in global && 'addEventListener' in global) { + attachTo.setImmediate = polifill.postMessage(); + } + // For older browsers + else { + attachTo.setImmediate = polifill.setTimeout(); + } + + attachTo.clearImmediate = clear; +})(hprose.global); + +/**********************************************************\ +| | +| hprose | +| | +| Official WebSite: http://www.hprose.com/ | +| http://www.hprose.org/ | +| | +\**********************************************************/ + +/**********************************************************\ + * * + * Future.js * + * * + * hprose Future for HTML5. * + * * + * LastModified: Dec 5, 2016 * + * Author: Ma Bingyao * + * * +\**********************************************************/ + +(function (hprose, global, undefined) { + 'use strict'; + + var PENDING = 0; + var FULFILLED = 1; + var REJECTED = 2; + + var hasPromise = 'Promise' in global; + var setImmediate = global.setImmediate; + var setTimeout = global.setTimeout; + var clearTimeout = global.clearTimeout; + var TimeoutError = global.TimeoutError; + + var foreach = Array.prototype.forEach; + var slice = Array.prototype.slice; + + function Future(computation) { + var self = this; + Object.defineProperties(this, { + _subscribers: { value: [] }, + resolve: { value: this.resolve.bind(this) }, + reject: { value: this.reject.bind(this) } + }); + if (typeof computation === 'function') { + setImmediate(function() { + try { + self.resolve(computation()); + } + catch(e) { + self.reject(e); + } + }); + } + } + + function isFuture(obj) { + return obj instanceof Future; + } + + function toFuture(obj) { + return isFuture(obj) ? obj : value(obj); + } + + function isPromise(obj) { + return 'function' === typeof obj.then; + } + + function delayed(duration, value) { + var computation = (typeof value === 'function') ? + value : + function() { return value; }; + var future = new Future(); + setTimeout(function() { + try { + future.resolve(computation()); + } + catch(e) { + future.reject(e); + } + }, duration); + return future; + } + + function error(e) { + var future = new Future(); + future.reject(e); + return future; + } + + function value(v) { + var future = new Future(); + future.resolve(v); + return future; + } + + function sync(computation) { + try { + var result = computation(); + return value(result); + } + catch(e) { + return error(e); + } + } + + function promise(executor) { + var future = new Future(); + executor(future.resolve, future.reject); + return future; + } + + function arraysize(array) { + var size = 0; + foreach.call(array, function() { ++size; }); + return size; + } + + function all(array) { + return toFuture(array).then(function(array) { + var n = array.length; + var count = arraysize(array); + var result = new Array(n); + if (count === 0) { return result; } + var future = new Future(); + foreach.call(array, function(element, index) { + toFuture(element).then(function(value) { + result[index] = value; + if (--count === 0) { + future.resolve(result); + } + }, + future.reject); + }); + return future; + }); + } + + function join() { + return all(arguments); + } + + function race(array) { + return toFuture(array).then(function(array) { + var future = new Future(); + foreach.call(array, function(element) { + toFuture(element).fill(future); + }); + return future; + }); + } + + function any(array) { + return toFuture(array).then(function(array) { + var n = array.length; + var count = arraysize(array); + if (count === 0) { + throw new RangeError('any(): array must not be empty'); + } + var reasons = new Array(n); + var future = new Future(); + foreach.call(array, function(element, index) { + toFuture(element).then(future.resolve, function(e) { + reasons[index] = e; + if (--count === 0) { + future.reject(reasons); + } + }); + }); + return future; + }); + } + + function settle(array) { + return toFuture(array).then(function(array) { + var n = array.length; + var count = arraysize(array); + var result = new Array(n); + if (count === 0) { return result; } + var future = new Future(); + foreach.call(array, function(element, index) { + var f = toFuture(element); + f.complete(function() { + result[index] = f.inspect(); + if (--count === 0) { + future.resolve(result); + } + }); + }); + return future; + }); + } + + function attempt(handler/*, arg1, arg2, ... */) { + var thisArg = (function() { return this; })(); + var args = slice.call(arguments, 1); + return all(args).then(function(args) { + return handler.apply(thisArg, args); + }); + } + + function run(handler, thisArg/*, arg1, arg2, ... */) { + var args = slice.call(arguments, 2); + return all(args).then(function(args) { + return handler.apply(thisArg, args); + }); + } + + function isGenerator(obj) { + if (!obj) { + return false; + } + return 'function' == typeof obj.next && 'function' == typeof obj['throw']; + } + + function isGeneratorFunction(obj) { + if (!obj) { + return false; + } + var constructor = obj.constructor; + if (!constructor) { + return false; + } + if ('GeneratorFunction' === constructor.name || + 'GeneratorFunction' === constructor.displayName) { + return true; + } + return isGenerator(constructor.prototype); + } + + function getThunkCallback(future) { + return function(err, res) { + if (err instanceof Error) { + return future.reject(err); + } + if (arguments.length < 2) { + return future.resolve(err); + } + if (err === null || err === undefined) { + res = slice.call(arguments, 1); + } + else { + res = slice.call(arguments, 0); + } + if (res.length == 1) { + future.resolve(res[0]); + } + else { + future.resolve(res); + } + }; + } + + function thunkToPromise(fn) { + if (isGeneratorFunction(fn) || isGenerator(fn)) { + return co(fn); + } + var thisArg = (function() { return this; })(); + var future = new Future(); + fn.call(thisArg, getThunkCallback(future)); + return future; + } + + function thunkify(fn) { + return function() { + var args = slice.call(arguments, 0); + var thisArg = this; + var results = new Future(); + args.push(function() { + thisArg = this; + results.resolve(arguments); + }); + try { + fn.apply(this, args); + } + catch (err) { + results.resolve([err]); + } + return function(done) { + results.then(function(results) { + done.apply(thisArg, results); + }); + }; + }; + } + + function promisify(fn) { + return function() { + var args = slice.call(arguments, 0); + var future = new Future(); + args.push(getThunkCallback(future)); + try { + fn.apply(this, args); + } + catch (err) { + future.reject(err); + } + return future; + }; + } + + function toPromise(obj) { + if (isGeneratorFunction(obj) || isGenerator(obj)) { + return co(obj); + } + return toFuture(obj); + } + + function co(gen) { + var thisArg = (function() { return this; })(); + if (typeof gen === 'function') { + var args = slice.call(arguments, 1); + gen = gen.apply(thisArg, args); + } + + if (!gen || typeof gen.next !== 'function') { + return toFuture(gen); + } + + var future = new Future(); + + function onFulfilled(res) { + try { + next(gen.next(res)); + } + catch (e) { + future.reject(e); + } + } + + function onRejected(err) { + try { + next(gen['throw'](err)); + } + catch (e) { + future.reject(e); + } + } + + function next(ret) { + if (ret.done) { + future.resolve(ret.value); + } + else { + (('function' == typeof ret.value) ? + thunkToPromise(ret.value) : + toPromise(ret.value)).then(onFulfilled, onRejected); + } + } + + onFulfilled(); + + return future; + } + + function wrap(handler, thisArg) { + return function() { + thisArg = thisArg || this; + return all(arguments).then(function(args) { + var result = handler.apply(thisArg, args); + if (isGeneratorFunction(result) || isGenerator(result)) { + return co.call(thisArg, result); + } + return result; + }); + }; + } + + co.wrap = wrap; + + function forEach(array, callback, thisArg) { + thisArg = thisArg || (function() { return this; })(); + return all(array).then(function(array) { + return array.forEach(callback, thisArg); + }); + } + + function every(array, callback, thisArg) { + thisArg = thisArg || (function() { return this; })(); + return all(array).then(function(array) { + return array.every(callback, thisArg); + }); + } + + function some(array, callback, thisArg) { + thisArg = thisArg || (function() { return this; })(); + return all(array).then(function(array) { + return array.some(callback, thisArg); + }); + } + + function filter(array, callback, thisArg) { + thisArg = thisArg || (function() { return this; })(); + return all(array).then(function(array) { + return array.filter(callback, thisArg); + }); + } + + function map(array, callback, thisArg) { + thisArg = thisArg || (function() { return this; })(); + return all(array).then(function(array) { + return array.map(callback, thisArg); + }); + } + + function reduce(array, callback, initialValue) { + if (arguments.length > 2) { + return all(array).then(function(array) { + return toFuture(initialValue).then(function(value) { + return array.reduce(callback, value); + }); + }); + } + return all(array).then(function(array) { + return array.reduce(callback); + }); + } + + function reduceRight(array, callback, initialValue) { + if (arguments.length > 2) { + return all(array).then(function(array) { + return toFuture(initialValue).then(function(value) { + return array.reduceRight(callback, value); + }); + }); + } + return all(array).then(function(array) { + return array.reduceRight(callback); + }); + } + + function indexOf(array, searchElement, fromIndex) { + return all(array).then(function(array) { + return toFuture(searchElement).then(function(searchElement) { + return array.indexOf(searchElement, fromIndex); + }); + }); + } + + function lastIndexOf(array, searchElement, fromIndex) { + return all(array).then(function(array) { + return toFuture(searchElement).then(function(searchElement) { + if (fromIndex === undefined) { + fromIndex = array.length - 1; + } + return array.lastIndexOf(searchElement, fromIndex); + }); + }); + } + + function includes(array, searchElement, fromIndex) { + return all(array).then(function(array) { + return toFuture(searchElement).then(function(searchElement) { + return array.includes(searchElement, fromIndex); + }); + }); + } + + function find(array, predicate, thisArg) { + thisArg = thisArg || (function() { return this; })(); + return all(array).then(function(array) { + return array.find(predicate, thisArg); + }); + } + + function findIndex(array, predicate, thisArg) { + thisArg = thisArg || (function() { return this; })(); + return all(array).then(function(array) { + return array.findIndex(predicate, thisArg); + }); + } + + Object.defineProperties(Future, { + // port from Dart + delayed: { value: delayed }, + error: { value: error }, + sync: { value: sync }, + value: { value: value }, + // Promise compatible + all: { value: all }, + race: { value: race }, + resolve: { value: value }, + reject: { value: error }, + // extended methods + promise: { value: promise }, + isFuture: { value: isFuture }, + toFuture: { value: toFuture }, + isPromise: { value: isPromise }, + toPromise: { value: toPromise }, + join: { value: join }, + any: { value: any }, + settle: { value: settle }, + attempt: { value: attempt }, + run: { value: run }, + thunkify: { value: thunkify }, + promisify: { value: promisify }, + co: { value: co }, + wrap: { value: wrap }, + // for array + forEach: { value: forEach }, + every: { value: every }, + some: { value: some }, + filter: { value: filter }, + map: { value: map }, + reduce: { value: reduce }, + reduceRight: { value: reduceRight }, + indexOf: { value: indexOf }, + lastIndexOf: { value: lastIndexOf }, + includes: { value: includes }, + find: { value: find }, + findIndex: { value: findIndex } + }); + + function _call(callback, next, x) { + setImmediate(function() { + try { + var r = callback(x); + next.resolve(r); + } + catch(e) { + next.reject(e); + } + }); + } + + function _resolve(onfulfill, next, x) { + if (onfulfill) { + _call(onfulfill, next, x); + } + else { + next.resolve(x); + } + } + + function _reject(onreject, next, e) { + if (onreject) { + _call(onreject, next, e); + } + else { + next.reject(e); + } + } + + Object.defineProperties(Future.prototype, { + _value: { writable: true }, + _reason: { writable: true }, + _state: { value: PENDING, writable: true }, + resolve: { value: function(value) { + if (value === this) { + this.reject(new TypeError('Self resolution')); + return; + } + if (isFuture(value)) { + value.fill(this); + return; + } + if ((value !== null) && + (typeof value === 'object') || + (typeof value === 'function')) { + var then; + try { + then = value.then; + } + catch (e) { + this.reject(e); + return; + } + if (typeof then === 'function') { + var notrun = true; + try { + var self = this; + then.call(value, function(y) { + if (notrun) { + notrun = false; + self.resolve(y); + } + }, function(r) { + if (notrun) { + notrun = false; + self.reject(r); + } + }); + return; + } + catch (e) { + if (notrun) { + notrun = false; + this.reject(e); + } + } + return; + } + } + if (this._state === PENDING) { + this._state = FULFILLED; + this._value = value; + var subscribers = this._subscribers; + while (subscribers.length > 0) { + var subscriber = subscribers.shift(); + _resolve(subscriber.onfulfill, subscriber.next, value); + } + } + } }, + reject: { value: function(reason) { + if (this._state === PENDING) { + this._state = REJECTED; + this._reason = reason; + var subscribers = this._subscribers; + while (subscribers.length > 0) { + var subscriber = subscribers.shift(); + _reject(subscriber.onreject, subscriber.next, reason); + } + } + } }, + then: { value: function(onfulfill, onreject) { + if (typeof onfulfill !== 'function') { onfulfill = null; } + if (typeof onreject !== 'function') { onreject = null; } + var next = new Future(); + if (this._state === FULFILLED) { + _resolve(onfulfill, next, this._value); + } + else if (this._state === REJECTED) { + _reject(onreject, next, this._reason); + } + else { + this._subscribers.push({ + onfulfill: onfulfill, + onreject: onreject, + next: next + }); + } + return next; + } }, + done: { value: function(onfulfill, onreject) { + this.then(onfulfill, onreject).then(null, function(error) { + setImmediate(function() { throw error; }); + }); + } }, + inspect: { value: function() { + switch (this._state) { + case PENDING: return { state: 'pending' }; + case FULFILLED: return { state: 'fulfilled', value: this._value }; + case REJECTED: return { state: 'rejected', reason: this._reason }; + } + } }, + catchError: { value: function(onreject, test) { + if (typeof test === 'function') { + var self = this; + return this['catch'](function(e) { + if (test(e)) { + return self['catch'](onreject); + } + else { + throw e; + } + }); + } + return this['catch'](onreject); + } }, + 'catch': { value: function(onreject) { + return this.then(null, onreject); + } }, + fail: { value: function(onreject) { + this.done(null, onreject); + } }, + whenComplete: { value: function(action) { + return this.then( + function(v) { action(); return v; }, + function(e) { action(); throw e; } + ); + } }, + complete: { value: function(oncomplete) { + oncomplete = oncomplete || function(v) { return v; }; + return this.then(oncomplete, oncomplete); + } }, + always: { value: function(oncomplete) { + this.done(oncomplete, oncomplete); + } }, + fill: { value: function(future) { + this.then(future.resolve, future.reject); + } }, + timeout: { value: function(duration, reason) { + var future = new Future(); + var timeoutId = setTimeout(function() { + future.reject(reason || new TimeoutError('timeout')); + }, duration); + this.whenComplete(function() { clearTimeout(timeoutId); }) + .fill(future); + return future; + } }, + delay: { value: function(duration) { + var future = new Future(); + this.then(function(result) { + setTimeout(function() { + future.resolve(result); + }, duration); + }, + future.reject); + return future; + } }, + tap: { value: function(onfulfilledSideEffect, thisArg) { + return this.then(function(result) { + onfulfilledSideEffect.call(thisArg, result); + return result; + }); + } }, + spread: { value: function(onfulfilledArray, thisArg) { + return this.then(function(array) { + return onfulfilledArray.apply(thisArg, array); + }); + } }, + get: { value: function(key) { + return this.then(function(result) { + return result[key]; + }); + } }, + set: { value: function(key, value) { + return this.then(function(result) { + result[key] = value; + return result; + }); + } }, + apply: { value: function(method, args) { + args = args || []; + return this.then(function(result) { + return all(args).then(function(args) { + return result[method].apply(result, args); + }); + }); + } }, + call: { value: function(method) { + var args = slice.call(arguments, 1); + return this.then(function(result) { + return all(args).then(function(args) { + return result[method].apply(result, args); + }); + }); + } }, + bind: { value: function(method) { + var bindargs = slice.call(arguments); + if (Array.isArray(method)) { + for (var i = 0, n = method.length; i < n; ++i) { + bindargs[0] = method[i]; + this.bind.apply(this, bindargs); + } + return; + } + bindargs.shift(); + var self = this; + Object.defineProperty(this, method, { value: function() { + var args = slice.call(arguments); + return self.then(function(result) { + return all(bindargs.concat(args)).then(function(args) { + return result[method].apply(result, args); + }); + }); + } }); + return this; + } }, + forEach: { value: function(callback, thisArg) { + return forEach(this, callback, thisArg); + } }, + every: { value: function(callback, thisArg) { + return every(this, callback, thisArg); + } }, + some: { value: function(callback, thisArg) { + return some(this, callback, thisArg); + } }, + filter: { value: function(callback, thisArg) { + return filter(this, callback, thisArg); + } }, + map: { value: function(callback, thisArg) { + return map(this, callback, thisArg); + } }, + reduce: { value: function(callback, initialValue) { + if (arguments.length > 1) { + return reduce(this, callback, initialValue); + } + return reduce(this, callback); + } }, + reduceRight: { value: function(callback, initialValue) { + if (arguments.length > 1) { + return reduceRight(this, callback, initialValue); + } + return reduceRight(this, callback); + } }, + indexOf: { value: function(searchElement, fromIndex) { + return indexOf(this, searchElement, fromIndex); + } }, + lastIndexOf: { value: function(searchElement, fromIndex) { + return lastIndexOf(this, searchElement, fromIndex); + } }, + includes: { value: function(searchElement, fromIndex) { + return includes(this, searchElement, fromIndex); + } }, + find: { value: function(predicate, thisArg) { + return find(this, predicate, thisArg); + } }, + findIndex: { value: function(predicate, thisArg) { + return findIndex(this, predicate, thisArg); + } } + }); + + hprose.Future = Future; + + hprose.thunkify = thunkify; + hprose.promisify = promisify; + hprose.co = co; + hprose.co.wrap = hprose.wrap = wrap; + + function Completer() { + var future = new Future(); + Object.defineProperties(this, { + future: { value: future }, + complete: { value: future.resolve }, + completeError: { value: future.reject }, + isCompleted: { get: function() { + return ( future._state !== PENDING ); + } } + }); + } + + hprose.Completer = Completer; + + hprose.resolved = value; + + hprose.rejected = error; + + hprose.deferred = function() { + var self = new Future(); + return Object.create(null, { + promise: { value: self }, + resolve: { value: self.resolve }, + reject: { value: self.reject } + }); + }; + + if (hasPromise) { return; } + + function MyPromise(executor) { + Future.call(this); + executor(this.resolve, this.reject); + } + + MyPromise.prototype = Object.create(Future.prototype); + MyPromise.prototype.constructor = Future; + + Object.defineProperties(MyPromise, { + all: { value: all }, + race: { value: race }, + resolve: { value: value }, + reject: { value: error } + }); + + global.Promise = MyPromise; + +})(hprose, hprose.global); + +/**********************************************************\ +| | +| hprose | +| | +| Official WebSite: http://www.hprose.com/ | +| http://www.hprose.org/ | +| | +\**********************************************************/ + +/**********************************************************\ + * * + * BytesIO.js * + * * + * hprose BytesIO for HTML5. * + * * + * LastModified: Nov 18, 2016 * + * Author: Ma Bingyao * + * * +\**********************************************************/ + +(function (hprose, undefined) { + 'use strict'; + + var toBinaryString = hprose.toBinaryString; + + var _EMPTY_BYTES = new Uint8Array(0); + var _INIT_SIZE = 1024; + + function writeInt32BE(bytes, p, i) { + bytes[p++] = i >>> 24 & 0xFF; + bytes[p++] = i >>> 16 & 0xFF; + bytes[p++] = i >>> 8 & 0xFF; + bytes[p++] = i & 0xFF; + return p; + } + + function writeInt32LE(bytes, p, i) { + bytes[p++] = i & 0xFF; + bytes[p++] = i >>> 8 & 0xFF; + bytes[p++] = i >>> 16 & 0xFF; + bytes[p++] = i >>> 24 & 0xFF; + return p; + } + + function writeString(bytes, p, str) { + var n = str.length; + for (var i = 0; i < n; ++i) { + var codeUnit = str.charCodeAt(i); + if (codeUnit < 0x80) { + bytes[p++] = codeUnit; + } + else if (codeUnit < 0x800) { + bytes[p++] = 0xC0 | (codeUnit >> 6); + bytes[p++] = 0x80 | (codeUnit & 0x3F); + } + else if (codeUnit < 0xD800 || codeUnit > 0xDFFF) { + bytes[p++] = 0xE0 | (codeUnit >> 12); + bytes[p++] = 0x80 | ((codeUnit >> 6) & 0x3F); + bytes[p++] = 0x80 | (codeUnit & 0x3F); + } + else { + if (i + 1 < n) { + var nextCodeUnit = str.charCodeAt(i + 1); + if (codeUnit < 0xDC00 && 0xDC00 <= nextCodeUnit && nextCodeUnit <= 0xDFFF) { + var rune = (((codeUnit & 0x03FF) << 10) | (nextCodeUnit & 0x03FF)) + 0x010000; + bytes[p++] = 0xF0 | (rune >> 18); + bytes[p++] = 0x80 | ((rune >> 12) & 0x3F); + bytes[p++] = 0x80 | ((rune >> 6) & 0x3F); + bytes[p++] = 0x80 | (rune & 0x3F); + ++i; + continue; + } + } + throw new Error('Malformed string'); + } + } + return p; + } + + function readShortString(bytes, n) { + var charCodes = new Array(n); + var i = 0, off = 0; + for (var len = bytes.length; i < n && off < len; i++) { + var unit = bytes[off++]; + switch (unit >> 4) { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + charCodes[i] = unit; + break; + case 12: + case 13: + if (off < len) { + charCodes[i] = ((unit & 0x1F) << 6) | + (bytes[off++] & 0x3F); + break; + } + throw new Error('Unfinished UTF-8 octet sequence'); + case 14: + if (off + 1 < len) { + charCodes[i] = ((unit & 0x0F) << 12) | + ((bytes[off++] & 0x3F) << 6) | + (bytes[off++] & 0x3F); + break; + } + throw new Error('Unfinished UTF-8 octet sequence'); + case 15: + if (off + 2 < len) { + var rune = (((unit & 0x07) << 18) | + ((bytes[off++] & 0x3F) << 12) | + ((bytes[off++] & 0x3F) << 6) | + (bytes[off++] & 0x3F)) - 0x10000; + if (0 <= rune && rune <= 0xFFFFF) { + charCodes[i++] = (((rune >> 10) & 0x03FF) | 0xD800); + charCodes[i] = ((rune & 0x03FF) | 0xDC00); + break; + } + throw new Error('Character outside valid Unicode range: 0x' + rune.toString(16)); + } + throw new Error('Unfinished UTF-8 octet sequence'); + default: + throw new Error('Bad UTF-8 encoding 0x' + unit.toString(16)); + } + } + if (i < n) { + charCodes.length = i; + } + return [String.fromCharCode.apply(String, charCodes), off]; + } + + function readLongString(bytes, n) { + var buf = []; + var charCodes = new Array(0x8000); + var i = 0, off = 0; + for (var len = bytes.length; i < n && off < len; i++) { + var unit = bytes[off++]; + switch (unit >> 4) { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + charCodes[i] = unit; + break; + case 12: + case 13: + if (off < len) { + charCodes[i] = ((unit & 0x1F) << 6) | + (bytes[off++] & 0x3F); + break; + } + throw new Error('Unfinished UTF-8 octet sequence'); + case 14: + if (off + 1 < len) { + charCodes[i] = ((unit & 0x0F) << 12) | + ((bytes[off++] & 0x3F) << 6) | + (bytes[off++] & 0x3F); + break; + } + throw new Error('Unfinished UTF-8 octet sequence'); + case 15: + if (off + 2 < len) { + var rune = (((unit & 0x07) << 18) | + ((bytes[off++] & 0x3F) << 12) | + ((bytes[off++] & 0x3F) << 6) | + (bytes[off++] & 0x3F)) - 0x10000; + if (0 <= rune && rune <= 0xFFFFF) { + charCodes[i++] = (((rune >> 10) & 0x03FF) | 0xD800); + charCodes[i] = ((rune & 0x03FF) | 0xDC00); + break; + } + throw new Error('Character outside valid Unicode range: 0x' + rune.toString(16)); + } + throw new Error('Unfinished UTF-8 octet sequence'); + default: + throw new Error('Bad UTF-8 encoding 0x' + unit.toString(16)); + } + if (i >= 0x7FFF - 1) { + var size = i + 1; + charCodes.length = size; + buf.push(String.fromCharCode.apply(String, charCodes)); + n -= size; + i = -1; + } + } + if (i > 0) { + charCodes.length = i; + buf.push(String.fromCharCode.apply(String, charCodes)); + } + return [buf.join(''), off]; + } + + function readString(bytes, n) { + if (n === undefined || n === null || (n < 0)) { n = bytes.length; } + if (n === 0) { return ['', 0]; } + return ((n < 0xFFFF) ? + readShortString(bytes, n) : + readLongString(bytes, n)); + } + + function readStringAsBytes(bytes, n) { + if (n === undefined) { n = bytes.length; } + if (n === 0) { return [_EMPTY_BYTES, 0]; } + var i = 0, off = 0; + for (var len = bytes.length; i < n && off < len; i++) { + var unit = bytes[off++]; + switch (unit >> 4) { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + break; + case 12: + case 13: + if (off < len) { + off++; + break; + } + throw new Error('Unfinished UTF-8 octet sequence'); + case 14: + if (off + 1 < len) { + off += 2; + break; + } + throw new Error('Unfinished UTF-8 octet sequence'); + case 15: + if (off + 2 < len) { + var rune = (((unit & 0x07) << 18) | + ((bytes[off++] & 0x3F) << 12) | + ((bytes[off++] & 0x3F) << 6) | + (bytes[off++] & 0x3F)) - 0x10000; + if (0 <= rune && rune <= 0xFFFFF) { + i++; + break; + } + throw new Error('Character outside valid Unicode range: 0x' + rune.toString(16)); + } + throw new Error('Unfinished UTF-8 octet sequence'); + default: + throw new Error('Bad UTF-8 encoding 0x' + unit.toString(16)); + } + } + return [bytes.subarray(0, off), off]; + } + + function pow2roundup(x) { + --x; + x |= x >> 1; + x |= x >> 2; + x |= x >> 4; + x |= x >> 8; + x |= x >> 16; + return x + 1; + } + + function BytesIO() { + var a = arguments; + switch (a.length) { + case 1: + switch (a[0].constructor) { + case Uint8Array: + this._bytes = a[0]; + this._length = a[0].length; + break; + case BytesIO: + this._bytes = a[0].toBytes(); + this._length = a[0].length; + break; + case String: + this.writeString(a[0]); + break; + case Number: + this._bytes = new Uint8Array(a[0]); + break; + default: + this._bytes = new Uint8Array(a[0]); + this._length = this._bytes.length; + break; + } + break; + case 2: + this._bytes = new Uint8Array(a[0], a[1]); + this._length = a[1]; + break; + case 3: + this._bytes = new Uint8Array(a[0], a[1], a[2]); + this._length = a[2]; + break; + } + this.mark(); + } + + Object.defineProperties(BytesIO.prototype, { + _bytes: { value: null, writable: true }, + _length: { value: 0, writable: true }, + _wmark: { value: 0, writable: true }, + _off: { value: 0, writable: true }, + _rmark: { value: 0, writable: true }, + _grow: { value: function(n) { + var bytes = this._bytes; + var required = this._length + n; + var size = pow2roundup(required); + if (bytes) { + size *= 2; + if (size > bytes.length) { + var buf = new Uint8Array(size); + buf.set(bytes); + this._bytes = buf; + } + } + else { + size = Math.max(size, _INIT_SIZE); + this._bytes = new Uint8Array(size); + } + } }, + length: { get: function() { return this._length; } }, + capacity: { get: function() { + return this._bytes ? this._bytes.length : 0; + } }, + position: { get: function() { return this._off; } }, + // returns a view of the the internal buffer. + bytes: { get : function() { + return (this._bytes === null) ? + _EMPTY_BYTES : + this._bytes.subarray(0, this._length); + } }, + buffer: { get : function() { + if (this._bytes === null) { + return _EMPTY_BYTES.buffer; + } + if (this._bytes.buffer.slice) { + return this._bytes.buffer.slice(0, this._length); + } + var buf = new Uint8Array(this._length); + buf.set(this._bytes.subarray(0, this._length)); + return buf.buffer; + } }, + mark: { value: function() { + this._wmark = this._length; + this._rmark = this._off; + } }, + reset: { value: function() { + this._length = this._wmark; + this._off = this._rmark; + } }, + clear: { value: function() { + this._bytes = null; + this._length = 0; + this._wmark = 0; + this._off = 0; + this._rmark = 0; + } }, + writeByte: { value: function(b) { + this._grow(1); + this._bytes[this._length++] = b; + } }, + writeInt32BE: { value: function(i) { + if ((i === (i | 0)) && (i <= 2147483647)) { + this._grow(4); + this._length = writeInt32BE(this._bytes, this._length, i); + return; + } + throw new TypeError('value is out of bounds'); + } }, + writeUInt32BE: { value: function(i) { + if (((i & 0x7FFFFFFF) + 0x80000000 === i) && (i >= 0)) { + this._grow(4); + this._length = writeInt32BE(this._bytes, this._length, i | 0); + return; + } + throw new TypeError('value is out of bounds'); + } }, + writeInt32LE: { value: function(i) { + if ((i === (i | 0)) && (i <= 2147483647)) { + this._grow(4); + this._length = writeInt32LE(this._bytes, this._length, i); + return; + } + throw new TypeError('value is out of bounds'); + } }, + writeUInt32LE: { value: function(i) { + if (((i & 0x7FFFFFFF) + 0x80000000 === i) && (i >= 0)) { + this._grow(4); + this._length = writeInt32LE(this._bytes, this._length, i | 0); + return; + } + throw new TypeError('value is out of bounds'); + } }, + write: { value: function(data) { + var n = data.byteLength || data.length; + if (n === 0) { return; } + this._grow(n); + var bytes = this._bytes; + var length = this._length; + switch (data.constructor) { + case ArrayBuffer: + bytes.set(new Uint8Array(data), length); + break; + case Uint8Array: + bytes.set(data, length); + break; + case BytesIO: + bytes.set(data.bytes, length); + break; + default: + for (var i = 0; i < n; i++) { + bytes[length + i] = data[i]; + } + break; + } + this._length += n; + } }, + writeAsciiString: { value: function(str) { + var n = str.length; + if (n === 0) { return; } + this._grow(n); + var bytes = this._bytes; + var l = this._length; + for (var i = 0; i < n; ++i, ++l) { + bytes[l] = str.charCodeAt(i); + } + this._length = l; + } }, + writeString: { value: function(str) { + var n = str.length; + if (n === 0) { return; } + // A single code unit uses at most 3 bytes. + // Two code units at most 4. + this._grow(n * 3); + this._length = writeString(this._bytes, this._length, str); + } }, + readByte: { value: function() { + if (this._off < this._length) { + return this._bytes[this._off++]; + } + return -1; + } }, + readInt32BE: { value: function() { + var bytes = this._bytes; + var off = this._off; + if (off + 3 < this._length) { + var result = bytes[off++] << 24 | + bytes[off++] << 16 | + bytes[off++] << 8 | + bytes[off++]; + this._off = off; + return result; + } + throw new Error('EOF'); + } }, + readUInt32BE: { value: function() { + var value = this.readInt32BE(); + if (value < 0) { + return (value & 0x7FFFFFFF) + 0x80000000; + } + return value; + } }, + readInt32LE: { value: function() { + var bytes = this._bytes; + var off = this._off; + if (off + 3 < this._length) { + var result = bytes[off++] | + bytes[off++] << 8 | + bytes[off++] << 16 | + bytes[off++] << 24; + this._off = off; + return result; + } + throw new Error('EOF'); + } }, + readUInt32LE: { value: function() { + var value = this.readInt32LE(); + if (value < 0) { + return (value & 0x7FFFFFFF) + 0x80000000; + } + return value; + } }, + read: { value: function(n) { + if (this._off + n > this._length) { + n = this._length - this._off; + } + if (n === 0) { return _EMPTY_BYTES; } + return this._bytes.subarray(this._off, this._off += n); + } }, + skip: { value: function(n) { + if (this._off + n > this._length) { + n = this._length - this._off; + this._off = this._length; + } + else { + this._off += n; + } + return n; + } }, + // the result is an Uint8Array, and includes tag. + readBytes: { value: function(tag) { + var pos = Array.indexOf(this._bytes, tag, this._off); + var buf; + if (pos === -1) { + buf = this._bytes.subarray(this._off, this._length); + this._off = this._length; + } + else { + buf = this._bytes.subarray(this._off, pos + 1); + this._off = pos + 1; + } + return buf; + } }, + // the result is a String, and doesn't include tag. + // but the position is the same as readBytes + readUntil: { value: function(tag) { + var pos = Array.indexOf(this._bytes, tag, this._off); + var str = ''; + if (pos === this._off) { + this._off++; + } + else if (pos === -1) { + str = readString(this._bytes.subarray(this._off, this._length))[0]; + this._off = this._length; + } + else { + str = readString(this._bytes.subarray(this._off, pos))[0]; + this._off = pos + 1; + } + return str; + } }, + readAsciiString: { value: function(n) { + if (this._off + n > this._length) { + n = this._length - this._off; + } + if (n === 0) { return ''; } + return toBinaryString(this._bytes.subarray(this._off, this._off += n)); + } }, + // n is the UTF16 length + readStringAsBytes: { value: function(n) { + var r = readStringAsBytes(this._bytes.subarray(this._off, this._length), n); + this._off += r[1]; + return r[0]; + } }, + // n is the UTF16 length + readString: { value: function(n) { + var r = readString(this._bytes.subarray(this._off, this._length), n); + this._off += r[1]; + return r[0]; + } }, + // returns a view of the the internal buffer and clears `this`. + takeBytes: { value: function() { + var buffer = this.bytes; + this.clear(); + return buffer; + } }, + // returns a copy of the current contents and leaves `this` intact. + toBytes: { value: function() { + return new Uint8Array(this.bytes); + } }, + toString: { value: function() { + return readString(this.bytes, this._length)[0]; + } }, + clone: { value: function() { + return new BytesIO(this.toBytes()); + } }, + trunc: { value: function() { + this._bytes = this._bytes.subarray(this._off, this._length); + this._length = this._bytes.length; + this._off = 0; + this._wmark = 0; + this._rmark = 0; + } } + }); + + function toString(data) { + /* jshint -W086 */ + if (data.length === 0) { return ''; } + switch(data.constructor) { + case String: return data; + case BytesIO: data = data.bytes; + case ArrayBuffer: data = new Uint8Array(data); + case Uint8Array: return readString(data, data.length)[0]; + default: return String.fromCharCode.apply(String, data); + } + } + + Object.defineProperty(BytesIO, 'toString', { value: toString }); + + hprose.BytesIO = BytesIO; + +})(hprose); + +/**********************************************************\ +| | +| hprose | +| | +| Official WebSite: http://www.hprose.com/ | +| http://www.hprose.org/ | +| | +\**********************************************************/ +/**********************************************************\ + * * + * Tags.js * + * * + * hprose tags enum for HTML5. * + * * + * LastModified: Nov 18, 2016 * + * Author: Ma Bingyao * + * * +\**********************************************************/ + +(function (hprose) { + 'use strict'; + + hprose.Tags = { + /* Serialize Tags */ + TagInteger : 0x69, // 'i' + TagLong : 0x6C, // 'l' + TagDouble : 0x64, // 'd' + TagNull : 0x6E, // 'n' + TagEmpty : 0x65, // 'e' + TagTrue : 0x74, // 't' + TagFalse : 0x66, // 'f' + TagNaN : 0x4E, // 'N' + TagInfinity : 0x49, // 'I' + TagDate : 0x44, // 'D' + TagTime : 0x54, // 'T' + TagUTC : 0x5A, // 'Z' + TagBytes : 0x62, // 'b' + TagUTF8Char : 0x75, // 'u' + TagString : 0x73, // 's' + TagGuid : 0x67, // 'g' + TagList : 0x61, // 'a' + TagMap : 0x6d, // 'm' + TagClass : 0x63, // 'c' + TagObject : 0x6F, // 'o' + TagRef : 0x72, // 'r' + /* Serialize Marks */ + TagPos : 0x2B, // '+' + TagNeg : 0x2D, // '-' + TagSemicolon : 0x3B, // ',' + TagOpenbrace : 0x7B, // '{' + TagClosebrace : 0x7D, // '}' + TagQuote : 0x22, // '"' + TagPoint : 0x2E, // '.' + /* Protocol Tags */ + TagFunctions : 0x46, // 'F' + TagCall : 0x43, // 'C' + TagResult : 0x52, // 'R' + TagArgument : 0x41, // 'A' + TagError : 0x45, // 'E' + TagEnd : 0x7A // 'z' + }; +})(hprose); + +/**********************************************************\ +| | +| hprose | +| | +| Official WebSite: http://www.hprose.com/ | +| http://www.hprose.org/ | +| | +\**********************************************************/ + +/**********************************************************\ + * * + * ClassManager.js * + * * + * hprose ClassManager for HTML5. * + * * + * LastModified: Nov 18, 2016 * + * Author: Ma Bingyao * + * * +\**********************************************************/ + +(function (hprose, global) { + 'use strict'; + + var WeakMap = global.WeakMap; + + var classCache = Object.create(null); + var aliasCache = new WeakMap(); + + function register(cls, alias) { + aliasCache.set(cls, alias); + classCache[alias] = cls; + } + + function getClassAlias(cls) { + return aliasCache.get(cls); + } + + function getClass(alias) { + return classCache[alias]; + } + + hprose.ClassManager = Object.create(null, { + register: { value: register }, + getClassAlias: { value: getClassAlias }, + getClass: { value: getClass } + }); + + hprose.register = register; + + register(Object, 'Object'); + +})(hprose, hprose.global); + +/**********************************************************\ +| | +| hprose | +| | +| Official WebSite: http://www.hprose.com/ | +| http://www.hprose.org/ | +| | +\**********************************************************/ + +/**********************************************************\ + * * + * Writer.js * + * * + * hprose Writer for HTML5. * + * * + * LastModified: Feb 13, 2017 * + * Author: Ma Bingyao * + * * +\**********************************************************/ + +(function (hprose, global, undefined) { + 'use strict'; + + var Map = global.Map; + var BytesIO = hprose.BytesIO; + var Tags = hprose.Tags; + var ClassManager = hprose.ClassManager; + + function getClassName(obj) { + var cls = obj.constructor; + if (!cls) { + return 'Object'; + } + var classname = ClassManager.getClassAlias(cls); + if (classname) { return classname; } + if (cls.name) { + classname = cls.name; + } + else { + var ctor = cls.toString(); + classname = ctor.substr(0, ctor.indexOf('(')).replace(/(^\s*function\s*)|(\s*$)/ig, ''); + if (classname === '' || classname === 'Object') { + return (typeof(obj.getClassName) === 'function') ? obj.getClassName() : 'Object'; + } + } + if (classname !== 'Object') { + ClassManager.register(cls, classname); + } + return classname; + } + + var fakeWriterRefer = Object.create(null, { + set: { value: function () {} }, + write: { value: function () { return false; } }, + reset: { value: function () {} } + }); + + function RealWriterRefer(stream) { + Object.defineProperties(this, { + _stream: { value: stream }, + _ref: { value: new Map(), writable: true } + }); + } + + Object.defineProperties(RealWriterRefer.prototype, { + _refcount: { value: 0, writable: true }, + set: { value: function (val) { + this._ref.set(val, this._refcount++); + } }, + write: { value: function (val) { + var index = this._ref.get(val); + if (index !== undefined) { + this._stream.writeByte(Tags.TagRef); + this._stream.writeString('' + index); + this._stream.writeByte(Tags.TagSemicolon); + return true; + } + return false; + } }, + reset: { value: function () { + this._ref = new Map(); + this._refcount = 0; + } } + }); + + function realWriterRefer(stream) { + return new RealWriterRefer(stream); + } + + function Writer(stream, simple) { + Object.defineProperties(this, { + stream: { value: stream }, + _classref: { value: Object.create(null), writable: true }, + _fieldsref: { value: [], writable: true }, + _refer: { value: simple ? fakeWriterRefer : realWriterRefer(stream) } + }); + } + + function serialize(writer, value) { + var stream = writer.stream; + if (value === undefined || value === null) { + stream.writeByte(Tags.TagNull); + return; + } + switch (value.constructor) { + case Function: + stream.writeByte(Tags.TagNull); + return; + case Number: + writeNumber(writer, value); + return; + case Boolean: + writeBoolean(writer, value); + return; + case String: + switch (value.length) { + case 0: + stream.writeByte(Tags.TagEmpty); + return; + case 1: + stream.writeByte(Tags.TagUTF8Char); + stream.writeString(value); + return; + } + writer.writeStringWithRef(value); + return; + case Date: + writer.writeDateWithRef(value); + return; + case Map: + writer.writeMapWithRef(value); + return; + case ArrayBuffer: + case Uint8Array: + case BytesIO: + writer.writeBytesWithRef(value); + return; + case Int8Array: + case Int16Array: + case Int32Array: + case Uint16Array: + case Uint32Array: + writeIntListWithRef(writer, value); + return; + case Float32Array: + case Float64Array: + writeDoubleListWithRef(writer, value); + return; + default: + if (Array.isArray(value)) { + writer.writeListWithRef(value); + } + else { + var classname = getClassName(value); + if (classname === 'Object') { + writer.writeMapWithRef(value); + } + else { + writer.writeObjectWithRef(value); + } + } + break; + } + } + + function writeNumber(writer, n) { + var stream = writer.stream; + n = n.valueOf(); + if (n === (n | 0)) { + if (0 <= n && n <= 9) { + stream.writeByte(n + 0x30); + } + else { + stream.writeByte(Tags.TagInteger); + stream.writeAsciiString('' + n); + stream.writeByte(Tags.TagSemicolon); + } + } + else if (isNaN(n)) { + stream.writeByte(Tags.TagNaN); + } + else if (isFinite(n)) { + stream.writeByte(Tags.TagDouble); + stream.writeAsciiString('' + n); + stream.writeByte(Tags.TagSemicolon); + } + else { + stream.writeByte(Tags.TagInfinity); + stream.writeByte((n > 0) ? Tags.TagPos : Tags.TagNeg); + } + } + + function writeInteger(writer, n) { + var stream = writer.stream; + if (0 <= n && n <= 9) { + stream.writeByte(n + 0x30); + } + else { + if (n < -2147483648 || n > 2147483647) { + stream.writeByte(Tags.TagLong); + } + else { + stream.writeByte(Tags.TagInteger); + } + stream.writeAsciiString('' + n); + stream.writeByte(Tags.TagSemicolon); + } + } + + function writeDouble(writer, n) { + var stream = writer.stream; + if (isNaN(n)) { + stream.writeByte(Tags.TagNaN); + } + else if (isFinite(n)) { + stream.writeByte(Tags.TagDouble); + stream.writeAsciiString('' + n); + stream.writeByte(Tags.TagSemicolon); + } + else { + stream.writeByte(Tags.TagInfinity); + stream.writeByte((n > 0) ? Tags.TagPos : Tags.TagNeg); + } + } + + function writeBoolean(writer, b) { + writer.stream.writeByte(b.valueOf() ? Tags.TagTrue : Tags.TagFalse); + } + + function writeUTCDate(writer, date) { + writer._refer.set(date); + var stream = writer.stream; + var year = ('0000' + date.getUTCFullYear()).slice(-4); + var month = ('00' + (date.getUTCMonth() + 1)).slice(-2); + var day = ('00' + date.getUTCDate()).slice(-2); + var hour = ('00' + date.getUTCHours()).slice(-2); + var minute = ('00' + date.getUTCMinutes()).slice(-2); + var second = ('00' + date.getUTCSeconds()).slice(-2); + var millisecond = ('000' + date.getUTCMilliseconds()).slice(-3); + stream.writeByte(Tags.TagDate); + stream.writeAsciiString(year + month + day); + stream.writeByte(Tags.TagTime); + stream.writeAsciiString(hour + minute + second); + if (millisecond !== '000') { + stream.writeByte(Tags.TagPoint); + stream.writeAsciiString(millisecond); + } + stream.writeByte(Tags.TagUTC); + } + + function writeDate(writer, date) { + writer._refer.set(date); + var stream = writer.stream; + var year = ('0000' + date.getFullYear()).slice(-4); + var month = ('00' + (date.getMonth() + 1)).slice(-2); + var day = ('00' + date.getDate()).slice(-2); + var hour = ('00' + date.getHours()).slice(-2); + var minute = ('00' + date.getMinutes()).slice(-2); + var second = ('00' + date.getSeconds()).slice(-2); + var millisecond = ('000' + date.getMilliseconds()).slice(-3); + if ((hour === '00') && (minute === '00') && + (second === '00') && (millisecond === '000')) { + stream.writeByte(Tags.TagDate); + stream.writeAsciiString(year + month + day); + } + else if ((year === '1970') && (month === '01') && (day === '01')) { + stream.writeByte(Tags.TagTime); + stream.writeAsciiString(hour + minute + second); + if (millisecond !== '000') { + stream.writeByte(Tags.TagPoint); + stream.writeAsciiString(millisecond); + } + } + else { + stream.writeByte(Tags.TagDate); + stream.writeAsciiString(year + month + day); + stream.writeByte(Tags.TagTime); + stream.writeAsciiString(hour + minute + second); + if (millisecond !== '000') { + stream.writeByte(Tags.TagPoint); + stream.writeAsciiString(millisecond); + } + } + stream.writeByte(Tags.TagSemicolon); + } + + function writeTime(writer, time) { + writer._refer.set(time); + var stream = writer.stream; + var hour = ('00' + time.getHours()).slice(-2); + var minute = ('00' + time.getMinutes()).slice(-2); + var second = ('00' + time.getSeconds()).slice(-2); + var millisecond = ('000' + time.getMilliseconds()).slice(-3); + stream.writeByte(Tags.TagTime); + stream.writeAsciiString(hour + minute + second); + if (millisecond !== '000') { + stream.writeByte(Tags.TagPoint); + stream.writeAsciiString(millisecond); + } + stream.writeByte(Tags.TagSemicolon); + } + + function writeBytes(writer, bytes) { + writer._refer.set(bytes); + var stream = writer.stream; + stream.writeByte(Tags.TagBytes); + var n = bytes.byteLength || bytes.length; + if (n > 0) { + stream.writeAsciiString('' + n); + stream.writeByte(Tags.TagQuote); + stream.write(bytes); + } + else { + stream.writeByte(Tags.TagQuote); + } + stream.writeByte(Tags.TagQuote); + } + + function writeString(writer, str) { + writer._refer.set(str); + var stream = writer.stream; + var n = str.length; + stream.writeByte(Tags.TagString); + if (n > 0) { + stream.writeAsciiString('' + n); + stream.writeByte(Tags.TagQuote); + stream.writeString(str); + } + else { + stream.writeByte(Tags.TagQuote); + } + stream.writeByte(Tags.TagQuote); + } + + function writeArray(writer, array, writeElem) { + writer._refer.set(array); + var stream = writer.stream; + var n = array.length; + stream.writeByte(Tags.TagList); + if (n > 0) { + stream.writeAsciiString('' + n); + stream.writeByte(Tags.TagOpenbrace); + for (var i = 0; i < n; i++) { + writeElem(writer, array[i]); + } + } + else { + stream.writeByte(Tags.TagOpenbrace); + } + stream.writeByte(Tags.TagClosebrace); + } + + function writeIntListWithRef(writer, list) { + if (!writer._refer.write(list)) { + writeArray(writer, list, writeInteger); + } + } + + function writeDoubleListWithRef(writer, list) { + if (!writer._refer.write(list)) { + writeArray(writer, list, writeDouble); + } + } + + function writeMap(writer, map) { + writer._refer.set(map); + var stream = writer.stream; + var fields = []; + for (var key in map) { + if (map.hasOwnProperty(key) && + typeof(map[key]) !== 'function') { + fields[fields.length] = key; + } + } + var n = fields.length; + stream.writeByte(Tags.TagMap); + if (n > 0) { + stream.writeAsciiString('' + n); + stream.writeByte(Tags.TagOpenbrace); + for (var i = 0; i < n; i++) { + serialize(writer, fields[i]); + serialize(writer, map[fields[i]]); + } + } + else { + stream.writeByte(Tags.TagOpenbrace); + } + stream.writeByte(Tags.TagClosebrace); + } + + function writeHarmonyMap(writer, map) { + writer._refer.set(map); + var stream = writer.stream; + var n = map.size; + stream.writeByte(Tags.TagMap); + if (n > 0) { + stream.writeAsciiString('' + n); + stream.writeByte(Tags.TagOpenbrace); + map.forEach(function(value, key) { + serialize(writer, key); + serialize(writer, value); + }); + } + else { + stream.writeByte(Tags.TagOpenbrace); + } + stream.writeByte(Tags.TagClosebrace); + } + + function writeObject(writer, obj) { + var stream = writer.stream; + var classname = getClassName(obj); + var fields, index; + if (classname in writer._classref) { + index = writer._classref[classname]; + fields = writer._fieldsref[index]; + } + else { + fields = []; + for (var key in obj) { + if (obj.hasOwnProperty(key) && + typeof(obj[key]) !== 'function') { + fields[fields.length] = key.toString(); + } + } + index = writeClass(writer, classname, fields); + } + stream.writeByte(Tags.TagObject); + stream.writeAsciiString('' + index); + stream.writeByte(Tags.TagOpenbrace); + writer._refer.set(obj); + var n = fields.length; + for (var i = 0; i < n; i++) { + serialize(writer, obj[fields[i]]); + } + stream.writeByte(Tags.TagClosebrace); + } + + function writeClass(writer, classname, fields) { + var stream = writer.stream; + var n = fields.length; + stream.writeByte(Tags.TagClass); + stream.writeAsciiString('' + classname.length); + stream.writeByte(Tags.TagQuote); + stream.writeString(classname); + stream.writeByte(Tags.TagQuote); + if (n > 0) { + stream.writeAsciiString('' + n); + stream.writeByte(Tags.TagOpenbrace); + for (var i = 0; i < n; i++) { + writeString(writer, fields[i]); + } + } + else { + stream.writeByte(Tags.TagOpenbrace); + } + stream.writeByte(Tags.TagClosebrace); + var index = writer._fieldsref.length; + writer._classref[classname] = index; + writer._fieldsref[index] = fields; + return index; + } + + Object.defineProperties(Writer.prototype, { + serialize: { value: function(value) { + serialize(this, value); + } }, + writeInteger: { value: function(value) { + writeInteger(this, value); + } }, + writeDouble: { value: function(value) { + writeDouble(this, value); + } }, + writeBoolean: { value: function(value) { + writeBoolean(this, value); + } }, + writeUTCDate: { value: function(value) { + writeUTCDate(this, value); + } }, + writeUTCDateWithRef: { value: function(value) { + if (!this._refer.write(value)) { + writeUTCDate(this, value); + } + } }, + writeDate: { value: function(value) { + writeDate(this, value); + } }, + writeDateWithRef: { value: function(value) { + if (!this._refer.write(value)) { + writeDate(this, value); + } + } }, + writeTime: { value: function(value) { + writeTime(this, value); + } }, + writeTimeWithRef: { value: function(value) { + if (!this._refer.write(value)) { + writeTime(this, value); + } + } }, + writeBytes: { value: function(value) { + writeBytes(this, value); + } }, + writeBytesWithRef: { value: function(value) { + if (!this._refer.write(value)) { + writeBytes(this, value); + } + } }, + writeString: { value: function(value) { + writeString(this, value); + } }, + writeStringWithRef: { value: function(value) { + if (!this._refer.write(value)) { + writeString(this, value); + } + } }, + writeList: { value: function(value) { + writeArray(this, value, serialize); + } }, + writeListWithRef: { value: function(value) { + if (!this._refer.write(value)) { + writeArray(this, value, serialize); + } + } }, + writeMap: { value: function(value) { + if (value instanceof Map) { + writeHarmonyMap(this, value); + } + else { + writeMap(this, value); + } + } }, + writeMapWithRef: { value: function(value) { + if (!this._refer.write(value)) { + if (value instanceof Map) { + writeHarmonyMap(this, value); + } + else { + writeMap(this, value); + } + } + } }, + writeObject: { value: function(value) { + writeObject(this, value); + } }, + writeObjectWithRef: { value: function(value) { + if (!this._refer.write(value)) { + writeObject(this, value); + } + } }, + reset: { value: function() { + this._classref = Object.create(null); + this._fieldsref.length = 0; + this._refer.reset(); + } } + }); + + hprose.Writer = Writer; + +})(hprose, hprose.global); + +/**********************************************************\ +| | +| hprose | +| | +| Official WebSite: http://www.hprose.com/ | +| http://www.hprose.org/ | +| | +\**********************************************************/ + +/**********************************************************\ + * * + * Reader.js * + * * + * hprose Reader for HTML5. * + * * + * LastModified: Nov 18, 2016 * + * Author: Ma Bingyao * + * * +\**********************************************************/ + +(function (hprose, global, undefined) { + 'use strict'; + + var Map = global.Map; + var BytesIO = hprose.BytesIO; + var Tags = hprose.Tags; + var ClassManager = hprose.ClassManager; + + function unexpectedTag(tag, expectTags) { + if (tag && expectTags) { + var expectTagStr = ''; + if (typeof(expectTags) === 'number') { + expectTagStr = String.fromCharCode(expectTags); + } + else { + expectTagStr = String.fromCharCode.apply(String, expectTags); + } + throw new Error('Tag "' + expectTagStr + '" expected, but "' + String.fromCharCode(tag) + '" found in stream'); + } + else if (tag) { + throw new Error('Unexpected serialize tag "' + String.fromCharCode(tag) + '" in stream'); + } + else { + throw new Error('No byte found in stream'); + } + } + + function readRaw(stream) { + var ostream = new BytesIO(); + _readRaw(stream, ostream); + return ostream.bytes; + } + + function _readRaw(stream, ostream) { + __readRaw(stream, ostream, stream.readByte()); + } + + function __readRaw(stream, ostream, tag) { + ostream.writeByte(tag); + switch (tag) { + case 48: + case 49: + case 50: + case 51: + case 52: + case 53: + case 54: + case 55: + case 56: + case 57: + case Tags.TagNull: + case Tags.TagEmpty: + case Tags.TagTrue: + case Tags.TagFalse: + case Tags.TagNaN: + break; + case Tags.TagInfinity: + ostream.writeByte(stream.readByte()); + break; + case Tags.TagInteger: + case Tags.TagLong: + case Tags.TagDouble: + case Tags.TagRef: + readNumberRaw(stream, ostream); + break; + case Tags.TagDate: + case Tags.TagTime: + readDateTimeRaw(stream, ostream); + break; + case Tags.TagUTF8Char: + readUTF8CharRaw(stream, ostream); + break; + case Tags.TagBytes: + readBytesRaw(stream, ostream); + break; + case Tags.TagString: + readStringRaw(stream, ostream); + break; + case Tags.TagGuid: + readGuidRaw(stream, ostream); + break; + case Tags.TagList: + case Tags.TagMap: + case Tags.TagObject: + readComplexRaw(stream, ostream); + break; + case Tags.TagClass: + readComplexRaw(stream, ostream); + _readRaw(stream, ostream); + break; + case Tags.TagError: + _readRaw(stream, ostream); + break; + default: unexpectedTag(tag); + } + } + function readNumberRaw(stream, ostream) { + var tag; + do { + tag = stream.readByte(); + ostream.writeByte(tag); + } while (tag !== Tags.TagSemicolon); + } + function readDateTimeRaw(stream, ostream) { + var tag; + do { + tag = stream.readByte(); + ostream.writeByte(tag); + } while (tag !== Tags.TagSemicolon && + tag !== Tags.TagUTC); + } + function readUTF8CharRaw(stream, ostream) { + ostream.writeString(stream.readString(1)); + } + function readBytesRaw(stream, ostream) { + var count = 0; + var tag = 48; + do { + count *= 10; + count += tag - 48; + tag = stream.readByte(); + ostream.writeByte(tag); + } while (tag !== Tags.TagQuote); + ostream.write(stream.read(count + 1)); + } + function readStringRaw(stream, ostream) { + var count = 0; + var tag = 48; + do { + count *= 10; + count += tag - 48; + tag = stream.readByte(); + ostream.writeByte(tag); + } while (tag !== Tags.TagQuote); + ostream.write(stream.readStringAsBytes(count + 1)); + } + function readGuidRaw(stream, ostream) { + ostream.write(stream.read(38)); + } + function readComplexRaw(stream, ostream) { + var tag; + do { + tag = stream.readByte(); + ostream.writeByte(tag); + } while (tag !== Tags.TagOpenbrace); + while ((tag = stream.readByte()) !== Tags.TagClosebrace) { + __readRaw(stream, ostream, tag); + } + ostream.writeByte(tag); + } + + function RawReader(stream) { + Object.defineProperties(this, { + stream: { value : stream }, + readRaw: { value: function() { return readRaw(stream); } } + }); + } + + hprose.RawReader = RawReader; + + var fakeReaderRefer = Object.create(null, { + set: { value: function() {} }, + read: { value: function() { unexpectedTag(Tags.TagRef); } }, + reset: { value: function() {} } + }); + + function RealReaderRefer() { + Object.defineProperties(this, { + ref: { value: [] } + }); + } + + Object.defineProperties(RealReaderRefer.prototype, { + set: { value: function(val) { this.ref.push(val); } }, + read: { value: function(index) { return this.ref[index]; } }, + reset: { value: function() { this.ref.length = 0; } } + }); + + function realReaderRefer() { + return new RealReaderRefer(); + } + + function getter(str) { + var obj = global; + var names = str.split('.'); + var i; + for (i = 0; i < names.length; i++) { + obj = obj[names[i]]; + if (obj === undefined) { + return null; + } + } + return obj; + } + function findClass(cn, poslist, i, c) { + if (i < poslist.length) { + var pos = poslist[i]; + cn[pos] = c; + var cls = findClass(cn, poslist, i + 1, '.'); + if (i + 1 < poslist.length) { + if (cls === null) { + cls = findClass(cn, poslist, i + 1, '_'); + } + } + return cls; + } + var classname = cn.join(''); + try { + var cl = getter(classname); + return ((typeof(cl) === 'function') ? cl : null); + } catch (e) { + return null; + } + } + + function getClass(classname) { + var cls = ClassManager.getClass(classname); + if (cls) { return cls; } + cls = getter(classname); + if (typeof(cls) === 'function') { + ClassManager.register(cls, classname); + return cls; + } + var poslist = []; + var pos = classname.indexOf('_'); + while (pos >= 0) { + poslist[poslist.length] = pos; + pos = classname.indexOf('_', pos + 1); + } + if (poslist.length > 0) { + var cn = classname.split(''); + cls = findClass(cn, poslist, 0, '.'); + if (cls === null) { + cls = findClass(cn, poslist, 0, '_'); + } + if (typeof(cls) === 'function') { + ClassManager.register(cls, classname); + return cls; + } + } + cls = function () {}; + Object.defineProperty(cls.prototype, 'getClassName', { value: function () { + return classname; + }}); + ClassManager.register(cls, classname); + return cls; + } + + + function readInt(stream, tag) { + var s = stream.readUntil(tag); + if (s.length === 0) { return 0; } + return parseInt(s, 10); + } + function unserialize(reader) { + var stream = reader.stream; + var tag = stream.readByte(); + switch (tag) { + case 48: + case 49: + case 50: + case 51: + case 52: + case 53: + case 54: + case 55: + case 56: + case 57: return tag - 48; + case Tags.TagInteger: return readIntegerWithoutTag(stream); + case Tags.TagLong: return readLongWithoutTag(stream); + case Tags.TagDouble: return readDoubleWithoutTag(stream); + case Tags.TagNull: return null; + case Tags.TagEmpty: return ''; + case Tags.TagTrue: return true; + case Tags.TagFalse: return false; + case Tags.TagNaN: return NaN; + case Tags.TagInfinity: return readInfinityWithoutTag(stream); + case Tags.TagDate: return readDateWithoutTag(reader); + case Tags.TagTime: return readTimeWithoutTag(reader); + case Tags.TagBytes: return readBytesWithoutTag(reader); + case Tags.TagUTF8Char: return readUTF8CharWithoutTag(reader); + case Tags.TagString: return readStringWithoutTag(reader); + case Tags.TagGuid: return readGuidWithoutTag(reader); + case Tags.TagList: return readListWithoutTag(reader); + case Tags.TagMap: return reader.useHarmonyMap ? readHarmonyMapWithoutTag(reader) : readMapWithoutTag(reader); + case Tags.TagClass: readClass(reader); return readObject(reader); + case Tags.TagObject: return readObjectWithoutTag(reader); + case Tags.TagRef: return readRef(reader); + case Tags.TagError: throw new Error(readString(reader)); + default: unexpectedTag(tag); + } + } + function readIntegerWithoutTag(stream) { + return readInt(stream, Tags.TagSemicolon); + } + function readInteger(stream) { + var tag = stream.readByte(); + switch (tag) { + case 48: + case 49: + case 50: + case 51: + case 52: + case 53: + case 54: + case 55: + case 56: + case 57: return tag - 48; + case Tags.TagInteger: return readIntegerWithoutTag(stream); + default: unexpectedTag(tag); + } + } + function readLongWithoutTag(stream) { + var s = stream.readUntil(Tags.TagSemicolon); + var l = parseInt(s, 10); + if (l.toString() === s) { return l; } + return s; + } + function readLong(stream) { + var tag = stream.readByte(); + switch (tag) { + case 48: + case 49: + case 50: + case 51: + case 52: + case 53: + case 54: + case 55: + case 56: + case 57: return tag - 48; + case Tags.TagInteger: + case Tags.TagLong: return readLongWithoutTag(stream); + default: unexpectedTag(tag); + } + } + function readDoubleWithoutTag(stream) { + return parseFloat(stream.readUntil(Tags.TagSemicolon)); + } + function readDouble(stream) { + var tag = stream.readByte(); + switch (tag) { + case 48: + case 49: + case 50: + case 51: + case 52: + case 53: + case 54: + case 55: + case 56: + case 57: return tag - 48; + case Tags.TagInteger: + case Tags.TagLong: + case Tags.TagDouble: return readDoubleWithoutTag(stream); + case Tags.TagNaN: return NaN; + case Tags.TagInfinity: return readInfinityWithoutTag(stream); + default: unexpectedTag(tag); + } + } + function readInfinityWithoutTag(stream) { + return ((stream.readByte() === Tags.TagNeg) ? -Infinity : Infinity); + } + function readBoolean(stream) { + var tag = stream.readByte(); + switch (tag) { + case Tags.TagTrue: return true; + case Tags.TagFalse: return false; + default: unexpectedTag(tag); + } + } + function readDateWithoutTag(reader) { + var stream = reader.stream; + var year = parseInt(stream.readAsciiString(4), 10); + var month = parseInt(stream.readAsciiString(2), 10) - 1; + var day = parseInt(stream.readAsciiString(2), 10); + var date; + var tag = stream.readByte(); + if (tag === Tags.TagTime) { + var hour = parseInt(stream.readAsciiString(2), 10); + var minute = parseInt(stream.readAsciiString(2), 10); + var second = parseInt(stream.readAsciiString(2), 10); + var millisecond = 0; + tag = stream.readByte(); + if (tag === Tags.TagPoint) { + millisecond = parseInt(stream.readAsciiString(3), 10); + tag = stream.readByte(); + if ((tag >= 48) && (tag <= 57)) { + stream.skip(2); + tag = stream.readByte(); + if ((tag >= 48) && (tag <= 57)) { + stream.skip(2); + tag = stream.readByte(); + } + } + } + if (tag === Tags.TagUTC) { + date = new Date(Date.UTC(year, month, day, hour, minute, second, millisecond)); + } + else { + date = new Date(year, month, day, hour, minute, second, millisecond); + } + } + else if (tag === Tags.TagUTC) { + date = new Date(Date.UTC(year, month, day)); + } + else { + date = new Date(year, month, day); + } + reader.refer.set(date); + return date; + } + function readDate(reader) { + var tag = reader.stream.readByte(); + switch (tag) { + case Tags.TagNull: return null; + case Tags.TagDate: return readDateWithoutTag(reader); + case Tags.TagRef: return readRef(reader); + default: unexpectedTag(tag); + } + } + function readTimeWithoutTag(reader) { + var stream = reader.stream; + var time; + var hour = parseInt(stream.readAsciiString(2), 10); + var minute = parseInt(stream.readAsciiString(2), 10); + var second = parseInt(stream.readAsciiString(2), 10); + var millisecond = 0; + var tag = stream.readByte(); + if (tag === Tags.TagPoint) { + millisecond = parseInt(stream.readAsciiString(3), 10); + tag = stream.readByte(); + if ((tag >= 48) && (tag <= 57)) { + stream.skip(2); + tag = stream.readByte(); + if ((tag >= 48) && (tag <= 57)) { + stream.skip(2); + tag = stream.readByte(); + } + } + } + if (tag === Tags.TagUTC) { + time = new Date(Date.UTC(1970, 0, 1, hour, minute, second, millisecond)); + } + else { + time = new Date(1970, 0, 1, hour, minute, second, millisecond); + } + reader.refer.set(time); + return time; + } + function readTime(reader) { + var tag = reader.stream.readByte(); + switch (tag) { + case Tags.TagNull: return null; + case Tags.TagTime: return readTimeWithoutTag(reader); + case Tags.TagRef: return readRef(reader); + default: unexpectedTag(tag); + } + } + function readBytesWithoutTag(reader) { + var stream = reader.stream; + var count = readInt(stream, Tags.TagQuote); + var bytes = stream.read(count); + stream.skip(1); + reader.refer.set(bytes); + return bytes; + } + function readBytes(reader) { + var tag = reader.stream.readByte(); + switch (tag) { + case Tags.TagNull: return null; + case Tags.TagEmpty: return new Uint8Array(0); + case Tags.TagBytes: return readBytesWithoutTag(reader); + case Tags.TagRef: return readRef(reader); + default: unexpectedTag(tag); + } + } + function readUTF8CharWithoutTag(reader) { + return reader.stream.readString(1); + } + function _readString(reader) { + var stream = reader.stream; + var s = stream.readString(readInt(stream, Tags.TagQuote)); + stream.skip(1); + return s; + } + function readStringWithoutTag(reader) { + var s = _readString(reader); + reader.refer.set(s); + return s; + } + function readString(reader) { + var tag = reader.stream.readByte(); + switch (tag) { + case Tags.TagNull: return null; + case Tags.TagEmpty: return ''; + case Tags.TagUTF8Char: return readUTF8CharWithoutTag(reader); + case Tags.TagString: return readStringWithoutTag(reader); + case Tags.TagRef: return readRef(reader); + default: unexpectedTag(tag); + } + } + function readGuidWithoutTag(reader) { + var stream = reader.stream; + stream.skip(1); + var s = stream.readAsciiString(36); + stream.skip(1); + reader.refer.set(s); + return s; + } + function readGuid(reader) { + var tag = reader.stream.readByte(); + switch (tag) { + case Tags.TagNull: return null; + case Tags.TagGuid: return readGuidWithoutTag(reader); + case Tags.TagRef: return readRef(reader); + default: unexpectedTag(tag); + } + } + function readListWithoutTag(reader) { + var stream = reader.stream; + var list = []; + reader.refer.set(list); + var count = readInt(stream, Tags.TagOpenbrace); + for (var i = 0; i < count; i++) { + list[i] = unserialize(reader); + } + stream.skip(1); + return list; + } + function readList(reader) { + var tag = reader.stream.readByte(); + switch (tag) { + case Tags.TagNull: return null; + case Tags.TagList: return readListWithoutTag(reader); + case Tags.TagRef: return readRef(reader); + default: unexpectedTag(tag); + } + } + function readMapWithoutTag(reader) { + var stream = reader.stream; + var map = {}; + reader.refer.set(map); + var count = readInt(stream, Tags.TagOpenbrace); + for (var i = 0; i < count; i++) { + var key = unserialize(reader); + var value = unserialize(reader); + map[key] = value; + } + stream.skip(1); + return map; + } + function readMap(reader) { + var tag = reader.stream.readByte(); + switch (tag) { + case Tags.TagNull: return null; + case Tags.TagMap: return readMapWithoutTag(reader); + case Tags.TagRef: return readRef(reader); + default: unexpectedTag(tag); + } + } + function readHarmonyMapWithoutTag(reader) { + var stream = reader.stream; + var map = new Map(); + reader.refer.set(map); + var count = readInt(stream, Tags.TagOpenbrace); + for (var i = 0; i < count; i++) { + var key = unserialize(reader); + var value = unserialize(reader); + map.set(key, value); + } + stream.skip(1); + return map; + } + function readHarmonyMap(reader) { + var tag = reader.stream.readByte(); + switch (tag) { + case Tags.TagNull: return null; + case Tags.TagMap: return readHarmonyMapWithoutTag(reader); + case Tags.TagRef: return readRef(reader); + default: unexpectedTag(tag); + } + } + function readObjectWithoutTag(reader) { + var stream = reader.stream; + var cls = reader.classref[readInt(stream, Tags.TagOpenbrace)]; + var obj = new cls.classname(); + reader.refer.set(obj); + for (var i = 0; i < cls.count; i++) { + obj[cls.fields[i]] = unserialize(reader); + } + stream.skip(1); + return obj; + } + function readObject(reader) { + var tag = reader.stream.readByte(); + switch(tag) { + case Tags.TagNull: return null; + case Tags.TagClass: readClass(reader); return readObject(reader); + case Tags.TagObject: return readObjectWithoutTag(reader); + case Tags.TagRef: return readRef(reader); + default: unexpectedTag(tag); + } + } + function readClass(reader) { + var stream = reader.stream; + var classname = _readString(reader); + var count = readInt(stream, Tags.TagOpenbrace); + var fields = []; + for (var i = 0; i < count; i++) { + fields[i] = readString(reader); + } + stream.skip(1); + classname = getClass(classname); + reader.classref.push({ + classname: classname, + count: count, + fields: fields + }); + } + function readRef(reader) { + return reader.refer.read(readInt(reader.stream, Tags.TagSemicolon)); + } + + function Reader(stream, simple, useHarmonyMap) { + RawReader.call(this, stream); + this.useHarmonyMap = !!useHarmonyMap; + Object.defineProperties(this, { + classref: { value: [] }, + refer: { value: simple ? fakeReaderRefer : realReaderRefer() } + }); + } + + Reader.prototype = Object.create(RawReader.prototype); + Reader.prototype.constructor = Reader; + + Object.defineProperties(Reader.prototype, { + useHarmonyMap: { value: false, writable: true }, + checkTag: { value: function(expectTag, tag) { + if (tag === undefined) { tag = this.stream.readByte(); } + if (tag !== expectTag) { unexpectedTag(tag, expectTag); } + } }, + checkTags: { value: function(expectTags, tag) { + if (tag === undefined) { tag = this.stream.readByte(); } + if (expectTags.indexOf(tag) >= 0) { return tag; } + unexpectedTag(tag, expectTags); + } }, + unserialize: { value: function() { + return unserialize(this); + } }, + readInteger: { value: function() { + return readInteger(this.stream); + } }, + readLong: { value: function() { + return readLong(this.stream); + } }, + readDouble: { value: function() { + return readDouble(this.stream); + } }, + readBoolean: { value: function() { + return readBoolean(this.stream); + } }, + readDateWithoutTag: { value: function() { + return readDateWithoutTag(this); + } }, + readDate: { value: function() { + return readDate(this); + } }, + readTimeWithoutTag: { value: function() { + return readTimeWithoutTag(this); + } }, + readTime: { value: function() { + return readTime(this); + } }, + readBytesWithoutTag: { value: function() { + return readBytesWithoutTag(this); + } }, + readBytes: { value: function() { + return readBytes(this); + } }, + readStringWithoutTag: { value: function() { + return readStringWithoutTag(this); + } }, + readString: { value: function() { + return readString(this); + } }, + readGuidWithoutTag: { value: function() { + return readGuidWithoutTag(this); + } }, + readGuid: { value: function() { + return readGuid(this); + } }, + readListWithoutTag: { value: function() { + return readListWithoutTag(this); + } }, + readList: { value: function() { + return readList(this); + } }, + readMapWithoutTag: { value: function() { + return this.useHarmonyMap ? + readHarmonyMapWithoutTag(this) : + readMapWithoutTag(this); + } }, + readMap: { value: function() { + return this.useHarmonyMap ? + readHarmonyMap(this) : + readMap(this); + } }, + readObjectWithoutTag: { value: function() { + return readObjectWithoutTag(this); + } }, + readObject: { value: function() { + return readObject(this); + } }, + reset: { value: function() { + this.classref.length = 0; + this.refer.reset(); + } } + }); + + hprose.Reader = Reader; +})(hprose, hprose.global); + +/**********************************************************\ +| | +| hprose | +| | +| Official WebSite: http://www.hprose.com/ | +| http://www.hprose.org/ | +| | +\**********************************************************/ + +/**********************************************************\ + * * + * Formatter.js * + * * + * hprose Formatter for HTML5. * + * * + * LastModified: Nov 18, 2016 * + * Author: Ma Bingyao * + * * +\**********************************************************/ + +(function (hprose) { + 'use strict'; + + var BytesIO = hprose.BytesIO; + var Writer = hprose.Writer; + var Reader = hprose.Reader; + + function serialize(value, simple) { + var stream = new BytesIO(); + var writer = new Writer(stream, simple); + writer.serialize(value); + return stream; + } + + function unserialize(stream, simple, useHarmonyMap) { + if (!(stream instanceof BytesIO)) { + stream = new BytesIO(stream); + } + return new Reader(stream, simple, useHarmonyMap).unserialize(); + } + + hprose.Formatter = { + serialize: function (value, simple) { + return serialize(value, simple).bytes; + }, + unserialize: unserialize + }; + + hprose.serialize = serialize; + + hprose.unserialize = unserialize; + +})(hprose); + +/**********************************************************\ +| | +| hprose | +| | +| Official WebSite: http://www.hprose.com/ | +| http://www.hprose.org/ | +| | +\**********************************************************/ + +/**********************************************************\ + * * + * ResultMode.js * + * * + * hprose ResultMode for HTML5. * + * * + * LastModified: Nov 18, 2016 * + * Author: Ma Bingyao * + * * +\**********************************************************/ + +(function (hprose) { + 'use strict'; + + hprose.ResultMode = { + Normal: 0, + Serialized: 1, + Raw: 2, + RawWithEndTag: 3 + }; + hprose.Normal = hprose.ResultMode.Normal; + hprose.Serialized = hprose.ResultMode.Serialized; + hprose.Raw = hprose.ResultMode.Raw; + hprose.RawWithEndTag = hprose.ResultMode.RawWithEndTag; + +})(hprose); + +/**********************************************************\ +| | +| hprose | +| | +| Official WebSite: http://www.hprose.com/ | +| http://www.hprose.org/ | +| | +\**********************************************************/ +/**********************************************************\ + * * + * Client.js * + * * + * hprose client for HTML5. * + * * + * LastModified: Apr 24, 2018 * + * Author: Ma Bingyao * + * * +\**********************************************************/ + +/* global Proxy */ +(function (hprose, global, undefined) { + 'use strict'; + + var setImmediate = global.setImmediate; + var Tags = hprose.Tags; + var ResultMode = hprose.ResultMode; + var BytesIO = hprose.BytesIO; + var Writer = hprose.Writer; + var Reader = hprose.Reader; + var Future = hprose.Future; + var parseuri = hprose.parseuri; + var isObjectEmpty = hprose.isObjectEmpty; + + var GETFUNCTIONS = new Uint8Array(1); + GETFUNCTIONS[0] = Tags.TagEnd; + + function noop(){} + + var s_boolean = 'boolean'; + var s_string = 'string'; + var s_number = 'number'; + var s_function = 'function'; + var s_object = 'object'; + + function HproseProxy(setFunction, ns) { + var settings = {}; + this.get = function(target, prop/*, receiver*/) { + var name = prop.toString(); + if (ns) { name = ns + '_' + name; } + if (name === 'then') { return undefined; } + if (!target.hasOwnProperty(name)) { + settings[name] = {}; + var handler = new HproseProxy(setFunction, name); + var func = setFunction(settings, name); + handler.apply = function(target, thisArg, argumentsList) { + return func.apply(null, argumentsList); + } + handler.set = function(target, prop, value/*, receiver*/) { + settings[name][prop] = value; + return true; + }; + target[name] = new Proxy(function() {}, handler); + } + return target[name]; + }; + } + + function Client(uri, functions, settings) { + + // private members + var _uri, + _uriList = [], + _index = -1, + _byref = false, + _simple = false, + _timeout = 30000, + _retry = 10, + _idempotent = false, + _failswitch = false, + _failround = 0, + _lock = false, + _tasks = [], + _useHarmonyMap = false, + _onerror = noop, + _onfailswitch = noop, + _filters = [], + _batch = false, + _batches = [], + _ready = new Future(), + _topics = Object.create(null), + _id = null, + _keepAlive = true, + _invokeHandler = invokeHandler, + _batchInvokeHandler = batchInvokeHandler, + _beforeFilterHandler = beforeFilterHandler, + _afterFilterHandler = afterFilterHandler, + _invokeHandlers = [], + _batchInvokeHandlers = [], + _beforeFilterHandlers = [], + _afterFilterHandlers = [], + + self = this; + + function outputFilter(request, context) { + for (var i = 0, n = _filters.length; i < n; i++) { + request = _filters[i].outputFilter(request, context); + } + return request; + } + + function inputFilter(response, context) { + for (var i = _filters.length - 1; i >= 0; i--) { + response = _filters[i].inputFilter(response, context); + } + return response; + } + + function beforeFilterHandler(request, context) { + request = outputFilter(request, context); + return _afterFilterHandler(request, context) + .then(function(response) { + if (context.oneway) { return; } + return inputFilter(response, context); + }); + } + + function afterFilterHandler(request, context) { + return self.sendAndReceive(request, context).catchError(function(e) { + var response = retry(request, context); + if (response !== null) { + return response; + } + throw e; + }); + } + + function sendAndReceive(request, context, onsuccess, onerror) { + _beforeFilterHandler(request, context).then(onsuccess, onerror); + } + + function failswitch() { + var n = _uriList.length; + if (n > 1) { + var i = _index + 1; + if (i >= n) { + i = 0; + _failround++; + } + _index = i; + _uri = _uriList[_index]; + } + else { + _failround++; + } + _onfailswitch(self); + } + + function retry(data, context) { + if (context.failswitch) { + failswitch(); + } + if (context.idempotent && (context.retried < context.retry)) { + var interval = ++context.retried * 500; + if (context.failswitch) { + interval -= (_uriList.length - 1) * 500; + } + if (interval > 5000) { + interval = 5000; + } + if (interval > 0) { + return Future.delayed(interval, function() { + return afterFilterHandler(data, context); + }); + } + else { + return afterFilterHandler(data, context); + } + } + return null; + } + + function normalizeFunctions(functions) { + var root = [Object.create(null)]; + for (var i in functions) { + var func = functions[i].split('_'); + var n = func.length - 1; + if (n > 0) { + var node = root; + for (var j = 0; j < n; j++) { + var f = func[j]; + if (node[0][f] === undefined) { + node[0][f] = [Object.create(null)]; + } + node = node[0][f]; + } + node.push(func[n]); + } + root.push(functions[i]); + } + return root; + } + + function initService(stub) { + var context = { + retry: _retry, + retried: 0, + idempotent: true, + failswitch: true, + timeout: _timeout, + client: self, + userdata: {} + }; + var onsuccess = function(data) { + var error = null; + try { + var stream = new BytesIO(data); + var reader = new Reader(stream, true); + var tag = stream.readByte(); + switch (tag) { + case Tags.TagError: + error = new Error(reader.readString()); + break; + case Tags.TagFunctions: + var functions = normalizeFunctions(reader.readList()); + reader.checkTag(Tags.TagEnd); + setFunctions(stub, functions); + break; + default: + error = new Error('Wrong Response:\r\n' + BytesIO.toString(data)); + break; + } + } + catch (e) { + error = e; + } + if (error !== null) { + _ready.reject(error); + } + else { + _ready.resolve(stub); + } + }; + sendAndReceive(GETFUNCTIONS, context, onsuccess, _ready.reject); + } + + function setFunction(stub, name) { + return function() { + if (_batch) { + return _invoke(stub, name, Array.slice(arguments), true); + } + else { + return Future.all(arguments).then(function(args) { + return _invoke(stub, name, args, false); + }); + } + }; + } + + function setMethods(stub, obj, namespace, name, methods) { + if (obj[name] !== undefined) { return; } + obj[name] = {}; + if (typeof(methods) === s_string || methods.constructor === Object) { + methods = [methods]; + } + if (Array.isArray(methods)) { + for (var i = 0; i < methods.length; i++) { + var m = methods[i]; + if (typeof(m) === s_string) { + obj[name][m] = setFunction(stub, namespace + name + '_' + m); + } + else { + for (var n in m) { + setMethods(stub, obj[name], namespace + name + '_', n, m[n]); + } + } + } + } + } + + function setFunctions(stub, functions) { + for (var i = 0; i < functions.length; i++) { + var f = functions[i]; + if (typeof(f) === s_string) { + if (stub[f] === undefined) { + stub[f] = setFunction(stub, f); + } + } + else { + for (var name in f) { + setMethods(stub, stub, '', name, f[name]); + } + } + } + } + + function copyargs(src, dest) { + var n = Math.min(src.length, dest.length); + for (var i = 0; i < n; ++i) { dest[i] = src[i]; } + } + + function initContext(batch) { + if (batch) { + return { + mode: ResultMode.Normal, + byref: _byref, + simple: _simple, + onsuccess: undefined, + onerror: undefined, + useHarmonyMap: _useHarmonyMap, + client: self, + userdata: {} + }; + } + return { + mode: ResultMode.Normal, + byref: _byref, + simple: _simple, + timeout: _timeout, + retry: _retry, + retried: 0, + idempotent: _idempotent, + failswitch: _failswitch, + oneway: false, + sync: false, + onsuccess: undefined, + onerror: undefined, + useHarmonyMap: _useHarmonyMap, + client: self, + userdata: {} + }; + } + + function getContext(stub, name, args, batch) { + var context = initContext(batch); + if (name in stub) { + var method = stub[name]; + for (var key in method) { + if (key in context) { + context[key] = method[key]; + } + } + } + var i = 0, n = args.length; + for (; i < n; ++i) { + if (typeof args[i] === s_function) { break; } + } + if (i === n) { return context; } + var extra = args.splice(i, n - i); + context.onsuccess = extra[0]; + n = extra.length; + for (i = 1; i < n; ++i) { + var arg = extra[i]; + switch (typeof arg) { + case s_function: + context.onerror = arg; break; + case s_boolean: + context.byref = arg; break; + case s_number: + context.mode = arg; break; + case s_object: + for (var k in arg) { + if (k in context) { + context[k] = arg[k]; + } + } + break; + } + } + return context; + } + + function encode(name, args, context) { + var stream = new BytesIO(); + stream.writeByte(Tags.TagCall); + var writer = new Writer(stream, context.simple); + writer.writeString(name); + if (args.length > 0 || context.byref) { + writer.reset(); + writer.writeList(args); + if (context.byref) { + writer.writeBoolean(true); + } + } + return stream; + } + + function __invoke(name, args, context, batch) { + if (_lock) { + return Future.promise(function(resolve, reject) { + _tasks.push({ + batch: batch, + name: name, + args: args, + context: context, + resolve: resolve, + reject: reject + }); + }); + } + if (batch) { + return multicall(name, args, context); + } + return call(name, args, context); + } + + function _invoke(stub, name, args, batch) { + return __invoke(name, args, getContext(stub, name, args, batch), batch); + } + + function errorHandling(name, error, context, reject) { + try { + if (context.onerror) { + context.onerror(name, error); + } + else { + _onerror(name, error); + } + reject(error); + } + catch (e) { + reject(e); + } + } + + function invokeHandler(name, args, context) { + var request = encode(name, args, context); + request.writeByte(Tags.TagEnd); + return Future.promise(function(resolve, reject) { + sendAndReceive(request.bytes, context, function(response) { + if (context.oneway) { + resolve(); + return; + } + var result = null; + var error = null; + try { + if (context.mode === ResultMode.RawWithEndTag) { + result = response; + } + else if (context.mode === ResultMode.Raw) { + result = response.subarray(0, response.byteLength - 1); + } + else { + var stream = new BytesIO(response); + var reader = new Reader(stream, false, context.useHarmonyMap); + var tag = stream.readByte(); + if (tag === Tags.TagResult) { + if (context.mode === ResultMode.Serialized) { + result = reader.readRaw(); + } + else { + result = reader.unserialize(); + } + tag = stream.readByte(); + if (tag === Tags.TagArgument) { + reader.reset(); + var _args = reader.readList(); + copyargs(_args, args); + tag = stream.readByte(); + } + } + else if (tag === Tags.TagError) { + error = new Error(reader.readString()); + tag = stream.readByte(); + } + if (tag !== Tags.TagEnd) { + error = new Error('Wrong Response:\r\n' + BytesIO.toString(response)); + } + } + } + catch (e) { + error = e; + } + if (error) { + reject(error); + } + else { + resolve(result); + } + }, reject); + }); + } + + function unlock(sync) { + return function() { + if (sync) { + _lock = false; + setImmediate(function(tasks) { + tasks.forEach(function(task) { + if ('settings' in task) { + endBatch(task.settings) + .then(task.resolve, task.reject); + } + else { + __invoke(task.name, task.args, task.context, task.batch).then(task.resolve, task.reject); + } + }); + }, _tasks); + _tasks = []; + } + }; + } + + function call(name, args, context) { + if (context.sync) { _lock = true; } + var promise = Future.promise(function(resolve, reject) { + _invokeHandler(name, args, context).then(function(result) { + try { + if (context.onsuccess) { + try { + context.onsuccess(result, args); + } + catch (e) { + if (context.onerror) { + context.onerror(name, e); + } + reject(e); + } + } + resolve(result); + } + catch (e) { + reject(e); + } + }, function(error) { + errorHandling(name, error, context, reject); + }); + }); + promise.whenComplete(unlock(context.sync)); + return promise; + } + + function multicall(name, args, context) { + return Future.promise(function(resolve, reject) { + _batches.push({ + args: args, + name: name, + context: context, + resolve: resolve, + reject: reject + }); + }); + } + + function getBatchContext(settings) { + var context = { + timeout: _timeout, + retry: _retry, + retried: 0, + idempotent: _idempotent, + failswitch: _failswitch, + oneway: false, + sync: false, + client: self, + userdata: {} + }; + for (var k in settings) { + if (k in context) { + context[k] = settings[k]; + } + } + return context; + } + + function batchInvokeHandler(batches, context) { + var request = batches.reduce(function(stream, item) { + stream.write(encode(item.name, item.args, item.context)); + return stream; + }, new BytesIO()); + request.writeByte(Tags.TagEnd); + return Future.promise(function(resolve, reject) { + sendAndReceive(request.bytes, context, function(response) { + if (context.oneway) { + resolve(batches); + return; + } + var i = -1; + var stream = new BytesIO(response); + var reader = new Reader(stream, false); + var tag = stream.readByte(); + try { + while (tag !== Tags.TagEnd) { + var result = null; + var error = null; + var mode = batches[++i].context.mode; + if (mode >= ResultMode.Raw) { + result = new BytesIO(); + } + if (tag === Tags.TagResult) { + if (mode === ResultMode.Serialized) { + result = reader.readRaw(); + } + else if (mode >= ResultMode.Raw) { + result.writeByte(Tags.TagResult); + result.write(reader.readRaw()); + } + else { + reader.useHarmonyMap = batches[i].context.useHarmonyMap; + reader.reset(); + result = reader.unserialize(); + } + tag = stream.readByte(); + if (tag === Tags.TagArgument) { + if (mode >= ResultMode.Raw) { + result.writeByte(Tags.TagArgument); + result.write(reader.readRaw()); + } + else { + reader.reset(); + var _args = reader.readList(); + copyargs(_args, batches[i].args); + } + tag = stream.readByte(); + } + } + else if (tag === Tags.TagError) { + if (mode >= ResultMode.Raw) { + result.writeByte(Tags.TagError); + result.write(reader.readRaw()); + } + else { + reader.reset(); + error = new Error(reader.readString()); + } + tag = stream.readByte(); + } + if ([Tags.TagEnd, + Tags.TagResult, + Tags.TagError].indexOf(tag) < 0) { + reject(new Error('Wrong Response:\r\n' + BytesIO.toString(response))); + return; + } + if (mode >= ResultMode.Raw) { + if (mode === ResultMode.RawWithEndTag) { + result.writeByte(Tags.TagEnd); + } + batches[i].result = result.bytes; + } + else { + batches[i].result = result; + } + batches[i].error = error; + } + } + catch (e) { + reject(e); + return; + } + resolve(batches); + }, reject); + }); + } + + function beginBatch() { + _batch = true; + } + + function endBatch(settings) { + settings = settings || {}; + _batch = false; + if (_lock) { + return Future.promise(function(resolve, reject) { + _tasks.push({ + batch: true, + settings: settings, + resolve: resolve, + reject: reject + }); + }); + } + var batchSize = _batches.length; + if (batchSize === 0) { return Future.value([]); } + var context = getBatchContext(settings); + if (context.sync) { _lock = true; } + var batches = _batches; + _batches = []; + var promise = Future.promise(function(resolve, reject) { + _batchInvokeHandler(batches, context).then(function(batches) { + batches.forEach(function(i) { + if (i.error) { + errorHandling(i.name, i.error, i.context, i.reject); + } + else { + try { + if (i.context.onsuccess) { + try { + i.context.onsuccess(i.result, i.args); + } + catch (e) { + if (i.context.onerror) { + i.context.onerror(i.name, e); + } + i.reject(e); + } + } + i.resolve(i.result); + } + catch (e) { + i.reject(e); + } + } + delete i.context; + delete i.resolve; + delete i.reject; + }); + resolve(batches); + }, function(error) { + batches.forEach(function(i) { + if ('reject' in i) { + errorHandling(i.name, error, i.context, i.reject); + } + }); + reject(error); + }); + }); + promise.whenComplete(unlock(context.sync)); + return promise; + } + + function getOnError() { + return _onerror; + } + function setOnError(value) { + if (typeof(value) === s_function) { + _onerror = value; + } + } + function getOnFailswitch() { + return _onfailswitch; + } + function setOnFailswitch(value) { + if (typeof(value) === s_function) { + _onfailswitch = value; + } + } + function getUri() { + return _uri; + } + function getUriList() { + return _uriList; + } + function setUriList(uriList) { + if (typeof(uriList) === s_string) { + _uriList = [uriList]; + } + else if (Array.isArray(uriList)) { + _uriList = uriList.slice(0); + _uriList.sort(function() { return Math.random() - 0.5; }); + } + else { + return; + } + _index = 0; + _uri = _uriList[_index]; + } + function getFailswitch() { + return _failswitch; + } + function setFailswitch(value) { + _failswitch = !!value; + } + function getFailround() { + return _failround; + } + function getTimeout() { + return _timeout; + } + function setTimeout(value) { + if (typeof(value) === 'number') { + _timeout = value | 0; + } + else { + _timeout = 0; + } + } + function getRetry() { + return _retry; + } + function setRetry(value) { + if (typeof(value) === 'number') { + _retry = value | 0; + } + else { + _retry = 0; + } + } + function getIdempotent() { + return _idempotent; + } + function setIdempotent(value) { + _idempotent = !!value; + } + function setKeepAlive(value) { + _keepAlive = !!value; + } + function getKeepAlive() { + return _keepAlive; + } + function getByRef() { + return _byref; + } + function setByRef(value) { + _byref = !!value; + } + function getSimpleMode() { + return _simple; + } + function setSimpleMode(value) { + _simple = !!value; + } + function getUseHarmonyMap() { + return _useHarmonyMap; + } + function setUseHarmonyMap(value) { + _useHarmonyMap = !!value; + } + function getFilter() { + if (_filters.length === 0) { + return null; + } + if (_filters.length === 1) { + return _filters[0]; + } + return _filters.slice(); + } + function setFilter(filter) { + _filters.length = 0; + if (Array.isArray(filter)) { + filter.forEach(function(filter) { + addFilter(filter); + }); + } + else { + addFilter(filter); + } + } + function addFilter(filter) { + if (filter && + typeof filter.inputFilter === 'function' && + typeof filter.outputFilter === 'function') { + _filters.push(filter); + } + } + function removeFilter(filter) { + var i = _filters.indexOf(filter); + if (i === -1) { + return false; + } + _filters.splice(i, 1); + return true; + } + function filters() { + return _filters; + } + function useService(uri, functions, create) { + if (create === undefined) { + if (typeof(functions) === s_boolean) { + create = functions; + functions = false; + } + if (!functions) { + if (typeof(uri) === s_boolean) { + create = uri; + uri = false; + } + else if (uri && uri.constructor === Object || + Array.isArray(uri)) { + functions = uri; + uri = false; + } + } + } + var stub = self; + if (create) { + stub = {}; + } + if (!uri && !_uri) { + return new Error('You should set server uri first!'); + } + if (uri) { + _uri = uri; + } + if (typeof(functions) === s_string || + (functions && functions.constructor === Object)) { + functions = [functions]; + } + if (Array.isArray(functions)) { + setFunctions(stub, functions); + } + else if (typeof(Proxy) === 'undefined') { + setImmediate(initService, stub); + return _ready; + } + else { + stub = new Proxy({}, new HproseProxy(setFunction)); + } + _ready.resolve(stub); + return stub; + } + function invoke(name, args, onsuccess/*, onerror, settings*/) { + var argc = arguments.length; + if ((argc < 1) || (typeof name !== s_string)) { + throw new Error('name must be a string'); + } + if (argc === 1) { args = []; } + if (argc === 2) { + if (!Array.isArray(args)) { + var _args = []; + if (typeof args !== s_function) { + _args.push(noop); + } + _args.push(args); + args = _args; + } + } + if (argc > 2) { + if (typeof onsuccess !== s_function) { + args.push(noop); + } + for (var i = 2; i < argc; i++) { + args.push(arguments[i]); + } + } + return _invoke(self, name, args, _batch); + } + function ready(onComplete, onError) { + return _ready.then(onComplete, onError); + } + function getTopic(name, id) { + if (_topics[name]) { + var topics = _topics[name]; + if (topics[id]) { + return topics[id]; + } + } + return null; + } + // subscribe(name, callback, timeout, failswitch) + // subscribe(name, id, callback, timeout, failswitch) + function subscribe(name, id, callback, timeout, failswitch) { + if (typeof name !== s_string) { + throw new TypeError('topic name must be a string.'); + } + if (id === undefined || id === null) { + if (typeof callback === s_function) { + id = callback; + } + else { + throw new TypeError('callback must be a function.'); + } + } + if (!_topics[name]) { + _topics[name] = Object.create(null); + } + if (typeof id === s_function) { + timeout = callback; + callback = id; + autoId().then(function(id) { + subscribe(name, id, callback, timeout, failswitch); + }); + return; + } + if (typeof callback !== s_function) { + throw new TypeError('callback must be a function.'); + } + if (Future.isPromise(id)) { + id.then(function(id) { + subscribe(name, id, callback, timeout, failswitch); + }); + return; + } + // Default subscribe timeout is 5 minutes. + if (timeout === undefined) { timeout = 300000; } + var topic = getTopic(name, id); + if (topic === null) { + var cb = function() { + _invoke(self, name, [id, topic.handler, cb, { + idempotent: true, + failswitch: failswitch, + timeout: timeout + }], false); + }; + topic = { + handler: function(result) { + var topic = getTopic(name, id); + if (topic) { + if (result !== null) { + var callbacks = topic.callbacks; + for (var i = 0, n = callbacks.length; i < n; ++i) { + try { + callbacks[i](result); + } + catch (e) {} + } + } + if (getTopic(name, id) !== null) { cb(); } + } + }, + callbacks: [callback] + }; + _topics[name][id] = topic; + cb(); + } + else if (topic.callbacks.indexOf(callback) < 0) { + topic.callbacks.push(callback); + } + } + function delTopic(topics, id, callback) { + if (topics) { + if (typeof callback === s_function) { + var topic = topics[id]; + if (topic) { + var callbacks = topic.callbacks; + var p = callbacks.indexOf(callback); + if (p >= 0) { + callbacks[p] = callbacks[callbacks.length - 1]; + callbacks.length--; + } + if (callbacks.length === 0) { + delete topics[id]; + } + } + } + else { + delete topics[id]; + } + } + } + // unsubscribe(name) + // unsubscribe(name, callback) + // unsubscribe(name, id) + // unsubscribe(name, id, callback) + function unsubscribe(name, id, callback) { + if (typeof name !== s_string) { + throw new TypeError('topic name must be a string.'); + } + if (id === undefined || id === null) { + if (typeof callback === s_function) { + id = callback; + } + else { + delete _topics[name]; + return; + } + } + if (typeof id === s_function) { + callback = id; + id = null; + } + if (id === null) { + if (_id === null) { + if (_topics[name]) { + var topics = _topics[name]; + for (id in topics) { + delTopic(topics, id, callback); + } + } + } + else { + _id.then(function(id) { + unsubscribe(name, id, callback); + }); + } + } + else if (Future.isPromise(id)) { + id.then(function(id) { + unsubscribe(name, id, callback); + }); + } + else { + delTopic(_topics[name], id, callback); + } + if (isObjectEmpty(_topics[name])) { + delete _topics[name]; + } + } + function isSubscribed(name) { + return !!_topics[name]; + } + function subscribedList() { + var list = []; + for (var name in _topics) { + list.push(name); + } + return list; + } + function getId() { + return _id; + } + function autoId() { + if (_id === null) { + _id = _invoke(self, '#', [], false); + } + return _id; + } + autoId.sync = true; + autoId.idempotent = true; + autoId.failswitch = true; + function addInvokeHandler(handler) { + _invokeHandlers.push(handler); + _invokeHandler = _invokeHandlers.reduceRight( + function(next, handler) { + return function(name, args, context) { + return Future.toPromise(handler(name, args, context, next)); + }; + }, invokeHandler); + } + function addBatchInvokeHandler(handler) { + _batchInvokeHandlers.push(handler); + _batchInvokeHandler = _batchInvokeHandlers.reduceRight( + function(next, handler) { + return function(batches, context) { + return Future.toPromise(handler(batches, context, next)); + }; + }, batchInvokeHandler); + } + function addBeforeFilterHandler(handler) { + _beforeFilterHandlers.push(handler); + _beforeFilterHandler = _beforeFilterHandlers.reduceRight( + function(next, handler) { + return function(request, context) { + return Future.toPromise(handler(request, context, next)); + }; + }, beforeFilterHandler); + } + function addAfterFilterHandler(handler) { + _afterFilterHandlers.push(handler); + _afterFilterHandler = _afterFilterHandlers.reduceRight( + function(next, handler) { + return function(request, context) { + return Future.toPromise(handler(request, context, next)); + }; + }, afterFilterHandler); + } + function use(handler) { + addInvokeHandler(handler); + return self; + } + var batch = Object.create(null, { + begin: { value: beginBatch }, + end: { value: endBatch }, + use: { value: function(handler) { + addBatchInvokeHandler(handler); + return batch; + } } + }); + var beforeFilter = Object.create(null, { + use: { value: function(handler) { + addBeforeFilterHandler(handler); + return beforeFilter; + } } + }); + var afterFilter = Object.create(null, { + use: { value: function(handler) { + addAfterFilterHandler(handler); + return afterFilter; + } } + }); + Object.defineProperties(this, { + '#': { value: autoId }, + onerror: { get: getOnError, set: setOnError }, + onfailswitch: { get: getOnFailswitch, set: setOnFailswitch }, + uri: { get: getUri }, + uriList: { get: getUriList, set: setUriList }, + id: { get: getId }, + failswitch: { get: getFailswitch, set: setFailswitch }, + failround: { get: getFailround }, + timeout: { get: getTimeout, set: setTimeout }, + retry: { get: getRetry, set: setRetry }, + idempotent: { get: getIdempotent, set: setIdempotent }, + keepAlive: { get: getKeepAlive, set: setKeepAlive }, + byref: { get: getByRef, set: setByRef }, + simple: { get: getSimpleMode, set: setSimpleMode }, + useHarmonyMap: { get: getUseHarmonyMap, set: setUseHarmonyMap }, + filter: { get: getFilter, set: setFilter }, + addFilter: { value: addFilter }, + removeFilter: { value: removeFilter }, + filters: { get: filters }, + useService: { value: useService }, + invoke: { value: invoke }, + ready: { value: ready }, + subscribe: { value: subscribe }, + unsubscribe: { value: unsubscribe }, + isSubscribed: { value : isSubscribed }, + subscribedList: { value : subscribedList }, + use: { value: use }, + batch: { value: batch }, + beforeFilter: { value: beforeFilter }, + afterFilter: { value: afterFilter } + }); + /* function constructor */ { + if ((settings) && (typeof settings === s_object)) { + ['failswitch', 'timeout', 'retry', 'idempotent', + 'keepAlive', 'byref', 'simple','useHarmonyMap', + 'filter'].forEach(function(key) { + if (key in settings) { + self[key] = settings[key]; + } + }); + } + if (uri) { + setUriList(uri); + useService(functions); + } + } + } + + function checkuri(uri) { + var parser = parseuri(uri); + var protocol = parser.protocol; + if (protocol === 'http:' || + protocol === 'https:' || + protocol === 'tcp:' || + protocol === 'tcp4:'|| + protocol === 'tcp6:' || + protocol === 'tcps:' || + protocol === 'tcp4s:' || + protocol === 'tcp6s:' || + protocol === 'tls:' || + protocol === 'ws:' || + protocol === 'wss:') { + return; + } + throw new Error('The ' + protocol + ' client isn\'t implemented.'); + } + + function create(uri, functions, settings) { + try { + return hprose.HttpClient.create(uri, functions, settings); + } + catch(e) {} + try { + return hprose.TcpClient.create(uri, functions, settings); + } + catch(e) {} + try { + return hprose.WebSocketClient.create(uri, functions, settings); + } + catch(e) {} + if (typeof uri === 'string') { + checkuri(uri); + } + else if (Array.isArray(uri)) { + uri.forEach(function(uri) { checkuri(uri); }); + throw new Error('Not support multiple protocol.'); + } + throw new Error('You should set server uri first!'); + } + + Object.defineProperty(Client, 'create', { value: create }); + + hprose.Client = Client; + +})(hprose, hprose.global); + +/**********************************************************\ +| | +| hprose | +| | +| Official WebSite: http://www.hprose.com/ | +| http://www.hprose.org/ | +| | +\**********************************************************/ + +/**********************************************************\ + * * + * CookieManager.js * + * * + * hprose CookieManager for HTML5. * + * * + * LastModified: Dec 2, 2016 * + * Author: Ma Bingyao * + * * +\**********************************************************/ + +(function (hprose) { + 'use strict'; + + var parseuri = hprose.parseuri; + + var s_cookieManager = {}; + + function setCookie(headers, uri) { + var parser = parseuri(uri); + var host = parser.host; + var name, values; + function _setCookie(value) { + var cookies, cookie, i; + cookies = value.replace(/(^\s*)|(\s*$)/g, '').split(';'); + cookie = {}; + value = cookies[0].replace(/(^\s*)|(\s*$)/g, '').split('=', 2); + if (value[1] === undefined) { value[1] = null; } + cookie.name = value[0]; + cookie.value = value[1]; + for (i = 1; i < cookies.length; i++) { + value = cookies[i].replace(/(^\s*)|(\s*$)/g, '').split('=', 2); + if (value[1] === undefined) { value[1] = null; } + cookie[value[0].toUpperCase()] = value[1]; + } + // Tomcat can return SetCookie2 with path wrapped in " + if (cookie.PATH) { + if (cookie.PATH.charAt(0) === '"') { + cookie.PATH = cookie.PATH.substr(1); + } + if (cookie.PATH.charAt(cookie.PATH.length - 1) === '"') { + cookie.PATH = cookie.PATH.substr(0, cookie.PATH.length - 1); + } + } + else { + cookie.PATH = '/'; + } + if (cookie.EXPIRES) { + cookie.EXPIRES = Date.parse(cookie.EXPIRES); + } + if (cookie.DOMAIN) { + cookie.DOMAIN = cookie.DOMAIN.toLowerCase(); + } + else { + cookie.DOMAIN = host; + } + cookie.SECURE = (cookie.SECURE !== undefined); + if (s_cookieManager[cookie.DOMAIN] === undefined) { + s_cookieManager[cookie.DOMAIN] = {}; + } + s_cookieManager[cookie.DOMAIN][cookie.name] = cookie; + } + for (name in headers) { + values = headers[name]; + name = name.toLowerCase(); + if ((name === 'set-cookie') || (name === 'set-cookie2')) { + if (typeof(values) === 'string') { + values = [values]; + } + values.forEach(_setCookie); + } + } + } + + function getCookie(uri) { + var parser = parseuri(uri); + var host = parser.host; + var path = parser.path; + var secure = (parser.protocol === 'https:'); + var cookies = []; + for (var domain in s_cookieManager) { + if (host.indexOf(domain) > -1) { + var names = []; + for (var name in s_cookieManager[domain]) { + var cookie = s_cookieManager[domain][name]; + if (cookie.EXPIRES && ((new Date()).getTime() > cookie.EXPIRES)) { + names.push(name); + } + else if (path.indexOf(cookie.PATH) === 0) { + if (((secure && cookie.SECURE) || + !cookie.SECURE) && (cookie.value !== null)) { + cookies.push(cookie.name + '=' + cookie.value); + } + } + } + for (var i in names) { + delete s_cookieManager[domain][names[i]]; + } + } + } + if (cookies.length > 0) { + return cookies.join('; '); + } + return ''; + } + + hprose.cookieManager = { + setCookie: setCookie, + getCookie: getCookie + }; +})(hprose); + +/**********************************************************\ +| | +| hprose | +| | +| Official WebSite: http://www.hprose.com/ | +| http://www.hprose.org/ | +| | +\**********************************************************/ +/**********************************************************\ + * * + * HttpClient.js * + * * + * hprose http client for HTML5. * + * * + * LastModified: Dec 2, 2016 * + * Author: Ma Bingyao * + * * +\**********************************************************/ + +(function (hprose, global, undefined) { + 'use strict'; + + var Client = hprose.Client; + var Future = hprose.Future; + var BytesIO = hprose.BytesIO; + var TimeoutError = global.TimeoutError; + var localfile = (global.location !== undefined && global.location.protocol === 'file:'); + var XMLHttpRequest = global.XMLHttpRequest; + var nativeXHR = (typeof(XMLHttpRequest) !== 'undefined'); + var corsSupport = (!localfile && nativeXHR && 'withCredentials' in new XMLHttpRequest()); + var parseuri = hprose.parseuri; + var cookieManager = hprose.cookieManager; + + function noop(){} + + function getResponseHeader(headers) { + var header = Object.create(null); + if (headers) { + headers = headers.split("\r\n"); + for (var i = 0, n = headers.length; i < n; i++) { + if (headers[i] !== "") { + var kv = headers[i].split(": ", 2); + var k = kv[0].trim(); + var v = kv[1].trim(); + if (k in header) { + if (Array.isArray(header[k])) { + header[k].push(v); + } + else { + header[k] = [header[k], v]; + } + } + else { + header[k] = v; + } + } + } + } + return header; + } + + function HttpClient(uri, functions, settings) { + if (this.constructor !== HttpClient) { + return new HttpClient(uri, functions, settings); + } + Client.call(this, uri, functions, settings); + var _header = Object.create(null); + var _onreqprogress = noop; + var _onresprogress = noop; + + var self = this; + + function getRequestHeader(headers) { + var header = Object.create(null); + var name, value; + for (name in _header) { + header[name] = _header[name]; + } + if (headers) { + for (name in headers) { + value = headers[name]; + if (Array.isArray(value)) { + header[name] = value.join(', '); + } + else { + header[name] = value; + } + } + } + return header; + } + + function xhrPost(request, context) { + var future = new Future(); + var xhr = new XMLHttpRequest(); + xhr.open('POST', self.uri, true); + if (corsSupport) { + xhr.withCredentials = 'true'; + } + xhr.responseType = 'arraybuffer'; + var header = getRequestHeader(context.httpHeader); + for (var name in header) { + xhr.setRequestHeader(name, header[name]); + } + xhr.onload = function() { + xhr.onload = noop; + if (xhr.status) { + var headers = xhr.getAllResponseHeaders(); + context.httpHeader = getResponseHeader(headers); + if (xhr.status === 200) { + future.resolve(new Uint8Array(xhr.response)); + } + else { + future.reject(new Error(xhr.status + ':' + xhr.statusText)); + } + } + }; + xhr.onerror = function() { + future.reject(new Error('error')); + }; + if (xhr.upload !== undefined) { + xhr.upload.onprogress = _onreqprogress; + } + xhr.onprogress = _onresprogress; + if (context.timeout > 0) { + future = future.timeout(context.timeout).catchError(function(e) { + xhr.onload = noop; + xhr.onerror = noop; + xhr.abort(); + throw e; + }, + function(e) { + return e instanceof TimeoutError; + }); + } + if (request.constructor === String || ArrayBuffer.isView) { + xhr.send(request); + } + else if (request.buffer.slice) { + xhr.send(request.buffer.slice(0, request.length)); + } + else { + var buf = new Uint8Array(request.length); + buf.set(request); + xhr.send(buf.buffer); + } + return future; + } + + function apiPost(request, context) { + var future = new Future(); + var header = getRequestHeader(context.httpHeader); + var cookie = cookieManager.getCookie(self.uri()); + if (cookie !== '') { + header['Cookie'] = cookie; + } + global.api.ajax({ + url: self.uri, + method: 'post', + data: { body: BytesIO.toString(request) }, + timeout: context.timeout, + dataType: 'text', + headers: header, + returnAll: true, + certificate: self.certificate + }, function(ret, err) { + if (ret) { + context.httpHeader = ret.headers; + if (ret.statusCode === 200) { + cookieManager.setCookie(ret.headers, self.uri); + future.resolve((new BytesIO(ret.body)).takeBytes()); + } + else { + future.reject(new Error(ret.statusCode+':'+ret.body)); + } + } + else { + future.reject(new Error(err.msg)); + } + }); + return future; + } + + function sendAndReceive(request, context) { + var apicloud = (typeof(global.api) !== "undefined" && + typeof(global.api.ajax) !== "undefined"); + var future = apicloud ? apiPost(request, context) : + xhrPost(request, context); + if (context.oneway) { future.resolve(); } + return future; + } + + function setOnRequestProgress(value) { + if (typeof(value) === 'function') { + _onreqprogress = value; + } + } + function getOnRequestProgress() { + return _onreqprogress; + } + function setOnResponseProgress(value) { + if (typeof(value) === 'function') { + _onresprogress = value; + } + } + function getOnResponseProgress() { + return _onresprogress; + } + function setHeader(name, value) { + if (name.toLowerCase() !== 'content-type' && + name.toLowerCase() !== 'content-length') { + if (value) { + _header[name] = value; + } + else { + delete _header[name]; + } + } + } + Object.defineProperties(this, { + onprogress: { get: getOnRequestProgress, set: setOnRequestProgress }, + onRequestProgress: { get: getOnRequestProgress, set: setOnRequestProgress }, + onResponseProgress: { get: getOnResponseProgress, set: setOnResponseProgress }, + setHeader: { value: setHeader }, + sendAndReceive: { value: sendAndReceive } + }); + } + + function checkuri(uri) { + var parser = parseuri(uri); + if (parser.protocol === 'http:' || + parser.protocol === 'https:') { + return; + } + throw new Error('This client desn\'t support ' + parser.protocol + ' scheme.'); + } + + function create(uri, functions, settings) { + if (typeof uri === 'string') { + checkuri(uri); + } + else if (Array.isArray(uri)) { + uri.forEach(function(uri) { checkuri(uri); }); + } + else { + throw new Error('You should set server uri first!'); + } + return new HttpClient(uri, functions, settings); + } + + Object.defineProperty(HttpClient, 'create', { value: create }); + + hprose.HttpClient = HttpClient; + +})(hprose, hprose.global); + +/**********************************************************\ +| | +| hprose | +| | +| Official WebSite: http://www.hprose.com/ | +| http://www.hprose.org/ | +| | +\**********************************************************/ +/**********************************************************\ + * * + * WebSocketClient.js * + * * + * hprose websocket client for HTML5. * + * * + * LastModified: Aug 20, 2017 * + * Author: Ma Bingyao * + * * +\**********************************************************/ + +(function (hprose, global, undefined) { + 'use strict'; + + var BytesIO = hprose.BytesIO; + var Client = hprose.Client; + var Future = hprose.Future; + var TimeoutError = global.TimeoutError; + var parseuri = hprose.parseuri; + + var WebSocket = global.WebSocket || global.MozWebSocket; + + function noop(){} + function WebSocketClient(uri, functions, settings) { + if (typeof(WebSocket) === "undefined") { + throw new Error('WebSocket is not supported by this browser.'); + } + if (this.constructor !== WebSocketClient) { + return new WebSocketClient(uri, functions, settings); + } + + Client.call(this, uri, functions, settings); + + var _id = 0; + var _count = 0; + var _futures = []; + var _requests = []; + var _ready = null; + var ws = null; + + var self = this; + + function getNextId() { + return (_id < 0x7fffffff) ? ++_id : _id = 0; + } + function send(id, request) { + var bytes = new BytesIO(); + bytes.writeInt32BE(id); + if (request.constructor === String) { + bytes.writeString(request); + } + else { + bytes.write(request); + } + var message = bytes.bytes; + if (ArrayBuffer.isView) { + ws.send(message); + } + else if (message.buffer.slice) { + ws.send(message.buffer.slice(0, message.length)); + } + else { + ws.send(message.buffer); + } + } + function onopen(e) { + _ready.resolve(e); + } + function onmessage(e) { + var bytes = new BytesIO(e.data); + var id = bytes.readInt32BE(); + var future = _futures[id]; + delete _futures[id]; + if (future !== undefined) { + --_count; + future.resolve(bytes.read(bytes.length - 4)); + } + if ((_count < 100) && (_requests.length > 0)) { + ++_count; + var request = _requests.pop(); + _ready.then(function() { send(request[0], request[1]); }); + } + if (_count === 0 && !self.keepAlive) { + close(); + } + } + function onclose(e) { + _futures.forEach(function(future, id) { + future.reject(new Error(e.code + ':' + e.reason)); + delete _futures[id]; + }); + _count = 0; + ws = null; + } + function connect() { + _ready = new Future(); + ws = new WebSocket(self.uri); + ws.binaryType = 'arraybuffer'; + ws.onopen = onopen; + ws.onmessage = onmessage; + ws.onerror = noop; + ws.onclose = onclose; + } + function sendAndReceive(request, context) { + var id = getNextId(); + var future = new Future(); + _futures[id] = future; + if (context.timeout > 0) { + future = future.timeout(context.timeout).catchError(function(e) { + delete _futures[id]; + --_count; + close(); + throw e; + }, + function(e) { + return e instanceof TimeoutError; + }); + } + if (ws === null || + ws.readyState === WebSocket.CLOSING || + ws.readyState === WebSocket.CLOSED) { + connect(); + } + if (_count < 100) { + ++_count; + _ready.then(function() { send(id, request); }); + } + else { + _requests.push([id, request]); + } + if (context.oneway) { future.resolve(); } + return future; + } + function close() { + if (ws !== null) { + ws.onopen = noop; + ws.onmessage = noop; + ws.onclose = noop; + ws.close(); + } + } + + Object.defineProperties(this, { + sendAndReceive: { value: sendAndReceive }, + close: { value: close } + }); + } + + function checkuri(uri) { + var parser = parseuri(uri); + if (parser.protocol === 'ws:' || + parser.protocol === 'wss:') { + return; + } + throw new Error('This client desn\'t support ' + parser.protocol + ' scheme.'); + } + + function create(uri, functions, settings) { + if (typeof uri === 'string') { + checkuri(uri); + } + else if (Array.isArray(uri)) { + uri.forEach(function(uri) { checkuri(uri); }); + } + else { + throw new Error('You should set server uri first!'); + } + return new WebSocketClient(uri, functions, settings); + } + + Object.defineProperty(WebSocketClient, 'create', { value: create }); + + hprose.WebSocketClient = WebSocketClient; + +})(hprose, hprose.global); + +/**********************************************************\ +| | +| hprose | +| | +| Official WebSite: http://www.hprose.com/ | +| http://www.hprose.org/ | +| | +\**********************************************************/ +/**********************************************************\ + * * + * ChromeTcpSocket.js * + * * + * chrome tcp socket for JavaScript. * + * * + * LastModified: Nov 18, 2016 * + * Author: Ma Bingyao * + * * +\**********************************************************/ + +(function (hprose, global, undefined) { + 'use strict'; + + var Future = hprose.Future; + + function noop(){} + + var socketPool = {}; + var socketManager = null; + + function receiveListener(info) { + var socket = socketPool[info.socketId]; + socket.onreceive(info.data); + } + + function receiveErrorListener(info) { + var socket = socketPool[info.socketId]; + socket.onerror(info.resultCode); + socket.destroy(); + } + + function ChromeTcpSocket() { + if (socketManager === null) { + socketManager = global.chrome.sockets.tcp; + socketManager.onReceive.addListener(receiveListener); + socketManager.onReceiveError.addListener(receiveErrorListener); + } + this.socketId = new Future(); + this.connected = false; + this.timeid = undefined; + this.onclose = noop; + this.onconnect = noop; + this.onreceive = noop; + this.onerror = noop; + } + + Object.defineProperties(ChromeTcpSocket.prototype, { + connect: { value: function(address, port, options) { + var self = this; + socketManager.create({ persistent: options && options.persistent }, function(createInfo) { + if (options) { + if ('noDelay' in options) { + socketManager.setNoDelay(createInfo.socketId, options.noDelay, function(result) { + if (result < 0) { + self.socketId.reject(result); + socketManager.disconnect(createInfo.socketId); + socketManager.close(createInfo.socketId); + self.onclose(); + } + }); + } + if ('keepAlive' in options) { + socketManager.setKeepAlive(createInfo.socketId, options.keepAlive, function(result) { + if (result < 0) { + self.socketId.reject(result); + socketManager.disconnect(createInfo.socketId); + socketManager.close(createInfo.socketId); + self.onclose(); + } + }); + } + } + if (options && options.tls) { + socketManager.setPaused(createInfo.socketId, true, function() { + socketManager.connect(createInfo.socketId, address, port, function(result) { + if (result < 0) { + self.socketId.reject(result); + socketManager.disconnect(createInfo.socketId); + socketManager.close(createInfo.socketId); + self.onclose(); + } + else { + socketManager.secure(createInfo.socketId, function(secureResult) { + if (secureResult !== 0) { + self.socketId.reject(result); + socketManager.disconnect(createInfo.socketId); + socketManager.close(createInfo.socketId); + self.onclose(); + } + else { + socketManager.setPaused(createInfo.socketId, false, function() { + self.socketId.resolve(createInfo.socketId); + }); + } + }); + } + }); + }); + } + else { + socketManager.connect(createInfo.socketId, address, port, function(result) { + if (result < 0) { + self.socketId.reject(result); + socketManager.disconnect(createInfo.socketId); + socketManager.close(createInfo.socketId); + self.onclose(); + } + else { + self.socketId.resolve(createInfo.socketId); + } + }); + } + }); + this.socketId.then(function(socketId) { + socketPool[socketId] = self; + self.connected = true; + self.onconnect(socketId); + }, function(reason) { + self.onerror(reason); + }); + } }, + send: { value: function(data) { + var self = this; + var promise = new Future(); + this.socketId.then(function(socketId) { + socketManager.send(socketId, data, function(sendInfo) { + if (sendInfo.resultCode < 0) { + self.onerror(sendInfo.resultCode); + promise.reject(sendInfo.resultCode); + self.destroy(); + } + else { + promise.resolve(sendInfo.bytesSent); + } + }); + }); + return promise; + } }, + destroy: { value: function() { + var self = this; + this.connected = false; + this.socketId.then(function(socketId) { + socketManager.disconnect(socketId); + socketManager.close(socketId); + delete socketPool[socketId]; + self.onclose(); + }); + } }, + ref: { value: function() { + this.socketId.then(function(socketId) { + socketManager.setPaused(socketId, false); + }); + } }, + unref: { value: function() { + this.socketId.then(function(socketId) { + socketManager.setPaused(socketId, true); + }); + } }, + clearTimeout: { value: function() { + if (this.timeid !== undefined) { + global.clearTimeout(this.timeid); + } + } }, + setTimeout: { value: function(timeout, fn) { + this.clearTimeout(); + this.timeid = global.setTimeout(fn, timeout); + } } + }); + + hprose.ChromeTcpSocket = ChromeTcpSocket; + +})(hprose, hprose.global); + +/**********************************************************\ +| | +| hprose | +| | +| Official WebSite: http://www.hprose.com/ | +| http://www.hprose.org/ | +| | +\**********************************************************/ +/**********************************************************\ + * * + * APICloudTcpSocket.js * + * * + * APICloud tcp socket for HTML5. * + * * + * LastModified: Nov 18, 2016 * + * Author: Ma Bingyao * + * * +\**********************************************************/ + +(function (hprose, global, undefined) { + 'use strict'; + + var Future = hprose.Future; + var atob = global.atob; + var btoa = global.btoa; + var toUint8Array = hprose.toUint8Array; + var toBinaryString = hprose.toBinaryString; + + function noop(){} + + var socketPool = {}; + var socketManager = null; + + function APICloudTcpSocket() { + if (socketManager === null) { + socketManager = global.api.require('socketManager'); + } + this.socketId = new Future(); + this.connected = false; + this.timeid = undefined; + this.onclose = noop; + this.onconnect = noop; + this.onreceive = noop; + this.onerror = noop; + } + + Object.defineProperties(APICloudTcpSocket.prototype, { + connect: { value: function(address, port, options) { + var self = this; + socketManager.createSocket({ + type: 'tcp', + host: address, + port: port, + timeout: options.timeout, + returnBase64: true + }, + function(ret/*, err*/) { + if (ret) { + switch(ret.state) { + case 101: break; + case 102: self.socketId.resolve(ret.sid); break; + case 103: self.onreceive(toUint8Array(atob(ret.data.replace(/\s+/g, '')))); break; + case 201: self.socketId.reject(new Error('Create TCP socket failed')); break; + case 202: self.socketId.reject(new Error('TCP connection failed')); break; + case 203: self.onclose(); self.onerror(new Error('Abnormal disconnect connection')); break; + case 204: self.onclose(); break; + case 205: self.onclose(); self.onerror(new Error('Unknown error')); break; + } + } + }); + this.socketId.then(function(socketId) { + socketPool[socketId] = self; + self.connected = true; + self.onconnect(socketId); + }, function(reason) { + self.onerror(reason); + }); + } }, + send: { value: function(data) { + var self = this; + var promise = new Future(); + this.socketId.then(function(socketId) { + socketManager.write({ + sid: socketId, + data: btoa(toBinaryString(data)), + base64: true + }, + function(ret, err) { + if (ret.status) { + promise.resolve(); + } + else { + self.onerror(new Error(err.msg)); + promise.reject(err.msg); + self.destroy(); + } + }); + }); + return promise; + } }, + destroy: { value: function() { + var self = this; + this.connected = false; + this.socketId.then(function(socketId) { + socketManager.closeSocket({ + sid: socketId + }, + function(ret, err) { + if (!ret.status) { + self.onerror(new Error(err.msg)); + } + }); + delete socketPool[socketId]; + //self.onclose(); + }); + } }, + ref: { value: noop }, + unref: { value: noop }, + clearTimeout: { value: function() { + if (this.timeid !== undefined) { + global.clearTimeout(this.timeid); + } + } }, + setTimeout: { value: function(timeout, fn) { + this.clearTimeout(); + this.timeid = global.setTimeout(fn, timeout); + } } + }); + + hprose.APICloudTcpSocket = APICloudTcpSocket; + +})(hprose, hprose.global); + +/**********************************************************\ +| | +| hprose | +| | +| Official WebSite: http://www.hprose.com/ | +| http://www.hprose.org/ | +| | +\**********************************************************/ +/**********************************************************\ + * * + * TcpClient.js * + * * + * hprose tcp client for HTML5. * + * * + * LastModified: Dec 2, 2016 * + * Author: Ma Bingyao * + * * +\**********************************************************/ + +(function (hprose, global, undefined) { + 'use strict'; + + var ChromeTcpSocket = hprose.ChromeTcpSocket; + var APICloudTcpSocket = hprose.APICloudTcpSocket; + var Client = hprose.Client; + var BytesIO = hprose.BytesIO; + var Future = hprose.Future; + var TimeoutError = global.TimeoutError; + var parseuri = hprose.parseuri; + + function noop(){} + + function setReceiveHandler(socket, onreceive) { + socket.onreceive = function(data) { + if (!('receiveEntry' in socket)) { + socket.receiveEntry = { + stream: new BytesIO(), + headerLength: 4, + dataLength: -1, + id: null + }; + } + var entry = socket.receiveEntry; + var stream = entry.stream; + var headerLength = entry.headerLength; + var dataLength = entry.dataLength; + var id = entry.id; + stream.write(data); + while (true) { + if ((dataLength < 0) && (stream.length >= headerLength)) { + dataLength = stream.readInt32BE(); + if ((dataLength & 0x80000000) !== 0) { + dataLength &= 0x7fffffff; + headerLength = 8; + } + } + if ((headerLength === 8) && (id === null) && (stream.length >= headerLength)) { + id = stream.readInt32BE(); + } + if ((dataLength >= 0) && ((stream.length - headerLength) >= dataLength)) { + onreceive(stream.read(dataLength), id); + headerLength = 4; + id = null; + stream.trunc(); + dataLength = -1; + } + else { + break; + } + } + entry.stream = stream; + entry.headerLength = headerLength; + entry.dataLength = dataLength; + entry.id = id; + }; + } + + function TcpTransporter(client) { + if (client) { + this.client = client; + this.uri = this.client.uri; + this.size = 0; + this.pool = []; + this.requests = []; + } + } + + Object.defineProperties(TcpTransporter.prototype, { + create: { value: function() { + var parser = parseuri(this.uri); + var protocol = parser.protocol; + var address = parser.hostname; + var port = parseInt(parser.port, 10); + var tls; + if (protocol === 'tcp:' || + protocol === 'tcp4:' || + protocol === 'tcp6:') { + tls = false; + } + else if (protocol === 'tcps:' || + protocol === 'tcp4s:' || + protocol === 'tcp6s:' || + protocol === 'tls:') { + tls = true; + } + else { + throw new Error('Unsupported ' + protocol + ' protocol!'); + } + var conn; + if (global.chrome && global.chrome.sockets && global.chrome.sockets.tcp) { + conn = new ChromeTcpSocket(); + } + else if (global.api && global.api.require) { + conn = new APICloudTcpSocket(); + } + else { + throw new Error('TCP Socket is not supported by this browser or platform.'); + } + var self = this; + conn.connect(address, port, { + persistent: true, + tls: tls, + timeout: this.client.timeout, + noDelay: this.client.noDelay, + keepAlive: this.client.keepAlive + }); + conn.onclose = function() { --self.size; }; + ++this.size; + return conn; + } } + }); + + function FullDuplexTcpTransporter(client) { + TcpTransporter.call(this, client); + } + + FullDuplexTcpTransporter.prototype = Object.create( + TcpTransporter.prototype, { + fetch: { value: function() { + var pool = this.pool; + while (pool.length > 0) { + var conn = pool.pop(); + if (conn.connected) { + if (conn.count === 0) { + conn.clearTimeout(); + conn.ref(); + } + return conn; + } + } + return null; + } }, + init: { value: function(conn) { + var self = this; + conn.count = 0; + conn.futures = {}; + conn.timeoutIds = {}; + setReceiveHandler(conn, function(data, id) { + var future = conn.futures[id]; + if (future) { + self.clean(conn, id); + if (conn.count === 0) { + self.recycle(conn); + } + future.resolve(data); + } + }); + conn.onerror = function (e) { + var futures = conn.futures; + for (var id in futures) { + var future = futures[id]; + self.clean(conn, id); + future.reject(e); + } + }; + } }, + recycle: { value: function(conn) { + conn.unref(); + conn.setTimeout(this.client.poolTimeout, function() { + conn.destroy(); + }); + } }, + clean: { value: function(conn, id) { + if (conn.timeoutIds[id] !== undefined) { + global.clearTimeout(conn.timeoutIds[id]); + delete conn.timeoutIds[id]; + } + delete conn.futures[id]; + --conn.count; + this.sendNext(conn); + } }, + sendNext: { value: function(conn) { + if (conn.count < 10) { + if (this.requests.length > 0) { + var request = this.requests.pop(); + request.push(conn); + this.send.apply(this, request); + } + else { + if (this.pool.lastIndexOf(conn) < 0) { + this.pool.push(conn); + } + } + } + } }, + send: { value: function(request, future, id, context, conn) { + var self = this; + var timeout = context.timeout; + if (timeout > 0) { + conn.timeoutIds[id] = global.setTimeout(function() { + self.clean(conn, id); + if (conn.count === 0) { + self.recycle(conn); + } + future.reject(new TimeoutError('timeout')); + }, timeout); + } + conn.count++; + conn.futures[id] = future; + + var len = request.length; + var buf = new BytesIO(8 + len); + buf.writeInt32BE(len | 0x80000000); + buf.writeInt32BE(id); + buf.write(request); + conn.send(buf.buffer).then(function() { + self.sendNext(conn); + }); + } }, + getNextId: { value: function() { + return (this.nextid < 0x7fffffff) ? ++this.nextid : this.nextid = 0; + } }, + sendAndReceive: { value: function(request, future, context) { + var conn = this.fetch(); + var id = this.getNextId(); + if (conn) { + this.send(request, future, id, context, conn); + } + else if (this.size < this.client.maxPoolSize) { + conn = this.create(); + conn.onerror = function(e) { + future.reject(e); + }; + var self = this; + conn.onconnect = function() { + self.init(conn); + self.send(request, future, id, context, conn); + }; + } + else { + this.requests.push([request, future, id, context]); + } + } } + }); + + FullDuplexTcpTransporter.prototype.constructor = TcpTransporter; + + function HalfDuplexTcpTransporter(client) { + TcpTransporter.call(this, client); + } + + HalfDuplexTcpTransporter.prototype = Object.create( + TcpTransporter.prototype, { + fetch: { value: function() { + var pool = this.pool; + while (pool.length > 0) { + var conn = pool.pop(); + if (conn.connected) { + conn.clearTimeout(); + conn.ref(); + return conn; + } + } + return null; + } }, + recycle: { value: function(conn) { + if (this.pool.lastIndexOf(conn) < 0) { + conn.unref(); + conn.setTimeout(this.client.poolTimeout, function() { + conn.destroy(); + }); + this.pool.push(conn); + } + } }, + clean: { value: function(conn) { + conn.onreceive = noop; + conn.onerror = noop; + if (conn.timeoutId !== undefined) { + global.clearTimeout(conn.timeoutId); + delete conn.timeoutId; + } + } }, + sendNext: { value: function(conn) { + if (this.requests.length > 0) { + var request = this.requests.pop(); + request.push(conn); + this.send.apply(this, request); + } + else { + this.recycle(conn); + } + } }, + send: { value: function(request, future, context, conn) { + var self = this; + var timeout = context.timeout; + if (timeout > 0) { + conn.timeoutId = global.setTimeout(function() { + self.clean(conn); + conn.destroy(); + future.reject(new TimeoutError('timeout')); + }, timeout); + } + setReceiveHandler(conn, function(data) { + self.clean(conn); + self.sendNext(conn); + future.resolve(data); + }); + conn.onerror = function(e) { + self.clean(conn); + future.reject(e); + }; + + var len = request.length; + var buf = new BytesIO(4 + len); + buf.writeInt32BE(len); + buf.write(request); + conn.send(buf.buffer); + } }, + sendAndReceive: { value: function(request, future, context) { + var conn = this.fetch(); + if (conn) { + this.send(request, future, context, conn); + } + else if (this.size < this.client.maxPoolSize) { + conn = this.create(); + var self = this; + conn.onerror = function(e) { + future.reject(e); + }; + conn.onconnect = function() { + self.send(request, future, context, conn); + }; + } + else { + this.requests.push([request, future, context]); + } + } } + }); + + HalfDuplexTcpTransporter.prototype.constructor = TcpTransporter; + + function TcpClient(uri, functions, settings) { + if (this.constructor !== TcpClient) { + return new TcpClient(uri, functions, settings); + } + Client.call(this, uri, functions, settings); + + var self = this; + var _noDelay = true; + var _fullDuplex = false; + var _maxPoolSize = 10; + var _poolTimeout = 30000; + var fdtrans = null; + var hdtrans = null; + + function getNoDelay() { + return _noDelay; + } + + function setNoDelay(value) { + _noDelay = !!value; + } + + function getFullDuplex() { + return _fullDuplex; + } + + function setFullDuplex(value) { + _fullDuplex = !!value; + } + + function getMaxPoolSize() { + return _maxPoolSize; + } + + function setMaxPoolSize(value) { + if (typeof(value) === 'number') { + _maxPoolSize = value | 0; + if (_maxPoolSize < 1) { + _maxPoolSize = 10; + } + } + else { + _maxPoolSize = 10; + } + } + + function getPoolTimeout() { + return _poolTimeout; + } + + function setPoolTimeout(value) { + if (typeof(value) === 'number') { + _poolTimeout = value | 0; + } + else { + _poolTimeout = 0; + } + } + + function sendAndReceive(request, context) { + var future = new Future(); + if (_fullDuplex) { + if ((fdtrans === null) || (fdtrans.uri !== self.uri)) { + fdtrans = new FullDuplexTcpTransporter(self); + } + fdtrans.sendAndReceive(request, future, context); + } + else { + if ((hdtrans === null) || (hdtrans.uri !== self.uri)) { + hdtrans = new HalfDuplexTcpTransporter(self); + } + hdtrans.sendAndReceive(request, future, context); + } + if (context.oneway) { future.resolve(); } + return future; + } + + Object.defineProperties(this, { + noDelay: { get: getNoDelay, set: setNoDelay }, + fullDuplex: { get: getFullDuplex, set: setFullDuplex }, + maxPoolSize: { get: getMaxPoolSize, set: setMaxPoolSize }, + poolTimeout: { get: getPoolTimeout, set: setPoolTimeout }, + sendAndReceive: { value: sendAndReceive } + }); + } + + function checkuri(uri) { + var parser = parseuri(uri); + var protocol = parser.protocol; + if (protocol === 'tcp:' || + protocol === 'tcp4:'|| + protocol === 'tcp6:' || + protocol === 'tcps:' || + protocol === 'tcp4s:' || + protocol === 'tcp6s:' || + protocol === 'tls:') { + return; + } + throw new Error('This client desn\'t support ' + protocol + ' scheme.'); + } + + function create(uri, functions, settings) { + if (typeof uri === 'string') { + checkuri(uri); + } + else if (Array.isArray(uri)) { + uri.forEach(function(uri) { checkuri(uri); }); + } + else { + throw new Error('You should set server uri first!'); + } + return new TcpClient(uri, functions, settings); + } + + Object.defineProperty(TcpClient, 'create', { value: create }); + + hprose.TcpClient = TcpClient; + +})(hprose, hprose.global); + +/**********************************************************\ +| | +| hprose | +| | +| Official WebSite: http://www.hprose.com/ | +| http://www.hprose.org/ | +| | +\**********************************************************/ + +/**********************************************************\ + * * + * JSONRPCClientFilter.js * + * * + * jsonrpc client filter for JavaScript. * + * * + * LastModified: Nov 18, 2016 * + * Author: Ma Bingyao * + * * +\**********************************************************/ + +/* global JSON */ +(function (hprose) { + 'use strict'; + + var Tags = hprose.Tags; + var BytesIO = hprose.BytesIO; + var Writer = hprose.Writer; + var Reader = hprose.Reader; + + var s_id = 1; + + function JSONRPCClientFilter(version) { + this.version = version || '2.0'; + } + + JSONRPCClientFilter.prototype.inputFilter = function inputFilter(data/*, context*/) { + var json = BytesIO.toString(data); + if (json.charAt(0) === '{') { + json = '[' + json + ']'; + } + var responses = JSON.parse(json); + var stream = new BytesIO(); + var writer = new Writer(stream, true); + for (var i = 0, n = responses.length; i < n; ++i) { + var response = responses[i]; + if (response.error) { + stream.writeByte(Tags.TagError); + writer.writeString(response.error.message); + } + else { + stream.writeByte(Tags.TagResult); + writer.serialize(response.result); + } + } + stream.writeByte(Tags.TagEnd); + return stream.bytes; + }; + + JSONRPCClientFilter.prototype.outputFilter = function outputFilter(data/*, context*/) { + var requests = []; + var stream = new BytesIO(data); + var reader = new Reader(stream, false, false); + var tag = stream.readByte(); + do { + var request = {}; + if (tag === Tags.TagCall) { + request.method = reader.readString(); + tag = stream.readByte(); + if (tag === Tags.TagList) { + request.params = reader.readListWithoutTag(); + tag = stream.readByte(); + } + if (tag === Tags.TagTrue) { + tag = stream.readByte(); + } + } + if (this.version === '1.1') { + request.version = '1.1'; + } + else if (this.version === '2.0') { + request.jsonrpc = '2.0'; + } + request.id = s_id++; + requests.push(request); + } while (tag === Tags.TagCall); + if (requests.length > 1) { + return JSON.stringify(requests); + } + return JSON.stringify(requests[0]); + }; + + hprose.JSONRPCClientFilter = JSONRPCClientFilter; + +})(hprose); + +/**********************************************************\ +| | +| hprose | +| | +| Official WebSite: http://www.hprose.com/ | +| http://www.hprose.org/ | +| | +\**********************************************************/ + +/**********************************************************\ + * * + * Loader.js * + * * + * hprose CommonJS/AMD/CMD loader for HTML5. * + * * + * LastModified: Nov 18, 2016 * + * Author: Ma Bingyao * + * * +\**********************************************************/ + +/* global define, module */ +(function (hprose) { + 'use strict'; + + hprose.common = { + Completer: hprose.Completer, + Future: hprose.Future, + ResultMode: hprose.ResultMode + }; + + hprose.io = { + BytesIO: hprose.BytesIO, + ClassManager: hprose.ClassManager, + Tags: hprose.Tags, + RawReader: hprose.RawReader, + Reader: hprose.Reader, + Writer: hprose.Writer, + Formatter: hprose.Formatter + }; + + hprose.client = { + Client: hprose.Client, + HttpClient: hprose.HttpClient, + TcpClient: hprose.TcpClient, + WebSocketClient: hprose.WebSocketClient + }; + + hprose.filter = { + JSONRPCClientFilter: hprose.JSONRPCClientFilter + }; + + if (typeof define === 'function') { + if (define.cmd) { + define('hprose', [], hprose); + } + else if (define.amd) { + define('hprose', [], function() { return hprose; }); + } + } + if (typeof module === 'object') { + module.exports = hprose; + } +})(hprose); diff --git a/gulpfile.js b/gulpfile.js index 4eb13ed..cf47b0a 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -1,3 +1,4 @@ +/* jshint node:true */ var gulp = require('gulp'), uglify = require('gulp-uglify'), concat = require('gulp-concat'), @@ -9,8 +10,11 @@ gulp.task('clear', function(){ del(['dist/hprose-html5.js']); }); -gulp.task('compress', ['clear'], function() { - return gulp.src(['src/Init.js', +gulp.task('concat', ['clear'], function() { + return gulp.src(['src/CopyRight.js', + 'src/Init.js', + 'src/Helper.js', + 'src/Polyfill.js', 'src/HarmonyMaps.js', 'src/TimeoutError.js', 'src/setImmediate.js', @@ -23,18 +27,35 @@ gulp.task('compress', ['clear'], function() { 'src/Formatter.js', 'src/ResultMode.js', 'src/Client.js', + 'src/CookieManager.js', 'src/HttpClient.js', 'src/WebSocketClient.js', + 'src/ChromeTcpSocket.js', + 'src/APICloudTcpSocket.js', + 'src/TcpClient.js', 'src/JSONRPCClientFilter.js', 'src/Loader.js']) + .pipe(concat('hprose-html5.src.js')) .pipe(jshint()) .pipe(jshint.reporter()) - .pipe(concat('hprose-html5.js')) - .pipe(uglify()) - .pipe(lzmajs()) .pipe(gulp.dest('dist')); }); +gulp.task('uglify', ['concat'], function() { + return gulp.src(['dist/hprose-html5.src.js', + 'utils/regenerator-runtime.js']) + .pipe(concat('hprose-html5.js')) + .pipe(uglify()) + .pipe(gulp.dest('dist')); +}); + +gulp.task('compress', ['uglify'], function() { + return gulp.src(['dist/hprose-html5.js']) + .pipe(concat('hprose-html5.min.js')) + .pipe(lzmajs()) + .pipe(gulp.dest('dist')); +}); + gulp.task('default', ['compress'], function() { return gulp.src(['src/CopyRight.js', 'dist/hprose-html5.js']) .pipe(concat('hprose-html5.js')) diff --git a/package.json b/package.json index 420d9f5..2bd539f 100644 --- a/package.json +++ b/package.json @@ -1,9 +1,8 @@ { "name": "hprose-html5", - "filename": "hprose-html5.js", - "version": "2.0.3", - "description": "Hprose is a High Performance Remote Object Service Engine. It is a modern, lightweight, cross-language, cross-platform, object-oriented, high performance, remote dynamic communication middleware. It is not only easy to use, but powerful. You just need a little time to learn, then you can use it to easily construct cross language cross platform distributed application system.", - "homepage": "https://github.com/andot/hprose", + "version": "2.0.36", + "description": "Hprose is a High Performance Remote Object Service Engine.", + "homepage": "https://github.com/hprose/hprose-html5", "keywords": [ "hprose", "rpc", @@ -42,25 +41,46 @@ "oneway", "promises-aplus" ], - "maintainers": [ - { - "name" : "Ma Bingyao", - "email" : "andot@hprose.com", - "web": "http://hprose.com/" - } - ], - "repositories": [ - { - "type": "git", - "url": "https://github.com/hprose/hprose-html5.git" - } - ], + "author": { + "name": "Ma Bingyao", + "email": "andot@hprose.com", + "url": "http://hprose.com/" + }, + "directories": { + "lib": "dist/" + }, + "main": "dist/hprose-html5.src.js", + "devDependencies": { + "del": "^3.0.0", + "gulp": "^3.9.1", + "gulp-concat": "^2.6.1", + "gulp-jshint": "^2.1.0", + "gulp-lzmajs": "^1.2.1", + "gulp-uglify": "^2.0.0", + "jshint": "^2.9.5", + "promises-aplus-tests": "*" + }, + "scripts": { + "aplus-tests": "promises-aplus-tests dist/hprose-html5.js" + }, + "engines": { + "node": "*" + }, + "repository": { + "type": "git", + "url": "https://github.com/hprose/hprose-html5.git" + }, "autoupdate": { "source": "git", "target": "git://github.com/hprose/hprose-html5.git", "basePath": "dist/", "files": [ - "hprose-html5.js" + "hprose-html5.src.js" ] - } + }, + "bugs": { + "url": "https://github.com/hprose/hprose-html5/issues", + "email": "andot@hprose.com" + }, + "license": "MIT" } diff --git a/src/APICloudTcpSocket.js b/src/APICloudTcpSocket.js new file mode 100644 index 0000000..c943a3a --- /dev/null +++ b/src/APICloudTcpSocket.js @@ -0,0 +1,132 @@ +/**********************************************************\ +| | +| hprose | +| | +| Official WebSite: http://www.hprose.com/ | +| http://www.hprose.org/ | +| | +\**********************************************************/ +/**********************************************************\ + * * + * APICloudTcpSocket.js * + * * + * APICloud tcp socket for HTML5. * + * * + * LastModified: Nov 18, 2016 * + * Author: Ma Bingyao * + * * +\**********************************************************/ + +(function (hprose, global, undefined) { + 'use strict'; + + var Future = hprose.Future; + var atob = global.atob; + var btoa = global.btoa; + var toUint8Array = hprose.toUint8Array; + var toBinaryString = hprose.toBinaryString; + + function noop(){} + + var socketPool = {}; + var socketManager = null; + + function APICloudTcpSocket() { + if (socketManager === null) { + socketManager = global.api.require('socketManager'); + } + this.socketId = new Future(); + this.connected = false; + this.timeid = undefined; + this.onclose = noop; + this.onconnect = noop; + this.onreceive = noop; + this.onerror = noop; + } + + Object.defineProperties(APICloudTcpSocket.prototype, { + connect: { value: function(address, port, options) { + var self = this; + socketManager.createSocket({ + type: 'tcp', + host: address, + port: port, + timeout: options.timeout, + returnBase64: true + }, + function(ret/*, err*/) { + if (ret) { + switch(ret.state) { + case 101: break; + case 102: self.socketId.resolve(ret.sid); break; + case 103: self.onreceive(toUint8Array(atob(ret.data.replace(/\s+/g, '')))); break; + case 201: self.socketId.reject(new Error('Create TCP socket failed')); break; + case 202: self.socketId.reject(new Error('TCP connection failed')); break; + case 203: self.onclose(); self.onerror(new Error('Abnormal disconnect connection')); break; + case 204: self.onclose(); break; + case 205: self.onclose(); self.onerror(new Error('Unknown error')); break; + } + } + }); + this.socketId.then(function(socketId) { + socketPool[socketId] = self; + self.connected = true; + self.onconnect(socketId); + }, function(reason) { + self.onerror(reason); + }); + } }, + send: { value: function(data) { + var self = this; + var promise = new Future(); + this.socketId.then(function(socketId) { + socketManager.write({ + sid: socketId, + data: btoa(toBinaryString(data)), + base64: true + }, + function(ret, err) { + if (ret.status) { + promise.resolve(); + } + else { + self.onerror(new Error(err.msg)); + promise.reject(err.msg); + self.destroy(); + } + }); + }); + return promise; + } }, + destroy: { value: function() { + var self = this; + this.connected = false; + this.socketId.then(function(socketId) { + socketManager.closeSocket({ + sid: socketId + }, + function(ret, err) { + if (!ret.status) { + self.onerror(new Error(err.msg)); + } + }); + delete socketPool[socketId]; + //self.onclose(); + }); + } }, + ref: { value: noop }, + unref: { value: noop }, + clearTimeout: { value: function() { + if (this.timeid !== undefined) { + global.clearTimeout(this.timeid); + } + } }, + setTimeout: { value: function(timeout, fn) { + this.clearTimeout(); + this.timeid = global.setTimeout(fn, timeout); + } } + }); + + hprose.APICloudTcpSocket = APICloudTcpSocket; + +})(hprose, hprose.global); diff --git a/src/Base64.js b/src/Base64.js new file mode 100644 index 0000000..d712887 --- /dev/null +++ b/src/Base64.js @@ -0,0 +1,134 @@ +/**********************************************************\ +| | +| hprose | +| | +| Official WebSite: http://www.hprose.com/ | +| http://www.hprose.org/ | +| | +\**********************************************************/ +/**********************************************************\ + * * + * Base64.js * + * * + * Base64 for HTML5. * + * * + * LastModified: Nov 18, 2016 * + * Author: Ma Bingyao * + * * +\**********************************************************/ + +(function (global) { + 'use strict'; + + if (typeof(global.btoa) === "undefined") { + global.btoa = (function() { + var base64EncodeChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'.split(''); + return function(str) { + var buf, i, j, len, r, l, c; + i = j = 0; + len = str.length; + r = len % 3; + len = len - r; + l = (len / 3) << 2; + if (r > 0) { + l += 4; + } + buf = new Array(l); + + while (i < len) { + c = str.charCodeAt(i++) << 16 | + str.charCodeAt(i++) << 8 | + str.charCodeAt(i++); + buf[j++] = base64EncodeChars[c >> 18] + + base64EncodeChars[c >> 12 & 0x3f] + + base64EncodeChars[c >> 6 & 0x3f] + + base64EncodeChars[c & 0x3f] ; + } + if (r === 1) { + c = str.charCodeAt(i++); + buf[j++] = base64EncodeChars[c >> 2] + + base64EncodeChars[(c & 0x03) << 4] + + "=="; + } + else if (r === 2) { + c = str.charCodeAt(i++) << 8 | + str.charCodeAt(i++); + buf[j++] = base64EncodeChars[c >> 10] + + base64EncodeChars[c >> 4 & 0x3f] + + base64EncodeChars[(c & 0x0f) << 2] + + "="; + } + return buf.join(''); + }; + })(); + } + + if (typeof(global.atob) === "undefined") { + global.atob = (function() { + var base64DecodeChars = [ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, + -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1 + ]; + return function(str) { + var c1, c2, c3, c4; + var i, j, len, r, l, out; + + len = str.length; + if (len % 4 !== 0) { + return ''; + } + if (/[^ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\+\/\=]/.test(str)) { + return ''; + } + if (str.charAt(len - 2) === '=') { + r = 1; + } + else if (str.charAt(len - 1) === '=') { + r = 2; + } + else { + r = 0; + } + l = len; + if (r > 0) { + l -= 4; + } + l = (l >> 2) * 3 + r; + out = new Array(l); + + i = j = 0; + while (i < len) { + // c1 + c1 = base64DecodeChars[str.charCodeAt(i++)]; + if (c1 === -1) { break; } + + // c2 + c2 = base64DecodeChars[str.charCodeAt(i++)]; + if (c2 === -1) { break; } + + out[j++] = String.fromCharCode((c1 << 2) | ((c2 & 0x30) >> 4)); + + // c3 + c3 = base64DecodeChars[str.charCodeAt(i++)]; + if (c3 === -1) { break; } + + out[j++] = String.fromCharCode(((c2 & 0x0f) << 4) | ((c3 & 0x3c) >> 2)); + + // c4 + c4 = base64DecodeChars[str.charCodeAt(i++)]; + if (c4 === -1) { break; } + + out[j++] = String.fromCharCode(((c3 & 0x03) << 6) | c4); + } + return out.join(''); + }; + })(); + } + +})(hprose.global); diff --git a/src/BytesIO.js b/src/BytesIO.js index 160be21..fea8658 100644 --- a/src/BytesIO.js +++ b/src/BytesIO.js @@ -13,34 +13,32 @@ * * * hprose BytesIO for HTML5. * * * - * LastModified: Aug 21, 2015 * + * LastModified: Nov 18, 2016 * * Author: Ma Bingyao * * * \**********************************************************/ -/* jshint -W067 */ -(function (global, undefined) { +(function (hprose, undefined) { 'use strict'; - var Future = global.hprose.Future; + var toBinaryString = hprose.toBinaryString; var _EMPTY_BYTES = new Uint8Array(0); var _INIT_SIZE = 1024; - var indexof = Function.prototype.call.bind(Array.prototype.indexOf); function writeInt32BE(bytes, p, i) { - bytes[p++] = i >>> 24 & 0xff; - bytes[p++] = i >>> 16 & 0xff; - bytes[p++] = i >>> 8 & 0xff; - bytes[p++] = i & 0xff; + bytes[p++] = i >>> 24 & 0xFF; + bytes[p++] = i >>> 16 & 0xFF; + bytes[p++] = i >>> 8 & 0xFF; + bytes[p++] = i & 0xFF; return p; } function writeInt32LE(bytes, p, i) { - bytes[p++] = i & 0xff; - bytes[p++] = i >>> 8 & 0xff; - bytes[p++] = i >>> 16 & 0xff; - bytes[p++] = i >>> 24 & 0xff; + bytes[p++] = i & 0xFF; + bytes[p++] = i >>> 8 & 0xFF; + bytes[p++] = i >>> 16 & 0xFF; + bytes[p++] = i >>> 24 & 0xFF; return p; } @@ -55,7 +53,7 @@ bytes[p++] = 0xC0 | (codeUnit >> 6); bytes[p++] = 0x80 | (codeUnit & 0x3F); } - else if (codeUnit < 0xD800 || codeUnit > 0xDfff) { + else if (codeUnit < 0xD800 || codeUnit > 0xDFFF) { bytes[p++] = 0xE0 | (codeUnit >> 12); bytes[p++] = 0x80 | ((codeUnit >> 6) & 0x3F); bytes[p++] = 0x80 | (codeUnit & 0x3F); @@ -80,7 +78,7 @@ } function readShortString(bytes, n) { - var charCodes = new Uint16Array(n); + var charCodes = new Array(n); var i = 0, off = 0; for (var len = bytes.length; i < n && off < len; i++) { var unit = bytes[off++]; @@ -100,21 +98,17 @@ if (off < len) { charCodes[i] = ((unit & 0x1F) << 6) | (bytes[off++] & 0x3F); + break; } - else { - throw new Error('Unfinished UTF-8 octet sequence'); - } - break; + throw new Error('Unfinished UTF-8 octet sequence'); case 14: if (off + 1 < len) { charCodes[i] = ((unit & 0x0F) << 12) | ((bytes[off++] & 0x3F) << 6) | (bytes[off++] & 0x3F); + break; } - else { - throw new Error('Unfinished UTF-8 octet sequence'); - } - break; + throw new Error('Unfinished UTF-8 octet sequence'); case 15: if (off + 2 < len) { var rune = (((unit & 0x07) << 18) | @@ -124,28 +118,24 @@ if (0 <= rune && rune <= 0xFFFFF) { charCodes[i++] = (((rune >> 10) & 0x03FF) | 0xD800); charCodes[i] = ((rune & 0x03FF) | 0xDC00); + break; } - else { - throw new Error('Character outside valid Unicode range: 0x' + rune.toString(16)); - } - } - else { - throw new Error('Unfinished UTF-8 octet sequence'); + throw new Error('Character outside valid Unicode range: 0x' + rune.toString(16)); } - break; + throw new Error('Unfinished UTF-8 octet sequence'); default: throw new Error('Bad UTF-8 encoding 0x' + unit.toString(16)); } } if (i < n) { - charCodes = charCodes.subarray(0, i); + charCodes.length = i; } return [String.fromCharCode.apply(String, charCodes), off]; } function readLongString(bytes, n) { var buf = []; - var charCodes = new Uint16Array(0xffff); + var charCodes = new Array(0x8000); var i = 0, off = 0; for (var len = bytes.length; i < n && off < len; i++) { var unit = bytes[off++]; @@ -165,21 +155,17 @@ if (off < len) { charCodes[i] = ((unit & 0x1F) << 6) | (bytes[off++] & 0x3F); + break; } - else { - throw new Error('Unfinished UTF-8 octet sequence'); - } - break; + throw new Error('Unfinished UTF-8 octet sequence'); case 14: if (off + 1 < len) { charCodes[i] = ((unit & 0x0F) << 12) | ((bytes[off++] & 0x3F) << 6) | (bytes[off++] & 0x3F); + break; } - else { - throw new Error('Unfinished UTF-8 octet sequence'); - } - break; + throw new Error('Unfinished UTF-8 octet sequence'); case 15: if (off + 2 < len) { var rune = (((unit & 0x07) << 18) | @@ -189,42 +175,40 @@ if (0 <= rune && rune <= 0xFFFFF) { charCodes[i++] = (((rune >> 10) & 0x03FF) | 0xD800); charCodes[i] = ((rune & 0x03FF) | 0xDC00); + break; } - else { - throw new Error('Character outside valid Unicode range: 0x' + rune.toString(16)); - } + throw new Error('Character outside valid Unicode range: 0x' + rune.toString(16)); } - else { - throw new Error('Unfinished UTF-8 octet sequence'); - } - break; + throw new Error('Unfinished UTF-8 octet sequence'); default: throw new Error('Bad UTF-8 encoding 0x' + unit.toString(16)); } - if (i >= 65534) { + if (i >= 0x7FFF - 1) { var size = i + 1; - buf.push(String.fromCharCode.apply(String, charCodes.subarray(0, size))); + charCodes.length = size; + buf.push(String.fromCharCode.apply(String, charCodes)); n -= size; i = -1; } } if (i > 0) { - buf.push(String.fromCharCode.apply(String, charCodes.subarray(0, i))); + charCodes.length = i; + buf.push(String.fromCharCode.apply(String, charCodes)); } return [buf.join(''), off]; } function readString(bytes, n) { - if (n === undefined || n === null || (n < 0)) n = bytes.length; - if (n === 0) return ['', 0]; - return ((n < 100000) ? + if (n === undefined || n === null || (n < 0)) { n = bytes.length; } + if (n === 0) { return ['', 0]; } + return ((n < 0xFFFF) ? readShortString(bytes, n) : readLongString(bytes, n)); } function readStringAsBytes(bytes, n) { - if (n === undefined) n = bytes.length; - if (n === 0) return _EMPTY_BYTES; + if (n === undefined) { n = bytes.length; } + if (n === 0) { return [_EMPTY_BYTES, 0]; } var i = 0, off = 0; for (var len = bytes.length; i < n && off < len; i++) { var unit = bytes[off++]; @@ -242,19 +226,15 @@ case 13: if (off < len) { off++; + break; } - else { - throw new Error('Unfinished UTF-8 octet sequence'); - } - break; + throw new Error('Unfinished UTF-8 octet sequence'); case 14: if (off + 1 < len) { off += 2; + break; } - else { - throw new Error('Unfinished UTF-8 octet sequence'); - } - break; + throw new Error('Unfinished UTF-8 octet sequence'); case 15: if (off + 2 < len) { var rune = (((unit & 0x07) << 18) | @@ -263,15 +243,11 @@ (bytes[off++] & 0x3F)) - 0x10000; if (0 <= rune && rune <= 0xFFFFF) { i++; + break; } - else { - throw new Error('Character outside valid Unicode range: 0x' + rune.toString(16)); - } + throw new Error('Character outside valid Unicode range: 0x' + rune.toString(16)); } - else { - throw new Error('Unfinished UTF-8 octet sequence'); - } - break; + throw new Error('Unfinished UTF-8 octet sequence'); default: throw new Error('Bad UTF-8 encoding 0x' + unit.toString(16)); } @@ -360,6 +336,17 @@ _EMPTY_BYTES : this._bytes.subarray(0, this._length); } }, + buffer: { get : function() { + if (this._bytes === null) { + return _EMPTY_BYTES.buffer; + } + if (this._bytes.buffer.slice) { + return this._bytes.buffer.slice(0, this._length); + } + var buf = new Uint8Array(this._length); + buf.set(this._bytes.subarray(0, this._length)); + return buf.buffer; + } }, mark: { value: function() { this._wmark = this._length; this._rmark = this._off; @@ -388,9 +375,9 @@ throw new TypeError('value is out of bounds'); } }, writeUInt32BE: { value: function(i) { - if ((i === (i | 0)) && (i >= 0)) { + if (((i & 0x7FFFFFFF) + 0x80000000 === i) && (i >= 0)) { this._grow(4); - this._length = writeInt32BE(this._bytes, this._length, i); + this._length = writeInt32BE(this._bytes, this._length, i | 0); return; } throw new TypeError('value is out of bounds'); @@ -404,16 +391,16 @@ throw new TypeError('value is out of bounds'); } }, writeUInt32LE: { value: function(i) { - if ((i === (i | 0)) && (i >= 0)) { + if (((i & 0x7FFFFFFF) + 0x80000000 === i) && (i >= 0)) { this._grow(4); - this._length = writeInt32LE(this._bytes, this._length, i); + this._length = writeInt32LE(this._bytes, this._length, i | 0); return; } throw new TypeError('value is out of bounds'); } }, write: { value: function(data) { var n = data.byteLength || data.length; - if (n === 0) return; + if (n === 0) { return; } this._grow(n); var bytes = this._bytes; var length = this._length; @@ -437,7 +424,7 @@ } }, writeAsciiString: { value: function(str) { var n = str.length; - if (n === 0) return; + if (n === 0) { return; } this._grow(n); var bytes = this._bytes; var l = this._length; @@ -448,7 +435,7 @@ } }, writeString: { value: function(str) { var n = str.length; - if (n === 0) return; + if (n === 0) { return; } // A single code unit uses at most 3 bytes. // Two code units at most 4. this._grow(n * 3); @@ -476,7 +463,7 @@ readUInt32BE: { value: function() { var value = this.readInt32BE(); if (value < 0) { - return (value & 0x7fffffff) + 0x80000000; + return (value & 0x7FFFFFFF) + 0x80000000; } return value; } }, @@ -496,7 +483,7 @@ readUInt32LE: { value: function() { var value = this.readInt32LE(); if (value < 0) { - return (value & 0x7fffffff) + 0x80000000; + return (value & 0x7FFFFFFF) + 0x80000000; } return value; } }, @@ -504,7 +491,7 @@ if (this._off + n > this._length) { n = this._length - this._off; } - if (n === 0) return _EMPTY_BYTES; + if (n === 0) { return _EMPTY_BYTES; } return this._bytes.subarray(this._off, this._off += n); } }, skip: { value: function(n) { @@ -519,7 +506,7 @@ } }, // the result is an Uint8Array, and includes tag. readBytes: { value: function(tag) { - var pos = indexof(this._bytes, tag, this._off); + var pos = Array.indexOf(this._bytes, tag, this._off); var buf; if (pos === -1) { buf = this._bytes.subarray(this._off, this._length); @@ -534,7 +521,7 @@ // the result is a String, and doesn't include tag. // but the position is the same as readBytes readUntil: { value: function(tag) { - var pos = indexof(this._bytes, tag, this._off); + var pos = Array.indexOf(this._bytes, tag, this._off); var str = ''; if (pos === this._off) { this._off++; @@ -553,21 +540,8 @@ if (this._off + n > this._length) { n = this._length - this._off; } - if (n === 0) return ''; - var bytes = this._bytes.subarray(this._off, this._off += n); - if (n < 100000) { - return String.fromCharCode.apply(String, bytes); - } - var remain = n & 0xffff; - var count = n >> 16; - var a = new Array(remain ? count + 1 : count); - for (var i = 0; i < count; ++i) { - a[i] = String.fromCharCode.apply(String, bytes.subarray(i << 16, (i + 1) << 16)); - } - if (remain) { - a[count] = String.fromCharCode.apply(String, bytes.subarray(count << 16, n)); - } - return a.join(''); + if (n === 0) { return ''; } + return toBinaryString(this._bytes.subarray(this._off, this._off += n)); } }, // n is the UTF16 length readStringAsBytes: { value: function(n) { @@ -608,7 +582,7 @@ function toString(data) { /* jshint -W086 */ - if (data.length === 0) return ''; + if (data.length === 0) { return ''; } switch(data.constructor) { case String: return data; case BytesIO: data = data.bytes; @@ -620,8 +594,6 @@ Object.defineProperty(BytesIO, 'toString', { value: toString }); - global.hprose.BytesIO = BytesIO; + hprose.BytesIO = BytesIO; -}(function() { - return this || (1, eval)('this'); -}())); +})(hprose); diff --git a/src/ChromeTcpSocket.js b/src/ChromeTcpSocket.js new file mode 100644 index 0000000..f7d10b7 --- /dev/null +++ b/src/ChromeTcpSocket.js @@ -0,0 +1,181 @@ +/**********************************************************\ +| | +| hprose | +| | +| Official WebSite: http://www.hprose.com/ | +| http://www.hprose.org/ | +| | +\**********************************************************/ +/**********************************************************\ + * * + * ChromeTcpSocket.js * + * * + * chrome tcp socket for JavaScript. * + * * + * LastModified: Nov 18, 2016 * + * Author: Ma Bingyao * + * * +\**********************************************************/ + +(function (hprose, global, undefined) { + 'use strict'; + + var Future = hprose.Future; + + function noop(){} + + var socketPool = {}; + var socketManager = null; + + function receiveListener(info) { + var socket = socketPool[info.socketId]; + socket.onreceive(info.data); + } + + function receiveErrorListener(info) { + var socket = socketPool[info.socketId]; + socket.onerror(info.resultCode); + socket.destroy(); + } + + function ChromeTcpSocket() { + if (socketManager === null) { + socketManager = global.chrome.sockets.tcp; + socketManager.onReceive.addListener(receiveListener); + socketManager.onReceiveError.addListener(receiveErrorListener); + } + this.socketId = new Future(); + this.connected = false; + this.timeid = undefined; + this.onclose = noop; + this.onconnect = noop; + this.onreceive = noop; + this.onerror = noop; + } + + Object.defineProperties(ChromeTcpSocket.prototype, { + connect: { value: function(address, port, options) { + var self = this; + socketManager.create({ persistent: options && options.persistent }, function(createInfo) { + if (options) { + if ('noDelay' in options) { + socketManager.setNoDelay(createInfo.socketId, options.noDelay, function(result) { + if (result < 0) { + self.socketId.reject(result); + socketManager.disconnect(createInfo.socketId); + socketManager.close(createInfo.socketId); + self.onclose(); + } + }); + } + if ('keepAlive' in options) { + socketManager.setKeepAlive(createInfo.socketId, options.keepAlive, function(result) { + if (result < 0) { + self.socketId.reject(result); + socketManager.disconnect(createInfo.socketId); + socketManager.close(createInfo.socketId); + self.onclose(); + } + }); + } + } + if (options && options.tls) { + socketManager.setPaused(createInfo.socketId, true, function() { + socketManager.connect(createInfo.socketId, address, port, function(result) { + if (result < 0) { + self.socketId.reject(result); + socketManager.disconnect(createInfo.socketId); + socketManager.close(createInfo.socketId); + self.onclose(); + } + else { + socketManager.secure(createInfo.socketId, function(secureResult) { + if (secureResult !== 0) { + self.socketId.reject(result); + socketManager.disconnect(createInfo.socketId); + socketManager.close(createInfo.socketId); + self.onclose(); + } + else { + socketManager.setPaused(createInfo.socketId, false, function() { + self.socketId.resolve(createInfo.socketId); + }); + } + }); + } + }); + }); + } + else { + socketManager.connect(createInfo.socketId, address, port, function(result) { + if (result < 0) { + self.socketId.reject(result); + socketManager.disconnect(createInfo.socketId); + socketManager.close(createInfo.socketId); + self.onclose(); + } + else { + self.socketId.resolve(createInfo.socketId); + } + }); + } + }); + this.socketId.then(function(socketId) { + socketPool[socketId] = self; + self.connected = true; + self.onconnect(socketId); + }, function(reason) { + self.onerror(reason); + }); + } }, + send: { value: function(data) { + var self = this; + var promise = new Future(); + this.socketId.then(function(socketId) { + socketManager.send(socketId, data, function(sendInfo) { + if (sendInfo.resultCode < 0) { + self.onerror(sendInfo.resultCode); + promise.reject(sendInfo.resultCode); + self.destroy(); + } + else { + promise.resolve(sendInfo.bytesSent); + } + }); + }); + return promise; + } }, + destroy: { value: function() { + var self = this; + this.connected = false; + this.socketId.then(function(socketId) { + socketManager.disconnect(socketId); + socketManager.close(socketId); + delete socketPool[socketId]; + self.onclose(); + }); + } }, + ref: { value: function() { + this.socketId.then(function(socketId) { + socketManager.setPaused(socketId, false); + }); + } }, + unref: { value: function() { + this.socketId.then(function(socketId) { + socketManager.setPaused(socketId, true); + }); + } }, + clearTimeout: { value: function() { + if (this.timeid !== undefined) { + global.clearTimeout(this.timeid); + } + } }, + setTimeout: { value: function(timeout, fn) { + this.clearTimeout(); + this.timeid = global.setTimeout(fn, timeout); + } } + }); + + hprose.ChromeTcpSocket = ChromeTcpSocket; + +})(hprose, hprose.global); diff --git a/src/ClassManager.js b/src/ClassManager.js index ada281b..8e8e165 100644 --- a/src/ClassManager.js +++ b/src/ClassManager.js @@ -13,13 +13,12 @@ * * * hprose ClassManager for HTML5. * * * - * LastModified: Jul 15, 2015 * + * LastModified: Nov 18, 2016 * * Author: Ma Bingyao * * * \**********************************************************/ -/* jshint -W067 */ -(function (global) { +(function (hprose, global) { 'use strict'; var WeakMap = global.WeakMap; @@ -40,16 +39,14 @@ return classCache[alias]; } - global.hprose.ClassManager = Object.create(null, { + hprose.ClassManager = Object.create(null, { register: { value: register }, getClassAlias: { value: getClassAlias }, getClass: { value: getClass } }); - global.hprose.register = register; + hprose.register = register; register(Object, 'Object'); -}(function() { - return this || (1, eval)('this'); -}())); +})(hprose, hprose.global); diff --git a/src/Client.js b/src/Client.js index fa3f2fa..2a07533 100644 --- a/src/Client.js +++ b/src/Client.js @@ -12,23 +12,24 @@ * * * hprose client for HTML5. * * * - * LastModified: Aug 18, 2015 * + * LastModified: Apr 24, 2018 * * Author: Ma Bingyao * * * \**********************************************************/ -/* jshint -W067 */ -(function (global, undefined) { +/* global Proxy */ +(function (hprose, global, undefined) { 'use strict'; var setImmediate = global.setImmediate; - var Tags = global.hprose.Tags; - var ResultMode = global.hprose.ResultMode; - var BytesIO = global.hprose.BytesIO; - var Writer = global.hprose.Writer; - var Reader = global.hprose.Reader; - var Future = global.hprose.Future; - var slice = Function.prototype.call.bind(Array.prototype.slice); + var Tags = hprose.Tags; + var ResultMode = hprose.ResultMode; + var BytesIO = hprose.BytesIO; + var Writer = hprose.Writer; + var Reader = hprose.Reader; + var Future = hprose.Future; + var parseuri = hprose.parseuri; + var isObjectEmpty = hprose.isObjectEmpty; var GETFUNCTIONS = new Uint8Array(1); GETFUNCTIONS[0] = Tags.TagEnd; @@ -40,13 +41,35 @@ var s_number = 'number'; var s_function = 'function'; var s_object = 'object'; - var s_undefined = 'undefined'; + + function HproseProxy(setFunction, ns) { + var settings = {}; + this.get = function(target, prop/*, receiver*/) { + var name = prop.toString(); + if (ns) { name = ns + '_' + name; } + if (name === 'then') { return undefined; } + if (!target.hasOwnProperty(name)) { + settings[name] = {}; + var handler = new HproseProxy(setFunction, name); + var func = setFunction(settings, name); + handler.apply = function(target, thisArg, argumentsList) { + return func.apply(null, argumentsList); + } + handler.set = function(target, prop, value/*, receiver*/) { + settings[name][prop] = value; + return true; + }; + target[name] = new Proxy(function() {}, handler); + } + return target[name]; + }; + } function Client(uri, functions, settings) { // private members var _uri, - _uris = [], + _uriList = [], _index = -1, _byref = false, _simple = false, @@ -54,10 +77,12 @@ _retry = 10, _idempotent = false, _failswitch = false, + _failround = 0, _lock = false, _tasks = [], _useHarmonyMap = false, _onerror = noop, + _onfailswitch = noop, _filters = [], _batch = false, _batches = [], @@ -94,46 +119,91 @@ request = outputFilter(request, context); return _afterFilterHandler(request, context) .then(function(response) { - if (context.oneway) return; + if (context.oneway) { return; } return inputFilter(response, context); }); } function afterFilterHandler(request, context) { - return self.sendAndReceive(request, context); + return self.sendAndReceive(request, context).catchError(function(e) { + var response = retry(request, context); + if (response !== null) { + return response; + } + throw e; + }); } function sendAndReceive(request, context, onsuccess, onerror) { - _beforeFilterHandler(request, context) - .then(onsuccess, function(e) { - if (retry(request, context, onsuccess, onerror)) return; - onerror(e); - }); + _beforeFilterHandler(request, context).then(onsuccess, onerror); + } + + function failswitch() { + var n = _uriList.length; + if (n > 1) { + var i = _index + 1; + if (i >= n) { + i = 0; + _failround++; + } + _index = i; + _uri = _uriList[_index]; + } + else { + _failround++; + } + _onfailswitch(self); } - function retry(data, context, onsuccess, onerror) { + function retry(data, context) { if (context.failswitch) { - if (++_index >= _uris.length) { - _index = 0; - _uri = _uris[_index]; + failswitch(); + } + if (context.idempotent && (context.retried < context.retry)) { + var interval = ++context.retried * 500; + if (context.failswitch) { + interval -= (_uriList.length - 1) * 500; + } + if (interval > 5000) { + interval = 5000; + } + if (interval > 0) { + return Future.delayed(interval, function() { + return afterFilterHandler(data, context); + }); + } + else { + return afterFilterHandler(data, context); } } - if (context.idempotent) { - if (--context.retry >= 0) { - var interval = (10 - context.retry) * 500; - if (context.retry > 10) interval = 500; - global.setTimeout(function() { - sendAndReceive(data, context, onsuccess, onerror); - }, interval); - return true; + return null; + } + + function normalizeFunctions(functions) { + var root = [Object.create(null)]; + for (var i in functions) { + var func = functions[i].split('_'); + var n = func.length - 1; + if (n > 0) { + var node = root; + for (var j = 0; j < n; j++) { + var f = func[j]; + if (node[0][f] === undefined) { + node[0][f] = [Object.create(null)]; + } + node = node[0][f]; + } + node.push(func[n]); } + root.push(functions[i]); } - return false; + return root; } function initService(stub) { var context = { retry: _retry, + retried: 0, idempotent: true, failswitch: true, timeout: _timeout, @@ -151,7 +221,7 @@ error = new Error(reader.readString()); break; case Tags.TagFunctions: - var functions = reader.readList(); + var functions = normalizeFunctions(reader.readList()); reader.checkTag(Tags.TagEnd); setFunctions(stub, functions); break; @@ -176,7 +246,7 @@ function setFunction(stub, name) { return function() { if (_batch) { - return _invoke(stub, name, slice(arguments), true); + return _invoke(stub, name, Array.slice(arguments), true); } else { return Future.all(arguments).then(function(args) { @@ -187,7 +257,7 @@ } function setMethods(stub, obj, namespace, name, methods) { - if (obj[name] !== undefined) return; + if (obj[name] !== undefined) { return; } obj[name] = {}; if (typeof(methods) === s_string || methods.constructor === Object) { methods = [methods]; @@ -200,7 +270,7 @@ } else { for (var n in m) { - setMethods(stub, obj[name], name + '_', n, m[n]); + setMethods(stub, obj[name], namespace + name + '_', n, m[n]); } } } @@ -225,7 +295,7 @@ function copyargs(src, dest) { var n = Math.min(src.length, dest.length); - for (var i = 0; i < n; ++i) dest[i] = src[i]; + for (var i = 0; i < n; ++i) { dest[i] = src[i]; } } function initContext(batch) { @@ -247,6 +317,7 @@ simple: _simple, timeout: _timeout, retry: _retry, + retried: 0, idempotent: _idempotent, failswitch: _failswitch, oneway: false, @@ -271,9 +342,9 @@ } var i = 0, n = args.length; for (; i < n; ++i) { - if (typeof args[i] === s_function) break; + if (typeof args[i] === s_function) { break; } } - if (i === n) return context; + if (i === n) { return context; } var extra = args.splice(i, n - i); context.onsuccess = extra[0]; n = extra.length; @@ -431,7 +502,7 @@ } function call(name, args, context) { - if (context.sync) _lock = true; + if (context.sync) { _lock = true; } var promise = Future.promise(function(resolve, reject) { _invokeHandler(name, args, context).then(function(result) { try { @@ -475,6 +546,7 @@ var context = { timeout: _timeout, retry: _retry, + retried: 0, idempotent: _idempotent, failswitch: _failswitch, oneway: false, @@ -597,9 +669,9 @@ }); } var batchSize = _batches.length; - if (batchSize === 0) return; + if (batchSize === 0) { return Future.value([]); } var context = getBatchContext(settings); - if (context.sync) _lock = true; + if (context.sync) { _lock = true; } var batches = _batches; _batches = []; var promise = Future.promise(function(resolve, reject) { @@ -653,15 +725,43 @@ _onerror = value; } } + function getOnFailswitch() { + return _onfailswitch; + } + function setOnFailswitch(value) { + if (typeof(value) === s_function) { + _onfailswitch = value; + } + } function getUri() { return _uri; } + function getUriList() { + return _uriList; + } + function setUriList(uriList) { + if (typeof(uriList) === s_string) { + _uriList = [uriList]; + } + else if (Array.isArray(uriList)) { + _uriList = uriList.slice(0); + _uriList.sort(function() { return Math.random() - 0.5; }); + } + else { + return; + } + _index = 0; + _uri = _uriList[_index]; + } function getFailswitch() { return _failswitch; } function setFailswitch(value) { _failswitch = !!value; } + function getFailround() { + return _failround; + } function getTimeout() { return _timeout; } @@ -749,6 +849,9 @@ _filters.splice(i, 1); return true; } + function filters() { + return _filters; + } function useService(uri, functions, create) { if (create === undefined) { if (typeof(functions) === s_boolean) { @@ -781,11 +884,16 @@ (functions && functions.constructor === Object)) { functions = [functions]; } - if (!Array.isArray(functions)) { + if (Array.isArray(functions)) { + setFunctions(stub, functions); + } + else if (typeof(Proxy) === 'undefined') { setImmediate(initService, stub); return _ready; } - setFunctions(stub, functions); + else { + stub = new Proxy({}, new HproseProxy(setFunction)); + } _ready.resolve(stub); return stub; } @@ -794,7 +902,7 @@ if ((argc < 1) || (typeof name !== s_string)) { throw new Error('name must be a string'); } - if (argc === 1) args = []; + if (argc === 1) { args = []; } if (argc === 2) { if (!Array.isArray(args)) { var _args = []; @@ -818,22 +926,18 @@ function ready(onComplete, onError) { return _ready.then(onComplete, onError); } - function getTopic(name, id, create) { + function getTopic(name, id) { if (_topics[name]) { var topics = _topics[name]; if (topics[id]) { return topics[id]; } - return null; - } - if (create) { - _topics[name] = Object.create(null); } return null; } - // subscribe(name, callback, timeout) - // subscribe(name, id, callback, timeout) - function subscribe(name, id, callback, timeout) { + // subscribe(name, callback, timeout, failswitch) + // subscribe(name, id, callback, timeout, failswitch) + function subscribe(name, id, callback, timeout, failswitch) { if (typeof name !== s_string) { throw new TypeError('topic name must be a string.'); } @@ -845,14 +949,14 @@ throw new TypeError('callback must be a function.'); } } + if (!_topics[name]) { + _topics[name] = Object.create(null); + } if (typeof id === s_function) { timeout = callback; callback = id; - if (_id === null) { - _id = autoId(); - } - _id.then(function(id) { - subscribe(name, id, callback, timeout); + autoId().then(function(id) { + subscribe(name, id, callback, timeout, failswitch); }); return; } @@ -861,23 +965,24 @@ } if (Future.isPromise(id)) { id.then(function(id) { - subscribe(name, id, callback, timeout); + subscribe(name, id, callback, timeout, failswitch); }); return; } - if (timeout === undefined) timeout = _timeout; - var topic = getTopic(name, id, true); + // Default subscribe timeout is 5 minutes. + if (timeout === undefined) { timeout = 300000; } + var topic = getTopic(name, id); if (topic === null) { var cb = function() { _invoke(self, name, [id, topic.handler, cb, { idempotent: true, - failswitch: false, + failswitch: failswitch, timeout: timeout }], false); }; topic = { handler: function(result) { - var topic = getTopic(name, id, false); + var topic = getTopic(name, id); if (topic) { if (result !== null) { var callbacks = topic.callbacks; @@ -888,7 +993,7 @@ catch (e) {} } } - if (getTopic(name, id, false) !== null) cb(); + if (getTopic(name, id) !== null) { cb(); } } }, callbacks: [callback] @@ -965,12 +1070,28 @@ else { delTopic(_topics[name], id, callback); } + if (isObjectEmpty(_topics[name])) { + delete _topics[name]; + } + } + function isSubscribed(name) { + return !!_topics[name]; + } + function subscribedList() { + var list = []; + for (var name in _topics) { + list.push(name); + } + return list; } function getId() { return _id; } function autoId() { - return _invoke(self, '#', [], false); + if (_id === null) { + _id = _invoke(self, '#', [], false); + } + return _id; } autoId.sync = true; autoId.idempotent = true; @@ -980,14 +1101,7 @@ _invokeHandler = _invokeHandlers.reduceRight( function(next, handler) { return function(name, args, context) { - try { - var result = handler(name, args, context, next); - if (Future.isFuture(result)) return result; - return Future.value(result); - } - catch (e) { - return Future.error(e); - } + return Future.toPromise(handler(name, args, context, next)); }; }, invokeHandler); } @@ -996,14 +1110,7 @@ _batchInvokeHandler = _batchInvokeHandlers.reduceRight( function(next, handler) { return function(batches, context) { - try { - var result = handler(batches, context, next); - if (Future.isFuture(result)) return result; - return Future.value(result); - } - catch (e) { - return Future.error(e); - } + return Future.toPromise(handler(batches, context, next)); }; }, batchInvokeHandler); } @@ -1012,14 +1119,7 @@ _beforeFilterHandler = _beforeFilterHandlers.reduceRight( function(next, handler) { return function(request, context) { - try { - var response = handler(request, context, next); - if (Future.isFuture(response)) return response; - return Future.value(response); - } - catch (e) { - return Future.error(e); - } + return Future.toPromise(handler(request, context, next)); }; }, beforeFilterHandler); } @@ -1028,14 +1128,7 @@ _afterFilterHandler = _afterFilterHandlers.reduceRight( function(next, handler) { return function(request, context) { - try { - var response = handler(request, context, next); - if (Future.isFuture(response)) return response; - return Future.value(response); - } - catch (e) { - return Future.error(e); - } + return Future.toPromise(handler(request, context, next)); }; }, afterFilterHandler); } @@ -1065,11 +1158,13 @@ }); Object.defineProperties(this, { '#': { value: autoId }, - onError: { get: getOnError, set: setOnError }, onerror: { get: getOnError, set: setOnError }, + onfailswitch: { get: getOnFailswitch, set: setOnFailswitch }, uri: { get: getUri }, + uriList: { get: getUriList, set: setUriList }, id: { get: getId }, failswitch: { get: getFailswitch, set: setFailswitch }, + failround: { get: getFailround }, timeout: { get: getTimeout, set: setTimeout }, retry: { get: getRetry, set: setRetry }, idempotent: { get: getIdempotent, set: setIdempotent }, @@ -1080,11 +1175,14 @@ filter: { get: getFilter, set: setFilter }, addFilter: { value: addFilter }, removeFilter: { value: removeFilter }, + filters: { get: filters }, useService: { value: useService }, invoke: { value: invoke }, ready: { value: ready }, subscribe: { value: subscribe }, unsubscribe: { value: unsubscribe }, + isSubscribed: { value : isSubscribed }, + subscribedList: { value : subscribedList }, use: { value: use }, batch: { value: batch }, beforeFilter: { value: beforeFilter }, @@ -1100,38 +1198,43 @@ } }); } - if (typeof(uri) === s_string) { - _uris = [uri]; - _index = 0; - useService(uri, functions); - } - else if (Array.isArray(uri)) { - _uris = uri; - _index = Math.floor(Math.random() * _uris.length); - useService(_uris[_index], functions); + if (uri) { + setUriList(uri); + useService(functions); } } } function checkuri(uri) { - var parser = document.createElement('a'); - parser.href = uri; - if (parser.protocol === 'http:' || - parser.protocol === 'https:' || - parser.protocol === 'ws:' || - parser.protocol === 'wss:') { + var parser = parseuri(uri); + var protocol = parser.protocol; + if (protocol === 'http:' || + protocol === 'https:' || + protocol === 'tcp:' || + protocol === 'tcp4:'|| + protocol === 'tcp6:' || + protocol === 'tcps:' || + protocol === 'tcp4s:' || + protocol === 'tcp6s:' || + protocol === 'tls:' || + protocol === 'ws:' || + protocol === 'wss:') { return; } - throw new Error('The ' + parser.protocol + ' client isn\'t implemented.'); + throw new Error('The ' + protocol + ' client isn\'t implemented.'); } function create(uri, functions, settings) { try { - return global.hprose.HttpClient.create(uri, functions, settings); + return hprose.HttpClient.create(uri, functions, settings); + } + catch(e) {} + try { + return hprose.TcpClient.create(uri, functions, settings); } catch(e) {} try { - return global.hprose.WebSocketClient.create(uri, functions, settings); + return hprose.WebSocketClient.create(uri, functions, settings); } catch(e) {} if (typeof uri === 'string') { @@ -1146,8 +1249,6 @@ Object.defineProperty(Client, 'create', { value: create }); - global.hprose.Client = Client; + hprose.Client = Client; -}(function() { - return this || (1, eval)('this'); -}())); +})(hprose, hprose.global); diff --git a/src/CookieManager.js b/src/CookieManager.js new file mode 100644 index 0000000..1414c1a --- /dev/null +++ b/src/CookieManager.js @@ -0,0 +1,120 @@ +/**********************************************************\ +| | +| hprose | +| | +| Official WebSite: http://www.hprose.com/ | +| http://www.hprose.org/ | +| | +\**********************************************************/ + +/**********************************************************\ + * * + * CookieManager.js * + * * + * hprose CookieManager for HTML5. * + * * + * LastModified: Dec 2, 2016 * + * Author: Ma Bingyao * + * * +\**********************************************************/ + +(function (hprose) { + 'use strict'; + + var parseuri = hprose.parseuri; + + var s_cookieManager = {}; + + function setCookie(headers, uri) { + var parser = parseuri(uri); + var host = parser.host; + var name, values; + function _setCookie(value) { + var cookies, cookie, i; + cookies = value.replace(/(^\s*)|(\s*$)/g, '').split(';'); + cookie = {}; + value = cookies[0].replace(/(^\s*)|(\s*$)/g, '').split('=', 2); + if (value[1] === undefined) { value[1] = null; } + cookie.name = value[0]; + cookie.value = value[1]; + for (i = 1; i < cookies.length; i++) { + value = cookies[i].replace(/(^\s*)|(\s*$)/g, '').split('=', 2); + if (value[1] === undefined) { value[1] = null; } + cookie[value[0].toUpperCase()] = value[1]; + } + // Tomcat can return SetCookie2 with path wrapped in " + if (cookie.PATH) { + if (cookie.PATH.charAt(0) === '"') { + cookie.PATH = cookie.PATH.substr(1); + } + if (cookie.PATH.charAt(cookie.PATH.length - 1) === '"') { + cookie.PATH = cookie.PATH.substr(0, cookie.PATH.length - 1); + } + } + else { + cookie.PATH = '/'; + } + if (cookie.EXPIRES) { + cookie.EXPIRES = Date.parse(cookie.EXPIRES); + } + if (cookie.DOMAIN) { + cookie.DOMAIN = cookie.DOMAIN.toLowerCase(); + } + else { + cookie.DOMAIN = host; + } + cookie.SECURE = (cookie.SECURE !== undefined); + if (s_cookieManager[cookie.DOMAIN] === undefined) { + s_cookieManager[cookie.DOMAIN] = {}; + } + s_cookieManager[cookie.DOMAIN][cookie.name] = cookie; + } + for (name in headers) { + values = headers[name]; + name = name.toLowerCase(); + if ((name === 'set-cookie') || (name === 'set-cookie2')) { + if (typeof(values) === 'string') { + values = [values]; + } + values.forEach(_setCookie); + } + } + } + + function getCookie(uri) { + var parser = parseuri(uri); + var host = parser.host; + var path = parser.path; + var secure = (parser.protocol === 'https:'); + var cookies = []; + for (var domain in s_cookieManager) { + if (host.indexOf(domain) > -1) { + var names = []; + for (var name in s_cookieManager[domain]) { + var cookie = s_cookieManager[domain][name]; + if (cookie.EXPIRES && ((new Date()).getTime() > cookie.EXPIRES)) { + names.push(name); + } + else if (path.indexOf(cookie.PATH) === 0) { + if (((secure && cookie.SECURE) || + !cookie.SECURE) && (cookie.value !== null)) { + cookies.push(cookie.name + '=' + cookie.value); + } + } + } + for (var i in names) { + delete s_cookieManager[domain][names[i]]; + } + } + } + if (cookies.length > 0) { + return cookies.join('; '); + } + return ''; + } + + hprose.cookieManager = { + setCookie: setCookie, + getCookie: getCookie + }; +})(hprose); diff --git a/src/CopyRight.js b/src/CopyRight.js index 26fa1eb..6b9a072 100644 --- a/src/CopyRight.js +++ b/src/CopyRight.js @@ -1,5 +1,5 @@ -// Hprose for HTML5 v2.0.3 -// Copyright (c) 2008-2015 http://hprose.com +// Hprose for HTML5 v2.0.36 +// Copyright (c) 2008-2016 http://hprose.com // Hprose is freely distributable under the MIT license. // For all details and documentation: // https://github.com/hprose/hprose-html5 diff --git a/src/Formatter.js b/src/Formatter.js index 45d5d66..ed8396f 100644 --- a/src/Formatter.js +++ b/src/Formatter.js @@ -13,18 +13,17 @@ * * * hprose Formatter for HTML5. * * * - * LastModified: Jul 15, 2015 * + * LastModified: Nov 18, 2016 * * Author: Ma Bingyao * * * \**********************************************************/ -/* jshint -W067 */ -(function (global) { +(function (hprose) { 'use strict'; - var BytesIO = global.hprose.BytesIO; - var Writer = global.hprose.Writer; - var Reader = global.hprose.Reader; + var BytesIO = hprose.BytesIO; + var Writer = hprose.Writer; + var Reader = hprose.Reader; function serialize(value, simple) { var stream = new BytesIO(); @@ -40,17 +39,15 @@ return new Reader(stream, simple, useHarmonyMap).unserialize(); } - global.hprose.Formatter = { + hprose.Formatter = { serialize: function (value, simple) { return serialize(value, simple).bytes; }, unserialize: unserialize }; - global.hprose.serialize = serialize; + hprose.serialize = serialize; - global.hprose.unserialize = unserialize; + hprose.unserialize = unserialize; -}(function() { - return this || (1, eval)('this'); -}())); +})(hprose); diff --git a/src/Future.js b/src/Future.js index ef2ad4e..898a01c 100644 --- a/src/Future.js +++ b/src/Future.js @@ -13,13 +13,12 @@ * * * hprose Future for HTML5. * * * - * LastModified: Jul 28, 2015 * + * LastModified: Dec 5, 2016 * * Author: Ma Bingyao * * * \**********************************************************/ -/* jshint -W067 */ -(function (global, undefined) { +(function (hprose, global, undefined) { 'use strict'; var PENDING = 0; @@ -30,16 +29,18 @@ var setImmediate = global.setImmediate; var setTimeout = global.setTimeout; var clearTimeout = global.clearTimeout; - var foreach = Function.prototype.call.bind(Array.prototype.forEach); - var slice = Function.prototype.call.bind(Array.prototype.slice); + var TimeoutError = global.TimeoutError; + + var foreach = Array.prototype.forEach; + var slice = Array.prototype.slice; function Future(computation) { + var self = this; Object.defineProperties(this, { _subscribers: { value: [] }, resolve: { value: this.resolve.bind(this) }, - reject: { value: this.reject.bind(this) }, + reject: { value: this.reject.bind(this) } }); - var self = this; if (typeof computation === 'function') { setImmediate(function() { try { @@ -56,8 +57,12 @@ return obj instanceof Future; } + function toFuture(obj) { + return isFuture(obj) ? obj : value(obj); + } + function isPromise(obj) { - return isFuture(obj) || (hasPromise && (obj instanceof global.Promise) && (typeof (obj.then === 'function'))); + return 'function' === typeof obj.then; } function delayed(duration, value) { @@ -106,21 +111,19 @@ function arraysize(array) { var size = 0; - foreach(array, function() { ++size; }); + foreach.call(array, function() { ++size; }); return size; } function all(array) { - array = isPromise(array) ? array : value(array); - return array.then(function(array) { + return toFuture(array).then(function(array) { var n = array.length; var count = arraysize(array); var result = new Array(n); - if (count === 0) return value(result); + if (count === 0) { return result; } var future = new Future(); - foreach(array, function(element, index) { - var f = (isPromise(element) ? element : value(element)); - f.then(function(value) { + foreach.call(array, function(element, index) { + toFuture(element).then(function(value) { result[index] = value; if (--count === 0) { future.resolve(result); @@ -137,20 +140,17 @@ } function race(array) { - array = isPromise(array) ? array : value(array); - return array.then(function(array) { + return toFuture(array).then(function(array) { var future = new Future(); - foreach(array, function(element) { - var f = (isPromise(element) ? element : value(element)); - f.then(future.resolve, future.reject); + foreach.call(array, function(element) { + toFuture(element).fill(future); }); return future; }); } function any(array) { - array = isPromise(array) ? array : value(array); - return array.then(function(array) { + return toFuture(array).then(function(array) { var n = array.length; var count = arraysize(array); if (count === 0) { @@ -158,9 +158,8 @@ } var reasons = new Array(n); var future = new Future(); - foreach(array, function(element, index) { - var f = (isPromise(element) ? element : value(element)); - f.then(future.resolve, function(e) { + foreach.call(array, function(element, index) { + toFuture(element).then(future.resolve, function(e) { reasons[index] = e; if (--count === 0) { future.reject(reasons); @@ -172,16 +171,15 @@ } function settle(array) { - array = isPromise(array) ? array : value(array); - return array.then(function(array) { + return toFuture(array).then(function(array) { var n = array.length; var count = arraysize(array); var result = new Array(n); - if (count === 0) return value(result); + if (count === 0) { return result; } var future = new Future(); - foreach(array, function(element, index) { - var f = (isPromise(element) ? element : value(element)); - f.whenComplete(function() { + foreach.call(array, function(element, index) { + var f = toFuture(element); + f.complete(function() { result[index] = f.inspect(); if (--count === 0) { future.resolve(result); @@ -193,52 +191,212 @@ } function attempt(handler/*, arg1, arg2, ... */) { - var args = slice(arguments, 1); + var thisArg = (function() { return this; })(); + var args = slice.call(arguments, 1); return all(args).then(function(args) { - return handler.apply(undefined, args); + return handler.apply(thisArg, args); }); } function run(handler, thisArg/*, arg1, arg2, ... */) { - var args = slice(arguments, 2); + var args = slice.call(arguments, 2); return all(args).then(function(args) { return handler.apply(thisArg, args); }); } + function isGenerator(obj) { + if (!obj) { + return false; + } + return 'function' == typeof obj.next && 'function' == typeof obj['throw']; + } + + function isGeneratorFunction(obj) { + if (!obj) { + return false; + } + var constructor = obj.constructor; + if (!constructor) { + return false; + } + if ('GeneratorFunction' === constructor.name || + 'GeneratorFunction' === constructor.displayName) { + return true; + } + return isGenerator(constructor.prototype); + } + + function getThunkCallback(future) { + return function(err, res) { + if (err instanceof Error) { + return future.reject(err); + } + if (arguments.length < 2) { + return future.resolve(err); + } + if (err === null || err === undefined) { + res = slice.call(arguments, 1); + } + else { + res = slice.call(arguments, 0); + } + if (res.length == 1) { + future.resolve(res[0]); + } + else { + future.resolve(res); + } + }; + } + + function thunkToPromise(fn) { + if (isGeneratorFunction(fn) || isGenerator(fn)) { + return co(fn); + } + var thisArg = (function() { return this; })(); + var future = new Future(); + fn.call(thisArg, getThunkCallback(future)); + return future; + } + + function thunkify(fn) { + return function() { + var args = slice.call(arguments, 0); + var thisArg = this; + var results = new Future(); + args.push(function() { + thisArg = this; + results.resolve(arguments); + }); + try { + fn.apply(this, args); + } + catch (err) { + results.resolve([err]); + } + return function(done) { + results.then(function(results) { + done.apply(thisArg, results); + }); + }; + }; + } + + function promisify(fn) { + return function() { + var args = slice.call(arguments, 0); + var future = new Future(); + args.push(getThunkCallback(future)); + try { + fn.apply(this, args); + } + catch (err) { + future.reject(err); + } + return future; + }; + } + + function toPromise(obj) { + if (isGeneratorFunction(obj) || isGenerator(obj)) { + return co(obj); + } + return toFuture(obj); + } + + function co(gen) { + var thisArg = (function() { return this; })(); + if (typeof gen === 'function') { + var args = slice.call(arguments, 1); + gen = gen.apply(thisArg, args); + } + + if (!gen || typeof gen.next !== 'function') { + return toFuture(gen); + } + + var future = new Future(); + + function onFulfilled(res) { + try { + next(gen.next(res)); + } + catch (e) { + future.reject(e); + } + } + + function onRejected(err) { + try { + next(gen['throw'](err)); + } + catch (e) { + future.reject(e); + } + } + + function next(ret) { + if (ret.done) { + future.resolve(ret.value); + } + else { + (('function' == typeof ret.value) ? + thunkToPromise(ret.value) : + toPromise(ret.value)).then(onFulfilled, onRejected); + } + } + + onFulfilled(); + + return future; + } + function wrap(handler, thisArg) { return function() { + thisArg = thisArg || this; return all(arguments).then(function(args) { - return handler.apply(thisArg, args); + var result = handler.apply(thisArg, args); + if (isGeneratorFunction(result) || isGenerator(result)) { + return co.call(thisArg, result); + } + return result; }); }; } + co.wrap = wrap; + function forEach(array, callback, thisArg) { + thisArg = thisArg || (function() { return this; })(); return all(array).then(function(array) { return array.forEach(callback, thisArg); }); } function every(array, callback, thisArg) { + thisArg = thisArg || (function() { return this; })(); return all(array).then(function(array) { return array.every(callback, thisArg); }); } function some(array, callback, thisArg) { + thisArg = thisArg || (function() { return this; })(); return all(array).then(function(array) { return array.some(callback, thisArg); }); } function filter(array, callback, thisArg) { + thisArg = thisArg || (function() { return this; })(); return all(array).then(function(array) { return array.filter(callback, thisArg); }); } function map(array, callback, thisArg) { + thisArg = thisArg || (function() { return this; })(); return all(array).then(function(array) { return array.map(callback, thisArg); }); @@ -247,10 +405,7 @@ function reduce(array, callback, initialValue) { if (arguments.length > 2) { return all(array).then(function(array) { - if (!isPromise(initialValue)) { - initialValue = value(initialValue); - } - return initialValue.then(function(value) { + return toFuture(initialValue).then(function(value) { return array.reduce(callback, value); }); }); @@ -263,10 +418,7 @@ function reduceRight(array, callback, initialValue) { if (arguments.length > 2) { return all(array).then(function(array) { - if (!isPromise(initialValue)) { - initialValue = value(initialValue); - } - return initialValue.then(function(value) { + return toFuture(initialValue).then(function(value) { return array.reduceRight(callback, value); }); }); @@ -276,6 +428,47 @@ }); } + function indexOf(array, searchElement, fromIndex) { + return all(array).then(function(array) { + return toFuture(searchElement).then(function(searchElement) { + return array.indexOf(searchElement, fromIndex); + }); + }); + } + + function lastIndexOf(array, searchElement, fromIndex) { + return all(array).then(function(array) { + return toFuture(searchElement).then(function(searchElement) { + if (fromIndex === undefined) { + fromIndex = array.length - 1; + } + return array.lastIndexOf(searchElement, fromIndex); + }); + }); + } + + function includes(array, searchElement, fromIndex) { + return all(array).then(function(array) { + return toFuture(searchElement).then(function(searchElement) { + return array.includes(searchElement, fromIndex); + }); + }); + } + + function find(array, predicate, thisArg) { + thisArg = thisArg || (function() { return this; })(); + return all(array).then(function(array) { + return array.find(predicate, thisArg); + }); + } + + function findIndex(array, predicate, thisArg) { + thisArg = thisArg || (function() { return this; })(); + return all(array).then(function(array) { + return array.findIndex(predicate, thisArg); + }); + } + Object.defineProperties(Future, { // port from Dart delayed: { value: delayed }, @@ -290,12 +483,17 @@ // extended methods promise: { value: promise }, isFuture: { value: isFuture }, + toFuture: { value: toFuture }, isPromise: { value: isPromise }, + toPromise: { value: toPromise }, join: { value: join }, any: { value: any }, settle: { value: settle }, attempt: { value: attempt }, run: { value: run }, + thunkify: { value: thunkify }, + promisify: { value: promisify }, + co: { value: co }, wrap: { value: wrap }, // for array forEach: { value: forEach }, @@ -304,7 +502,12 @@ filter: { value: filter }, map: { value: map }, reduce: { value: reduce }, - reduceRight: { value: reduceRight } + reduceRight: { value: reduceRight }, + indexOf: { value: indexOf }, + lastIndexOf: { value: lastIndexOf }, + includes: { value: includes }, + find: { value: find }, + findIndex: { value: findIndex } }); function _call(callback, next, x) { @@ -319,6 +522,15 @@ }); } + function _resolve(onfulfill, next, x) { + if (onfulfill) { + _call(onfulfill, next, x); + } + else { + next.resolve(x); + } + } + function _reject(onreject, next, e) { if (onreject) { _call(onreject, next, e); @@ -328,82 +540,63 @@ } } - - function _resolve(onfulfill, onreject, self, next, x) { - function resolvePromise(y) { - _resolve(onfulfill, onreject, self, next, y); - } - function rejectPromise(r) { - _reject(onreject, next, r); - } - if (isPromise(x)) { - if (x === self) { - rejectPromise(new TypeError('Self resolution')); + Object.defineProperties(Future.prototype, { + _value: { writable: true }, + _reason: { writable: true }, + _state: { value: PENDING, writable: true }, + resolve: { value: function(value) { + if (value === this) { + this.reject(new TypeError('Self resolution')); return; } - x.then(resolvePromise, rejectPromise); - return; - } - if ((x !== null) && - (typeof x === 'object') || - (typeof x === 'function')) { - var then; - try { - then = x.then; - } - catch (e) { - rejectPromise(e); + if (isFuture(value)) { + value.fill(this); return; } - if (typeof then === 'function') { - var notrun = true; + if ((value !== null) && + (typeof value === 'object') || + (typeof value === 'function')) { + var then; try { - then.call(x, function(y) { - if (notrun) { - notrun = false; - resolvePromise(y); - } - }, function(r) { + then = value.then; + } + catch (e) { + this.reject(e); + return; + } + if (typeof then === 'function') { + var notrun = true; + try { + var self = this; + then.call(value, function(y) { + if (notrun) { + notrun = false; + self.resolve(y); + } + }, function(r) { + if (notrun) { + notrun = false; + self.reject(r); + } + }); + return; + } + catch (e) { if (notrun) { notrun = false; - rejectPromise(r); + this.reject(e); } - }); - return; - } - catch (e) { - if (notrun) { - notrun = false; - rejectPromise(e); } + return; } - return; } - } - if (onfulfill) { - _call(onfulfill, next, x); - } - else { - next.resolve(x); - } - } - - Object.defineProperties(Future.prototype, { - _value: { writable: true }, - _reason: { writable: true }, - _state: { value: PENDING, writable: true }, - resolve: { value: function(value) { if (this._state === PENDING) { this._state = FULFILLED; this._value = value; var subscribers = this._subscribers; while (subscribers.length > 0) { var subscriber = subscribers.shift(); - _resolve(subscriber.onfulfill, - subscriber.onreject, - this, - subscriber.next, - value); + _resolve(subscriber.onfulfill, subscriber.next, value); } } } }, @@ -414,48 +607,33 @@ var subscribers = this._subscribers; while (subscribers.length > 0) { var subscriber = subscribers.shift(); - if (subscriber.onreject) { - _call(subscriber.onreject, - subscriber.next, - reason); - } - else { - subscriber.next.reject(reason); - } + _reject(subscriber.onreject, subscriber.next, reason); } } } }, then: { value: function(onfulfill, onreject) { - if (typeof onfulfill !== 'function') onfulfill = null; - if (typeof onreject !== 'function') onreject = null; - if (onfulfill || onreject) { - var next = new Future(); - if (this._state === FULFILLED) { - if (onfulfill) { - _resolve(onfulfill, onreject, this, next, this._value); - } - else { - next.resolve(this._value); - } - } - else if (this._state === REJECTED) { - if (onreject) { - _call(onreject, next, this._reason); - } - else { - next.reject(this._reason); - } - } - else { - this._subscribers.push({ - onfulfill: onfulfill, - onreject: onreject, - next: next - }); - } - return next; + if (typeof onfulfill !== 'function') { onfulfill = null; } + if (typeof onreject !== 'function') { onreject = null; } + var next = new Future(); + if (this._state === FULFILLED) { + _resolve(onfulfill, next, this._value); } - return this; + else if (this._state === REJECTED) { + _reject(onreject, next, this._reason); + } + else { + this._subscribers.push({ + onfulfill: onfulfill, + onreject: onreject, + next: next + }); + } + return next; + } }, + done: { value: function(onfulfill, onreject) { + this.then(onfulfill, onreject).then(null, function(error) { + setImmediate(function() { throw error; }); + }); } }, inspect: { value: function() { switch (this._state) { @@ -481,29 +659,32 @@ 'catch': { value: function(onreject) { return this.then(null, onreject); } }, + fail: { value: function(onreject) { + this.done(null, onreject); + } }, whenComplete: { value: function(action) { return this.then( - function(v) { - var f = action(); - if (f === undefined) return v; - f = isPromise(f) ? f : value(f); - return f.then(function() { return v; }); - }, - function(e) { - var f = action(); - if (f === undefined) throw e; - f = isPromise(f) ? f : value(f); - return f.then(function() { throw e; }); - } + function(v) { action(); return v; }, + function(e) { action(); throw e; } ); } }, + complete: { value: function(oncomplete) { + oncomplete = oncomplete || function(v) { return v; }; + return this.then(oncomplete, oncomplete); + } }, + always: { value: function(oncomplete) { + this.done(oncomplete, oncomplete); + } }, + fill: { value: function(future) { + this.then(future.resolve, future.reject); + } }, timeout: { value: function(duration, reason) { var future = new Future(); var timeoutId = setTimeout(function() { future.reject(reason || new TimeoutError('timeout')); }, duration); this.whenComplete(function() { clearTimeout(timeoutId); }) - .then(future.resolve, future.reject); + .fill(future); return future; } }, delay: { value: function(duration) { @@ -547,7 +728,7 @@ }); } }, call: { value: function(method) { - var args = slice(arguments, 1); + var args = slice.call(arguments, 1); return this.then(function(result) { return all(args).then(function(args) { return result[method].apply(result, args); @@ -555,7 +736,7 @@ }); } }, bind: { value: function(method) { - var bindargs = slice(arguments); + var bindargs = slice.call(arguments); if (Array.isArray(method)) { for (var i = 0, n = method.length; i < n; ++i) { bindargs[0] = method[i]; @@ -566,7 +747,7 @@ bindargs.shift(); var self = this; Object.defineProperty(this, method, { value: function() { - var args = slice(arguments); + var args = slice.call(arguments); return self.then(function(result) { return all(bindargs.concat(args)).then(function(args) { return result[method].apply(result, args); @@ -601,10 +782,30 @@ return reduceRight(this, callback, initialValue); } return reduceRight(this, callback); + } }, + indexOf: { value: function(searchElement, fromIndex) { + return indexOf(this, searchElement, fromIndex); + } }, + lastIndexOf: { value: function(searchElement, fromIndex) { + return lastIndexOf(this, searchElement, fromIndex); + } }, + includes: { value: function(searchElement, fromIndex) { + return includes(this, searchElement, fromIndex); + } }, + find: { value: function(predicate, thisArg) { + return find(this, predicate, thisArg); + } }, + findIndex: { value: function(predicate, thisArg) { + return findIndex(this, predicate, thisArg); } } }); - global.hprose.Future = Future; + hprose.Future = Future; + + hprose.thunkify = thunkify; + hprose.promisify = promisify; + hprose.co = co; + hprose.co.wrap = hprose.wrap = wrap; function Completer() { var future = new Future(); @@ -618,38 +819,38 @@ }); } - global.hprose.Completer = Completer; + hprose.Completer = Completer; - global.hprose.resolved = value; + hprose.resolved = value; - global.hprose.rejected = error; + hprose.rejected = error; - global.hprose.deferred = function() { + hprose.deferred = function() { var self = new Future(); return Object.create(null, { promise: { value: self }, resolve: { value: self.resolve }, - reject: { value: self.reject }, + reject: { value: self.reject } }); }; - if (hasPromise) return; + if (hasPromise) { return; } - global.Promise = function(executor) { + function MyPromise(executor) { Future.call(this); executor(this.resolve, this.reject); - }; + } - global.Promise.prototype = Object.create(Future.prototype); - global.Promise.prototype.constructor = Future; + MyPromise.prototype = Object.create(Future.prototype); + MyPromise.prototype.constructor = Future; - Object.defineProperties(global.Promise, { + Object.defineProperties(MyPromise, { all: { value: all }, race: { value: race }, resolve: { value: value }, reject: { value: error } }); -}(function() { - return this || (1, eval)('this'); -}())); + global.Promise = MyPromise; + +})(hprose, hprose.global); diff --git a/src/HarmonyMaps.js b/src/HarmonyMaps.js index 8f7f51a..5be6667 100644 --- a/src/HarmonyMaps.js +++ b/src/HarmonyMaps.js @@ -13,12 +13,11 @@ * * * Harmony Maps for HTML5. * * * - * LastModified: Jul 15, 2015 * + * LastModified: Nov 18, 2016 * * Author: Ma Bingyao * * * \**********************************************************/ -/* jshint -W067 */ (function (global) { 'use strict'; @@ -30,7 +29,7 @@ hasForEach = 'forEach' in new global.Map(); } - if (hasWeakMap && hasMap && hasForEach) return; + if (hasWeakMap && hasMap && hasForEach) { return; } var namespaces = Object.create(null); var count = 0; @@ -42,7 +41,9 @@ if ((this === obj) && (n in namespaces) && (namespaces[n] === namespace)) { - if (!(n in privates)) privates[n] = Object.create(null); + if (!(n in privates)) { + privates[n] = Object.create(null); + } return privates[n]; } else { @@ -61,9 +62,13 @@ var n = count++; namespaces[n] = namespace; var map = function (key) { - if (key !== Object(key)) throw new Error('value is not a non-null object'); + if (key !== Object(key)) { + throw new Error('value is not a non-null object'); + } var privates = key.valueOf(namespace, n); - if (privates !== key.valueOf()) return privates; + if (privates !== key.valueOf()) { + return privates; + } reDefineValueOf(key); return key.valueOf(namespace, n); }; @@ -113,9 +118,9 @@ var nullMap = Object.create(null); namespaces[n] = namespace; var map = function (key) { - if (key === null) return nullMap; + if (key === null) { return nullMap; } var privates = key.valueOf(namespace, n); - if (privates !== key.valueOf()) return privates; + if (privates !== key.valueOf()) { return privates; } reDefineValueOf(key); return key.valueOf(namespace, n); }; @@ -200,7 +205,7 @@ clear: { value: function () { keys.length = 0; - for (var key in map) map[key].clear(); + for (var key in map) { map[key].clear(); } size = 0; } }, @@ -292,6 +297,4 @@ return m; }; } -}(function() { - return this || (1, eval)('this'); -}())); +})(hprose.global); diff --git a/src/Helper.js b/src/Helper.js new file mode 100644 index 0000000..8fcae53 --- /dev/null +++ b/src/Helper.js @@ -0,0 +1,114 @@ +/**********************************************************\ +| | +| hprose | +| | +| Official WebSite: http://www.hprose.com/ | +| http://www.hprose.org/ | +| | +\**********************************************************/ + +/**********************************************************\ + * * + * Helper.js * + * * + * hprose helper for HTML5. * + * * + * LastModified: Nov 18, 2016 * + * Author: Ma Bingyao * + * * +\**********************************************************/ + +(function (hprose, undefined) { + 'use strict'; + + function generic(method) { + if (typeof method !== "function") { + throw new TypeError(method + " is not a function"); + } + return function(context) { + return method.apply(context, Array.prototype.slice.call(arguments, 1)); + }; + } + + var arrayLikeObjectArgumentsEnabled = true; + + try { + String.fromCharCode.apply(String, new Uint8Array([1])); + } + catch (e) { + arrayLikeObjectArgumentsEnabled = false; + } + + function toArray(arrayLikeObject) { + var n = arrayLikeObject.length; + var a = new Array(n); + for (var i = 0; i < n; ++i) { + a[i] = arrayLikeObject[i]; + } + return a; + } + + var getCharCodes = arrayLikeObjectArgumentsEnabled ? function(bytes) { return bytes; } : toArray; + + function toBinaryString(bytes) { + if (bytes instanceof ArrayBuffer) { + bytes = new Uint8Array(bytes); + } + var n = bytes.length; + if (n < 0xFFFF) { + return String.fromCharCode.apply(String, getCharCodes(bytes)); + } + var remain = n & 0x7FFF; + var count = n >> 15; + var a = new Array(remain ? count + 1 : count); + for (var i = 0; i < count; ++i) { + a[i] = String.fromCharCode.apply(String, getCharCodes(bytes.subarray(i << 15, (i + 1) << 15))); + } + if (remain) { + a[count] = String.fromCharCode.apply(String, getCharCodes(bytes.subarray(count << 15, n))); + } + return a.join(''); + } + + function toUint8Array(bs) { + var n = bs.length; + var data = new Uint8Array(n); + for (var i = 0; i < n; i++) { + data[i] = bs.charCodeAt(i) & 0xFF; + } + return data; + } + + var parseuri = function(url) { + var pattern = new RegExp("^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?"); + var matches = url.match(pattern); + var host = matches[4].split(':', 2); + return { + protocol: matches[1], + host: matches[4], + hostname: host[0], + port: parseInt(host[1], 10) || 0, + path: matches[5], + query: matches[7], + fragment: matches[9] + }; + } + + var isObjectEmpty = function (obj) { + if (obj) { + var prop; + for (prop in obj) { + return false; + } + } + return true; + } + + hprose.generic = generic; + hprose.toBinaryString = toBinaryString; + hprose.toUint8Array = toUint8Array; + hprose.toArray = toArray; + hprose.parseuri = parseuri; + hprose.isObjectEmpty = isObjectEmpty; + +})(hprose); diff --git a/src/HttpClient.js b/src/HttpClient.js index cab1e0d..569deb1 100644 --- a/src/HttpClient.js +++ b/src/HttpClient.js @@ -12,22 +12,57 @@ * * * hprose http client for HTML5. * * * - * LastModified: Aug 2, 2015 * + * LastModified: Dec 2, 2016 * * Author: Ma Bingyao * * * \**********************************************************/ -/* jshint -W067 */ -(function (global, undefined) { +(function (hprose, global, undefined) { 'use strict'; - var Client = global.hprose.Client; - var Future = global.hprose.Future; + var Client = hprose.Client; + var Future = hprose.Future; + var BytesIO = hprose.BytesIO; + var TimeoutError = global.TimeoutError; + var localfile = (global.location !== undefined && global.location.protocol === 'file:'); + var XMLHttpRequest = global.XMLHttpRequest; + var nativeXHR = (typeof(XMLHttpRequest) !== 'undefined'); + var corsSupport = (!localfile && nativeXHR && 'withCredentials' in new XMLHttpRequest()); + var parseuri = hprose.parseuri; + var cookieManager = hprose.cookieManager; function noop(){} + function getResponseHeader(headers) { + var header = Object.create(null); + if (headers) { + headers = headers.split("\r\n"); + for (var i = 0, n = headers.length; i < n; i++) { + if (headers[i] !== "") { + var kv = headers[i].split(": ", 2); + var k = kv[0].trim(); + var v = kv[1].trim(); + if (k in header) { + if (Array.isArray(header[k])) { + header[k].push(v); + } + else { + header[k] = [header[k], v]; + } + } + else { + header[k] = v; + } + } + } + } + return header; + } + function HttpClient(uri, functions, settings) { - if (this.constructor !== HttpClient) return new HttpClient(uri, functions, settings); + if (this.constructor !== HttpClient) { + return new HttpClient(uri, functions, settings); + } Client.call(this, uri, functions, settings); var _header = Object.create(null); var _onreqprogress = noop; @@ -35,19 +70,43 @@ var self = this; - function send(request, future) { + function getRequestHeader(headers) { + var header = Object.create(null); + var name, value; + for (name in _header) { + header[name] = _header[name]; + } + if (headers) { + for (name in headers) { + value = headers[name]; + if (Array.isArray(value)) { + header[name] = value.join(', '); + } + else { + header[name] = value; + } + } + } + return header; + } + + function xhrPost(request, context) { + var future = new Future(); var xhr = new XMLHttpRequest(); xhr.open('POST', self.uri, true); - if (global.location !== undefined && global.location.protocol !== 'file:') { + if (corsSupport) { xhr.withCredentials = 'true'; } xhr.responseType = 'arraybuffer'; - for (var name in _header) { - xhr.setRequestHeader(name, _header[name]); + var header = getRequestHeader(context.httpHeader); + for (var name in header) { + xhr.setRequestHeader(name, header[name]); } xhr.onload = function() { xhr.onload = noop; if (xhr.status) { + var headers = xhr.getAllResponseHeaders(); + context.httpHeader = getResponseHeader(headers); if (xhr.status === 200) { future.resolve(new Uint8Array(xhr.response)); } @@ -63,6 +122,17 @@ xhr.upload.onprogress = _onreqprogress; } xhr.onprogress = _onresprogress; + if (context.timeout > 0) { + future = future.timeout(context.timeout).catchError(function(e) { + xhr.onload = noop; + xhr.onerror = noop; + xhr.abort(); + throw e; + }, + function(e) { + return e instanceof TimeoutError; + }); + } if (request.constructor === String || ArrayBuffer.isView) { xhr.send(request); } @@ -70,28 +140,56 @@ xhr.send(request.buffer.slice(0, request.length)); } else { - xhr.send(request.buffer); + var buf = new Uint8Array(request.length); + buf.set(request); + xhr.send(buf.buffer); } - return xhr; + return future; } - function sendAndReceive(request, env) { + function apiPost(request, context) { var future = new Future(); - var xhr = send(request, future); - if (env.timeout > 0) { - future = future.timeout(env.timeout).catchError(function(e) { - xhr.onload = noop; - xhr.onerror = noop; - xhr.abort(); - throw e; - }, - function(e) { - return e instanceof TimeoutError; - }); + var header = getRequestHeader(context.httpHeader); + var cookie = cookieManager.getCookie(self.uri()); + if (cookie !== '') { + header['Cookie'] = cookie; } - if (env.oneway) future.resolve(); + global.api.ajax({ + url: self.uri, + method: 'post', + data: { body: BytesIO.toString(request) }, + timeout: context.timeout, + dataType: 'text', + headers: header, + returnAll: true, + certificate: self.certificate + }, function(ret, err) { + if (ret) { + context.httpHeader = ret.headers; + if (ret.statusCode === 200) { + cookieManager.setCookie(ret.headers, self.uri); + future.resolve((new BytesIO(ret.body)).takeBytes()); + } + else { + future.reject(new Error(ret.statusCode+':'+ret.body)); + } + } + else { + future.reject(new Error(err.msg)); + } + }); return future; } + + function sendAndReceive(request, context) { + var apicloud = (typeof(global.api) !== "undefined" && + typeof(global.api.ajax) !== "undefined"); + var future = apicloud ? apiPost(request, context) : + xhrPost(request, context); + if (context.oneway) { future.resolve(); } + return future; + } + function setOnRequestProgress(value) { if (typeof(value) === 'function') { _onreqprogress = value; @@ -120,7 +218,6 @@ } } Object.defineProperties(this, { - onProgress: { get: getOnRequestProgress, set: setOnRequestProgress }, onprogress: { get: getOnRequestProgress, set: setOnRequestProgress }, onRequestProgress: { get: getOnRequestProgress, set: setOnRequestProgress }, onResponseProgress: { get: getOnResponseProgress, set: setOnResponseProgress }, @@ -130,8 +227,7 @@ } function checkuri(uri) { - var parser = document.createElement('a'); - parser.href = uri; + var parser = parseuri(uri); if (parser.protocol === 'http:' || parser.protocol === 'https:') { return; @@ -147,15 +243,13 @@ uri.forEach(function(uri) { checkuri(uri); }); } else { - return new Error('You should set server uri first!'); + throw new Error('You should set server uri first!'); } return new HttpClient(uri, functions, settings); } Object.defineProperty(HttpClient, 'create', { value: create }); - global.hprose.HttpClient = HttpClient; + hprose.HttpClient = HttpClient; -}(function() { - return this || (1, eval)('this'); -}())); +})(hprose, hprose.global); diff --git a/src/Init.js b/src/Init.js index 3ffcd27..7055d01 100644 --- a/src/Init.js +++ b/src/Init.js @@ -13,17 +13,19 @@ * * * hprose init for HTML5. * * * - * LastModified: Jul 15, 2015 * + * LastModified: Nov 18, 2016 * * Author: Ma Bingyao * * * \**********************************************************/ -/* jshint -W067 */ -(function (global) { - 'use strict'; +var hprose = Object.create(null); - global.hprose = Object.create(null); - -}(function() { - return this || (1, eval)('this'); -}())); +/* global global, window, self */ +hprose.global = ( + // Among the various tricks for obtaining a reference to the global + // object, this seems to be the most reliable technique that does not + // use indirect eval (which violates Content Security Policy). + typeof global === "object" ? global : + typeof window === "object" ? window : + typeof self === "object" ? self : this +); diff --git a/src/JSONRPCClientFilter.js b/src/JSONRPCClientFilter.js index da3f7c0..28a85fd 100644 --- a/src/JSONRPCClientFilter.js +++ b/src/JSONRPCClientFilter.js @@ -13,19 +13,19 @@ * * * jsonrpc client filter for JavaScript. * * * - * LastModified: Jul 17, 2015 * + * LastModified: Nov 18, 2016 * * Author: Ma Bingyao * * * \**********************************************************/ -/* jshint -W067 */ -(function (global) { +/* global JSON */ +(function (hprose) { 'use strict'; - var Tags = global.hprose.Tags; - var BytesIO = global.hprose.BytesIO; - var Writer = global.hprose.Writer; - var Reader = global.hprose.Reader; + var Tags = hprose.Tags; + var BytesIO = hprose.BytesIO; + var Writer = hprose.Writer; + var Reader = hprose.Reader; var s_id = 1; @@ -33,7 +33,7 @@ this.version = version || '2.0'; } - JSONRPCClientFilter.prototype.inputFilter = function inputFilter(data, context) { + JSONRPCClientFilter.prototype.inputFilter = function inputFilter(data/*, context*/) { var json = BytesIO.toString(data); if (json.charAt(0) === '{') { json = '[' + json + ']'; @@ -56,7 +56,7 @@ return stream.bytes; }; - JSONRPCClientFilter.prototype.outputFilter = function outputFilter(data, context) { + JSONRPCClientFilter.prototype.outputFilter = function outputFilter(data/*, context*/) { var requests = []; var stream = new BytesIO(data); var reader = new Reader(stream, false, false); @@ -89,8 +89,6 @@ return JSON.stringify(requests[0]); }; - global.hprose.JSONRPCClientFilter = JSONRPCClientFilter; + hprose.JSONRPCClientFilter = JSONRPCClientFilter; -}(function() { - return this || (1, eval)('this'); -}())); +})(hprose); diff --git a/src/Loader.js b/src/Loader.js index b0cfcf8..3e2bdf5 100644 --- a/src/Loader.js +++ b/src/Loader.js @@ -13,52 +13,51 @@ * * * hprose CommonJS/AMD/CMD loader for HTML5. * * * - * LastModified: Jul 15, 2015 * + * LastModified: Nov 18, 2016 * * Author: Ma Bingyao * * * \**********************************************************/ -/* jshint -W067 */ -(function (global) { +/* global define, module */ +(function (hprose) { 'use strict'; - global.hprose.common = { - Completer: global.hprose.Completer, - Future: global.hprose.Future, - ResultMode: global.hprose.ResultMode + hprose.common = { + Completer: hprose.Completer, + Future: hprose.Future, + ResultMode: hprose.ResultMode }; - global.hprose.io = { - BytesIO: global.hprose.BytesIO, - ClassManager: global.hprose.ClassManager, - Tags: global.hprose.Tags, - RawReader: global.hprose.RawReader, - Reader: global.hprose.Reader, - Writer: global.hprose.Writer, - Formatter: global.hprose.Formatter + hprose.io = { + BytesIO: hprose.BytesIO, + ClassManager: hprose.ClassManager, + Tags: hprose.Tags, + RawReader: hprose.RawReader, + Reader: hprose.Reader, + Writer: hprose.Writer, + Formatter: hprose.Formatter }; - global.hprose.client = { - Client: global.hprose.Client, - HttpClient: global.hprose.HttpClient, - WebSocketClient: global.hprose.WebSocketClient + hprose.client = { + Client: hprose.Client, + HttpClient: hprose.HttpClient, + TcpClient: hprose.TcpClient, + WebSocketClient: hprose.WebSocketClient }; - global.hprose.filter = { - JSONRPCClientFilter: global.hprose.JSONRPCClientFilter + hprose.filter = { + JSONRPCClientFilter: hprose.JSONRPCClientFilter }; if (typeof define === 'function') { if (define.cmd) { - define('hprose', [], global.hprose); + define('hprose', [], hprose); } else if (define.amd) { - define('hprose', [], function() { return global.hprose; }); + define('hprose', [], function() { return hprose; }); } } - if (typeof module === 'object' && typeof module.exports === 'object') { - module.exports = global.hprose; + if (typeof module === 'object') { + module.exports = hprose; } -}(function() { - return this || (1, eval)('this'); -}())); +})(hprose); diff --git a/src/Polyfill.js b/src/Polyfill.js new file mode 100644 index 0000000..8c4a989 --- /dev/null +++ b/src/Polyfill.js @@ -0,0 +1,414 @@ +/**********************************************************\ +| | +| hprose | +| | +| Official WebSite: http://www.hprose.com/ | +| http://www.hprose.org/ | +| | +\**********************************************************/ + +/**********************************************************\ + * * + * Polyfill.js * + * * + * Polyfill for JavaScript. * + * * + * LastModified: Nov 18, 2016 * + * Author: Ma Bingyao * + * * +\**********************************************************/ + +(function (generic, undefined) { + 'use strict'; + /* Function */ + if (!Function.prototype.bind) { + Object.defineProperty(Function.prototype, 'bind', { value: function(oThis) { + if (typeof this !== 'function') { + throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable'); + } + var aArgs = Array.prototype.slice.call(arguments, 1), + toBind = this, + NOP = function() {}, + bound = function() { + return toBind.apply(this instanceof NOP ? this : oThis, + aArgs.concat(Array.prototype.slice.call(arguments))); + }; + if (this.prototype) { + NOP.prototype = this.prototype; + } + bound.prototype = new NOP(); + return bound; + } }); + } + /* Array */ + if (!Array.prototype.includes) { + Object.defineProperty(Array.prototype, 'includes', { value: function(searchElement /*, fromIndex*/ ) { + var O = Object(this); + var len = parseInt(O.length, 10) || 0; + if (len === 0) { + return false; + } + var n = parseInt(arguments[1], 10) || 0; + var k; + if (n >= 0) { + k = n; + } + else { + k = len + n; + if (k < 0) { k = 0; } + } + var currentElement; + while (k < len) { + currentElement = O[k]; + if (searchElement === currentElement || + (searchElement !== searchElement && currentElement !== currentElement)) { // NaN !== NaN + return true; + } + k++; + } + return false; + } }); + } + if (!Array.prototype.find) { + Object.defineProperty(Array.prototype, 'find', { value: function(predicate) { + if (this === null || this === undefined) { + throw new TypeError('Array.prototype.find called on null or undefined'); + } + if (typeof predicate !== 'function') { + throw new TypeError('predicate must be a function'); + } + var list = Object(this); + var length = list.length >>> 0; + var thisArg = arguments[1]; + var value; + for (var i = 0; i < length; i++) { + value = list[i]; + if (predicate.call(thisArg, value, i, list)) { + return value; + } + } + return undefined; + } }); + } + if (!Array.prototype.findIndex) { + Object.defineProperty(Array.prototype, 'findIndex', { value: function(predicate) { + if (this === null || this === undefined) { + throw new TypeError('Array.prototype.findIndex called on null or undefined'); + } + if (typeof predicate !== 'function') { + throw new TypeError('predicate must be a function'); + } + var list = Object(this); + var length = list.length >>> 0; + var thisArg = arguments[1]; + var value; + + for (var i = 0; i < length; i++) { + value = list[i]; + if (predicate.call(thisArg, value, i, list)) { + return i; + } + } + return -1; + } }); + } + if (!Array.prototype.fill) { + Object.defineProperty(Array.prototype, 'fill', { value: function(value) { + if (this === null || this === undefined) { + throw new TypeError('this is null or not defined'); + } + var O = Object(this); + var len = O.length >>> 0; + var start = arguments[1]; + var relativeStart = start >> 0; + var k = relativeStart < 0 ? Math.max(len + relativeStart, 0) : Math.min(relativeStart, len); + var end = arguments[2]; + var relativeEnd = end === undefined ? len : end >> 0; + var f = relativeEnd < 0 ? Math.max(len + relativeEnd, 0) : Math.min(relativeEnd, len); + + while (k < f) { + O[k] = value; + k++; + } + return O; + } }); + } + if (!Array.prototype.copyWithin) { + Object.defineProperty(Array.prototype, 'copyWithin', { value: function(target, start/*, end*/) { + if (this === null || this === undefined) { + throw new TypeError('this is null or not defined'); + } + var O = Object(this); + var len = O.length >>> 0; + var relativeTarget = target >> 0; + var to = relativeTarget < 0 ? Math.max(len + relativeTarget, 0) : Math.min(relativeTarget, len); + var relativeStart = start >> 0; + var from = relativeStart < 0 ? Math.max(len + relativeStart, 0) : Math.min(relativeStart, len); + var end = arguments[2]; + var relativeEnd = end === undefined ? len : end >> 0; + var f = relativeEnd < 0 ? Math.max(len + relativeEnd, 0) : Math.min(relativeEnd, len); + var count = Math.min(f - from, len - to); + var direction = 1; + if (from < to && to < (from + count)) { + direction = -1; + from += count - 1; + to += count - 1; + } + while (count > 0) { + if (from in O) { + O[to] = O[from]; + } + else { + delete O[to]; + } + from += direction; + to += direction; + count--; + } + return O; + } }); + } + if (!Array.from) { + Object.defineProperty(Array, 'from', { value: (function() { + var toStr = Object.prototype.toString; + var isCallable = function(fn) { + return typeof fn === 'function' || toStr.call(fn) === '[object Function]'; + }; + var toInteger = function(value) { + var number = Number(value); + if (isNaN(number)) { return 0; } + if (number === 0 || !isFinite(number)) { return number; } + return (number > 0 ? 1 : -1) * Math.floor(Math.abs(number)); + }; + var maxSafeInteger = Math.pow(2, 53) - 1; + var toLength = function(value) { + var len = toInteger(value); + return Math.min(Math.max(len, 0), maxSafeInteger); + }; + + return function(arrayLike/*, mapFn, thisArg */) { + var C = this; + var items = Object(arrayLike); + if (arrayLike === null || arrayLike === undefined) { + throw new TypeError("Array.from requires an array-like object - not null or undefined"); + } + var mapFn = arguments.length > 1 ? arguments[1] : void undefined; + var T; + if (typeof mapFn !== 'undefined') { + if (!isCallable(mapFn)) { + throw new TypeError('Array.from: when provided, the second argument must be a function'); + } + if (arguments.length > 2) { + T = arguments[2]; + } + } + var len = toLength(items.length); + var A = isCallable(C) ? Object(new C(len)) : new Array(len); + var k = 0; + var kValue; + while (k < len) { + kValue = items[k]; + if (mapFn) { + A[k] = typeof T === 'undefined' ? mapFn(kValue, k) : mapFn.call(T, kValue, k); + } + else { + A[k] = kValue; + } + k += 1; + } + A.length = len; + return A; + }; + }()) }); + } + if (!Array.of) { + Object.defineProperty(Array, 'of', { value: function() { + return Array.prototype.slice.call(arguments); + } }); + } + /* String */ + if (!String.prototype.startsWith) { + Object.defineProperty(String.prototype, 'startsWith', { value: function(searchString, position){ + position = position || 0; + return this.substr(position, searchString.length) === searchString; + } }); + } + if (!String.prototype.endsWith) { + Object.defineProperty(String.prototype, 'endsWith', { value: function(searchString, position) { + var subjectString = this.toString(); + if (typeof position !== 'number' || !isFinite(position) || Math.floor(position) !== position || position > subjectString.length) { + position = subjectString.length; + } + position -= searchString.length; + var lastIndex = subjectString.indexOf(searchString, position); + return lastIndex !== -1 && lastIndex === position; + } }); + } + if (!String.prototype.includes) { + Object.defineProperty(String.prototype, 'includes', { value: function() { + if (typeof arguments[1] === "number") { + if (this.length < arguments[0].length + arguments[1].length) { + return false; + } + else { + return this.substr(arguments[1], arguments[0].length) === arguments[0]; + } + } + else { + return String.prototype.indexOf.apply(this, arguments) !== -1; + } + } }); + } + if (!String.prototype.repeat) { + Object.defineProperty(String.prototype, 'repeat', { value: function(count) { + var str = this.toString(); + count = +count; + if (count !== count) { + count = 0; + } + if (count < 0) { + throw new RangeError('repeat count must be non-negative'); + } + if (count === Infinity) { + throw new RangeError('repeat count must be less than infinity'); + } + count = Math.floor(count); + if (str.length === 0 || count === 0) { + return ''; + } + // Ensuring count is a 31-bit integer allows us to heavily optimize the + // main part. But anyway, most current (August 2014) browsers can't handle + // strings 1 << 28 chars or longer, so: + if (str.length * count >= 1 << 28) { + throw new RangeError('repeat count must not overflow maximum string size'); + } + var rpt = ''; + for (;;) { + if ((count & 1) === 1) { + rpt += str; + } + count >>>= 1; + if (count === 0) { + break; + } + str += str; + } + // Could we try: + // return Array(count + 1).join(this); + return rpt; + } }); + } + if (!String.prototype.trim) { + Object.defineProperty(String.prototype, 'trim', { value: function() { + return this.toString().replace(/^[\s\xa0]+|[\s\xa0]+$/g, ''); + } }); + } + if (!String.prototype.trimLeft) { + Object.defineProperty(String.prototype, 'trimLeft', { value: function() { + return this.toString().replace(/^[\s\xa0]+/, ''); + } }); + } + if (!String.prototype.trimRight) { + Object.defineProperty(String.prototype, 'trimRight', { value: function() { + return this.toString().replace(/[\s\xa0]+$/, ''); + } }); + } + /* Object */ + if (!Object.keys) { + Object.defineProperty(Object, 'keys', { value: (function () { + var hasOwnProperty = Object.prototype.hasOwnProperty, + hasDontEnumBug = !({toString: null}).propertyIsEnumerable('toString'), + dontEnums = [ + 'toString', + 'toLocaleString', + 'valueOf', + 'hasOwnProperty', + 'isPrototypeOf', + 'propertyIsEnumerable', + 'constructor' + ], + dontEnumsLength = dontEnums.length; + return function (obj) { + if (typeof obj !== 'object' && typeof obj !== 'function' || obj === null) { + throw new TypeError('Object.keys called on non-object'); + } + var result = []; + for (var prop in obj) { + if (hasOwnProperty.call(obj, prop)) { + result.push(prop); + } + } + if (hasDontEnumBug) { + for (var i=0; i < dontEnumsLength; i++) { + if (hasOwnProperty.call(obj, dontEnums[i])) { + result.push(dontEnums[i]); + } + } + } + return result; + }; + })() }); + } + + function genericMethods(obj, properties) { + var proto = obj.prototype; + for (var i = 0, len = properties.length; i < len; i++) { + var property = properties[i]; + var method = proto[property]; + if (typeof method === 'function' && typeof obj[property] === 'undefined') { + Object.defineProperty(obj, property, { value: generic(method) }); + } + } + } + genericMethods(Array, [ + "pop", + "push", + "reverse", + "shift", + "sort", + "splice", + "unshift", + "concat", + "join", + "slice", + "indexOf", + "lastIndexOf", + "filter", + "forEach", + "every", + "map", + "some", + "reduce", + "reduceRight", + "includes", + "find", + "findIndex" + ]); + genericMethods(String, [ + 'quote', + 'substring', + 'toLowerCase', + 'toUpperCase', + 'charAt', + 'charCodeAt', + 'indexOf', + 'lastIndexOf', + 'include', + 'startsWith', + 'endsWith', + 'repeat', + 'trim', + 'trimLeft', + 'trimRight', + 'toLocaleLowerCase', + 'toLocaleUpperCase', + 'match', + 'search', + 'replace', + 'split', + 'substr', + 'concat', + 'slice' + ]); + +})(hprose.generic); diff --git a/src/Reader.js b/src/Reader.js index 22de239..4ff8e05 100644 --- a/src/Reader.js +++ b/src/Reader.js @@ -13,19 +13,18 @@ * * * hprose Reader for HTML5. * * * - * LastModified: Aug 3, 2015 * + * LastModified: Nov 18, 2016 * * Author: Ma Bingyao * * * \**********************************************************/ -/* jshint -W067 */ -(function (global, undefined) { +(function (hprose, global, undefined) { 'use strict'; var Map = global.Map; - var BytesIO = global.hprose.BytesIO; - var Tags = global.hprose.Tags; - var ClassManager = global.hprose.ClassManager; + var BytesIO = hprose.BytesIO; + var Tags = hprose.Tags; + var ClassManager = hprose.ClassManager; function unexpectedTag(tag, expectTags) { if (tag && expectTags) { @@ -177,7 +176,7 @@ }); } - global.hprose.RawReader = RawReader; + hprose.RawReader = RawReader; var fakeReaderRefer = Object.create(null, { set: { value: function() {} }, @@ -270,7 +269,7 @@ function readInt(stream, tag) { var s = stream.readUntil(tag); - if (s.length === 0) return 0; + if (s.length === 0) { return 0; } return parseInt(s, 10); } function unserialize(reader) { @@ -334,7 +333,7 @@ function readLongWithoutTag(stream) { var s = stream.readUntil(Tags.TagSemicolon); var l = parseInt(s, 10); - if (l.toString() === s) return l; + if (l.toString() === s) { return l; } return s; } function readLong(stream) { @@ -658,12 +657,12 @@ Object.defineProperties(Reader.prototype, { useHarmonyMap: { value: false, writable: true }, checkTag: { value: function(expectTag, tag) { - if (tag === undefined) tag = this.stream.readByte(); - if (tag !== expectTag) unexpectedTag(tag, expectTag); + if (tag === undefined) { tag = this.stream.readByte(); } + if (tag !== expectTag) { unexpectedTag(tag, expectTag); } } }, checkTags: { value: function(expectTags, tag) { - if (tag === undefined) tag = this.stream.readByte(); - if (expectTags.indexOf(tag) >= 0) return tag; + if (tag === undefined) { tag = this.stream.readByte(); } + if (expectTags.indexOf(tag) >= 0) { return tag; } unexpectedTag(tag, expectTags); } }, unserialize: { value: function() { @@ -739,7 +738,5 @@ } } }); - global.hprose.Reader = Reader; -}(function() { - return this || (1, eval)('this'); -}())); + hprose.Reader = Reader; +})(hprose, hprose.global); diff --git a/src/ResultMode.js b/src/ResultMode.js index f4fd380..01d3e1e 100644 --- a/src/ResultMode.js +++ b/src/ResultMode.js @@ -13,26 +13,23 @@ * * * hprose ResultMode for HTML5. * * * - * LastModified: Jul 15, 2015 * + * LastModified: Nov 18, 2016 * * Author: Ma Bingyao * * * \**********************************************************/ -/* jshint -W067 */ -(function (global) { +(function (hprose) { 'use strict'; - global.hprose.ResultMode = { + hprose.ResultMode = { Normal: 0, Serialized: 1, Raw: 2, RawWithEndTag: 3 }; - global.hprose.Normal = global.hprose.ResultMode.Normal; - global.hprose.Serialized = global.hprose.ResultMode.Serialized; - global.hprose.Raw = global.hprose.ResultMode.Raw; - global.hprose.RawWithEndTag = global.hprose.ResultMode.RawWithEndTag; + hprose.Normal = hprose.ResultMode.Normal; + hprose.Serialized = hprose.ResultMode.Serialized; + hprose.Raw = hprose.ResultMode.Raw; + hprose.RawWithEndTag = hprose.ResultMode.RawWithEndTag; -}(function() { - return this || (1, eval)('this'); -}())); +})(hprose); diff --git a/src/Tags.js b/src/Tags.js index c972dc9..66b85d5 100644 --- a/src/Tags.js +++ b/src/Tags.js @@ -12,16 +12,15 @@ * * * hprose tags enum for HTML5. * * * - * LastModified: Jul 15, 2015 * + * LastModified: Nov 18, 2016 * * Author: Ma Bingyao * * * \**********************************************************/ -/* jshint -W067 */ -(function (global) { +(function (hprose) { 'use strict'; - global.hprose.Tags = { + hprose.Tags = { /* Serialize Tags */ TagInteger : 0x69, // 'i' TagLong : 0x6C, // 'l' @@ -60,6 +59,4 @@ TagError : 0x45, // 'E' TagEnd : 0x7A // 'z' }; -}(function() { - return this || (1, eval)('this'); -}())); +})(hprose); diff --git a/src/TcpClient.js b/src/TcpClient.js new file mode 100644 index 0000000..964a4e8 --- /dev/null +++ b/src/TcpClient.js @@ -0,0 +1,470 @@ +/**********************************************************\ +| | +| hprose | +| | +| Official WebSite: http://www.hprose.com/ | +| http://www.hprose.org/ | +| | +\**********************************************************/ +/**********************************************************\ + * * + * TcpClient.js * + * * + * hprose tcp client for HTML5. * + * * + * LastModified: Dec 2, 2016 * + * Author: Ma Bingyao * + * * +\**********************************************************/ + +(function (hprose, global, undefined) { + 'use strict'; + + var ChromeTcpSocket = hprose.ChromeTcpSocket; + var APICloudTcpSocket = hprose.APICloudTcpSocket; + var Client = hprose.Client; + var BytesIO = hprose.BytesIO; + var Future = hprose.Future; + var TimeoutError = global.TimeoutError; + var parseuri = hprose.parseuri; + + function noop(){} + + function setReceiveHandler(socket, onreceive) { + socket.onreceive = function(data) { + if (!('receiveEntry' in socket)) { + socket.receiveEntry = { + stream: new BytesIO(), + headerLength: 4, + dataLength: -1, + id: null + }; + } + var entry = socket.receiveEntry; + var stream = entry.stream; + var headerLength = entry.headerLength; + var dataLength = entry.dataLength; + var id = entry.id; + stream.write(data); + while (true) { + if ((dataLength < 0) && (stream.length >= headerLength)) { + dataLength = stream.readInt32BE(); + if ((dataLength & 0x80000000) !== 0) { + dataLength &= 0x7fffffff; + headerLength = 8; + } + } + if ((headerLength === 8) && (id === null) && (stream.length >= headerLength)) { + id = stream.readInt32BE(); + } + if ((dataLength >= 0) && ((stream.length - headerLength) >= dataLength)) { + onreceive(stream.read(dataLength), id); + headerLength = 4; + id = null; + stream.trunc(); + dataLength = -1; + } + else { + break; + } + } + entry.stream = stream; + entry.headerLength = headerLength; + entry.dataLength = dataLength; + entry.id = id; + }; + } + + function TcpTransporter(client) { + if (client) { + this.client = client; + this.uri = this.client.uri; + this.size = 0; + this.pool = []; + this.requests = []; + } + } + + Object.defineProperties(TcpTransporter.prototype, { + create: { value: function() { + var parser = parseuri(this.uri); + var protocol = parser.protocol; + var address = parser.hostname; + var port = parseInt(parser.port, 10); + var tls; + if (protocol === 'tcp:' || + protocol === 'tcp4:' || + protocol === 'tcp6:') { + tls = false; + } + else if (protocol === 'tcps:' || + protocol === 'tcp4s:' || + protocol === 'tcp6s:' || + protocol === 'tls:') { + tls = true; + } + else { + throw new Error('Unsupported ' + protocol + ' protocol!'); + } + var conn; + if (global.chrome && global.chrome.sockets && global.chrome.sockets.tcp) { + conn = new ChromeTcpSocket(); + } + else if (global.api && global.api.require) { + conn = new APICloudTcpSocket(); + } + else { + throw new Error('TCP Socket is not supported by this browser or platform.'); + } + var self = this; + conn.connect(address, port, { + persistent: true, + tls: tls, + timeout: this.client.timeout, + noDelay: this.client.noDelay, + keepAlive: this.client.keepAlive + }); + conn.onclose = function() { --self.size; }; + ++this.size; + return conn; + } } + }); + + function FullDuplexTcpTransporter(client) { + TcpTransporter.call(this, client); + } + + FullDuplexTcpTransporter.prototype = Object.create( + TcpTransporter.prototype, { + fetch: { value: function() { + var pool = this.pool; + while (pool.length > 0) { + var conn = pool.pop(); + if (conn.connected) { + if (conn.count === 0) { + conn.clearTimeout(); + conn.ref(); + } + return conn; + } + } + return null; + } }, + init: { value: function(conn) { + var self = this; + conn.count = 0; + conn.futures = {}; + conn.timeoutIds = {}; + setReceiveHandler(conn, function(data, id) { + var future = conn.futures[id]; + if (future) { + self.clean(conn, id); + if (conn.count === 0) { + self.recycle(conn); + } + future.resolve(data); + } + }); + conn.onerror = function (e) { + var futures = conn.futures; + for (var id in futures) { + var future = futures[id]; + self.clean(conn, id); + future.reject(e); + } + }; + } }, + recycle: { value: function(conn) { + conn.unref(); + conn.setTimeout(this.client.poolTimeout, function() { + conn.destroy(); + }); + } }, + clean: { value: function(conn, id) { + if (conn.timeoutIds[id] !== undefined) { + global.clearTimeout(conn.timeoutIds[id]); + delete conn.timeoutIds[id]; + } + delete conn.futures[id]; + --conn.count; + this.sendNext(conn); + } }, + sendNext: { value: function(conn) { + if (conn.count < 10) { + if (this.requests.length > 0) { + var request = this.requests.pop(); + request.push(conn); + this.send.apply(this, request); + } + else { + if (this.pool.lastIndexOf(conn) < 0) { + this.pool.push(conn); + } + } + } + } }, + send: { value: function(request, future, id, context, conn) { + var self = this; + var timeout = context.timeout; + if (timeout > 0) { + conn.timeoutIds[id] = global.setTimeout(function() { + self.clean(conn, id); + if (conn.count === 0) { + self.recycle(conn); + } + future.reject(new TimeoutError('timeout')); + }, timeout); + } + conn.count++; + conn.futures[id] = future; + + var len = request.length; + var buf = new BytesIO(8 + len); + buf.writeInt32BE(len | 0x80000000); + buf.writeInt32BE(id); + buf.write(request); + conn.send(buf.buffer).then(function() { + self.sendNext(conn); + }); + } }, + getNextId: { value: function() { + return (this.nextid < 0x7fffffff) ? ++this.nextid : this.nextid = 0; + } }, + sendAndReceive: { value: function(request, future, context) { + var conn = this.fetch(); + var id = this.getNextId(); + if (conn) { + this.send(request, future, id, context, conn); + } + else if (this.size < this.client.maxPoolSize) { + conn = this.create(); + conn.onerror = function(e) { + future.reject(e); + }; + var self = this; + conn.onconnect = function() { + self.init(conn); + self.send(request, future, id, context, conn); + }; + } + else { + this.requests.push([request, future, id, context]); + } + } } + }); + + FullDuplexTcpTransporter.prototype.constructor = TcpTransporter; + + function HalfDuplexTcpTransporter(client) { + TcpTransporter.call(this, client); + } + + HalfDuplexTcpTransporter.prototype = Object.create( + TcpTransporter.prototype, { + fetch: { value: function() { + var pool = this.pool; + while (pool.length > 0) { + var conn = pool.pop(); + if (conn.connected) { + conn.clearTimeout(); + conn.ref(); + return conn; + } + } + return null; + } }, + recycle: { value: function(conn) { + if (this.pool.lastIndexOf(conn) < 0) { + conn.unref(); + conn.setTimeout(this.client.poolTimeout, function() { + conn.destroy(); + }); + this.pool.push(conn); + } + } }, + clean: { value: function(conn) { + conn.onreceive = noop; + conn.onerror = noop; + if (conn.timeoutId !== undefined) { + global.clearTimeout(conn.timeoutId); + delete conn.timeoutId; + } + } }, + sendNext: { value: function(conn) { + if (this.requests.length > 0) { + var request = this.requests.pop(); + request.push(conn); + this.send.apply(this, request); + } + else { + this.recycle(conn); + } + } }, + send: { value: function(request, future, context, conn) { + var self = this; + var timeout = context.timeout; + if (timeout > 0) { + conn.timeoutId = global.setTimeout(function() { + self.clean(conn); + conn.destroy(); + future.reject(new TimeoutError('timeout')); + }, timeout); + } + setReceiveHandler(conn, function(data) { + self.clean(conn); + self.sendNext(conn); + future.resolve(data); + }); + conn.onerror = function(e) { + self.clean(conn); + future.reject(e); + }; + + var len = request.length; + var buf = new BytesIO(4 + len); + buf.writeInt32BE(len); + buf.write(request); + conn.send(buf.buffer); + } }, + sendAndReceive: { value: function(request, future, context) { + var conn = this.fetch(); + if (conn) { + this.send(request, future, context, conn); + } + else if (this.size < this.client.maxPoolSize) { + conn = this.create(); + var self = this; + conn.onerror = function(e) { + future.reject(e); + }; + conn.onconnect = function() { + self.send(request, future, context, conn); + }; + } + else { + this.requests.push([request, future, context]); + } + } } + }); + + HalfDuplexTcpTransporter.prototype.constructor = TcpTransporter; + + function TcpClient(uri, functions, settings) { + if (this.constructor !== TcpClient) { + return new TcpClient(uri, functions, settings); + } + Client.call(this, uri, functions, settings); + + var self = this; + var _noDelay = true; + var _fullDuplex = false; + var _maxPoolSize = 10; + var _poolTimeout = 30000; + var fdtrans = null; + var hdtrans = null; + + function getNoDelay() { + return _noDelay; + } + + function setNoDelay(value) { + _noDelay = !!value; + } + + function getFullDuplex() { + return _fullDuplex; + } + + function setFullDuplex(value) { + _fullDuplex = !!value; + } + + function getMaxPoolSize() { + return _maxPoolSize; + } + + function setMaxPoolSize(value) { + if (typeof(value) === 'number') { + _maxPoolSize = value | 0; + if (_maxPoolSize < 1) { + _maxPoolSize = 10; + } + } + else { + _maxPoolSize = 10; + } + } + + function getPoolTimeout() { + return _poolTimeout; + } + + function setPoolTimeout(value) { + if (typeof(value) === 'number') { + _poolTimeout = value | 0; + } + else { + _poolTimeout = 0; + } + } + + function sendAndReceive(request, context) { + var future = new Future(); + if (_fullDuplex) { + if ((fdtrans === null) || (fdtrans.uri !== self.uri)) { + fdtrans = new FullDuplexTcpTransporter(self); + } + fdtrans.sendAndReceive(request, future, context); + } + else { + if ((hdtrans === null) || (hdtrans.uri !== self.uri)) { + hdtrans = new HalfDuplexTcpTransporter(self); + } + hdtrans.sendAndReceive(request, future, context); + } + if (context.oneway) { future.resolve(); } + return future; + } + + Object.defineProperties(this, { + noDelay: { get: getNoDelay, set: setNoDelay }, + fullDuplex: { get: getFullDuplex, set: setFullDuplex }, + maxPoolSize: { get: getMaxPoolSize, set: setMaxPoolSize }, + poolTimeout: { get: getPoolTimeout, set: setPoolTimeout }, + sendAndReceive: { value: sendAndReceive } + }); + } + + function checkuri(uri) { + var parser = parseuri(uri); + var protocol = parser.protocol; + if (protocol === 'tcp:' || + protocol === 'tcp4:'|| + protocol === 'tcp6:' || + protocol === 'tcps:' || + protocol === 'tcp4s:' || + protocol === 'tcp6s:' || + protocol === 'tls:') { + return; + } + throw new Error('This client desn\'t support ' + protocol + ' scheme.'); + } + + function create(uri, functions, settings) { + if (typeof uri === 'string') { + checkuri(uri); + } + else if (Array.isArray(uri)) { + uri.forEach(function(uri) { checkuri(uri); }); + } + else { + throw new Error('You should set server uri first!'); + } + return new TcpClient(uri, functions, settings); + } + + Object.defineProperty(TcpClient, 'create', { value: create }); + + hprose.TcpClient = TcpClient; + +})(hprose, hprose.global); diff --git a/src/TimeoutError.js b/src/TimeoutError.js index b4397ee..7ca5787 100644 --- a/src/TimeoutError.js +++ b/src/TimeoutError.js @@ -13,19 +13,21 @@ * * * TimeoutError for HTML5. * * * - * LastModified: Jul 17, 2015 * + * LastModified: Nov 18, 2016 * * Author: Ma Bingyao * * * \**********************************************************/ -function TimeoutError(message) { - Error.call(this); - this.message = message; - this.name = TimeoutError.name; - if (typeof Error.captureStackTrace === 'function') { - Error.captureStackTrace(this, TimeoutError); +(function(global) { + function TimeoutError(message) { + Error.call(this); + this.message = message; + this.name = TimeoutError.name; + if (typeof Error.captureStackTrace === 'function') { + Error.captureStackTrace(this, TimeoutError); + } } -} - -TimeoutError.prototype = Object.create(Error.prototype); -TimeoutError.prototype.constructor = TimeoutError; + TimeoutError.prototype = Object.create(Error.prototype); + TimeoutError.prototype.constructor = TimeoutError; + global.TimeoutError = TimeoutError; +})(hprose.global); \ No newline at end of file diff --git a/src/WebSocketClient.js b/src/WebSocketClient.js index 8ee7e4c..e95e409 100644 --- a/src/WebSocketClient.js +++ b/src/WebSocketClient.js @@ -12,22 +12,30 @@ * * * hprose websocket client for HTML5. * * * - * LastModified: Aug 15, 2015 * + * LastModified: Aug 20, 2017 * * Author: Ma Bingyao * * * \**********************************************************/ -/* jshint -W067 */ -(function (global, undefined) { +(function (hprose, global, undefined) { 'use strict'; - var Client = global.hprose.Client; - var BytesIO = global.hprose.BytesIO; - var Future = global.hprose.Future; + var BytesIO = hprose.BytesIO; + var Client = hprose.Client; + var Future = hprose.Future; + var TimeoutError = global.TimeoutError; + var parseuri = hprose.parseuri; + + var WebSocket = global.WebSocket || global.MozWebSocket; function noop(){} function WebSocketClient(uri, functions, settings) { - if (this.constructor !== WebSocketClient) return new WebSocketClient(uri, functions, settings); + if (typeof(WebSocket) === "undefined") { + throw new Error('WebSocket is not supported by this browser.'); + } + if (this.constructor !== WebSocketClient) { + return new WebSocketClient(uri, functions, settings); + } Client.call(this, uri, functions, settings); @@ -77,11 +85,11 @@ } if ((_count < 100) && (_requests.length > 0)) { ++_count; - var request = _requests.shift(); + var request = _requests.pop(); _ready.then(function() { send(request[0], request[1]); }); } - if (_count === 0) { - if (!self.keepAlive) close(); + if (_count === 0 && !self.keepAlive) { + close(); } } function onclose(e) { @@ -101,25 +109,26 @@ ws.onerror = noop; ws.onclose = onclose; } - function sendAndReceive(request, env) { - if (ws === null || - ws.readyState === WebSocket.CLOSING || - ws.readyState === WebSocket.CLOSED) { - connect(); - } + function sendAndReceive(request, context) { var id = getNextId(); var future = new Future(); _futures[id] = future; - if (self.timeout > 0) { - future = future.timeout(self.timeout).catchError(function(e) { + if (context.timeout > 0) { + future = future.timeout(context.timeout).catchError(function(e) { delete _futures[id]; --_count; + close(); throw e; }, function(e) { return e instanceof TimeoutError; }); } + if (ws === null || + ws.readyState === WebSocket.CLOSING || + ws.readyState === WebSocket.CLOSED) { + connect(); + } if (_count < 100) { ++_count; _ready.then(function() { send(id, request); }); @@ -127,7 +136,7 @@ else { _requests.push([id, request]); } - if (env.oneway) future.resolve(); + if (context.oneway) { future.resolve(); } return future; } function close() { @@ -146,8 +155,7 @@ } function checkuri(uri) { - var parser = document.createElement('a'); - parser.href = uri; + var parser = parseuri(uri); if (parser.protocol === 'ws:' || parser.protocol === 'wss:') { return; @@ -163,15 +171,13 @@ uri.forEach(function(uri) { checkuri(uri); }); } else { - return new Error('You should set server uri first!'); + throw new Error('You should set server uri first!'); } return new WebSocketClient(uri, functions, settings); } Object.defineProperty(WebSocketClient, 'create', { value: create }); - global.hprose.WebSocketClient = WebSocketClient; + hprose.WebSocketClient = WebSocketClient; -}(function() { - return this || (1, eval)('this'); -}())); +})(hprose, hprose.global); diff --git a/src/Writer.js b/src/Writer.js index f5a5c11..d99e83e 100644 --- a/src/Writer.js +++ b/src/Writer.js @@ -13,24 +13,26 @@ * * * hprose Writer for HTML5. * * * - * LastModified: Aug 2, 2015 * + * LastModified: Feb 13, 2017 * * Author: Ma Bingyao * * * \**********************************************************/ -/* jshint -W067 */ -(function (global, undefined) { +(function (hprose, global, undefined) { 'use strict'; var Map = global.Map; - var BytesIO = global.hprose.BytesIO; - var Tags = global.hprose.Tags; - var ClassManager = global.hprose.ClassManager; + var BytesIO = hprose.BytesIO; + var Tags = hprose.Tags; + var ClassManager = hprose.ClassManager; function getClassName(obj) { var cls = obj.constructor; + if (!cls) { + return 'Object'; + } var classname = ClassManager.getClassAlias(cls); - if (classname) return classname; + if (classname) { return classname; } if (cls.name) { classname = cls.name; } @@ -303,9 +305,14 @@ var stream = writer.stream; stream.writeByte(Tags.TagBytes); var n = bytes.byteLength || bytes.length; - if (n > 0) stream.writeAsciiString('' + n); - stream.writeByte(Tags.TagQuote); - if (n > 0) stream.write(bytes); + if (n > 0) { + stream.writeAsciiString('' + n); + stream.writeByte(Tags.TagQuote); + stream.write(bytes); + } + else { + stream.writeByte(Tags.TagQuote); + } stream.writeByte(Tags.TagQuote); } @@ -314,9 +321,14 @@ var stream = writer.stream; var n = str.length; stream.writeByte(Tags.TagString); - if (n > 0) stream.writeAsciiString('' + n); - stream.writeByte(Tags.TagQuote); - if (n > 0) stream.writeString(str); + if (n > 0) { + stream.writeAsciiString('' + n); + stream.writeByte(Tags.TagQuote); + stream.writeString(str); + } + else { + stream.writeByte(Tags.TagQuote); + } stream.writeByte(Tags.TagQuote); } @@ -325,10 +337,15 @@ var stream = writer.stream; var n = array.length; stream.writeByte(Tags.TagList); - if (n > 0) stream.writeAsciiString('' + n); - stream.writeByte(Tags.TagOpenbrace); - for (var i = 0; i < n; i++) { - writeElem(writer, array[i]); + if (n > 0) { + stream.writeAsciiString('' + n); + stream.writeByte(Tags.TagOpenbrace); + for (var i = 0; i < n; i++) { + writeElem(writer, array[i]); + } + } + else { + stream.writeByte(Tags.TagOpenbrace); } stream.writeByte(Tags.TagClosebrace); } @@ -357,11 +374,16 @@ } var n = fields.length; stream.writeByte(Tags.TagMap); - if (n > 0) stream.writeAsciiString('' + n); - stream.writeByte(Tags.TagOpenbrace); - for (var i = 0; i < n; i++) { - serialize(writer, fields[i]); - serialize(writer, map[fields[i]]); + if (n > 0) { + stream.writeAsciiString('' + n); + stream.writeByte(Tags.TagOpenbrace); + for (var i = 0; i < n; i++) { + serialize(writer, fields[i]); + serialize(writer, map[fields[i]]); + } + } + else { + stream.writeByte(Tags.TagOpenbrace); } stream.writeByte(Tags.TagClosebrace); } @@ -371,12 +393,17 @@ var stream = writer.stream; var n = map.size; stream.writeByte(Tags.TagMap); - if (n > 0) stream.writeAsciiString('' + n); - stream.writeByte(Tags.TagOpenbrace); - map.forEach(function(value, key) { - serialize(writer, key); - serialize(writer, value); - }); + if (n > 0) { + stream.writeAsciiString('' + n); + stream.writeByte(Tags.TagOpenbrace); + map.forEach(function(value, key) { + serialize(writer, key); + serialize(writer, value); + }); + } + else { + stream.writeByte(Tags.TagOpenbrace); + } stream.writeByte(Tags.TagClosebrace); } @@ -417,10 +444,15 @@ stream.writeByte(Tags.TagQuote); stream.writeString(classname); stream.writeByte(Tags.TagQuote); - if (n > 0) stream.writeAsciiString('' + n); - stream.writeByte(Tags.TagOpenbrace); - for (var i = 0; i < n; i++) { - writeString(writer, fields[i]); + if (n > 0) { + stream.writeAsciiString('' + n); + stream.writeByte(Tags.TagOpenbrace); + for (var i = 0; i < n; i++) { + writeString(writer, fields[i]); + } + } + else { + stream.writeByte(Tags.TagOpenbrace); } stream.writeByte(Tags.TagClosebrace); var index = writer._fieldsref.length; @@ -523,8 +555,6 @@ } } }); - global.hprose.Writer = Writer; + hprose.Writer = Writer; -}(function() { - return this || (1, eval)('this'); -}())); +})(hprose, hprose.global); diff --git a/src/setImmediate.js b/src/setImmediate.js index 9014fe4..0dbbc6d 100644 --- a/src/setImmediate.js +++ b/src/setImmediate.js @@ -9,60 +9,44 @@ /**********************************************************\ * * - * hprose/common/setImmediate.js * + * setImmediate.js * * * * setImmediate for HTML5. * * * - * LastModified: Jul 19, 2015 * + * LastModified: Nov 18, 2016 * * Author: Ma Bingyao * * * \**********************************************************/ -/* jshint -W067 */ (function(global, undefined) { 'use strict'; - - // @see http://codeforhire.com/2013/09/21/setimmediate-and-messagechannel-broken-on-internet-explorer-10/ - var notUseNative = (global.navigator && /Trident/.test(global.navigator.userAgent)); - - if (!notUseNative && (global.msSetImmediate || global.setImmediate)) { - if (!global.setImmediate) { - global.setImmediate = global.msSetImmediate; - global.clearImmediate = global.msClearImmediate; - } - return; - } + if (global.setImmediate) { return; } var doc = global.document; - var slice = Function.prototype.call.bind(Array.prototype.slice); - var toString = Function.prototype.call.bind(Object.prototype.toString); + var MutationObserver = global.MutationObserver || global.WebKitMutationObserver || global.MozMutationOvserver; var polifill = {}; var nextId = 1; var tasks = {}; - var lock = false; function wrap(handler) { - var args = slice(arguments, 1); + var args = Array.prototype.slice.call(arguments, 1); return function() { handler.apply(undefined, args); }; } + function clear(handleId) { + delete tasks[handleId]; + } + function run(handleId) { - if (lock) { - // Delay by doing a setTimeout. setImmediate was tried instead, but in Firefox 7 it generated a "too much recursion" error. - global.setTimeout(wrap(run, handleId), 0); - } else { - var task = tasks[handleId]; - if (task) { - lock = true; - try { - task(); - } - finally { - clear(handleId); - lock = false; - } + var task = tasks[handleId]; + if (task) { + try { + task(); + } + finally { + clear(handleId); } } } @@ -72,9 +56,24 @@ return nextId++; } - function clear(handleId) { - delete tasks[handleId]; - } + polifill.mutationObserver = function() { + var queue = [], + node = doc.createTextNode(''), + observer = new MutationObserver(function() { + while (queue.length > 0) { + run(queue.shift()); + } + }); + + observer.observe(node, {"characterData": true}); + + return function() { + var handleId = create(arguments); + queue.push(handleId); + node.data = handleId & 1; + return handleId; + }; + }; polifill.messageChannel = function() { var channel = new global.MessageChannel(); @@ -99,27 +98,22 @@ }; polifill.postMessage = function() { - var messagePrefix = 'setImmediate$' + Math.random() + '$'; - - var onGlobalMessage = function(event) { - if (event.source === global && - typeof(event.data) === 'string' && - event.data.indexOf(messagePrefix) === 0) { - - run(Number(event.data.slice(messagePrefix.length))); + var iframe = doc.createElement('iframe'); + iframe.style.display = 'none'; + doc.documentElement.appendChild(iframe); + var iwin = iframe.contentWindow; + iwin.document.write(''); + iwin.document.close(); + var queue = []; + window.addEventListener('message', function() { + while (queue.length > 0) { + run(queue.shift()); } - }; - - if (global.addEventListener) { - global.addEventListener('message', onGlobalMessage, false); - - } else { - global.attachEvent('onmessage', onGlobalMessage); - } - + }); return function() { var handleId = create(arguments); - global.postMessage(messagePrefix + handleId, '*'); + queue.push(handleId); + iwin.postMessage(1, "*"); return handleId; }; }; @@ -144,61 +138,45 @@ }; }; + // If supported, we should attach to the prototype of global, since that is where setTimeout et al. live. + var attachTo = Object.getPrototypeOf && Object.getPrototypeOf(global); + attachTo = (attachTo && attachTo.setTimeout ? attachTo : global); + polifill.setTimeout = function() { return function() { var handleId = create(arguments); - global.setTimeout( wrap( run, handleId ), 0 ); + attachTo.setTimeout( wrap( run, handleId ), 0 ); return handleId; }; }; - function canUsePostMessage() { - if (global.postMessage && !global.importScripts) { - var asynch = true; - var oldOnMessage = global.onmessage; - global.onmessage = function() { - asynch = false; - }; - global.postMessage('', '*'); - global.onmessage = oldOnMessage; - return asynch; - } - } - - // If supported, we should attach to the prototype of global, since that is where setTimeout et al. live. - var attachTo = Object.getPrototypeOf && Object.getPrototypeOf(global); - attachTo = (attachTo && attachTo.setTimeout ? attachTo : global); - - if (notUseNative) { - attachTo.setImmediate = polifill.setTimeout(); - // Don't get fooled by e.g. browserify environments. // For Node.js before 0.9 - } else if (toString(global.process) === '[object process]') { + if (typeof(global.process) !== 'undefined' && + Object.prototype.toString.call(global.process) === '[object process]' && + !global.process.browser) { attachTo.setImmediate = polifill.nextTick(); - - // For non-IE10 modern browsers - } else if (canUsePostMessage()) { - attachTo.setImmediate = polifill.postMessage(); - + } + // For IE 6–9 + else if (doc && ('onreadystatechange' in doc.createElement('script'))) { + attachTo.setImmediate = polifill.readyStateChange(); + } + // For MutationObserver, where supported + else if (doc && MutationObserver) { + attachTo.setImmediate = polifill.mutationObserver(); + } // For web workers, where supported - } else if (global.MessageChannel) { + else if (global.MessageChannel) { attachTo.setImmediate = polifill.messageChannel(); - - // For IE 6–8 - } else if (doc && ('onreadystatechange' in doc.createElement('script'))) { - attachTo.setImmediate = polifill.readyStateChange(); - + } + // For non-IE modern browsers + else if (doc && 'postMessage' in global && 'addEventListener' in global) { + attachTo.setImmediate = polifill.postMessage(); + } // For older browsers - } else { + else { attachTo.setImmediate = polifill.setTimeout(); } - attachTo.msSetImmediate = attachTo.setImmediate; - attachTo.clearImmediate = clear; - attachTo.msClearImmediate = clear; - -}(function() { - return this || (1, eval)('this'); -}())); +})(hprose.global); diff --git a/test/Future.Test.js b/test/Future.Test.js index 44d95d0..7ec5212 100644 --- a/test/Future.Test.js +++ b/test/Future.Test.js @@ -234,4 +234,4 @@ testPromise(); testPromise(); testPromise(); -})(this); +})(this || [eval][0]('this')); diff --git a/test/test.html b/test/test.html new file mode 100644 index 0000000..3710c74 --- /dev/null +++ b/test/test.html @@ -0,0 +1,19 @@ + + + + + hprose test + + + + + + + diff --git a/test/test_sea.html b/test/test_sea.html index c3f6f8b..2e62978 100644 --- a/test/test_sea.html +++ b/test/test_sea.html @@ -11,7 +11,7 @@ } }); seajs.use('hprose', function(hprose) { - var client = new hprose.HttpClient("http://www.hprose.com/example/", ["hello"]); + var client = new hprose.HttpClient("http://www.hprose.com/example/index.php", ["hello"]); client.hello("World!", function(result) { alert(result); }, function(name, err) { diff --git a/test/test_src.html b/test/test_src.html index 9a1d763..d3f3ffe 100644 --- a/test/test_src.html +++ b/test/test_src.html @@ -4,6 +4,8 @@ hprose test + + diff --git a/utils/regenerator-runtime.js b/utils/regenerator-runtime.js new file mode 100644 index 0000000..4ec72f1 --- /dev/null +++ b/utils/regenerator-runtime.js @@ -0,0 +1,669 @@ +/** + * Copyright (c) 2014, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * https://raw.github.com/facebook/regenerator/master/LICENSE file. An + * additional grant of patent rights can be found in the PATENTS file in + * the same directory. + */ + +!(function(global) { + "use strict"; + + var hasOwn = Object.prototype.hasOwnProperty; + var undefined; // More compressible than void 0. + var $Symbol = typeof Symbol === "function" ? Symbol : {}; + var iteratorSymbol = $Symbol.iterator || "@@iterator"; + var toStringTagSymbol = $Symbol.toStringTag || "@@toStringTag"; + + var inModule = typeof module === "object"; + var runtime = global.regeneratorRuntime; + if (runtime) { + if (inModule) { + // If regeneratorRuntime is defined globally and we're in a module, + // make the exports object identical to regeneratorRuntime. + module.exports = runtime; + } + // Don't bother evaluating the rest of this file if the runtime was + // already defined globally. + return; + } + + // Define the runtime globally (as expected by generated code) as either + // module.exports (if we're in a module) or a new, empty object. + runtime = global.regeneratorRuntime = inModule ? module.exports : {}; + + function wrap(innerFn, outerFn, self, tryLocsList) { + // If outerFn provided and outerFn.prototype is a Generator, then outerFn.prototype instanceof Generator. + var protoGenerator = outerFn && outerFn.prototype instanceof Generator ? outerFn : Generator; + var generator = Object.create(protoGenerator.prototype); + var context = new Context(tryLocsList || []); + + // The ._invoke method unifies the implementations of the .next, + // .throw, and .return methods. + generator._invoke = makeInvokeMethod(innerFn, self, context); + + return generator; + } + runtime.wrap = wrap; + + // Try/catch helper to minimize deoptimizations. Returns a completion + // record like context.tryEntries[i].completion. This interface could + // have been (and was previously) designed to take a closure to be + // invoked without arguments, but in all the cases we care about we + // already have an existing method we want to call, so there's no need + // to create a new function object. We can even get away with assuming + // the method takes exactly one argument, since that happens to be true + // in every case, so we don't have to touch the arguments object. The + // only additional allocation required is the completion record, which + // has a stable shape and so hopefully should be cheap to allocate. + function tryCatch(fn, obj, arg) { + try { + return { type: "normal", arg: fn.call(obj, arg) }; + } catch (err) { + return { type: "throw", arg: err }; + } + } + + var GenStateSuspendedStart = "suspendedStart"; + var GenStateSuspendedYield = "suspendedYield"; + var GenStateExecuting = "executing"; + var GenStateCompleted = "completed"; + + // Returning this object from the innerFn has the same effect as + // breaking out of the dispatch switch statement. + var ContinueSentinel = {}; + + // Dummy constructor functions that we use as the .constructor and + // .constructor.prototype properties for functions that return Generator + // objects. For full spec compliance, you may wish to configure your + // minifier not to mangle the names of these two functions. + function Generator() {} + function GeneratorFunction() {} + function GeneratorFunctionPrototype() {} + + var Gp = GeneratorFunctionPrototype.prototype = Generator.prototype; + GeneratorFunction.prototype = Gp.constructor = GeneratorFunctionPrototype; + GeneratorFunctionPrototype.constructor = GeneratorFunction; + GeneratorFunctionPrototype[toStringTagSymbol] = GeneratorFunction.displayName = "GeneratorFunction"; + + // Helper for defining the .next, .throw, and .return methods of the + // Iterator interface in terms of a single ._invoke method. + function defineIteratorMethods(prototype) { + ["next", "throw", "return"].forEach(function(method) { + prototype[method] = function(arg) { + return this._invoke(method, arg); + }; + }); + } + + runtime.isGeneratorFunction = function(genFun) { + var ctor = typeof genFun === "function" && genFun.constructor; + return ctor + ? ctor === GeneratorFunction || + // For the native GeneratorFunction constructor, the best we can + // do is to check its .name property. + (ctor.displayName || ctor.name) === "GeneratorFunction" + : false; + }; + + runtime.mark = function(genFun) { + if (Object.setPrototypeOf) { + Object.setPrototypeOf(genFun, GeneratorFunctionPrototype); + } else { + genFun.__proto__ = GeneratorFunctionPrototype; + if (!(toStringTagSymbol in genFun)) { + genFun[toStringTagSymbol] = "GeneratorFunction"; + } + } + genFun.prototype = Object.create(Gp); + return genFun; + }; + + // Within the body of any async function, `await x` is transformed to + // `yield regeneratorRuntime.awrap(x)`, so that the runtime can test + // `value instanceof AwaitArgument` to determine if the yielded value is + // meant to be awaited. Some may consider the name of this method too + // cutesy, but they are curmudgeons. + runtime.awrap = function(arg) { + return new AwaitArgument(arg); + }; + + function AwaitArgument(arg) { + this.arg = arg; + } + + function AsyncIterator(generator) { + function invoke(method, arg, resolve, reject) { + var record = tryCatch(generator[method], generator, arg); + if (record.type === "throw") { + reject(record.arg); + } else { + var result = record.arg; + var value = result.value; + if (value instanceof AwaitArgument) { + return Promise.resolve(value.arg).then(function(value) { + invoke("next", value, resolve, reject); + }, function(err) { + invoke("throw", err, resolve, reject); + }); + } + + return Promise.resolve(value).then(function(unwrapped) { + // When a yielded Promise is resolved, its final value becomes + // the .value of the Promise<{value,done}> result for the + // current iteration. If the Promise is rejected, however, the + // result for this iteration will be rejected with the same + // reason. Note that rejections of yielded Promises are not + // thrown back into the generator function, as is the case + // when an awaited Promise is rejected. This difference in + // behavior between yield and await is important, because it + // allows the consumer to decide what to do with the yielded + // rejection (swallow it and continue, manually .throw it back + // into the generator, abandon iteration, whatever). With + // await, by contrast, there is no opportunity to examine the + // rejection reason outside the generator function, so the + // only option is to throw it from the await expression, and + // let the generator function handle the exception. + result.value = unwrapped; + resolve(result); + }, reject); + } + } + + if (typeof process === "object" && process.domain) { + invoke = process.domain.bind(invoke); + } + + var previousPromise; + + function enqueue(method, arg) { + function callInvokeWithMethodAndArg() { + return new Promise(function(resolve, reject) { + invoke(method, arg, resolve, reject); + }); + } + + return previousPromise = + // If enqueue has been called before, then we want to wait until + // all previous Promises have been resolved before calling invoke, + // so that results are always delivered in the correct order. If + // enqueue has not been called before, then it is important to + // call invoke immediately, without waiting on a callback to fire, + // so that the async generator function has the opportunity to do + // any necessary setup in a predictable way. This predictability + // is why the Promise constructor synchronously invokes its + // executor callback, and why async functions synchronously + // execute code before the first await. Since we implement simple + // async functions in terms of async generators, it is especially + // important to get this right, even though it requires care. + previousPromise ? previousPromise.then( + callInvokeWithMethodAndArg, + // Avoid propagating failures to Promises returned by later + // invocations of the iterator. + callInvokeWithMethodAndArg + ) : callInvokeWithMethodAndArg(); + } + + // Define the unified helper method that is used to implement .next, + // .throw, and .return (see defineIteratorMethods). + this._invoke = enqueue; + } + + defineIteratorMethods(AsyncIterator.prototype); + + // Note that simple async functions are implemented on top of + // AsyncIterator objects; they just return a Promise for the value of + // the final result produced by the iterator. + runtime.async = function(innerFn, outerFn, self, tryLocsList) { + var iter = new AsyncIterator( + wrap(innerFn, outerFn, self, tryLocsList) + ); + + return runtime.isGeneratorFunction(outerFn) + ? iter // If outerFn is a generator, return the full iterator. + : iter.next().then(function(result) { + return result.done ? result.value : iter.next(); + }); + }; + + function makeInvokeMethod(innerFn, self, context) { + var state = GenStateSuspendedStart; + + return function invoke(method, arg) { + if (state === GenStateExecuting) { + throw new Error("Generator is already running"); + } + + if (state === GenStateCompleted) { + if (method === "throw") { + throw arg; + } + + // Be forgiving, per 25.3.3.3.3 of the spec: + // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-generatorresume + return doneResult(); + } + + while (true) { + var delegate = context.delegate; + if (delegate) { + if (method === "return" || + (method === "throw" && delegate.iterator[method] === undefined)) { + // A return or throw (when the delegate iterator has no throw + // method) always terminates the yield* loop. + context.delegate = null; + + // If the delegate iterator has a return method, give it a + // chance to clean up. + var returnMethod = delegate.iterator["return"]; + if (returnMethod) { + var record = tryCatch(returnMethod, delegate.iterator, arg); + if (record.type === "throw") { + // If the return method threw an exception, let that + // exception prevail over the original return or throw. + method = "throw"; + arg = record.arg; + continue; + } + } + + if (method === "return") { + // Continue with the outer return, now that the delegate + // iterator has been terminated. + continue; + } + } + + var record = tryCatch( + delegate.iterator[method], + delegate.iterator, + arg + ); + + if (record.type === "throw") { + context.delegate = null; + + // Like returning generator.throw(uncaught), but without the + // overhead of an extra function call. + method = "throw"; + arg = record.arg; + continue; + } + + // Delegate generator ran and handled its own exceptions so + // regardless of what the method was, we continue as if it is + // "next" with an undefined arg. + method = "next"; + arg = undefined; + + var info = record.arg; + if (info.done) { + context[delegate.resultName] = info.value; + context.next = delegate.nextLoc; + } else { + state = GenStateSuspendedYield; + return info; + } + + context.delegate = null; + } + + if (method === "next") { + // Setting context._sent for legacy support of Babel's + // function.sent implementation. + context.sent = context._sent = arg; + + } else if (method === "throw") { + if (state === GenStateSuspendedStart) { + state = GenStateCompleted; + throw arg; + } + + if (context.dispatchException(arg)) { + // If the dispatched exception was caught by a catch block, + // then let that catch block handle the exception normally. + method = "next"; + arg = undefined; + } + + } else if (method === "return") { + context.abrupt("return", arg); + } + + state = GenStateExecuting; + + var record = tryCatch(innerFn, self, context); + if (record.type === "normal") { + // If an exception is thrown from innerFn, we leave state === + // GenStateExecuting and loop back for another invocation. + state = context.done + ? GenStateCompleted + : GenStateSuspendedYield; + + var info = { + value: record.arg, + done: context.done + }; + + if (record.arg === ContinueSentinel) { + if (context.delegate && method === "next") { + // Deliberately forget the last sent value so that we don't + // accidentally pass it on to the delegate. + arg = undefined; + } + } else { + return info; + } + + } else if (record.type === "throw") { + state = GenStateCompleted; + // Dispatch the exception by looping back around to the + // context.dispatchException(arg) call above. + method = "throw"; + arg = record.arg; + } + } + }; + } + + // Define Generator.prototype.{next,throw,return} in terms of the + // unified ._invoke helper method. + defineIteratorMethods(Gp); + + Gp[iteratorSymbol] = function() { + return this; + }; + + Gp[toStringTagSymbol] = "Generator"; + + Gp.toString = function() { + return "[object Generator]"; + }; + + function pushTryEntry(locs) { + var entry = { tryLoc: locs[0] }; + + if (1 in locs) { + entry.catchLoc = locs[1]; + } + + if (2 in locs) { + entry.finallyLoc = locs[2]; + entry.afterLoc = locs[3]; + } + + this.tryEntries.push(entry); + } + + function resetTryEntry(entry) { + var record = entry.completion || {}; + record.type = "normal"; + delete record.arg; + entry.completion = record; + } + + function Context(tryLocsList) { + // The root entry object (effectively a try statement without a catch + // or a finally block) gives us a place to store values thrown from + // locations where there is no enclosing try statement. + this.tryEntries = [{ tryLoc: "root" }]; + tryLocsList.forEach(pushTryEntry, this); + this.reset(true); + } + + runtime.keys = function(object) { + var keys = []; + for (var key in object) { + keys.push(key); + } + keys.reverse(); + + // Rather than returning an object with a next method, we keep + // things simple and return the next function itself. + return function next() { + while (keys.length) { + var key = keys.pop(); + if (key in object) { + next.value = key; + next.done = false; + return next; + } + } + + // To avoid creating an additional object, we just hang the .value + // and .done properties off the next function object itself. This + // also ensures that the minifier will not anonymize the function. + next.done = true; + return next; + }; + }; + + function values(iterable) { + if (iterable) { + var iteratorMethod = iterable[iteratorSymbol]; + if (iteratorMethod) { + return iteratorMethod.call(iterable); + } + + if (typeof iterable.next === "function") { + return iterable; + } + + if (!isNaN(iterable.length)) { + var i = -1, next = function next() { + while (++i < iterable.length) { + if (hasOwn.call(iterable, i)) { + next.value = iterable[i]; + next.done = false; + return next; + } + } + + next.value = undefined; + next.done = true; + + return next; + }; + + return next.next = next; + } + } + + // Return an iterator with no values. + return { next: doneResult }; + } + runtime.values = values; + + function doneResult() { + return { value: undefined, done: true }; + } + + Context.prototype = { + constructor: Context, + + reset: function(skipTempReset) { + this.prev = 0; + this.next = 0; + // Resetting context._sent for legacy support of Babel's + // function.sent implementation. + this.sent = this._sent = undefined; + this.done = false; + this.delegate = null; + + this.tryEntries.forEach(resetTryEntry); + + if (!skipTempReset) { + for (var name in this) { + // Not sure about the optimal order of these conditions: + if (name.charAt(0) === "t" && + hasOwn.call(this, name) && + !isNaN(+name.slice(1))) { + this[name] = undefined; + } + } + } + }, + + stop: function() { + this.done = true; + + var rootEntry = this.tryEntries[0]; + var rootRecord = rootEntry.completion; + if (rootRecord.type === "throw") { + throw rootRecord.arg; + } + + return this.rval; + }, + + dispatchException: function(exception) { + if (this.done) { + throw exception; + } + + var context = this; + function handle(loc, caught) { + record.type = "throw"; + record.arg = exception; + context.next = loc; + return !!caught; + } + + for (var i = this.tryEntries.length - 1; i >= 0; --i) { + var entry = this.tryEntries[i]; + var record = entry.completion; + + if (entry.tryLoc === "root") { + // Exception thrown outside of any try block that could handle + // it, so set the completion value of the entire function to + // throw the exception. + return handle("end"); + } + + if (entry.tryLoc <= this.prev) { + var hasCatch = hasOwn.call(entry, "catchLoc"); + var hasFinally = hasOwn.call(entry, "finallyLoc"); + + if (hasCatch && hasFinally) { + if (this.prev < entry.catchLoc) { + return handle(entry.catchLoc, true); + } else if (this.prev < entry.finallyLoc) { + return handle(entry.finallyLoc); + } + + } else if (hasCatch) { + if (this.prev < entry.catchLoc) { + return handle(entry.catchLoc, true); + } + + } else if (hasFinally) { + if (this.prev < entry.finallyLoc) { + return handle(entry.finallyLoc); + } + + } else { + throw new Error("try statement without catch or finally"); + } + } + } + }, + + abrupt: function(type, arg) { + for (var i = this.tryEntries.length - 1; i >= 0; --i) { + var entry = this.tryEntries[i]; + if (entry.tryLoc <= this.prev && + hasOwn.call(entry, "finallyLoc") && + this.prev < entry.finallyLoc) { + var finallyEntry = entry; + break; + } + } + + if (finallyEntry && + (type === "break" || + type === "continue") && + finallyEntry.tryLoc <= arg && + arg <= finallyEntry.finallyLoc) { + // Ignore the finally entry if control is not jumping to a + // location outside the try/catch block. + finallyEntry = null; + } + + var record = finallyEntry ? finallyEntry.completion : {}; + record.type = type; + record.arg = arg; + + if (finallyEntry) { + this.next = finallyEntry.finallyLoc; + } else { + this.complete(record); + } + + return ContinueSentinel; + }, + + complete: function(record, afterLoc) { + if (record.type === "throw") { + throw record.arg; + } + + if (record.type === "break" || + record.type === "continue") { + this.next = record.arg; + } else if (record.type === "return") { + this.rval = record.arg; + this.next = "end"; + } else if (record.type === "normal" && afterLoc) { + this.next = afterLoc; + } + }, + + finish: function(finallyLoc) { + for (var i = this.tryEntries.length - 1; i >= 0; --i) { + var entry = this.tryEntries[i]; + if (entry.finallyLoc === finallyLoc) { + this.complete(entry.completion, entry.afterLoc); + resetTryEntry(entry); + return ContinueSentinel; + } + } + }, + + "catch": function(tryLoc) { + for (var i = this.tryEntries.length - 1; i >= 0; --i) { + var entry = this.tryEntries[i]; + if (entry.tryLoc === tryLoc) { + var record = entry.completion; + if (record.type === "throw") { + var thrown = record.arg; + resetTryEntry(entry); + } + return thrown; + } + } + + // The context.catch method must only be called with a location + // argument that corresponds to a known catch block. + throw new Error("illegal catch attempt"); + }, + + delegateYield: function(iterable, resultName, nextLoc) { + this.delegate = { + iterator: values(iterable), + resultName: resultName, + nextLoc: nextLoc + }; + + return ContinueSentinel; + } + }; +})( + // Among the various tricks for obtaining a reference to the global + // object, this seems to be the most reliable technique that does not + // use indirect eval (which violates Content Security Policy). + typeof global === "object" ? global : + typeof window === "object" ? window : + typeof self === "object" ? self : this +);