<!doctype html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>HTTPing | Access servers based on network response time!</title> <script type="text/javascript"> /* Configuration start */ var test_url_list = [ { name : 'Site 1', testurl: "http://site1.app.example.com/MYTESTFILE.txt", redirect: "http://site1.app.example.com"}, { name : 'Site 2', testurl: "http://site2.app.example.com/MYTESTFILE.txt", redirect: "http://site2.app.example.com"} ]; /* Configuration finishes */ /* DO NOT EDIT BELOW */ (function(globals) { var define, requireModule; (function() { var registry = {}, seen = {}; define = function(name, deps, callback) { registry[name] = { deps: deps, callback: callback }; }; requireModule = function(name) { if (seen[name]) { return seen[name]; } seen[name] = {}; var mod = registry[name]; if (!mod) { throw new Error("Module '" + name + "' not found."); } var deps = mod.deps, callback = mod.callback, reified = [], exports; for (var i=0, l=deps.length; i<l; i++) { if (deps[i] === 'exports') { reified.push(exports = {}); } else { reified.push(requireModule(deps[i])); } } var value = callback.apply(this, reified); return seen[name] = exports || value; }; })(); define("rsvp/all", ["rsvp/promise","exports"], function(__dependency1__, __exports__) { "use strict"; var Promise = __dependency1__.Promise; /* global toString */ function promiseAtLeast(expected_count, promises) { if (Object.prototype.toString.call(promises) !== "[object Array]") { throw new TypeError('You must pass an array to all.'); } function canceller() { var promise; for (var i = 0; i < promises.length; i++) { promise = promises[i]; if (promise && typeof promise.then === 'function' && typeof promise.cancel === 'function') { promise.cancel(); } } } return new Promise(function(resolve, reject) { var results = [], remaining = promises.length, promise, remaining_count = promises.length - expected_count; if (remaining === 0) { if (expected_count === 1) { resolve(); } else { resolve([]); } } function resolver(index) { return function(value) { resolveAll(index, value); }; } function resolveAll(index, value) { results[index] = value; if (--remaining === remaining_count) { if (remaining_count === 0) { resolve(results); } else { resolve(value); canceller(); } } } function cancelAll(rejectionValue) { reject(rejectionValue); canceller(); } for (var i = 0; i < promises.length; i++) { promise = promises[i]; if (promise && typeof promise.then === 'function') { promise.then(resolver(i), cancelAll); } else { resolveAll(i, promise); } } }, canceller ); } function all(promises) { return promiseAtLeast(promises.length, promises); } function any(promises) { return promiseAtLeast(1, promises); } __exports__.all = all; __exports__.any = any; }); define("rsvp/async", ["exports"], function(__exports__) { "use strict"; var browserGlobal = (typeof window !== 'undefined') ? window : {}; var BrowserMutationObserver = browserGlobal.MutationObserver || browserGlobal.WebKitMutationObserver; var async; var local = (typeof global !== 'undefined') ? global : this; function checkNativePromise() { if (typeof Promise === "function" && typeof Promise.resolve === "function") { try { /* global Promise */ var promise = new Promise(function(){}); if ({}.toString.call(promise) === "[object Promise]") { return true; } } catch (e) {} } return false; } function useNativePromise() { var nativePromise = Promise.resolve(); return function(callback, arg) { nativePromise.then(function () { callback(arg); }); }; } // old node function useNextTick() { return function(callback, arg) { process.nextTick(function() { callback(arg); }); }; } // node >= 0.10.x function useSetImmediate() { return function(callback, arg) { /* global setImmediate */ setImmediate(function(){ callback(arg); }); }; } function useMutationObserver() { var queue = []; var observer = new BrowserMutationObserver(function() { var toProcess = queue.slice(); queue = []; toProcess.forEach(function(tuple) { var callback = tuple[0], arg= tuple[1]; callback(arg); }); }); var element = document.createElement('div'); observer.observe(element, { attributes: true }); // Chrome Memory Leak: https://bugs.webkit.org/show_bug.cgi?id=93661 window.addEventListener('unload', function(){ observer.disconnect(); observer = null; }, false); return function(callback, arg) { queue.push([callback, arg]); element.setAttribute('drainQueue', 'drainQueue'); }; } function useSetTimeout() { return function(callback, arg) { local.setTimeout(function() { callback(arg); }, 1); }; } if (checkNativePromise()) { async = useNativePromise(); } else if (typeof setImmediate === 'function') { async = useSetImmediate(); } else if (typeof process !== 'undefined' && {}.toString.call(process) === '[object process]') { async = useNextTick(); } else if (BrowserMutationObserver) { async = useMutationObserver(); } else { async = useSetTimeout(); } __exports__.async = async; }); define("rsvp/cancellation_error", ["exports"], function(__exports__) { "use strict"; // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error function CancellationError(message) { this.name = "cancel"; if ((message !== undefined) && (typeof message !== "string")) { throw new TypeError('You must pass a string.'); } this.message = message || "Default Message"; } CancellationError.prototype = new Error(); CancellationError.prototype.constructor = CancellationError; __exports__.CancellationError = CancellationError; }); define("rsvp/config", ["rsvp/async","exports"], function(__dependency1__, __exports__) { "use strict"; var async = __dependency1__.async; var config = {}; config.async = async; __exports__.config = config; }); define("rsvp/defer", ["rsvp/promise","exports"], function(__dependency1__, __exports__) { "use strict"; var Promise = __dependency1__.Promise; function defer() { var deferred = { // pre-allocate shape resolve: undefined, reject: undefined, promise: undefined }; deferred.promise = new Promise(function(resolve, reject) { deferred.resolve = resolve; deferred.reject = reject; }); return deferred; } __exports__.defer = defer; }); define("rsvp/events", ["exports"], function(__exports__) { "use strict"; var Event = function(type, options) { this.type = type; for (var option in options) { if (!options.hasOwnProperty(option)) { continue; } this[option] = options[option]; } }; var indexOf = function(callbacks, callback) { for (var i=0, l=callbacks.length; i<l; i++) { if (callbacks[i][0] === callback) { return i; } } return -1; }; var callbacksFor = function(object) { var callbacks = object._promiseCallbacks; if (!callbacks) { callbacks = object._promiseCallbacks = {}; } return callbacks; }; var EventTarget = { mixin: function(object) { object.on = this.on; object.off = this.off; object.trigger = this.trigger; return object; }, on: function(eventNames, callback, binding) { var allCallbacks = callbacksFor(this), callbacks, eventName; eventNames = eventNames.split(/\s+/); binding = binding || this; while (eventName = eventNames.shift()) { callbacks = allCallbacks[eventName]; if (!callbacks) { callbacks = allCallbacks[eventName] = []; } if (indexOf(callbacks, callback) === -1) { callbacks.push([callback, binding]); } } }, off: function(eventNames, callback) { var allCallbacks = callbacksFor(this), callbacks, eventName, index; eventNames = eventNames.split(/\s+/); while (eventName = eventNames.shift()) { if (!callback) { allCallbacks[eventName] = []; continue; } callbacks = allCallbacks[eventName]; index = indexOf(callbacks, callback); if (index !== -1) { callbacks.splice(index, 1); } } }, trigger: function(eventName, options) { var allCallbacks = callbacksFor(this), callbacks, callbackTuple, callback, binding, event; if (callbacks = allCallbacks[eventName]) { // Don't cache the callbacks.length since it may grow for (var i=0; i<callbacks.length; i++) { callbackTuple = callbacks[i]; callback = callbackTuple[0]; binding = callbackTuple[1]; if (typeof options !== 'object') { options = { detail: options }; } event = new Event(eventName, options); callback.call(binding, event); } } } }; __exports__.EventTarget = EventTarget; }); define("rsvp/hash", ["rsvp/defer","exports"], function(__dependency1__, __exports__) { "use strict"; var defer = __dependency1__.defer; function size(object) { var s = 0; for (var prop in object) { s++; } return s; } function hash(promises) { var results = {}, deferred = defer(), remaining = size(promises); if (remaining === 0) { deferred.resolve({}); } var resolver = function(prop) { return function(value) { resolveAll(prop, value); }; }; var resolveAll = function(prop, value) { results[prop] = value; if (--remaining === 0) { deferred.resolve(results); } }; var rejectAll = function(error) { deferred.reject(error); }; for (var prop in promises) { if (promises[prop] && typeof promises[prop].then === 'function') { promises[prop].then(resolver(prop), rejectAll); } else { resolveAll(prop, promises[prop]); } } return deferred.promise; } __exports__.hash = hash; }); define("rsvp/node", ["rsvp/promise","rsvp/all","exports"], function(__dependency1__, __dependency2__, __exports__) { "use strict"; var Promise = __dependency1__.Promise; var all = __dependency2__.all; function makeNodeCallbackFor(resolve, reject) { return function (error, value) { if (error) { reject(error); } else if (arguments.length > 2) { resolve(Array.prototype.slice.call(arguments, 1)); } else { resolve(value); } }; } function denodeify(nodeFunc) { return function() { var nodeArgs = Array.prototype.slice.call(arguments), resolve, reject; var thisArg = this; var promise = new Promise(function(nodeResolve, nodeReject) { resolve = nodeResolve; reject = nodeReject; }); all(nodeArgs).then(function(nodeArgs) { nodeArgs.push(makeNodeCallbackFor(resolve, reject)); try { nodeFunc.apply(thisArg, nodeArgs); } catch(e) { reject(e); } }); return promise; }; } __exports__.denodeify = denodeify; }); define("rsvp/promise", ["rsvp/config","rsvp/events","rsvp/cancellation_error","exports"], function(__dependency1__, __dependency2__, __dependency3__, __exports__) { "use strict"; var config = __dependency1__.config; var EventTarget = __dependency2__.EventTarget; var CancellationError = __dependency3__.CancellationError; function objectOrFunction(x) { return isFunction(x) || (typeof x === "object" && x !== null); } function isFunction(x){ return typeof x === "function"; } var Promise = function(resolver, canceller) { var promise = this, resolved = false; if (typeof resolver !== 'function') { throw new TypeError('You must pass a resolver function as the sole argument to the promise constructor'); } if ((canceller !== undefined) && (typeof canceller !== 'function')) { throw new TypeError('You can only pass a canceller function' + ' as the second argument to the promise constructor'); } if (!(promise instanceof Promise)) { return new Promise(resolver, canceller); } var resolvePromise = function(value) { if (resolved) { return; } resolved = true; resolve(promise, value); }; var rejectPromise = function(value) { if (resolved) { return; } resolved = true; reject(promise, value); }; this.on('promise:failed', function(event) { this.trigger('error', { detail: event.detail }); }, this); this.on('error', onerror); this.cancel = function () { // For now, simply reject the promise and does not propagate the cancel // to parent or children if (resolved) { return; } if (canceller !== undefined) { try { canceller(); } catch (e) { rejectPromise(e); return; } } // Trigger cancel? rejectPromise(new CancellationError()); }; try { resolver(resolvePromise, rejectPromise); } catch(e) { rejectPromise(e); } }; function onerror(event) { if (config.onerror) { config.onerror(event.detail); } } var invokeCallback = function(type, promise, callback, event) { var hasCallback = isFunction(callback), value, error, succeeded, failed; if (promise.isFulfilled) { return; } if (promise.isRejected) { return; } if (hasCallback) { try { value = callback(event.detail); succeeded = true; } catch(e) { failed = true; error = e; } } else { value = event.detail; succeeded = true; } if (handleThenable(promise, value)) { return; } else if (hasCallback && succeeded) { resolve(promise, value); } else if (failed) { reject(promise, error); } else if (type === 'resolve') { resolve(promise, value); } else if (type === 'reject') { reject(promise, value); } }; Promise.prototype = { constructor: Promise, isRejected: undefined, isFulfilled: undefined, rejectedReason: undefined, fulfillmentValue: undefined, then: function(done, fail) { this.off('error', onerror); var thenPromise = new this.constructor(function() {}, function () { thenPromise.trigger('promise:cancelled', {}); }); if (this.isFulfilled) { config.async(function(promise) { invokeCallback('resolve', thenPromise, done, { detail: promise.fulfillmentValue }); }, this); } if (this.isRejected) { config.async(function(promise) { invokeCallback('reject', thenPromise, fail, { detail: promise.rejectedReason }); }, this); } this.on('promise:resolved', function(event) { invokeCallback('resolve', thenPromise, done, event); }); this.on('promise:failed', function(event) { invokeCallback('reject', thenPromise, fail, event); }); return thenPromise; }, fail: function(fail) { return this.then(null, fail); }, always: function(fail) { return this.then(fail, fail); } }; EventTarget.mixin(Promise.prototype); function resolve(promise, value) { if (promise === value) { fulfill(promise, value); } else if (!handleThenable(promise, value)) { fulfill(promise, value); } } function handleThenable(promise, value) { var then = null, resolved; try { if (promise === value) { throw new TypeError("A promises callback cannot return that same promise."); } if (objectOrFunction(value)) { then = value.then; if (isFunction(then)) { promise.on('promise:cancelled', function(event) { if (isFunction(value.cancel)) { value.cancel(); } }); then.call(value, function(val) { if (resolved) { return true; } resolved = true; if (value !== val) { resolve(promise, val); } else { fulfill(promise, val); } }, function(val) { if (resolved) { return true; } resolved = true; reject(promise, val); }); return true; } } } catch (error) { reject(promise, error); return true; } return false; } function fulfill(promise, value) { config.async(function() { if (promise.isFulfilled) { return; } if (promise.isRejected) { return; } promise.trigger('promise:resolved', { detail: value }); promise.isFulfilled = true; promise.fulfillmentValue = value; }); } function reject(promise, value) { config.async(function() { if (promise.isFulfilled) { return; } if (promise.isRejected) { return; } promise.trigger('promise:failed', { detail: value }); promise.isRejected = true; promise.rejectedReason = value; }); } __exports__.Promise = Promise; }); define("rsvp/queue", ["rsvp/promise","rsvp/resolve","exports"], function(__dependency1__, __dependency2__, __exports__) { "use strict"; var Promise = __dependency1__.Promise; var resolve = __dependency2__.resolve; // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error function ResolvedQueueError(message) { this.name = "resolved"; if ((message !== undefined) && (typeof message !== "string")) { throw new TypeError('You must pass a string.'); } this.message = message || "Default Message"; } ResolvedQueueError.prototype = new Error(); ResolvedQueueError.prototype.constructor = ResolvedQueueError; var Queue = function() { var queue = this, promise_list = [], promise, fulfill, reject, resolved; if (!(this instanceof Queue)) { return new Queue(); } function canceller() { for (var i = 0; i < 2; i++) { promise_list[i].cancel(); } } promise = new Promise(function(done, fail) { fulfill = function (fulfillmentValue) { if (resolved) {return;} queue.isFulfilled = true; queue.fulfillmentValue = fulfillmentValue; resolved = true; return done(fulfillmentValue); }; reject = function (rejectedReason) { if (resolved) {return;} queue.isRejected = true; queue.rejectedReason = rejectedReason ; resolved = true; return fail(rejectedReason); }; }, canceller); promise_list.push(resolve()); promise_list.push(promise_list[0].then(function () { promise_list.splice(0, 2); if (promise_list.length === 0) { fulfill(); } })); queue.cancel = function () { if (resolved) {return;} resolved = true; promise.cancel(); promise.fail(function (rejectedReason) { queue.isRejected = true; queue.rejectedReason = rejectedReason; }); }; queue.then = function () { return promise.then.apply(promise, arguments); }; queue.push = function(done, fail) { var last_promise = promise_list[promise_list.length - 1], next_promise; if (resolved) { throw new ResolvedQueueError(); } next_promise = last_promise.then(done, fail); promise_list.push(next_promise); // Handle pop promise_list.push(next_promise.then(function (fulfillmentValue) { promise_list.splice(0, 2); if (promise_list.length === 0) { fulfill(fulfillmentValue); } else { return fulfillmentValue; } }, function (rejectedReason) { promise_list.splice(0, 2); if (promise_list.length === 0) { reject(rejectedReason); } else { throw rejectedReason; } })); return this; }; }; Queue.prototype = Object.create(Promise.prototype); Queue.prototype.constructor = Queue; __exports__.Queue = Queue; __exports__.ResolvedQueueError = ResolvedQueueError; }); define("rsvp/reject", ["rsvp/promise","exports"], function(__dependency1__, __exports__) { "use strict"; var Promise = __dependency1__.Promise; function reject(reason) { return new Promise(function (resolve, reject) { reject(reason); }); } __exports__.reject = reject; }); define("rsvp/resolve", ["rsvp/promise","exports"], function(__dependency1__, __exports__) { "use strict"; var Promise = __dependency1__.Promise; function resolve(thenable) { return new Promise(function(resolve, reject) { if (typeof thenable === "object" && thenable !== null) { var then = thenable.then; if ((then !== undefined) && (typeof then === "function")) { return then.apply(thenable, [resolve, reject]); } } return resolve(thenable); }, function () { if ((thenable !== undefined) && (thenable.cancel !== undefined)) { thenable.cancel(); } }); } __exports__.resolve = resolve; }); define("rsvp/rethrow", ["exports"], function(__exports__) { "use strict"; var local = (typeof global === "undefined") ? this : global; function rethrow(reason) { local.setTimeout(function() { throw reason; }); throw reason; } __exports__.rethrow = rethrow; }); define("rsvp/timeout", ["rsvp/promise","exports"], function(__dependency1__, __exports__) { "use strict"; var Promise = __dependency1__.Promise; function promiseSetTimeout(millisecond, should_reject, message) { var timeout_id; function resolver(resolve, reject) { timeout_id = setTimeout(function () { if (should_reject) { reject(message); } else { resolve(message); } }, millisecond); } function canceller() { clearTimeout(timeout_id); } return new Promise(resolver, canceller); } function delay(millisecond, message) { return promiseSetTimeout(millisecond, false, message); } function timeout(millisecond) { return promiseSetTimeout(millisecond, true, "Timed out after " + millisecond + " ms"); } Promise.prototype.delay = function(millisecond) { return this.then(function (fulfillmentValue) { return delay(millisecond, fulfillmentValue); }); }; __exports__.delay = delay; __exports__.timeout = timeout; }); define("rsvp", ["rsvp/events","rsvp/cancellation_error","rsvp/promise","rsvp/node","rsvp/all","rsvp/queue","rsvp/timeout","rsvp/hash","rsvp/rethrow","rsvp/defer","rsvp/config","rsvp/resolve","rsvp/reject","exports"], function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __exports__) { "use strict"; var EventTarget = __dependency1__.EventTarget; var CancellationError = __dependency2__.CancellationError; var Promise = __dependency3__.Promise; var denodeify = __dependency4__.denodeify; var all = __dependency5__.all; var any = __dependency5__.any; var Queue = __dependency6__.Queue; var ResolvedQueueError = __dependency6__.ResolvedQueueError; var delay = __dependency7__.delay; var timeout = __dependency7__.timeout; var hash = __dependency8__.hash; var rethrow = __dependency9__.rethrow; var defer = __dependency10__.defer; var config = __dependency11__.config; var resolve = __dependency12__.resolve; var reject = __dependency13__.reject; function configure(name, value) { config[name] = value; } __exports__.CancellationError = CancellationError; __exports__.Promise = Promise; __exports__.EventTarget = EventTarget; __exports__.all = all; __exports__.any = any; __exports__.Queue = Queue; __exports__.ResolvedQueueError = ResolvedQueueError; __exports__.delay = delay; __exports__.timeout = timeout; __exports__.hash = hash; __exports__.rethrow = rethrow; __exports__.defer = defer; __exports__.denodeify = denodeify; __exports__.configure = configure; __exports__.resolve = resolve; __exports__.reject = reject; }); window.RSVP = requireModule("rsvp"); })(window); </script> <script type="text/javascript"> /*jslint indent: 2, maxlen: 80, nomen: true */ /*global console, window, document, RSVP, XMLHttpRequest */ (function (document, RSVP, XMLHttpRequest) { "use strict"; var promise_list = []; function ajax(param) { var xhr = new XMLHttpRequest(); return new RSVP.Promise(function (resolve, reject, notify) { var k; xhr.open(param.type || "GET", param.url, true); xhr.responseType = param.dataType || ""; if (typeof param.headers === 'object' && param.headers !== null) { for (k in param.headers) { if (param.headers.hasOwnProperty(k)) { xhr.setRequestHeader(k, param.headers[k]); } } } xhr.addEventListener("load", function (e) { if (e.target.status >= 400) { return reject(e); } return resolve(e); }); xhr.addEventListener("error", reject); xhr.addEventListener("progress", notify); if (typeof param.xhrFields === 'object' && param.xhrFields !== null) { for (k in param.xhrFields) { if (param.xhrFields.hasOwnProperty(k)) { xhr[k] = param.xhrFields[k]; } } } if (typeof param.beforeSend === 'function') { param.beforeSend(xhr); } xhr.send(param.data); }, function () { xhr.abort(); }); } function testURL(url) { return RSVP.Queue() .push(function () { return ajax({ url: url }); }) .push(function (evt) { return evt.target.responseText; }, function () { return "FAIL"; }); } function launchTest(test_case) { var start = new Date().getTime(), url = test_case.testurl; return new RSVP.Queue() .push(function () { return RSVP.any([RSVP.delay(4000), testURL(url + "?nocache=" + start)]); }) .push(function (result) { var elapsed = new Date().getTime() - start; if (result === undefined) { return {url: test_case.redirect, time: 1000000001, name: test_case.name}; } if (result === "FAIL") { return {url: test_case.redirect, time: 1000000000, name: test_case.name}; } return {url: test_case.redirect, name: test_case.name, time: elapsed}; }); } function runOnce(test_queue) { return new RSVP.Queue() .push(function () { var u; for (u in test_url_list) { if (test_url_list.hasOwnProperty(u)) { test_queue.push(launchTest(test_url_list[u])); } } return RSVP.all(test_queue); }) .push(undefined, function (reason) { console.log(reason); return "OK"; }); } function renderPartialResult(result, main_div, winner_div) { var u, y, interaction, winner = 0, t_i, table_dict = {}, interaction_dict = {}, msg = ""; msg += "<table width=100%>"; for (u in result) { if (result.hasOwnProperty(u)) { interaction = parseInt(u / test_url_list.length, 10); if (!interaction_dict.hasOwnProperty(interaction)) { interaction_dict[interaction] = 1; } if (!table_dict.hasOwnProperty(result[u].name)) { table_dict[result[u].name] = { total: 0, name: result[u].name, url: result[u].url }; } if (result[u].time === 1000000000) { table_dict[result[u].name][interaction] = "FAIL"; table_dict[result[u].name].total = "REJECT"; } else if (result[u].time === 1000000001) { table_dict[result[u].name][interaction] = "TIMEOUT"; table_dict[result[u].name].total = "REJECT"; } else { table_dict[result[u].name][interaction] = result[u].time; if (table_dict[result[u].name].total !== "REJECT") { table_dict[result[u].name].total += result[u].time; } } } } msg += "</tr> <th> </th>"; t_i = 0; for (u in interaction_dict) { if (interaction_dict.hasOwnProperty(u)) { msg += '<th> Test ' + u + "</th>"; t_i += 1; } } msg += "<th class='avg'> AVERAGE </th></tr>"; for (u in table_dict) { if (table_dict.hasOwnProperty(u)) { if (winner === 0) { winner = table_dict[u]; } if (table_dict[u].total !== "REJECT") { table_dict[u].average = table_dict[u].total / t_i; if (winner.average === "REJECT") { winner = table_dict[u]; } if (winner.average > table_dict[u].average) { winner = table_dict[u]; } } else { table_dict[u].average = "REJECT"; } } } for (u in table_dict) { if (table_dict.hasOwnProperty(u)) { if (u === winner.name) { msg += "<tr class='winner'>"; } else { msg += "<tr>"; } msg += "<td>"; if (table_dict[u].url) { msg += '<a href="' + table_dict[u].url + '">' + u + '</a>'; } else { msg += u; } msg += "</td>"; for (y in interaction_dict) { if (interaction_dict.hasOwnProperty(y)) { msg += "<td>" + table_dict[u][y] + "</td>"; } } msg += "<td>" + table_dict[u].average + "</td>"; msg += "</tr>"; } } msg += "</table>"; msg = "<h2> The best frontend for you is ... <strong>" + winner.name + " </strong> </h2>" + msg; main_div.innerHTML = msg; msg = ""; msg += "<p><a class=btn href=" + winner.url + "> Click to Connect via "; msg += winner.name + "</a> </p>"; winner_div.innerHTML = msg; return winner; } function runAll() { return runOnce(promise_list) .push(function () { return runOnce(promise_list) .push(function () { return runOnce(promise_list) .push(function () { return runOnce(promise_list) .push(function () { return runOnce(promise_list) .push(function (result) { var winner, div = document.getElementsByClassName("table"), winner_div = document.getElementsByClassName("link"); winner = renderPartialResult(result, div[0], winner_div[0]); return winner; }); }); }); }); }); } runAll(); }(document, RSVP, XMLHttpRequest)); </script> <style type="text/css"> /* === animation === */ @-ms-keyframes spin { from { -ms-transform: rotate(0deg); } to { -ms-transform: rotate(360deg); } } @-moz-keyframes spin { from { -moz-transform: rotate(0deg); } to { -moz-transform: rotate(360deg); } } @-webkit-keyframes spin { from { -webkit-transform: rotate(0deg); } to { -webkit-transform: rotate(360deg); } } @keyframes spin { from { transform:rotate(0deg); } to { transform:rotate(360deg); } } /* === font (embedded icons (hehe) and text === */ @charset "UTF-8"; body { font-family: Arial; } @font-face { font-family: "untitled-font-1"; src: url('untitled-font-1.eot') format('embedded-opentype'); /* src:url("fonts/untitled-font-1.eot"); src:url("fonts/untitled-font-1.eot?#iefix") format("embedded-opentype"), url("fonts/untitled-font-1.woff") format("woff"), url("fonts/untitled-font-1.ttf") format("truetype"), url("fonts/untitled-font-1.svg#untitled-font-1") format("svg"); */ font-weight: normal; font-style: normal; } @font-face { font-family: 'untitled-font-1'; src: url(data:application/x-font-woff;charset=utf-8;base64,d09GRgABAAAAAAYUAA0AAAAACQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABGRlRNAAAF+AAAABoAAAAccMNEjEdERUYAAAXYAAAAHwAAACAANAAGT1MvMgAAAaAAAABDAAAAVk/WXJhjbWFwAAAB/AAAAEwAAAFSBH8EQWdhc3AAAAXQAAAACAAAAAj//wADZ2x5ZgAAAlgAAAJVAAADWMuB/dpoZWFkAAABMAAAAC8AAAA2BZDizGhoZWEAAAFgAAAAHQAAACQD+AIFaG10eAAAAeQAAAAVAAAAFgZcADJsb2NhAAACSAAAABAAAAAQAcYCqG1heHAAAAGAAAAAHgAAACAAUQBubmFtZQAABLAAAADjAAAB5t04W7Zwb3N0AAAFlAAAADkAAABPoMpE/3jaY2BkYGAA4nxBDvl4fpuvDNxMDCBwyenCPTgtxKDKeJvxHZDLwQCWBgAAQAnmAHjaY2BkYGB8x8DAoMfEAAKMtxkYGVABCwAysQICAAAAeNpjYGRgYGBnyGbgYAABJiBmZACJOYD5DAAOIQDAAAB42mNgZGJgnMDAysDB6MOYxsDA4A6lvzJIMrQwMDAxsHIywAAjAxIISHNNYXBgSGRIZXzw/wGDHuO7/7dhagCNTgwRAHjaY2KAACYIVmAwZxBiUAUAAsAAlQAAAHjaY2BgYGaAYBkGRgYQ8AHyGMF8FgYDIM0BhExgmWSG1P//waxECOv/ov8LobrAgJGNAc5lBOlhYkAFjAyUA2YWVgY2hkELAMs0CcIAAAAAAAAAAACYAPwBLgGseNp9UkFrE0EUfm9mMrMzuzOz3d1sFqTtZmM2pbYV0iRbKGoUL730IEiF5Bd48ehPEAQPIt4F67HiTQ/+gTY/wEMvBb0J/gAPwdnEUnvxDXzzvp157Pu+eeBBDl38hr/AhwxKGMADOIQpPAUYJYJ3inIw2u230kXeW5LyklQ1Y9fY9bPRP2Xpf+59DIyNsiyy5oWvbKj81Br/vTZRbLQ2cWSwUlIb6cJo+cOGcRJaGyZx+Ca0rcyGeSv96gkdCM8TgRYDLqQSnAslxesiCLIiCx7mSil/LfU/ldoYXcPbNJDSz3wp55vWGFvD5k7oYif/nnouaniecCF4DQBAoHJ+neI5DOE+QNfJuIVOx9AJuVpO0hpprWF/VN0lC5perZ6rWVSM+imeNpPO707SREIYpcqTytoVoognmL9xc8NnwnNsxVolPUUpIwQnefGkyMfT8bOiGcfNIpGJn0oVGal4gyNvEBEEgixSrqSJlEz9RP7cKvK82Noej50MQIicjpnTsQpQcdfOilOwjmlruNwTi+7rHeRinVPGKJ9RpFSccX4mKCVkg1Mi8FiQ+oTOPCSNGTd81iDozRip/9GALhzgOX4GDTfgNuzD46Vjf/2qXbnOhoNe2WkXgq9i0kp32/1q1G33yl7pPBZcNJr11LSLuq/BPXRG76Mrc93i4fKFaji4SnNK2PyYkdo4nDqH5+/w0TY6ORdOE+KRG7H5cWQ02+OBDi9CHfA99sGTy9HhXIrLMXJYTZgTTtlye/WSuNdg5Mskrucpnkh9YqVS0p5o+AMxl2fXAAAAeNqVj0+KwjAUh79oLQwKbgaXkgNMSlJx42JwMx5BPIBVCtJCrVdx64U8ikdwMS+d52LciIG8fPnl9/4EGHHGEJdhjFXukfKt3OeLi3IinpvygKH5VE4Zm6U4TfIhyrTLityT+l65z4Yf5UQ8V+UBE+7KKVNjOVHRUso+ULDFsaPuNEeAU9WW7aHYul1dtU6Ef68PcaViPBv2UsiSk8k4lgWvmvx5ArPu5iXmEgNzKSwNVnWzL2yeebuwT+OIEmYueJf7IO53/7IWV8NRMqIrjhBHZl00x7KubMj82zV/ARVDTeoAeNpjYGJABowM6IAdLMrEyMTIzMjCyMpeXJCZl5daxFJanFrEnpZfVJ5YlMKZASRSijLLUgG4GQunAAAAAAAAAf//AAJ42mNgZGBg4ANiCQYQYGJgZGBmYAOSLGAeAwAEpgA7AHjaY2BgYGQAgjO2i86D6EtOF+7BaABQ9wgAAAA=) format('woff'), url('untitled-font-1.ttf') format('truetype'), url('untitled-font-1.svg#untitled-font-1') format('svg'); font-weight: normal; font-style: normal; } /* === set font on classes === */ [class^="custom-icon-"]:before, [class*=" custom-icon-"]:before { font-family: "untitled-font-1" !important; font-style: normal !important; font-weight: normal !important; font-variant: normal !important; text-transform: none !important; speak: none; line-height: 1; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } .custom-icon-spinner:before { content: "a"; } .custom-icon-user:before { content: "b"; } .custom-icon-forward:before { content: "c"; } .custom-icon-harddrive:before { content: "e"; } /* === logo === */ .custom-grandenet-logo { background: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIj8+Cjxzdmcgd2lkdGg9IjIwMCIgaGVpZ2h0PSIxMjAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPgogPCEtLSBDcmVhdGVkIHdpdGggTWV0aG9kIERyYXcgLSBodHRwOi8vZ2l0aHViLmNvbS9kdW9waXhlbC9NZXRob2QtRHJhdy8gLS0+CiA8Zz4KICA8dGl0bGU+YmFja2dyb3VuZDwvdGl0bGU+CiAgPHJlY3QgZmlsbD0iI2ZmZiIgaWQ9ImNhbnZhc19iYWNrZ3JvdW5kIiBoZWlnaHQ9IjEyMiIgd2lkdGg9IjIwMiIgeT0iLTEiIHg9Ii0xIi8+CiAgPGcgZGlzcGxheT0ibm9uZSIgb3ZlcmZsb3c9InZpc2libGUiIHk9IjAiIHg9IjAiIGhlaWdodD0iMTAwJSIgd2lkdGg9IjEwMCUiIGlkPSJjYW52YXNHcmlkIj4KICAgPHJlY3QgZmlsbD0idXJsKCNncmlkcGF0dGVybikiIHN0cm9rZS13aWR0aD0iMCIgeT0iMCIgeD0iMCIgaGVpZ2h0PSIxMDAlIiB3aWR0aD0iMTAwJSIvPgogIDwvZz4KIDwvZz4KIDxnPgogIDx0aXRsZT5MYXllciAxPC90aXRsZT4KICA8aW1hZ2Ugc3Ryb2tlPSJudWxsIiB4bGluazpocmVmPSJkYXRhOmltYWdlL3BuZztiYXNlNjQsaVZCT1J3MEtHZ29BQUFBTlNVaEVVZ0FBQVZZQUFBQ2lDQVlBQUFBYTIrVTRBQUFnQUVsRVFWUjQydTFkZVh3VDFkcHV5NjZBaUx0eTNSVVZSVkhjRU53RkJaZUw2M1c3S29vYlh1VzY0NEtDY04wdXFCOTgrb0c0bzRoUWxySVZzS1cwZElHV1V1amVVa3JUZEV2VHBFM1ROa21UenBkbjhNUnBtSm5NVENadEd0OC9uaDgwbVp3NTYzUGU4MjRuaXVPNEtBS0JRQ0RvQitvRUFvRkFJR0lsRUFnRUl0WWVCYWU3SStyWC9jMFh2SnBobm5iemhxcmtzWEhHdk9kM21ONWVWTkEweHVKd1IxTWZFUWdFSWxZVktMUTYrOSsxcFdibCtTc01uQmhBc3I5WHRaNUlmVVVnRUloWUZTREw1Qmc4Y3FYQkxrV3FRdnhVYWh0SmZVWWdFSWhZWldCdjkwU04zMWlWcUlSVWdVdGlLeTM3bTF4OXFlOElCQUlScXdUbTdiUGVxcFJVR2Y2WlZQYzU5UjJCUUNCaWxjRGtMVFhMMVJMcmhTc05qaGF2cEV2OVJ5QVFpRmo5QUhJY3NjTGdVa3Vzd0U1VDJ4Q2FSQVFDZ1lqVkR3ZHNyajVhU0JWWWU5QitCazBpQW9GQXhPb0hkMGRIMU9qVmxVWXR4RnBLQml3Q2dVREVLbzRudDlkOXFKWlVMMTlkYWZCNFNabjZqMEFnRUxHS1lKT2haWmhhWXYxNHIvVjI2anNDZ1VERUtvTlhNc3d2S0NYVjIrT3I0eHh1a2xZSkJBSVJxeXlzVG5mMEF3bTFTd0tSNm8wYnFsSVIra3A5UmlBUWlGZ1ZvTjNURWJXNHNPbXFrYkVHbXhpcHZyWExQS1haUmI2ckJBS0JpRlUxR3AyZTZKU2ExbU1XNWpkZUIxM3E1c3FXayt0YTNUSFVOd1FDZ1lpVlFDQVFpRmdKQkFLQmlKVkFJQkFJUkt3RUFvRkF4RW9nRUFoRXJBUUNnVURFU2lBUUNBUWlWZ0tCUUNCaTFST3RGYjI0L2YrOWpDdDQvVGF1Yk42bFhGMzhNVnhIRDR1SVFtWXM4L2FqdUxMUFJuRUZiMDdnU3VhTzRld2xmV2hTRWdoRXJGMExWMk1VdDNQU1RHNmQ5MDkvSkkxWXpkV3M2UmxYVTF2U0IzSTd4bndsMm83VWNRdTR0bXFLOGlJUWlGaTdRa28xeG5CSkY2MFVKU09HOWIwY3ZQUWF6dTFvM0RPQTJ6VElLTnVPMzA5TjVXeDUvV2lDRWdoRXJLRkY1ajJ2eUpJUnc2YkJCcTdsWUsrd2JJUFRFczF0T1NsYlVUdVNMb3psT3R3MFNRa0VJdFlRQWRLYkVqSmlLSjQ5TGl6YlVmSE5PYXJhVWZrajNhbEZJQkN4aGdqN1B4MnRpcEFTaDI4TXkzWmtUSmlqcWgxWjk3NU1rNVJBSUdJTkRmSmZuYVNLa0RiMGF3ekxkZ1RTRWZzajQ3WlpORWtKQkNMVzBDRDNYL2VvSXFUNG9hVmgyWTcwbXo5UzFZNmR0NzlMazVSQUlHSU5EZW8ySGF1S2tKSkhmeDhSRzBURjE4TnBraElJUkt5aGdjY1Z4VzArdGxBeElZV3JQeXNDQU5aRnV4V3JNK0JGUUpPVVFDQmlEWjNVR244TTc2Y2FpSkRTYi9xRWoyb0sxM2JrUFBXb0ltSTFmSGMyVFZBQ2dZaTFDOXlWbHB3clM2NTdIcC9DdVIxaEhzcnFpZUpEY2VWSXRYREdlSnFjQkVLRUV1ditKbGZmZDdNYUhuMWtXOTJDT3pmWHhONjFwV2JsL0Z6citIeUxjMEJIZDBtRnpVVjllRGVralFPcitXUDFodjRXYnZjREwzSzE2NDdYVTFKdGRScDdsOVIrZnRmdTh1Y1c3Q3A3YkZsQjFRZFBtV3hKSituV2p2ckVJZHlleDU3eVJXRnRQTEtXeXhnL2w3UHVPcUtyK3hSamlUSEYyR0tNQVl3NXhyN01Pd2Rvb1JBSU9oQ3IzZVdKZWptOS9zVUxWaGpjWXRkQUF5K2sxci9SMnQ3TmlVOUFwSjUyM2N1dHNXNDhjM3ZSemRXSkJXTTRmK1JXdmpPOTNXM1hzUTN1cU81TUlJTXhuSlphUDBOcW5ERUhYc2t3djJCdnAydS9DUVROeE9yeWRFUTluV3lhTGJYUWhQaEhRdTFpaThNZFVRWVdhOHVlb3hJTHhyckVTSldodUdiZWZaSFExZ2J2MkQyUVVMdEV5VmcvbldLYTFlN3BvRVZESUdnaDF0blpsdnVWTERTR3QzYVpwMFJTaDZUdmYyQ3pIS2t5TkxlVjlPL3BiWDF6bDNtcW1ySCtJTnR5SHkwYUFrRWxzVFk1UGRFalZ4cnNhaGJiaFNzTmprcDdlKzlJNkF4bmUwT01FbElGS3N3L2orN0piVFUwdC9mRzJLa1o2NUd4QnB2TlJTb0JBa0VWc2E0OWFEOUR6VUpqbUwvUE9pRXkxQUE1ZzVVU2E3NXgxak05dWEzejlsbHYxVExXY1JYMjAybmhFQWdxaVBXTm5lYW50U3cySENram9UTWNMcE5paWZWZy9ROWplbkpiWDk5cGZrYkxXTS9ZWlg2S0ZnNkJvSUpZNFY2alpiRTl2OFAwZGlSMEJ0eU9kcFRjbWFXRVdHSGs2c2x0ZlRiRk5GUExXTCtYMWZBd0xSd0NRUVd4ZnJyWE9sSExZbnR0cC9tNVNPbVF1cWJmaHdVaTFiMkdWMmQyZFBSc0MvbHJHZWJudFl3MVZBaTBjQWdFRmNTNnZzSitxcGJGdHRYWWNsSWtkUW9DQTZSSU5XUC93MnZiWERXOWVub2JOMWUybkt4bHJEY1lXazZsaFVNZ3FDQlcrQ21PMzFpVnFHYWhYYmFxc3JiTkhYbVdZbk56eGpGN0tsNzZhSHZSemNadEJlTmFNdzlNK2Y1Zy9ROVhlenBjRWRFK0JBWmN1cXJTcEdhc0oyeXEza3ErckFTQ0JqL1dOUWZ0WjZwWmJLdks3UkdkTEtTand4M2w5amdpc20yeEI1clBVZVVSY05CT1Y4VVFDRnBEV24vWmJ4c3hZb1hCRldpaC9XOSs0N1hVaVQwYkMvTWJydzgwenBnTHYrNXZ2b0Q2aTBBSU1nbExZbFhyQ1VpOElyYlE3dGhjdlJyNjJKNXV3Q0VjOG9SWVYyRS83ZmJOMVd2RnhocHpZRnQxNi9IVVZ3U0NEc1RLZ094R1M0cWFydmkvZ3FacklNa20xN1FlNnlGQ2pUaGdUREcyR0dPTU5jYWNNbHNSQ0NFaVZnS0JRQ0FRc1JJSUJBSVJxMXlJS2VMM3pjMXB4N1c3bTRNdjA1YlhqNnZiY0J4bnpUeEM5K3RiMnFwaXVQcUVvL2tyWk5xYmRTbXpvOE1UMWRpU083Q2hlZWRRVzF2SmdJNE9Tb0JDSUJDeGFnUWM4QXVxUHBpNnJXQ2Nnem5tSnhWZTM1aG5mRythcTcxUmZmNVgzRHF3L1pKbG5hNC93ZCtXblVjR1hWK1BNNHJiOSt5RDNQbys5azRYQWVMNmxTQ0kwR2haZlg1YTZkMDdoTUVKTzhzZVhhbnJMUVlFQXVHdlFhek9kbXQwV3VtOWlWS1JUK21sOTI5dGNWYjJVVTZxeFgyNCtDSGxvbmRMNGVaWGU1bjJsSWVRZW5IUGx0VGRWZmt2MzZGRlNrVWliYm1RMnRyR0xSVDlSQ0FRc1NwSFRzWExzd0xGNnUrcGVPbER4V1ZtUC9xMDdNVjkrRjVyZmFGU2tDc2JVbXlyTVVaTm1aQklBN1VmMG51TG82SVBUV0FDZ1lnMWNKaWxzN3EzMHJSOVRhMEZ5aTdkMjN4OG5pejViUnBzMEt4dkxYcjN4b0RYV0J0L1VTVmRaaDZZOHFPUzlwZWJ2aDFIRTVoQUlHSU5pTXFHRlNPVkVtdTFkYjJ5VUZyYzRpcEhmQnVQTUdtdU02NnBEa1NzQnhlZHAwWU5rRmh3alZ0Sis3UEtuL21LSmpDQlFNU3F3R0N6YW9SU1lzV3ppc3BOSGJ0UWx2aGd4TkphNThvZnpneElySTI3QnlndEQ1NFBTdHVmZFdEcUVwckFCQUlSYTBEVTIzWWNyN3Nxb09LYmMyU0pEK1FZakVmQTFyK2xTNVAyeGN2VnFCa1FYcHErL3grYmxMUi9yK0cxZC84cWs3VEszdDRMYVE2WGx6V2Z0N2l3NmFwRmhVMVhJMExzOTZyV0V3ODJ1L3E0S1JKUTFSeERmb2cvY0IzMXlWK0FXRDBkN1ZIcHBmY2xCQ0tWMUpMSnFZcnpGT0E1dUQ2SkVWL0JheE9EOW1lMUZmVGxFczVNUEt6c2hMTVMxQnF1QU9oT2xSQnJnejN6NkVpZW1Ma056aVBtNTFySDM3V2xabVdnSkRGWHJUV1d2cHBobm9iOEZRNDNrV3lnMEdYV2J4ZXNNTGk3Z2N4OXFHMXRqNG5VelNEc0ttU3liVDlKNkwvcUQrUkd0ZGl6MUpOS1UwNS9MbS82WFZ6Mnc4L3hibEFOS1lPbG5qVzN1YU5YSG1nK0Y0TzR5ZEF5ekJsb3NicXMwZHlCQlJkeE95ZSt4M3NaUUVwMmEwczE2UGEwd1lEMXZSeXA1aGxudmhDcENYQk1iZTRZM0VpaEpRazNjUFZhWXpIZGNoQmV4Q3A4cDVhNzhzSmdNN2l1eHhNcjBHRGZOVFM1YUVLWlA2RWtGOTlhV3R1NCtiUlF2bnVYcWUwb1NFRCsyYnl3NExzdTRxdytCc1lwTVZJdHJwbDNMM0xFUnVLaTMxM3ZHQVJpOUYrQTE2MnJ5c0pGbHgvbldPLzRQTGZ4NW85eUxIZStrbUYrWWZMV21tVmk2UzI3YXZFUnNRWkhySGgvdnNVNUlOenJyT1dkWVRzQmtGemFaRXMrc2FUMml6dExheGRPZ3NkQXU5c2UydUFFVDBmVWpSdXFVc1VtQVk2YVhhMExnMlMrdis2ckNTVTFuMDgybUg4ZEJYZTBTRDc2NHpZSzF0OGpWeHJzLzA2dmZ3a1p0K1IwcU0wdVR4Uk9GVk9UVFhPSVdIc0dzVDZXVkRlZi9mL3hwTHA1Z1U1ZlJLdzlITVdOem41eWVqektQeHVpRUdhM0orcTJUZFdiV0Y5ZnU4Nll2YS9CY1lUYWN2SXN6aU1lMlZhM2dJZzF2RWtLNHlSY1c4ajlUTVFhd2RocmRod3BSYXlqVmxXYUtROXRhSURqUGV2bnkxZFhHZzdZWEgyQ2tmUmh4QW9GK2U5dGNCeUo2Mm0rTFdvYWpkc3p2aWxxdWp5MjNINDJOb0ZnUFJQc1hza2JsM0orVzl4MDJkZUZUVmZDQzhLcDBSRFgwdTZKU3ZDUzFmZkZ0bEhJcll2Ykg3THJIWU53WDVsV3drQy9acGtjZzVmdGIrYno5ZjVjYXJzUXFoc2x3b2JZTzZIYVlaOU5qSy9lNkpLNVN5MWM2a3pFcW5WeXkxeXc5OCtrdXMrcGowS2c4dkZPNExGeHhqeld6N2lIcTZ1TkVVMU9UelRVQ1NDMEwvTWJ4LzFXMWp4Y3VNRHUvNzMydXd0WEdoeHlSalBvZ1VGZ2NwdXZXQjFNcmU2WTkzWTNQSFJ4cktIUnY4d3hhNDJGZUU0cGFhTWQwRU5EQ0JDckkvcjVpN3pHbTlRUUJ0WUUyZ1U3ZzFpWjBIUGozcnQybGNSWTNkTGU2NUxZU2d2N0hPNXplcEZjTUhWbVk3UWdyL0VHNFcvRXZCcmtqRnEwdVAyQUFmRWZDSkN0RWlVN1FUMHlUVzFIc1g0ZXZiclNpTnRqdStwb1ozVzZvLyt6eHpKNVpLekJKbVg4a2pLOFNHSE9Ic3M5U3V1d3hkaHk4aFZyS2lzQ2xwbHR1VGRRK3d6TjdiMXYzVlM5V1UxZEE1RlVwVjE1bVMrbjE3OG9SYTVTeENnOHFXQVRzYms4UVJOcnNIVldNOTV5ZGFIRkxZTDB1cmFqWit3eVAvWEU5cnBQUHNpMjNGZmhuYlRVTDZFQmlJMU4xTGQybWFkMGxjNE1oQTRwTTlDQ0VmNE9WOFAvSzdYK2RYZ2xRUExEdjgra21ON3psemJUdlBOSGpYVWN1SHRyemMrenN5MzN6OTlubllBRkx6VGtBZEQveXhud0pteXNUdkNYZHQvTmFuajBzMXpyTFpCaVgweXJmM1ZjbkhHZlVtS0E5SHZUaHFvZG5hNC85NzRESkk4eWNaU0gya2I0UFZRamFvZ1I2Zy9oYVFWdEQ0Wlk5YWd6RVNzaElqQjVTODF5TmxGVGE5dUdkcFZsbXJscFlYSEFTajEzaitWdUhQLzhqM2c0R3E0NDBEeGN6cGtka1dHVDRxdlhzN0xoQ3FhVVdKOU9OczB1c0I1K0drS1pRdUtIamxEcS9lOWxOVHdzUEYxQm5TSVdLSUgzUTJoUVFnelk1SVRHeEIyMWJjZjQ2eVp4dW9EUE1Ic09td0YwMFdxSThkZXk1dlBaZDlpZzBHNnR4S3BIbmNOUEZlQTBSM01WUzg3bGNxZmR4MlhjTm92TGUya3lIeTdxYmlFQzZVNWdZcG0yRHVXS1oxM0xaVTUrbmN0KzZIbHUvNmVqdWFaOS9jS2hma0x5Q0tXdnNCaXBnUUNOZG4xT0l5azFyY2V3Y2lFMUthbkQ2bkw3V1hLR2xCOUxiSmV3Wng5TXJGMGs5Z3gwbFhCTlk4L0JQUzFZb3d3a1NhYi94TCtsamE1K2NucGpuT3hZbWVnSE5lL0VVVng0US9CckdlYm53NzNPWFdlOHdzTGRlbktXYU5obzRqbWJPVXY2UUNLNWJvRFRFczN0ZnVCRjhWeXh2Ung4MmtPUHExdmoxb1g2VGFlblExTm9wQkpKd3AvVU5ocGEvcVpuVzZBZkZIcVE2R0dFS2JBNEIvamMvZFlZeThTZWdjR05QZk5Vc21tdUh0WnVlRld3WjJCWUMxVG1tb1AyTTluelVPMm9mZWQyNzJZZ0hCdDRYNFI3blVOUHJOV3JUZ3FZNFdsZGpJc3pieHRDWk5lRndFbGgyL2x4QWNjbTgrNVh1VzV5SXdOUll0S3lDUnpJY0tWVS95VzJFUFQwaGNReGUzK1RxMjlHWGR1UURZYVdVK0hPczZpZ2FVeWc4dFhXd2VKd1I3UG40WlVnOXN5VDIrcytaTS9BblVnUFluMGh0ZjROOWt5QkFxTnRYYXM3UmhpbHFQYWRtQWZDZHNBWFdTakpoMk9kUTB1c1NESVNQN1EwTUxIK2taUkVUN1VBcmx6WjkvejkzSTVydnVSVkR5VnpydWt4YW9lR0hZTzRuQ21QY3lsWEx1R0pyZnpMRVp6ZVlhcTRoMHZKdUFCVnk0ZDFWMThJcmVJNDFvWXJzY0lQRkVZUTZGSUR1VjdwUmF6d1l3MzAvQTNycTNheVo1UVlXWlhVQWZwSjlneU1Qb0ZPQ0VMclBnSnB0THl6eU9yc0w5eGs0ZE1iN25VT0hiRWltWW5TeFFzZ09Za2VDeEpFSUpiQU91SHNyVnhMZVhoYjhMRUJySXQySDFaMzVJMXQxeWxrdDlYUVM5VzRKRjIwc3J2NjQvNkUybS9ZQk41VTJUSk1xeXBBYUd6UWsxamhaL3JjRHRPN2VyZ3hxYTJEa3VlRlBxdEtNbnNwS1ZQb1g2b1dGNjAwdEdwdDl6dVpEWS81clBtYnFyY3kxVkE0MXprMHhKcDIvWHhWQ3hqWnBZSmRqQzBIZTNFYkIxWkx2aVB0aG5sY3VGNFRiVTQ2U3JaL2NsKzRWNWYzMUt3NVVkVzRyTy9keXVlVzdZWStlU3V6NFFrMmdaOU5NYzBNVlFpaWxvWFM2UFJFQ3cwclF1djE3ZkhWY1RDQXdBQTJhN2ZsQWFHbHVhdUlGUnVOTUFtTlc0ZUlJcFFKb3RGS1VzSDBQVFl4b1p2WlR5VzJpOE85enFFaDFzM0g1YXRhd0JtM3pnNTZNWmIrNStxQTc0R2FJQnlKRlJaNXVYcERDdmUwNnlBVnp4MmphbHo0UGl2czJ4MTlndVRWUWoxaXZVYlBnRkFRSy93cS9kUGM3VEU3Qm9vNXdpc3BQeFFTNjVWcktzdlpNMWFITzFxUE1vVytwZkRYVldnd1ZHUTRETlJ1aEFvTGoralkzTUs5enZvVDYvWlJQNnRhdkRsUFBScHljZ0txWTA4T1MySk5HdmxiWUlJckNuNVRVSEpsakQ5Y1RkMlRJdEpMQmtMUEFJU1VoZ3V4M3JtNUpwYjlaa2xSMHhYQkVsWW9pQlhobVhKdVExcktmSFJiM1Jmc21ab0FlbSs5RTVvZ3o0SFFCZS9qdmRiYnU3dk9nTm9FVE1FdGpKd25IMU8xZUdHa0NYWXhLdEhyTnFRT0NrdGl6UmcvTnpEQk5RYi9ucWJjZnFyR0JTNXgzZGd2UWdkM1NLM3BFcEZMWFVtc1dFaENJeFVrcDNBazF2L3VzOTdHbm9GQlJvOHloVTc3U2p3TjlFNW9namgrWC9wSTc2YUw2M2U2czg2OEs2QzdLNG5Wa25Fazd3K3BaUEhHRHlubjJxcUNkd0N2WFgrYy9IdUdsc29aZ2VDL2lLUWFPRUxoWDBUVkJKTU9FTGNOSUJRUmVWeHhkSUdEcytSeHR2U2pLMlhybm56Wmovb0VCWGlpdUxUclBsZE1yRkFkZENPeGdyU0VWbDFFRHlHTFZIY1RxOUF3QlAyZlV0ZW9yaVJXdUh5eForQWhFTWhsVFppeVQ2cE1qQWM3UlNEeGVLV0tJQXF4QUFXMTdZYXVXQ2lKVDArcmY3bXI2d3dJRXpLVk5ybjZkaDJ4cXRIblZTNDlYYmRJb3F6N3BrdSt4N2hNTW1VY01oaUpLYSsxWHVXQmFJKy9iNm41emI4OHhDYzNpeVdVZ0lGSVNoMEFBNUtLRzEwVmVRYkVIMTBXY0Z6ZzhxV0hYbGVIeUNWL055WkVHMEg2YUpEUkhZSUFrWUFFS2ZMMFZnVUlFekxEWWkyVzJnN2pqRFNDd2xzbnVwSllZVGxIOEFCN0RoNE1Za2RodUxMQlhVell4M0oxUUw0QzloeHlES3lyc0o4bWxXUUYzZ2h3ajNvaXFlNVR2Zm8rVFJCNnF6UStYODg2QS85SXFGMHN6R01oRk1Edy8rM1ZyY2VGamxnaEhaVitlQlZQREtJR21YNk5mQWlsbms3b3VFK3E4SzFidUExOWJiNzNiRDBsazZ0Wks1c3dWeXFOR0N5S1VwbDE1QUNwU3NyUytGVkI0MWpKYUNqY2k0V2dDYUc3a3pYekNOMEpxM0hQQU5rZ0FVaTFJT0F3VVpYQTNVck1iUVprTUdWNzNVY3pzeG9lZ1VFSngxK29EK0JVTHBSMDlTWlcxTWMvTlNDUzgyQWpCa2toMGttc3ZsMUpyR0laMlRDZmtYUUY5Y1JwNnFIRTJxK0VQcUpLeXNSbTVwL1FCSWxkcHFYV3owRHlHVnowaVBHQVo0U3dEL1Mwc01OTHBMdnFET0EyWUdGWk9PR2luRS8yV2lmZHM3Vm1hZGNrWVFFeDdKMzZDSmR5K1hmOGNUemxpbTk0WXhWdU1RM1ZZa1E0Sm1MZVd5dDZCU0p1N0Z4aWs4c1hSbWZ1SEVhbkJKL3V0VTZVS2c5WmtBSkdSalZtRCtBY3RhRzlTd3Z2S2ZsZ0xIL1JJY0tPRTg1STRqTC8vZ1pYc1hoNE9McWxJY1piR0lXakZ2Q0xoWTVPajhXTk9TTzg4a1VLSVA1QWZyU2hKRlk4SjNSYms2c25rcm1vU2NFSEFsSFQvM0QvMG90WUVkM21mNHJwcWpvektWOHVyU05sdC9wRGI0UGRTNnBqdGJqNUlKUlJxdE9Sc28xQ2E3V0h1aUxUMWZUMCt1bFNZeWFjM01pUUJiZVpFcG5FRzFvWE40Nk1pQ1gzVCtQSHlvRlVoZXhVM1dXOEVzNXZuS0RnWHl2V1R5eUxsdG82b1AwSTI1MjJ3L1NXTU5tTFAzQUxBTnljeEhTYndiZ3V3VWRZN1VXUmV0U1pBUUtYMER2RS8xWVJTaHZvbDFoWENPUnAxRkllL0FiRnNyVmpNTFZJd0FSeGtpMjN1ZnJncWhKazlsOWMySFFWdXhJRjNnUE5DbFU0d1Y1bkRIMTZYSVg5ZEVoOGVEL1VCTUxOV0VuNWF1dWdwYzRnTVJoamZpaXhqWUtMR09wYzE2cXVubkpHUnRncGZpcTFqWVNxQzltMzRpdGJUZ21VSVN5WWQrSjRyelJWbjU1MTlnYzJiUVFzb0F6by9YZWEyb2JJR1FyL1Vvc1V1enAwWThKb0ZSdzc3VUZrcllmUlJTak5RQStYRU9CeU5BS0JFTm40U3pZYW9qOHNlc2pLcnNmTnE5aTVRTERJU3U5dzA0V0RCQUlSYTFnZkF6MVJka2Q1M3paWFRTKzN4L0dYUEFZNzJ5M1Jkc2ZCdmk1M1V6Uk5XQUtCaUZWNzFJUEhHVlZXdCtqbTFKSy83MHdzR01NQnlVWGpLOHBOMzE3YjdyYi9KUWpWWkVzK2NkZUJKNWF5OW04cnVOYSt6L0RtRzgxdEpmMXA0aElJUkt5cTRHeTNSdTh1ZjNZaEl4Ui9lTC83TXRLbFY0UDUxMUZTN2Q5ZWVGTnR2VzNIOFRSNUNRUWlWc1hJTjc3L3ZCU3BNT0FaVGVVajYxVkR5bURPWHFKLzlpdDNheFJuVGg3TVdiT09DQ2F2cXNXZWRYUml3VFZ1dWZZbkZWNXZjYlNiWTJnQ0V3aEVyQUhSNHFqb2sxZ3cxaFdJV0xjVmpITkFzbFdWbENUMTJpODZKM2Nlc1pwMzBOY2o4cXpvblpzNjVZaU5QNmFZSy90c2xKYnk5aG5lbUJHby9VQnA3Y0pKTklFSkJDTFdnS2kyYmpoYkNha0FOWTN4eXBKMDRQb1loTHVLaFhSdUdtemdiUG5CUllidGVld3B5WkRSQXdzdVV1VU81bW1MZ2k1VlNmdWhMb240Q2VwMlJuSDdmLzBiMTk1R2k3V3JBRUhod0txVHFNOGppRmdONW1XWEtpWFdLc3ZhNFlySzNmdjB3N0pKU0xJZmZrNTdHSy8zMkMrYnVMcXZUVTBhUU9pT2xiWWZocTJJbjZDYmJuK1hXK1Q5NzhiYlp2RWtHNVlrRkh2eVlYVnoyYjBid3ZKaG5ET0lGSkJJakxOMy9paSsvTU5PWUFkNmN3MEtyaS9QZXU5NkhtcmVtL2pJTTN5ZmI1Z3doOC9Kb1dkL3RiZEVjZG4vdVpyYi9jRlkvditxaFppUHIrRGJvMGNvdHNjZHhaV3ZPVkZ4V1NyN01xd21xcms1N1ZpbHhGTFg5THV5Qy9BMkg1OG5uMmJ3NkRMTmRTNmVkVzNBN0ZFeTJiWkVVNWdWamE5UTB2NTg0NnhuSXA1WW15dDZjZDhmVTh3djlHMlBUMUgxVzdZUWdvWGNPM0svdUppdjIvcWJQdW4wZWV4bFAvS2Y3L253S2tWMWRWaWp1Y0p2enVHc2dwc3ZtaXQ3OFdYOGNGeitZYyt2dTJFZXQ3aDNLN2Z6elFsY2U2dDB1Zmc5b0tiZnNCbXN2K1ZEL25jZ1diM0cwbW1MNHVLdSs1d3ZkM0V2QjFleDRUalZaZnh3YkNIL2U0OE9GMjl1R0QrWEwydmY1NWNvZWw1bFg0YVhtMVZIZTFSSzhhUzhRS1N5bytTT0hNV2VBWnVPcXBDLzc4azd5RnFEQkpRazNUWjhmNWFxSkNTMUN5Y3BJVmFUTGVta2lDRFBRTVFHMHZwMllEVlByR3BJa0MyRVlDRjVXaW5xd3kwWllPWVdSYnU1NnVUQm5iNHJXWG82Lzl0dkJ4bTVaZ1hadzNiUHVlYVFaRDd4UGQ5bmRSbEg4cC9GWG5yNHlhU2xKb2FYNHZIOTh2UGpPSk5FWmpTeE5palpURURZM3h4aDR0YmQrR2xRRzQ5dmsvRDJ3ZXFyRnZOMVdUdHVBZDhtbEYrM1MxMUd0eCs5UXBKZXhGcXg4VmkrckNYOUxaejFqMnVKNU5ySitsSmhYNFRkUXF0clNqd2xFS2xVV3pjb0o2dGs3eUNHS3JsMDVZOW5CQ1JXczkraUMraHUxaENUVWp3eFg2NzlPUlV2ejhZbUZCSEVxaGNCK2hOSW9JV2c5SHV4T3R1cllyaGZ6a2ppdjkveHIzc09WeEYwSEpJcUdWbktiZHl1NWtPUzJPSVlGOWVROStmeHZtekZLZnp2Ti8vOURYRTFoTGZNbkU5SDg3L2JjdmVyaW9sVnovNE9KTUhobUozM3Z5UDREUWJQUXJVRENSc2J3eStuSjNQZkRTbm55bGNyRnhBZ3ZhTWN1ZjVVc3hFa1BmR0VqK3hSVngzN0ltejlPTVdNT1Bpc3BqSCtkRlhsR1g4NVZaYjREbnh4c2ZialRVTzBiREpwa0xvR2FialZXZFU3WS8vRGE2WDhlTnZkelpGejNGY2lDV2c1dGdkYStGcS9iek5IYzcrTldNMS9CL0tVMGtNMmx2NGgwWHIvQkFGS1Nxc2ZqT1dmU1huKy9zUDBpZmc4L1ZWNTc0K2ExRUU4T2FzbDFtRDdPcUJFNzVVQzExenpwZS9vRHlrWWFUNTkzeGYzNFg0K2JZZHZjNUl5bGduZnlmcFRyRDdtdmYwVmJSeitZOG5VQy9uL2QzNUVTNndNYmE2NlhqZ1c1MWErTXgwUlI0YUdYMGNodEZXOWdhRkRXaGNLdzFhd3VRSXNhUU5GcitORzNsTjdxV1ovV2FnNjZtM0pKeFJVelgxaVgrV00xL09yWmo5dGJrNC90cU1qd25JUmFORUQ2bEd1bHUraEoxeDErWGY4NXl0Ry9oYlFPQVc5S1NzbmI2SDRQVXpmRGpZY0lwY1g3dTIwU0ZkZnVlU1FFV244WEYwM0Y3bDJRNUtFc1V5SlI0QlVPU0JQcURhKzdtdno5Wk1wUy96STMycUs1dUt1bjg4L3QvS1NaWjEwekdvbGJIaVB5RzBjVXZVdC92NnNReWVEeWE5SHJJNDFwQUFCNWs2N2o5dDF4OXRjenBUSCtVQUIzUlR6OWRFOGVlUEtHQ1NSTHZjdUlueEdiaWZCRXlBV0d3akszMGdEeXpzV0JReGNYVUdza0FyWjhmN25VMU41ZFlBaVMvYUhWL25LZ25UcXJ4OE01ZEZjVHNjcWRteG5CcDN0Q201VDlpK0h2OVhETzA3THoxdlBsL0YxSHp1WDVWMFRnYnc1UU1TUVdQR2JiNDZzNVkxSlFvOEJJVGt5c3NiejdEUG9hL0ZaMmNxVFpjZFY2bk1JS29iNFkzd0NsaGFKbGJKYkVjS2FXRnRxWTdqaUg4L29KREg5Y21ZaS83M3g5ODQzdDJJaDRmUGZMbGlyU2NXZ1JzY0sxNlpmaDIvay8vNSthS25QMktIMHhMUnp4bmhmZVd2SEx1UnM1YjFsZFlMcHI5eCt5UGpsUFFtRlVoMGlwbnBJZXZJeDFYZWc1WHh5T2ZmakNmdDg3NE5VcjhRZHpGKzZaOFNKNC9tZWo2NDg3QmtZdlBDOXNQK1N2RUlTUG9QcmxGSmlsZXMzbmZUTXRMQUo0VU9zUzRmdDVQOWZsVGprVCtQajB3L3puMEZISi94ZHdrUFArNlRBVUJyRm1Ic1Qvci8wbEV6SlkyMGdsUDV5cW84WThDK2tPYWxuaTc0N20zOHUrWm1IZEQwTlNKRnh4dXUzOFhyUW4wN0s1akpuM3FDYXpObkdBVGV6OHJVbmFDb0RzT1QzOVVuTldlOWZkOWdHQlVNZHZtdXAvdk8wa1BqUHFmeG5GZXVQVTB5c2N1UVlTSldnVU05TUM1dlF2UTcyd3NtWjhQQnovUDh6MzczeFQ4bjB0MkdIcEtEUjMzYzZkakxkWktPSUhoc1NsNTRTS3lRa0xIam9JTFVhZStEZUE2di9pb3RXOHVVVy8zQ21aTDh3dlNOSUl4aC9XeW5TMEJzNHVxTjk3RGdkekNhR01pbzNIM09ZVVJCL3MrY2NnbkIydHNIaU4xb2tWcWsrVW1NSUpHSWxoQlZnREdMNk9QNDR1T1JjMzNIWlo3bXRqK1o5UlFHMm9PQmN6bzZjb2k1TTlqOG52WlN4VDZzT1ZpdHBNT3MrU0I4a0pQVmVrTGhlYms5S0pOYmZIM2hSa1pIcys2UExEdWszcDkwWGtOUzFibWF5b2VtbWFOL3ZoYXFLcmZlL2RFaFZsSEMwSmgwclNheUV5SXVzK2lPNkNINk9mS2htV1c4ZjBRb05HRXpLcTl3NjlKQmU3Y25IK0w4UjhpbFdibHREZE1pSVZiaXdkcjE5OHlGM0l1OFJWWW9zbHY0dC9UQXBYQTdicHo1eVNPMHdiQ2RmN3E2M2JwRXNPL1hGdS9sbnZ6dXFRbE1iMFRmWXhGQkhaNU4wbmVES2hIS1duYjAxS0MrYVlEeEFhdE1IaWthaXdZY1huMWR2UDBwWFlnMmxqaFhYLytMQ3RybDdMSGZqdHNUUGNxMjNyRHpRZkc2YjIwT2tFR0hBbUdKc01jWVlhOXhNaXJISEhBaWRwK1hkMVNRQUFBd2dTVVJCVkVaK1gxLzBFRnZvVE04cWpHWmlCb3JzdVdONGFZWDNQZlJLc0haampLUURQOU5saHNvZGkzK1BNY1pIZ2xMUFFJWEIxLzAvVndmc2ovbzlBL2gyd1loaktlakxxenRnMUpGNm51azJvZFBVMG9haWI4OFdOUXo2eDlRejFRU2U3eTdYT25hYVFUU1lXRDZKMnJTQklaRllzWGt5WDFjOUpOWVZCNXFIUzEwOVBDN091Ty9ib3FiUjdnNjYzNm1uQThTSlcwZkh4aG56eE1ZYWN3Q0VHNUwzTTh0Ky9CMXYvM20wdTIvNm9UajdqNi80TTNUNHl4RytLS1RLTFVOOXp2bVNCSlU5NEZDNDRnQnpTQ0t2R0JBMXhPY0t1T1ZEeVdmZ3RhQWtKaDFyaWNYU3B6ejNnTTlTRDNJVnM3QlhiUnZDRzV3Z1JVcEptM0p0Y0ZpaStlTTlQQS93SGh5MXBTeitMQitDa3ZXdW81TjlKNlQ5KzA3K3Q2a3ZUZTcwT2VxRnordi9TQUVhTExFSzY0RVRGRFlWRmpuR0cxRzlteG1DQ2VERHJNYmRDZzdvdUd0YjdpNTNodG5abHZzN2lGeDdMREIyNys5dWVGREpXQy9JYTd4Qjk3R0dVendtYTlyMHUvN01SdVk5M3ZzN2JDT21ISi85ZEhLV2ozaGhaWmNrdkxVbmRFbklKcXUvWExJVkpvRUhrdmJZSm9PakxveGt6TGdIQ1ExbENLVnorTzVDaWxyU3I1RXo1L1RYTENIaWVNMGZwZitRa21FSVFpUVhHK2VhSFlONHRRdzJLSkJNVjRRb1MyMDZ2NTZ6V2JRZjE0ejVpdi9jOGtmNnoyQ0psZmtzZzBEUkp3aGNnSUdVUFlmRU5GRFJvRS93LzZxa284UTJuTU0rd04zWlNoWWFBKzR1ajB4SnJpV3F5aEkzdktqNmt3ZnpqZTgvVjJGZWVybmRVZFl2a3RxNHVMRHBLalZqdmJUVWRwR3VkV0M2VXlRdDhTMzJ0SUUrRWhWYWhPR0NWTGZ6U0g2aEkrT1ZYSFRRdnM4T2tUUGkwVU1sc2FKT3FDT2VRY0lVcWVmZzlDNTBZQmMxek5SRiszU3h6RzFJcUc2QTd5elVKVkFQNE8vZkxvemxueTM4ZXJndVIrL0drajY4V3h2ekl3V1p3TjBKcWhTUUNJdHFDamFwamxhSkZXVFBuMEM4R3dra2JlRjNxQ3UrYTlyZk8yaGloZEVUdVEzZ2RzWk9EbXllQ1o4RDBTTFBBRTRNK096WGN6ZjVuMGc2dlFSWE4xKzd6cGl0WnJGZEhHdG9iSFpGbHM2MXNXWGZvTFRTZXhORmJpNW94WVdHa1pBQXhlWWRzNUd4QnB1YXNiNStmVldtVTYvcnZSR256UXhWUXZjWlRPU1NuODdneVVicVdKcjI4aDJ5WmNmZk5lT1FzL3VVeDBPbVk0VXhpbDlVd3pkSzV2UUVDYkJ5b01JUXpWSGFHdVhML0NTVzBJVnROamkyZytqWW9vZStPZEFKUXExT0UvNmgyeDU3cXBNRWlRUWxiVHBGRVdyVnNiSTZKWWprVG1hQkd6Q0VxaVZXb1ZzZS92Nzl3V244LzZHUzhmZFhGdnM5QWtWd3NtTGVFbExFQ2wyYW1vWEdzTDdDZm1xa2tHcUw0MkNmcE1JYlRYTFpwY3Jydnh2YjA5c1pWMkUvWGN0WXh4NW9Qa2VYT3V5ZVBjNlh4RnBwQkJQMGlmZ05VdmJKU1pMTXg3VllKbVdqVm1KRlBmZzhySEFCUThUUDJoTWs2OHU4Qm5pSjZrQnZVWC9iTGZlOGNpaUN6Q3VGU2tuaE1Hb3hJdzJUNXVFaG9TZXhncGh3L0dWQkRDQXNsazBLZWxoOEZ5ekJhaUZXNkpMWjc1amxYd2gyYW1CMVU1b3JBTWQ5WkI1am4yUHpnc1FLVno2eGZwV3JPMzdyMXplZEh2aDRyL1YyTFl2dDMrbjFMMFVLc1dhVlQxMnM0TTZ0VnR6UDFaUGJPVDJ0L21VdFkvM3BYdXZFb044UHlZZ2RrU0hKS1hHQWgwVEFRa3JsanBFRmk0ZjdudE9hQkJyeDdhSkpXQnIvSkVJZzQ0MWJPK1ZVOVZtUzM3bkpKOG5JK2R1eXNtQWNhY2p0MTRtVWNlekg4WkxGd2pPTE9DUmw1bE1LVlFvaXo2UTJta0JFaG5ISS9aK1J2TXNWZTVZWnM5QUg4RE9HU2dDZnNlL2cvZ1YzTmkySnhkVmsxbUxrdCt5c0JNbWsyd2k0WUNvQ2RtcFFvc05GNkRSTFJwNzQ2Tk44bmxmb3JHRWtsY3BXRnN3TkFtOW5Oanl1WmJGTlM2MmZFUW1rNm5MYm9wWGVZRkRac09LaW50elc1M2VZM3RZeTF1OW1OVHdhOVB1WkpaZmxHdFhUME1TT2hobXZUVlFsUFRGaWhPc1NDSXpGckhlS2h6OHh4NmUrZ1B1UHNEem9RTVhxaEp5alVvbW84VDc0b0RJZExWUWdPTzZ5NHo0akRYd21kRCtERndBSUZXV3o1MEN5TUFJaWo2c2NzVUpmaXVmV1hMM0lKM1VEK0J0dEFwbUs2WUNocHNDdEJUekJlazhFT0hHRU9wa01TK1lOcVpUcFZxRUNZV0cwMEtFemRZVlNCMytoWGhha0NrSStHSGVDVDFLSHJodSt4RGh0WUZOQk96RTM4RjRZS1pIREFLNXorQnRqZ08veG5OQ0x4WjlZMzhwc2VFTExZbnRybDNsS1pPaFc5dzVTU3F3RlZSOU03Y2x0ZlhPWGVhcVdzY2JtRy9UNzk4NjdsQ2NGZGp6Vzh4b1ZsQTFDREpSOXlwOTB4SWhSbU9xUEpTbUJCQVZyK1dIcDUzNDRrMStNSUhSSTE4blBQc2psTHJqSVorR1hVbHV3UEtJQTNzZmVqY1VQaVZWTU9oUkswSEQ5WVpaeFBuM2U4bUd5eE1xQ0s1ai9MZlRWRm9VWGFpTFRHRFpETVQyM1htUFlhU3puaitJM0ZtSHVpSlVYTCs4MFJqQWdRVldpeGtnRmw2MzFOMy9VS2ZNV1BDMVlzSUVXYkpvMFU1Slk0eXRiVHRHeTJCYm1OMTdmWmFUZ2J2UHVNRjlkd08yNmF3YVhjdFZpL2dhQVl1OUFOQmYyRGJic1ZxZXh0MUppTGF0YmRITnd4MkV2cVpSNmQ4Q1VLNWR3S1ZkOHc2Y3ozUC9wYU03VjFDWDlDUGNwTFdPOXhkaHlzaTQ1QXVUY2hJSXVlMi9nc3YyUGRzaXF4VDZERk9Ldk80V2pQRzR2OVlUUWNNbm5EdmJXUTVpOVNTbGcyZmV2c3hqSmdFRGdoV0U3MkV0ekZCVmNqSnhkTUU4eGx2N1NQdG9JaVpGSmlWQ1pLRG15Q3orSFBsa3FseTU4aHBHVHRtRFJlZnhHQnc4VEpDcm4zNG5Vb043M2lxR21jeHJTem9hYmRrL1VxRldWWnJWZUFhWTJkMHlYa0dwOXd0SGNWdSt4UUNwai8zN3ZjUzBJWDhzTzcwQnVMN3JGb0lSWTYyMDdqdGZjRHR5RHRkNTdyQks5a3R0N05LeVVTZENoRStwYTNURVlPelZqZmVtcVNsTnJPMFhkL2VXVGlCUFU2VmlCLzhscnZGSE5ZcHVUYmJtM1N5cmI1SlZ3TmcweUJyeGpLczh2TWtNbEtzdy9qMVp5OWJSbWw2c3k3dzRZcUEyNDROQzBkV2lvK3hRQkhtckdHbEl1TFpvZUJDM1hYeE5DUTZ5SXJubDlwL2taSlFzTkJwQ1dycEJnY0NUQVZTZUJDSW5Ca2o1UXU5VHFqc3FwbUQ1WGlsU1RpeWFVMjFxTEJtZ3EzMUVYelcwWVlGYlVCdHlsNVc0SmFiOWk3SjVOTWMxVU10YlF5VktVSFlHZ2tWZ0JwNmNqNnFNY3k1MVNhb0VMVmhqY2tIWkNtcUNqazk0alpiQmlVZ1hTL0JJMWFDQlhnM25acGJobW14SHE5c0tiYWhHQjVXZzNhMWQ3Rkw1OXM2cDJWS21JZUFraVZ3Q1NybUJNeGNZYWMrRGpIT3NkVGcrUktvRVFGTEV5bU52YzBUait2WkpoZm1GcXNtbk8wOG1tMlQrWDJpNkVmcTVMSzVyL3l1MnFDR216d0UwbXlGaDZYR0RZM0ZiYUgyUWJkSmtaRSthb2FrZm1QYTkwVlI5alRERzJHR01BWXc2akpPWUFMUlFDUVVkaURSdmsvZnRPVllTMG9iOGxMTnV4L1pKbHF0cVJjZXRzbXFRRUFoRnJhRkQ2MFpXcUNHbXJUSDdNN2tUcTJJWGhLckVTQ0lTL0dyRTJwQTVTUlVnRnIwME15M1ljK1B3U1ZlMG9tM2NwVFZJQ2dZaTErNlU5K0lmYThzSXp2VjliZFF5M2NXQzFvblpzT1NtYmM3ZlNKQ1VRaUZoRENPdXVJN2o0b2FVQkNhbGk4ZkN3YmtmZHhtTjVQMVZaSGZFQU0xZTc3bmlhb0FRQ0VXdm9ZUy90dzIwN2I3Mmt3YXBrempVOW9oMlZQNTNCKzZsSzZZY2JkdytneVVrZ0VMRjJIUkNyYmRveWxOdnorQlRlWHhVeDl2a3YzOEcxVmNYMHFIWTRMZEZjMFRzMzhUa1AwbS82aE52OTREU3VOdTRFenVPa2lVa2dFTEVTQ0FRQ2dZaVZRQ0FRaUZnSkJBS0JpSlZBSUJDSVdBa0VBb0ZBeEVvZ0VBaEVyQVFDZ1VERVNpQVFDQVFpVmdLQlFDQmlKUkFJQkNKV0FvRkFJQkN4RWdnRUFoRXJnVUFnRUxGR0ZEd2RIVkdsVGE2K3NRZWF6L21weEhieDNnYkhrWFJMS1lGQUlHTFZBTnpLR2xkaFAvMmFPR08rL3pYUWw4UldXbkJqcllzSWxrQWdFTEVxUTB1N0orckZ0UHBYL1FuVkgvZHNyVmxhYVcvdlRYMUdJQkNJV0FQZ2cyekxmWUZJbGVFZkNiV0wyMGx5SlJBSVJLelNTS3R0RzZxVVZCa1dGVFpkVFgxSElCQ0lXQ1h3YklwcHBscGlIYlBXV0FpZExQVWZnVUFnWWhVeFdGMjkxbGlzbGxpQmltYlN0UklJQkNMV3d3QnkxRUtxd0xvSysyazBpUWdFQWhHckh4cWRubWl0eEpwYTJ6YVVKaEdCUUNCaUZjR2srT3IxYWtuMWdoVUd0ODNsb2Y0akVBaEVyR0tZblcyNVh5Mnh3cCtWK281QUlCQ3hTcURCNFk0ZUcyZk1VMHFxSTFZWVhEbG14MERxT3dLQlFNUXFnOStyV2s5VVNxeWY1VnB2b1Q0akVBaEVyQXFRWE5ONjdIWHJxcktrQ0hYVXFrcnowbExiUlI3eVh5VVFDRVNzNnJ3RTV1ZGF4eitjV1BzbEVxL2cyRDk1UzgzeTkzYzNQRmh1Yy9XaFBpSVFDRVNzUVFDcEF1M3RaUGtuRUFoRXJBUUNnVURFU2lBUUNFU3NCQUtCUUpERS93Tnl0Z3FTS3duMzdBQUFBQUJKUlU1RXJrSmdnZz09IiBpZD0ic3ZnXzEiIGhlaWdodD0iOTguMjA2NTIxIiB3aWR0aD0iMTk0Ljk5OTk5OCIgeT0iMTAuNzkzNDc5IiB4PSIzLjAwMDAwMiIvPgogPC9nPgo8L3N2Zz4=) no-repeat center center; display: block; } .custom-header-logo { width: 200px; height: 120px; margin: 0 auto; } .custom-icon-logo { width: 100px; height: 60px; } /* === corners === */ .custom-corner-all { border: 1px solid #9FD9F2; -webkit-border-radius: .375em; border-radius: .375em; } /* === wrapper === */ .custom-wrapper { max-width: 40em; padding: 0 1em; -moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box; display: block; margin: 0 auto; } @media (max-width: 40em) { .custom-wrapper { max-width: none; width: 100%; } } /* === description === */ .custom-description { padding: .5em 0; } .custom-description > span { display: inline-block; vertical-align: middle; text-align: center; width: 15%; line-height: 90px; height: 90px; } .custom-description .custom-icon { color: #24A9E1; font-size: 2em; } .custom-description > .custom-icon-logo { width: 35%; } /* === ipv4/6 info === */ .custom-description .custom-icon:nth-child(2):after { content: "IPv4"; } .custom-description .custom-icon:nth-child(4):after { content: "IPv6"; } .custom-description .custom-icon:nth-child(2):after, .custom-description .custom-icon:nth-child(4):after { display: block; line-height: 1em; font-family: Arial; font-size: .6em; margin-top: -32px; } @media (max-width: 40em) { .custom-description > .custom-grandenet-logo { background-position: 13px 0px; background-size: 9em; } .custom-description > .custom-grandenet-logo { width: 30%; } } /* === button === */ .btn { background-color:#FFC131; background-image:-webkit-linear-gradient(left top, #FFC131 42%, #FFB100 70%); background-image:linear-gradient(left top, #FFC131 42%, #FFB100 70%); display: block; text-align: center; padding: .5em 0; -webkit-border-radius: .375em; border-radius: .375em; color: black; text-decoration: none; font-weight: bold; } .btn:hover { background: #FFB100; text-decoration: none; font-weight: bold; } .btn:hover { background: #FFC131; text-decoration: none; } /* === table === */ table { background: rgba(159,217,242,.15); border: 1px solid #24A9E1; border-radius: .375em; padding: .5em; margin-bottom: 1em; } table th, table td { text-align: right; } table tr td:first-child { text-align: left; } table tr { border: 1px solid #24A9E1; } /* result */ .table h2 { font-weight: normal; text-align: center; } .table p { display: inline-block; vertical-align: middle; max-width: 80%; } .winner th, .winner td { background: #24A9E1; } @media (max-width: 26em) { table { padding: 0; } table tr td, table tr th { font-size: .6em; } } /* spinner */ .custom-icon-spinner { margin-right: .25em; padding-top: 10px; -webkit-animation-name: spin; -webkit-animation-duration: 600ms; -webkit-animation-iteration-count: infinite; -webkit-animation-timing-function: linear; animation-name: spin; animation-duration: 600ms; animation-iteration-count: infinite; animation-timing-function: linear; font-size: 2em; display: inline-block; width: auto; height: auto; vertical-align: middle; } </style> </head> <body> <div class="custom-wrapper custom-corner-all"> <header> <span class="custom-grandenet-logo custom-header-logo"></span> </header> <div class="table"> <span class="custom-icon custom-icon-spinner"></span> <p>Testing all possible frontends, please wait...</p> </div> <div class="custom-description"> <span class="custom-corner-all custom-icon custom-icon-user"></span> <span class="custom-icon custom-icon-forward"></span> <span class="custom-corner-all custom-grandenet-logo custom-icon-logo"></span> <span class="custom-icon custom-icon-forward"></span> <span class="custom-corner-all custom-icon custom-icon-harddrive"></span> </div> <div class=link></div> </div> </body> </html>