diff --git a/samples/Samples.Echo/Samples.Echo.csproj b/samples/Samples.Echo/Samples.Echo.csproj
new file mode 100644
index 0000000..d156e7f
--- /dev/null
+++ b/samples/Samples.Echo/Samples.Echo.csproj
@@ -0,0 +1,78 @@
+
+
+
+
+ Debug
+ {F706A854-E68F-4AE2-AE2A-714110651EED}
+ {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}
+ Library
+ bin
+ v4.5
+ full
+ true
+ 1.4
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ web.config
+
+
+ web.config
+
+
+
+ 12.0
+
+
+ Samples.Echo
+
+
+
+
+
+
+
+ True
+ True
+ 23485
+ /
+ http://localhost:23485/
+ False
+ False
+
+
+ False
+
+
+
+
+
+ false
+ true
+
+
+ true
+ false
+
+
+ xcopy /d "$(SolutionDir)\src\stormancer-sdk-js\stormancer.js" ".."
+
+
+
\ No newline at end of file
diff --git a/samples/Samples.Echo/Scripts/msgPack.ts b/samples/Samples.Echo/Scripts/msgPack.ts
new file mode 100644
index 0000000..e3a42a4
--- /dev/null
+++ b/samples/Samples.Echo/Scripts/msgPack.ts
@@ -0,0 +1,726 @@
+///
+
+/*!{id:msgpack.js,ver:1.05,license:"MIT",author:"uupaa.js@gmail.com"}*/
+
+// === msgpack ===
+// MessagePack -> http://msgpack.sourceforge.net/
+
+declare function vblen(b);
+declare function vbstr(b);
+
+this.msgpack || (function (globalScope) {
+
+ globalScope.msgpack = {
+ pack: msgpackpack, // msgpack.pack(data:Mix,
+ // toString:Boolean = false):ByteArray/ByteString/false
+ // [1][mix to String] msgpack.pack({}, true) -> "..."
+ // [2][mix to ByteArray] msgpack.pack({}) -> [...]
+ unpack: msgpackunpack, // msgpack.unpack(data:BinaryString/ByteArray):Mix
+ // [1][String to mix] msgpack.unpack("...") -> {}
+ // [2][ByteArray to mix] msgpack.unpack([...]) -> {}
+ worker: "msgpack.js", // msgpack.worker - WebWorkers script filename
+ upload: msgpackupload, // msgpack.upload(url:String, option:Hash, callback:Function)
+ download: msgpackdownload // msgpack.download(url:String, option:Hash, callback:Function)
+ };
+
+ var _ie = /MSIE/.test(navigator.userAgent),
+ _bin2num = {}, // BinaryStringToNumber { "\00": 0, ... "\ff": 255 }
+ _num2bin = {}, // NumberToBinaryString { 0: "\00", ... 255: "\ff" }
+ _num2b64 = ("ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
+ "abcdefghijklmnopqrstuvwxyz0123456789+/").split(""),
+ _buf = [], // decode buffer
+ _idx = 0, // decode buffer[index]
+ _error = 0, // msgpack.pack() error code. 1 = CYCLIC_REFERENCE_ERROR
+ _isArray = Array.isArray || (function (mix) {
+ return Object.prototype.toString.call(mix) === "[object Array]";
+ }),
+ _toString = String.fromCharCode, // CharCode/ByteArray to String
+ _MAX_DEPTH = 512;
+
+ // for WebWorkers Code Block
+ (self).importScripts && (onmessage = function (event) {
+ if (event.data.method === "pack") {
+ (window).postMessage(base64encode(msgpackpack(event.data.data)));
+ } else {
+ (window).postMessage(msgpackunpack(event.data.data));
+ }
+ });
+
+ // msgpack.pack
+ function msgpackpack(data, // @param Mix:
+ settings?) { // @param Boolean(= false):
+ // @return ByteArray/BinaryString/false:
+ // false is error return
+ // [1][mix to String] msgpack.pack({}, true) -> "..."
+ // [2][mix to ByteArray] msgpack.pack({}) -> [...]
+ var toString = false;
+ _error = 0;
+ if (!settings) {
+ settings = {byteProperties:[]};
+ }
+ var byteArray = encode([], data, 0,settings);
+
+ return _error ? false
+ : toString ? byteArrayToByteString(byteArray)
+ : byteArray;
+ }
+
+ // msgpack.unpack
+ function msgpackunpack(data, settings?) { // @param BinaryString/ByteArray:
+ // @return Mix/undefined:
+ // undefined is error return
+ // [1][String to mix] msgpack.unpack("...") -> {}
+ // [2][ByteArray to mix] msgpack.unpack([...]) -> {}
+ if (!settings) {
+ settings = { byteProperties: [] };
+ }
+ _buf = typeof data === "string" ? toByteArray(data) : data;
+ _idx = -1;
+ return decode(settings); // mix or undefined
+ }
+
+ // inner - encoder
+ function encode(rv, // @param ByteArray: result
+ mix, // @param Mix: source data
+ depth, // @param Number: depth
+ settings?,
+ bytesArray?
+ ) {
+ var size, i, iz, c, pos, // for UTF8.encode, Array.encode, Hash.encode
+ high, low, sign, exp, frac; // for IEEE754
+
+ if (mix == null) { // null or undefined -> 0xc0 ( null )
+ rv.push(0xc0);
+ } else if (mix === false) { // false -> 0xc2 ( false )
+ rv.push(0xc2);
+ } else if (mix === true) { // true -> 0xc3 ( true )
+ rv.push(0xc3);
+ } else {
+ switch (typeof mix) {
+ case "number":
+ if (mix !== mix) { // isNaN
+ rv.push(0xcb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff); // quiet NaN
+ } else if (mix === Infinity) {
+ rv.push(0xcb, 0x7f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); // positive infinity
+ } else if (Math.floor(mix) === mix) { // int or uint
+ if (mix < 0) {
+ // int
+ if (mix >= -32) { // negative fixnum
+ rv.push(0xe0 + mix + 32);
+ } else if (mix > -0x80) {
+ rv.push(0xd0, mix + 0x100);
+ } else if (mix > -0x8000) {
+ mix += 0x10000;
+ rv.push(0xd1, mix >> 8, mix & 0xff);
+ } else if (mix > -0x80000000) {
+ mix += 0x100000000;
+ rv.push(0xd2, mix >>> 24, (mix >> 16) & 0xff,
+ (mix >> 8) & 0xff, mix & 0xff);
+ } else {
+ high = Math.floor(mix / 0x100000000);
+ low = mix & 0xffffffff;
+ rv.push(0xd3, (high >> 24) & 0xff, (high >> 16) & 0xff,
+ (high >> 8) & 0xff, high & 0xff,
+ (low >> 24) & 0xff, (low >> 16) & 0xff,
+ (low >> 8) & 0xff, low & 0xff);
+ }
+ } else {
+ // uint
+ if (mix < 0x80) {
+ rv.push(mix); // positive fixnum
+ } else if (mix < 0x100) { // uint 8
+ rv.push(0xcc, mix);
+ } else if (mix < 0x10000) { // uint 16
+ rv.push(0xcd, mix >> 8, mix & 0xff);
+ } else if (mix < 0x100000000) { // uint 32
+ rv.push(0xce, mix >>> 24, (mix >> 16) & 0xff,
+ (mix >> 8) & 0xff, mix & 0xff);
+ } else {
+ high = Math.floor(mix / 0x100000000);
+ low = mix & 0xffffffff;
+ rv.push(0xcf, (high >> 24) & 0xff, (high >> 16) & 0xff,
+ (high >> 8) & 0xff, high & 0xff,
+ (low >> 24) & 0xff, (low >> 16) & 0xff,
+ (low >> 8) & 0xff, low & 0xff);
+ }
+ }
+ } else { // double
+ // THX!! @edvakf
+ // http://javascript.g.hatena.ne.jp/edvakf/20101128/1291000731
+ sign = mix < 0;
+ sign && (mix *= -1);
+
+ // add offset 1023 to ensure positive
+ // 0.6931471805599453 = Math.LN2;
+ exp = ((Math.log(mix) / 0.6931471805599453) + 1023) | 0;
+
+ // shift 52 - (exp - 1023) bits to make integer part exactly 53 bits,
+ // then throw away trash less than decimal point
+ frac = mix * Math.pow(2, 52 + 1023 - exp);
+
+ // S+-Exp(11)--++-----------------Fraction(52bits)-----------------------+
+ // || || |
+ // v+----------++--------------------------------------------------------+
+ // 00000000|00000000|00000000|00000000|00000000|00000000|00000000|00000000
+ // 6 5 55 4 4 3 2 1 8 0
+ // 3 6 21 8 0 2 4 6
+ //
+ // +----------high(32bits)-----------+ +----------low(32bits)------------+
+ // | | | |
+ // +---------------------------------+ +---------------------------------+
+ // 3 2 21 1 8 0
+ // 1 4 09 6
+ low = frac & 0xffffffff;
+ sign && (exp |= 0x800);
+ high = ((frac / 0x100000000) & 0xfffff) | (exp << 20);
+
+ rv.push(0xcb, (high >> 24) & 0xff, (high >> 16) & 0xff,
+ (high >> 8) & 0xff, high & 0xff,
+ (low >> 24) & 0xff, (low >> 16) & 0xff,
+ (low >> 8) & 0xff, low & 0xff);
+ }
+ break;
+ case "string":
+ // http://d.hatena.ne.jp/uupaa/20101128
+ iz = mix.length;
+ pos = rv.length; // keep rewrite position
+
+ rv.push(0); // placeholder
+
+ // utf8.encode
+ for (i = 0; i < iz; ++i) {
+ c = mix.charCodeAt(i);
+ if (c < 0x80) { // ASCII(0x00 ~ 0x7f)
+ rv.push(c & 0x7f);
+ } else if (c < 0x0800) {
+ rv.push(((c >>> 6) & 0x1f) | 0xc0, (c & 0x3f) | 0x80);
+ } else if (c < 0x10000) {
+ rv.push(((c >>> 12) & 0x0f) | 0xe0,
+ ((c >>> 6) & 0x3f) | 0x80, (c & 0x3f) | 0x80);
+ }
+ }
+ size = rv.length - pos - 1;
+
+ if (size < 32) {
+ rv[pos] = 0xa0 + size; // rewrite
+ } else if (size < 0x10000) { // 16
+ rv.splice(pos, 1, 0xda, size >> 8, size & 0xff);
+ } else if (size < 0x100000000) { // 32
+ rv.splice(pos, 1, 0xdb,
+ size >>> 24, (size >> 16) & 0xff,
+ (size >> 8) & 0xff, size & 0xff);
+ }
+ break;
+ default: // array or hash
+ if (++depth >= _MAX_DEPTH) {
+ _error = 1; // CYCLIC_REFERENCE_ERROR
+ return rv = []; // clear
+ }
+ if (_isArray(mix)) {
+ if (bytesArray) {
+ size = mix.length;
+ if (size < 32) {
+ rv.push(0xa0 + size);
+ } else if (size < 0x10000) { // 16
+ rv.push(0xda, size >> 8, size & 0xff);
+ } else if (size < 0x100000000) { // 32
+ rv.push(0xdb, size >>> 24, (size >> 16) & 0xff,
+ (size >> 8) & 0xff, size & 0xff);
+ }
+ for (i = 0; i < size; ++i) {
+ rv.push(mix[i]);
+ }
+ }
+ else {
+ size = mix.length;
+ if (size < 16) {
+ rv.push(0x90 + size);
+ } else if (size < 0x10000) { // 16
+ rv.push(0xdc, size >> 8, size & 0xff);
+ } else if (size < 0x100000000) { // 32
+ rv.push(0xdd, size >>> 24, (size >> 16) & 0xff,
+ (size >> 8) & 0xff, size & 0xff);
+ }
+ for (i = 0; i < size; ++i) {
+ encode(rv, mix[i], depth,settings);
+ }
+ }
+ } else { // hash
+ // http://d.hatena.ne.jp/uupaa/20101129
+ pos = rv.length; // keep rewrite position
+ rv.push(0); // placeholder
+ size = 0;
+ for (i in mix) {
+ if (typeof (mix[i]) == "function") {
+ continue;
+ }
+ ++size;
+ encode(rv, i, depth);
+ if ($.inArray(i,settings.byteProperties)!=-1) {
+ encode(rv, mix[i], depth,settings,true);
+ }
+ else {
+ encode(rv, mix[i], depth, settings,false);
+ }
+ }
+ if (size < 16) {
+ rv[pos] = 0x80 + size; // rewrite
+ } else if (size < 0x10000) { // 16
+ rv.splice(pos, 1, 0xde, size >> 8, size & 0xff);
+ } else if (size < 0x100000000) { // 32
+ rv.splice(pos, 1, 0xdf,
+ size >>> 24, (size >> 16) & 0xff,
+ (size >> 8) & 0xff, size & 0xff);
+ }
+ }
+ }
+ }
+ return rv;
+ }
+
+ // inner - decoder
+ function decode(settings,rawAsArray?) { // @return Mix:
+ var size, i, iz, c, num = 0,
+ sign, exp, frac, ary, hash,
+ buf = _buf, type = buf[++_idx],key;
+
+ if (type >= 0xe0) { // Negative FixNum (111x xxxx) (-32 ~ -1)
+ return type - 0x100;
+ }
+ if (type < 0xc0) {
+ if (type < 0x80) { // Positive FixNum (0xxx xxxx) (0 ~ 127)
+ return type;
+ }
+ if (type < 0x90) { // FixMap (1000 xxxx)
+ num = type - 0x80;
+ type = 0x80;
+ } else if (type < 0xa0) { // FixArray (1001 xxxx)
+ num = type - 0x90;
+ type = 0x90;
+ } else { // if (type < 0xc0) { // FixRaw (101x xxxx)
+ num = type - 0xa0;
+ type = 0xa0;
+ }
+ }
+ switch (type) {
+ case 0xc0: return null;
+ case 0xc2: return false;
+ case 0xc3: return true;
+ case 0xca: // float
+ num = buf[++_idx] * 0x1000000 + (buf[++_idx] << 16) +
+ (buf[++_idx] << 8) + buf[++_idx];
+ sign = num & 0x80000000; // 1bit
+ exp = (num >> 23) & 0xff; // 8bits
+ frac = num & 0x7fffff; // 23bits
+ if (!num || num === 0x80000000) { // 0.0 or -0.0
+ return 0;
+ }
+ if (exp === 0xff) { // NaN or Infinity
+ return frac ? NaN : Infinity;
+ }
+ return (sign ? -1 : 1) *
+ (frac | 0x800000) * Math.pow(2, exp - 127 - 23); // 127: bias
+ case 0xcb: // double
+ num = buf[++_idx] * 0x1000000 + (buf[++_idx] << 16) +
+ (buf[++_idx] << 8) + buf[++_idx];
+ sign = num & 0x80000000; // 1bit
+ exp = (num >> 20) & 0x7ff; // 11bits
+ frac = num & 0xfffff; // 52bits - 32bits (high word)
+ if (!num || num === 0x80000000) { // 0.0 or -0.0
+ _idx += 4;
+ return 0;
+ }
+ if (exp === 0x7ff) { // NaN or Infinity
+ _idx += 4;
+ return frac ? NaN : Infinity;
+ }
+ num = buf[++_idx] * 0x1000000 + (buf[++_idx] << 16) +
+ (buf[++_idx] << 8) + buf[++_idx];
+ return (sign ? -1 : 1) *
+ ((frac | 0x100000) * Math.pow(2, exp - 1023 - 20) // 1023: bias
+ + num * Math.pow(2, exp - 1023 - 52));
+ // 0xcf: uint64, 0xce: uint32, 0xcd: uint16
+ case 0xcf: num = buf[++_idx] * 0x1000000 + (buf[++_idx] << 16) +
+ (buf[++_idx] << 8) + buf[++_idx];
+ return num * 0x100000000 +
+ buf[++_idx] * 0x1000000 + (buf[++_idx] << 16) +
+ (buf[++_idx] << 8) + buf[++_idx];
+ case 0xce: num += buf[++_idx] * 0x1000000 + (buf[++_idx] << 16);
+ case 0xcd: num += buf[++_idx] << 8;
+ case 0xcc: return num + buf[++_idx];
+ // 0xd3: int64, 0xd2: int32, 0xd1: int16, 0xd0: int8
+ case 0xd3: num = buf[++_idx];
+ if (num & 0x80) { // sign -> avoid overflow
+ return ((num ^ 0xff) * 0x100000000000000 +
+ (buf[++_idx] ^ 0xff) * 0x1000000000000 +
+ (buf[++_idx] ^ 0xff) * 0x10000000000 +
+ (buf[++_idx] ^ 0xff) * 0x100000000 +
+ (buf[++_idx] ^ 0xff) * 0x1000000 +
+ (buf[++_idx] ^ 0xff) * 0x10000 +
+ (buf[++_idx] ^ 0xff) * 0x100 +
+ (buf[++_idx] ^ 0xff) + 1) * -1;
+ }
+ return num * 0x100000000000000 +
+ buf[++_idx] * 0x1000000000000 +
+ buf[++_idx] * 0x10000000000 +
+ buf[++_idx] * 0x100000000 +
+ buf[++_idx] * 0x1000000 +
+ buf[++_idx] * 0x10000 +
+ buf[++_idx] * 0x100 +
+ buf[++_idx];
+ case 0xd2: num = buf[++_idx] * 0x1000000 + (buf[++_idx] << 16) +
+ (buf[++_idx] << 8) + buf[++_idx];
+ return num < 0x80000000 ? num : num - 0x100000000; // 0x80000000 * 2
+ case 0xd1: num = (buf[++_idx] << 8) + buf[++_idx];
+ return num < 0x8000 ? num : num - 0x10000; // 0x8000 * 2
+ case 0xd0: num = buf[++_idx];
+ return num < 0x80 ? num : num - 0x100; // 0x80 * 2
+ // 0xdb: raw32, 0xda: raw16, 0xa0: raw ( string ) (or Array if rawAsArray == true)
+ case 0xdb: num += buf[++_idx] * 0x1000000 + (buf[++_idx] << 16);
+ case 0xda: num += (buf[++_idx] << 8) + buf[++_idx];
+ case 0xa0:
+ if (rawAsArray) {
+ for (ary = [], i = _idx, iz = i + num; i < iz;) {
+ ary.push(buf[++i]);
+ }
+ _idx = i;
+ return ary;
+ }
+ else {// utf8.decode
+
+ for (ary = [], i = _idx, iz = i + num; i < iz;) {
+ c = buf[++i]; // lead byte
+ ary.push(c < 0x80 ? c : // ASCII(0x00 ~ 0x7f)
+ c < 0xe0 ? ((c & 0x1f) << 6 | (buf[++i] & 0x3f)) :
+ ((c & 0x0f) << 12 | (buf[++i] & 0x3f) << 6
+ | (buf[++i] & 0x3f)));
+ }
+ _idx = i;
+ return ary.length < 10240 ? _toString.apply(null, ary)
+ : byteArrayToByteString(ary);
+ }
+ // 0xdf: map32, 0xde: map16, 0x80: map
+ case 0xdf: num += buf[++_idx] * 0x1000000 + (buf[++_idx] << 16);
+ case 0xde: num += (buf[++_idx] << 8) + buf[++_idx];
+ case 0x80: hash = {};
+ while (num--) {
+ // make key/value pair
+ size = buf[++_idx] - 0xa0;
+
+ for (ary = [], i = _idx, iz = i + size; i < iz;) {
+ c = buf[++i]; // lead byte
+ ary.push(c < 0x80 ? c : // ASCII(0x00 ~ 0x7f)
+ c < 0xe0 ? ((c & 0x1f) << 6 | (buf[++i] & 0x3f)) :
+ ((c & 0x0f) << 12 | (buf[++i] & 0x3f) << 6
+ | (buf[++i] & 0x3f)));
+ }
+ _idx = i;
+ key = _toString.apply(null, ary)
+ if ($.inArray(key, settings.byteProperties) != -1) {
+ hash[key] = decode(settings,true);
+ }
+ else {
+
+ hash[key] = decode(settings);
+ }
+ }
+ return hash;
+ // 0xdd: array32, 0xdc: array16, 0x90: array
+ case 0xdd: num += buf[++_idx] * 0x1000000 + (buf[++_idx] << 16);
+ case 0xdc: num += (buf[++_idx] << 8) + buf[++_idx];
+ case 0x90: ary = [];
+ while (num--) {
+ ary.push(decode(settings,rawAsArray));
+ }
+ return ary;
+ }
+ return;
+ }
+
+ // inner - byteArray To ByteString
+ function byteArrayToByteString(byteArray) { // @param ByteArray
+ // @return String
+ // http://d.hatena.ne.jp/uupaa/20101128
+ try {
+ return _toString.apply(this, byteArray); // toString
+ } catch (err) {
+ ; // avoid "Maximum call stack size exceeded"
+ }
+ var rv = [], i = 0, iz = byteArray.length, num2bin = _num2bin;
+
+ for (; i < iz; ++i) {
+ rv[i] = num2bin[byteArray[i]];
+ }
+ return rv.join("");
+ }
+
+ // msgpack.download - load from server
+ function msgpackdownload(url, // @param String:
+ option, // @param Hash: { worker, timeout, before, after }
+ // option.worker - Boolean(= false): true is use WebWorkers
+ // option.timeout - Number(= 10): timeout sec
+ // option.before - Function: before(xhr, option)
+ // option.after - Function: after(xhr, option, { status, ok })
+ callback) { // @param Function: callback(data, option, { status, ok })
+ // data - Mix/null:
+ // option - Hash:
+ // status - Number: HTTP status code
+ // ok - Boolean:
+ option.method = "GET";
+ option.binary = true;
+ ajax(url, option, callback);
+ }
+
+ // msgpack.upload - save to server
+ function msgpackupload(url, // @param String:
+ option, // @param Hash: { data, worker, timeout, before, after }
+ // option.data - Mix:
+ // option.worker - Boolean(= false): true is use WebWorkers
+ // option.timeout - Number(= 10): timeout sec
+ // option.before - Function: before(xhr, option)
+ // option.after - Function: after(xhr, option, { status, ok })
+ callback) { // @param Function: callback(data, option, { status, ok })
+ // data - String: responseText
+ // option - Hash:
+ // status - Number: HTTP status code
+ // ok - Boolean:
+ option.method = "PUT";
+ option.binary = true;
+
+ if (option.worker && globalScope.Worker) {
+ var worker = new Worker(globalScope.msgpack.worker);
+
+ worker.onmessage = function (event) {
+ option.data = event.data;
+ ajax(url, option, callback);
+ };
+ worker.postMessage({ method: "pack", data: option.data });
+ } else {
+ // pack and base64 encode
+ option.data = base64encode(msgpackpack(option.data));
+ ajax(url, option, callback);
+ }
+ }
+
+ // inner -
+ function ajax(url, // @param String:
+ option, // @param Hash: { data, ifmod, method, timeout,
+ // header, binary, before, after, worker }
+ // option.data - Mix: upload data
+ // option.ifmod - Boolean: true is "If-Modified-Since" header
+ // option.method - String: "GET", "POST", "PUT"
+ // option.timeout - Number(= 10): timeout sec
+ // option.header - Hash(= {}): { key: "value", ... }
+ // option.binary - Boolean(= false): true is binary data
+ // option.before - Function: before(xhr, option)
+ // option.after - Function: after(xhr, option, { status, ok })
+ // option.worker - Boolean(= false): true is use WebWorkers
+ callback) { // @param Function: callback(data, option, { status, ok })
+ // data - String/Mix/null:
+ // option - Hash:
+ // status - Number: HTTP status code
+ // ok - Boolean:
+ function readyStateChange() {
+ if (xhr.readyState === 4) {
+ var data, status = xhr.status, worker, byteArray,
+ rv = { status: status, ok: status >= 200 && status < 300 };
+
+ if (!run++) {
+ if (method === "PUT") {
+ data = rv.ok ? xhr.responseText : "";
+ } else {
+ if (rv.ok) {
+ if (option.worker && globalScope.Worker) {
+ worker = new Worker(globalScope.msgpack.worker);
+ worker.onmessage = function (event) {
+ callback(event.data, option, rv);
+ };
+ worker.postMessage({
+ method: "unpack",
+ data: xhr.responseText
+ });
+ gc();
+ return;
+ } else {
+ byteArray = _ie ? toByteArrayIE(xhr)
+ : toByteArray(xhr.responseText);
+ data = msgpackunpack(byteArray);
+ }
+ }
+ }
+ after && after(xhr, option, rv);
+ callback(data, option, rv);
+ gc();
+ }
+ }
+ }
+
+ function ng(abort, status) {
+ if (!run++) {
+ var rv = { status: status || 400, ok: false };
+
+ after && after(xhr, option, rv);
+ callback(null, option, rv);
+ gc(abort);
+ }
+ }
+
+ function gc(abort?) {
+ abort && xhr && xhr.abort && xhr.abort();
+ watchdog && (clearTimeout(watchdog), watchdog = 0);
+ xhr = null;
+ globalScope.addEventListener &&
+ globalScope.removeEventListener("beforeunload", ng, false);
+ }
+
+ var watchdog = 0,
+ method = option.method || "GET",
+ header = option.header || {},
+ before = option.before,
+ after = option.after,
+ data = option.data || null,
+ xhr = globalScope.XMLHttpRequest ? new XMLHttpRequest() :
+ globalScope.ActiveXObject ? new ActiveXObject("Microsoft.XMLHTTP") :
+ null,
+ run = 0, i,
+ overrideMimeType = "overrideMimeType",
+ setRequestHeader = "setRequestHeader",
+ getbinary = method === "GET" && option.binary;
+
+ try {
+ xhr.onreadystatechange = readyStateChange;
+ xhr.open(method, url, true); // ASync
+
+ before && before(xhr, option);
+
+ getbinary && xhr[overrideMimeType] &&
+ xhr[overrideMimeType]("text/plain; charset=x-user-defined");
+ data &&
+ xhr[setRequestHeader]("Content-Type",
+ "application/x-www-form-urlencoded");
+
+ for (i in header) {
+ xhr[setRequestHeader](i, header[i]);
+ }
+
+ globalScope.addEventListener &&
+ globalScope.addEventListener("beforeunload", ng, false); // 400: Bad Request
+
+ xhr.send(data);
+ watchdog = setTimeout(function () {
+ ng(1, 408); // 408: Request Time-out
+ }, (option.timeout || 10) * 1000);
+ } catch (err) {
+ ng(0, 400); // 400: Bad Request
+ }
+ }
+
+ // inner - BinaryString To ByteArray
+ function toByteArray(data) { // @param BinaryString: "\00\01"
+ // @return ByteArray: [0x00, 0x01]
+ var rv = [], bin2num = _bin2num, remain,
+ ary = data.split(""),
+ i = -1, iz;
+
+ iz = ary.length;
+ remain = iz % 8;
+
+ while (remain--) {
+ ++i;
+ rv[i] = bin2num[ary[i]];
+ }
+ remain = iz >> 3;
+ while (remain--) {
+ rv.push(bin2num[ary[++i]], bin2num[ary[++i]],
+ bin2num[ary[++i]], bin2num[ary[++i]],
+ bin2num[ary[++i]], bin2num[ary[++i]],
+ bin2num[ary[++i]], bin2num[ary[++i]]);
+ }
+ return rv;
+ }
+
+ // inner - BinaryString to ByteArray
+ function toByteArrayIE(xhr) {
+ var rv = [], data, remain,
+ charCodeAt = "charCodeAt",
+ loop, v0, v1, v2, v3, v4, v5, v6, v7,
+ i = -1, iz;
+
+ iz = vblen(xhr);
+ data = vbstr(xhr);
+ loop = Math.ceil(iz / 2);
+ remain = loop % 8;
+
+ while (remain--) {
+ v0 = data[charCodeAt](++i); // 0x00,0x01 -> 0x0100
+ rv.push(v0 & 0xff, v0 >> 8);
+ }
+ remain = loop >> 3;
+ while (remain--) {
+ v0 = data[charCodeAt](++i);
+ v1 = data[charCodeAt](++i);
+ v2 = data[charCodeAt](++i);
+ v3 = data[charCodeAt](++i);
+ v4 = data[charCodeAt](++i);
+ v5 = data[charCodeAt](++i);
+ v6 = data[charCodeAt](++i);
+ v7 = data[charCodeAt](++i);
+ rv.push(v0 & 0xff, v0 >> 8, v1 & 0xff, v1 >> 8,
+ v2 & 0xff, v2 >> 8, v3 & 0xff, v3 >> 8,
+ v4 & 0xff, v4 >> 8, v5 & 0xff, v5 >> 8,
+ v6 & 0xff, v6 >> 8, v7 & 0xff, v7 >> 8);
+ }
+ iz % 2 && rv.pop();
+
+ return rv;
+ }
+
+ // inner - base64.encode
+ function base64encode(data) { // @param ByteArray:
+ // @return Base64String:
+ var rv = [],
+ c = 0, i = -1, iz = data.length,
+ pad = [0, 2, 1][data.length % 3],
+ num2bin = _num2bin,
+ num2b64 = _num2b64;
+
+ if (globalScope.btoa) {
+ while (i < iz) {
+ rv.push(num2bin[data[++i]]);
+ }
+ return btoa(rv.join(""));
+ }
+ --iz;
+ while (i < iz) {
+ c = (data[++i] << 16) | (data[++i] << 8) | (data[++i]); // 24bit
+ rv.push(num2b64[(c >> 18) & 0x3f],
+ num2b64[(c >> 12) & 0x3f],
+ num2b64[(c >> 6) & 0x3f],
+ num2b64[c & 0x3f]);
+ }
+ pad > 1 && (rv[rv.length - 2] = "=");
+ pad > 0 && (rv[rv.length - 1] = "=");
+ return rv.join("");
+ }
+
+ // --- init ---
+ (function () {
+ var i = 0, v;
+
+ for (; i < 0x100; ++i) {
+ v = _toString(i);
+ _bin2num[v] = i; // "\00" -> 0x00
+ _num2bin[i] = v; // 0 -> "\00"
+ }
+ // http://twitter.com/edvakf/statuses/15576483807
+ for (i = 0x80; i < 0x100; ++i) { // [Webkit][Gecko]
+ _bin2num[_toString(0xf700 + i)] = i; // "\f780" -> 0x80
+ }
+ })();
+
+ _ie && document.write('
-
diff --git a/src/stormancer-sdk-js/web.Debug.config b/samples/Samples.Echo/web.Debug.config
similarity index 100%
rename from src/stormancer-sdk-js/web.Debug.config
rename to samples/Samples.Echo/web.Debug.config
diff --git a/src/stormancer-sdk-js/web.Release.config b/samples/Samples.Echo/web.Release.config
similarity index 100%
rename from src/stormancer-sdk-js/web.Release.config
rename to samples/Samples.Echo/web.Release.config
diff --git a/src/stormancer-sdk-js/Client.ts b/src/stormancer-sdk-js/Client.ts
index 5687b83..8fd7444 100644
--- a/src/stormancer-sdk-js/Client.ts
+++ b/src/stormancer-sdk-js/Client.ts
@@ -100,12 +100,13 @@ module Stormancer {
var parameter: SceneInfosRequestDto = { Metadata: self._serverConnection.metadata, Token: ci.token };
return self.sendSystemRequest(MessageIDTypes.ID_GET_SCENE_INFOS, parameter);
}).then((result: SceneInfosDto) => {
- if (!self._serverConnection.serializer) {
+ if (!self._serverConnection.serializerChosen) {
if (!result.SelectedSerializer) {
throw new Error("No serializer selected.");
}
self._serverConnection.serializer = self._serializers[result.SelectedSerializer];
self._serverConnection.metadata["serializer"] = result.SelectedSerializer;
+ self._serverConnection.serializerChosen = true;
}
var scene = new Scene(self._serverConnection, self, sceneId, ci.token, result);
return scene;
diff --git a/src/stormancer-sdk-js/Core/IConnection.ts b/src/stormancer-sdk-js/Core/IConnection.ts
index 4f671ad..9fa2191 100644
--- a/src/stormancer-sdk-js/Core/IConnection.ts
+++ b/src/stormancer-sdk-js/Core/IConnection.ts
@@ -50,6 +50,7 @@ module Stormancer {
// Returns advanced statistics about the connection.
//getConnectionStatistics(): IConnectionStatistics;
+ serializerChosen: boolean;
serializer: ISerializer;
}
}
diff --git a/src/stormancer-sdk-js/Transports/WebSocketClientConnection.ts b/src/stormancer-sdk-js/Transports/WebSocketClientConnection.ts
index 0be59f8..0b10c22 100644
--- a/src/stormancer-sdk-js/Transports/WebSocketClientConnection.ts
+++ b/src/stormancer-sdk-js/Transports/WebSocketClientConnection.ts
@@ -63,6 +63,7 @@ module Stormancer {
this.application = application;
}
- public serializer: ISerializer;
+ public serializerChosen: boolean = false;
+ public serializer: ISerializer = new MsgPackSerializer();
}
}
diff --git a/src/stormancer-sdk-js/stormancer-sdk-js.csproj b/src/stormancer-sdk-js/stormancer-sdk-js.csproj
index 5155ef6..1de927f 100644
--- a/src/stormancer-sdk-js/stormancer-sdk-js.csproj
+++ b/src/stormancer-sdk-js/stormancer-sdk-js.csproj
@@ -18,16 +18,12 @@
-
-
-
-
@@ -70,12 +66,6 @@
-
- web.config
-
-
- web.config
-
12.0
@@ -107,6 +97,7 @@
True
true
stormancer.js
+ True
true
diff --git a/stormancer-sdk-js.sln b/stormancer-sdk-js.sln
index 301451e..f84bce1 100644
--- a/stormancer-sdk-js.sln
+++ b/stormancer-sdk-js.sln
@@ -9,6 +9,11 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{8A09
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "stormancer-sdk-js", "src\stormancer-sdk-js\stormancer-sdk-js.csproj", "{AC5DB693-0AAB-4BA7-8D74-67C307BCDCE7}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Samples.Echo", "samples\Samples.Echo\Samples.Echo.csproj", "{F706A854-E68F-4AE2-AE2A-714110651EED}"
+ ProjectSection(ProjectDependencies) = postProject
+ {AC5DB693-0AAB-4BA7-8D74-67C307BCDCE7} = {AC5DB693-0AAB-4BA7-8D74-67C307BCDCE7}
+ EndProjectSection
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -19,11 +24,16 @@ Global
{AC5DB693-0AAB-4BA7-8D74-67C307BCDCE7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AC5DB693-0AAB-4BA7-8D74-67C307BCDCE7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AC5DB693-0AAB-4BA7-8D74-67C307BCDCE7}.Release|Any CPU.Build.0 = Release|Any CPU
+ {F706A854-E68F-4AE2-AE2A-714110651EED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {F706A854-E68F-4AE2-AE2A-714110651EED}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F706A854-E68F-4AE2-AE2A-714110651EED}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {F706A854-E68F-4AE2-AE2A-714110651EED}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{AC5DB693-0AAB-4BA7-8D74-67C307BCDCE7} = {EF042117-5269-4865-B492-6C0A3802F940}
+ {F706A854-E68F-4AE2-AE2A-714110651EED} = {8A0942AA-DC07-4A67-9192-91F4EEEEA3D5}
EndGlobalSection
EndGlobal