text:
/** Ephellon Dantzler - 2015, 2018
  * How to use ([...] is optional):
  * Simply call on SynQ([attribute-name]), and that's it
  * For in depth help, use SynQ.help([string:item-name])
  * FAQ:
  * Q0) How can I get help?
  * A0)   Use `SynQ.help([string:item-name])`
  * Q1) What if I just want to update some storage data?
  * A2)   Use `SynQ.set(string:name, string:data[, string:password])`
              `SynQ.get(string:name[, string:password])`
              `SynQ.pop(string:name[, string:password])`
  * Q2) What if I want to get rid of all of my data (in SynQ)?
  * A2)   Use `SynQ.clear([boolean:clear-all])`
          + See note #1
  * Q3) What if I want to synchronize data across my entire domain?
  * A3)   Set the `use_global_synq_token` variable to a defined value (`null` counts as defined)
  * Q4) How do I check on the status of my data?
  * A4)   You can use `SynQ.list([boolean:show-private])` to show your data
  * Q5) What about the other things I see under SynQ?
  * A5)   Those are for future technologies, but you can use them as you see fit
  * Q6) How much space do I have?
  * A6)   It depends on the browser but you can use `SynQ.size()` to find the current maximum.
          The highest is 5 MiB (5,242,880 b, with UTF-16 enabled) because JS uses UTF-16 characters by default.
          + See note #3, #4
          `SynQ.size([number:value[, number:base[, string:symbol]]])` also converts `value` into an SI foramatted string,
          e.g. `SynQ.size(8214, 1000, "m")` returns "8.214km"
  * Q7) What if I want more space?
  * A7)   Set the `use_utf16_synq_token` variable to a defined value; SynQ will then force UTF-8 data strings;
          the space will be doubled, max being 10 MiB (10,485,760 b, with UTF-16 disabled/UTF-8 enabled).
          + See note #3
  * Q8) How can I see how much space I am using?
  * A8)   Use `SynQ.used([boolean:synq-data-only])`
  *
  * Notes:
  * 1) `SynQ.clear` will only remove "local" (see note #2a) items if the `use_global_synq_token` isn't set
  * 2a) By "local" I mean per the unique page identifier (URL),
        - i.e. "https://example.com/page-1" NEQ "https://example.com/page-2" (pathname: page-1/page-2)
        - etc. "https://example.com/page-1" NEQ "http://example.com/page-1" (protocol: https/http)
  * 2b) By "global" I mean per unique domain name (host),
        + i.e. "https://example.com/page-1" EQU "https://example.com/page-2" (domain: https://example.com)
        - etc. "https://example.com/page-1" NEQ "http://exmple.com/page-1" (protocol: https/http)
  * 3) Data units are given in bits and bytes (1B = 8b [0000 0000]), with no regard to encoding.
        e.g. if `SynQ.used()` returns "16" it means 16 bits/2 Bytes (i.e. 1 UTF-16 character, or 2 UTF-8 characters)
  * 4) According to [Mozilla](https://developer.mozilla.org/en-US/docs/Web/API/Storage/LocalStorage),
        pretty sure they know what they're talking about
  */

var NO_NAME_ERROR   = "The resource name is missing",
    UTF8_ONLY_ERROR = "Only UTF-8 characters are allowed.",
    NULL_KEY_ERROR  = "The [use_vpn_synq_token] flag is set, therefore all entries require a password.",
    IE              = {
      "addEventListener": "attachEvent",
      "dispatchEvent":    "fireEvent",
      "Event":            "CustomEvent"
    }, SA = false,
    window, global, self, top,
    document, navigator,
    localStorage, sessionStorage, storage, connection,
    // SynQ Tokens
    use_global_synq_token, // use a global state
    use_utf16_synq_token, // use UTF16 character pairs
    use_cookie_synq_token, // use cookies instead of localStorage
    use_uuid_synq_token, // use a static UUID
    use_vpn_synq_token, // use a VPN-like setup
    internal = '[[InternalAccess]]';

window = window || global || top || self || this || {};
document = window.document || {};
navigator = window.navigator || {};

var CustomEvent;

// IE and Edge?
if(typeof CustomEvent == 'object') {
  for(var property in IE)
    window[ property ] = window[ IE[property] ] || window[ property ];

  (function() {
    function CustomEvent (event, parameters) {
      var E = document.createEvent('CustomEvent');
      parameters = parameters || { bubbles: false, cancelable: false, detail: undefined };
      E.initCustomEvent(event, parameters.bubbles, parameters.cancelable, parameters.detail);

      return E;
    }

    CustomEvent.prototype = Event.prototype;

    window.CustomEvent = CustomEvent;
  })();

  IE = true;
} else if(CustomEvent == undefined) {
  (function() {
    function CustomEvent (event, parameters) {
      addEventListener(event, parameters || { bubbles: false, cancelable: false, detail: undefined });
    }

    CustomEvent.prototype = Event.prototype;

    window.CustomEvent = CustomEvent;
  })();

  SA = true; IE = false;
} else {
  IE = false;
}

/* Helper functions not under SynQ */
// repeat a string
String.prototype.repeat = String.prototype.repeat || function repeat(number) {
  for(var string = this.toString(); number-- > 0;)
    string += string;
  return string;
};

// map values
Array.prototype.map = function(callback, self) {
  for(var index = 0, length = this.length, array = [], self = self || null; index < length; index++)
    array.push(callback.call(self, this[index], index, this));
  return array;
};

// ping an address
// https://stackoverflow.com/questions/4282151/is-it-possible-to-ping-a-server-from-javascript
// Powered by: Lorem Picsum
function ping(address, options) {
  if(ping.inUse)
    return 'Currently pinging an address, please wait.';

  var fallback = {
    callback: function() { return arguments; },
    pass:     function() {},
    fail:     function() {},
    timeout:  10000
  },
      x = ((Math.random() * 638) | 0) + 126,
      y = ((Math.random() * 638) | 0) + 126;

  address = address || "picsum.photos/" + y + "/" + x + "/?random";
  options = options || fallback;

  ping.inUse    = true;
  ping.address  = address;
  ping.callback = options.callback || fallback.callback;
  ping.pass     = options.pass     || fallback.pass;
  ping.fail     = options.fail     || fallback.fail;

  ping.ping = new Image();
  ping.clear = function(status) {
    clearTimeout(ping.timeout);
    ping.inUse = false;

    var time = +(new Date) - ping.start,
        size = (ping.ping.height * ping.ping.width * 64) || 1;

    return ping.callback.call(null, ping.trip = {
      time:    time,
      status:  (status? "pass": "fail"),
      address: ping.address,
      resolve: ping.ping.src,
      size:    size,
      speed:   ((size / time) | 0),
      uplink:  ((size / time / 2) | 0)
    });
  };

  ping.ping.onload  = function() { return ping.clear(!0), ping.pass.call(null, arguments); };
  ping.ping.onerror = function() { return ping.clear(!1), ping.fail.call(null, arguments); };

  ping.start    = +(new Date);
  ping.ping.src = 'https://' + address;
  ping.timeout  = setTimeout(ping.fail, options.timeout || fallback.timeout);
}

// The main function
function SynQ(name) {
  ++SynQ[internal];

  name = name || null;

  if(name == null)
    name = SynQ.syn;
  if(name instanceof Array)
    name = name.join('],[');

  var messages = [],
      uuids    = SynQ.get('.uuids'),
      copies   = {},
      query    = document.querySelectorAll('[' + name + ']');

  uuids = (uuids || "").split(',');

  function fetch(e) {
    var a = e.attributes,
        n =
    ("synq-attr" in a)?
      "#ATTR":
    ("synq-data" in a)?
      ("value" in e)?
        "value":
      "innerText":
    ("synq-text" in a)?
      "innerHTML":
    ("synq-html" in a)?
      "outerHTML":
    "";

    if(n == "")
      return n;

    switch(n) {
      case '#ATTR':
        var o = {},
            l = a['synq-attr'].value,
            f = function(v, i, r) {o[v] = a[v].value};

        if(!l.length)
          [].slice.call(a).map(f);
        else
          l.split(/\s+/).map(f);
        return o;
        break;
    }

    return e[n];
  }

  for(var index = 0, element, uuid, name, value, info, id, attr, host, obj = false; index < query.length; obj = false, index++) {
    // Element information
    element       = query[index];
    info          = element.tagName;
    attr          = element.attributes;
    id            = ('id' in attr)? attr.id.value: null;
    name          = ('name' in attr)? attr.name.value: null;
    uuid          = ('synq-uuid' in attr)? attr['synq-uuid'].value: null;
    host          = ('synq-host' in attr)? attr['synq-host'].value: null;
    copies[info] |= 0;

    // Setup hosts
    if(host != null)
      element.setAttribute('name', SynQ.host = host || id || uuid || name);

    // Add copies of elements for the UUID to work properly
    info += (id != null || uuid != null)?
      "#" + (id || uuid):
    ":nth-child(" + (++copies[info]) + ")";

    // Get, and test value
    value = fetch(element);

    if(obj = typeof value == 'object')
      value = SynQ.deflate(value);

    // Get/Set the element's UUID
    if(uuid == null)
      uuid = (obj? '!': '') + SynQ.sign(info, 1);
    else if(obj)
      uuid = /^!/.test(uuid)? uuid: '!' + uuid;

    // Set the element's UUID for future references
    element.setAttribute('synq-uuid', uuid);

    // Push the UUID
    if(!~uuids.indexOf(uuid))
      uuids.push(uuid);

    // Push the messages
    uuid = ".values/#" + uuid;
    messages.push( SynQ.encodeURL(value) );
    SynQ.set(uuid, value);
  }

  SynQ.set('.values', messages.join(SynQ.esc));
  SynQ.set('.uuids', uuids.join(',').replace(/^,/, ''));

  --SynQ[internal];
}

SynQ.syn = "synq-attr synq-data synq-text synq-html synq-host".split(" ");
  // change this accordingly; this is the syncronizing attribute for your elements
  // synq-data: .innerText OR .value
  // synq-text: .innerHTML
  // synq-html: .outerHTML
SynQ.esc = "%%";
  // change to your liking; this is the list delimeter

/* The event-listeners */
// eventlistener target
SynQ.eventlistener = function(event) {
  ++SynQ[internal];

  var messages = SynQ.get('.values'),
      uuids    = SynQ.get('.uuids'),
      copies   = {},
      query    = document.querySelectorAll('[' + SynQ.syn.join('],[') + ']');

  messages = messages || "";
  messages = (messages.length > 0)? messages.split(SynQ.esc): [];

  uuids = uuids || "";
  uuids = (uuids.length > 0)? uuids.split(','): [];

  function write(e, m) {
    var a = e.attributes,
        n =
    ("synq-attr" in a)?
      "#ATTR":
    ("synq-data" in a)?
      ("value" in e)?
        "value":
      "innerText":
    ("synq-text" in a)?
      "innerHTML":
    ("synq-html" in a)?
      "outerHTML":
    "";

    if(n == "")
      return n;

    switch(n) {
      case '#ATTR':
        for(var p in m)
          e.setAttribute(p, m[p]);
        return a;
        break;
    }

    e[n] = m? m: e[n];
  }

  updating:
  for(var index = 0, length = query.length, element, uuid, name, value, info, id, attr, host, obj = false; index < length; obj = false, index++) {
    // Element information
    element       = query[index];
    info          = element.tagName;
    attr          = element.attributes;
    id            = ('id' in attr)? attr.id.value: null;
    name          = ('name' in attr)? attr.name.value: null;
    uuid          = ('synq-uuid' in attr)? attr['synq-uuid'].value: null;
    host          = ('synq-host' in attr)? attr['synq-host'].value: null;
    copies[info] |= 0;

    // Don't overwrite skip elements (higher number = higher priority)
    // synq-skip = number of times to ignore SynQ-ing
    if('synq-skip' in attr) {
      skip = +attr['synq-skip'].value;
      skip |= 0;
      if(skip > 0) {
        element.setAttribute('synq-skip', --skip);
        continue updating;
      } else {
        element.removeAttribute('synq-skip');
      }
    }

    if(host != null)
      element.setAttribute('name', SynQ.host = SynQ.host || host || uuid);

    info += (id != null || uuid != null)?
      "#" + (id || uuid):
    ":nth-child(" + (++copies[info]) + ")";

    // Get the element's UUID
    if(uuid == null)
      uuid = SynQ.sign(info, 1);

    // UUID is set
    // Write confidently, even if the HTML document has changed
    if(uuid != null) {
      value = SynQ.get('.values/#!' + uuid);
      value = (obj = value != null)?
        value:
      SynQ.get('.values/#' + uuid);
      value = value != null?
        value:
      "";
    }
    // UUID isn't set
    // Write, assuming the HTML document hasn't changed
    else {
      value = messages[index] || "";
    }

    // Set the element's UUID for future references
    element.setAttribute('synq-uuid', uuid = (obj? '!': '') + uuid);

    value = SynQ.decodeURL(value);

    if(/^!/.test(uuid))
      value = SynQ.inflate(value);

    write(element, value);
  }

  --SynQ[internal];
};

// add listener
SynQ.addEventListener = function(event, action) {
  SynQ.prevent([event, action], [undefined, null, ""], "Failed to add event listener '" + event + "'", "addEventListener");

  if(SynQ[internal])
    return action;
  else
    ++SynQ[internal];

  var event  = SynQ.eventName + '/' + event + '/#',
      events = SynQ.get(event + 0),
      fn     = SynQ.parseFunction(action),
      name   = fn[2] || events.length;

  events = events || "";
  events = (events.length > 0)? events.split(SynQ.esc): [name];

  if(events.indexOf(name) < 0)
    events.push(name);

  SynQ.set(event + 0, events);
  SynQ.set(event + name, action);

  return --SynQ[internal], events.length - 1;
};

// remove listener
SynQ.removeEventListener = function(name, parent) {
  SynQ.prevent(name, [undefined, null, ""], "Failed to remove event listener '" + (parent || '*') + "." + name + "'", "removeEventListener");

  if(SynQ[internal])
    return parent;
  else
    ++SynQ[internal];

  if(parent)
    return --SynQ[internal], SynQ.pop(SynQ.eventName + '/' + parent + '/#' + name);

  var events = SynQ.events.split(' '),
      popped = [];

  for(var index = 0, listener, values; index < events.length; index++) {
    parent = SynQ.eventName + '/' + events[index] + '/#';
    listener = SynQ.pop(parent + name);

    if(listener) {
      values = SynQ.pop(parent += 0).split(',');
      values.splice(values.indexOf(name) - 1, 1);
      SynQ.set(parent, values + "");
      popped.push(listener);
    }
  }

  return --SynQ[internal], popped;
};

// trigger listener
SynQ.triggerEvent = function(event, data) {
  SynQ.prevent(event, [undefined, null, ""], "Failed to trigger event '" + event + "'", "triggerEvent");

  if(SynQ[internal])
    return data;
  else
    ++SynQ[internal];

  var event  = SynQ.eventName + '/' + event + '/#',
      events = SynQ.get(event + 0);

  events = events || "";
  events = (events.length > 0)? events.split(SynQ.esc): [];

  for(var index = 0, head, body, fn, host = SynQ.host; index < events.length; index++) {
    fn = SynQ.parseFunction(SynQ.get(event + events[index]));
    head = fn[0];
    body = fn[1];
    --SynQ[internal];
    new Function(head, body).call(null, data);
    ++SynQ[internal];
  }

  return --SynQ[internal], data;
};

/* The URL-oriented functions */
// URI encoder
SynQ.encodeURL = function(url) {
  for(var index = 0, characters = "% \"<>[\\]^`{|}", url = url.toString(); index < characters.length; index++)
    url = url.replace(RegExp( "\\" + characters[index], "g" ), "%" + characters.charCodeAt(index).toString(16));

  return url;
};

// URI decoder
SynQ.decodeURL = function(url) {
  for(var regexp = /%(\d{2})/, url = url.toString(); regexp.test(url);)
    url = url.replace(regexp, function($0, $1, $_) {
      return String.fromCharCode(+("0x" + $1)) + "\r\f"; // prevent intentional %code from being removed
    });

  return url.replace(/(% "<>\[\\\]\^`\{\|\})\r\f/g, "$1");
};

/* The storage-oriented functions */
// List all of the current SynQ's data (paths)
SynQ.list = function(all) {
  var signature = SynQ.shadow || SynQ.signature,
      regexp = RegExp("^(" +
                 (use_global_synq_token != undefined || all? "synq://localhost:(443|80)\/.*|": "") +
                 signature.replace(/(\W)/g, "\\$1") +
               ")" + (all? ".+": "[^\\.].+") + "$"),
      array  = {};

  for(var item in storage)
    if(regexp.test(item))
      array[item] = storage[item];

  return array;
};

// The "clear all" option
SynQ.clear = function(all) {
  var signature = SynQ.shadow || SynQ.signature,
      regexp = RegExp("^(" +
                 signature.replace(/(\W)/g, "\\$1") +
               ")" + (all? ".+": "(.*\/)?[^\\.].+") + "$");

  for(var item in storage)
    if(regexp.test(item))
      storage.removeItem(item);

  return SynQ.triggerEvent('clear');
};

// Push (set) a resource
SynQ.set = function(name, data, key) {
  SynQ.prevent(name, [undefined, null], NO_NAME_ERROR, 'set');

  data = data.toString();
  key = key || use_vpn_synq_token;

  var UTF16 = use_utf16_synq_token != undefined;

  if(UTF16)
    SynQ.prevent(data, /[^\u0000-\u00ff]/, UTF8_ONLY_ERROR);

  if(key != undefined && key != null)
    data = SynQ.lock(data, key),
    key  = /^./.test(name)? '': '.';
  else
    key = "";

  if(UTF16 && data)
    data = SynQ.pack(data);

  storage.setItem(SynQ.signature + key + name, data);

  SynQ.last.push(name);

  return SynQ.triggerEvent('set', name);
};

// Pull (get) a resource
SynQ.get = function(name, key) {
  SynQ.prevent(name, [undefined, null], NO_NAME_ERROR, 'get');

  var data, UTF16 = use_utf16_synq_token != undefined;

  key = key || use_vpn_synq_token;

  if(UTF16)
    SynQ.prevent(data, /[^\u0000-\u00ff]/, UTF8_ONLY_ERROR);

  if(key != undefined && key != null)
    data = storage.getItem(SynQ.signature + "." + name);
  else
    data = storage.getItem(SynQ.signature + name);

  if(UTF16 && data)
    data = SynQ.unpack(data);

  if(key != undefined && key != null)
    data = SynQ.unlock(data, key);

  return SynQ.triggerEvent('get', data);
};

// Append (push) a resource
SynQ.push = function(name, data, key, delimiter) {
  SynQ.prevent(name, [undefined, null, ""], NO_NAME_ERROR, 'push');
  ++SynQ[internal];
  key = key || use_vpn_synq_token;

  var last = SynQ.get(name, key) || "";

  delimiter = delimiter || SynQ.esc;
  data = (last.length > 0)? last.split(delimiter).concat(data): [data];
  data = SynQ.set(name, data.join(delimiter), key);

  return --SynQ[internal], SynQ.triggerEvent('push', data);
};

// Pull a resource
SynQ.pull = function(name, key, delimiter) {
  ++SynQ[internal];
  delimiter = delimiter || SynQ.esc;
  key = key || use_vpn_synq_token;

  var data = SynQ.get(name, key);

  data = data || "";
  data = (data.length > 0)? data.split(delimiter): [data];

  return --SynQ[internal], SynQ.triggerEvent('pull', data);
}

// Remove a resource
SynQ.pop = function(name, key) {
  ++SynQ[internal];
  name = name || SynQ.last.pop();
  key = key || use_vpn_synq_token;

  SynQ.prevent(name, [undefined, null, ""], NO_NAME_ERROR, 'pop');

  var data = SynQ.get(name, key);

  if(key != undefined && key != null)
    storage.removeItem(SynQ.signature + "." + name);
  else
    storage.removeItem(SynQ.signature + name);

  return --SynQ[internal], SynQ.triggerEvent('pop', data);
};

// Broadcast to a global storage
SynQ.upload = function(name, data, key) {
  SynQ.prevent(name, [undefined, null], NO_NAME_ERROR, 'upload');

  if(data == undefined || data == null) {
    key = (key? '.': '');
    return key + SynQ.sign(key + name)
      .replace(/(.{1,4})(.{1,2})?(.{1,2})?(.{1,2})?(.{1,6})?(.{1,12})?/, "$1-$2-$3-$4-$5:$6")
      .replace(/[\-\:]+$/, "");
  }

  data = data.toString();
  key = key || use_vpn_synq_token;

  var UTF16 = use_utf16_synq_token != undefined;

  if(UTF16)
    SynQ.prevent(data, /[^\u0000-\u00ff]/, UTF8_ONLY_ERROR);

  if(key != undefined && key != null)
    data = SynQ.lock(data, key),
    key  = /^./.test(name)? '': '.';
  else
    key = "";

  if(UTF16 && data) {
    for(var index = 0, length = data.length, array = []; index < length;)
      array.push(SynQ.pack16(data[index++], data[index++]));

    data = array.join("");
  }

  // ".name" and "name" won't be interchangeable
  name = SynQ.sign(key + name)
    .replace(/(.{1,4})(.{1,2})?(.{1,2})?(.{1,2})?(.{1,6})?(.{1,12})?/, "$1-$2-$3-$4-$5:$6")
    .replace(/[\-\:]+$/, "");

  storage.setItem('synq://localhost:' + (key.length? 443: 80) + '/' + name, data);

  SynQ.last_upload.push(name);

  return SynQ.triggerEvent('upload', name);
};

// Retrieve a global item
SynQ.download = function(name, key) {
  SynQ.prevent(name, [undefined, null], NO_NAME_ERROR, 'download');

  var data, UTF16 = use_utf16_synq_token != undefined;

  key = key || use_vpn_synq_token;

  if(UTF16)
    SynQ.prevent(data, /[^\u0000-\u00ff]/, UTF8_ONLY_ERROR);

  // ".name" and "name" won't be interchangeable
  name = SynQ.sign((key? ".": "") + name)
    .replace(/(.{1,4})(.{1,2})?(.{1,2})?(.{1,2})?(.{1,6})?(.{1,12})?/, "$1-$2-$3-$4-$5:$6")
    .replace(/[\-\:]+$/, "");

  if(key != undefined && key != null)
    data = storage.getItem('synq://localhost:443/' + name);
  else
    data = storage.getItem('synq://localhost:80/' + name);

  if(UTF16 && data) {
    for(var index = 0, length = data.length, array = []; index < length;)
      array.push(SynQ.unpack16(data[index++]));

    for(data = [], array = array.join("").split(/([01]{8})/), index = 0, length = array.length; index < length; index++)
      if(array[index] != "")
        data.push(String.fromCharCode(+("0b" + array[index])));

    data = data.join("");
  }

  if(key != undefined && key != null)
    data = SynQ.unlock(data, key);

  return SynQ.triggerEvent('download', data);
};

// Append (push) a resource
SynQ.append = function(name, data, key, delimiter) {
  ++SynQ[internal];
  SynQ.prevent(name, [undefined, null, ""], NO_NAME_ERROR, 'append');

  delimiter = delimiter || SynQ.esc;
  key = key || use_vpn_synq_token;
  data = SynQ.download(name, key).split(SynQ.esc).concat(data);
  data = SynQ.upload(name, data.join(delimiter), key);

  return --SynQ[internal], SynQ.triggerEvent('append', data);
};

// Pull a resource
SynQ.recall = function(name, key, delimiter) {
  ++SynQ[internal];
  delimiter = delimiter || SynQ.esc;
  key = key || use_vpn_synq_token;

  var data = SynQ.download(name, key);

  data = data || "";
  data = (data.length > 0)? data.split(delimiter): [data];

  return --SynQ[internal], SynQ.triggerEvent('recall', data);
}

// Remove a global resource
SynQ.snip = function(name, key) {
  name = name || SynQ.last_upload.pop();
  key = key || use_vpn_synq_token;

  ++SynQ[internal];
  SynQ.prevent(name, [undefined, null, ""], NO_NAME_ERROR, 'snip');

  var data = SynQ.get(name, key),
      name = SynQ.set(name, null, key);

  if(key != undefined && key != null)
    storage.removeItem('synq://localhost:443/' + name);
  else
    storage.removeItem('synq://localhost:80/' + name);

  return --SynQ[internal], SynQ.triggerEvent('snip', data);
};

/* Search, and like-wise helpers */
// Search for entries
SynQ.find = function(query, all, results) {
  results = results || [];

  if(/^synq:\/\/(\w+)\/\?/.test(query)) {
    var url = SynQ.parseURL(query),
        original = SynQ.signature,
        shadow = url.origin + '/',
        params = url.searchParameters;

    SynQ.shadow = shadow;
    results = SynQ.find(params.query, params.all);
    SynQ.shadow = null;

    return results;
  }

  if(query instanceof Array) {
    query.forEach(function(entry, index, array) {
      results.concat(SynQ.find(entry, all, results));
    });
    return results;
  }

  var owned = SynQ.list(all), test;

  if(query instanceof RegExp)
    test = function() { return query.test.call(query, arguments) };
  else
    test = function(string) { return string == (query += "") || !!~string.indexOf(query) };

  for(var entry in owned)
    if(!~results.indexOf(entry) && (test(entry) || test(owned[entry] + "")))
      results.push(entry);

  return results;
}

/* The space-oriented functions */
// Test data limits (in Bytes -> iB) or return an SI formated value
SynQ.size = function(number, base, symbol) {
  var backup = {},
      size   = function(n, b, s) {
        b = b || 1024;
        s = s || (n < 1024? 'b': 'iB');

        if(n < b && n > -b)
          for(var k = "m\u00b5npfaz", x = 0, g = k.length; (x < g) && (n < 1); x++)
            n *= b;
        else
          for(var k = "kMGTPEZY", x = 0, g = k.length; (x < g) && (n >= b); x++)
            n /= b;

        return n + (k[x - 1] || "") + s;
      },
      found;

  number = number || null;

  if((number == null || number == undefined))
    if(IE && use_cookie_synq_token == undefined) {
      for(var n in storage)
        backup[n] = storage[n];

      storage.clear();

      found = storage.remainingSpace | 0;

      for(var n in backup)
        storage[n] = backup[n];
    } else {
      for(var n in storage)
        backup[n] = storage[n];

      storage.clear();

      _1kiB: // 0 b - 1 kiB
      for(var s = "_", i = 1, j, l = 1024, p = true; p && i < l; i *= 2)
        try {
          storage.setItem("SizeTest", s.repeat(i));
        } catch(e) {
          p = false;

          break _1kiB;
        };

      _1MiB: // 1 kiB - 1 MiB
      for(j = l, l *= 1024; p && i < l; i *= 2)
        try {
          storage.setItem("SizeTest", s.repeat(i));
        } catch(e) {
          p = false;

          break _1MiB;
        };

      _1GiB: // 1 MiB - 1 GiB
      for(j = l, l *= 1024; p && i < l; i += j)
        try {
          storage.setItem("SizeTest", s.repeat(i));
        } catch(e) {
          p = false;

          break _1GiB;
        };

      storage.clear();

      for(var n in backup)
        storage[n] = backup[n];

      found = i;
    } // :defined number

  SynQ.size = function(number, base, symbol) {
    return (number == undefined || number == null)?
      SynQ.size.max | 0:
    SynQ.size.convert(+number, base, symbol)
  };

  SynQ.size.convert = size;
  SynQ.size.max = found *= 2;

  if(number != null)
    return SynQ.size(number, base, symbol);

  return found;
};

// How much space is in use?
SynQ.used = function(exclusive) {
  var size = 0,
      signature = SynQ.shadow || SynQ.signature;

  for(var item in storage)
    if(storage.hasOwnProperty(item))
      if(exclusive && RegExp(signature.replace(/(\W)/g, "\\$1")).test(item))
        size += storage[item].length | 0;
      else if(!exclusive)
        size += storage[item].length | 0;

  return size * 2;
};

// Return a number from an SI formatted string
SynQ.parseSize = function(size, base, symbol) {
  var e = "";

  base = base || 1024;
  symbol = symbol || (+size < 1024? 'b': 'iB');
  size = (size || e)
    .replace(/^\s*([\d\. ]+[zafpn\u00b5mkMGTPEZY]|[\d\., ]+).*/, "$1")
    .replace(/[^\w\.]/g, e)
    .replace(symbol, e)
    .replace(/(\d+)?(\.\d+)?/, function($0, $1, $2, $_) {
      $1 = $1 || e; $2 = $2 || e;
      return $1 + $2.replace(/\./g, e);
    });

  var sizes = "zafpn\u00b5m kMGTPEZY",
      tail  = size.replace((size = parseInt(size)), e);

  return size * Math.pow(base, sizes.indexOf(tail) - 7);
};

/* The "security" oritned functions */
// Lock and unlock data (weak security)
SynQ.lock = function(data, key) {
  data = data || "";
  key = SynQ.salt(SynQ.sign(key, 0));

  for(var index = 0, salted = []; index < data.length; index++)
    salted.push(String.fromCharCode(
      data.charCodeAt(index) ^ key.charCodeAt(index % 256)
    ));

  return salted.join("");
};

SynQ.unlock = SynQ.lock;

// KSA algorithm
SynQ.salt = function(text) {
  for(var index = 0, exdex = 0, swap = 0, salted = [], text = text || ""; index < 256; index++)
    salted[index] = index;

  for(index = 0; index < 256; index++)
    exdex = (exdex + salted[index] + text.charCodeAt(index % text.length)) % 256,
    salted[swap]  = salted[index],
    salted[index] = salted[exdex],
    salted[exdex] = salted[swap];

  for(index = 0; index < 256; index++)
    salted[index] = String.fromCharCode( salted[index] );

  return salted.join("");
};

// The hash/signature function (from Mi/o, by me)
SynQ.sign = function(string, fidelity) {
  var array = (string + "").split(/([^]{16})/),
      gamma = 0,
      method;

  fidelity = 18 - (((fidelity || 0) * 16) | 0);

  method = function(s) {
    return s? s.charCodeAt(0): s;
  };

  array.forEach(function(value, index, self) {
    return (value == "")?
      self.splice(index, 1):
    gamma += value.charCodeAt(0);
  });

  for(var index = 0, length = array.length, last = length - 1, result = []; index < length; index++)
    for(var self = array[index], next = (array[index + 1] || ""), mirror = array[last], a, b, c, d, e, f, g = gamma, i = 0, j = self.length, k = mirror.length, l = length, m = k - 1, q = fidelity; i < j; ++i, --m, g = gamma += a + b + c + d + e + f)
      a = method(self[i])         | 0,
      b = method(self[j - i - 1]) | 0,
      c = method(mirror[m])       | 0,
      d = method(mirror[k - m])   | 0,
      e = method(next[i])         | 0,
      f = method(next[m])         | 0,
      result.push(Math.abs(
        (((a ^ ~b) << (i + k)) |  (j & e) | g) ^
        (((b | -c) ^  (m + j)) |  (j & f) | g) ^
        (((c & ~d) << (e - k)) >> (k ^ q) + g) ^
        (((d << a) ^  (f - j)) >> (k ^ q) + g) ^

        ((a & b | c ^ d) ^ e - f) << (q & e & f)
      ));

  result.splice(fidelity, result.length - fidelity);

  result.forEach(function(value, index, self) {
    return self.splice(index, 1, (value ^ gamma).toString((gamma % 20) + 16));
  });

  return result.join("").slice(0, 256);
};

/* Helpers under SynQ */
// Parse a function (returns a "head" and "body")
SynQ.parseFunction = function(fn) {
  SynQ.prevent(fn, [undefined, null, ""], "Failed to parse empty function", "parseFunction");

  fn = fn.toString().replace(/(?:\bfunction(\s+[a-zA-Z\$_]\w*)?)?\s*(\(.*?\))\s*(\{[^]*\})/, "$2 => $3");

  var name = (RegExp.$1 || "").replace(/\s+/g, "");

  fn = fn.split(/\s*\=>\s*/, 2);

  return [fn[0].replace(/^\(|\)$/g, ""), fn[1].replace(/^\{|\}$/g, ""), name];
};

// Parse all URL types (even unconventional ones)
SynQ.parseURL = function(url) {
  if(url == undefined || url == null)
    return {};

    var url  = url.toString(),
        data = url.match(/^((([^:\/?#]+):)?(?:\/{2})?)(?:([^:]+):([^@]+)@)?(([^:\/?#]*)?(?:\:(\d+))?)?([^?#]*)(\?[^#]*)?(#.*)?$/),
        i    = 0,
        e    = "";

  data = data || e;

    return {
        href:             data[i++] || e,
        origin:           (data[i++] + data[i + 4]) || e,
        protocol:         data[i++] || e,
        scheme:           data[i++] || e,
        username:         data[i++] || e,
        password:         data[i++] || e,
        host:             data[i++] || e,
        hostname:         data[i++] || e,
        port:             data[i++] || e,
        pathname:         data[i++] || e,
        search:           data[i++] || e,
        searchParameters: (function(sd) {
          parsing:
          for(var i = 0, s = {}, e = "", d = sd.slice(1, sd.length).split('&'), n, p, c; sd != e && i < d.length; i++) {
            c = d[i].split('=');
            n = c[0] || e;

            p = c.slice(1, c.length).join('=');

            s[n] = (s[n] != undefined)?
              s[n] instanceof Array?
            s[n].concat(p):
              [s[n], p]:
            p;
          }

          return s;
        })(data[i - 1] || e),
        hash:             data[i++] || e
    };
};

// Handle errors
SynQ.prevent = function(variable, failures, message, helper) {
  function prevent(a, b, c, d) {
    if(a == b)
      throw new Error(c + (d? ", please see SynQ.help('" + d + "').": "."));
  };

  // Array, *, *
  if(variable instanceof Array)
    for(var index = 0, length = variable.length; index < length; index++)
      SynQ.prevent(variable[index], failures, message, helper);
  // *, Function, *
  else if(failures instanceof RegExp)
    prevent(failures.test(variable), true, message, helper);
  // *, Array, *
  else if(failures instanceof Array)
    for(var index = 0, length = failures.length; index < length; index++)
      prevent(variable, failures[index], message, helper);
};

/* Data oriented functions */
// Pack UTF8 characters
SynQ.pack = function(string) {
  for(var index = 0, length = string.length, array = []; index < length;)
    array.push(SynQ.pack16(string[index++], string[index++]));

  return array.join("");
}

// Unpack UTF16 characters
SynQ.unpack = function(string) {
  for(var index = 0, length = string.length, array = [], data = []; index < length;)
    array.push(SynQ.unpack16(string[index++]));

  for(array = array.join("").split(/([01]{8})/), index = 0, length = array.length; index < length; index++)
    if(array[index] != "")
      data.push(String.fromCharCode(+("0b" + array[index])));

  return data.join("");
}

// Pack UTF8 characters (helper)
SynQ.pack16 = function(a, b) {
  var s = function(c) {return ("00000000" + c.charCodeAt(0).toString(2)).slice(-8)};
  return String.fromCharCode(+("0b" + s(a) + (b? s(b): "")));
};

// Unpack UTF16 characters (helper)
SynQ.unpack16 = function(a) {
  var b, s = function(c) {return (((b = c.charCodeAt(0)) < 0xff? "": "00000000") + b.toString(2)).slice(-16)};
  return s(a);
};

// Stringify objects
var JSON, Symbol,
    Map, WeakMap, Set, WeakSet,
    Int8Array, Int16Array, Int32Array,
    Uint8Array, Uint8ClampedArray, Uint16Array, Uint32Array,
    Float32Array, Float64Array;

SynQ.deflate =
// (JSON && JSON.stringify)?
//   JSON.stringify:
function(object, filter, space, indent) {
  var pack = SynQ.deflate,
      json = [],
      blacklist = [],
      list = [],
      max = 10,
      filterfn,
      ltypes = [Boolean, Number, String],
      atypes = [Array, Map, Set, WeakMap, WeakSet],
      otypes = [Object, Int8Array, Int16Array, Int32Array, Uint8Array, Uint8ClampedArray, Uint16Array, Uint32Array, Float32Array, Float64Array],
      type = (object && !!~atypes.indexOf(object.constructor))?
        '[]':
      (object && !!~otypes.indexOf(object.constructor))?
        '{}':
      (object && typeof object == 'object' && 'toJSON' in object)?
        '""':
      '';

  if(object === undefined || object === null || !!~ltypes.indexOf(object.constructor))
    return ((object && object.constructor == String)?
      '"' + object.replace(/\\/g, '\\\\') + '"':
    (object !== undefined && object !== null && (object.constructor == Boolean || (object.constructor == Number && (object.valueOf() < Infinity && object.valueOf() > -Infinity))))?
      object:
    null) + '';

  filter = filter || function(key, value) { return value };
  space = space || '';
  indent = indent || space.length;
  space = ((typeof space == 'number')?
    '\t'.repeat(space):
  space).slice(0, max);

  function format(string, data) {
    if(!filterfn(data.key, data.value))
      return '';

    for(var regexp = /#\{(\w+)\}/; regexp.test(string);)
      string = string.replace(regexp, function($0, $1, $$, $_) {
        if(data.string && data[$1].constructor == String)
          return data[$1].replace(/[\\"]/g, '\\$&').replace(/\n/g, '\\n').replace(/\r/g, '\\r');
        return data[$1];
      });

    return space + string.replace(/\:\s+/, space? ': ': ':');
  }

  if(!!~atypes.indexOf(filter.constructor))
    filterfn = function(key, value) { return !!~filter.indexOf(key) };
  else if(filter instanceof Function)
    filterfn = filter;
  else
    filterfn = function(key, value) { return value };

  if(!!~atypes.indexOf(object.constructor))
    for(var data, index = 0, length = object.length | 0; index < length; index++)
      json.push(format('#{value}', { value: pack(object[index], filter, space) }));
  else if('toJSON' in object)
    json.push(format('#{value}', { key: 'toJSON', value: object.toJSON() })),
    type = '';
  else serializing:
    for(var key in object) {
      var value = object[key];

      if(value == object || !!~blacklist.indexOf(key)) {
        blacklist.push(key);
        continue serializing;
      }

      if(value === undefined || value === null || value.constructor == Function || value.constructor == Symbol)
        json.push(format('"#{key}": null', { key: key, value: value }));
      else if(value.constructor == RegExp)
        json.push(format('"#{key}": #{value}', { key: key, value: pack(value.source + '$=' + value.flags, filter, space) }));
      else if(value.constructor == String)
        json.push(format('"#{key}": "#{value}"', { key: key, value: value, string: true }));
      else if(!!~ltypes.indexOf(value.constructor))
        json.push(format('"#{key}": #{value}', { key: key, value: value }));
      else if(!!~atypes.indexOf(value.constructor))
        json.push(format('"#{key}": #{value}', { key: key, value: pack(value, filter, space) }));
      else if(!!~otypes.indexOf(value.constructor))
        json.push(format('"#{key}": #{value}', { key: key, value: pack(value, filter, space + space, space.length) }));
      else if(/^synq\:\/\//.test(key))
        if(!key.indexOf(SynQ.signature))
          json.push(format('"#{key}": "#{value}"', { key: key, value: value, string: true }));
        else
          /* foreign SynQ token */;
      else if(value instanceof Object && !value instanceof Function)
        json.push(format('"#{key}": #{value}', { key: key, value: pack(value = Object.assign(value, {constructor: Object}), filter, space, space.length) }));
      else if(value instanceof Object)
        json.push(format('"#{key}": #{value}', { key: key, value: '{}' }));
      else
        json.push(format('"#{key}": "#{value}"', { key: key, value: value, string: true }));
    }

  var head = (type[0] || '') + (space? '\n': ''),
      tail = (space? '\n' + space.slice(indent, space.length): '') + (type[1] || '');

  function trim(array) {
    for(var index = 0, length = json.length; index < length; index++)
      if(array[index] == '' || array[index] == undefined)
        array.splice(index, 1);

    return array;
  }

  for(var index = 0; index < max && !~json.indexOf(undefined); index++)
    trim(json);

  return (head + json.join(',' + (space? '\n': '')) + tail).replace(/\{\s*\}/g, '{}').replace(/(".+?"\:\s*)undefined\b/g, '$1null');
};

// Parse JSON strings
SynQ.inflate = function(string, mutator) {
  var object, R = RegExp, regexp,
      parse = SynQ.inflate,
      type =
      /^\{[^]*\}$/.test(string)?
        'object':
      /^\[[^]*\]$/.test(string)?
        'array':
      'literal';

  mutator = mutator || function(key, value) { return value };

  switch(type) {
    case 'object':
      object = {};
      if(/\{\s*(?:,\s*)?\}/.test(string))
        break;
      else
        for(var regexp = /\{([^]*)\}/, string = string.replace(/^\{/, '^').replace(/\}$/, '$'), dummy; regexp.test(string);)
          string = string.replace(regexp, function($0, $1, $$, $_) {
            for(var layer = 0, index = 0; layer >= 0 && index < $1.length; index++)
              layer += $1[index] == '{'? 1: $1[index] == '}'? -1: 0;
            index -= +(layer < 0);
            return (dummy = $1.split('')).splice(index, 1, ')@'), dummy = dummy.join(''),
              '@(' + dummy.slice(0, index).replace(/\{/g, '#(').replace(/\}/g, ')#') + dummy.slice(index, dummy.length) + (layer < 0? '}': '');
          });
      string = string.replace(/#\(/g, '{').replace(/\)#/g, '}').replace(/@\(/, '{').replace(/\)@/, '}');

      string
        .split(/\s*("(?:[^\\"]*?|\\.)"\s*\:\s*(?:null|true|false|\d+|"(?:[^\\"]*?|\\.)"|\[[^]*\]|\{[^]*\}|@\([^]*?\)@))(?=\s*,|(?:\s*,)?\s*\$\s*$)/)
        .map(function(value) {
          if(/^([\{\s,\}]+|[\^\$])$/.test(value = value.replace(/@\(/g, '{').replace(/\)@/g, '}')) || /^\^|\$$/.test(value)) return;

          value.replace(/\s*"([^\\"]*?|\\.)"\s*\:\s*(null|true|false|\d+|"(?:[^\\"]*?|\\.)"|\[[^]*\]|\{[^]*\})/);
          return (R.$2 == "")?
            "":
          object[R.$1] = mutator(R.$1, parse(R.$2.replace(/^\^|\$$/g, ''), mutator));
        });
      break;

    case 'array':
      object = [];
      if(/\[\s*(?:,\s*)?\]/.test(string))
        break;
      else
        for(var regexp = /\[([^]*)\]/, string = string.replace(/^\[/, '^').replace(/\]$/, '$'), dummy; regexp.test(string);)
          string = string.replace(regexp, function($0, $1, $$, $_) {
            for(var layer = 0, index = 0; layer >= 0 && index < $1.length; index++)
              layer += $1[index] == '['? 1: $1[index] == ']'? -1: 0;
            index -= +(layer < 0);
            return (dummy = $1.split('')).splice(index, 1, ')@'), dummy = dummy.join(''),
              '@(' + dummy.slice(0, index).replace(/\[/g, '#(').replace(/\]/g, ')#') + dummy.slice(index, dummy.length) + (layer < 0? ']': '');
          });
      string = string.replace(/#\(/g, '[').replace(/\)#/g, ']').replace(/@\(/, '[').replace(/\)@/, ']');

      var index = 0;
      string
        .split(/\s*(null|true|false|\d+|"(?:[^\\"]*?|\\.)"|\[[^]*\]|\{[^]*\}|@\([^]*?\)@)(?=\s*,|(?:\s*,)?\s*\$\s*$)/)
        .map(function(value) {
          if(/^([\[\s,\]]+|[\^\$])$/.test(value = value.replace(/@\(/g, '[').replace(/\)@/g, ']')) || /^\^|\$$/.test(value)) return;

          object.push(mutator(index++, parse(value.replace(/^\^|\$$/g, ''), mutator)));
        });
      break;

    case 'literal':
    default:
      object = /^"(.*)"$/.test(string)? R.$1: +string <= +Infinity? +string: string === "null"? null: string === "true";
      break;
  }

  return object;
};

// Help
SynQ.help = function(item) {
  if(item == undefined || item == null)
    item = "help";

  item = item.replace(/[^a-z\d]|synq([\.\-]|_token)/gi, "");

  var m, i = item.toLowerCase();

  switch(i) {
    /* HTML */
    case 'attr':
      m = "Synchronizes an element's attributes. The list should be space separated./~Usage: <% $-@=attributes-to-sync>...<\\%>/~Interpreted Type: Array//$-@: defaults to all attributes if no value is given."
      break;

    case 'data':
      m = "Synchronizes an element's value, or innerText (priority to value)./~Usage: <% $-@>...<\\%>/~Interpreted Type: Boolean"
      break;

    case 'host':
      m = "Creates a main object (for multiple frames), and is given the highest priority. Also sets the element's [NAME] to its [ID], or [SYNQ-UUID]./~Usage: <% $-@=host-name>...<\\%>/~Interpreted Type: String"
      break;

    case 'html':
      m = "Synchronizes an element's outerHTML./~Usage: <% $-@>...<\\%>/~Interpreted Type: Boolean"
      break;

    case 'skip':
      m = "Delays synchronizing an element. Especially useful for multiple IFRAMEs with access to the parent document./~Usage: <% $-@=number-of-delays>...<\\%>/~Interpreted Type: Number//$-@: defaults to 0 if no value is given."
      break;

    case 'text':
      m = "Synchronizes an element's innerHTML./~Usage: <% $-@>...<\\%>/~Interpreted Type: Boolean"
      break;

    case 'uuid':
      m = "The UUID that $ generates for each synchronized element./~Usage: <% $-@=static-uuid>...<\\%>/~Interpreted Type: String//$-@: if you set [$-@], all copies of the element (including across frames) will need to have the same value. Otherwise, SynQ will handle this assignment automatically."
      break;

    /* JS */
    case 'addeventlistener':
      m = "Adds an event listener to $'s {events} method./~Usage: $.@(event-name, callback)/~Arguments: String, Function/~Returns: Number//event-name: {events}./return: the number of events attached."
      break;

    case 'append':
      m = "Pushes data to a global array./~Usage: $.@(array-name, data[, key[, delimiter]])/~Arguments: String, String[, String[, String]]/~Returns: <array-name>//key: {key}."
      break;

    case 'clear':
      m = "Removes all owned items from storage (related to $)./~Usage: $.@([remove-all])/~Arguments: [Boolean]/~Returns: Undefined//remove-all: if set to true, will remove all private items too."
      break;

    case 'decodeurl':
      m = "Decodes a URL string (e.g. '%20' -> ' ')./~Usage: $.@(URL)/~Arguments: String/~Returns: String"
      break;

    case 'deflate':
      m = "Polyfill of JSON.stringify. Defaltes\\serializes objects (turns them into strings)./~Usage: $.@(object[, filter[, spaces]])/~Arguments: *[, Function[, String | Number]]/~Returns: String => '<object>'//object: any JavaScript object./filter: searches for true\\non-empty entries. Called on as:/~for(var key in <object>)/~~<filter>(key, <object>[key]);//spaces: if set, then the ouput will be stylised using indentation."
      break;

    case 'download':
      m = "Retruns data from the global storage item (see also, '$.get')./~Usage: $.@(name[, key])/~Arguments: String[, String]/~Returns: String//key: {key}."
      break;

    case 'encodeurl':
      m = "Encodes a URL string (e.g. ' ' -> '%20')./~Usage: $.@(URL)/~Arguments: String/~Returns: String"
      break;

    case 'esc':
      m = "The list delimeter for $ to use when storing element values./~Usage: $.@ = delimeter/~Types: String/~Current: '{esc}'/~Default: '%%'"
      break;

    case 'eventlistener':
      m = "The Event Listener for $ (fires automatically from $)./~Usage: $.@(event)/~Arguments: Object/~Returns: Undefined"
      break;

    case 'find':
      m = "Searches $ for the given item(s). Can also traverse foreign (unowned) entries./~Usage: $.@(query[, search-private[, previous-finds]])/~Arguments: Array | RegExp | String[, Boolean[, Array]]//query: if you have a $ URL to another site (verbatim), you can search its entries via:/~synq:{uuid}\\?auth=<BtoA {username}:{password}>&all=<search-private>&query=<query>&query=...//previous-finds: used to prevent $ from duplicating entries/URL => auth: btoa(username + ':' + password), only used for VPN searches, where 'password' is the original key (before being signed)"
      break;

    case 'get':
      m = "Returns data from the local storage item./~Usage: $.@(name[, key])/~Arguments: String[, String]/~Returns: String//key: {key}."
      break;

    case 'help':
      m = "Displays help messages./~Usage: $.@(item-name)/~Arguments: String/~Returns: String"
      break;

    case 'inflate':
      m = "Polyfill of JSON.parse. Inflates\\deserializes strings (turns them into objects)./~Usage: $.@(json-string[, mutator])/~Arguments: String[, Function]/~Returns: Array | Boolean | Object | Number | null | undefined => <object>//string: a JSON compliant string./mutator: mutates each entry. Called on as:/~for(var key in <object>)/~~<mutator>(key, <object>[key]);"
      break;

    case 'isnan':
      m = "Tests to see if an object is a number or not./~Usage: @(object)/~Arguments: */~Returns: Boolean"
      break;

    case 'last':
      m = "An array that's used to hold each item's name in the order they're created./~Usage: $.@ = ['name-1', 'name-2'...]/~Types: Array"
      break;

    case 'lastupload':
      m = "An array that's used to hold each item's name in the order they're created./~Usage: $.@ = ['name-1', 'name-2'...]/~Types: Array"
      break;

    case 'list':
      m = "Returns the currently owned storage items./~Usage: $.@([show-all])/~Arguments: Boolean/~Returns: Object//show-all: when set to true, will return private items as well."
      break;

    case 'lock':
    case 'unlock':
      m = "Locks and unlocks a string./~Usage: $.@(data, key)/~Arguments: String, String/~Returns: String"
      break;

    case 'pack':
      m = "Packs (encodes) a UTF-8 string into UTF-16 characters./~Usage: $.@(string)/~Arguments: String/~Return: String => UTF16"
      break;

    case 'pack16':
      m = "Packs (encodes) a UTF-16 character, by using two UTF-8 characters./~Usage: $.@(character[, character])/~Arguments: Character[, Character]/~Returns: String//return: if the second character is missing, then the first character will be returned."
      break;

    case 'parsefunction':
      m = "Returns an array of function data./~Usage: $.@(function-string)/~Arguments: String/~Returns: Array => {0: [function parameters], 1: [function statements], 2: [function name], length: 3}"
      break;

    case 'parsesize':
      m = "Returns a number from an SI formatted* string./~Usage: $.@(number[, base[, symbol]])/~Arguments: String[, Number[, String]]/~Returns: Number//* Does not recognize 'd' (deci), 'h' (hecto) or 'c' (centi)"
      break;

    case 'parseurl':
      m = "Returns a URL object./~Usage: $.@(URL)/~Arguments: String/~Returns: Object => {href, origin, protocol, scheme, username, password, host, port, path, search, searchParameters, hash}"
      break;

    case 'ping':
      m = "Pings an address. If no address is given, then pings a random address. Powered by Lorem Picsum (https:picsum.photos)./~Usage: $.@(address[, options])/~Arguments: String[, Object => {callback, pass, fail, timeout}]/~Returns: Undefined//address: must be an address to an image./return: calls on <callback> using: <callback>.call(null, ping.trip);//ping.trip => {/~address: <address>/~resolve: [image address]/~size: [image height * image.width]/~speed: [image size \\ time]/~status: 'pass' | 'fail'/~time: [ping time]/~uplink: [speed \\ 2]/}"
      break;

    case 'pop':
      m = "Removes, and returns the item from the local storage./~Usage: $.@([name[, key]])/~Argumments: [String[, String]]/~Returns: String//name: the name of the item to fetch. If left empty, will use the name of the last item created./key: {key}."
      break;

    case 'prevent':
      m = "Used to prevent a value from being used./~Usage: $.@(value-to-test, illegal-values, error-message[, helper-link])/~Arguments: Array | String, Array | RegExp, String[, String]/~Returns: Undefined/~Throws: Error(<message[ + helper-link]>)//helper-link: the word, or phrase used by $.help to display the help message,/~~e.g. $.prevent($.doesNotExist, [null, undefined], 'This is an example error', 'example')/~~throws Error => 'This is an eample error, see $.help('example')'."
      break;

    case 'pull':
      m = "Returns data from a local storage array./~Usage: $.@(array-name[, key[, delimiter]])/~Arguments: String[, String[, String]]/~Returns: Array//key: {key}"
      break;

    case 'push':
      m = "Pushes data to a local storage array (delimited by $.esc)./~Usage: $.@(array-name, data[, key])/~Arguments: String, String[, String]/~Returns: String<array-name>//key: {key}"
      break;

    case 'recall':
      m = "Gets data from a global array (see also, '$.pull')./~Usage: $.@(array-name[, key[, delimiter]])/~Arguments: String[, String[, String]]/~Returns: Array//key: {key}"
      break;

    case 'removeeventlistener':
      m = "Removes a(n) event listener(s)./~Usage: $.@(function-name[, event-name])/~Arguments: String[, String]/~Returns: Array | String//event-name: {events}./~If left empty, will remove <function-name> from every event."
      break;

    case 'salt':
      m = "Salts (encrypts) a string, usually a password./~Usage: $.@(string)/~Arguments: String/~Returns: String"
      break;

    case 'set':
      m = "Adds the item to storage./~Usage: $.@(name, data[, key])/~Arguments: String, String[, String]/~Returns: <name>//key: {key}."
      break;

    case 'sign':
      m = "Hashes a string (think of SHA, or MD5)./~Usage: $.@(string[, fidelity-level])/~Arguments: String[, Float]/~Returns: String//fidelity-level: determines the size of the returned string. The closer to 1 the level is, the shorter the string."
      break;

    case 'signature':
      m = "The UUID of the current page (if use_global# is undefined), or current domain.//Current Signature: {signature}/Global Token Flag: {global#}"
      break;

    case 'size':
      m = "1. Returns the maximum amount of space for the storage (in bytes; 1B = 8b)/~Usage: $.@()/~Arguments: NONE/~Returns: Integer//2. Returns the SI formatted version of the given number./~Usage: $.@(number[, base[, symbol]])/~Arguments: Number[, Number[, String]]/~Returns: String//base: the base to use, e.g. 1000; default is 1024./symbol: the symbol to append to the returned string, default is 'iB'."
      break;

    case 'snip':
      m = "Removes, and returns the item from the global storage (see also, '$.pop')./~Usage: $.@(name[, key])/~Arguments: String[, String]/~Returns: String//key: {key}."
      break;

    case 'syn':
      m = "The attribute name(s) for elements to update./~Usage: $.@ = ['name-1', 'name-2'...]/~Types: Array | String/~Default: {syn}"
      break;

    case 'synq':
      m = "The main function and container. Updates the storage, while also updating all 'attached' elements./~Usage: $([attribute-names])/~Arguments: String | Array/~Returns: Undefined//attribute-name: if you want to use multiple names, you can also set $.syn"
      break;

    case 'triggerevent':
      m = "Triggers all event listeners for an event./~Usage: $.@(event-name[, data])/~Arguments: String[, Array]/~Returns: <data>//data: the arguments to pass onto each listener."
      break;

    case 'unpack':
      m = "Unacks (decodes) a UTF-16 string into UTF-8 characters./~Usage: $.@(string)/~Arguments: String/~Return: String => {UTF8}"
      break;

    case 'unpack16':
      m = "Unpacks (decodes) a UTF-16 character into two UTF-8 characters./~Usage: $.@(character)/~Arguments: Character/~Returns: String//return: automatically handles UTF-8 characters, and returns the character iteslf."
      break;

    case 'upload':
      m = "Adds data to global storage (see also, '$.set')./~Usage: $.@(name[, data[, key]])/~Arguments: String[, String[, String]]/~Returns: String//return: a UUID for the data./data: if no data is given, still returns the UUID./key: {key}."
      break;

    case 'used':
      m = "Returns the number of bytes (1B = 8b) in use./~Usage: $.@([$-only])/~Arguments: [Boolean]/~Returns: Integer//$-only: when set to true, will ony return the amount of owned space $ is using."
      break;

    case 'usecookie':
      m = "Forces the page to use cookies instead of the localStorage./This may increase storage capcity on some browsers*, but not all. See the table below.//Browser (version)/~UTF-16 \\ UTF-8//Chrome (65.0.3325.181)/~22 \\ 44 MiB/Firefox (59.0.2)/~22 \\ 44 MiB/Opera (52.0.2871.40)/~22 \\ 44 MiB/Safari (7534.57.2)**/~22 \\ 44 B/Edge (41.16299.248.0)/~22 \\ 44 MiB/Internet Explorer (11.309.16299.0)**/~32 \\ 64 B//* Obtained values by hand (Windows 10 PC, x64)./** Note that this browser wasn't intended for my machine. Also, the cookie size can be changed by the user."
      break;

    case 'useuuid':
      m = "TODO!Forces $ to use the assigned value as the 'UUID.'/This can be useful for dynamic pages that change their name often (like CodePen's debug feature), but still need a static ID.//Basically, a manual, selective version of 'global#'"
      break;

    case 'useglobal':
      m = "Used to determine if $ should use a local* or global** name.//* $ will save all data for the current URL only, i.e. http:github.com\\page-1 will not have access to http:github.com\\page-2./** $ will save all data for the current host, i.e. http:github.com will be used by $, instead of http:github.com\\page-n."
      break;

    case 'useutf16':
      m = "Used to instruct $ to save data as UTF-16 streams, e.g. 'acdf' will be combined into 'be' (as an example)./It does this by combining UTF-8 characters (\u0000 - \u00ff), and generating a UTF-16 character (\u0100 - \uffff)."
      break;

    case 'usevpn':
      m = "Forces $ to use a VPN-like setup with a 'private' session. This uses sessionStorage; a one-time, non-iterable signature; and a forced local state./~Usage: vpn# = <value>/~Interpreted Type: String"
      break;

    case '':
    case '*':
      m = "Help can be used for the following items://<!-- HTML -->//$-attr/$-data/$-host/$-html/$-skip/$-text/$-uuid//\\* JavaScript *\\//ping/$/~addEventListener/~append - Global push/~clear/~decodeURL/~deflate/~download - Global get/~enocdeURL/~esc/~eventlistener/~find/~get/~help/~host/~inflate/~last/~list/~lock/~pack/~pack16/~parseFunction/~parseSize/~parseURL/~pop/~prevent/~pull/~push/~recall - Global pull/~removeEventListener/~salt/~set/~sign/~signature/~size/~snip - Global pop/~syn/~triggerEvent/~unlock/~unpack/~unpack16/~upload - Global set/~used/cookie#/global#/utf16#/uuid#/vpn#"
      break;

    default:
      m = "Sorry, couldn't find '@'; try $.help('*') to list all items that have help messages."
      break;
  }

  m = ("/" + m + "/")
    .replace(/TODO!/, "This feature (@) is not yet ready, but is planned for future releases./Please note that the documentation for '@' is not final, and may change or be removed.//")
    .replace(/\//g, "\n")
    .replace(/~/g, "\t")
    .replace(/\\/g, "/")
    .replace(/\$-/g, "synq-")
    .replace(/\$/g, "SynQ")
    .replace(/(?:use_?)?(\w+)#/g, "use_$1_synq_token")
    .replace(/%/g, "element")
    .replace(/@/g, item)
    .replace(/(https?|synq)\:/g, "$1://")
    .replace(/(\w+\s+\|(?:[\w \|]+?))( ?[^\w |])/g, '($1)$2')
    .replace(/\B'([^']+?)'\B/g, '"$1"')
    .replace(/\{key\}/gi, "the password to lock/unlock the data with")
    .replace(/\{events\}/gi, SynQ.events.split(' ').join(', ').replace(/(.+),\s*(.+?)$/, "$1, or $2"))
    .replace(/\{syn\}/gi, '["' + SynQ.syn.join('","') + '"]');

  for(var r = /\{(\w+?)\}/, e = [], i = 0; r.test(m) && !~e.indexOf(RegExp["$&"]);)
    m = m.replace(r, function($0, $1, $$, $_) {
      return ($1 in SynQ)? SynQ[$1]: ($1 in window)? window[$1]: e[i++] = $0;
    });

  return m;
};

/* Polyfills */
// localStorage - Mozilla
if(!("localStorage" in window) || (use_cookie_synq_token != undefined && !SA))
  Object.defineProperty(window, "localStorage", new(function() {
    var keys          = [],
        StorageObject = {},
        onstorage     = new CustomEvent("storage", {bubbles: false, cancelable: false, composed: true});

    Object.defineProperty(StorageObject, "getItem", {
      value: function(key) {
        return (key)?
          this[key]:
        null;
      },
      writable:     false,
      configurable: false,
      enumerable:   false
    });

    Object.defineProperty(StorageObject, "key", {
      value: function(keyID) {
        return keys[keyID];
      },
      writable:     false,
      configurable: false,
      enumerable:   false
    });

    Object.defineProperty(StorageObject, "setItem", {
      value: function(key, value) {
        if(key == undefined || key == null)
          return;

        document.cookie = escape(key) + "=" + escape(value) + ";expires=Thu, Dec 31 2099 23:59:59 GMT;path=/";
        window.dispatchEvent(onstorage);
      },
      writable:     false,
      configurable: false,
      enumerable:   false
    });

    Object.defineProperty(StorageObject, "length", {
      get: function() {
        return keys.length;
      },
      configurable: false,
      enumerable:   false
    });

    Object.defineProperty(StorageObject, "removeItem", {
      value: function(key) {
        if(key == undefined || key == null)
          return;

        document.cookie = escape(key) + "=;expires=Thu, 01 Jan 1970 00:00:00 GMT;path=/";
        window.dispatchEvent(onstorage);
      },
      writable:     false,
      configurable: false,
      enumerable:   false
    });

    Object.defineProperty(StorageObject, "clear", {
      value: function() {
        if(keys.length == undefined || keys.length == null)
          return;

        for(var key in keys)
          document.cookie = escape(key) + "=;expires=Thu, 01 Jan 1970 00:00:00 GMT;path=/";

        window.dispatchEvent(onstorage);
      },
      writable:     false,
      configurable: false,
      enumerable:   false
    });

    Object.defineProperty(StorageObject, "type", {
      value:        'cookie',
      writable:     false,
      configurable: false,
      enumerable:   false
    });

    this.get = function() {
      var index;

      for(var key in StorageObject) {
        index = keys.indexOf(key);
        if(index == -1)
          StorageObject.setItem(key, StorageObject[key]);
        else
          keys.splice(index, 1);
        delete StorageObject[key];
      }

      for(keys; keys.length > 0; keys.splice(0, 1))
        StorageObject.removeItem(keys[0]);

      for(var cookie, key, index = 0, cookies = document.cookie.split(/\s*;\s*/); index < cookies.length; index++) {
        cookie = cookies[index].split(/\s*=\s*/);
        if(cookie.length > 1)
          key = unescape(cookie[0]),
          StorageObject[key] = unescape(cookie[1]),
          keys.push(key);
      }

      return StorageObject;
    };

    this.configurable = false;
    this.enumerable   = true;
  })());

storage = (use_vpn_synq_token == undefined)?
  window.localStorage:
window.sessionStorage || window.localStorage;

// navigator.connection - Mozilla, Ephellon
if(!("connection" in navigator))
  Object.defineProperty(window, "NetworkInformation", new(function() {
    var keys            = [],
        NetworkObject   = {},
        onnetwork       = new CustomEvent("online", {bubbles: false, cancelable: false, composed: true});

    ping("", {
      callback: function(TripInformation) {
        var k = 1000, M = k * k,
            t = TripInformation, s = t.speed, m = t.time,
            r = function(x, y) { return (x / y) - ((x / y) % y) };

        s = r(s, 25);
        m = r(m, 25);

        Object.defineProperty(NetworkObject, "downlink", {
          value:        s,
          writable:     false,
          configurable: false,
          enumerable:   true
        });

        Object.defineProperty(NetworkObject, "downlinkMax", {
          value:        s,
          writable:     false,
          configurable: false,
          enumerable:   true
        });

        Object.defineProperty(NetworkObject, "effectiveType", {
          value: (function(speed) {
            if(speed < 500)
              return '4g';
            if(speed < 500 * k)
              return '3g';
            if(speed < 500 * M)
              return '2g';
            return 'slow-2g';
          })(s),
          writable:     false,
          configurable: false,
          enumerable:   true
        });

        Object.defineProperty(NetworkObject, "onchange", {
          value:        null,
          writable:     true,
          configurable: false,
          enumerable:   true
        });

        Object.defineProperty(NetworkObject, "rtt", {
          value:        m,
          writable:     false,
          configurable: false,
          enumerable:   true
        });

        Object.defineProperty(NetworkObject, "saveData", {
          value:        false,
          writable:     true,
          configurable: false,
          enumerable:   true
        });

        Object.defineProperty(NetworkObject, "type", {
          value:        'unknown',
          writable:     false,
          configurable: false,
          enumerable:   true
        });
      }
    });

    this.get = function() {
      return NetworkObject;
    };

    this.configurable = false;
    this.enumerable   = true;
  })());

connection = navigator.connection;

/* Setup and auto-management */
// Auto-update & run
if(use_uuid_synq_token != undefined)
  Object.defineProperty(SynQ, "signature", {
    value: (use_uuid_synq_token + ""),
    writable: false,
    configurable: false,
    enumerable: true
  });
else if(use_vpn_synq_token != undefined)
  Object.defineProperty(SynQ, "signature", {
    value: "synq://" + SynQ.sign(+(new Date), 1) + ":" + (use_vpn_synq_token = SynQ.sign(use_vpn_synq_token, 0.75)) + "@" + SynQ.sign(location, 1) + ":443/",
    writable: false,
    configurable: false,
    enumerable: false
  });
else if(use_global_synq_token == undefined)
  Object.defineProperty(SynQ, "signature", {
    value: "synq://" + SynQ.sign(location, 1) + "/",
    writable: false,
    configurable: false,
    enumerable: true
  });
else
  Object.defineProperty(SynQ, "signature", {
    value: "synq://" + SynQ.sign(location.origin, 1) + "/",
    writable: false,
    configurable: false,
    enumerable: true
  });

SynQ.eventName = '.events';
SynQ.events = "set get pop push pull upload download snip append recall clear";
SynQ.last = [];
SynQ.last_upload = [];
SynQ.host = null;
SynQ.shadow = null;
SynQ[internal] |= 0;

SynQ.eventlistener();
window.addEventListener("storage", window.onstorage = SynQ.eventlistener, false);


Call for papers for Journal of General Virology's new collection: Arboviruses and their Vectors.
Following IMAV 2017, Journal of General Virology is inviting submissions of research papers and reviews for a new thematic collection on Arboviruses and their Vectors.
Curated by Journal of General Virology Editor, Eng Eong Ooi (Duke NUS Medical School) and Editorial Board Members Alain Kohl (University of Glasgow) and Esther Schnettler (Bernhard Nocht Institute for Tropical Medicine) the collection will present the latest advances in arbovirus research.
Authors should submit their manuscript to the online submission system for Journal of General Virology. Please indicate clearly in your cover letter that it is intended for the Arboviruses and their Vectors Collection.
To submit a review, authors should first contact the Reviews Editor via the journal's Editorial Office.
For more information, please contact the Editorial Office using the subject line 'Arboviruses and their Vectors Collection'.


Unlike natural cork, BBB's RaceRibbons BHT-05 Handlebar Tape is made of synthetic cork with a consistent quality throughout, with no weak points that can tear under heavy use. Each roll is long enough to completely wrap the handlebars. Available in different colours.


The Queensland Office of Fair Trading has warned consumers against doing business with online retailer Scott Dwyer and his collectable toy business, Premium Collectables.
Dwyer is alleged to have received $47,097 by way of deposits or full payment, for products he has not supplied.
The OFT is urging any consumers who have had similar dealings with Premium Collectables to contact them at www.qld.gov.au/fairtrading or call 13 QGOV (13 74 68).
Internet Retailing founder, Mark Freidin, chats with Scott Dwyer, owner of online retailer Premium Collectables.
Mark Freidin: Scott, have you always been in the collectables business, and how have you translated this to the web. How did you start out?
Scott Dwyer: Premium Collectables originally started in 2013 under the name Premium Collect.
I decided to leave the car fleet industry after five years in customer service roles. I saw it as an opportunity to onsell some of my own private collectables as well as onsell collectable items picked up at markets and auctions. I found this was only moderately successful with one major hurdle to selling this product type online — because most items on offer were either second hand or preserved for many years it did appear somewhat of a challenge to get commitments from online buyers to purchase high end items unsighted and by photos only. The one exception to this seemed to be toys, which I took more interest in over the course of trading as Premium Collect.
Following six months of intensive research and networking in Asia and North America new opportunities arose to look at a new direction. Due to extensive gaps for toy collectors in the Australian marketplace we identified products we now had means to import that were not presently being sold domestically.
In 2014 we rebranded and relaunched the business as Premiumcollectables.com.au, with a new focus on purely modern day toy collectors. Almost immediately we noticed a lot of attention being given to our website and almost disbelief that we were based in Australia.
We made our presence known in many fan forums, collector groups and social media, and on many occasions we asked our customers and potential consumers what they wanted to see in the toy industry for the 'adult' collector. We have ran fan polls and took feedback throughout the journey and pride ourselves on being able to offer a more complete suite of product for a collector than just the odd one or two pieces that may present elsewhere.
The other real part of our growth is what I think is a real appreciation from customers that we offer a proper loyalty program. One that almost immediately yields results the more the customer commitments to your brand. Late last year we also introduced a VIP program for very large buyers or what we see at Premium as the High End Collector Base, who essentially are buying 100 percent of merchandise through premium collectables.
MF: What web platform are you using and how do you manage your inventory and accounting?
SD: We tested a few platforms upon inception, but the final decision was Shopify, based on its very inclusive features that go beyond just a web shop and cart software. It has very solid inventory control for the plan we are on, which is a special plan for use only with high volume turnover business.
Our accounting software also integrates with our Shopify platform, by using quick books, seamless transfer from both platforms maintains time and money that can be dedicated to other tasks within the company.
I would also mention for our online payments, eWay Australia, who form the bridge between the customer buying in the cart and having funds drawn from the account from the bank. They have been a great partner over the three years we have been with them. They are prepeared to offer a professional industry leading secure product to small business start up and provide competitive priced services the larger you grow. Our incidents of online fraud and loss have been exceptionally low, accounting for only 1 per cent of total turnover over a three year period. The product they offer is industry leading and I would recommend any online business concerned about fraud and security to speak to eWay about the product they offer.
MF: How do you promote yourself to get traffic, signups, and conversions to your site?
SD: How we attract and continue to attract customers is where the real foundation of the success is for Premium Collectables. Maintaining a good standing in the Collectors Realm, embedding digital advertising in fan forums, groups and toy news websites are key ways to attract traffic our site that are looking to buy the products we sell.
We also have run many Facebook ad campaigns, maintain a heavy presence of Twitter and recently opened our Instagram account. We also have formed alliances with several toy reviewers with online video presence who feature our products and feature our store.
We have stayed well clear of traditional media, such as news print and radio, because we do not see that as the future or where we would see much growth with our core demographic of customers.
We do have some web video promotions due to start very soon which an exciting new direction for us that we still are keeping under wraps for now. We plan to announce in August what this new venture entails.
MF: What role does social media play in your business?
SD: I mentioned it already but it cannot be understated just how relevant or how big a part social media plays a part in the growth and direction the business takes. We owe so much to our foundation customers who first noticed us on social media and took the chance on a new player in the market and gave us the chance to win there business, the amount of positive feedback through the page and social media we get. I think plays a big part in how fast we moving up in this competitive market.
I think the fact we always pay close attention to what people say about our brand on social media, and really anytime we feel a customer has not had a positive experience we seek them out to obtain clarification as to why there experience was not as premium as it should be.
It is a very customer focused brand because social media is one of our largest pillars in where we stand and how we operate. I don't think we would even still be in the market , if not for our social media presence and support.
MF: What metrics do you look at on a regular basis?
SD: The basic metrics I look at are, where does our business do well, who is buying from us and where are they from?
We do look at what success rate we have when we receive a visitor to our page, and find one out of two either buy something or have intended to buy something. We find one out of five who leave without buying either come back to us again or after we send a reminder they left the store before the order was completed, come back and finalise it. So we do catch quite a few window shoppers as well with that feature.
Currently our demographic is 18-38 year old males — 80 per cent of our trade is from that group.
I am very passionate about seeing more female customers as I know there is a marketplace for those customers as well. You only need to visit Supanova etc to see there are many females who also find collectable toys a cool hobby, and that is one metric we want to change and are paying close attention too presently.
We also want to pursue our NZ market more. We have distribution licenses to sell into that market and are researching the best ways to promote our brand into the NZ market. We currently sell to only 15 per cent of our customers who are from NZ and with our very low shipping rates we offer this should really be much higher and we aim to make it so.
MF: What are Energon points, do they help build loyalty and return customers?
SD: Aside from social media, this does appear to be one of our biggest drawcards to bring people into the business. It is a rewards program that gives you discounts on orders in the future based on the amount you spend over time. The beauty of our program though is you do not just earn points by buying toys, we give points to customers who refer a new customer who places an order. We give points to customers who share our Facebook page via Facebook, our Twitter page via Twitter. We give points to customers on a adhoc basis who we see mention Premium Collectables in a positive way on a variety of forums on the internet.
So it really is a loyalty program that stays very true to the meaning of loyalty.
It may seem very generous as a program, but we are looking to build long term relationships with our base. Over time this equates to some very large sums of money being offloaded by our collectors solely with Premium. So it is very much here to stay as it has contributed a lot to our growth and customer appreciation.
MF: How has Zippay helped grow the business? Is there a difference in cart size for Zippay customers compared to normal checkouts?
SD: Whereas our bank (NAB) has been of no help at all to us over the last 12 months, Zippay has proven to be an amazing new partnership. I feel the fit between Premium and Zippay is ideal as it combines two premium products together to give consumers more choice.
by 15 per cent in its first two months. I was very sceptical initially after being approached by other so called buy now pay later schemes. But because we had to be very protective of our loyal customer base, we could not endorse a product with anything that would not be beneficial to them. I held many discussions with Zippay before moving ahead, but found there product to be an excellent option to our customers who worry about missing out on the items we sell due to our demand always being unable to keep up with supply.
MF: Are you using any backend smarts such as cart abandonment, Facebook pixel etc?
SD: We do have a Cart Abandon integrated with our store and as such it does have some success in bringing the customer back. This is another space we may work implementing custom discounts , deals etc in order to convert those type of sales.
Facebook Pixel is something we plan to start using more of in August 2016 once our current Facebook marketing campaign ends.
Business is a scam just to get money. Had to initiate chargebacks through the bank fraud department. Buyer beware.
Thank you for warning customers, and for assisting the police with Scott's criminal trial.


If you are not already swooping down on end-of-day foodie bargains from our favourite local eateries, then you might be interested in downloading the Too Good To Go app. Many of our favourite Roman Road businesses are signed up already, selling their unsold sarnies and soups at cracking discounts.
Too Good To Go is an app that has been designed to reduce food waste. It gives businesses the chance to sell their left-over meals at a discount and allows people to buy perfectly good food for less.
Cafes, juice bars and restaurants on the app list how many left-over meals they have at the end of the day and what they will cost, with all dishes reduced to between £2 and £3.80.
Users select what they want, pay for it through the app and collect their meal in designated hours (usually before closing on the same day). Customers don't know what exactly they get until they pick it up at the restaurant. You will be able to select a sandwich or a pastry but it doesn't give precise details on each product.
Numerous restaurants in Westfield Stratford.
The aim of the app is to reduce food waste. According to Wrap, a national organisation for the prevention of food waste in the UK, 210,000 tonnes of food that is thrown away annually by UK restaurants.
The two co-founders, Londoners Jamie Crummie and Chris Wilson, wanted to create a platform which would allow businesses to sell their surplus food at a discount rather than it being thrown away. They stumbled upon this concept while attending a technology event in Denmark, who are already blazing a trail in food waste innovations. The duo approached the team in Denmark and set upon bringing the technology to the UK.
Up to this date, Too Good To Go partnered with over 15,000 stores, 6 million people use the app, and over 7.8 million meals have been rescued. It is an amazing way of helping to tackle food waste and providing more affordable meals to residents.
Crummie and Wilson are already talking to big chains like Nando's about signing up to the platform, which would mean a big change in how the country tackles food waste.
It launched back in 2016 but only started gaining scale and traction this year.
The app is available to download from App Store and Google Play and is free.
If you enjoyed reading this article, why not have a look at another great high street app created by local resident Pamela Tironi.


With the summer break now drawing to a close, the Blancpain GT Sports Club returns this weekend to Budapest, Hungary, as Boutsen Ginion's Karim Ojjeh (#2 BMW M6 GT3) looks to wrap up his maiden championship title.
Twelve entries from five manufacturers including, BMW, Ferrari, Lamborghini, Mercedes and Porsche, head to the Hungaroring for the 2018 season's penultimate round, with the overall, Titanium Cup and Iron Cup championships all up for grabs.
Karim Ojjeh holds a 51-point advantage over AF Corse's Mario Cordoni (#70 Ferrari 488 GT3) in the overall standings, with just 66 points available from the final two rounds. The Saudi Arabian has been in fine form this year and could also clinch the inaugural Titanium Cup title with a solid performance this weekend.
The battle behind is sure to go down to the wire though, with Coach McKansy (#17 HP Racing International Lamborghini Huracan GT3) and last year's Hungarian Qualifying Race-winner Patrick Van Glabeke (#488 AF Corse Ferrari 488 GT3) both hoping for a strong result at the 4.381-mile circuit, as they look to launch themselves into second-place contention.
Elsewhere, Herberth Motorsport's Jürgen Häring (#66 Porsche 991 GT3 R) and AF Corse's Angélique Detavernier (#55 Ferrari 488 GT3), will both be ones to watch, having shown impressive pace last time out.
Also at Herberth Motorsport, Edward Lewis Brauner (#991 Porsche 991 GT3 R) returns to the series having missed the Misano and Spa rounds, as he looks to add to his points tally at Budapest.
Joining the series is legendary racer and team owner Kenny Habul (#751 Sun Energy 1 by Akka ASP Team Mercedes-AMG GT3), who will hope his vast GT racing experience will help him fight at the front at the Hungarian Grand Prix venue.
Four Iron Cup entries also make up the grid, with class leader Klaus Dieter Frers (#3 Artega Rennsport Ferrari 488 GT3) looking likely to regain the title, having lost out by just one point to Stephen Earle (#111 Kessel Racing Ferrari 488 GT3) last year.
The American is best positioned to put a stopper in his rival's efforts, but will have to watch out behind from Louis-Philippe Soenen (#50 AF Corse Ferrari 488 GT3), who may still cause an upset. Roberto Rayneri (#60 GDL Racing Mercedes SLS AMG GT3) could yet get ahead of the Belgian, as he looks to add to his first class podium from Spa.
Both practice sessions, qualifying and the 25-minute Qualifying Race will all take place on Saturday, with the 40-minute Main Race getting underway on Sunday morning.
Stay up to date this weekend by following both live races on our Facebook page, website and YouTube channel, with regular updates on our Twitter. The Blancpain GT Sports Club is supporting the penultimate Blancpain GT Series Sprint Cup round, with the GT4 European Series and Formula Renault Eurocup also in action.


text:
Home > Uncategorized > Inglett's instructions on mound: Go slow
Inglett's instructions on mound: Go slow
July 28, 2010 Jordan Schelling
MILWAUKEE — When called upon to pitch the ninth inning Tuesday, utility man Joe Inglett was instructed not to try to light up the radar gun.
In the past, Brewers manager Ken Macha has seen less than stellar results from position players who can reach the 90-mph range on the mound.
"I remember one back in Houston where Davey Martinez, who's the bench coach now for Tampa, center fielder, great arm — he wanted to pitch," Macha said. "It was kind of like [Paul] Janish last year in Cincinnati, the guy's throwing 90-plus and just getting raked.
"We had to take him out. We brought in Junior Noboa. He was throwing 60 and went 1-2-3. It's below hitting speed."
Another reason for Inglett to throw in the 50-mph range has more to do with health than his performance on the mound.
Earlier this season, Cardinals infielder Felipe Lopez hit the disabled list with an elbow injury just days after he pitched a scoreless 18th inning in a 20-inning game against the Mets. It's unclear whether the injury was related to Lopez' appearance on the mound, but it certainly couldn't have helped.
While throwing slow could have helped prevent an injury to Inglett, choosing the utility man to pitch prevented another Brewers position player from developing an arm injury.
"You've got to have somebody that isn't going to want to try to air it out," third baseman Casey McGehee said. "You put [Alcides Escobar] up there, he might hit 100. But you've got to put somebody in that's not going to try to light up the radar gun.
"The worst thing you can do is have somebody go out there like that and get hurt."
Categories: Uncategorized Tags: Baseball, Cincinnati Reds, Joe Inglett, Ken Macha, Milwaukee Brewers
Weeks won't be limited by leadoff label Utility man Inglett throws scoreless inning

redpajama_set_name: RedPajamaCommonCrawl


People who visited this listing also viewed other businesses in the Restaurants category by clicking "Restaurants above, beside "Chicago". The "View Larger Map" link below will allow you to put in your address and give you driving directions to 1422 W Taylor St to visit Japonica Specialty Sushi. This is the business contact information for Japonica Specialty Sushi, which is located at 1422 W Taylor St in Chicago. Feel free to call them at (312) 421-3288. Do you want to know more about Japonica Specialty Sushi? If so, click on the button that says "Read Merchant Reviews" to see previous testimonials. Please click "send" and inform us if you have found that Japonica Specialty Sushi is not longer at 1422 W Taylor St in Chicago, or can not be reached at (312) 421-3288.


I've always wanted to live close enough to my work to be able to bike there. The thought of leaving a smaller footprint on the earth by bicycling somewhere I go five days a week has appeal to me. Also appealing, is the drive at the busiest time of day is a major dislike of mine, so why not slow it down and enjoy the commute.
For the past year, I've lived within three miles of my work. Where I live, we celebrate May as Bike Month and are encouraged to use this month to bike to work. The perfect storm.
Day 1. May 1. It's pouring. I do it anyway with slicker over my backpack and ball cap to keep the rain off my face. I do it. My jeans and underwear stay wet until noon. But. I did it.
Day 2. Beautiful cool morning. I feel like a kid riding to school. I notice how awake and good I feel at 9am.
Day 7. Flat tire on the way to work. Had to walk half of the way so late and sweating.
Day 10. Worked from home. Scared away by rain chances.
Day 15. F it. I drove.
Day 20-30. It was unseasonably hot. As in, hot at 7am hot.
I'm so glad I rode to work for Bike Month, but there were negatives. I sweat too much. The day's first half hour was me mopping sweat off myself while I cooled down. It didn't help that it is up hill the entire way to work. However, the ride home was relaxing and a great transition to my real life. Another negative is the time it takes to not only bike there, but secure your bike, change out of your bike clothes, and do it all over again at the end of the day.
The positives outweigh the negatives and I plan to continue riding to work regularly. I love how I felt at 9am. I really had gotten my heart pumping already and it was so easy to fit exercise into my life without it taking up a great deal of time.
Last summer, I spent two hours after work three days a week riding my bike to get in shape. This year, my daily shorter rides, but on more hills, got me in just as good shape and were much more enjoyable.
I got to know the neighborhood dogs. 🙂 I got to know the kids on their bikes riding to school. I smelled the Spring flowering bushes; felt every bump; and waved at people watering their flowers or walking their dogs.
I really didn't wear makeup and couldn't fix my hair. I guess this is the reason more women don't bike to work. It was freeing yes, but I do admit that I felt my professionalism could be considered compromised. If it was more accepted, I think it would change America's beauty standards.
So with this past weekend being the official start to summer, plan to do something new these months to reinvent yourself just a little. And, be sure to let me know what those things are.
¹ City of Copenhagen, The Technical and Environmental Administration Traffic Department. Copenhagen City of Cyclists: Bicycle Account 2012. 2013.


Association lien rights are extraordinary.
Condominium and homeowners associations are granted a favorable recovery method afforded to very few creditors. That is, these associations can file a lien against the owner's property for unpaid assessments, fines, late fees and interest before obtaining a judgment. General contractors and subcontractors are also granted similar rights. Other creditors must first obtain a judgment before recording a lien against property.
However, this extraordinary recourse comes with strict responsibilities. Improper liens can be ordered cancelled from the records, which could cost the association valuable ranking rights. With counsel from Alford & Alford, associations properly prepare their liens and are guided with proper safeguards to protect the enforceability of the liens, taking under advisement legal and practical considerations.
Our association filed a lien; will it protect our position for future delinquencies?
No. Separate liens must be filed as new delinquencies accrue.
A lien preserves the claim described therein for only one year for condo associations and five years for homeowners associations. To preserve the benefits of the lien, a lawsuit and notice of filing lawsuit must be filed before the deadline passes. There are specific requirements for the lien, lawsuit and the notice of filing lawsuit. Contact Alford & Alford to make sure your notice of filing lawsuit complies with the statute.
I am on a condo board and we have a unit owner that owes just a small amount. Can I file a lien?
Yes, but there is a minimum amount of late fees and fines that can be included in the lien. Contact Alford & Alford, LLP for a full discussion of the amount of liens. There is no universal moment in time in which the delinquent amount justifies filing a lien; there are legal and practical considerations particular to each fact situation.
I am on a condo board and we have unit owners that go months without paying. What can we do about that?
If a unit owner misses payments for three or more consecutive months during an eight month period, then the Board can accelerate the dues for a 12 month period. There are restrictions and requirements that the Board must meet before accelerating dues. With counsel from Alford & Alford, LLP, condo boards and property managers are well informed of the type of assessments that can be accelerated and the process to do so.
Condominium Living. Louisiana law now requires condominium associations to post fidelity bonds or to have insurance in place to cover malfeance actions. So Louisiana condo associations must now abide by both Louisiana law and HUD requirements on this coverage. Contact us for a comparison of the two standards imperative to compliant operation of Louisiana condominiums.
Free Board Orientation. If your condo or homeowners association is not already represented by legal counsel, contact us about a free board orientation (subject to location and time constraints). We will discuss board meetings, laws relative to condo or homeowners associations, and suggestions for collecting dues and assessments and enforcing declarations and building restrictions.
If your community development is experiencing turnover by sales or foreclosures, contact Alford & Alford about tracking these transactions to avoid unnecessary gaps in the collection of dues and assessments.
Alford & Alford counsels associations on the interpretation and amendments to declarations, bylaws, policies and procedures. We also provide guidance on issues relevant to board and general membership meetings.
1. In the budgeting process, calculate the bad debt percentage and factor that into the amount of the annual assessment. As distasteful as it may be for paying owners to absorb the payments due by others, to ignore reality could create a cash shortage for the association, which can affect the ability of the association to make repairs, perform routine maintenance and procure insurance.
2. Enter the cost to record the lien on the owner's statement of account at the time the expense is incurred. That way if a payoff of the account is subsequently requested, the expense will not be forgotten.
3. Similarly, if it is the association's practice to cancel the lien upon payment (as opposed to shifting this burden to the owner), then the cost to cancel the lien should also be recorded on the owner's statement at the time the lien is recorded.
If the governing documents do not authorize late fees, then don't include late fees on the statements.
If the governing documents allow for interest at the legal rate (which changes every year), then don't charge the same flat rate year after year.
5. The association should closely monitor foreclosures so that the new owner can be promptly billed. A database of seizing creditors and contact info for each should be maintained to reduce the expense and time of tracing the same creditor over and over. In most instances, it will be the seizing creditor that bids in the property at the foreclosure.
When a condo association is not responsible for interior repairs.
Ready to get started? Schedule a consult now.
Louisiana condominium association held to strict compliance with lien statute.