text: // Generated by LiveScript 1.3.0
  (function(){
    var root, Q, sax, isFunction, isDeferred, get, getBinary, cacheBinary, callbackify, XMLLoader, JSONLoader, undelta, undeltaR, scale, BinaryLoader, ScanlineLoader, loaders;
    root = this;
    Q = root.Q || require('q');
    sax = root.sax || require('sax');
    isFunction = function(it){
      return it && it.constructor && it.call && it.apply;
    };
    isDeferred = function(it){
      return it && it.resolve && it.reject && it.promise;
    };
    get = function(path, d){
      var fs;
      if (!isDeferred(d)) {
        d = Q.defer();
      }
      if (root.window) {
        $.ajax({
          type: 'GET',
          url: path,
          dataType: 'text',
          progress: function(it){
            d.notify(it);
          }
        }).done(function(it){
          d.resolve(it);
        }).fail(function(it){
          d.reject(it);
        });
      } else {
        fs = require('fs');
        fs.readFile(path, {
          encoding: 'utf8'
        }, function(err, data){
          if (err) {
            return d.reject(err);
          } else {
            return d.resolve(data);
          }
        });
      }
      return d.promise;
    };
    getBinary = function(path, d){
      var xhr;
      if (!isDeferred(d)) {
        d = Q.defer();
      }
      if (root.window) {
        xhr = new XMLHttpRequest;
        xhr.open('GET', path, true);
        xhr.responseType = 'arraybuffer';
        xhr.onprogress = function(it){
          d.notify(it);
        };
        xhr.onreadystatechange = function(e){
          if (this.readyState === 4) {
            if (this.status === 200) {
              d.resolve(this.response);
            } else {
              d.reject(this.status);
            }
          }
        };
        xhr.send();
      } else {
        d.reject(new Error('not implemented'));
      }
      return d.promise;
    };
    cacheBinary = function(){
      var cache;
      cache = {};
      return {
        get: function(dir, packed, d){
          if (!cache[packed]) {
            if (!isDeferred(d)) {
              d = Q.defer();
            }
            getBinary(dir + "" + packed + ".bin", d);
            cache[packed] = d.promise;
          }
          return cache[packed];
        }
      };
    }();
    callbackify = function(loader){
      return function(path, success, fail, progress){
        var d, p;
        d = isDeferred(success)
          ? success
          : Q.defer();
        p = d.promise;
        if (isFunction(success)) {
          p.then(success);
        }
        if (isFunction(fail)) {
          p.fail(fail);
        }
        if (isFunction(progress)) {
          p.progress(progress);
        }
        loader(path, d);
        return d.promise;
      };
    };
    XMLLoader = function(path, d){
      var p;
      p = get(path);
      p.fail(function(it){
        return d.reject(it);
      }).progress(function(it){
        return d.notify(it);
      });
      p.then(function(doc){
        var ret, outlines, tracks, outline, track, strict, parser;
        ret = [];
        outlines = [];
        tracks = [];
        strict = true;
        parser = sax.parser(strict);
        parser.onopentag = function(node){
          if (outline) {
            switch (node.name) {
            case 'MoveTo':
              return outline.push({
                type: 'M',
                x: parseFloat(node.attributes.x),
                y: parseFloat(node.attributes.y)
              });
            case 'LineTo':
              return outline.push({
                type: 'L',
                x: parseFloat(node.attributes.x),
                y: parseFloat(node.attributes.y)
              });
            case 'CubicTo':
              return outline.push({
                type: 'C',
                begin: {
                  x: parseFloat(node.attributes.x1),
                  y: parseFloat(node.attributes.y1)
                },
                mid: {
                  x: parseFloat(node.attributes.x2),
                  y: parseFloat(node.attributes.y2)
                },
                end: {
                  x: parseFloat(node.attributes.x3),
                  y: parseFloat(node.attributes.y3)
                }
              });
            case 'QuadTo':
              return outline.push({
                type: 'Q',
                begin: {
                  x: parseFloat(node.attributes.x1),
                  y: parseFloat(node.attributes.y1)
                },
                end: {
                  x: parseFloat(node.attributes.x2),
                  y: parseFloat(node.attributes.y2)
                }
              });
            }
          } else if (track) {
            switch (node.name) {
            case 'MoveTo':
              return track.push({
                x: parseFloat(node.attributes.x),
                y: parseFloat(node.attributes.y),
                size: node.attributes.size ? parseFloat(node.attributes.size) : undefined
              });
            }
          } else {
            if (node.name === 'Outline') {
              outline = [];
            }
            if (node.name === 'Track') {
              return track = [];
            }
          }
        };
        parser.onclosetag = function(name){
          if (name === 'Outline') {
            outlines.push(outline);
            outline = null;
          }
          if (name === 'Track') {
            tracks.push(track);
            return track = null;
          }
        };
        parser.onend = function(){
          var i, ref$, outline, track;
          for (i in ref$ = outlines) {
            outline = ref$[i];
            track = tracks[i];
            ret.push({
              outline: outline,
              track: track
            });
          }
          return d.resolve(ret);
        };
        parser.onerror = function(err){
          return d.reject(err);
        };
        return parser.write(doc).close();
      });
    };
    JSONLoader = function(path, d){
      get(path).then(function(it){
        return d.resolve(JSON.parse(it));
      }).fail(function(it){
        return d.reject(it);
      }).progress(function(it){
        return d.notify(it);
      });
    };
    undelta = function(xs){
      var results, i$, to$, i;
      results = [xs[0]];
      for (i$ = 1, to$ = xs.length; i$ < to$; ++i$) {
        i = i$;
        results.push((results[i - 1] + xs[i] + 256) % 256);
      }
      return results;
    };
    undeltaR = function(result, current){
      var prev;
      prev = result.length !== 0 ? result[result.length - 1] : 0;
      return result.concat([(prev + current + 256) % 256]);
    };
    scale = function(v){
      return v * 2060.0 / 256;
    };
    BinaryLoader = function(path, d){
      var start, dir, packed, file_id, p;
      start = 1 + path.lastIndexOf('/');
      dir = path.substr(0, start);
      packed = path.substr(path.length - 6, 2);
      file_id = parseInt(path.substring(start, path.length - 6), 16);
      p = cacheBinary.get(dir, packed);
      p.fail(function(it){
        return d.reject(it);
      }).progress(function(it){
        return d.notify(it);
      });
      p.then(function(bin){
        var offset, size, data_view, stroke_count, i, id, p, ret, strokes_len, i$, outline, cmd_len, cood_len, j$, cmd, xs, ys, j, len$, track, track_len, size_indices, size_len, ss, index;
        size = {
          M: 1,
          L: 1,
          Q: 2,
          C: 3
        };
        data_view = new DataView(bin);
        stroke_count = data_view.getUint16(0, true);
        i = 0;
        while (i < stroke_count) {
          id = data_view.getUint16(2 + i * 6, true);
          if (id === file_id) {
            offset = data_view.getUint32(2 + i * 6 + 2, true);
            break;
          }
        }
        if (i === stroke_count) {
          d.reject(new Error("stroke not found"));
          return;
        }
        p = 0;
        ret = [];
        strokes_len = data_view.getUint8(offset + p++);
        for (i$ = 0; i$ < strokes_len; ++i$) {
          outline = [];
          cmd_len = data_view.getUint8(offset + p++);
          cood_len = 0;
          for (j$ = 0; j$ < cmd_len; ++j$) {
            cmd = {
              type: String.fromCharCode(data_view.getUint8(offset + p++))
            };
            cood_len += size[cmd.type];
            outline.push(cmd);
          }
          xs = [];
          ys = [];
          for (j$ = 0; j$ < cood_len; ++j$) {
            xs.push(data_view.getUint8(offset + p++));
          }
          for (j$ = 0; j$ < cood_len; ++j$) {
            ys.push(data_view.getUint8(offset + p++));
          }
          xs = undelta(xs).map(scale);
          ys = undelta(ys).map(scale);
          j = 0;
          for (j$ = 0, len$ = outline.length; j$ < len$; ++j$) {
            cmd = outline[j$];
            switch (cmd.type) {
            case 'M':
              cmd.x = xs[j];
              cmd.y = ys[j++];
              break;
            case 'L':
              cmd.x = xs[j];
              cmd.y = ys[j++];
              break;
            case 'Q':
              cmd.begin = {
                x: xs[j],
                y: ys[j++]
              };
              cmd.end = {
                x: xs[j],
                y: ys[j++]
              };
              break;
            case 'C':
              cmd.begin = {
                x: xs[j],
                y: ys[j++]
              };
              cmd.mid = {
                x: xs[j],
                y: ys[j++]
              };
              cmd.end = {
                x: xs[j],
                y: ys[j++]
              };
            }
          }
          track = [];
          track_len = data_view.getUint8(offset + p++);
          size_indices = [];
          size_len = data_view.getUint8(offset + p++);
          for (j$ = 0; j$ < size_len; ++j$) {
            size_indices.push(data_view.getUint8(offset + p++));
          }
          xs = [];
          ys = [];
          ss = [];
          for (j$ = 0; j$ < track_len; ++j$) {
            xs.push(data_view.getUint8(offset + p++));
          }
          for (j$ = 0; j$ < track_len; ++j$) {
            ys.push(data_view.getUint8(offset + p++));
          }
          for (j$ = 0; j$ < size_len; ++j$) {
            ss.push(data_view.getUint8(offset + p++));
          }
          xs = undelta(xs).map(scale);
          ys = undelta(ys).map(scale);
          ss = ss.map(scale);
          for (j$ = 0; j$ < track_len; ++j$) {
            j = j$;
            track.push({
              x: xs[j],
              y: ys[j]
            });
          }
          j = 0;
          for (j$ = 0, len$ = size_indices.length; j$ < len$; ++j$) {
            index = size_indices[j$];
            track[index].size = ss[j++];
          }
          ret.push({
            outline: outline,
            track: track
          });
        }
        return d.resolve(ret);
      });
    };
    ScanlineLoader = function(path, d){
      get(path).progress(function(it){
        return d.notify(it);
      }).fail(function(it){
        return d.reject(it);
      }).then(function(it){
        var strokes, stroke, data, lines, i$, len$, line, r;
        strokes = [];
        stroke = [];
        data = null;
        lines = it.split(/\r+\n+/);
        for (i$ = 0, len$ = lines.length; i$ < len$; ++i$) {
          line = lines[i$];
          if (r = /^([0|1]),(\d+)$/.exec(line)) {
            if (r[1] === '0' && r[2] === '0') {
              stroke.push(data);
              strokes.push(stroke);
              stroke = [];
              data = null;
            } else {
              if (data) {
                stroke.push(data);
              }
              data = {
                direction: +r[1],
                lines: []
              };
            }
          } else if (r = /^(\d+),(\d+),(\d+)$/.exec(line)) {
            data.lines.push({
              idx: +r[1],
              start: +r[2],
              end: +r[3]
            });
          }
        }
        return d.resolve(strokes);
      });
    };
    loaders = {
      XML: callbackify(XMLLoader),
      JSON: callbackify(JSONLoader),
      Binary: callbackify(BinaryLoader),
      Scanline: callbackify(ScanlineLoader)
    };
    if (root.window) {
      root.zhStrokeData || (root.zhStrokeData = {});
      root.zhStrokeData.loaders = loaders;
    } else {
      module.exports = loaders;
    }
  }).call(this);
  