diff --git a/Common/FontsFreeType/Private/FreeType/base.js b/Common/FontsFreeType/Private/FreeType/base.js
new file mode 100644
index 0000000000000000000000000000000000000000..0623129f2c2d678d1425524d578a6564e5d053aa
--- /dev/null
+++ b/Common/FontsFreeType/Private/FreeType/base.js
@@ -0,0 +1,3553 @@
+/******************************************************************************/
+// stream
+/******************************************************************************/
+function FT_Frame_Field(v,s,o)
+{
+    this.value = v;
+    this.size = s;
+    this.offset = o;
+}
+function FT_Stream(data, size)
+{
+    this.obj = null;
+    this.data = data;
+    this.size = size;
+    this.pos = 0;
+    this.cur = 0;
+
+    this.Seek = function(_pos)
+    {
+        if (_pos > this.size)
+            return FT_Common.FT_Err_Invalid_Stream_Operation;
+        this.pos = _pos;
+        return FT_Common.FT_Err_Ok;
+    }
+    this.Skip = function(_skip)
+    {
+        if (_skip < 0)
+            return FT_Common.FT_Err_Invalid_Stream_Operation;
+        return this.Seek(this.pos + _skip);
+    }
+    this.Read = function(pointer, count)
+    {
+        return this.ReadAt(this.pos, pointer, count);
+    }
+    this.ReadArray = function(count)
+    {
+        var read_bytes = this.size - this.pos;
+        if (read_bytes > count)
+            read_bytes = count;
+        if (0 == read_bytes)
+            return null;
+        var a = new Array(read_bytes);
+        for (var i = 0;i<count;i++)
+            a[i] = this.data[this.pos+i];
+        return a;
+    }
+    this.ReadAt = function(_pos, pointer, count)
+    {
+        if (_pos > this.size)
+            return FT_Common.FT_Err_Invalid_Stream_Operation;
+        var read_bytes = this.size - _pos;
+        if (read_bytes > count)
+            read_bytes = count;
+
+        FT_Common.memcpy_p2(pointer,this.data,_pos,count);
+
+        this.pos = _pos + read_bytes;
+
+        if (read_bytes < count)
+            return FT_Common.FT_Err_Invalid_Stream_Operation;
+
+        return FT_Common.FT_Err_Ok;
+    }
+    this.TryRead = function(pointer, count)
+    {
+        var read_bytes = 0;
+        if (this.pos < this.size)
+            return read_bytes;
+        read_bytes = this.size - this.pos;
+        if (read_bytes > count)
+            read_bytes = count;
+
+        FT_Common.memcpy_p2(pointer,this.data,this.pos,count);
+
+        this.pos += read_bytes;
+        return read_bytes;
+    }
+
+    // 1 bytes
+    this.GetUChar = function()
+    {
+        if (this.cur >= this.size)
+            return 0;
+        return this.data[this.cur++];
+    }
+    this.GetChar = function()
+    {
+        if (this.cur >= this.size)
+            return 0;
+        var m = this.data[this.cur++];
+        if (m > FT_Common.m_c)
+            m -= FT_Common.a_c;
+        return m;
+    }
+    this.GetString1 = function(len)
+    {
+        if (this.cur + len > this.size)
+            return "";
+        var t = "";
+        for (var i = 0; i < len; i++)
+            t += String.fromCharCode(this.data[this.cur + i]);
+        this.cur += len;
+        return t;
+    }
+    this.ReadString1 = function(len)
+    {
+        if (this.pos + len > this.size)
+            return "";
+        var t = "";
+        for (var i = 0; i < len; i++)
+            t += String.fromCharCode(this.data[this.pos + i]);
+        this.pos += len;
+        return t;
+    }
+
+    this.ReadUChar = function()
+    {
+        if (this.pos >= this.size)
+        {
+            FT_Error = FT_Common.FT_Err_Invalid_Stream_Operation;
+            return 0;
+        }
+        FT_Error = FT_Common.FT_Err_Ok;
+        return this.data[this.pos++];
+    }
+    this.ReadChar = function()
+    {
+        if (this.pos >= this.size)
+        {
+            FT_Error = FT_Common.FT_Err_Invalid_Stream_Operation;
+            return 0;
+        }
+        FT_Error = FT_Common.FT_Err_Ok;
+        var m = this.data[this.pos++];
+        if (m > FT_Common.m_c)
+            m -= FT_Common.a_c;
+        return m;
+    }
+
+    // 2 byte
+    this.GetUShort = function()
+    {
+        if (this.cur + 1 >= this.size)
+            return 0;
+        return (this.data[this.cur++] << 8 | this.data[this.cur++]);
+    }
+    this.GetShort = function()
+    {
+        return FT_Common.UShort_To_Short(this.GetUShort());
+    }
+    this.ReadUShort = function()
+    {
+        if (this.pos + 1 >= this.size)
+        {
+            FT_Error = FT_Common.FT_Err_Invalid_Stream_Operation;
+            return 0;
+        }
+        FT_Error = FT_Common.FT_Err_Ok;
+        return (this.data[this.pos++] << 8 | this.data[this.pos++]);
+    }
+    this.ReadShort = function()
+    {
+        return FT_Common.UShort_To_Short(this.ReadUShort());
+    }
+    this.GetUShortLE = function()
+    {
+        if (this.cur + 1 >= this.size)
+            return 0;
+        return (this.data[this.cur++] | this.data[this.cur++] << 8);
+    }
+    this.GetShortLE = function()
+    {
+        return FT_Common.UShort_To_Short(this.GetUShortLE());
+    }
+    this.ReadUShortLE = function()
+    {
+        if (this.pos + 1 >= this.size)
+        {
+            FT_Error = FT_Common.FT_Err_Invalid_Stream_Operation;
+            return 0;
+        }
+        FT_Error = FT_Common.FT_Err_Ok;
+        return (this.data[this.pos++] | this.data[this.pos++] << 8);
+    }
+    this.ReadShortLE = function()
+    {
+        return FT_Common.UShort_To_Short(this.ReadUShortLE());
+    }
+
+    // 4 byte
+    this.GetULong = function()
+    {
+        if (this.cur + 3 >= this.size)
+            return 0;
+        //return (this.data[this.cur++] << 24 | this.data[this.cur++] << 16 | this.data[this.cur++] << 8 | this.data[this.cur++]);
+        var s = (this.data[this.cur++] << 24 | this.data[this.cur++] << 16 | this.data[this.cur++] << 8 | this.data[this.cur++]);
+        if (s < 0)
+            s += FT_Common.a_i;
+        return s;
+    }
+    this.GetLong = function()
+    {
+        // 32-битные числа - по умолчанию знаковые!!!
+        //return FT_Common.UintToInt(this.GetULong());
+        return (this.data[this.cur++] << 24 | this.data[this.cur++] << 16 | this.data[this.cur++] << 8 | this.data[this.cur++]);
+    }
+    this.ReadULong = function()
+    {
+        if (this.pos + 3 >= this.size)
+        {
+            FT_Error = FT_Common.FT_Err_Invalid_Stream_Operation;
+            return 0;
+        }
+        FT_Error = FT_Common.FT_Err_Ok;
+        var s = (this.data[this.pos++] << 24 | this.data[this.pos++] << 16 | this.data[this.pos++] << 8 | this.data[this.pos++]);
+        if (s < 0)
+            s += FT_Common.a_i;
+        return s;
+    }
+    this.ReadLong = function()
+    {
+        // 32-битные числа - по умолчанию знаковые!!!
+        //return FT_Common.Uint_To_int(this.ReadULong());
+        if (this.pos + 3 >= this.size)
+        {
+            FT_Error = FT_Common.FT_Err_Invalid_Stream_Operation;
+            return 0;
+        }
+        FT_Error = FT_Common.FT_Err_Ok;
+        return (this.data[this.pos++] << 24 | this.data[this.pos++] << 16 | this.data[this.pos++] << 8 | this.data[this.pos++]);
+    }
+
+    this.GetULongLE = function()
+    {
+        if (this.cur + 3 >= this.size)
+            return 0;
+        return (this.data[this.cur++] | this.data[this.cur++] << 8 | this.data[this.cur++] << 16 | this.data[this.cur++] << 24);
+    }
+    this.GetLongLE = function()
+    {
+        return FT_Common.Uint_To_int(this.GetULongLE());
+    }
+    this.ReadULongLE = function()
+    {
+        if (this.pos + 3 >= this.size)
+        {
+            FT_Error = FT_Common.FT_Err_Invalid_Stream_Operation;
+            return 0;
+        }
+        FT_Error = FT_Common.FT_Err_Ok;
+        return (this.data[this.pos++] | this.data[this.pos++] << 8 | this.data[this.pos++] << 16 | this.data[this.pos++] << 24);
+    }
+    this.ReadLongLE = function()
+    {
+        return FT_Common.Uint_To_int(this.ReadULongLE());
+    }
+
+    // 3 byte
+    this.GetUOffset = function()
+    {
+        if (this.cur + 2 >= this.size)
+            return 0;
+        return (this.data[this.cur++] << 16 | this.data[this.cur++] << 8 | this.data[this.cur++]);
+    }
+    this.GetUOffsetLE = function()
+    {
+        if (this.cur + 2 >= this.size)
+            return 0;
+        return (this.data[this.cur++] | this.data[this.cur++] << 8 | this.data[this.cur++] << 16);
+    }
+    this.ReadUOffset = function()
+    {
+        if (this.pos + 2 >= this.size)
+        {
+            FT_Error = FT_Common.FT_Err_Invalid_Stream_Operation;
+            return 0;
+        }
+        FT_Error = FT_Common.FT_Err_Ok;
+        return (this.data[this.pos++] << 16 | this.data[this.pos++] << 8 | this.data[this.pos++]);
+    }
+    this.ReadUOffsetLE = function()
+    {
+        if (this.pos + 2 >= this.size)
+        {
+            FT_Error = FT_Common.FT_Err_Invalid_Stream_Operation;
+            return 0;
+        }
+        FT_Error = FT_Common.FT_Err_Ok;
+        return (this.data[this.pos++] | this.data[this.pos++] << 8 | this.data[this.pos++] << 16);
+    }
+    this.EnterFrame = function(count)
+    {
+        if (this.pos >= this.size || this.size - this.pos < count)
+            return FT_Common.FT_Err_Invalid_Stream_Operation;
+
+        this.cur = this.pos;
+        this.pos += count;
+        return FT_Common.FT_Err_Ok;
+    }
+    this.ExtractFrame = function(count, pointer)
+    {
+        if (null == pointer)
+            pointer = new CPointer();
+
+        var err = this.EnterFrame(count);
+        if (err != FT_Common.FT_Err_Ok)
+            return err;
+
+        pointer.data = this.data;
+        pointer.pos = this.cur;
+
+        this.cur = 0;
+        return err;
+    }
+    this.ReleaseFrame = function()
+    {
+    }
+    this.ExitFrame = function()
+    {
+        this.cur = 0;
+    }
+
+    this.ReadFields = function(arrayFields, structure)
+    {
+        // arrayFields : array {value, size, offset}
+        // structures : data pointer
+        var error = FT_Common.FT_Err_Ok;
+        var cursor = this.cur;
+        var frame_accessed = false;
+
+        var data = null;
+        var pos = 0;
+
+        var ind = 0;
+        do
+        {
+            var value;
+            var sign_shift;
+
+            switch (arrayFields[ind].value)
+            {
+                case 4:  /* access a new frame */
+                    error = this.EnterFrame(arrayFields[ind].offset);
+                    if (error != FT_Common.FT_Err_Ok)
+                    {
+                        if (frame_accessed === true)
+                            this.ExitFrame();
+                        return error;
+                    }
+
+                    frame_accessed = true;
+                    cursor = this.cur;
+                    ind++;
+                    continue;  /* loop! */
+
+                case 24:  /* read a byte sequence */
+                case 25:   /* skip some bytes      */
+                {
+                    var len = arrayFields[ind].size;
+                    if ( cursor + len > this.size )
+                    {
+                        error = FT_Common.FT_Err_Invalid_Stream_Operation;
+                        if (frame_accessed === true)
+                            this.ExitFrame();
+                        return error;
+                    }
+
+                    if ( arrayFields[ind] == 24 )
+                    {
+                        data = structure.data;
+                        pos = structure.pos + arrayFields[ind].offset;
+
+                        for (var i=0;i<len;i++)
+                            data[i] = this.data[cursor+i];
+                    }
+                    cursor += len;
+                    ind++;
+                    continue;
+                }
+
+                case 8:
+                case 9:  /* read a single byte */
+                    value = this.data[cursor++];
+                    sign_shift = 24;
+                    break;
+
+                case 13:
+                case 12:  /* read a 2-byte big-endian short */
+                    value = this.data[cursor++] << 8 | this.data[cursor++];
+                    sign_shift = 16;
+                    break;
+
+                case 15:
+                case 14:  /* read a 2-byte little-endian short */
+                    value = this.data[cursor++] | this.data[cursor++] << 8;
+                    sign_shift = 16;
+                    break;
+
+                case 17:
+                case 16:  /* read a 4-byte big-endian long */
+                    value = this.data[cursor++] << 24 | this.data[cursor++] << 16 | this.data[cursor++] << 8 | this.data[cursor++];
+                    sign_shift = 0;
+                    break;
+
+                case 19:
+                case 18:  /* read a 4-byte little-endian long */
+                    value = this.data[cursor++] | this.data[cursor++] << 8 | this.data[cursor++] << 16 | this.data[cursor++] << 24;
+                    sign_shift = 0;
+                    break;
+
+                case 21:
+                case 20:  /* read a 3-byte big-endian long */
+                    value = this.data[cursor++] << 16 | this.data[cursor++] << 8 | this.data[cursor++];
+                    sign_shift = 8;
+                    break;
+
+                case 23:
+                case 22:  /* read a 3-byte little-endian long */
+                    value = this.data[cursor++] | this.data[cursor++] << 8 | this.data[cursor++] << 16;
+                    sign_shift = 8;
+                    break;
+
+                default:
+                    /* otherwise, exit the loop */
+                    this.cur = cursor;
+                    if (frame_accessed === true)
+                        this.ExitFrame();
+                    return error;
+            }
+
+            /* now, compute the signed value is necessary */
+            if ( arrayFields[ind].value & 1 )
+                value = (( value << sign_shift ) >>> sign_shift) & 0xFFFFFFFF;
+
+            /* finally, store the value in the object */
+
+            data = structure.data;
+            pos = structure.pos + arrayFields[ind].offset;
+            switch (arrayFields[ind])
+            {
+                case 1:
+                    data[pos] = value & 0xFF;
+                    break;
+
+                case 2:
+                    data[pos] = (value >>> 8)&0xFF;
+                    data[pos+1] = value&0xFF;
+                    break;
+
+                case 4:
+                    data[pos] = (value >>> 24)&0xFF;
+                    data[pos+1] = (value >>> 16)&0xFF;
+                    data[pos+2] = (value >>> 8)&0xFF;
+                    data[pos+3] = value&0xFF;
+                    break;
+
+                default:
+                    data[pos] = (value >>> 24)&0xFF;
+                    data[pos+1] = (value >>> 16)&0xFF;
+                    data[pos+2] = (value >>> 8)&0xFF;
+                    data[pos+3] = value&0xFF;
+            }
+
+            /* go to next field */
+            ind++;
+        }
+        while ( 1 );
+
+        return error;
+    }
+    this.ReadFields2 = function(fields, structure)
+    {
+        // arrayFields : array {value, size, offset}
+        // structures : data pointer
+        var error = FT_Common.FT_Err_Ok;
+        var cursor = this.cur;
+        var frame_accessed = false;
+
+        var data = null;
+        var pos = 0;
+
+        var ind = 0;
+        do
+        {
+            var value;
+            var sign_shift;
+
+            var fval = fields[ind];
+            var fsize = fields[ind+1];
+            var foffset = fields[ind+2];
+
+            switch (fval)
+            {
+                case 4:  /* access a new frame */
+                    error = this.EnterFrame(foffset);
+                    if (error != FT_Common.FT_Err_Ok)
+                    {
+                        if (frame_accessed === true)
+                            this.ExitFrame();
+                        return error;
+                    }
+
+                    frame_accessed = true;
+                    cursor = this.cur;
+                    ind+=3;
+                    continue;  /* loop! */
+
+                case 24:  /* read a byte sequence */
+                case 25:   /* skip some bytes      */
+                {
+                    if ( cursor + fsize > this.size )
+                    {
+                        error = FT_Common.FT_Err_Invalid_Stream_Operation;
+                        if (frame_accessed === true)
+                            this.ExitFrame();
+                        return error;
+                    }
+
+                    if ( fval == 24 )
+                    {
+                        data = structure.data;
+                        pos = structure.pos + arrayFields[ind].offset;
+
+                        for (var i=0;i<len;i++)
+                            data[i] = this.data[cursor+i];
+                    }
+                    cursor += fsize;
+                    ind++;
+                    continue;
+                }
+
+                case 8:
+                case 9:  /* read a single byte */
+                    value = this.data[cursor++];
+                    sign_shift = 24;
+                    break;
+
+                case 13:
+                case 12:  /* read a 2-byte big-endian short */
+                    value = this.data[cursor++] << 8 | this.data[cursor++];
+                    sign_shift = 16;
+                    break;
+
+                case 15:
+                case 14:  /* read a 2-byte little-endian short */
+                    value = this.data[cursor++] | this.data[cursor++] << 8;
+                    sign_shift = 16;
+                    break;
+
+                case 17:
+                case 16:  /* read a 4-byte big-endian long */
+                    value = this.data[cursor++] << 24 | this.data[cursor++] << 16 | this.data[cursor++] << 8 | this.data[cursor++];
+                    sign_shift = 0;
+                    break;
+
+                case 19:
+                case 18:  /* read a 4-byte little-endian long */
+                    value = this.data[cursor++] | this.data[cursor++] << 8 | this.data[cursor++] << 16 | this.data[cursor++] << 24;
+                    sign_shift = 0;
+                    break;
+
+                case 21:
+                case 20:  /* read a 3-byte big-endian long */
+                    value = this.data[cursor++] << 16 | this.data[cursor++] << 8 | this.data[cursor++];
+                    sign_shift = 8;
+                    break;
+
+                case 23:
+                case 22:  /* read a 3-byte little-endian long */
+                    value = this.data[cursor++] | this.data[cursor++] << 8 | this.data[cursor++] << 16;
+                    sign_shift = 8;
+                    break;
+
+                default:
+                    /* otherwise, exit the loop */
+                    this.cur = cursor;
+                    if (frame_accessed === true)
+                        this.ExitFrame();
+                    return error;
+            }
+
+            /* now, compute the signed value is necessary */
+            if (0 != (fval & 1))
+                value = (( value << sign_shift ) >>> sign_shift) & 0xFFFFFFFF;
+
+            /* finally, store the value in the object */
+
+            data = structure.data;
+            pos = structure.pos + arrayFields[ind].offset;
+            switch (arrayFields[ind])
+            {
+                case 1:
+                    data[pos] = value & 0xFF;
+                    break;
+
+                case 2:
+                    data[pos] = (value >>> 8)&0xFF;
+                    data[pos+1] = value&0xFF;
+                    break;
+
+                case 4:
+                    data[pos] = (value >>> 24)&0xFF;
+                    data[pos+1] = (value >>> 16)&0xFF;
+                    data[pos+2] = (value >>> 8)&0xFF;
+                    data[pos+3] = value&0xFF;
+                    break;
+
+                default:
+                    data[pos] = (value >>> 24)&0xFF;
+                    data[pos+1] = (value >>> 16)&0xFF;
+                    data[pos+2] = (value >>> 8)&0xFF;
+                    data[pos+3] = value&0xFF;
+            }
+
+            /* go to next field */
+            ind+=3;
+        }
+        while ( 1 );
+
+        return error;
+    }
+}
+/******************************************************************************/
+// memory
+/******************************************************************************/
+function CPointer()
+{
+    this.obj    = null;
+    this.data   = null;
+    this.pos    = 0;
+}
+function dublicate_pointer(p)
+{
+    if (null == p)
+        return null;
+
+    var d = new CPointer();
+    d.data = p.data;
+    d.pos = p.pos;
+    return d;
+}
+function copy_pointer(p, size)
+{
+    var _p = g_memory.Alloc(size);
+    for (var i = 0; i < size; i++)
+        _p.data[i] = p.data[p.pos + i];
+    return _p;
+}
+
+function FT_Memory()
+{
+    this.canvas = document.createElement('canvas');
+    this.canvas.width = 1;
+    this.canvas.height = 1;
+    this.ctx    = this.canvas.getContext('2d');
+
+    this.Alloc = function(size)
+    {
+        var p = new CPointer();
+        p.obj = this.ctx.createImageData(1,parseInt((size + 3) / 4));
+        p.data = p.obj.data;
+        p.pos = 0;
+        return p;
+    }
+    this.AllocHeap = function()
+    {
+        // TODO: нужно посмотреть, как эта память будет использоваться.
+        // нужно ли здесь делать стек, либо все время от нуля делать??
+    }
+    this.CreateStream = function(size)
+    {
+        var _size = parseInt((size + 3) / 4);
+        var obj = this.ctx.createImageData(1,_size);
+        return new FT_Stream(obj.data,_size);
+    }
+}
+var g_memory = new FT_Memory();
+
+function FT_PEEK_CHAR(p)
+{
+    var r = p.data[p.pos];
+    if (r > FT_Common.m_c)
+        return r-FT_Common.a_c;
+    return r;
+}
+function FT_NEXT_CHAR(p)
+{
+    var r = p.data[p.pos++];
+    if (r > FT_Common.m_c)
+        return r - FT_Common.a_c;
+    return r;
+}
+function FT_PEEK_BYTE(p)
+{
+    return p.data[p.pos];
+}
+function FT_NEXT_BYTE(p)
+{
+    var r = p.data[p.pos++];
+    return r;
+}
+function FT_PEEK_SHORT(p)
+{
+    var r = (p.data[p.pos] << 8 | p.data[p.pos+1]);
+    if (r > FT_Common.m_s)
+        return r - FT_Common.a_s;
+    return r;
+}
+function FT_PEEK_SHORT_LE(p)
+{
+    var r = (p.data[p.pos+1] << 8 | p.data[p.pos]);
+    if (r > FT_Common.m_s)
+        return r - FT_Common.a_s;
+    return r;
+}
+function FT_NEXT_SHORT(p)
+{
+    var r = (p.data[p.pos++] << 8 | p.data[p.pos++]);
+    if (r > FT_Common.m_s)
+        return r - FT_Common.a_s;
+    return r;
+}
+function FT_PEEK_USHORT(p)
+{
+    var r = (p.data[p.pos] << 8 | p.data[p.pos+1]);
+    return r;
+}
+function FT_PEEK_USHORT_LE(p)
+{
+    var r = (p.data[p.pos + 1] << 8 | p.data[p.pos]);
+    return r;
+}
+function FT_NEXT_USHORT(p)
+{
+    var r = (p.data[p.pos++] << 8 | p.data[p.pos++]);
+    return r;
+}
+function FT_PEEK_UOFF3(p)
+{
+    var r = (p.data[p.pos] << 16 | p.data[p.pos+1] << 8 | p.data[p.pos+2]);
+    return r;
+}
+function FT_NEXT_UOFF3(p)
+{
+    var r = (p.data[p.pos++] << 16 | p.data[p.pos++] << 8 | p.data[p.pos++]);
+    return r;
+}
+function FT_PEEK_LONG(p)
+{
+    return (p.data[p.pos] << 24 | p.data[p.pos+1] << 16 | p.data[p.pos+2] << 8 | p.data[p.pos+3]);
+}
+function FT_NEXT_LONG(p)
+{
+    var r = (p.data[p.pos++] << 24 | p.data[p.pos++] << 16 | p.data[p.pos++] << 8 | p.data[p.pos++]);
+    return r;
+}
+function FT_PEEK_ULONG(p)
+{
+    var r = (p.data[p.pos] << 24 | p.data[p.pos+1] << 16 | p.data[p.pos+2] << 8 | p.data[p.pos+3]);
+    if (r<0)
+        r+=FT_Common.a_i;
+    return r;
+}
+function FT_PEEK_ULONG_LE(p)
+{
+    var r = (p.data[p.pos+3] << 24 | p.data[p.pos+2] << 16 | p.data[p.pos+1] << 8 | p.data[p.pos]);
+    if (r<0)
+        r+=FT_Common.a_i;
+    return r;
+}
+function FT_NEXT_ULONG(p)
+{
+    var r = (p.data[p.pos++] << 24 | p.data[p.pos++] << 16 | p.data[p.pos++] << 8 | p.data[p.pos++]);
+    if (r<0)
+        r+=FT_Common.a_i;
+    return r;
+}
+function FT_PEEK_String1(p,len)
+{
+    var t = "";
+    for (var i = 0; i < len; i++)
+    {
+        var r = p.data[p.pos + i];
+        if (r == 0)
+            return t;
+        t += String.fromCharCode(r);
+    }
+    return t;
+}
+function FT_NEXT_String1(p,len)
+{
+    var t = "";
+    for (var i = 0; i < len; i++)
+        t += String.fromCharCode(p.data[p.pos + i]);
+    p.pos+=len;
+    return t;
+}
+function ft_memchr(p, v, size)
+{
+    for (var i=0;i<size;i++)
+        if (p.data[p.pos+i] == v)
+            return i;
+    return -1;
+}
+function _strncmp(s1,s2,n)
+{
+    var m1 = s1.length;
+    var m2 = s2.length;
+    var l = n;
+    if (m1 < l)
+        l = m1;
+    if (m2 < l)
+        l = m2;
+
+    for (var i=0;i<l;i++)
+    {
+        var c = s1.charCodeAt(i) - s2.charCodeAt(i);
+        if (c != 0)
+            return c;
+    }
+    return m1 - m2;
+}
+
+function _strcmp_data(s,p)
+{
+    var m = s.length;
+
+    for (var i=0;i<m;i++)
+    {
+        var _c = p.data[p.pos + i];
+        if (_c == FT_Common.SYMBOL_CONST_S0)
+            return 1;
+
+        var c = s.charCodeAt(i) - _c;
+        if (c != 0)
+            return c;
+    }
+
+    if (p.data[p.pos + m] == FT_Common.SYMBOL_CONST_S0)
+        return 0;
+
+    return -1;
+}
+
+function _strcmp(s1,s2)
+{
+    return (s1 == s2) ? 0 : 1;
+}
+
+function _strncmp_data(p,s,n)
+{
+    var m2 = s.length;
+    var l = n;
+    if (m2 < l)
+        l = m2;
+
+    var m1 = 0;
+    for (var i=0;i<l;i++)
+    {
+        m1++;
+        if (FT_Common.SYMBOL_CONST_S0 == p.data[p.pos + i])
+        {
+            m1 = i;
+            break;
+        }
+
+        var c = p.data[p.pos + i] - s.charCodeAt(i);
+        if (c != 0)
+            return c;
+    }
+    return m1 - m2;
+}
+function _strncmp2(s1,s2,n,start1,start2)
+{
+    var m1 = s1.length - start1;
+    var m2 = s2.length - start2;
+    var l = n;
+    if (m1 < l)
+        l = m1;
+    if (m2 < l)
+        l = m2;
+
+    for (var i=0;i<l;i++)
+    {
+        var c = s1.charCodeAt(i + start1) - s2.charCodeAt(i + start2);
+        if (c != 0)
+            return c;
+    }
+    return m1 - m2;
+}
+function _mem_strcpyn1(dst, src, size)
+{
+    var i = 0;
+    var slen = src.length;
+    while (size > 1 && i < slen)
+    {
+        dst.data[dst.pos + i] = src.charCodeAt(i);
+        i++;
+    }
+
+    dst.data[dst.pos + i] = 0;  /* always zero-terminate */
+    return i != slen;
+}
+/******************************************************************************/
+// calc
+/******************************************************************************/
+function FT_LOAD_TARGET_MODE(x)
+{
+    return ((x >>> 16) & 15);
+}
+function FT_LOAD_TARGET(x)
+{
+    return ((x & 15) << 16);
+}
+function FT_PIX_FLOOR(x)
+{
+    return x & ~63;
+}
+function FT_PIX_ROUND(x)
+{
+    return (x + 32) & ~63;
+}
+function FT_PIX_CEIL(x)
+{
+    return (x + 63) & ~63;
+}
+
+function FT_RoundFix(a)
+{
+    return (a >= 0) ? (a + 0x8000) & ~0xFFFF : -((-a + 0x8000) & ~0xFFFF);
+}
+function FT_CeilFix(a)
+{
+    return (a >= 0) ? (a + 0xFFFF) & ~0xFFFF : -((-a + 0xFFFF) & ~0xFFFF);
+}
+function FT_FloorFix(a)
+{
+    return (a >= 0) ?  a & ~0xFFFF : -((-a) & ~0xFFFF);
+}
+
+// int64 support
+function _FT_MulDiv(a,b,c)
+{
+    var s = 1;
+    var d = 0;
+
+    if ( a < 0 ) { a = -a; s = -1; }
+    if ( b < 0 ) { b = -b; s = -s; }
+    if ( c < 0 ) { c = -c; s = -s; }
+
+    d = (c > 0 ? parseInt((a * b + (c >>> 1)) / c) : 0x7FFFFFFF);
+    return (s > 0) ? d : -d;
+}
+function _FT_MulFix(a,b)
+{
+    var s = 1;
+    if (a < 0)
+    {
+        a = -a;
+        s = -1;
+    }
+    if (b < 0)
+    {
+        b = -b;
+        s = -s;
+    }
+
+    var c = ((a * b + 0x8000) >>> 16) & 0xFFFFFFFF;
+    return ( s > 0 ) ? c : -c;
+}
+function _FT_DivFix(a,b)
+{
+    var q;
+    var s = 1;
+    if ( a < 0 ) { a = -a; s = -1; }
+    if ( b < 0 ) { b = -b; s = -s; }
+
+    if (b == 0)
+        q = 0x7FFFFFFF;
+    else
+    {
+        q = parseInt(((a * 65536) + (b >>> 1)) / b);
+        if (q < 0)
+            q += FT_Common.a_i;
+    }
+
+    return (s < 0 ? -q : q);
+}
+
+function Int64()
+{
+    this.lo = 0;
+    this.hi = 0;
+}
+function ft_multo64(x, y, z)
+{
+    var lo1, hi1, lo2, hi2, lo, hi, i1, i2;
+
+    lo1 = x & 0x0000FFFF;  hi1 = x >>> 16;
+    lo2 = y & 0x0000FFFF;  hi2 = y >>> 16;
+
+    lo = lo1 * lo2;
+    i1 = lo1 * hi2;
+    i2 = lo2 * hi1;
+    hi = hi1 * hi2;
+
+
+    i1 += i2;
+    if (i1 < i2)
+        hi += (1 << 16);
+    
+    hi += i1 >>> 16;
+    i1  = (i1 << 16) & 0xFFFFFFFF;
+    if (i1 < 0)
+        i1 += FT_Common.a_i;
+
+
+    
+    lo += i1;
+    if (lo < i1)
+        hi++;
+
+    z.lo = lo;
+    z.hi = hi;
+}
+function ft_div64by32(hi, lo, y)
+{
+    var q = 0;
+    var r = hi;
+
+    if (r >= y)
+        return 2147483647;
+
+    var i = 32;
+    do
+    {
+        r = (r << 1) & 0xFFFFFFFF;
+        q = (q << 1) & 0xFFFFFFFF;
+        if (q < 0)
+            q += FT_Common.a_i;
+
+        r  |= lo >>> 31;
+        if (r < 0)
+            r += FT_Common.a_i;
+
+        if (r >= y)
+        {
+            r -= y;
+            q |= 1;
+        }
+        lo = (lo << 1) & 0xFFFFFFFF;
+        if (lo < 0)
+            lo += FT_Common.a_i;
+    } while ( --i );
+
+    return q;
+}
+function FT_Add64(x, y, z)
+{
+    var lo = x.lo + y.lo;
+    var hi = x.hi + y.hi;
+    if (lo < x.lo)
+        hi++;
+
+    z.lo = lo;
+    z.hi = hi;
+}
+var temp1 = new Int64();
+var temp2 = new Int64();
+function FT_MulDiv(a, b, c)
+{
+    if (a > FT_Common.m_i || b > FT_Common.m_i || c > FT_Common.m_i)
+        alert("error");
+
+    if (a == 0 || b == c)
+        return a;
+
+    var s = 1;
+    if ( a < 0 ) { a = -a; s = -1; }
+    if ( b < 0 ) { b = -b; s = -s; }
+    if ( c < 0 ) { c = -c; s = -s; }
+
+    if (a <= 46340 && b <= 46340 && c <= 176095 && c > 0)
+        a = ((a * b + (c >> 1)) / c) >> 0;
+    else if (c > 0)
+    {
+        ft_multo64(a >= 0 ? a : a + FT_Common.a_i, b >= 0 ? b : b + FT_Common.a_i, temp1);
+
+        temp2.hi = 0;
+        temp2.lo = (c >>> 1);
+        FT_Add64(temp1, temp2, temp1);
+        a = ft_div64by32(temp1.hi, temp1.lo, c);
+    }
+    else
+        a = 0x7FFFFFFF;
+
+    return (s < 0 ? -a : a);
+}
+function FT_MulFix(a, b)
+{
+    if (a > FT_Common.m_i || b > FT_Common.m_i)
+    {
+		//alert("error");
+		a &= 0xFFFFFFFF;
+		b &= 0xFFFFFFFF;
+	}
+
+    if (a == 0 || b == 0x10000)
+        return a;
+
+    var s = a; a = Math.abs(a);
+    s ^= b; b = Math.abs(b);
+
+    var ua = a < 0 ? a + FT_Common.a_i : a;
+    var ub = b < 0 ? b + FT_Common.a_i : b;
+
+    if (ua <= 2048 && ub <= 1048576)
+        ua = (ua * ub + 0x8000) >>> 16;
+    else
+    {
+        var al = ua & 0xFFFF;
+
+        ua = ((ua >>> 16) * ub) + (al * (ub >>> 16)) + ((al * (ub & 0xFFFF) + 0x8000) >>> 16);
+    }
+    var _l = FT_Common.UintToInt(ua);
+    return (s < 0 ? -_l : _l);
+}
+function FT_DivFix(a, b)
+{
+    if (a > FT_Common.m_i || b > FT_Common.m_i)
+    {
+        a = (a & 0xFFFFFFFF);
+        b = (b & 0xFFFFFFFF);
+    }
+    
+    var q = 0;
+
+    var s = 1;
+    if ( a < 0 ) { a = -a; s = -1; }
+    if ( b < 0 ) { b = -b; s = -s; }
+
+    if (b == 0)
+    {
+        q = 0x7FFFFFFF;
+    }
+    else if ((a >> 16) == 0)
+    {
+        q = parseInt((a * 65536 + parseInt(b / 2)) / b);
+        //q = parseInt((((a << 16) & 0xFFFFFFFF) + (b >> 1)) / b);
+        if (q < 0)
+            q += FT_Common.a_i;
+    }
+    else
+    {
+        temp1.hi  = (a >> 16);
+        temp1.lo  = (a << 16) & 0xFFFFFFFF;
+        if (temp1.lo < 0)
+            temp1.lo += FT_Common.a_i;
+
+        temp2.hi = 0;
+        temp2.lo = (b >> 1);
+
+        if (temp2.lo < 0)
+            temp2.lo += FT_Common.a_i;
+
+        FT_Add64(temp1, temp2, temp1);
+        q = ft_div64by32(temp1.hi, temp1.lo, b < 0 ? b + FT_Common.a_i : b);
+    }
+
+    var _q = (q > FT_Common.m_i) ? q - FT_Common.a_i : q;
+    return (s < 0) ? -_q : _q;
+}
+
+function FT_Sqrt32(x)
+{
+    var val, root, newroot, mask;
+
+    root = 0;
+    mask = 0x40000000;
+    val  = x;
+
+    do
+    {
+        newroot = root + mask;
+        if ( newroot <= val )
+        {
+            val -= newroot;
+            root = newroot + mask;
+        }
+
+        root >>>= 1;
+        mask >>>= 2;
+
+    } while ( mask != 0 );
+
+    return root;
+}
+
+function FT_Matrix_Multiply(a, b)
+{
+    var xx, xy, yx, yy;
+
+    if ( !a || !b )
+        return;
+
+    xx = FT_MulFix(a.xx, b.xx) + FT_MulFix(a.xy, b.yx);
+    xy = FT_MulFix(a.xx, b.xy) + FT_MulFix(a.xy, b.yy);
+    yx = FT_MulFix(a.yx, b.xx) + FT_MulFix(a.yy, b.yx);
+    yy = FT_MulFix(a.yx, b.xy) + FT_MulFix(a.yy, b.yy);
+
+    b.xx = xx;  b.xy = xy;
+    b.yx = yx;  b.yy = yy;
+}
+
+function FT_Matrix_Invert(matrix)
+{
+    var delta, xx, yy;
+
+    if (!matrix)
+        return FT_Common.FT_Err_Invalid_Argument;
+
+    delta = FT_MulFix(matrix.xx, matrix.yy) - FT_MulFix(matrix.xy, matrix.yx);
+    if ( !delta )
+        return FT_Common.FT_Err_Invalid_Argument;
+
+    matrix.xy = -FT_DivFix(matrix.xy, delta);
+    matrix.yx = -FT_DivFix(matrix.yx, delta);
+
+    xx = matrix.xx;
+    yy = matrix.yy;
+
+    matrix.xx = FT_DivFix(yy, delta);
+    matrix.yy = FT_DivFix(xx, delta);
+
+    return 0;
+}
+
+function FT_Matrix_Multiply_Scaled(a, b, scaling)
+{
+    var xx, xy, yx, yy;
+    var val = 0x10000 * scaling;
+    if ( !a || !b )
+        return;
+
+    xx = FT_MulDiv(a.xx, b.xx, val) + FT_MulDiv(a.xy, b.yx, val);
+    xy = FT_MulDiv(a.xx, b.xy, val) + FT_MulDiv(a.xy, b.yy, val);
+    yx = FT_MulDiv(a.yx, b.xx, val) + FT_MulDiv(a.yy, b.yx, val);
+    yy = FT_MulDiv(a.yx, b.xy, val) + FT_MulDiv(a.yy, b.yy, val);
+
+    b.xx = xx; b.xy = xy;
+    b.yx = yx; b.yy = yy;
+}
+
+function FT_Vector_Transform_Scaled(vector, matrix, scaling)
+{
+    var xz, yz;
+    var val = 0x10000 * scaling;
+    if (!vector || !matrix)
+        return;
+
+    xz = FT_MulDiv(vector.x, matrix.xx, val) + FT_MulDiv(vector.y, matrix.xy, val);
+    yz = FT_MulDiv(vector.x, matrix.yx, val) + FT_MulDiv(vector.y, matrix.yy, val);
+
+    vector.x = xz;
+    vector.y = yz;
+}
+
+function FT_SqrtFixed(x)
+{
+    var root, rem_hi, rem_lo, test_div;
+    var count;
+
+    root = 0;
+    if (x > 0)
+    {
+        rem_hi = 0;
+        rem_lo = x;
+        count  = 24;
+        do
+        {
+            rem_hi   = (rem_hi << 2) | (rem_lo >>> 30);
+            rem_lo <<= 2;
+            root   <<= 1;
+            test_div = (root << 1) + 1;
+
+            if (rem_hi >= test_div)
+            {
+                rem_hi -= test_div;
+                root   += 1;
+            }
+        } while (--count);
+    }
+
+    return root;
+}
+
+function ft_corner_orientation(in_x, in_y, out_x, out_y)
+{
+    var result;
+    if ( in_y == 0 )
+    {
+        if ( in_x >= 0 )
+            result = out_y;
+        else
+            result = -out_y;
+    }
+    else if ( in_x == 0 )
+    {
+        if ( in_y >= 0 )
+            result = -out_x;
+        else
+            result = out_x;
+    }
+    else if ( out_y == 0 )
+    {
+        if ( out_x >= 0 )
+            result = in_y;
+        else
+            result = -in_y;
+    }
+    else if ( out_x == 0 )
+    {
+        if ( out_y >= 0 )
+            result = -in_x;
+        else
+            result =  in_x;
+    }
+    else
+    {
+        var delta = in_x * out_y - in_y * out_x;
+
+        if ( delta == 0 )
+            result = 0;
+        else
+            result = 1 - 2 * ( delta < 0 );
+    }
+
+    return result;
+}
+
+function ft_corner_is_flat(in_x, in_y, out_x, out_y)
+{
+    var ax = in_x;
+    var ay = in_y;
+
+    var d_in, d_out, d_corner;
+
+    if ( ax < 0 )
+        ax = -ax;
+    if ( ay < 0 )
+        ay = -ay;
+    d_in = ax + ay;
+
+    ax = out_x;
+    if ( ax < 0 )
+        ax = -ax;
+    ay = out_y;
+    if ( ay < 0 )
+        ay = -ay;
+    d_out = ax + ay;
+
+    ax = out_x + in_x;
+    if ( ax < 0 )
+        ax = -ax;
+    ay = out_y + in_y;
+    if ( ay < 0 )
+        ay = -ay;
+    d_corner = ax + ay;
+
+    return (( d_in + d_out - d_corner ) < ( d_corner >>> 4 )) ? 1 : 0;
+}
+/******************************************************************************/
+// glyph
+/******************************************************************************/
+// bitmap
+function ft_bitmap_glyph_init(glyph, slot)
+{
+    var library = glyph.library;
+
+    if (slot.format != FT_Common.FT_GLYPH_FORMAT_BITMAP)
+        return FT_Common.FT_Err_Invalid_Glyph_Format;
+
+    glyph.left = slot.bitmap_left;
+    glyph.top  = slot.bitmap_top;
+
+    if ((slot.internal.flags & FT_Common.FT_GLYPH_OWN_BITMAP) != 0)
+    {
+        var d = glyph.bitmap;
+        var s = slot.bitmap;
+
+        d.rows = s.rows;
+        d.width = s.width;
+        d.pitch = s.pitch;
+        d.buffer = dublicate_pointer(s.buffer);
+        d.num_grays = s.num_grays;
+        d.pixel_mode = s.pixel_mode;
+        d.palette_mode = s.palette_mode;
+        d.palette = s.palette;
+
+        slot.internal.flags &= ~FT_Common.FT_GLYPH_OWN_BITMAP;
+    }
+    else
+    {
+        FT_Bitmap_New(glyph.bitmap);
+        return FT_Bitmap_Copy(library, slot.bitmap, glyph.bitmap);
+    }
+    return 0;
+}
+function ft_bitmap_glyph_copy(source, target)
+{
+    target.left = source.left;
+    target.top  = source.top;
+    return FT_Bitmap_Copy(source.library, source.bitmap, target.bitmap);
+}
+function ft_bitmap_glyph_done(bitmap_glyph)
+{
+    FT_Bitmap_Done(bitmap_glyph.library, bitmap_glyph.bitmap);
+}
+function ft_bitmap_glyph_bbox(glyph, cbox)
+{
+    cbox.xMin = glyph.left << 6;
+    cbox.xMax = cbox.xMin + (glyph.bitmap.width << 6);
+    cbox.yMax = glyph.top << 6;
+    cbox.yMin = cbox.yMax - (glyph.bitmap.rows << 6);
+}
+
+// outline
+function ft_outline_glyph_init(glyph, slot)
+{
+    var source = slot.outline;
+    var target = glyph.outline;
+
+
+    /* check format in glyph slot */
+    if (slot.format != FT_Common.FT_GLYPH_FORMAT_OUTLINE)
+        return FT_Common.FT_Err_Invalid_Glyph_Format;
+
+    var error = FT_Outline_New(glyph.library, source.n_points, source.n_contours, glyph.outline);
+    if (error != 0)
+        return error;
+
+    FT_Outline_Copy(source, target);
+    return error;
+}
+function ft_outline_glyph_done(glyph)
+{
+    FT_Outline_Done(glyph.library, glyph.outline);
+}
+function ft_outline_glyph_copy(source, target)
+{
+    var library = source.library;
+    var error = FT_Outline_New(library, source.outline.n_points, source.outline.n_contours, target.outline);
+    if (error != 0)
+        FT_Outline_Copy(source.outline, target.outline);
+
+    return error;
+}
+function ft_outline_glyph_transform(glyph, matrix, delta)
+{
+    if (matrix != null)
+        FT_Outline_Transform(glyph.outline, matrix);
+
+    if (delta != null)
+        FT_Outline_Translate(glyph.outline, delta.x, delta.y);
+}
+function ft_outline_glyph_bbox(glyph, bbox)
+{
+    FT_Outline_Get_CBox(glyph.outline, bbox);
+}
+function ft_outline_glyph_prepare(glyph, slot)
+{
+    slot.format         = FT_Common.FT_GLYPH_FORMAT_OUTLINE;
+
+    var d = slot.outline;
+    var s = glyph.outline;
+
+    d.n_contours = s.n_contours;
+    d.n_points = s.n_points;
+    d.points = s.points;
+    d.tags = s.tags;
+    d.contours = s.contours;
+    d.flags = s.flags;
+
+    slot.outline.flags &= ~FT_Common.FT_OUTLINE_OWNER;
+    return 0;
+}
+
+function _ft_bitmap_glyph_class()
+{
+    this.glyph_size = 0; // glyph_type
+    this.glyph_format = FT_Common.FT_GLYPH_FORMAT_BITMAP;
+    this.glyph_init = ft_bitmap_glyph_init;
+    this.glyph_done = ft_bitmap_glyph_done;
+    this.glyph_copy = ft_bitmap_glyph_copy;
+    this.glyph_transform = null;
+    this.glyph_bbox = ft_bitmap_glyph_bbox;
+    this.glyph_prepare = null;
+}
+var ft_bitmap_glyph_class = new _ft_bitmap_glyph_class();
+function _ft_outline_glyph_class()
+{
+    this.glyph_size = 1; // glyph_type
+    this.glyph_format = FT_Common.FT_GLYPH_FORMAT_OUTLINE;
+    this.glyph_init = ft_outline_glyph_init;
+    this.glyph_done = ft_outline_glyph_done;
+    this.glyph_copy = ft_outline_glyph_copy;
+    this.glyph_transform = ft_outline_glyph_transform;
+    this.glyph_bbox = ft_outline_glyph_bbox;
+    this.glyph_prepare = ft_outline_glyph_prepare;
+}
+var ft_outline_glyph_class = new _ft_outline_glyph_class();
+
+function FT_GlyphRec()
+{
+    this.library = null;
+    this.clazz = null;
+    this.format = 0;
+    this.advance = new FT_Vector();
+}
+function FT_BitmapGlyphRec()
+{
+    this.library = null;
+    this.clazz = null;
+    this.format = 0;
+    this.advance = new FT_Vector();
+
+    this.left = 0;
+    this.top = 0;
+    this.bitmap = new FT_Bitmap();
+}
+function FT_OutlineGlyphRec()
+{
+    this.library = null;
+    this.clazz = null;
+    this.format = 0;
+    this.advance = new FT_Vector();
+
+    this.outline = new FT_Outline();
+}
+function ft_new_glyph(library, clazz)
+{
+    var glyph = null;
+    if (clazz.glyph_size == 0)
+        glyph = new FT_BitmapGlyphRec();
+    else
+        glyph = new FT_OutlineGlyphRec();
+
+    glyph.library = library;
+    glyph.clazz = clazz;
+    glyph.format = clazz.glyph_format;
+    return glyph;
+}
+/******************************************************************************/
+// glyphloader
+/******************************************************************************/
+function FT_CreateVectorArray(array, start, count)
+{
+    for (var i = start + count - 1; i >= start; i--)
+        array[i] = new FT_Vector();
+}
+function FT_CreateArray(array, start, count)
+{
+    for (var i = start + count - 1; i >= start; i--)
+        array[i] = 0;
+}
+function FT_CreateArraySubGlyphs(array, start, count)
+{
+    for (var i = start + count - 1; i >= start; i--)
+        array[i] = new FT_SubGlyph();
+}
+function FT_OutlineCur()
+{
+    this.n_contours = 0;
+    this.n_points = 0;
+
+    this.points = 0;
+    this.tags = 0;
+    this.contours = 0;
+
+    this.flags = 0;
+}
+function FT_SubGlyph()
+{
+    this.index = 0;
+    this.flags = 0;
+    this.arg1 = 0;
+    this.arg2 = 0;
+    this.transform = new FT_Matrix();
+}
+function FT_GlyphLoad()
+{
+    this.outline = new FT_Outline();
+    this.extra_points = null;
+    this.extra_points2 = 0;
+    this.num_subglyphs = 0;
+    this.subglyphs = null;
+}
+function FT_GlyphLoadCur()
+{
+    this.outline = new FT_OutlineCur();
+    this.extra_points = 0;
+    this.extra_points2 = 0;
+    this.num_subglyphs = 0;
+    this.subglyphs = 0;
+}
+function FT_GlyphLoader()
+{
+    this.memory = null;
+    this.max_points = 0;
+    this.max_contours = 0;
+    this.max_subglyphs = 0;
+    this.use_extra = 0;
+
+    this.base = new FT_GlyphLoad();
+    this.current = new FT_GlyphLoadCur();
+
+    this.other = null;
+}
+
+function FT_GlyphLoader_New(memory)
+{
+    var loader = new FT_GlyphLoader();
+    loader.memory = memory;
+    return loader;
+}
+function FT_GlyphLoader_Rewind(loader)
+{
+    var base    = loader.base;
+    var current = loader.current;
+
+    base.outline.n_points   = 0;
+    base.outline.n_contours = 0;
+    base.num_subglyphs      = 0;
+
+    var _cur = current.outline;
+    _cur.n_contours = 0;
+    _cur.n_points = 0;
+    _cur.points = 0;
+    _cur.tags = 0;
+    _cur.contours = 0;
+    _cur.flags = 0;
+
+    current.extra_points = 0;
+    current.extra_points2 = 0;
+    current.num_subglyphs = 0;
+    current.subglyphs = 0;
+
+    current.extra_points  = 0;
+    current.extra_points2 = base.extra_points2;
+}
+function FT_GlyphLoader_Reset(loader)
+{
+    var base = loader.base;
+
+    base.outline.points = null;
+    base.outline.tags = null;
+    base.outline.contours = null;
+    base.extra_points = null;
+    base.extra_points2 = 0;
+    base.subglyphs = null;
+
+    loader.max_points    = 0;
+    loader.max_contours  = 0;
+    loader.max_subglyphs = 0;
+
+    FT_GlyphLoader_Rewind(loader);
+}
+function FT_GlyphLoader_Done(loader)
+{
+    if (loader)
+        FT_GlyphLoader_Reset(loader);
+}
+function FT_GlyphLoader_Adjust_Points(loader)
+{
+    var base    = loader.base.outline;
+    var current = loader.current.outline;
+
+    current.points   = base.n_points;
+    current.tags     = base.n_points;
+    current.contours = base.n_contours;
+
+    if (loader.use_extra == 1)
+    {
+        loader.current.extra_points  = base.n_points;
+        loader.current.extra_points2 = loader.base.extra_points2 + base.n_points;
+    }
+}
+function FT_GlyphLoader_CreateExtra(loader)
+{
+    var c = 2*loader.max_points;
+    loader.base.extra_points = new Array(c);
+    FT_CreateVectorArray(loader.base.extra_points, 0, c);
+    loader.use_extra = 1;
+    loader.base.extra_points2 = loader.max_points;
+    FT_GlyphLoader_Adjust_Points(loader);
+    return 0;
+}
+function FT_GlyphLoader_Adjust_Subglyphs(loader)
+{
+    loader.current.subglyphs = loader.base.num_subglyphs;
+}
+function FT_GlyphLoader_CheckPoints(loader, n_points, n_contours)
+{
+    var base = loader.base.outline;
+    var current = loader.current.outline;
+    var adjust = 0;
+
+    var new_max = base.n_points + current.n_points + n_points;
+    var old_max = loader.max_points;
+
+    if (new_max > old_max)
+    {
+        new_max = (new_max + 7) & ~7;
+
+        if (new_max > 32767)
+            return FT_Error.FT_Err_Array_Too_Large;
+
+        if (null == base.points)
+            base.points = new Array(new_max);
+        if (null == base.tags)
+            base.tags = new Array(new_max);
+
+        FT_CreateVectorArray(base.points, old_max, new_max - old_max);
+        FT_CreateArray(base.tags, old_max, new_max - old_max);
+
+        if (1 == loader.use_extra)
+        {
+            if (null == loader.base.extra_points)
+                loader.base.extra_points = new Array(2 * (new_max - old_max));
+            FT_CreateVectorArray(loader.base.extra_points, old_max * 2, 2 * (new_max - old_max));
+            loader.base.extra_points2 = new_max;
+        }
+
+        adjust = 1;
+        loader.max_points = new_max;
+    }
+
+    /* check contours */
+    old_max = loader.max_contours;
+    new_max = base.n_contours + current.n_contours + n_contours;
+    if (new_max > old_max)
+    {
+        new_max = (new_max + 4) & ~4;
+
+        if (new_max > 32767)
+            return FT_Common.FT_Err_Array_Too_Large;
+
+        if (base.contours == null)
+            base.contours = new Array(new_max);
+        FT_CreateArray(base.contours, old_max, new_max - old_max);
+
+        adjust = 1;
+        loader.max_contours = new_max;
+    }
+
+    if (adjust == 1)
+        FT_GlyphLoader_Adjust_Points(loader);
+
+    return 0;
+}
+function FT_GlyphLoader_CheckSubGlyphs(loader, n_subs)
+{
+    var base    = loader.base;
+    var current = loader.current;
+
+    var new_max = base.num_subglyphs + current.num_subglyphs + n_subs;
+    var old_max = loader.max_subglyphs;
+    if (new_max > old_max)
+    {
+        new_max = (new_max + 2) & ~2;
+
+        if (null == base.subglyphs)
+            base.subglyphs = new Array(new_max);
+        FT_CreateArraySubGlyphs(base.subglyphs, old_max, new_max - old_max);
+        loader.max_subglyphs = new_max;
+        FT_GlyphLoader_Adjust_Subglyphs(loader);
+    }
+    return 0;
+}
+function FT_GlyphLoader_Prepare(loader)
+{
+    var current = loader.current;
+
+    current.outline.n_points   = 0;
+    current.outline.n_contours = 0;
+    current.num_subglyphs      = 0;
+
+    FT_GlyphLoader_Adjust_Points(loader);
+    FT_GlyphLoader_Adjust_Subglyphs(loader);
+}
+function FT_GlyphLoader_Add(loader)
+{
+    if ( !loader )
+        return;
+
+    var base    = loader.base;
+    var current = loader.current;
+
+    var n_curr_contours = current.outline.n_contours;
+    var n_base_points   = base.outline.n_points;
+
+    base.outline.n_points = base.outline.n_points + current.outline.n_points;
+    base.outline.n_contours = base.outline.n_contours + current.outline.n_contours;
+
+    base.num_subglyphs += current.num_subglyphs;
+
+    var mass = base.outline.contours;
+    var start = current.outline.contours;
+    for (var n = 0; n < n_curr_contours; n++)
+        mass[start+n] = mass[start+n] + n_base_points;
+
+    FT_GlyphLoader_Prepare(loader);
+}
+function FT_GlyphLoader_CopyPoints(target, source)
+{
+    var num_points   = source.base.outline.n_points;
+    var num_contours = source.base.outline.n_contours;
+
+
+    var error = FT_GlyphLoader_CheckPoints(target, num_points, num_contours);
+    if (error != 0)
+    {
+        var _out = target.base.outline;
+        var _in = source.base.outline;
+
+        var i=0;
+
+        var out_p = _out.points;
+        var in_p = _in.points;
+        var out_t = _out.tags;
+        var in_t = _in.tags;
+
+        for (i=0;i<num_points;i++)
+        {
+            out_p[i].x = in_p[i].x;
+            out_p[i].y = in_p[i].y;
+
+            out_t[i] = in_t[i];
+        }
+
+        var out_c = _out.contours;
+        var in_c = _in.contours;
+        for (i=0;i<num_contours;i++)
+            out_c[i] = in_c[i];
+
+        if (1 == target.use_extra && 1 == source.use_extra)
+        {
+            var out_e = target.base.extra_points;
+            var in_e = source.base.extra_points;
+            var c = 2 * num_points;
+            for (i=0;i<c;i++)
+            {
+                out_e[i].x = in_e[i].x;
+                out_e[i].y = in_e[i].y;
+            }
+        }
+
+        _out.n_points   = num_points;
+        _out.n_contours = num_contours;
+
+        FT_GlyphLoader_Adjust_Points(target);
+    }
+
+    return error;
+}
+function FT_GLYPHLOADER_CHECK_POINTS(_loader,_points,_contours)
+{
+    if (_points == 0 || (_loader.base.outline.n_points + _loader.current.outline.n_points + _points) <= _loader.max_points)
+    {
+        if (_contours == 0 || (_loader.base.outline.n_contours + _loader.current.outline.n_contours + _contours) <= _loader.max_contours)
+            return 0;
+    }
+    return FT_GlyphLoader_CheckPoints(_loader,_points,_contours);
+}
+/******************************************************************************/
+// ftmm
+/******************************************************************************/
+function FT_MM_Axis()
+{
+    this.name = null;
+    this.minimum = 0;
+    this.maximum = 0;
+}
+function FT_Var_Axis()
+{
+    this.name = null;
+
+    this.minimum = 0;
+    this.def = 0;
+    this.maximum = 0;
+
+    this.tag = 0;
+    this.strid = 0;
+}
+function FT_Var_Named_Style()
+{
+    this.coords = null;
+    this.strid = 0;
+}
+function FT_MM_Var()
+{
+    this.num_axis = 0;
+    this.num_designs = 0;
+    this.num_namedstyles = 0;
+    this.axis = null;
+    this.namedstyle = null;
+
+    this.dublicate = function()
+    {
+        var res = new FT_MM_Var();
+        res.num_axis = this.num_axis;
+        res.num_designs = this.num_designs;
+        res.num_namedstyles = this.num_namedstyles;
+
+        var c = res.num_axis;
+        if (c != 0)
+        {
+            res.axis = new Array(c);
+            for (var i=0;i<c;i++)
+            {
+                res.axis[i] = new FT_Var_Axis();
+                var _m = res.axis[i];
+                var _s = this.axis[i];
+
+                _m.name = _s.name;
+                _m.minimum = _s.minimum;
+                _m.def = _s.def;
+                _m.maximum = _s.maximum;
+                _m.tag = _s.tag;
+                _m.strid = _s.strid;
+            }
+        }
+        c = res.num_namedstyles;
+        if (c != 0)
+        {
+            res.namedstyle = new Array(c);
+            for (var i=0;i<c;i++)
+            {
+                res.namedstyle[i] = new FT_Var_Named_Style();
+                var _m = res.namedstyle[i];
+                var _s = this.namedstyle[i];
+
+                _m.strid = _s.strid;
+                if (null != _s.coords)
+                    _m.coords = _s.coords.splice(0,0);
+            }
+        }
+    }
+}
+function FT_Multi_Master()
+{
+    this.num_axis = 0;
+    this.num_designs = 0;
+    this.axis = new Array(FT_Common.T1_MAX_MM_AXIS);
+
+    for (var i = 0; i < FT_Common.T1_MAX_MM_AXIS; i++)
+        this.axis[i] = new FT_MM_Axis();
+}
+/******************************************************************************/
+// ftdriver
+/******************************************************************************/
+function FT_Driver_Class()
+{
+    this.flags = 0;
+    this.name = "";
+    this.version = 0;
+    this.requires = 0;
+
+    this.module_interface = null;
+
+    this.init = null;
+    this.done = null;
+    this.get_interface = null;
+
+    this.face_object_size = 0;
+    this.size_object_size = 0;
+    this.slot_object_size = 0;
+
+    this.init_face = null;
+    this.done_face = null;
+
+    this.init_size = null;
+    this.done_size = null;
+
+    this.init_slot = null;
+    this.done_slot = null;
+
+    //#ifdef FT_CONFIG_OPTION_OLD_INTERNALS
+    this.set_char_sizes = null;
+    this.set_pixel_sizes = null;
+    //#endif
+
+    this.load_glyph = null;
+
+    this.get_kerning = null;
+    this.attach_file = null;
+    this.get_advances = null;
+
+    this.request_size = null;
+    this.select_size = null;
+}
+//#ifdef FT_CONFIG_OPTION_OLD_INTERNALS
+function ft_stub_set_char_sizes(size, width, height, horz_res, vert_res)
+{
+    var driver = size.face.driver;
+    if (driver.clazz.request_size != null)
+    {
+        var req = new FT_Size_RequestRec();
+        req.type   = 0;
+        req.width  = width;
+        req.height = height;
+
+        if (horz_res == 0)
+            horz_res = vert_res;
+
+        if (vert_res == 0)
+            vert_res = horz_res;
+
+        if (horz_res == 0)
+            horz_res = vert_res = 72;
+
+        req.horiResolution = horz_res;
+        req.vertResolution = vert_res;
+
+        return driver.clazz.request_size(size, req);
+    }
+    return 0;
+}
+function  ft_stub_set_pixel_sizes(size, width, height)
+{
+    var driver = size.face.driver;
+    if (driver.clazz.request_size)
+    {
+        var req = new FT_Size_RequestRec();
+        req.type           = 0;
+        req.width          = width  << 6;
+        req.height         = height << 6;
+        req.horiResolution = 0;
+        req.vertResolution = 0;
+        return driver.clazz.request_size(size, req);
+    }
+    return 0;
+}
+//#endif
+/******************************************************************************/
+// ftvalid
+/******************************************************************************/
+function FT_ValidatorRec()
+{
+    this.base = new CPointer();
+    this.limit = 0;
+    this.level = 0
+    this.error = 0
+}
+/******************************************************************************/
+// pshints
+/******************************************************************************/
+/******************************************************************************/
+// tttypes
+/******************************************************************************/
+function TTC_HeaderRec()
+{
+    this.tag = 0;
+    this.version = 0;
+    this.count = 0;
+    this.offsets = null;
+}
+function SFNT_HeaderRec()
+{
+    this.format_tag = 0;
+    this.num_tables = 0;
+    this.search_range = 0;
+    this.entry_selector = 0;
+    this.range_shift = 0;
+
+    this.offset = 0;  /* not in file */
+}
+function TT_Table()
+{
+    this.Tag = 0;
+    this.CheckSum = 0;
+    this.Offset = 0;
+    this.Length = 0;
+}
+function TT_LongMetricsRec()
+{
+    this.advance = 0;
+    this.bearing = 0;
+}
+function TT_NameEntryRec()
+{
+    this.platformID = 0;
+    this.encodingID = 0;
+    this.languageID = 0;
+    this.nameID = 0;
+    this.stringLength = 0;
+    this.stringOffset = 0;
+    this.string = null;
+}
+function TT_NameTableRec()
+{
+    this.format = 0;
+    this.numNameRecords = 0;
+    this.storageOffset = 0;
+    this.names = null;
+    this.stream = null;
+}
+function TT_GaspRange()
+{
+    this.maxPPEM = 0;
+    this.gaspFlag = 0;
+}
+function TT_Gasp()
+{
+    this.version = 0;
+    this.numRanges = 0;
+    this.gaspRanges = null;
+}
+//#ifdef FT_CONFIG_OPTION_OLD_INTERNALS
+function TT_HdmxEntryRec()
+{
+    this.ppem = 0;
+    this.max_width = 0;
+    this.widths = null;
+}
+function TT_HdmxRec()
+{
+    this.version = 0;
+    this.num_records = 0;
+    this.records = null;
+}
+function TT_Kern0_PairRec()
+{
+    this.left = 0;
+    this.right = 0;
+    this.value = 0;
+}
+//#endif
+function TT_SBit_MetricsRec()
+{
+    this.height = 0;
+    this.width = 0;
+
+    this.horiBearingX = 0;
+    this.horiBearingY = 0;
+    this.horiAdvance = 0;
+
+    this.vertBearingX = 0;
+    this.vertBearingY = 0;
+    this.vertAdvance = 0;
+}
+function TT_SBit_Small_Metrics()
+{
+    this.height = 0;
+    this.width = 0;
+
+    this.bearingX = 0;
+    this.bearingY = 0;
+    this.advance = 0;
+}
+function TT_SBit_LineMetricsRec()
+{
+    this.ascender = 0;
+    this.descender = 0;
+    this.max_width = 0;
+    this.caret_slope_numerator = 0;
+    this.caret_slope_denominator = 0;
+    this.caret_offset = 0;
+    this.min_origin_SB = 0;
+    this.min_advance_SB = 0;
+    this.max_before_BL = 0;
+    this.min_after_BL = 0;
+
+    this.pad1 = 0;
+    this.pad2 = 0;
+}
+function TT_SBit_RangeRec()
+{
+    this.first_glyph = 0;
+    this.last_glyph = 0;
+
+    this.index_format = 0;
+    this.image_format = 0;
+    this.image_offset = 0;
+
+    this.image_size = 0;
+    this.metrics = new TT_SBit_MetricsRec();
+    this.num_glyphs = 0;
+
+    this.glyph_offsets = null;
+    this.glyph_codes = null;
+
+    this.table_offset = 0;
+}
+function TT_SBit_StrikeRec()
+{
+    this.num_ranges = 0;
+    this.sbit_ranges = null;
+    this.ranges_offset = 0;
+
+    this.color_ref = 0;
+
+    this.hori = new TT_SBit_LineMetricsRec();
+    this.vert = new TT_SBit_LineMetricsRec();
+
+    this.start_glyph = 0;
+    this.end_glyph = 0;
+
+    this.x_ppem = 0;
+    this.y_ppem = 0;
+
+    this.bit_depth = 0;
+    this.flags = 0;
+}
+function TT_SBit_ComponentRec()
+{
+    this.glyph_code = 0;
+    this.x_offset = 0;
+    this.y_offset = 0;
+}
+function TT_SBit_ScaleRec()
+{
+    this.hori = new TT_SBit_LineMetricsRec();
+    this.vert = new TT_SBit_LineMetricsRec();
+
+    this.x_ppem = 0;
+    this.y_ppem = 0;
+
+    this.x_ppem_substitute = 0;
+    this.y_ppem_substitute = 0;
+}
+function TT_Post_20Rec()
+{
+    this.num_glyphs = 0;
+    this.num_names = 0;
+    this.glyph_indices = null;
+    this.glyph_names = null;
+}
+function TT_Post_25Rec()
+{
+    this.num_glyphs = 0;
+    this.offsets = null;
+}
+function TT_Post_NamesRec()
+{
+    this.loaded = false;
+    this.format = null;
+}
+//#ifdef TT_CONFIG_OPTION_BDF
+function TT_BDFRec()
+{
+    this.table = null;
+    this.table_end = 0;
+    this.strings = null;
+    this.strings_size = 0;
+    this.num_strikes = 0;
+    this.loaded = 0;
+}
+//#endif
+function TT_GlyphZoneRec()
+{
+    this.memory = null;
+    this.max_points = 0;
+    this.max_contours = 0;
+    this.n_points = 0;    /* number of points in zone    */
+    this.n_contours = 0;  /* number of contours          */
+
+    this.org = null;         /* original point coordinates  */
+    this.cur = null;         /* current point coordinates   */
+    this.orus = null;        /* original (unscaled) point coordinates */
+
+    this.tags = null;        /* current touch flags         */
+    this.contours = null;    /* contour end points          */
+
+    this._offset_org = 0;
+    this._offset_cur = 0;
+    this._offset_orus = 0;
+    this._offset_tags = 0;
+    this._offset_contours = 0;
+
+    this.first_point = 0; /* offset of first (#0) point  */
+}
+TT_GlyphZoneRec.prototype =
+{
+    Clear : function()
+    {
+        this.memory = null;
+        this.max_points = 0;
+        this.max_contours = 0;
+        this.n_points = 0;
+        this.n_contours = 0;
+
+        this.org = null;
+        this.cur = null;
+        this.orus = null;
+
+        this.tags = null;
+        this.contours = null;
+
+        this._offset_org = 0;
+        this._offset_cur = 0;
+        this._offset_orus = 0;
+        this._offset_tags = 0;
+        this._offset_contours = 0;
+
+        this.first_point = 0;
+    },
+
+    Copy : function(src)
+    {
+        this.memory = src.memory;
+        this.max_points = src.max_points;
+        this.max_contours = src.max_contours;
+        this.n_points = src.n_points;
+        this.n_contours = src.n_contours;
+
+        this.org = src.org;
+        this.cur = src.cur;
+        this.orus = src.orus;
+
+        this.tags = src.tags;
+        this.contours = src.contours;
+
+        this._offset_org = src._offset_org;
+        this._offset_cur = src._offset_cur;
+        this._offset_orus = src._offset_orus;
+        this._offset_tags = src._offset_tags;
+        this._offset_contours = src._offset_contours;
+
+        this.first_point = src.first_point;
+    }
+}
+
+function TT_LoaderRec()
+{
+    this.face = null;
+    this.size = null;
+    this.glyph = null;
+    this.gloader = null;
+
+    this.load_flags = 0;
+    this.glyph_index = 0;
+
+    this.stream = null;
+    this.byte_len = 0;
+
+    this.n_contours = 0;
+    this.bbox = new FT_BBox();
+    this.left_bearing = 0;
+    this.advance = 0;
+    this.linear = 0;
+    this.linear_def = 0;
+    this.preserve_pps = 0;
+    this.pp1 = new FT_Vector();
+    this.pp2 = new FT_Vector();
+
+    this.glyf_offset = 0;
+
+    this.base = new TT_GlyphZoneRec();
+    this.zone = new TT_GlyphZoneRec();
+
+    this.exec = null;
+    this.instructions = null;
+    this.ins_pos = 0;
+
+    this.other = null;
+
+    this.top_bearing = 0;
+    this.vadvance = 0;
+    this.pp3 = new FT_Vector();
+    this.pp4 = new FT_Vector();
+
+    this.cursor = 0;
+    this.limit = 0;
+
+    this.Clear = function()
+    {
+        this.load_flags = 0;
+        this.glyph_index = 0;
+
+        this.stream = null;
+        this.byte_len = 0;
+
+        this.n_contours = 0;
+        this.bbox.xMin = 0;
+        this.bbox.yMin = 0;
+        this.bbox.xMax = 0;
+        this.bbox.yMax = 0;
+        this.left_bearing = 0;
+        this.advance = 0;
+        this.linear = 0;
+        this.linear_def = 0;
+        this.preserve_pps = 0;
+        this.pp1.x = 0;
+        this.pp1.y = 0;
+        this.pp2.x = 0;
+        this.pp2.y = 0;
+
+        this.glyf_offset = 0;
+
+        this.exec = null;
+        this.instructions = null;
+        this.ins_pos = 0;
+
+        this.other = null;
+
+        this.top_bearing = 0;
+        this.vadvance = 0;
+        this.pp3.x = 0;
+        this.pp3.y = 0;
+        this.pp4.x = 0;
+        this.pp4.y = 0;
+
+        this.cursor = 0;
+        this.limit = 0;
+
+        this.gloader = null;
+    }
+}
+/******************************************************************************/
+// tttables
+/******************************************************************************/
+function TT_Header()
+{
+    this.Table_Version = 0;
+    this.Font_Revision = 0;
+
+    this.CheckSum_Adjust = 0;
+    this.Magic_Number = 0;
+
+    this.Flags = 0;
+    this.Units_Per_EM = 0;
+
+    this.Created1 = 0;
+    this.Created2 = 0;
+    this.Modified1 = 0;
+    this.Modified2 = 0;
+
+    this.xMin = 0;
+    this.yMin = 0;
+    this.xMax = 0;
+    this.yMax = 0;
+
+    this.Mac_Style = 0;
+    this.Lowest_Rec_PPEM = 0;
+
+    this.Font_Direction = 0;
+    this.Index_To_Loc_Format = 0;
+    this.Glyph_Data_Format = 0;
+}
+function TT_HoriHeader()
+{
+    this.Version = 0;
+    this.Ascender = 0;
+    this.Descender = 0;
+    this.Line_Gap = 0;
+
+    this.advance_Width_Max = 0;
+
+    this.min_Left_Side_Bearing = 0;
+    this.min_Right_Side_Bearing = 0;
+    this.xMax_Extent = 0;
+    this.caret_Slope_Rise = 0;
+    this.caret_Slope_Run = 0;
+    this.caret_Offset = 0;
+
+    this.Reserved1 = 0;
+    this.Reserved2 = 0;
+    this.Reserved3 = 0;
+    this.Reserved4 = 0;
+
+    this.metric_Data_Format = 0;
+    this.number_Of_HMetrics = 0;
+
+    this.long_metrics = null;
+    this.short_metrics = null;
+}
+function TT_VertHeader()
+{
+    this.Version = 0;
+    this.Ascender = 0;
+    this.Descender = 0;
+    this.Line_Gap = 0;
+
+    this.advance_Height_Max = 0;
+
+    this.min_Top_Side_Bearing = 0;
+    this.min_Bottom_Side_Bearing = 0;
+    this.yMax_Extent = 0;
+    this.caret_Slope_Rise = 0;
+    this.caret_Slope_Run = 0;
+    this.caret_Offset = 0;
+
+    this.Reserved1 = 0;
+    this.Reserved2 = 0;
+    this.Reserved3 = 0;
+    this.Reserved4 = 0;
+
+    this.metric_Data_Format = 0;
+    this.number_Of_VMetrics = 0;
+
+    this.long_metrics = null;
+    this.short_metrics = null;
+}
+function TT_OS2()
+{
+    this.version = 0;
+    this.xAvgCharWidth = 0;
+    this.usWeightClass = 0;
+    this.usWidthClass = 0;
+    this.fsType = 0;
+    this.ySubscriptXSize = 0;
+    this.ySubscriptYSize = 0;
+    this.ySubscriptXOffset = 0;
+    this.ySubscriptYOffset = 0;
+    this.ySuperscriptXSize = 0;
+    this.ySuperscriptYSize = 0;
+    this.ySuperscriptXOffset = 0;
+    this.ySuperscriptYOffset = 0;
+    this.yStrikeoutSize = 0;
+    this.yStrikeoutPosition = 0;
+    this.sFamilyClass = 0;
+
+    this.panose = new Array(10);
+
+    this.ulUnicodeRange1 = 0;        /* Bits 0-31   */
+    this.ulUnicodeRange2 = 0;        /* Bits 32-63  */
+    this.ulUnicodeRange3 = 0;        /* Bits 64-95  */
+    this.ulUnicodeRange4 = 0;        /* Bits 96-127 */
+
+    this.achVendID = new Array(4);
+
+    this.fsSelection = 0;
+    this.usFirstCharIndex = 0;
+    this.usLastCharIndex = 0;
+    this.sTypoAscender = 0;
+    this.sTypoDescender = 0;
+    this.sTypoLineGap = 0;
+    this.usWinAscent = 0;
+    this.usWinDescent = 0;
+
+    /* only version 1 tables: */
+    this.ulCodePageRange1 = 0;       /* Bits 0-31   */
+    this.ulCodePageRange2 = 0;       /* Bits 32-63  */
+
+    /* only version 2 tables: */
+    this.sxHeight = 0;
+    this.sCapHeight = 0;
+    this.usDefaultChar = 0;
+    this.usBreakChar = 0;
+    this.usMaxContext = 0;
+}
+function TT_Postscript()
+{
+    this.FormatType = 0;
+    this.italicAngle = 0;
+    this.underlinePosition = 0;
+    this.underlineThickness = 0;
+    this.isFixedPitch = 0;
+    this.minMemType42 = 0;
+    this.maxMemType42 = 0;
+    this.minMemType1 = 0;
+    this.maxMemType1 = 0;
+}
+function TT_PCLT()
+{
+    this.Version = 0;
+    this.FontNumber = 0;
+    this.Pitch = 0;
+    this.xHeight = 0;
+    this.Style = 0;
+    this.TypeFamily = 0;
+    this.CapHeight = 0;
+    this.SymbolSet = 0;
+    this.TypeFace = "";
+    this.CharacterComplement = "";
+    this.FileName = "";
+    this.StrokeWeight = 0;
+    this.WidthType = 0;
+    this.SerifStyle = 0;
+    this.Reserved = 0;
+}
+function TT_MaxProfile()
+{
+    this.version = 0;
+    this.numGlyphs = 0;
+    this.maxPoints = 0;
+    this.maxContours = 0;
+    this.maxCompositePoints = 0;
+    this.maxCompositeContours = 0;
+    this.maxZones = 0;
+    this.maxTwilightPoints = 0;
+    this.maxStorage = 0;
+    this.maxFunctionDefs = 0;
+    this.maxInstructionDefs = 0;
+    this.maxStackElements = 0;
+    this.maxSizeOfInstructions = 0;
+    this.maxComponentElements = 0;
+    this.maxComponentDepth = 0;
+}
+function FT_Get_Sfnt_Table(face, tag)
+{
+    var table = null;
+    if (face && ((face.face_flags & FT_Common.FT_FACE_FLAG_SFNT) != 0))
+    {
+        var service = FT_FACE_FIND_SERVICE( face, "sfnt-table");
+        if (service != null)
+            table = service.get_table(face, tag);
+    }
+    return table;
+}
+function FT_Load_Sfnt_Table(face, tag, offset, buffer, length)
+{
+    if (face == null || ((face.face_flags & FT_Common.FT_FACE_FLAG_SFNT) == 0))
+        return FT_Common.FT_Err_Invalid_Face_Handle;
+
+    var service = FT_FACE_FIND_SERVICE(face, FT_SERVICE_ID_SFNT_TABLE);
+    if (service == null)
+        return FT_Common.FT_Err_Unimplemented_Feature;
+
+    return service.load_table(face, tag, offset, buffer, length);
+}
+function FT_Sfnt_Table_Info(face, table_index, tag, length)
+{
+    if (face == null || ((face.face_flags & FT_Common.FT_FACE_FLAG_SFNT) == 0))
+        return FT_Common.FT_Err_Invalid_Face_Handle;
+
+    var service = FT_FACE_FIND_SERVICE(face, FT_SERVICE_ID_SFNT_TABLE);
+    if (service == null)
+        return FT_Common.FT_Err_Unimplemented_Feature;
+
+    return service.table_info(face, table_index, tag);
+}
+function FT_Get_CMap_Language_ID(charmap)
+{
+    if (charmap == null || charmap.face == null)
+        return 0;
+
+    var service = FT_FACE_FIND_SERVICE(charmap.face, FT_SERVICE_ID_TT_CMAP);
+    if (service == null)
+        return 0;
+    var cmap_info = new TT_CMapInfo();
+    if (0 != service.get_cmap_info( charmap, cmap_info))
+        return 0;
+    return cmap_info.language;
+}
+/******************************************************************************/
+// ftimage
+/******************************************************************************/
+function FT_Vector()
+{
+    this.x = 0;
+    this.y = 0;
+}
+function dublicate_vector(v)
+{
+    var _v = new FT_Vector();
+    _v.x = v.x;
+    _v.y = v.y;
+    return _v;
+}
+function FT_BBox()
+{
+    this.xMin = 0;
+    this.yMin = 0;
+    this.xMax = 0;
+    this.yMax = 0;
+}
+function dublicate_bbox(v)
+{
+    var _v = new FT_BBox();
+    _v.xMin = v.xMin;
+    _v.yMin = v.yMin;
+    _v.xMax = v.xMax;
+    _v.yMax = v.yMax;
+    return _v;
+}
+function FT_Bitmap()
+{
+    this.rows = 0;
+    this.width = 0;
+    this.pitch = 0;
+    this.buffer = null;
+    this.num_grays = 0;
+    this.pixel_mode = 0;
+    this.palette_mode = 0;
+    this.palette = null;
+}
+function DoNullBitmap(im)
+{
+    im.rows = 0;
+    im.width = 0;
+    im.pitch = 0;
+    im.buffer = null;
+    im.num_grays = 0;
+    im.pixel_mode = 0;
+    im.palette_mode = 0;
+    im.palette = null;
+}
+function FT_Outline()
+{
+    this.n_contours = 0;
+    this.n_points = 0;
+
+    this.points = null;
+    this.tags = null;
+    this.contours = null;
+
+    this.flags = 0;
+}
+function EquatingOutline(d, s)
+{
+    d.n_contours = s.n_contours;
+    d.n_points = s.n_points;
+    d.points = s.points;
+    d.tags = s.tags;
+    d.contours = s.contours;
+    d.flags = s.flags;
+}
+function FT_Span()
+{
+    this.x = 0;
+    this.len = 0;
+    this.coverage = 0;
+}
+function FT_Raster_Params()
+{
+    this.target = null;
+    this.source = null;
+    this.flags = 0;
+    this.gray_spans = null;
+    this.black_spans = null;
+    this.bit_test = null;
+    this.bit_set = null;
+    this.user = null;
+    this.clip_box = new FT_BBox();
+}
+/******************************************************************************/
+// ftbitmap
+/******************************************************************************/
+function FT_Bitmap_New(bitmap)
+{
+    DoNullBitmap(bitmap);
+}
+function FT_Bitmap_Copy(library, source, target)
+{
+    var pitch  = source.pitch;
+    if (source == target)
+        return 0;
+
+    if (source.buffer == null)
+    {
+        target.rows = source.rows;
+        target.width = source.width;
+        target.pitch = source.pitch;
+        target.buffer = source.buffer;
+        target.num_grays = source.num_grays;
+        target.pixel_mode = source.pixel_mode;
+        target.palette_mode = source.palette_mode;
+        target.palette = source.palette;
+
+        return 0;
+    }
+
+    if (pitch < 0)
+        pitch = -pitch;
+    var size = (pitch * source.rows);
+
+    if (target.buffer != null)
+    {
+        var target_pitch = target.pitch;
+
+        if (target_pitch < 0 )
+            target_pitch = -target_pitch;
+        var target_size = (target_pitch * target.rows);
+
+        if (target_size != size)
+        {
+            target.buffer = null;
+            target.buffer = g_memory.Alloc(size);//new Array(size);
+        }
+    }
+    else
+        target.buffer = g_memory.Alloc(size);//new Array(size);
+
+    var s = source.buffer;
+    var d = target.buffer;
+    for (var i=0;i<size;i++)
+        d[i]=s[i];
+
+    return 0;
+}
+function FT_Bitmap_Done(library, bitmap)
+{
+    DoNullBitmap(bitmap);
+    return 0;
+}
+/******************************************************************************/
+// ftsnames
+/******************************************************************************/
+function FT_SfntName()
+{
+    this.platform_id = 0;
+    this.encoding_id = 0;
+    this.language_id = 0;
+    this.name_id = 0;
+
+    this.string = "";
+    this.string_len = 0;
+}
+function FT_Get_Sfnt_Name_Count(face)
+{
+    return (face != null && (face.face_flags & FT_Common.FT_FACE_FLAG_SFNT) != 0) ? face.num_names : 0;
+}
+function FT_Get_Sfnt_Name(face, idx, aname)
+{
+    var error = FT_Common.FT_Err_Invalid_Argument;
+    if (face != null && (face.face_flags & FT_Common.FT_FACE_FLAG_SFNT) != 0)
+    {
+        if (idx < face.num_names)
+        {
+            var entry = face.name_table.names[idx];
+
+            if (entry.stringLength > 0 && entry.string == null)
+            {
+                var stream = face.stream;
+                error = stream.Seek(entry.stringOffset);
+                entry.string = stream.ReadString1(entry.stringLength);
+                error = FT_Error;
+
+                if (0 != error)
+                {
+                    entry.string = null;
+                    entry.stringLength = 0;
+                }
+            }
+
+            aname.platform_id = entry.platformID;
+            aname.encoding_id = entry.encodingID;
+            aname.language_id = entry.languageID;
+            aname.name_id     = entry.nameID;
+            aname.string      = entry.string;
+            aname.string_len  = entry.stringLength;
+        }
+    }
+    return 0;
+}
+/******************************************************************************/
+// ftincrem
+/******************************************************************************/
+function FT_Incremental_MetricsRec()
+{
+    this.bearing_x = 0;
+    this.bearing_y = 0;
+    this.advance = 0;
+    this.advance_v = 0;
+}
+function FT_Incremental_FuncsRec()
+{
+    this.get_glyph_data = null;
+    this.free_glyph_data = null;
+    this.get_glyph_metrics = null;
+}
+function FT_Incremental_Interface()
+{
+    this.funcs = null;
+    this.object = null;
+}
+/******************************************************************************/
+// fttypes
+/******************************************************************************/
+function FT_Matrix()
+{
+    this.xx = 0;
+    this.xy = 0;
+    this.yx = 0;
+    this.yy = 0;
+}
+function dublicate_matrix(m)
+{
+    var _m = new FT_Matrix();
+    _m.xx = m.xx;
+    _m.xy = m.xy;
+    _m.yx = m.yx;
+    _m.yy = m.yy;
+    return _m;
+}
+function FT_Data()
+{
+    this.pointer = null;
+    this.length = 0;
+}
+function FT_Generic()
+{
+    this.data = null;
+    this.finalizer = null;
+}
+function FT_Glyph_Metrics()
+{
+    this.width = 0;
+    this.height = 0;
+
+    this.horiBearingX = 0;
+    this.horiBearingY = 0;
+    this.horiAdvance = 0;
+
+    this.vertBearingX = 0;
+    this.vertBearingY = 0;
+    this.vertAdvance = 0;
+
+}
+function FT_Bitmap_Size()
+{
+    this.height = 0;
+    this.width = 0;
+
+    this.size = 0;
+
+    this.x_ppem = 0;
+    this.y_ppem = 0;
+}
+function FT_CharMapRec()
+{
+    this.face = null;
+    this.encoding = 0;
+    this.platform_id = 0;
+    this.encoding_id = 0;
+}
+function FT_Face()
+{
+    this.num_faces = 0;
+    this.face_index = 0;
+
+    this.face_flags = 0;
+    this.style_flags = 0;
+
+    this.num_glyphs = 0;
+
+    this.family_name = "";
+    this.style_name = "";
+
+    this.num_fixed_sizes = 0;
+    this.available_sizes = [];
+
+    this.num_charmaps = 0;
+    this.charmaps = [];
+
+    this.generic = new FT_Generic();
+
+    /*# The following member variables (down to `underline_thickness') */
+    /*# are only relevant to scalable outlines; cf. @FT_Bitmap_Size    */
+    /*# for bitmap fonts.                                              */
+    this.bbox = new FT_BBox();
+
+    this.units_per_EM = 0;
+    this.ascender = 0;
+    this.descender = 0;
+    this.height = 0;
+
+    this.max_advance_width = 0;
+    this.max_advance_height = 0;
+
+    this.underline_position = 0;
+    this.underline_thickness = 0;
+
+    this.glyph = null;
+    this.size = null;
+    this.charmap = null;
+
+    /*@private begin */
+    this.driver = null;
+    this.memory = null;
+    this.stream = null;
+
+    this.sizes_list = [];
+
+    this.autohint = [];
+    this.extensions = null;
+
+    this.internal = null;
+    /*@private end */
+}
+function FT_Size_Metrics()
+{
+    this.x_ppem = 0;
+    this.y_ppem = 0;
+
+    this.x_scale = 0;
+    this.y_scale = 0;
+
+    this.ascender = 0;
+    this.descender = 0;
+    this.height = 0;
+    this.max_advance = 0;
+}
+FT_Size_Metrics.prototype =
+{
+    Copy : function(src)
+    {
+        this.x_ppem = src.x_ppem;
+        this.y_ppem = src.y_ppem;
+
+        this.x_scale = src.x_scale;
+        this.y_scale = src.y_scale;
+
+        this.ascender = src.ascender;
+        this.descender = src.descender;
+        this.height = src.height;
+        this.max_advance = src.max_advance;
+    }
+};
+
+function FT_Size()
+{
+    this.face = null;
+    this.generic = null;
+    this.metrics = new FT_Size_Metrics();
+    this.internal = null;
+}
+function FT_GlyphSlot()
+{
+    this.library = null;
+    this.face = null;
+    this.next = null;
+    this.reserved = 0;       /* retained for binary compatibility */
+    this.generic = null;
+
+    this.metrics = new FT_Glyph_Metrics();
+    this.linearHoriAdvance = 0;
+    this.linearVertAdvance = 0;
+    this.advance = new FT_Vector();
+
+    this.format = 0;
+
+    this.bitmap = new FT_Bitmap();
+    this.bitmap_left = 0;
+    this.bitmap_top = 0;
+
+    this.outline = new FT_Outline();
+
+    this.num_subglyphs = 0;
+    this.subglyphs = [];
+
+    this.control_data = null;
+    this.control_len = 0;
+
+    this.lsb_delta = 0;
+    this.rsb_delta = 0;
+
+    this.other = null;
+
+    this.internal = null;
+
+    this.base_root = null;
+}
+function FT_Open_Args()
+{
+    this.flags = null;
+    this.memory_base = null;
+    this.memory_size = null;
+    this.pathname = "";
+    this.stream = null;
+    this.driver = null;
+    this.num_params = 0;
+    this.params = null;
+}
+function FT_Size_RequestRec()
+{
+    this.type = 0;
+    this.width = 0;
+    this.height = 0;
+    this.horiResolution = 0;
+    this.vertResolution = 0;
+}
+function FT_CMapRec()
+{
+    this.charmap = new FT_CharMapRec();
+    this.clazz = null;
+
+    this.type = FT_Common.FT_CMAP_0;
+}
+function __FT_CMapRec(val)
+{
+    switch (val.type)
+    {
+        case FT_Common.FT_CMAP_0:
+            return val;
+        case FT_Common.FT_CMAP_1:
+            return val.cmap;
+        case FT_Common.FT_CMAP_4:
+        case FT_Common.FT_CMAP_12:
+        case FT_Common.FT_CMAP_13:
+        case FT_Common.FT_CMAP_14:
+            return val.cmap.cmap;
+        default:
+            break;
+    }
+    return val;
+}
+function __FT_TTCMapRec(val)
+{
+    switch (val.type)
+    {
+        case FT_Common.FT_CMAP_0:
+            return null;
+        case FT_Common.FT_CMAP_1:
+            return val;
+        case FT_Common.FT_CMAP_4:
+        case FT_Common.FT_CMAP_12:
+        case FT_Common.FT_CMAP_13:
+        case FT_Common.FT_CMAP_14:
+            return val.cmap;
+        default:
+            break;
+    }
+    return null;
+}
+function __FT_CharmapRec(val)
+{
+    switch (val.type)
+    {
+        case FT_Common.FT_CMAP_0:
+            return val.charmap;
+        case FT_Common.FT_CMAP_1:
+            return val.cmap.charmap;
+        case FT_Common.FT_CMAP_4:
+        case FT_Common.FT_CMAP_12:
+        case FT_Common.FT_CMAP_13:
+        case FT_Common.FT_CMAP_14:
+            return val.cmap.cmap.charmap;
+        default:
+            break;
+    }
+    return val.charmap;
+}
+function FT_CMap_ClassRec()
+{
+    this.size = 0;
+    this.init = null;
+    this.done = null;
+    this.char_index = null;
+    this.char_next = null;
+
+    this.char_var_index = null;
+    this.char_var_default = null;
+    this.variant_list = null;
+    this.charvariant_list = null;
+    this.variantchar_list = null;
+}
+function create_cmap_class_rec(size_,init_,done_,char_index_,char_next_,var_index_,var_default_,
+                               var_list_,char_var_list_, var_char_list_)
+{
+    var c = new FT_CMap_ClassRec();
+    c.size = size_;
+    c.init = init_;
+    c.done = done_;
+    c.char_index = char_index_;
+    c.char_next = char_next_;
+
+    c.char_var_index = var_index_;
+    c.char_var_default = var_default_;
+    c.variant_list = var_list_;
+    c.charvariant_list = char_var_list_;
+    c.variantchar_list = var_char_list_;
+    return c;
+}
+function FT_Face_Internal()
+{
+    //#ifdef FT_CONFIG_OPTION_OLD_INTERNALS
+    this.reserved1 = 0;
+    this.reserved2 = 0;
+    //#endif
+    this.transform_matrix = new FT_Matrix();
+    this.transform_delta = new FT_Vector();
+    this.transform_flags = 0;
+
+    this.services = new FT_ServiceCache();
+
+    //#ifdef FT_CONFIG_OPTION_INCREMENTAL
+    this.incremental_interface = null;
+    //#endif
+
+    this.ignore_unpatented_hinter = false;
+    this.refcount = 0;
+}
+function FT_Slot_Internal()
+{
+    this.loader = null;
+    this.flags = 0;
+    this.glyph_transformed = false;
+    this.glyph_matrix = new FT_Matrix();
+    this.glyph_delta = new FT_Vector();
+    this.glyph_hints = null;
+}
+function FT_Module()
+{
+    this.clazz = null;      // FT_Module_Class
+    this.library = null;    // FT_Library
+    this.memory = null;     // FT_Memory
+    this.generic = null;    // FT_Generic
+}
+function FT_Driver()
+{
+    this.root = new FT_Module();
+    this.clazz = new FT_Driver_Class();
+    this.faces_list = [];
+    this.extensions = null;
+    this.glyph_loader = null;
+}
+function FT_Module_Class()
+{
+    this.flags = 0;
+    this.name = "";
+    this.version = 0;
+    this.requires = 0;
+
+    this.module_interface = null;
+
+    this.init = null;
+    this.done = null;
+    this.get_interface = null;
+}
+/******************************************************************************/
+// outline
+/******************************************************************************/
+function FT_Outline_New(library, numPoints, numContours, anoutline)
+{
+    if (library == null)
+        return FT_Common.FT_Err_Invalid_Library_Handle;
+
+    return FT_Outline_New_Internal(library.Memory, numPoints, numContours, anoutline);
+}
+function FT_Outline_New_Internal(memory, numPoints, numContours, anoutline)
+{
+    if (null == anoutline || null == memory)
+        return FT_Common.FT_Err_Invalid_Argument;
+
+    var _points = new Array(numPoints);
+    for (var i = 0; i < numPoints; i++)
+        _points[i] = new FT_Vector();
+
+    var _tags = new Array(numPoints);
+    for (var i = 0; i < numPoints; i++)
+        _tags[i] = 0;
+    var _contours = new Array(numContours);
+    for (var i = 0; i < numContours; i++)
+        _contours[i] = 0;
+
+    anoutline.points = _points;
+    anoutline.tags = _tags;
+    anoutline.contours = _contours;
+
+    anoutline.n_points    = numPoints & 0xFFFF;
+    anoutline.n_contours  = numContours & 0xFFFF;
+    anoutline.flags      |= FT_Common.FT_OUTLINE_OWNER;
+
+    return 0;
+}
+function FT_Outline_Check(outline)
+{
+    if (outline != null)
+    {
+        var n_points   = outline.n_points;
+        var n_contours = outline.n_contours;
+        var end0, end;
+        var n;
+
+        if (n_points == 0 && n_contours == 0)
+            return 0;
+
+        if (n_points <= 0 || n_contours <= 0)
+            return FT_Common.FT_Err_Invalid_Argument;
+
+        end0 = end = -1;
+        var _c = outline.contours;
+        for (n = 0; n < n_contours; n++)
+        {
+            end = _c[n];
+            if (end <= end0 || end >= n_points)
+                return FT_Common.FT_Err_Invalid_Argument;
+            end0 = end;
+        }
+
+        if ( end != n_points - 1 )
+            return FT_Common.FT_Err_Invalid_Argument;
+
+        return 0;
+    }
+    return FT_Common.FT_Err_Invalid_Argument;
+}
+function FT_Outline_Copy(source, target)
+{
+    if (null == source || null == target || source.n_points != target.n_points || source.n_contours != target.n_contours)
+        return FT_Common.FT_Err_Invalid_Argument;
+
+    if (source == target)
+        return 0;
+
+    var n_p = source.n_points;
+    var s_p = source.points;
+    var d_p = target.points;
+    var s_t = source.tags;
+    var t_t = target.tags;
+    for (var i = 0; i < n_p; i++)
+    {
+        d_p[i].x = s_p[i].x;
+        d_p[i].y = s_p[i].y;
+
+        t_t[i] = s_t[i];
+    }
+
+    var n_c = source.n_contours;
+    var s_c = source.contours;
+    var t_c = target.contours;
+    for (var i = 0; i < source.n_contours; i++)
+    {
+        t_c[i] = s_c[i];
+    }
+
+    var is_owner = target.flags & FT_Common.FT_OUTLINE_OWNER;
+    target.flags = source.flags;
+
+    target.flags &= ~FT_Common.FT_OUTLINE_OWNER;
+    target.flags |= is_owner;
+
+    return 0;
+}
+function FT_Outline_Done_Internal(memory, outline)
+{
+    if (memory != null && outline != null)
+    {
+        if (outline.flags & FT_Common.FT_OUTLINE_OWNER)
+        {
+            outline.points = null;
+            outline.tags = null;
+            outline.contours = null;
+        }
+
+        outline.n_points = 0;
+        outline.n_contours = 0;
+        outline.flags = 0;
+
+        return 0;
+    }
+    else
+        return FT_Common.FT_Err_Invalid_Argument;
+}
+function FT_Outline_Done(library, outline)
+{
+    if (library == null)
+        return FT_Common.FT_Err_Invalid_Library_Handle;
+
+    return FT_Outline_Done_Internal(library.memory, outline);
+}
+/******************************************************************************/
+// obj
+/******************************************************************************/
+function find_unicode_charmap(face)
+{
+    if (null == face || null == face.charmaps)
+        return FT_Common.FT_Err_Invalid_CharMap_Handle;
+
+    var count = Math.min(face.charmaps.length, face.num_charmaps);
+    if (0 == count)
+        return FT_Common.FT_Err_Invalid_CharMap_Handle;
+
+    var cur = count - 1;
+    for ( ; cur >= 0; cur--)
+    {
+        var cmap = __FT_CharmapRec(face.charmaps[cur]);
+        if (cmap.encoding == FT_Common.FT_ENCODING_UNICODE)
+        {
+            if ((cmap.platform_id == FT_Common.TT_PLATFORM_MICROSOFT && cmap.encoding_id == FT_Common.TT_MS_ID_UCS_4) ||
+                (cmap.platform_id == FT_Common.TT_PLATFORM_APPLE_UNICODE && cmap.encoding_id == FT_Common.TT_APPLE_ID_UNICODE_32))
+            {
+                //#ifdef FT_MAX_CHARMAP_CACHEABLE
+                if (cur > FT_Common.FT_MAX_CHARMAP_CACHEABLE)
+                {
+                    continue;
+                }
+                //#endif
+                face.charmap = face.charmaps[cur];
+                return FT_Common.FT_Err_Ok;
+            }
+        }
+    }
+    cur = count - 1;
+    for ( ; cur >= 0; cur--)
+    {
+        var cmap = __FT_CharmapRec(face.charmaps[cur]);
+        if (cmap.encoding == FT_Common.FT_ENCODING_UNICODE)
+        {
+            //#ifdef FT_MAX_CHARMAP_CACHEABLE
+            if (cur > FT_Common.FT_MAX_CHARMAP_CACHEABLE)
+            {
+                continue;
+            }
+            //#endif
+            face.charmap = face.charmaps[cur];
+            return FT_Common.FT_Err_Ok;
+        }
+    }
+    return FT_Common.FT_Err_Invalid_CharMap_Handle;
+}
+function ft_glyphslot_init(slot)
+{
+    var driver = slot.face.driver;
+    slot.library = driver.library;
+    slot.internal = new FT_Slot_Internal();
+
+    var error = 0;
+    if ((driver.flags & FT_Common.FT_MODULE_DRIVER_NO_OUTLINES) == 0)
+        slot.internal.loader = FT_GlyphLoader_New(driver.memory);
+
+    if (driver.clazz.init_slot)
+        error = driver.clazz.init_slot(slot);
+    return error;
+}
+function ft_glyphslot_free_bitmap(slot)
+{
+    if (slot.internal != null && (slot.internal.flags & FT_Common.FT_GLYPH_OWN_BITMAP) != 0)
+    {
+        slot.bitmap.buffer = null;
+        slot.internal.flags &= ~FT_Common.FT_GLYPH_OWN_BITMAP;
+    }
+    else
+    {
+        slot.bitmap.buffer = null;
+    }
+}
+function ft_glyphslot_set_bitmap(slot, buffer)
+{
+    ft_glyphslot_free_bitmap(slot);
+    slot.bitmap.buffer = buffer;
+}
+function ft_glyphslot_alloc_bitmap(slot, size)
+{
+    if ((slot.internal.flags & FT_Common.FT_GLYPH_OWN_BITMAP) != 0)
+        slot.bitmap.buffer = null;
+    else
+        slot.internal.flags |= FT_Common.FT_GLYPH_OWN_BITMAP;
+
+    slot.bitmap.buffer = g_memory.Alloc(size);
+    return 0;
+}
+function ft_glyphslot_clear(slot)
+{
+    ft_glyphslot_free_bitmap(slot);
+
+    var metrics = slot.metrics;
+    metrics.width = 0;
+    metrics.height = 0;
+    metrics.horiBearingX = 0;
+    metrics.horiBearingY = 0;
+    metrics.horiAdvance = 0;
+    metrics.vertBearingX = 0;
+    metrics.vertBearingY = 0;
+    metrics.vertAdvance = 0;
+
+    var outl = slot.outline;
+    outl.n_contours = 0;
+    outl.n_points = 0;
+    outl.contours = null;
+    outl.points = null;
+    outl.tags = null;
+    outl.flags = 0;
+
+    slot.bitmap.width      = 0;
+    slot.bitmap.rows       = 0;
+    slot.bitmap.pitch      = 0;
+    slot.bitmap.pixel_mode = 0;
+
+    slot.bitmap_left   = 0;
+    slot.bitmap_top    = 0;
+    slot.num_subglyphs = 0;
+    slot.subglyphs     = 0;
+    slot.control_data  = 0;
+    slot.control_len   = 0;
+    slot.other         = 0;
+    slot.format        = FT_Common.FT_GLYPH_FORMAT_NONE;
+
+    slot.linearHoriAdvance = 0;
+    slot.linearVertAdvance = 0;
+    slot.lsb_delta         = 0;
+    slot.rsb_delta         = 0;
+}
+function ft_glyphslot_done(slot)
+{
+    var clazz = slot.face.driver.clazz;
+    if (clazz.done_slot != null)
+        clazz.done_slot(slot);
+
+    ft_glyphslot_free_bitmap(slot);
+    slot.internal = null;
+}
+function ft_glyphslot_grid_fit_metrics(slot,  vertical)
+{
+    var metrics = slot.metrics;
+    var right, bottom;
+
+    if (1 ==  vertical)
+    {
+        metrics.horiBearingX = FT_PIX_FLOOR(metrics.horiBearingX);
+        metrics.horiBearingY = FT_PIX_CEIL (metrics.horiBearingY);
+
+        right  = FT_PIX_CEIL(metrics.vertBearingX + metrics.width);
+        bottom = FT_PIX_CEIL(metrics.vertBearingY + metrics.height);
+
+        metrics.vertBearingX = FT_PIX_FLOOR(metrics.vertBearingX);
+        metrics.vertBearingY = FT_PIX_FLOOR(metrics.vertBearingY);
+
+        metrics.width  = right - metrics.vertBearingX;
+        metrics.height = bottom - metrics.vertBearingY;
+    }
+    else
+    {
+        metrics.vertBearingX = FT_PIX_FLOOR(metrics.vertBearingX);
+        metrics.vertBearingY = FT_PIX_FLOOR(metrics.vertBearingY);
+
+        right  = FT_PIX_CEIL (metrics.horiBearingX + metrics.width);
+        bottom = FT_PIX_FLOOR(metrics.horiBearingY - metrics.height);
+
+        metrics.horiBearingX = FT_PIX_FLOOR(metrics.horiBearingX);
+        metrics.horiBearingY = FT_PIX_CEIL (metrics.horiBearingY);
+
+        metrics.width  = right - metrics.horiBearingX;
+        metrics.height = metrics.horiBearingY - bottom;
+    }
+
+    metrics.horiAdvance = FT_PIX_ROUND(metrics.horiAdvance);
+    metrics.vertAdvance = FT_PIX_ROUND(metrics.vertAdvance);
+}
+function ft_synthesize_vertical_metrics(metrics, advance)
+{
+    var height = metrics.height;
+
+    /* compensate for glyph with bbox above/below the baseline */
+    if (metrics.horiBearingY < 0)
+    {
+        if (height < metrics.horiBearingY)
+            height = metrics.horiBearingY;
+    }
+    else if (metrics.horiBearingY > 0)
+        height -= metrics.horiBearingY;
+
+    /* the factor 1.2 is a heuristical value */
+    if (advance == 0)
+        advance = parseInt(height * 12 / 10);
+
+    metrics.vertBearingX = parseInt(metrics.horiBearingX - metrics.horiAdvance / 2);
+    metrics.vertBearingY = parseInt((advance - height) / 2);
+    metrics.vertAdvance  = advance;
+}
\ No newline at end of file
diff --git a/Common/FontsFreeType/Private/FreeType/config.js b/Common/FontsFreeType/Private/FreeType/config.js
new file mode 100644
index 0000000000000000000000000000000000000000..e130ff0eeea752aaad3044ec43f62d104f6a6e1b
--- /dev/null
+++ b/Common/FontsFreeType/Private/FreeType/config.js
@@ -0,0 +1,1078 @@
+function FT_MAKE_TAG(a,b,c,d)
+{
+    var r = a.charCodeAt(0) << 24 | b.charCodeAt(0) << 16 | c.charCodeAt(0) << 8 | d.charCodeAt(0);
+    if (r < 0)
+        r+=FT_Common.a_i;
+    return r;
+}
+function _FT_Common()
+{
+// GENERATOR_START_CONSTANTS
+    this.FT_ENCODING_NONE = 0;
+
+    this.FT_ENCODING_MS_SYMBOL = FT_MAKE_TAG("s","y","m","b");
+    this.FT_ENCODING_UNICODE = FT_MAKE_TAG("u","n","i","c");
+
+    this.FT_ENCODING_SJIS = FT_MAKE_TAG("s","j","i","s");
+    this.FT_ENCODING_GB2312 = FT_MAKE_TAG("g","b"," "," ");
+    this.FT_ENCODING_BIG5 = FT_MAKE_TAG("b","i","g","5");
+    this.FT_ENCODING_WANSUNG = FT_MAKE_TAG("w","a","n","s");
+    this.FT_ENCODING_JOHAB = FT_MAKE_TAG("j","o","h","a");
+
+    /* for backwards compatibility */
+    this.FT_ENCODING_MS_SJIS    = this.FT_ENCODING_SJIS;
+    this.FT_ENCODING_MS_GB2312  = this.FT_ENCODING_GB2312;
+    this.FT_ENCODING_MS_BIG5    = this.FT_ENCODING_BIG5;
+    this.FT_ENCODING_MS_WANSUNG = this.FT_ENCODING_WANSUNG;
+    this.FT_ENCODING_MS_JOHAB   = this.FT_ENCODING_JOHAB;
+
+    this.FT_ENCODING_ADOBE_STANDARD = FT_MAKE_TAG("A","D","O","B");
+    this.FT_ENCODING_ADOBE_EXPERT = FT_MAKE_TAG("A","D","B","E");
+    this.FT_ENCODING_ADOBE_CUSTOM = FT_MAKE_TAG("A","D","B","C");
+    this.FT_ENCODING_ADOBE_LATIN_1 = FT_MAKE_TAG("l","a","t","1");
+
+    this.FT_ENCODING_OLD_LATIN_2 = FT_MAKE_TAG("l","a","t","2");
+
+    this.FT_ENCODING_APPLE_ROMAN = FT_MAKE_TAG("a","r","m","n");
+
+    // modules types
+    this.FT_MODULE_FONT_DRIVER        = 1;
+    this.FT_MODULE_RENDERER           = 2;
+    this.FT_MODULE_HINTER             = 4;
+    this.FT_MODULE_STYLER             = 8;
+
+    this.FT_MODULE_DRIVER_SCALABLE    = 0x100;
+    this.FT_MODULE_DRIVER_NO_OUTLINES = 0x200;
+    this.FT_MODULE_DRIVER_HAS_HINTER  = 0x400;
+
+    // errors codes
+    this.FT_Err_Ok                             = 0x00;
+    this.FT_Err_Cannot_Open_Resource           = 0x01;
+    this.FT_Err_Unknown_File_Format            = 0x02;
+    this.FT_Err_Invalid_File_Format            = 0x03;
+    this.FT_Err_Invalid_Version                = 0x04;
+    this.FT_Err_Lower_Module_Version           = 0x05;
+    this.FT_Err_Invalid_Argument               = 0x06;
+    this.FT_Err_Unimplemented_Feature          = 0x07;
+    this.FT_Err_Invalid_Table                  = 0x08;
+    this.FT_Err_Invalid_Offset                 = 0x09;
+    this.FT_Err_Array_Too_Large                = 0x0A;
+
+    /* glyph/character errors */
+    this.FT_Err_Invalid_Glyph_Index            = 0x10;
+    this.FT_Err_Invalid_Character_Code         = 0x11;
+    this.FT_Err_Invalid_Glyph_Format           = 0x12;
+    this.FT_Err_Cannot_Render_Glyph            = 0x13;
+    this.FT_Err_Invalid_Outline                = 0x14;
+    this.FT_Err_Invalid_Composite              = 0x15;
+    this.FT_Err_Too_Many_Hints                 = 0x16;
+    this.FT_Err_Invalid_Pixel_Size             = 0x17;
+
+    /* handle errors */
+    this.FT_Err_Invalid_Handle                 = 0x20;
+    this.FT_Err_Invalid_Library_Handle         = 0x21;
+    this.FT_Err_Invalid_Driver_Handle          = 0x22;
+    this.FT_Err_Invalid_Face_Handle            = 0x23;
+    this.FT_Err_Invalid_Size_Handle            = 0x24;
+    this.FT_Err_Invalid_Slot_Handle            = 0x25;
+    this.FT_Err_Invalid_CharMap_Handle         = 0x26;
+    this.FT_Err_Invalid_Cache_Handle           = 0x27;
+    this.FT_Err_Invalid_Stream_Handle          = 0x28;
+
+    /* driver errors */
+    this.FT_Err_Too_Many_Drivers               = 0x30;
+    this.FT_Err_Too_Many_Extensions            = 0x31;
+    /* memory errors */
+
+    this.FT_Err_Out_Of_Memory                  = 0x40;
+    this.FT_Err_Unlisted_Object                = 0x41;
+
+    /* stream errors */
+    this.FT_Err_Cannot_Open_Stream             = 0x51;
+    this.FT_Err_Invalid_Stream_Seek            = 0x52;
+    this.FT_Err_Invalid_Stream_Skip            = 0x53;
+    this.FT_Err_Invalid_Stream_Read            = 0x54;
+    this.FT_Err_Invalid_Stream_Operation       = 0x55;
+    this.FT_Err_Invalid_Frame_Operation        = 0x56;
+    this.FT_Err_Nested_Frame_Access            = 0x57;
+    this.FT_Err_Invalid_Frame_Read             = 0x58;
+
+    /* raster errors */
+    this.FT_Err_Raster_Uninitialized           = 0x60;
+    this.FT_Err_Raster_Corrupted               = 0x61;
+    this.FT_Err_Raster_Overflow                = 0x62;
+    this.FT_Err_Raster_Negative_Height         = 0x63;
+
+    /* cache errors */
+    this.FT_Err_Too_Many_Caches                = 0x70;
+
+    /* TrueType and SFNT errors */
+    this.FT_Err_Invalid_Opcode                 = 0x80;
+    this.FT_Err_Too_Few_Arguments              = 0x81;
+    this.FT_Err_Stack_Overflow                 = 0x82;
+    this.FT_Err_Code_Overflow                  = 0x83;
+    this.FT_Err_Bad_Argument                   = 0x84;
+    this.FT_Err_Divide_By_Zero                 = 0x85;
+    this.FT_Err_Invalid_Reference              = 0x86;
+    this.FT_Err_Debug_OpCode                   = 0x87;
+    this.FT_Err_ENDF_In_Exec_Stream            = 0x88;
+    this.FT_Err_Nested_DEFS                    = 0x89;
+    this.FT_Err_Invalid_CodeRange              = 0x8A;
+    this.FT_Err_Execution_Too_Long             = 0x8B;
+    this.FT_Err_Too_Many_Function_Defs         = 0x8C;
+    this.FT_Err_Too_Many_Instruction_Defs      = 0x8D;
+    this.FT_Err_Table_Missing                  = 0x8E;
+    this.FT_Err_Horiz_Header_Missing           = 0x8F;
+    this.FT_Err_Locations_Missing              = 0x90;
+    this.FT_Err_Name_Table_Missing             = 0x91;
+    this.FT_Err_CMap_Table_Missing             = 0x92;
+    this.FT_Err_Hmtx_Table_Missing             = 0x93;
+    this.FT_Err_Post_Table_Missing             = 0x94;
+    this.FT_Err_Invalid_Horiz_Metrics          = 0x95;
+    this.FT_Err_Invalid_CharMap_Format         = 0x96;
+    this.FT_Err_Invalid_PPem                   = 0x97;
+    this.FT_Err_Invalid_Vert_Metrics           = 0x98;
+    this.FT_Err_Could_Not_Find_Context         = 0x99;
+    this.FT_Err_Invalid_Post_Table_Format      = 0x9A;
+    this.FT_Err_Invalid_Post_Table             = 0x9B;
+
+    /* CFF, CID, and Type 1 errors */
+    this.FT_Err_Syntax_Error                   = 0xA0;
+    this.FT_Err_Stack_Underflow                = 0xA1;
+    this.FT_Err_Ignore                         = 0xA2;
+    this.FT_Err_No_Unicode_Glyph_Name          = 0xA3;
+
+    /* BDF errors */
+    this.FT_Err_Missing_Startfont_Field        = 0xB0;
+    this.FT_Err_Missing_Font_Field             = 0xB1;
+    this.FT_Err_Missing_Size_Field             = 0xB2;
+    this.FT_Err_Missing_Fontboundingbox_Field  = 0xB3;
+    this.FT_Err_Missing_Chars_Field            = 0xB4;
+    this.FT_Err_Missing_Startchar_Field        = 0xB5;
+    this.FT_Err_Missing_Encoding_Field         = 0xB6;
+    this.FT_Err_Missing_Bbx_Field              = 0xB7;
+    this.FT_Err_Bbx_Too_Big                    = 0xB8;
+    this.FT_Err_Corrupted_Font_Header          = 0xB9;
+    this.FT_Err_Corrupted_Font_Glyphs          = 0xBA;
+
+    this.FT_Mod_Err                            = 0x100;
+
+    //
+    this.BDF_PROPERTY_TYPE_NONE     = 0;
+    this.BDF_PROPERTY_TYPE_ATOM     = 1;
+    this.BDF_PROPERTY_TYPE_INTEGER  = 2;
+    this.BDF_PROPERTY_TYPE_CARDINAL = 3;
+
+    //
+    this.TT_CMAP_FLAG_UNSORTED     = 1;
+    this.TT_CMAP_FLAG_OVERLAPPING  = 2;
+
+    this.m_c = 0x7F;
+    this.m_s = 0x7FFF;
+    this.m_i = 0x7FFFFFFF;
+    this.a_c = 0xFF + 1;
+    this.a_s = 0xFFFF + 1;
+    this.a_i = 0xFFFFFFFF + 1;    
+
+    // base
+    this.FT_MAX_CHARMAP_CACHEABLE = 15;
+
+    this.TT_PLATFORM_APPLE_UNICODE = 0;
+    this.TT_PLATFORM_MACINTOSH = 1;
+    this.TT_PLATFORM_ISO = 2;
+    this.TT_PLATFORM_MICROSOFT = 3;
+    this.TT_PLATFORM_CUSTOM = 4;
+    this.TT_PLATFORM_ADOBE = 7;
+
+    //
+    this.TT_MAC_ID_ROMAN = 0;
+    //
+    this.TT_MS_ID_SYMBOL_CS = 0;
+    this.TT_MS_ID_UNICODE_CS = 1;
+    this.TT_MS_ID_SJIS = 2;
+    this.TT_MS_ID_GB2312 = 3;
+    this.TT_MS_ID_BIG_5 = 4;
+    this.TT_MS_ID_WANSUNG = 5;
+    this.TT_MS_ID_JOHAB = 6;
+    this.TT_MS_ID_UCS_4 = 10;
+
+    this.TT_APPLE_ID_DEFAULT = 0;
+    this.TT_APPLE_ID_UNICODE_1_1 = 1;
+    this.TT_APPLE_ID_ISO_10646 = 2;
+    this.TT_APPLE_ID_UNICODE_2_0 = 3;
+    this.TT_APPLE_ID_UNICODE_32 = 4;
+    this.TT_APPLE_ID_VARIANT_SELECTOR = 5;
+
+    // true type tags
+    this.TTAG_avar = FT_MAKE_TAG("a","v","a","r");
+    this.TTAG_BASE = FT_MAKE_TAG("B","A","S","E");
+    this.TTAG_bdat = FT_MAKE_TAG("b","d","a","t");
+    this.TTAG_BDF  = FT_MAKE_TAG("B","D","F"," ");
+    this.TTAG_bhed = FT_MAKE_TAG("b","h","e","d");
+    this.TTAG_bloc = FT_MAKE_TAG("b","l","o","c");
+    this.TTAG_bsln = FT_MAKE_TAG("b","s","l","n");
+    this.TTAG_CFF  = FT_MAKE_TAG("C","F","F"," ");
+    this.TTAG_CID  = FT_MAKE_TAG("C","I","D"," ");
+    this.TTAG_cmap = FT_MAKE_TAG("c","m","a","p");
+    this.TTAG_cvar = FT_MAKE_TAG("c","v","a","r");
+    this.TTAG_cvt  = FT_MAKE_TAG("c","v","t"," ");
+    this.TTAG_DSIG = FT_MAKE_TAG("D","S","I","G");
+    this.TTAG_EBDT = FT_MAKE_TAG("E","B","D","T");
+    this.TTAG_EBLC = FT_MAKE_TAG("E","B","L","C");
+    this.TTAG_EBSC = FT_MAKE_TAG("E","B","S","C");
+    this.TTAG_feat = FT_MAKE_TAG("f","e","a","t");
+    this.TTAG_FOND = FT_MAKE_TAG("F","O","N","D");
+    this.TTAG_fpgm = FT_MAKE_TAG("f","p","g","m");
+    this.TTAG_fvar = FT_MAKE_TAG("f","v","a","r");
+    this.TTAG_gasp = FT_MAKE_TAG("g","a","s","p");
+    this.TTAG_GDEF = FT_MAKE_TAG("G","D","E","F");
+    this.TTAG_glyf = FT_MAKE_TAG("g","l","y","f");
+    this.TTAG_GPOS = FT_MAKE_TAG("G","P","O","S");
+    this.TTAG_GSUB = FT_MAKE_TAG("G","S","U","B");
+    this.TTAG_gvar = FT_MAKE_TAG("g","v","a","r");
+    this.TTAG_hdmx = FT_MAKE_TAG("h","d","m","x");
+    this.TTAG_head = FT_MAKE_TAG("h","e","a","d");
+    this.TTAG_hhea = FT_MAKE_TAG("h","h","e","a");
+    this.TTAG_hmtx = FT_MAKE_TAG("h","m","t","x");
+    this.TTAG_JSTF = FT_MAKE_TAG("J","S","T","F");
+    this.TTAG_just = FT_MAKE_TAG("j","u","s","t");
+    this.TTAG_kern = FT_MAKE_TAG("k","e","r","n");
+    this.TTAG_lcar = FT_MAKE_TAG("l","c","a","r");
+    this.TTAG_loca = FT_MAKE_TAG("l","o","c","a");
+    this.TTAG_LTSH = FT_MAKE_TAG("L","T","S","H");
+    this.TTAG_LWFN = FT_MAKE_TAG("L","W","F","N");
+    this.TTAG_MATH = FT_MAKE_TAG("M","A","T","H");
+    this.TTAG_maxp = FT_MAKE_TAG("m","a","x","p");
+    this.TTAG_META = FT_MAKE_TAG("M","E","T","A");
+    this.TTAG_MMFX = FT_MAKE_TAG("M","M","F","X");
+    this.TTAG_MMSD = FT_MAKE_TAG("M","M","S","D");
+    this.TTAG_mort = FT_MAKE_TAG("m","o","r","t");
+    this.TTAG_morx = FT_MAKE_TAG("m","o","r","x");
+    this.TTAG_name = FT_MAKE_TAG("n","a","m","e");
+    this.TTAG_opbd = FT_MAKE_TAG("o","p","b","d");
+    this.TTAG_OS2  = FT_MAKE_TAG("O","S","/","2");
+    this.TTAG_OTTO = FT_MAKE_TAG("O","T","T","O");
+    this.TTAG_PCLT = FT_MAKE_TAG("P","C","L","T");
+    this.TTAG_POST = FT_MAKE_TAG("P","O","S","T");
+    this.TTAG_post = FT_MAKE_TAG("p","o","s","t");
+    this.TTAG_prep = FT_MAKE_TAG("p","r","e","p");
+    this.TTAG_prop = FT_MAKE_TAG("p","r","o","p");
+    this.TTAG_sfnt = FT_MAKE_TAG("s","f","n","t");
+    this.TTAG_SING = FT_MAKE_TAG("S","I","N","G");
+    this.TTAG_trak = FT_MAKE_TAG("t","r","a","k");
+    this.TTAG_true = FT_MAKE_TAG("t","r","u","e");
+    this.TTAG_ttc  = FT_MAKE_TAG("t","t","c"," ");
+    this.TTAG_ttcf = FT_MAKE_TAG("t","t","c","f");
+    this.TTAG_TYP1 = FT_MAKE_TAG("T","Y","P","1");
+    this.TTAG_typ1 = FT_MAKE_TAG("t","y","p","1");
+    this.TTAG_VDMX = FT_MAKE_TAG("V","D","M","X");
+    this.TTAG_vhea = FT_MAKE_TAG("v","h","e","a");
+    this.TTAG_vmtx = FT_MAKE_TAG("v","m","t","x");
+
+    //
+    this.FT_FACE_FLAG_SCALABLE         = (1 << 0);
+    this.FT_FACE_FLAG_FIXED_SIZES      = (1 << 1);
+    this.FT_FACE_FLAG_FIXED_WIDTH      = (1 << 2);
+    this.FT_FACE_FLAG_SFNT             = (1 << 3);
+    this.FT_FACE_FLAG_HORIZONTAL       = (1 << 4);
+    this.FT_FACE_FLAG_VERTICAL         = (1 << 5);
+    this.FT_FACE_FLAG_KERNING          = (1 << 6);
+    this.FT_FACE_FLAG_FAST_GLYPHS      = (1 << 7);
+    this.FT_FACE_FLAG_MULTIPLE_MASTERS = (1 << 8);
+    this.FT_FACE_FLAG_GLYPH_NAMES      = (1 << 9);
+    this.FT_FACE_FLAG_EXTERNAL_STREAM  = (1 << 10);
+    this.FT_FACE_FLAG_HINTER           = (1 << 11);
+    this.FT_FACE_FLAG_CID_KEYED        = (1 << 12);
+    this.FT_FACE_FLAG_TRICKY           = (1 << 13);
+
+    this.FT_SIZE_REQUEST_TYPE_NOMINAL   = 0;
+    this.FT_SIZE_REQUEST_TYPE_REAL_DIM  = 1;
+    this.FT_SIZE_REQUEST_TYPE_BBOX      = 2;
+    this.FT_SIZE_REQUEST_TYPE_CELL      = 3;
+    this.FT_SIZE_REQUEST_TYPE_SCALES    = 4;
+    this.FT_SIZE_REQUEST_TYPE_MAX       = 5;
+
+    this.FT_LOAD_DEFAULT                      = 0x0;
+    this.FT_LOAD_NO_SCALE                     = 0x1;
+    this.FT_LOAD_NO_HINTING                   = 0x2;
+    this.FT_LOAD_RENDER                       = 0x4;
+    this.FT_LOAD_NO_BITMAP                    = 0x8;
+    this.FT_LOAD_VERTICAL_LAYOUT              = 0x10;
+    this.FT_LOAD_FORCE_AUTOHINT               = 0x20;
+    this.FT_LOAD_CROP_BITMAP                  = 0x40;
+    this.FT_LOAD_PEDANTIC                     = 0x80;
+    this.FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH  = 0x200;
+    this.FT_LOAD_NO_RECURSE                   = 0x400;
+    this.FT_LOAD_IGNORE_TRANSFORM             = 0x800;
+    this.FT_LOAD_MONOCHROME                   = 0x1000;
+    this.FT_LOAD_LINEAR_DESIGN                = 0x2000;
+    this.FT_LOAD_NO_AUTOHINT                  = 0x8000;
+
+    this.FT_GLYPH_FORMAT_NONE       = 0;
+    this.FT_GLYPH_FORMAT_COMPOSITE  = FT_MAKE_TAG("c","o","m","p");
+    this.FT_GLYPH_FORMAT_BITMAP     = FT_MAKE_TAG("b","i","t","s");
+    this.FT_GLYPH_FORMAT_OUTLINE    = FT_MAKE_TAG("o","u","t","l");
+    this.FT_GLYPH_FORMAT_PLOTTER    = FT_MAKE_TAG("p","l","o","t");
+
+    this.FT_RENDER_MODE_NORMAL      = 0;
+    this.FT_RENDER_MODE_LIGHT       = 1;
+    this.FT_RENDER_MODE_MONO        = 2;
+    this.FT_RENDER_MODE_LCD         = 3;
+    this.FT_RENDER_MODE_LCD_V       = 4;
+    this.FT_RENDER_MODE_MAX         = 5;
+
+    this.FT_SUBGLYPH_FLAG_ARGS_ARE_WORDS            = 1;
+    this.FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES        = 2;
+    this.FT_SUBGLYPH_FLAG_ROUND_XY_TO_GRID          = 4;
+    this.FT_SUBGLYPH_FLAG_SCALE                     = 8;
+    this.FT_SUBGLYPH_FLAG_XY_SCALE                  = 0x40;
+    this.FT_SUBGLYPH_FLAG_2X2                       = 0x80;
+    this.FT_SUBGLYPH_FLAG_USE_MY_METRICS            = 0x200;
+
+    this.FT_LOAD_ADVANCE_ONLY       = 0x100;
+    this.FT_LOAD_SBITS_ONLY         = 0x4000;
+
+    this.FT_KERNING_DEFAULT         = 0;
+    this.FT_KERNING_UNFITTED        = 1;
+    this.FT_KERNING_UNSCALED        = 2;
+
+    //
+    this.TT_NAME_ID_COPYRIGHT           = 0;
+    this.TT_NAME_ID_FONT_FAMILY         = 1;
+    this.TT_NAME_ID_FONT_SUBFAMILY      = 2;
+    this.TT_NAME_ID_UNIQUE_ID           = 3;
+    this.TT_NAME_ID_FULL_NAME           = 4;
+    this.TT_NAME_ID_VERSION_STRING      = 5;
+    this.TT_NAME_ID_PS_NAME             = 6;
+    this.TT_NAME_ID_TRADEMARK           = 7;
+
+    this.TT_NAME_ID_MANUFACTURER        = 8;
+    this.TT_NAME_ID_DESIGNER            = 9;
+    this.TT_NAME_ID_DESCRIPTION         = 10;
+    this.TT_NAME_ID_VENDOR_URL          = 11;
+    this.TT_NAME_ID_DESIGNER_URL        = 12;
+    this.TT_NAME_ID_LICENSE             = 13;
+    this.TT_NAME_ID_LICENSE_URL         = 14;
+
+    this.TT_NAME_ID_PREFERRED_FAMILY     = 16;
+    this.TT_NAME_ID_PREFERRED_SUBFAMILY  = 17;
+    this.TT_NAME_ID_MAC_FULL_NAME        = 18;
+
+    this.TT_NAME_ID_SAMPLE_TEXT          = 19;
+
+    this.TT_NAME_ID_CID_FINDFONT_NAME    = 20;
+
+    this.TT_NAME_ID_WWS_FAMILY           = 21;
+    this.TT_NAME_ID_WWS_SUBFAMILY        = 22;
+
+    //
+    this.FT_STYLE_FLAG_ITALIC   = 1;
+    this.FT_STYLE_FLAG_BOLD     = 2;
+
+    //
+    this.FT_RASTER_FLAG_DEFAULT = 0;
+    this.FT_RASTER_FLAG_AA      = 1;
+    this.FT_RASTER_FLAG_DIRECT  = 2;
+    this.FT_RASTER_FLAG_CLIP    = 4;
+
+    //
+    this.FT_CURVE_TAG_ON        = 1;
+    this.FT_CURVE_TAG_CONIC     = 0;
+    this.FT_CURVE_TAG_CUBIC     = 2;
+
+    //
+    this.FT_OUTLINE_NONE             = 0x0;
+    this.FT_OUTLINE_OWNER            = 0x1;
+    this.FT_OUTLINE_EVEN_ODD_FILL    = 0x2;
+    this.FT_OUTLINE_REVERSE_FILL     = 0x4;
+    this.FT_OUTLINE_IGNORE_DROPOUTS  = 0x8;
+    this.FT_OUTLINE_SMART_DROPOUTS   = 0x10;
+    this.FT_OUTLINE_INCLUDE_STUBS    = 0x20;
+
+    this.FT_OUTLINE_HIGH_PRECISION   = 0x100;
+    this.FT_OUTLINE_SINGLE_PASS      = 0x200;
+
+    //
+    this.FT_GLYPH_OWN_BITMAP         = 0x1;
+
+    //
+    this.FT_PIXEL_MODE_NONE     = 0;
+    this.FT_PIXEL_MODE_MONO     = 1;
+    this.FT_PIXEL_MODE_GRAY     = 2;
+    this.FT_PIXEL_MODE_GRAY2    = 3;
+    this.FT_PIXEL_MODE_GRAY4    = 4;
+    this.FT_PIXEL_MODE_LCD      = 5;
+    this.FT_PIXEL_MODE_LCD_V    = 6;
+    this.FT_PIXEL_MODE_MAX      = 7;
+
+    this.ErrorLongJump          = -100;
+
+    //
+    this.FT_GLYPH_BBOX_UNSCALED  = 0;
+    this.FT_GLYPH_BBOX_SUBPIXELS = 0;
+    this.FT_GLYPH_BBOX_GRIDFIT   = 1;
+    this.FT_GLYPH_BBOX_TRUNCATE  = 2;
+    this.FT_GLYPH_BBOX_PIXELS    = 3;
+
+    // GX_TupleCountFlags
+    this.GX_TC_TUPLES_SHARE_POINT_NUMBERS = 0x8000;
+    this.GX_TC_RESERVED_TUPLE_FLAGS       = 0x7000;
+    this.GX_TC_TUPLE_COUNT_MASK           = 0x0FFF;
+
+    // GX_TupleIndexFlags
+    this.GX_TI_EMBEDDED_TUPLE_COORD  = 0x8000;
+    this.GX_TI_INTERMEDIATE_TUPLE    = 0x4000;
+    this.GX_TI_PRIVATE_POINT_NUMBERS = 0x2000;
+    this.GX_TI_RESERVED_TUPLE_FLAG   = 0x1000;
+    this.GX_TI_TUPLE_INDEX_MASK      = 0x0FFF;
+
+    //
+    this.TTAG_wght = FT_MAKE_TAG("w","g","h","t");
+    this.TTAG_wdth = FT_MAKE_TAG("w","d","t","h");
+    this.TTAG_opsz = FT_MAKE_TAG("o","p","s","z");
+    this.TTAG_slnt = FT_MAKE_TAG("s","l","n","t");
+
+    //
+    this.FT_PARAM_TAG_UNPATENTED_HINTING = FT_MAKE_TAG("u","n","p","a");
+
+    // это для типа указателя на cmap
+    this.FT_CMAP_0      = 0;
+    this.FT_CMAP_1      = 1;
+    this.FT_CMAP_4      = 2;
+    this.FT_CMAP_12     = 3;
+    this.FT_CMAP_13     = 4;
+    this.FT_CMAP_14     = 5;
+
+    // t1types
+    this.T1_BLEND_UNDERLINE_POSITION    = 0;
+    this.T1_BLEND_UNDERLINE_THICKNESS   = 1;
+    this.T1_BLEND_ITALIC_ANGLE          = 2;
+
+    this.T1_BLEND_BLUE_VALUES           = 3;
+    this.T1_BLEND_OTHER_BLUES           = 4;
+    this.T1_BLEND_STANDARD_WIDTH        = 5;
+    this.T1_BLEND_STANDARD_HEIGHT       = 6;
+    this.T1_BLEND_STEM_SNAP_WIDTHS      = 7;
+    this.T1_BLEND_STEM_SNAP_HEIGHTS     = 8;
+    this.T1_BLEND_BLUE_SCALE            = 9;
+    this.T1_BLEND_BLUE_SHIFT            = 10;
+    this.T1_BLEND_FAMILY_BLUES          = 11;
+    this.T1_BLEND_FAMILY_OTHER_BLUES    = 12;
+    this.T1_BLEND_FORCE_BOLD            = 13;
+    this.T1_BLEND_MAX                   = 14;
+
+    this.T1_MAX_MM_DESIGNS              = 16;
+    this.T1_MAX_MM_AXIS                 = 4;
+    this.T1_MAX_MM_MAP_POINTS           = 20;
+
+    this.T1_ENCODING_TYPE_NONE          = 0;
+    this.T1_ENCODING_TYPE_ARRAY         = 1;
+    this.T1_ENCODING_TYPE_STANDARD      = 2;
+    this.T1_ENCODING_TYPE_ISOLATIN1     = 3;
+    this.T1_ENCODING_TYPE_EXPERT        = 4;
+
+    // keys
+    this.PS_DICT_FONT_TYPE              = 0;
+    this.PS_DICT_FONT_MATRIX            = 1;
+    this.PS_DICT_FONT_BBOX              = 2;
+    this.PS_DICT_PAINT_TYPE             = 3;
+    this.PS_DICT_FONT_NAME              = 4;
+    this.PS_DICT_UNIQUE_ID              = 5;
+    this.PS_DICT_NUM_CHAR_STRINGS       = 6;
+    this.PS_DICT_CHAR_STRING_KEY        = 7;
+    this.PS_DICT_CHAR_STRING            = 8;
+    this.PS_DICT_ENCODING_TYPE          = 9;
+    this.PS_DICT_ENCODING_ENTRY         = 10;
+
+        /* conventionally in the font Private dictionary */
+    this.PS_DICT_NUM_SUBRS              = 11;
+    this.PS_DICT_SUBR                   = 12;
+    this.PS_DICT_STD_HW                 = 13;
+    this.PS_DICT_STD_VW                 = 14;
+    this.PS_DICT_NUM_BLUE_VALUES        = 15;
+    this.PS_DICT_BLUE_VALUE             = 16;
+    this.PS_DICT_BLUE_FUZZ              = 17;
+    this.PS_DICT_NUM_OTHER_BLUES        = 18;
+    this.PS_DICT_OTHER_BLUE             = 19;
+    this.PS_DICT_NUM_FAMILY_BLUES       = 20;
+    this.PS_DICT_FAMILY_BLUE            = 21;
+    this.PS_DICT_NUM_FAMILY_OTHER_BLUES = 22;
+    this.PS_DICT_FAMILY_OTHER_BLUE      = 23;
+    this.PS_DICT_BLUE_SCALE             = 24;
+    this.PS_DICT_BLUE_SHIFT             = 25;
+    this.PS_DICT_NUM_STEM_SNAP_H        = 26;
+    this.PS_DICT_STEM_SNAP_H            = 27;
+    this.PS_DICT_NUM_STEM_SNAP_V        = 28;
+    this.PS_DICT_STEM_SNAP_V            = 29;
+    this.PS_DICT_FORCE_BOLD             = 30;
+    this.PS_DICT_RND_STEM_UP            = 31;
+    this.PS_DICT_MIN_FEATURE            = 32;
+    this.PS_DICT_LEN_IV                 = 33;
+    this.PS_DICT_PASSWORD               = 34;
+    this.PS_DICT_LANGUAGE_GROUP         = 35;
+
+    /* conventionally in the font FontInfo dictionary */
+    this.PS_DICT_VERSION                = 36;
+    this.PS_DICT_NOTICE                 = 37;
+    this.PS_DICT_FULL_NAME              = 38;
+    this.PS_DICT_FAMILY_NAME            = 39;
+    this.PS_DICT_WEIGHT                 = 40;
+    this.PS_DICT_IS_FIXED_PITCH         = 41;
+    this.PS_DICT_UNDERLINE_POSITION     = 42;
+    this.PS_DICT_UNDERLINE_THICKNESS    = 43;
+    this.PS_DICT_FS_TYPE                = 44;
+    this.PS_DICT_ITALIC_ANGLE           = 45;
+
+    this.PS_DICT_MAX = this.PS_DICT_ITALIC_ANGLE;
+
+    this.TT_ADOBE_ID_STANDARD  = 0;
+    this.TT_ADOBE_ID_EXPERT    = 1;
+    this.TT_ADOBE_ID_CUSTOM    = 2;
+    this.TT_ADOBE_ID_LATIN_1   = 3;
+
+    // PSAUX
+    this.T1_TOKEN_TYPE_NONE     = 0;
+    this.T1_TOKEN_TYPE_ANY      = 1;
+    this.T1_TOKEN_TYPE_STRING   = 2;
+    this.T1_TOKEN_TYPE_ARRAY    = 3;
+    this.T1_TOKEN_TYPE_KEY      = 4;
+    this.T1_TOKEN_TYPE_MAX      = 5;
+
+    this.T1_FIELD_TYPE_NONE             = 0;
+    this.T1_FIELD_TYPE_BOOL             = 1;
+    this.T1_FIELD_TYPE_INTEGER          = 2;
+    this.T1_FIELD_TYPE_FIXED            = 3;
+    this.T1_FIELD_TYPE_FIXED_1000       = 4;
+    this.T1_FIELD_TYPE_STRING           = 5;
+    this.T1_FIELD_TYPE_KEY              = 6;
+    this.T1_FIELD_TYPE_BBOX             = 7;
+    this.T1_FIELD_TYPE_INTEGER_ARRAY    = 8;
+    this.T1_FIELD_TYPE_FIXED_ARRAY      = 9;
+    this.T1_FIELD_TYPE_CALLBACK         = 10;
+    this.T1_FIELD_TYPE_MAX              = 11;
+
+    this.T1_FIELD_LOCATION_CID_INFO     = 0;
+    this.T1_FIELD_LOCATION_FONT_DICT    = 1;
+    this.T1_FIELD_LOCATION_FONT_EXTRA   = 2;
+    this.T1_FIELD_LOCATION_FONT_INFO    = 3;
+    this.T1_FIELD_LOCATION_PRIVATE      = 4;
+    this.T1_FIELD_LOCATION_BBOX         = 5;
+    this.T1_FIELD_LOCATION_LOADER       = 6;
+    this.T1_FIELD_LOCATION_FACE         = 7;
+    this.T1_FIELD_LOCATION_BLEND        = 8;
+    this.T1_FIELD_LOCATION_MAX          = 9;
+
+    this.T1_FIELD_DICT_FONTDICT         = 1;
+    this.T1_FIELD_DICT_PRIVATE          = 2;
+
+    this.T1_Parse_Start                 = 0;
+    this.T1_Parse_Have_Width            = 1;
+    this.T1_Parse_Have_Moveto           = 2;
+    this.T1_Parse_Have_Path             = 3;
+
+    this.T1_MAX_CHARSTRINGS_OPERANDS    = 256;
+
+    this.AFM_VALUE_TYPE_STRING          = 0;
+    this.AFM_VALUE_TYPE_NAME            = 1;
+    this.AFM_VALUE_TYPE_FIXED           = 2;
+    this.AFM_VALUE_TYPE_INTEGER         = 3;
+    this.AFM_VALUE_TYPE_BOOL            = 4;
+    this.AFM_VALUE_TYPE_INDEX           = 5;
+
+    this.AFM_STREAM_STATUS_NORMAL       = 0;
+    this.AFM_STREAM_STATUS_EOC          = 1;
+    this.AFM_STREAM_STATUS_EOL          = 2;
+    this.AFM_STREAM_STATUS_EOF          = 3;
+
+    this.AFM_MAX_ARGUMENTS              = 5;
+
+    this.AFM_TOKEN_ASCENDER = 0;
+    this.AFM_TOKEN_AXISLABEL = 1;
+    this.AFM_TOKEN_AXISTYPE = 2;
+    this.AFM_TOKEN_B = 3;
+    this.AFM_TOKEN_BLENDAXISTYPES = 4;
+    this.AFM_TOKEN_BLENDDESIGNMAP = 5;
+    this.AFM_TOKEN_BLENDDESIGNPOSITIONS = 6;
+    this.AFM_TOKEN_C = 7;
+    this.AFM_TOKEN_CC = 8;
+    this.AFM_TOKEN_CH = 9;
+    this.AFM_TOKEN_CAPHEIGHT = 10;
+    this.AFM_TOKEN_CHARWIDTH = 11;
+    this.AFM_TOKEN_CHARACTERSET = 12;
+    this.AFM_TOKEN_CHARACTERS = 13;
+    this.AFM_TOKEN_DESCENDER = 14;
+    this.AFM_TOKEN_ENCODINGSCHEME = 15;
+    this.AFM_TOKEN_ENDAXIS = 16;
+    this.AFM_TOKEN_ENDCHARMETRICS = 17;
+    this.AFM_TOKEN_ENDCOMPOSITES = 18;
+    this.AFM_TOKEN_ENDDIRECTION = 19;
+    this.AFM_TOKEN_ENDFONTMETRICS = 20;
+    this.AFM_TOKEN_ENDKERNDATA = 21;
+    this.AFM_TOKEN_ENDKERNPAIRS = 22;
+    this.AFM_TOKEN_ENDTRACKKERN = 23;
+    this.AFM_TOKEN_ESCCHAR = 24;
+    this.AFM_TOKEN_FAMILYNAME = 25;
+    this.AFM_TOKEN_FONTBBOX = 26;
+    this.AFM_TOKEN_FONTNAME = 27;
+    this.AFM_TOKEN_FULLNAME = 28;
+    this.AFM_TOKEN_ISBASEFONT = 29;
+    this.AFM_TOKEN_ISCIDFONT = 30;
+    this.AFM_TOKEN_ISFIXEDPITCH = 31;
+    this.AFM_TOKEN_ISFIXEDV = 32;
+    this.AFM_TOKEN_ITALICANGLE = 33;
+    this.AFM_TOKEN_KP = 34;
+    this.AFM_TOKEN_KPH = 35;
+    this.AFM_TOKEN_KPX = 36;
+    this.AFM_TOKEN_KPY = 37;
+    this.AFM_TOKEN_L = 38;
+    this.AFM_TOKEN_MAPPINGSCHEME = 39;
+    this.AFM_TOKEN_METRICSSETS = 40;
+    this.AFM_TOKEN_N = 41;
+    this.AFM_TOKEN_NOTICE = 42;
+    this.AFM_TOKEN_PCC = 43;
+    this.AFM_TOKEN_STARTAXIS = 44;
+    this.AFM_TOKEN_STARTCHARMETRICS = 45;
+    this.AFM_TOKEN_STARTCOMPOSITES = 46;
+    this.AFM_TOKEN_STARTDIRECTION = 47;
+    this.AFM_TOKEN_STARTFONTMETRICS = 48;
+    this.AFM_TOKEN_STARTKERNDATA = 49;
+    this.AFM_TOKEN_STARTKERNPAIRS = 50;
+    this.AFM_TOKEN_STARTKERNPAIRS0 = 51;
+    this.AFM_TOKEN_STARTKERNPAIRS1 = 52;
+    this.AFM_TOKEN_STARTTRACKKERN = 53;
+    this.AFM_TOKEN_STDHW = 54;
+    this.AFM_TOKEN_STDVW = 55;
+    this.AFM_TOKEN_TRACKKERN = 56;
+    this.AFM_TOKEN_UNDERLINEPOSITION = 57;
+    this.AFM_TOKEN_UNDERLINETHICKNESS = 58;
+    this.AFM_TOKEN_VV = 59;
+    this.AFM_TOKEN_VVECTOR = 60;
+    this.AFM_TOKEN_VERSION = 61;
+    this.AFM_TOKEN_W = 62;
+    this.AFM_TOKEN_W0 = 63;
+    this.AFM_TOKEN_W0X = 64;
+    this.AFM_TOKEN_W0Y = 65;
+    this.AFM_TOKEN_W1 = 66;
+    this.AFM_TOKEN_W1X = 67;
+    this.AFM_TOKEN_W1Y = 68;
+    this.AFM_TOKEN_WX = 69;
+    this.AFM_TOKEN_WY = 70;
+    this.AFM_TOKEN_WEIGHT = 71;
+    this.AFM_TOKEN_WEIGHTVECTOR = 72;
+    this.AFM_TOKEN_XHEIGHT = 73;
+    this.N_AFM_TOKENS = 74;
+    this.AFM_TOKEN_UNKNOWN = 75;
+
+    this.T1_MAX_TABLE_ELEMENTS = 32;
+    this.T1_MAX_SUBRS_CALLS = 16;
+
+    this.TABLE_EXTEND = 5;
+
+    // константы строковые
+    this.SYMBOL_CONST_SR                = "\r".charCodeAt(0);
+    this.SYMBOL_CONST_SN                = "\n".charCodeAt(0);
+    this.SYMBOL_CONST_ST                = "\t".charCodeAt(0);
+    this.SYMBOL_CONST_SF                = "\f".charCodeAt(0);
+    this.SYMBOL_CONST_S0                = "\0".charCodeAt(0);
+
+    this.SYMBOL_CONST_SPACE             = " ".charCodeAt(0);
+    this.SYMBOL_CONST_LS1               = "(".charCodeAt(0);
+    this.SYMBOL_CONST_LS2               = "[".charCodeAt(0);
+    this.SYMBOL_CONST_LS3               = "{".charCodeAt(0);
+    this.SYMBOL_CONST_RS1               = ")".charCodeAt(0);
+    this.SYMBOL_CONST_RS2               = "]".charCodeAt(0);
+    this.SYMBOL_CONST_RS3               = "}".charCodeAt(0);
+    this.SYMBOL_CONST_BS                = "/".charCodeAt(0);
+    this.SYMBOL_CONST_SS                = "\\".charCodeAt(0);
+
+    this.SYMBOL_CONST_MATH_1            = "<".charCodeAt(0);
+    this.SYMBOL_CONST_MATH_2            = ">".charCodeAt(0);
+    this.SYMBOL_CONST_MATH_3            = "%".charCodeAt(0);
+    this.SYMBOL_CONST_MATH_MINUS        = "-".charCodeAt(0);
+    this.SYMBOL_CONST_MATH_PLUS         = "+".charCodeAt(0);
+
+    this.SYMBOL_CONST_0                 = "0".charCodeAt(0);
+    this.SYMBOL_CONST_7                 = "7".charCodeAt(0);
+    this.SYMBOL_CONST_9                 = "9".charCodeAt(0);
+
+    this.SYMBOL_CONST_a                 = "a".charCodeAt(0);
+    this.SYMBOL_CONST_b                 = "b".charCodeAt(0);
+    this.SYMBOL_CONST_c                 = "c".charCodeAt(0);
+    this.SYMBOL_CONST_d                 = "d".charCodeAt(0);
+    this.SYMBOL_CONST_e                 = "e".charCodeAt(0);
+    this.SYMBOL_CONST_f                 = "f".charCodeAt(0);
+    this.SYMBOL_CONST_g                 = "g".charCodeAt(0);
+    this.SYMBOL_CONST_h                 = "h".charCodeAt(0);
+    this.SYMBOL_CONST_i                 = "i".charCodeAt(0);
+    this.SYMBOL_CONST_j                 = "j".charCodeAt(0);
+    this.SYMBOL_CONST_k                 = "k".charCodeAt(0);
+    this.SYMBOL_CONST_l                 = "l".charCodeAt(0);
+    this.SYMBOL_CONST_m                 = "m".charCodeAt(0);
+    this.SYMBOL_CONST_n                 = "n".charCodeAt(0);
+    this.SYMBOL_CONST_o                 = "o".charCodeAt(0);
+    this.SYMBOL_CONST_p                 = "p".charCodeAt(0);
+    this.SYMBOL_CONST_q                 = "q".charCodeAt(0);
+    this.SYMBOL_CONST_r                 = "r".charCodeAt(0);
+    this.SYMBOL_CONST_s                 = "s".charCodeAt(0);
+    this.SYMBOL_CONST_t                 = "t".charCodeAt(0);
+    this.SYMBOL_CONST_u                 = "u".charCodeAt(0);
+    this.SYMBOL_CONST_v                 = "v".charCodeAt(0);
+    this.SYMBOL_CONST_w                 = "w".charCodeAt(0);
+    this.SYMBOL_CONST_x                 = "x".charCodeAt(0);
+    this.SYMBOL_CONST_y                 = "y".charCodeAt(0);
+    this.SYMBOL_CONST_z                 = "z".charCodeAt(0);
+
+    this.SYMBOL_CONST_A                 = "A".charCodeAt(0);
+    this.SYMBOL_CONST_B                 = "B".charCodeAt(0);
+    this.SYMBOL_CONST_C                 = "C".charCodeAt(0);
+    this.SYMBOL_CONST_D                 = "D".charCodeAt(0);
+    this.SYMBOL_CONST_E                 = "E".charCodeAt(0);
+    this.SYMBOL_CONST_F                 = "F".charCodeAt(0);
+    this.SYMBOL_CONST_G                 = "G".charCodeAt(0);
+    this.SYMBOL_CONST_H                 = "H".charCodeAt(0);
+    this.SYMBOL_CONST_I                 = "I".charCodeAt(0);
+    this.SYMBOL_CONST_J                 = "J".charCodeAt(0);
+    this.SYMBOL_CONST_K                 = "K".charCodeAt(0);
+    this.SYMBOL_CONST_L                 = "L".charCodeAt(0);
+    this.SYMBOL_CONST_M                 = "M".charCodeAt(0);
+    this.SYMBOL_CONST_N                 = "N".charCodeAt(0);
+    this.SYMBOL_CONST_O                 = "O".charCodeAt(0);
+    this.SYMBOL_CONST_P                 = "P".charCodeAt(0);
+    this.SYMBOL_CONST_Q                 = "Q".charCodeAt(0);
+    this.SYMBOL_CONST_R                 = "R".charCodeAt(0);
+    this.SYMBOL_CONST_S                 = "S".charCodeAt(0);
+    this.SYMBOL_CONST_T                 = "T".charCodeAt(0);
+    this.SYMBOL_CONST_U                 = "U".charCodeAt(0);
+    this.SYMBOL_CONST_V                 = "V".charCodeAt(0);
+    this.SYMBOL_CONST_W                 = "W".charCodeAt(0);
+    this.SYMBOL_CONST_X                 = "X".charCodeAt(0);
+    this.SYMBOL_CONST_Y                 = "Y".charCodeAt(0);
+    this.SYMBOL_CONST_Z                 = "Z".charCodeAt(0);
+
+    this.SYMBOL_CONST_VOSCL             = "!".charCodeAt(0);
+    this.SYMBOL_CONST_VOPROS            = "?".charCodeAt(0);
+    this.SYMBOL_CONST_LOGOR             = "|".charCodeAt(0);
+
+    this.SYMBOL_CONST_POINT             = ".".charCodeAt(0);
+    this.SYMBOL_CONST_SHARP             = "#".charCodeAt(0);
+    this.SYMBOL_CONST_SERP              = ";".charCodeAt(0);
+    this.SYMBOL_CONST__                 = "_".charCodeAt(0);
+
+    this.op_none = 0;
+    this.op_endchar = 1;
+    this.op_hsbw = 2;
+    this.op_seac = 3;
+    this.op_sbw = 4;
+    this.op_closepath = 5;
+    this.op_hlineto = 6;
+    this.op_hmoveto = 7;
+    this.op_hvcurveto = 8;
+    this.op_rlineto = 9;
+    this.op_rmoveto = 10;
+    this.op_rrcurveto = 11;
+    this.op_vhcurveto = 12;
+    this.op_vlineto = 13;
+    this.op_vmoveto = 14;
+    this.op_dotsection = 15;
+    this.op_hstem = 16;
+    this.op_hstem3 = 17;
+    this.op_vstem = 18;
+    this.op_vstem3 = 19;
+    this.op_div = 20;
+    this.op_callothersubr = 21;
+    this.op_callsubr = 22;
+    this.op_pop = 23;
+    this.op_return = 24;
+    this.op_setcurrentpoint = 25;
+    this.op_unknown15 = 26;
+    this.op_max = 27;
+
+    // cff
+    this.CFF_MAX_CID_FONTS = 256;
+
+    this.CFF_MAX_STACK_DEPTH = 96;
+
+    this.CFF_CODE_TOPDICT = 0x1000;
+    this.CFF_CODE_PRIVATE = 0x2000;
+
+    this.CFFCODE_TOPDICT = 0x1000;
+    this.CFFCODE_PRIVATE = 0x2000;
+
+    this.cff_kind_none = 0;
+    this.cff_kind_num = 1;
+    this.cff_kind_fixed = 2;
+    this.cff_kind_fixed_thousand = 3;
+    this.cff_kind_string = 4;
+    this.cff_kind_bool = 5;
+    this.cff_kind_delta = 6;
+    this.cff_kind_callback = 7;
+    this.cff_kind_max = 8;
+
+    this.CFF_MAX_OPERANDS = 48;
+    this.CFF_MAX_SUBRS_CALLS = 32;
+    this.CFF_MAX_TRANS_ELEMENTS = 32;
+
+    this.CFF_COUNT_CHECK_WIDTH  = 0x80;
+    this.CFF_COUNT_EXACT        = 0x40;
+    this.CFF_COUNT_CLEAR_STACK  = 0x20;
+
+    this.cff_op_unknown = 0;
+
+    this.cff_op_rmoveto = 1;
+    this.cff_op_hmoveto = 2;
+    this.cff_op_vmoveto = 3;
+
+    this.cff_op_rlineto = 4;
+    this.cff_op_hlineto = 5;
+    this.cff_op_vlineto = 6;
+
+    this.cff_op_rrcurveto = 7;
+    this.cff_op_hhcurveto = 8;
+    this.cff_op_hvcurveto = 9;
+    this.cff_op_rcurveline = 10;
+    this.cff_op_rlinecurve = 11;
+    this.cff_op_vhcurveto = 12;
+    this.cff_op_vvcurveto = 13;
+
+    this.cff_op_flex = 14;
+    this.cff_op_hflex = 15;
+    this.cff_op_hflex1 = 16;
+    this.cff_op_flex1 = 17;
+
+    this.cff_op_endchar = 18;
+
+    this.cff_op_hstem = 19;
+    this.cff_op_vstem = 20;
+    this.cff_op_hstemhm = 21;
+    this.cff_op_vstemhm = 22;
+
+    this.cff_op_hintmask = 23;
+    this.cff_op_cntrmask = 24;
+    this.cff_op_dotsection = 25;
+
+    this.cff_op_abs = 26;
+    this.cff_op_add = 27;
+    this.cff_op_sub = 28;
+    this.cff_op_div = 29;
+    this.cff_op_neg = 30;
+    this.cff_op_random = 31;
+    this.cff_op_mul = 32;
+    this.cff_op_sqrt = 33;
+
+    this.cff_op_blend = 34;
+
+    this.cff_op_drop = 35;
+    this.cff_op_exch = 36;
+    this.cff_op_index = 37;
+    this.cff_op_roll = 38;
+    this.cff_op_dup = 39;
+
+    this.cff_op_put = 40;
+    this.cff_op_get = 41;
+    this.cff_op_store = 42;
+    this.cff_op_load = 43;
+
+    this.cff_op_and = 44;
+    this.cff_op_or = 45;
+    this.cff_op_not = 46;
+    this.cff_op_eq = 47;
+    this.cff_op_ifelse = 48;
+
+    this.cff_op_callsubr = 49;
+    this.cff_op_callgsubr = 50;
+    this.cff_op_return = 51;
+
+    /* Type 1 opcodes: invalid but seen in real life */
+    this.cff_op_hsbw = 52;
+    this.cff_op_closepath = 53;
+    this.cff_op_callothersubr = 54;
+    this.cff_op_pop = 55;
+    this.cff_op_seac = 56;
+    this.cff_op_sbw = 57;
+    this.cff_op_setcurrentpoint = 58;
+
+    this.cff_op_max = 59;
+
+    // t1
+    this.T1_PRIVATE = 1;
+    this.T1_FONTDIR_AFTER_PRIVATE = 2;
+
+    // ttinterp
+    this.TT_MAX_CODE_RANGES = 3;
+
+    this.tt_coderange_none  = 0;
+    this.tt_coderange_font  = 1;
+    this.tt_coderange_cvt   = 2;
+    this.tt_coderange_glyph = 3;
+
+    this.SPH_OPTION_BITMAP_WIDTHS = false;
+    this.SPH_OPTION_SET_SUBPIXEL = true;
+    this.SPH_OPTION_SET_GRAYSCALE = false;
+    this.SPH_OPTION_SET_COMPATIBLE_WIDTHS = false;
+    this.SPH_OPTION_SET_RASTERIZER_VERSION = 38;
+
+    this.SPH_TWEAK_ALLOW_X_DMOVE                  = 0x0000001;
+    this.SPH_TWEAK_ALLOW_X_DMOVEX                 = 0x0000002;
+    this.SPH_TWEAK_ALLOW_X_MOVE_ZP2               = 0x0000004;
+    this.SPH_TWEAK_ALWAYS_DO_DELTAP               = 0x0000008;
+    this.SPH_TWEAK_ALWAYS_SKIP_DELTAP             = 0x0000010;
+    this.SPH_TWEAK_COURIER_NEW_2_HACK             = 0x0000020;
+    this.SPH_TWEAK_DEEMBOLDEN                     = 0x0000040;
+    this.SPH_TWEAK_DELTAP_SKIP_EXAGGERATED_VALUES = 0x0000080;
+    this.SPH_TWEAK_DO_SHPIX                       = 0x0000100;
+    this.SPH_TWEAK_EMBOLDEN                       = 0x0000200;
+    this.SPH_TWEAK_MIAP_HACK                      = 0x0000400;
+    this.SPH_TWEAK_NORMAL_ROUND                   = 0x0000800;
+    this.SPH_TWEAK_NO_ALIGNRP_AFTER_IUP           = 0x0001000;
+    this.SPH_TWEAK_NO_CALL_AFTER_IUP              = 0x0002000;
+    this.SPH_TWEAK_NO_DELTAP_AFTER_IUP            = 0x0004000;
+    this.SPH_TWEAK_PIXEL_HINTING                  = 0x0008000;
+    this.SPH_TWEAK_RASTERIZER_35                  = 0x0010000;
+    this.SPH_TWEAK_ROUND_NONPIXEL_Y_MOVES         = 0x0020000;
+    this.SPH_TWEAK_SKIP_INLINE_DELTAS             = 0x0040000;
+    this.SPH_TWEAK_SKIP_IUP                       = 0x0080000;
+    this.SPH_TWEAK_SKIP_NONPIXEL_Y_MOVES          = 0x0100000;
+    this.SPH_TWEAK_SKIP_OFFPIXEL_Y_MOVES          = 0x0200000;
+    this.SPH_TWEAK_TIMES_NEW_ROMAN_HACK           = 0x0400000;
+    this.SPH_TWEAK_MIRP_CVT_ZERO                  = 0x0800000;
+
+    this.FT_CURVE_TAG_HAS_SCANMODE                  = 4;
+    this.FT_CURVE_TAG_TOUCH_X                       = 8;  /* reserved for the TrueType hinter */
+    this.FT_CURVE_TAG_TOUCH_Y                       = 16;  /* reserved for the TrueType hinter */
+    this.FT_CURVE_TAG_TOUCH_BOTH                    = (this.FT_CURVE_TAG_TOUCH_X | this.FT_CURVE_TAG_TOUCH_Y);
+
+    this.FT_ORIENTATION_TRUETYPE   = 0;
+    this.FT_ORIENTATION_POSTSCRIPT = 1;
+    this.FT_ORIENTATION_FILL_RIGHT = this.FT_ORIENTATION_TRUETYPE;
+    this.FT_ORIENTATION_FILL_LEFT  = this.FT_ORIENTATION_POSTSCRIPT;
+    this.FT_ORIENTATION_NONE = 2;
+
+    this.FT_ANGLE_PI  = (180 << 16);
+    this.FT_ANGLE_PI2 = (this.FT_ANGLE_PI / 2);
+    this.FT_TRIG_MAX_ITERS = 23;
+
+    this.FT_TRIG_SCALE = 0x9B74EDA8;
+    if (this.FT_TRIG_SCALE < 0)
+        this.FT_TRIG_SCALE = this.IntToUInt(this.FT_TRIG_SCALE);
+
+    this.tt_coderange_none  = 0;
+    this.tt_coderange_font  = 1;
+    this.tt_coderange_cvt   = 2;
+    this.tt_coderange_glyph = 3;
+
+    this.MAX_RUNNABLE_OPCODES = 1000000;
+	
+	this.ARGS_ARE_WORDS         = 0x0001;
+	this.ARGS_ARE_XY_VALUES     = 0x0002;
+	this.ROUND_XY_TO_GRID       = 0x0004;
+	this.WE_HAVE_A_SCALE        = 0x0008;
+	this.MORE_COMPONENTS        = 0x0020;
+	this.WE_HAVE_AN_XY_SCALE    = 0x0040;
+	this.WE_HAVE_A_2X2          = 0x0080;
+	this.WE_HAVE_INSTR          = 0x0100;
+	this.USE_MY_METRICS         = 0x0200;
+	this.OVERLAP_COMPOUND       = 0x0400;
+	this.SCALED_COMPONENT_OFFSET   = 0x0800;
+	this.UNSCALED_COMPONENT_OFFSET = 0x1000;
+
+// GENERATOR_END_CONSTANTS
+
+	this.UintToInt = function(v){
+        return (v>FT_Common.m_i)?v-FT_Common.a_i:v;
+    }
+    this.UShort_To_Short = function(v){
+        return (v>FT_Common.m_s)?v-FT_Common.a_s:v;
+    }
+    this.IntToUInt = function(v){
+        return (v<0)?v+FT_Common.a_i:v;
+    }
+    this.Short_To_UShort = function(v){
+        return (v<0)?v+FT_Common.a_s:v;
+    }
+    this.memset = function(d,v,s)
+    {
+        for (var i=0;i<s;i++)
+            d[i]=v;
+    }
+    this.memcpy = function(d,s,l)
+    {
+        for (var i=0;i<l;i++)
+            d[i]=s[i];
+    }
+    this.memset_p = function(d,v,s)
+    {
+        var _d = d.data;
+        var _e = d.pos+s;
+        for (var i=d.pos;i<_e;i++)
+            _d[i]=v;
+    }
+    this.memcpy_p = function(d,s,l)
+    {
+        var _d1=d.data;
+        var _p1=d.pos;
+        var _d2=s.data;
+        var _p2=s.pos;
+        for (var i=0;i<l;i++)
+            _d1[_p1++]=_d2[_p2++];
+    }
+    this.memcpy_p2 = function(d,s,p,l)
+    {
+        var _d1=d.data;
+        var _p1=d.pos;
+        var _p2=p;
+        for (var i=0;i<l;i++)
+            _d1[_p1++]=s[_p2++];
+    }
+    this.realloc = function(memory, pointer, cur_count, new_count)
+    {
+        var ret = { block: null, err : 0, size : new_count};
+        if (cur_count < 0 || new_count < 0)
+        {
+            /* may help catch/prevent nasty security issues */
+            ret.err = FT_Common.FT_Err_Invalid_Argument;
+        }
+        else if (new_count == 0)
+        {
+            ret.block = null;
+        }
+        else if (cur_count == 0)
+        {
+            ret.block = memory.Alloc(new_count);
+        }
+        else
+        {
+            var block2 = memory.Alloc(new_count);
+            FT_Common.memcpy_p(block2, pointer, cur_count);
+            ret.block = block2;
+        }
+        return ret;
+    }
+
+    this.realloc_long = function(memory, pointer, cur_count, new_count)
+    {
+        var ret = { block: null, err : 0, size : new_count};
+        if (cur_count < 0 || new_count < 0)
+        {
+            /* may help catch/prevent nasty security issues */
+            ret.err = FT_Common.FT_Err_Invalid_Argument;
+        }
+        else if (new_count == 0)
+        {
+            ret.block = null;
+        }
+        else if (cur_count == 0)
+        {
+            ret.block = CreateIntArray(new_count);
+        }
+        else
+        {
+            var block2 = CreateIntArray(new_count);
+            for (var i = 0; i < cur_count; i++)
+                block2[i] = pointer[i];
+
+            ret.block = block2;
+        }
+        return ret;
+    }
+}
+var FT_Common = new _FT_Common();
\ No newline at end of file
diff --git a/Common/FontsFreeType/Private/FreeType/drivers/cff.js b/Common/FontsFreeType/Private/FreeType/drivers/cff.js
new file mode 100644
index 0000000000000000000000000000000000000000..9ab92612aa16935eb1790bdb770d9338ebae93a5
--- /dev/null
+++ b/Common/FontsFreeType/Private/FreeType/drivers/cff.js
@@ -0,0 +1,5967 @@
+/******************************************************************************/
+// cfftypes
+/******************************************************************************/
+function CFF_IndexRec()
+{
+    this.stream = null;
+    this.start = 0;
+    this.count = 0;
+    this.off_size = 0;
+    this.data_offset = 0;
+    this.data_size = 0;
+
+    this.offsets = null;
+    this.bytes = null;
+
+    this.clear = function()
+    {
+        this.stream = null;
+        this.start = 0;
+        this.count = 0;
+        this.off_size = 0;
+        this.data_offset = 0;
+        this.data_size = 0;
+
+        this.offsets = null;
+        this.bytes = null;
+    }
+}
+
+function CFF_EncodingRec()
+{
+    this.format = 0;
+    this.offset = 0;
+
+    this.count = 0;
+    this.sids = CreateIntArray(256);
+    this.codes = CreateIntArray(256);
+}
+
+function CFF_CharsetRec()
+{
+    this.format = 0;
+    this.offset = 0;
+
+    this.sids = null;
+    this.cids = null;
+
+    this.max_cid = 0;
+    this.num_glyphs = 0;
+}
+
+function CFF_FontRecDictRec()
+{
+    this.version = 0;
+    this.notice = 0;
+    this.copyright = 0;
+    this.full_name = 0;
+    this.family_name = 0;
+    this.weight = 0;
+    this.is_fixed_pitch = 0;
+    this.italic_angle = 0;
+    this.underline_position = 0;
+    this.underline_thickness = 0;
+    this.paint_type = 0;
+    this.charstring_type = 0;
+    this.font_matrix = new FT_Matrix();
+    this.has_font_matrix = 0;
+    this.units_per_em = 0;
+    this.font_offset = new FT_Vector();
+    this.unique_id = 0;
+    this.font_bbox = new FT_BBox();
+    this.stroke_width = 0;
+    this.charset_offset = 0;
+    this.encoding_offset = 0;
+    this.charstrings_offset = 0;
+    this.private_offset = 0;
+    this.private_size = 0;
+    this.synthetic_base = 0;
+    this.embedded_postscript = 0;
+
+    this.cid_registry = 0;
+    this.cid_ordering = 0;
+    this.cid_supplement = 0;
+
+    this.cid_font_version = 0;
+    this.cid_font_revision = 0;
+    this.cid_font_type = 0;
+    this.cid_count = 0;
+    this.cid_uid_base = 0;
+    this.cid_fd_array_offset = 0;
+    this.cid_fd_select_offset = 0;
+    this.cid_font_name = 0;
+
+    this.clear = function()
+    {
+        this.version = 0;
+        this.notice = 0;
+        this.copyright = 0;
+        this.full_name = 0;
+        this.family_name = 0;
+        this.weight = 0;
+        this.is_fixed_pitch = 0;
+        this.italic_angle = 0;
+        this.underline_position = 0;
+        this.underline_thickness = 0;
+        this.paint_type = 0;
+        this.charstring_type = 0;
+
+        this.font_matrix.xx = 0;
+        this.font_matrix.xy = 0;
+        this.font_matrix.yx = 0;
+        this.font_matrix.yy = 0;
+
+        this.has_font_matrix = 0;
+        this.units_per_em = 0;
+
+        this.font_offset.x = 0;
+        this.font_offset.y = 0;
+
+        this.unique_id = 0;
+
+        this.font_bbox.xMin = 0;
+        this.font_bbox.yMin = 0;
+        this.font_bbox.xMax = 0;
+        this.font_bbox.yMax = 0;
+
+        this.stroke_width = 0;
+        this.charset_offset = 0;
+        this.encoding_offset = 0;
+        this.charstrings_offset = 0;
+        this.private_offset = 0;
+        this.private_size = 0;
+        this.synthetic_base = 0;
+        this.embedded_postscript = 0;
+
+        this.cid_registry = 0;
+        this.cid_ordering = 0;
+        this.cid_supplement = 0;
+
+        this.cid_font_version = 0;
+        this.cid_font_revision = 0;
+        this.cid_font_type = 0;
+        this.cid_count = 0;
+        this.cid_uid_base = 0;
+        this.cid_fd_array_offset = 0;
+        this.cid_fd_select_offset = 0;
+        this.cid_font_name = 0;
+    }
+}
+
+function CFF_PrivateRec()
+{
+    this.num_blue_values = 0;
+    this.num_other_blues = 0;
+    this.num_family_blues = 0;
+    this.num_family_other_blues = 0;
+
+    this.blue_values = CreateIntArray(14);
+    this.other_blues = CreateIntArray(10);
+    this.family_blues = CreateIntArray(14);
+    this.family_other_blues = CreateIntArray(10);
+
+    this.blue_scale = 0;
+    this.blue_shift = 0;
+    this.blue_fuzz = 0;
+    this.standard_width = 0;
+    this.standard_height = 0;
+
+    this.num_snap_widths = 0;
+    this.num_snap_heights = 0;
+    this.snap_widths = CreateIntArray(13);
+    this.snap_heights = CreateIntArray(13);
+    this.force_bold = 0;
+    this.force_bold_threshold = 0;
+    this.lenIV = 0;
+    this.language_group = 0;
+    this.expansion_factor = 0;
+    this.initial_random_seed = 0;
+    this.local_subrs_offset = 0;
+    this.default_width = 0;
+    this.nominal_width = 0;
+
+    this.clear = function()
+    {
+        this.num_blue_values = 0;
+        this.num_other_blues = 0;
+        this.num_family_blues = 0;
+        this.num_family_other_blues = 0;
+
+        for (var i = 0; i < 14; i++)
+            this.blue_values[i] = 0;
+        for (var i = 0; i < 10; i++)
+            this.other_blues[i] = 0;
+        for (var i = 0; i < 14; i++)
+            this.family_blues[i] = 0;
+        for (var i = 0; i < 10; i++)
+            this.family_other_blues[i] = 0;
+
+        this.blue_scale = 0;
+        this.blue_shift = 0;
+        this.blue_fuzz = 0;
+        this.standard_width = 0;
+        this.standard_height = 0;
+
+        this.num_snap_widths = 0;
+        this.num_snap_heights = 0;
+
+        for (var i = 0; i < 13; i++)
+            this.snap_widths[i] = 0;
+        for (var i = 0; i < 13; i++)
+            this.snap_heights[i] = 0;
+
+        this.force_bold = 0;
+        this.force_bold_threshold = 0;
+        this.lenIV = 0;
+        this.language_group = 0;
+        this.expansion_factor = 0;
+        this.initial_random_seed = 0;
+        this.local_subrs_offset = 0;
+        this.default_width = 0;
+        this.nominal_width = 0;
+    }
+}
+
+function CFF_FDSelectRec()
+{
+    this.format = 0;
+    this.range_count = 0;
+
+    /* that's the table, taken from the file `as is' */
+    this.data = null;
+    this.data_size = 0;
+
+    /* small cache for format 3 only */
+    this.cache_first = 0;
+    this.cache_count = 0;
+    this.cache_fd = 0;
+}
+
+/* A SubFont packs a font dict and a private dict together.  They are */
+/* needed to support CID-keyed CFF fonts.                             */
+function CFF_SubFontRec()
+{
+    this.font_dict = new CFF_FontRecDictRec();
+    this.private_dict = new CFF_PrivateRec();
+
+    this.local_subrs_index = new CFF_IndexRec();
+    this.local_subrs = []; /* array of pointers into Local Subrs INDEX data */
+}
+
+function CFF_FontRec()
+{
+    this.stream = null;
+    this.memory = null;
+    this.num_faces = 0;
+    this.num_glyphs = 0;
+
+    this.version_major = 0;
+    this.version_minor = 0;
+    this.header_size = 0;
+    this.absolute_offsize = 0;
+
+
+    this.name_index = new CFF_IndexRec();
+    this.top_dict_index = new CFF_IndexRec();
+    this.global_subrs_index = new CFF_IndexRec();
+
+    this.encoding = new CFF_EncodingRec();
+    this.charset = new CFF_CharsetRec();
+
+    this.charstrings_index = new CFF_IndexRec();
+    this.font_dict_index = new CFF_IndexRec();
+    this.private_index = new CFF_IndexRec();
+    this.local_subrs_index = new CFF_IndexRec();
+
+    this.font_name = "";
+
+    /* array of pointers into Global Subrs INDEX data */
+    this.global_subrs = [];
+
+    /* array of pointers into String INDEX data stored at string_pool */
+    this.num_strings = 0;
+    this.strings = null;
+    this.string_pool = null;
+
+    this.top_font = new CFF_SubFontRec();
+    this.num_subfonts = 0;
+    this.subfonts = new Array(FT_Common.CFF_MAX_CID_FONTS);
+    for (var i = 0; i < FT_Common.CFF_MAX_CID_FONTS; i++)
+        this.subfonts[i] = null;
+
+    this.fd_select = new CFF_FDSelectRec();
+
+    /* interface to PostScript hinter */
+    this.pshinter = null;
+
+    /* interface to Postscript Names service */
+    this.psnames = null;
+
+    /* since version 2.3.0 */
+    this.font_info = null;   /* font info dictionary */
+
+    /* since version 2.3.6 */
+    this.registry = "";
+    this.ordering = "";
+}
+
+function CFF_ParserRec()
+{
+    this.library = null;
+    this.start = null;
+    this.limit = 0;
+    this.cursor = null;
+
+    this.stack = new Array(FT_Common.CFF_MAX_STACK_DEPTH + 1);
+    this.top = 0;
+
+    this.object_code = 0;
+    this.object = 0;
+
+    this.clear = function()
+    {
+        this.library = null;
+        this.start = null;
+        this.limit = 0;
+        this.cursor = null;
+
+        for (var i = 0; i < (FT_Common.CFF_MAX_STACK_DEPTH + 1); i++)
+            this.stack[i] = 0;
+        this.top = 0;
+
+        this.object_code = 0;
+        this.object = 0;
+    }
+}
+
+function CFF_Field_Handler()
+{
+    this.kind = 0;
+    this.code = 0;
+    this.offset = 0;
+    this.size = 0;
+    this.reader = null;
+    this.array_max = 0;
+    this.count_offset = 0;
+
+    this.set_field = null;
+    this.set_field_count = null;
+}
+
+function create_cff_field(_kind, _code, _reader, _array_max, _set_field, _set_field_count)
+{
+    var ret = new CFF_Field_Handler();
+    ret.kind = _kind;
+    ret.code = _code;
+    ret.offset = 0;
+    ret.size = 0;
+    ret.reader = _reader;
+    ret.array_max = _array_max;
+    ret.count_offset = 0;
+
+    ret.set_field = _set_field;
+    ret.set_field_count = _set_field_count;
+
+    return ret;
+}
+/******************************************************************************/
+// cffparse
+/******************************************************************************/
+function cff_parser_init(parser, code, object, library)
+{
+    parser.clear();
+    
+    parser.top = 0;
+    parser.object_code = code;
+    parser.object = object;
+    parser.library = library;
+}
+
+function cff_parse_integer(start, limit)
+{
+    var p = dublicate_pointer(start);
+    var v   = p.data[p.pos];
+    p.pos++;
+    var val = 0;
+
+    if (v == 28)
+    {
+        if (p.pos + 2 > limit)
+            return 0;
+
+        val = FT_Common.UShort_To_Short((p.data[p.pos] << 8) | p.data[p.pos + 1]);
+        p.pos += 2;
+    }
+    else if ( v == 29 )
+    {
+        if (p.pos + 4 > limit)
+            return 0;
+
+        val = (p.data[p.pos] << 24) | (p.data[p.pos + 1] << 16) | (p.data[p.pos + 2] << 8) | p.data[p.pos + 3];
+        p.pos += 4;
+    }
+    else if (v < 247)
+    {
+        val = v - 139;
+    }
+    else if (v < 251)
+    {
+        if (p.pos + 1 > limit)
+            return 0;
+
+        val = (v - 247) * 256 + p.data[p.pos] + 108;
+        p.pos++;
+    }
+    else
+    {
+        if (p + 1 > limit)
+            return 0;
+
+        val = -(v - 251) * 256 - p.data[p.pos] - 108;
+        p.pos++;
+    }
+    return val;
+}
+
+var power_tens = [1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000];
+
+function cff_parse_real(start, limit, power_ten, is_scaling)
+{
+    var scaling = 0;
+    var result = 0;
+
+    var p = dublicate_pointer(start);
+    var nib = 0;
+    var phase = 0;
+
+    var sign = 0, exponent_sign = 0;
+
+    var number   = 0;
+    var exponent = 0;
+
+    var exponent_add    = 0;
+    var integer_length  = 0;
+    var fraction_length = 0;
+
+    /* First of all, read the integer part. */
+    phase = 4;
+
+    for (;;)
+    {
+        /* If we entered this iteration with phase == 4, we need to */
+        /* read a new byte.  This also skips past the initial 0x1E. */
+        if (phase)
+        {
+            p.pos++;
+
+            /* Make sure we don't read past the end. */
+            if (p.pos >= limit)
+                return { res : result, scaling: scaling };
+        }
+
+        /* Get the nibble. */
+        nib = (p.data[p.pos] >> phase) & 0xF;
+        phase = 4 - phase;
+
+        if (nib == 0xE)
+            sign = 1;
+        else if (nib > 9)
+            break;
+        else
+        {
+            /* Increase exponent if we can't add the digit. */
+            if (number >= 0xCCCCCCC)
+                exponent_add++;
+            /* Skip leading zeros. */
+            else if ( nib || number )
+            {
+                integer_length++;
+                number = number * 10 + nib;
+            }
+        }
+    }
+
+    /* Read fraction part, if any. */
+    if (nib == 0xa)
+    {
+        for (;;)
+        {
+            /* If we entered this iteration with phase == 4, we need */
+            /* to read a new byte.                                   */
+            if (phase)
+            {
+                p.pos++;
+
+                /* Make sure we don't read past the end. */
+                if (p.pos >= limit)
+                    return { res : result, scaling: scaling };
+            }
+
+            /* Get the nibble. */
+            nib   = (p.data[p.pos] >> phase) & 0xF;
+            phase = 4 - phase;
+            if (nib >= 10)
+                break;
+
+            /* Skip leading zeros if possible. */
+            if (!nib && !number)
+                exponent_add--;
+            /* Only add digit if we don't overflow. */
+            else if (number < 0xCCCCCCC && fraction_length < 9)
+            {
+                fraction_length++;
+                number = number * 10 + nib;
+            }
+        }
+    }
+
+    /* Read exponent, if any. */
+    if (nib == 12)
+    {
+        exponent_sign = 1;
+        nib           = 11;
+    }
+
+    if (nib == 11)
+    {
+        for (;;)
+        {
+            /* If we entered this iteration with phase == 4, */
+            /* we need to read a new byte.                   */
+            if (phase)
+            {
+                p.pos++;
+
+                /* Make sure we don't read past the end. */
+                if (p.pos >= limit)
+                    return { res : result, scaling: scaling };
+            }
+
+            /* Get the nibble. */
+            nib   = (p.data[p.pos] >> phase) & 0xF;
+            phase = 4 - phase;
+            if (nib >= 10)
+                break;
+
+            exponent = exponent * 10 + nib;
+
+            /* Arbitrarily limit exponent. */
+            if (exponent > 1000)
+                return { res : result, scaling: scaling };
+        }
+
+        if (exponent_sign)
+            exponent = -exponent;
+    }
+
+    /* We don't check `power_ten' and `exponent_add'. */
+    exponent += power_ten + exponent_add;
+
+    if (is_scaling != 0)
+    {
+        /* Only use `fraction_length'. */
+        fraction_length += integer_length;
+        exponent        += integer_length;
+
+        if (fraction_length <= 5)
+        {
+            if (number > 0x7FFF)
+            {
+                result  = FT_DivFix(number, 10);
+                scaling = exponent - fraction_length + 1;
+            }
+            else
+            {
+                if (exponent > 0)
+                {
+                    /* Make `scaling' as small as possible. */
+                    var new_fraction_length = Math.min(exponent, 5);
+                    exponent -= new_fraction_length;
+                    var shift = new_fraction_length - fraction_length;
+
+                    number *= power_tens[shift];
+                    if (number > 0x7FFF)
+                    {
+                        number /= 10;
+                        exponent += 1;
+                    }
+                }
+                else
+                    exponent -= fraction_length;
+
+                result = number << 16;
+                scaling = exponent;
+            }
+        }
+        else
+        {
+            if ((number / power_tens[fraction_length - 5]) > 0x7FFF)
+            {
+                result = FT_DivFix(number, power_tens[fraction_length - 4]);
+                scaling = exponent - 4;
+            }
+            else
+            {
+                result = FT_DivFix(number, power_tens[fraction_length - 5]);
+                scaling = exponent - 5;
+            }
+        }
+    }
+    else
+    {
+        integer_length  += exponent;
+        fraction_length -= exponent;
+
+        /* Check for overflow and underflow. */
+        if (Math.abs(integer_length) > 5)
+            return { res : result, scaling: scaling };
+
+        /* Remove non-significant digits. */
+        if (integer_length < 0)
+        {
+            number /= power_tens[-integer_length];
+            fraction_length += integer_length;
+        }
+
+        /* this can only happen if exponent was non-zero */
+        if (fraction_length == 10)
+        {
+            number /= 10;
+            fraction_length -= 1;
+        }
+
+        /* Convert into 16.16 format. */
+        if (fraction_length > 0)
+        {
+            if ((number / power_tens[fraction_length]) > 0x7FFF)
+                return { res : result, scaling: scaling };
+
+            result = FT_DivFix(number, power_tens[fraction_length]);
+        }
+        else
+        {
+            number *= power_tens[-fraction_length];
+
+            if (number > 0x7FFF)
+                return { res : result, scaling: scaling };
+
+            result = number << 16;
+        }
+    }
+
+    if (sign)
+        result = -result;
+
+    return { res : result, scaling: scaling };
+}
+
+function cff_parse_num(d, start)
+{
+    var _d0 = d[start];
+    var _d1 = d[start + 1];
+    if (_d0.data[_d0.pos] == 30)
+        return cff_parse_real(_d0, _d1.pos, 0, false).res >> 16;
+    return cff_parse_integer(_d0, _d1.pos);
+}
+
+function cff_parse_fixed(d, start)
+{
+    var _d0 = d[start];
+    var _d1 = d[start + 1];
+    if (_d0.data[_d0.pos] == 30)
+        return cff_parse_real(_d0, _d1.pos, 0, false).res;
+    return cff_parse_integer(_d0, _d1.pos) << 16;
+}
+
+function cff_parse_fixed_scaled(d, start, scaling)
+{
+    var _d0 = d[start];
+    var _d1 = d[start + 1];
+    if (_d0.data[_d0.pos] == 30)
+        return cff_parse_real(_d0, _d1.pos, scaling, false).res;
+
+    return (cff_parse_integer(_d0, _d1.pos) * power_tens[scaling]) << 16;
+}
+
+function cff_parse_fixed_dynamic(d, start)
+{
+    var _d0 = d[start];
+    var _d1 = d[start + 1];
+    if (_d0.data[_d0.pos] == 30)
+        return cff_parse_real(_d0, _d1.pos, 0, true);
+
+    var integer_length = 0;
+    var number = cff_parse_integer(_d0, _d1.pos);
+
+    var scaling = 0;
+    if (number > 0x7FFF)
+    {
+        for (integer_length = 5; integer_length < 10; integer_length++)
+            if (number < power_tens[integer_length])
+                break;
+
+        if ((number / power_tens[integer_length - 5]) > 0x7FFF)
+        {
+            scaling = integer_length - 4;
+            var result = FT_DivFix(number, power_tens[integer_length - 4]);
+            return { res : result, scaling: scaling };
+        }
+        else
+        {
+            scaling = integer_length - 5;
+            var result = FT_DivFix(number, power_tens[integer_length - 5]);
+            return { res : result, scaling: scaling };
+        }
+    }
+    else
+    {
+        return { res : number << 16, scaling: 0 };
+    }
+}
+
+function cff_parse_font_matrix(parser)
+{
+    var dict = parser.object;
+    var matrix = dict.font_matrix;
+    var offset = dict.font_offset;
+    //FT_ULong*        upm    = &dict.units_per_em;
+    var data = parser.stack;
+    var start = 0;
+    var error = FT_Common.FT_Err_Stack_Underflow;
+
+    if (parser.top >= 6)
+    {
+        var scaling = 0;
+        error = FT_Common.FT_Err_Ok;
+
+        dict.has_font_matrix = 1;
+        /* We expect a well-formed font matrix, this is, the matrix elements */
+        /* `xx' and `yy' are of approximately the same magnitude.  To avoid  */
+        /* loss of precision, we use the magnitude of element `xx' to scale  */
+        /* all other elements.  The scaling factor is then contained in the  */
+        /* `units_per_em' value.                                             */
+
+        var ret = cff_parse_fixed_dynamic(data, start++);
+        scaling = ret.scaling;
+        matrix.xx = ret.res;
+
+        scaling = -scaling;
+        if (scaling < 0 || scaling > 9)
+        {
+            /* Return default matrix in case of unlikely values. */
+            matrix.xx = 0x10000;
+            matrix.yx = 0;
+            matrix.xy = 0;
+            matrix.yy = 0x10000;
+            offset.x  = 0;
+            offset.y  = 0;
+            dict.units_per_em = 1;
+
+            return error;
+        }
+
+        matrix.yx = cff_parse_fixed_scaled(data, start++, scaling);
+        matrix.xy = cff_parse_fixed_scaled(data, start++, scaling);
+        matrix.yy = cff_parse_fixed_scaled(data, start++, scaling);
+        offset.x  = cff_parse_fixed_scaled(data, start++, scaling);
+        offset.y  = cff_parse_fixed_scaled(data, start, scaling);
+
+        dict.units_per_em = power_tens[scaling];
+    }
+
+    return error;
+}
+
+function cff_parse_font_bbox(parser)
+{
+    var dict = parser.object;
+    var bbox = dict.font_bbox;
+    var data = parser.stack;
+
+    if (parser.top >= 4)
+    {
+        var start = 0;
+
+        bbox.xMin = FT_RoundFix(cff_parse_fixed(data, start++));
+        bbox.yMin = FT_RoundFix(cff_parse_fixed(data, start++));
+        bbox.xMax = FT_RoundFix(cff_parse_fixed(data, start++));
+        bbox.yMax = FT_RoundFix(cff_parse_fixed(data, start));
+
+        return 0;
+    }
+    return FT_Common.FT_Err_Stack_Underflow;
+}
+
+function cff_parse_private_dict(parser)
+{
+    var dict = parser.object;
+    var data = parser.stack;
+
+    if (parser.top >= 2)
+    {
+        dict.private_size   = cff_parse_num(data, 0);
+        dict.private_offset = cff_parse_num(data, 1);
+
+        return 0;
+    }
+    return FT_Common.FT_Err_Stack_Underflow;
+}
+
+function cff_parse_cid_ros(parser)
+{
+    var dict = parser.object;
+    var data = parser.stack;
+
+    if (parser.top >= 3)
+    {
+        dict.cid_registry = FT_Common.IntToUInt(cff_parse_num(data, 0));
+        dict.cid_ordering = FT_Common.IntToUInt(cff_parse_num(data, 1));
+
+        dict.cid_supplement = cff_parse_num(data, 2);
+        return 0;
+    }
+    return FT_Common.FT_Err_Stack_Underflow;
+}
+
+function cff_parser_run(parser, start, limit)
+{
+    var p = dublicate_pointer(start);
+    var error = 0;
+
+    parser.top    = 0;
+    parser.start  = start;
+    parser.limit  = limit;
+    parser.cursor = dublicate_pointer(start);
+
+    var tops = parser.stack;
+    while (p.pos < limit)
+    {
+        var v = p.data[p.pos];
+
+        if (v >= 27 && v != 31)
+        {
+            /* it's a number; we will push its position on the stack */
+            if (parser.top >= FT_Common.CFF_MAX_STACK_DEPTH)
+                return FT_Common.FT_Err_Invalid_Argument;
+
+            tops[parser.top++] = dublicate_pointer(p);
+
+            /* now, skip it */
+            if (v == 30)
+            {
+                /* skip real number */
+                p.pos++;
+                for (;;)
+                {
+                    /* An unterminated floating point number at the */
+                    /* end of a dictionary is invalid but harmless. */
+                    if (p.pos >= limit)
+                        return error;
+                    v = p.data[p.pos] >> 4;
+                    if (v == 15)
+                        break;
+                    v = p.data[p.pos] & 0xF;
+                    if (v == 15)
+                        break;
+                    p.pos++;
+                }
+            }
+            else if (v == 28)
+                p.pos += 2;
+            else if (v == 29)
+                p.pos += 4;
+            else if (v > 246)
+                p.pos += 1;
+        }
+        else
+        {
+            /* This is not a number, hence it's an operator.  Compute its code */
+            /* and look for it in our current list.                            */
+
+            var num_args = parser.top;
+            var code = v;
+
+            tops[parser.top++] = dublicate_pointer(p);
+            if (v == 12)
+            {
+                /* two byte operator */
+                p.pos++;
+                if (p.pos >= limit)
+                    return FT_Common.FT_Err_Invalid_Argument;
+
+                code = 0x100 | p.data[p.pos];
+            }
+            code = code | parser.object_code;
+
+            var fields = cff_field_handlers;
+            for (var field_ = 0; field_ < fields.length; field_++)
+            {
+                var field = fields[field_];
+                if (field.code == FT_Common.UintToInt(code))
+                {
+                    /* we found our field's handler; read it */
+                    var val;
+
+                    /* check that we have enough arguments -- except for */
+                    /* delta encoded arrays, which can be empty          */
+                    if (field.kind != FT_Common.cff_kind_delta && num_args < 1)
+                        return FT_Common.FT_Err_Invalid_Argument;
+
+                    switch (field.kind)
+                    {
+                        case FT_Common.cff_kind_bool:
+                        case FT_Common.cff_kind_string:
+                        case FT_Common.cff_kind_num:
+                            val = cff_parse_num(parser.stack, 0);
+                            fire_t1_field(parser.object, val, field);
+                            break;
+
+                        case FT_Common.cff_kind_fixed:
+                            val = cff_parse_fixed(parser.stack, 0);
+                            fire_t1_field(parser.object, val, field);
+                            break;
+
+                        case FT_Common.cff_kind_fixed_thousand:
+                            val = cff_parse_fixed_scaled(parser.stack, 0, 3);
+                            fire_t1_field(parser.object, val, field);
+                            break;
+
+                        case FT_Common.cff_kind_delta:
+                            var data = parser.stack;
+                            var _data_pos = 0;
+
+                            if (num_args > field.array_max)
+                                num_args = field.array_max;
+
+                            fire_t1_field_count(parser.object, num_args, field);
+                            val = 0;
+                            field.offset = 0;
+                            while (num_args > 0)
+                            {
+                                val += cff_parse_num(data, _data_pos++);
+                                fire_t1_field(parser.object, val, field);
+                                field.offset++;
+                                num_args--;
+                            }
+
+                            break;
+
+                        default:  /* callback */
+                            error = field.reader(parser);
+                            if ( error )
+                                return error;
+                    }
+
+                    break;
+                }
+            }
+
+            /* this is an unknown operator, or it is unsupported; */
+            /* we will ignore it for now.                         */
+            /* clear stack */
+            parser.top = 0;
+        }
+        p.pos++;
+    }
+
+    return error;
+}
+
+/******************************************************************************/
+// cfftoken
+/******************************************************************************/
+var cff_field_handlers = new Array(51);
+
+// CFF_FontRecDictRec
+cff_field_handlers[0] = create_cff_field(FT_Common.cff_kind_string, 0 | FT_Common.CFFCODE_TOPDICT, null, 0, function(obj, val, f) { obj.version = val }, undefined);
+cff_field_handlers[1] = create_cff_field(FT_Common.cff_kind_string, 1 | FT_Common.CFFCODE_TOPDICT, null, 0, function(obj, val, f) { obj.notice = val }, undefined);
+cff_field_handlers[2] = create_cff_field(FT_Common.cff_kind_string, 0x100 | FT_Common.CFFCODE_TOPDICT, null, 0, function(obj, val, f) { obj.copyright = val }, undefined);
+cff_field_handlers[3] = create_cff_field(FT_Common.cff_kind_string, 2 | FT_Common.CFFCODE_TOPDICT, null, 0, function(obj, val, f) { obj.full_name = val }, undefined);
+cff_field_handlers[4] = create_cff_field(FT_Common.cff_kind_string, 3 | FT_Common.CFFCODE_TOPDICT, null, 0, function(obj, val, f) { obj.family_name = val }, undefined);
+cff_field_handlers[5] = create_cff_field(FT_Common.cff_kind_string, 4 | FT_Common.CFFCODE_TOPDICT, null, 0, function(obj, val, f) { obj.weight = val }, undefined);
+
+cff_field_handlers[6] = create_cff_field(FT_Common.cff_kind_bool, 0x101 | FT_Common.CFFCODE_TOPDICT, null, 0, function(obj, val, f) { obj.is_fixed_pitch = val }, undefined);
+
+cff_field_handlers[7] = create_cff_field(FT_Common.cff_kind_fixed, 0x102 | FT_Common.CFFCODE_TOPDICT, null, 0, function(obj, val, f) { obj.italic_angle = val }, undefined);
+cff_field_handlers[8] = create_cff_field(FT_Common.cff_kind_fixed, 0x103 | FT_Common.CFFCODE_TOPDICT, null, 0, function(obj, val, f) { obj.underline_position = val }, undefined);
+cff_field_handlers[9] = create_cff_field(FT_Common.cff_kind_fixed, 0x104 | FT_Common.CFFCODE_TOPDICT, null, 0, function(obj, val, f) { obj.underline_thickness = val }, undefined);
+
+cff_field_handlers[10] = create_cff_field(FT_Common.cff_kind_num, 0x105 | FT_Common.CFFCODE_TOPDICT, null, 0, function(obj, val, f) { obj.paint_type = val }, undefined);
+cff_field_handlers[11] = create_cff_field(FT_Common.cff_kind_num, 0x106 | FT_Common.CFFCODE_TOPDICT, null, 0, function(obj, val, f) { obj.charstring_type = val }, undefined);
+
+cff_field_handlers[12] = create_cff_field(FT_Common.cff_kind_callback, 0x107 | FT_Common.CFFCODE_TOPDICT, cff_parse_font_matrix, 0, undefined, undefined);
+
+cff_field_handlers[13] = create_cff_field(FT_Common.cff_kind_num, 13 | FT_Common.CFFCODE_TOPDICT, null, 0, function(obj, val, f) { obj.unique_id = val }, undefined);
+
+cff_field_handlers[14] = create_cff_field(FT_Common.cff_kind_callback, 5 | FT_Common.CFFCODE_TOPDICT, cff_parse_font_bbox, 0, undefined, undefined);
+
+cff_field_handlers[15] = create_cff_field(FT_Common.cff_kind_num, 0x108 | FT_Common.CFFCODE_TOPDICT, null, 0, function(obj, val, f) { obj.stroke_width = val }, undefined);
+cff_field_handlers[16] = create_cff_field(FT_Common.cff_kind_num, 15 | FT_Common.CFFCODE_TOPDICT, null, 0, function(obj, val, f) { obj.charset_offset = val }, undefined);
+cff_field_handlers[17] = create_cff_field(FT_Common.cff_kind_num, 16 | FT_Common.CFFCODE_TOPDICT, null, 0, function(obj, val, f) { obj.encoding_offset = val }, undefined);
+cff_field_handlers[18] = create_cff_field(FT_Common.cff_kind_num, 17 | FT_Common.CFFCODE_TOPDICT, null, 0, function(obj, val, f) { obj.charstrings_offset = val }, undefined);
+
+cff_field_handlers[19] = create_cff_field(FT_Common.cff_kind_callback, 18 | FT_Common.CFFCODE_TOPDICT, cff_parse_private_dict, 0, undefined, undefined);
+
+cff_field_handlers[20] = create_cff_field(FT_Common.cff_kind_num, 0x114 | FT_Common.CFFCODE_TOPDICT, null, 0, function(obj, val, f) { obj.synthetic_base = val }, undefined);
+
+cff_field_handlers[21] = create_cff_field(FT_Common.cff_kind_string, 0x115 | FT_Common.CFFCODE_TOPDICT, null, 0, function(obj, val, f) { obj.embedded_postscript = val }, undefined);
+
+cff_field_handlers[22] = create_cff_field(FT_Common.cff_kind_callback, 0x11E | FT_Common.CFFCODE_TOPDICT, cff_parse_cid_ros, 0, undefined, undefined);
+
+cff_field_handlers[23] = create_cff_field(FT_Common.cff_kind_num, 0x11F | FT_Common.CFFCODE_TOPDICT, null, 0, function(obj, val, f) { obj.cid_font_version = val }, undefined);
+cff_field_handlers[24] = create_cff_field(FT_Common.cff_kind_num, 0x120 | FT_Common.CFFCODE_TOPDICT, null, 0, function(obj, val, f) { obj.cid_font_revision = val }, undefined);
+cff_field_handlers[25] = create_cff_field(FT_Common.cff_kind_num, 0x121 | FT_Common.CFFCODE_TOPDICT, null, 0, function(obj, val, f) { obj.cid_font_type = val }, undefined);
+cff_field_handlers[26] = create_cff_field(FT_Common.cff_kind_num, 0x122 | FT_Common.CFFCODE_TOPDICT, null, 0, function(obj, val, f) { obj.cid_count = val }, undefined);
+cff_field_handlers[27] = create_cff_field(FT_Common.cff_kind_num, 0x123 | FT_Common.CFFCODE_TOPDICT, null, 0, function(obj, val, f) { obj.cid_uid_base = val }, undefined);
+cff_field_handlers[28] = create_cff_field(FT_Common.cff_kind_num, 0x124 | FT_Common.CFFCODE_TOPDICT, null, 0, function(obj, val, f) { obj.cid_fd_array_offset = val }, undefined);
+cff_field_handlers[29] = create_cff_field(FT_Common.cff_kind_num, 0x125 | FT_Common.CFFCODE_TOPDICT, null, 0, function(obj, val, f) { obj.cid_fd_select_offset = val }, undefined);
+
+cff_field_handlers[30] = create_cff_field(FT_Common.cff_kind_string, 0x126 | FT_Common.CFFCODE_TOPDICT, null, 0, function(obj, val, f) { obj.cid_font_name = val }, undefined);
+
+// CFF_PrivateRec
+cff_field_handlers[31] = create_cff_field(FT_Common.cff_kind_delta, 6 | FT_Common.CFFCODE_PRIVATE, null, 14, function(obj, val, f) { obj.blue_values[f.offset] = val }, function(obj, val, f) { obj.num_blue_values = val });
+cff_field_handlers[32] = create_cff_field(FT_Common.cff_kind_delta, 7 | FT_Common.CFFCODE_PRIVATE, null, 10, function(obj, val, f) { obj.other_blues[f.offset] = val }, function(obj, val, f) { obj.num_other_blues = val });
+cff_field_handlers[33] = create_cff_field(FT_Common.cff_kind_delta, 8 | FT_Common.CFFCODE_PRIVATE, null, 14, function(obj, val, f) { obj.family_blues[f.offset] = val }, function(obj, val, f) { obj.num_family_blues = val });
+cff_field_handlers[34] = create_cff_field(FT_Common.cff_kind_delta, 9 | FT_Common.CFFCODE_PRIVATE, null, 10, function(obj, val, f) { obj.family_other_blues[f.offset] = val }, function(obj, val, f) { obj.num_family_other_blues = val });
+
+cff_field_handlers[35] = create_cff_field(FT_Common.cff_kind_fixed_thousand, 0x109 | FT_Common.CFFCODE_PRIVATE, null, 0, function(obj, val, f) { obj.blue_scale = val }, undefined);
+
+cff_field_handlers[36] = create_cff_field(FT_Common.cff_kind_num, 0x10A | FT_Common.CFFCODE_PRIVATE, null, 0, function(obj, val, f) { obj.blue_shift = val }, undefined);
+cff_field_handlers[37] = create_cff_field(FT_Common.cff_kind_num, 0x10B | FT_Common.CFFCODE_PRIVATE, null, 0, function(obj, val, f) { obj.blue_fuzz = val }, undefined);
+cff_field_handlers[38] = create_cff_field(FT_Common.cff_kind_num, 10 | FT_Common.CFFCODE_PRIVATE, null, 0, function(obj, val, f) { obj.standard_width = val }, undefined);
+cff_field_handlers[39] = create_cff_field(FT_Common.cff_kind_num, 11 | FT_Common.CFFCODE_PRIVATE, null, 0, function(obj, val, f) { obj.standard_height = val }, undefined);
+
+cff_field_handlers[40] = create_cff_field(FT_Common.cff_kind_delta, 0x10C | FT_Common.CFFCODE_PRIVATE, null, 13, function(obj, val, f) { obj.snap_widths[f.offset] = val }, function(obj, val, f) { obj.num_snap_widths = val });
+cff_field_handlers[41] = create_cff_field(FT_Common.cff_kind_delta, 0x10D | FT_Common.CFFCODE_PRIVATE, null, 13, function(obj, val, f) { obj.snap_heights[f.offset] = val }, function(obj, val, f) { obj.num_snap_heights = val });
+
+cff_field_handlers[42] = create_cff_field(FT_Common.cff_kind_bool, 0x10E | FT_Common.CFFCODE_PRIVATE, null, 0, function(obj, val, f) { obj.force_bold = val }, undefined);
+cff_field_handlers[43] = create_cff_field(FT_Common.cff_kind_fixed, 0x10F | FT_Common.CFFCODE_PRIVATE, null, 0, function(obj, val, f) { obj.force_bold_threshold = val }, undefined);
+
+cff_field_handlers[44] = create_cff_field(FT_Common.cff_kind_num, 0x110 | FT_Common.CFFCODE_PRIVATE, null, 0, function(obj, val, f) { obj.lenIV = val }, undefined);
+cff_field_handlers[45] = create_cff_field(FT_Common.cff_kind_num, 0x111 | FT_Common.CFFCODE_PRIVATE, null, 0, function(obj, val, f) { obj.language_group = val }, undefined);
+
+cff_field_handlers[46] = create_cff_field(FT_Common.cff_kind_fixed, 0x112 | FT_Common.CFFCODE_PRIVATE, null, 0, function(obj, val, f) { obj.expansion_factor = val }, undefined);
+
+cff_field_handlers[47] = create_cff_field(FT_Common.cff_kind_num, 0x113 | FT_Common.CFFCODE_PRIVATE, null, 0, function(obj, val, f) { obj.initial_random_seed = val }, undefined);
+cff_field_handlers[48] = create_cff_field(FT_Common.cff_kind_num, 19 | FT_Common.CFFCODE_PRIVATE, null, 0, function(obj, val, f) { obj.local_subrs_offset = val }, undefined);
+cff_field_handlers[49] = create_cff_field(FT_Common.cff_kind_num, 20 | FT_Common.CFFCODE_PRIVATE, null, 0, function(obj, val, f) { obj.default_width = val }, undefined);
+cff_field_handlers[50] = create_cff_field(FT_Common.cff_kind_num, 21 | FT_Common.CFFCODE_PRIVATE, null, 0, function(obj, val, f) { obj.nominal_width = val }, undefined);
+
+/******************************************************************************/
+// cffload
+/******************************************************************************/
+var cff_isoadobe_charset =
+[
+    0,   1,   2,   3,   4,   5,   6,   7,
+    8,   9,  10,  11,  12,  13,  14,  15,
+    16,  17,  18,  19,  20,  21,  22,  23,
+    24,  25,  26,  27,  28,  29,  30,  31,
+    32,  33,  34,  35,  36,  37,  38,  39,
+    40,  41,  42,  43,  44,  45,  46,  47,
+    48,  49,  50,  51,  52,  53,  54,  55,
+    56,  57,  58,  59,  60,  61,  62,  63,
+    64,  65,  66,  67,  68,  69,  70,  71,
+    72,  73,  74,  75,  76,  77,  78,  79,
+    80,  81,  82,  83,  84,  85,  86,  87,
+    88,  89,  90,  91,  92,  93,  94,  95,
+    96,  97,  98,  99, 100, 101, 102, 103,
+    104, 105, 106, 107, 108, 109, 110, 111,
+    112, 113, 114, 115, 116, 117, 118, 119,
+    120, 121, 122, 123, 124, 125, 126, 127,
+    128, 129, 130, 131, 132, 133, 134, 135,
+    136, 137, 138, 139, 140, 141, 142, 143,
+    144, 145, 146, 147, 148, 149, 150, 151,
+    152, 153, 154, 155, 156, 157, 158, 159,
+    160, 161, 162, 163, 164, 165, 166, 167,
+    168, 169, 170, 171, 172, 173, 174, 175,
+    176, 177, 178, 179, 180, 181, 182, 183,
+    184, 185, 186, 187, 188, 189, 190, 191,
+    192, 193, 194, 195, 196, 197, 198, 199,
+    200, 201, 202, 203, 204, 205, 206, 207,
+    208, 209, 210, 211, 212, 213, 214, 215,
+    216, 217, 218, 219, 220, 221, 222, 223,
+    224, 225, 226, 227, 228
+];
+
+var cff_expert_charset =
+[
+    0,   1, 229, 230, 231, 232, 233, 234,
+    235, 236, 237, 238,  13,  14,  15,  99,
+    239, 240, 241, 242, 243, 244, 245, 246,
+    247, 248,  27,  28, 249, 250, 251, 252,
+    253, 254, 255, 256, 257, 258, 259, 260,
+    261, 262, 263, 264, 265, 266, 109, 110,
+    267, 268, 269, 270, 271, 272, 273, 274,
+    275, 276, 277, 278, 279, 280, 281, 282,
+    283, 284, 285, 286, 287, 288, 289, 290,
+    291, 292, 293, 294, 295, 296, 297, 298,
+    299, 300, 301, 302, 303, 304, 305, 306,
+    307, 308, 309, 310, 311, 312, 313, 314,
+    315, 316, 317, 318, 158, 155, 163, 319,
+    320, 321, 322, 323, 324, 325, 326, 150,
+    164, 169, 327, 328, 329, 330, 331, 332,
+    333, 334, 335, 336, 337, 338, 339, 340,
+    341, 342, 343, 344, 345, 346, 347, 348,
+    349, 350, 351, 352, 353, 354, 355, 356,
+    357, 358, 359, 360, 361, 362, 363, 364,
+    365, 366, 367, 368, 369, 370, 371, 372,
+    373, 374, 375, 376, 377, 378
+];
+
+var cff_expertsubset_charset =
+[
+    0,   1, 231, 232, 235, 236, 237, 238,
+    13,  14,  15,  99, 239, 240, 241, 242,
+    243, 244, 245, 246, 247, 248,  27,  28,
+    249, 250, 251, 253, 254, 255, 256, 257,
+    258, 259, 260, 261, 262, 263, 264, 265,
+    266, 109, 110, 267, 268, 269, 270, 272,
+    300, 301, 302, 305, 314, 315, 158, 155,
+    163, 320, 321, 322, 323, 324, 325, 326,
+    150, 164, 169, 327, 328, 329, 330, 331,
+    332, 333, 334, 335, 336, 337, 338, 339,
+    340, 341, 342, 343, 344, 345, 346
+];
+
+var cff_standard_encoding =
+[
+    0,   0,   0,   0,   0,   0,   0,   0,
+    0,   0,   0,   0,   0,   0,   0,   0,
+    0,   0,   0,   0,   0,   0,   0,   0,
+    0,   0,   0,   0,   0,   0,   0,   0,
+    1,   2,   3,   4,   5,   6,   7,   8,
+    9,  10,  11,  12,  13,  14,  15,  16,
+    17,  18,  19,  20,  21,  22,  23,  24,
+    25,  26,  27,  28,  29,  30,  31,  32,
+    33,  34,  35,  36,  37,  38,  39,  40,
+    41,  42,  43,  44,  45,  46,  47,  48,
+    49,  50,  51,  52,  53,  54,  55,  56,
+    57,  58,  59,  60,  61,  62,  63,  64,
+    65,  66,  67,  68,  69,  70,  71,  72,
+    73,  74,  75,  76,  77,  78,  79,  80,
+    81,  82,  83,  84,  85,  86,  87,  88,
+    89,  90,  91,  92,  93,  94,  95,   0,
+    0,   0,   0,   0,   0,   0,   0,   0,
+    0,   0,   0,   0,   0,   0,   0,   0,
+    0,   0,   0,   0,   0,   0,   0,   0,
+    0,   0,   0,   0,   0,   0,   0,   0,
+    0,  96,  97,  98,  99, 100, 101, 102,
+    103, 104, 105, 106, 107, 108, 109, 110,
+    0, 111, 112, 113, 114,   0, 115, 116,
+    117, 118, 119, 120, 121, 122,   0, 123,
+    0, 124, 125, 126, 127, 128, 129, 130,
+    131,   0, 132, 133,   0, 134, 135, 136,
+    137,   0,   0,   0,   0,   0,   0,   0,
+    0,   0,   0,   0,   0,   0,   0,   0,
+    0, 138,   0, 139,   0,   0,   0,   0,
+    140, 141, 142, 143,   0,   0,   0,   0,
+    0, 144,   0,   0,   0, 145,   0,   0,
+    146, 147, 148, 149,   0,   0,   0,   0
+];
+
+var cff_expert_encoding =
+[
+    0,   0,   0,   0,   0,   0,   0,   0,
+    0,   0,   0,   0,   0,   0,   0,   0,
+    0,   0,   0,   0,   0,   0,   0,   0,
+    0,   0,   0,   0,   0,   0,   0,   0,
+    1, 229, 230,   0, 231, 232, 233, 234,
+    235, 236, 237, 238,  13,  14,  15,  99,
+    239, 240, 241, 242, 243, 244, 245, 246,
+    247, 248,  27,  28, 249, 250, 251, 252,
+    0, 253, 254, 255, 256, 257,   0,   0,
+    0, 258,   0,   0, 259, 260, 261, 262,
+    0,   0, 263, 264, 265,   0, 266, 109,
+    110, 267, 268, 269,   0, 270, 271, 272,
+    273, 274, 275, 276, 277, 278, 279, 280,
+    281, 282, 283, 284, 285, 286, 287, 288,
+    289, 290, 291, 292, 293, 294, 295, 296,
+    297, 298, 299, 300, 301, 302, 303,   0,
+    0,   0,   0,   0,   0,   0,   0,   0,
+    0,   0,   0,   0,   0,   0,   0,   0,
+    0,   0,   0,   0,   0,   0,   0,   0,
+    0,   0,   0,   0,   0,   0,   0,   0,
+    0, 304, 305, 306,   0,   0, 307, 308,
+    309, 310, 311,   0, 312,   0,   0, 312,
+    0,   0, 314, 315,   0,   0, 316, 317,
+    318,   0,   0,   0, 158, 155, 163, 319,
+    320, 321, 322, 323, 324, 325,   0,   0,
+    326, 150, 164, 169, 327, 328, 329, 330,
+    331, 332, 333, 334, 335, 336, 337, 338,
+    339, 340, 341, 342, 343, 344, 345, 346,
+    347, 348, 349, 350, 351, 352, 353, 354,
+    355, 356, 357, 358, 359, 360, 361, 362,
+    363, 364, 365, 366, 367, 368, 369, 370,
+    371, 372, 373, 374, 375, 376, 377, 378
+];
+
+function cff_get_standard_encoding(charcode)
+{
+    return (charcode < 256 ? cff_standard_encoding[charcode] : 0);
+}
+
+function cff_index_read_offset(idx)
+{
+    var result = 0;
+    var tmp = g_memory.Alloc(4);
+    var error = idx.stream.Read(tmp, idx.off_size);
+
+    if (error == 0)
+    {
+        for (var nn = 0; nn < idx.off_size; nn++)
+            result = (result << 8) | tmp.data[nn];
+
+        result = FT_Common.IntToUInt(result);
+    }
+
+    return { err : error, result: result };
+}
+
+function cff_index_init(idx, stream, load)
+{
+    idx.clear();
+    idx.stream = stream;
+    idx.start  = stream.pos;
+
+    var count = stream.ReadUShort();
+    var error = FT_Error;
+    if (error != 0)
+        return error;
+
+    if (0 == count)
+        return error;
+
+    var offsize = stream.ReadUChar();
+    if (error != 0)
+        return error;
+
+    if (offsize < 1 || offsize > 4)
+        return FT_Common.FT_Err_Invalid_Table;
+
+    idx.count    = count;
+    idx.off_size = offsize;
+    var size = (count + 1) * offsize;
+
+    idx.data_offset = idx.start + 3 + size;
+
+    error = stream.Skip(size - offsize);
+    if (error != 0)
+        return error;
+
+    var _err = cff_index_read_offset(idx);
+    error = _err.err;
+    size = _err.result;
+    if (error != 0)
+        return error;
+
+    if (size == 0)
+        return FT_Common.FT_Err_Invalid_Table;
+
+    idx.data_size = --size;
+
+    if (load)
+    {
+        /* load the data */
+        idx.bytes = new CPointer();
+        error = stream.ExtractFrame(size, idx.bytes);
+    }
+    else
+    {
+        /* skip the data */
+        error = stream.Skip(size);
+    }
+
+    return error;
+}
+
+function cff_index_done(idx)
+{
+    if (idx.stream != null)
+    {
+        idx.clear();
+    }
+}
+
+function cff_index_load_offsets(idx)
+{
+    var error = 0;
+    var stream = idx.stream;
+
+    if (idx.count > 0 && idx.offsets == null)
+    {
+        var offsize = idx.off_size;
+        var data_size = (idx.count + 1) * offsize;
+
+        error = stream.Seek(idx.start + 3);
+        if (error == 0)
+            error = stream.EnterFrame(data_size);
+
+        if (error != 0)
+            return error;
+
+        idx.offsets = CreateUIntArray(idx.count + 1);
+
+        var poff = 0;
+        var p = stream.cur;
+        var p_end  = p + data_size;
+
+        var _s = stream.data;
+        var _d = idx.offsets;
+
+        switch (offsize)
+        {
+            case 1:
+                for (; p < p_end; p++, poff++)
+                    _d[poff] = _s[p];
+                break;
+
+            case 2:
+                for (; p < p_end; p += 2, poff++)
+                    _d[poff] = (_s[p] << 8 | _s[p+1]);
+                break;
+
+            case 3:
+                for (; p < p_end; p += 3, poff++)
+                    _d[poff] = (_s[p] << 16 | _s[p+1] << 8 | _s[p+2]);
+                break;
+
+            default:
+                for (; p < p_end; p += 4, poff++)
+                {
+                    var r = (_s[p] << 24 | _s[p+1] << 16 | _s[p+2] << 8 | _s[p+3]);
+                    if (r<0)
+                        r+=FT_Common.a_i;
+                    _d[poff] = r;
+                }
+        }
+
+        stream.ExitFrame();
+    }
+
+    return error;
+}
+
+function cff_index_get_pointers(idx, table, pool, is_pool)
+{
+    var error = 0;
+
+    if (idx.offsets == null)
+    {
+        error = cff_index_load_offsets(idx);
+        if (error != 0)
+            return { err: error, table: table, pool: pool };
+    }
+
+    if (idx.count > 0)
+    {
+        var t = new Array(idx.count + 1);
+        var new_bytes = g_memory.Alloc(idx.data_size + idx.count);
+
+        var extra = 0;
+        var org_bytes = idx.bytes;
+
+        /* at this point, `idx->offsets' can't be NULL */
+        var cur_offset = idx.offsets[0] - 1;
+
+        /* sanity check */
+        if (cur_offset >= idx.data_size)
+        {
+            cur_offset = 0;
+        }
+
+        if (is_pool == 0)
+        {
+            t[0] = dublicate_pointer(org_bytes);
+            t[0].pos += cur_offset;
+        }
+        else
+        {
+            t[0] = dublicate_pointer(new_bytes);
+            t[0].pos += cur_offset;
+        }
+
+        for (var n = 1; n <= idx.count; n++)
+        {
+            var next_offset = idx.offsets[n] - 1;
+
+            /* empty slot + two sanity checks for invalid offset tables */
+            if (next_offset == 0 || next_offset < cur_offset || (next_offset >= idx.data_size && n < idx.count))
+                next_offset = cur_offset;
+
+            if (is_pool == 0)
+            {
+                t[n] = dublicate_pointer(org_bytes);
+                t[n].pos += next_offset;
+            }
+            else
+            {
+                t[n] = dublicate_pointer(new_bytes);
+                t[n].pos += next_offset + extra;
+
+                if (next_offset != cur_offset)
+                {
+                    var _d = t[n - 1];
+                    var _s = dublicate_pointer(org_bytes);
+                    _s.pos += cur_offset;
+                    var _l = t[n].pos - t[n-1].pos;
+
+                    for (var i = 0; i < _l; i++)
+                        _d.data[_d.pos + i] = _s.data[_s.pos + i];
+
+                    t[n].data[t[n].pos] = FT_Common.SYMBOL_CONST_S0;
+                    t[n].pos += 1;
+                    extra++;
+                }
+            }
+
+            cur_offset = next_offset;
+        }
+
+        return { err: error, table: t, pool: new_bytes };
+    }
+
+    return { err: error, table: table, pool: pool };
+}
+
+function cff_index_access_element(idx, element)
+{
+    var error = 0;
+    var pbytes = null;
+    var pbyte_len = 0;
+
+    if (idx && idx.count > element)
+    {
+        /* compute start and end offsets */
+        var stream = idx.stream;
+        var off1, off2 = 0;
+
+
+        /* load offsets from file or the offset table */
+        if (idx.offsets == null)
+        {
+            var pos = element * idx.off_size;
+
+            error = stream.Seek(idx.start + 3 + pos);
+            if (error != 0)
+                return { err: error, bytes: pbytes, len: pbyte_len };
+
+            var ret = cff_index_read_offset(idx);
+            error = ret.err;
+            off1 = ret.result;
+            if (error != 0)
+                return { err: error, bytes: pbytes, len: pbyte_len };
+
+            if (off1 != 0)
+            {
+                do
+                {
+                    element++;
+                    ret = cff_index_read_offset(idx);
+                    error = ret.err;
+                    off2 = ret.result;
+                }
+                while (off2 == 0 && element < idx.count);
+            }
+        }
+        else   /* use offsets table */
+        {
+            off1 = idx.offsets[element];
+            if (off1)
+            {
+                do
+                {
+                    element++;
+                    off2 = idx.offsets[element];
+
+                } while (off2 == 0 && element < idx.count);
+            }
+        }
+
+        /* XXX: should check off2 does not exceed the end of this entry; */
+        /*      at present, only truncate off2 at the end of this stream */
+        if (off2 > stream.size + 1 || idx.data_offset > stream.size - off2 + 1)
+        {
+            off2 = stream.size - idx.data_offset + 1;
+        }
+
+        /* access element */
+        if (off1 && off2 > off1)
+        {
+            pbyte_len = off2 - off1;
+
+            if (idx.bytes != null)
+            {
+                /* this index was completely loaded in memory, that's easy */
+                pbytes = dublicate_pointer(idx.bytes);
+                pbytes.pos += (off1 - 1);
+            }
+            else
+            {
+                /* this index is still on disk/file, access it through a frame */
+                error = stream.Seek(idx.data_offset + off1 - 1);
+                if (error == 0)
+                {
+                    pbytes = new CPointer();
+                    error = stream.ExtractFrame(off2 - off1, pbytes);
+                }
+            }
+        }
+        else
+        {
+            /* empty index element */
+            pbytes = null;
+            pbyte_len = 0;
+        }
+    }
+    else
+        error = FT_Common.FT_Err_Invalid_Argument;
+
+    return { err: error, bytes: pbytes, len: pbyte_len };
+}
+
+function cff_index_forget_element(idx, pbytes)
+{
+    if (idx.bytes == null)
+    {
+        idx.stream.ReleaseFrame();
+        pbytes = null;
+    }
+}
+
+function cff_index_get_name(font, element)
+{
+    var idx = font.name_index;
+    var ret = cff_index_access_element(idx, element);
+    if (0 != ret.err)
+        return null;
+
+    var name = "";
+    var _len = ret.len;
+    var _d = ret.bytes;
+    for (var i = 0; i < _len; i++)
+        name += String.fromCharCode(_d.data[_d.pos + i]);
+
+    cff_index_forget_element(idx, ret.bytes);
+    return name;
+}
+
+function cff_index_get_string(font, element)
+{
+    return (element < font.num_strings) ? FT_PEEK_String1(font.strings[element], 1000) : null;
+}
+
+function cff_index_get_sid_string(font, sid)
+{
+    /* value 0xFFFFU indicates a missing dictionary entry */
+    if (sid == 0xFFFF)
+        return null;
+
+    /* if it is not a standard string, return it */
+    if (sid > 390)
+        return cff_index_get_string(font, sid - 391);
+
+    /* CID-keyed CFF fonts don't have glyph names */
+    if (font.psnames == null)
+        return null;
+
+    /* this is a standard string */
+    return font.psnames.adobe_std_strings(sid);
+}
+
+function CFF_Done_FD_Select(fdselect, stream)
+{
+    if (fdselect.data)
+    {
+        stream.ReleaseFrame();
+        fdselect.data = null;
+    }
+
+    fdselect.data_size   = 0;
+    fdselect.format      = 0;
+    fdselect.range_count = 0;
+}
+
+function CFF_Load_FD_Select(fdselect, num_glyphs, stream, offset)
+{
+    var error = stream.Seek(offset);
+    if (error != 0)
+        return error;
+
+    var format = stream.ReadUChar();
+    error = FT_Error;
+    if (error != 0)
+        return error;
+
+    fdselect.format      = format;
+    fdselect.cache_count = 0;   /* clear cache */
+
+    switch (format)
+    {
+        case 0:     /* format 0, that's simple */
+            fdselect.data_size = num_glyphs;
+            fdselect.data = new CPointer();
+            error = stream.ExtractFrame(fdselect.data_size, fdselect.data);
+            break;
+        case 3:     /* format 3, a tad more complex */
+            var num_ranges = stream.ReadUShort();
+            error = FT_Error;
+            if (error != 0)
+                return error;
+
+            fdselect.data_size = num_ranges * 3 + 2;
+            fdselect.data = new CPointer();
+            error = stream.ExtractFrame(fdselect.data_size, fdselect.data);
+            break;
+
+        default:    /* hmm... that's wrong */
+            error = FT_Common.FT_Err_Invalid_File_Format;
+    }
+
+    return error;
+}
+
+function cff_fd_select_get(fdselect, glyph_index)
+{
+    var fd = 0;
+    switch (fdselect.format)
+    {
+        case 0:
+            fd = fdselect.data.data[fdselect.data.pos + glyph_index];
+            break;
+
+        case 3:
+            /* first, compare to cache */
+            if ((glyph_index - fdselect.cache_first) < fdselect.cache_count)
+            {
+                fd = fdselect.cache_fd;
+                break;
+            }
+
+            /* then, lookup the ranges array */
+            var p = dublicate_pointer(fdselect.data);
+            var p_limit = p.pos + fdselect.data_size;
+
+            var first = FT_NEXT_USHORT(p);
+            do
+            {
+                if (glyph_index < first)
+                    break;
+
+                var fd2 = p.data[p.pos];
+                p.pos++;
+                var limit = FT_NEXT_USHORT(p);
+
+                if (glyph_index < limit)
+                {
+                    fd = fd2;
+
+                    /* update cache */
+                    fdselect.cache_first = first;
+                    fdselect.cache_count = limit-first;
+                    fdselect.cache_fd    = fd2;
+                    break;
+                }
+                first = limit;
+
+            } while ( p < p_limit );
+            break;
+
+        default:
+            break;
+    }
+
+    return fd;
+}
+
+function cff_charset_compute_cids(charset, num_glyphs, memory)
+{
+    var error = 0;
+    var max_cid = 0;
+
+    if (charset.max_cid > 0)
+        return error;
+
+    for (var i = 0; i < num_glyphs; i++)
+    {
+        if (charset.sids[i] > max_cid)
+            max_cid = charset.sids[i];
+    }
+
+    charset.cids = CreateUIntArray(max_cid + 1);
+
+    /* When multiple GIDs map to the same CID, we choose the lowest */
+    /* GID.  This is not described in any spec, but it matches the  */
+    /* behaviour of recent Acroread versions.                       */
+    for (var j = num_glyphs - 1; j >= 0 ; j--)
+        charset.cids[charset.sids[j]] = j;
+
+    charset.max_cid    = max_cid;
+    charset.num_glyphs = num_glyphs;
+
+    return error;
+}
+
+function cff_charset_cid_to_gindex(charset, cid)
+{
+    if (cid <= charset.max_cid)
+        return charset.cids[cid];
+    return 0;
+}
+
+function cff_charset_free_cids(charset, memory)
+{
+    charset.cids = null;
+    charset.max_cid = 0;
+}
+
+function cff_charset_done(charset, stream)
+{
+    cff_charset_free_cids(charset, stream.memory);
+
+    charset.sids = null;
+    charset.format = 0;
+    charset.offset = 0;
+}
+
+function cff_charset_load(charset, num_glyphs, stream, base_offset, offset, invert)
+{
+    var error = 0;
+    var glyph_sid = 0;
+
+    /* If the the offset is greater than 2, we have to parse the */
+    /* charset table.                                            */
+    if (offset > 2)
+    {
+        charset.offset = base_offset + offset;
+
+        error = stream.Seek(charset.offset);
+        if (error != 0)
+        {
+            charset.sids = null;
+            charset.cids = null;
+            charset.format = 0;
+            charset.offset = 0;
+            return error;
+        }
+
+        charset.format = stream.ReadUChar();
+        error = FT_Error;
+        if (error != 0)
+        {
+            charset.sids = null;
+            charset.cids = null;
+            charset.format = 0;
+            charset.offset = 0;
+            return error;
+        }
+
+        charset.sids = CreateUIntArray(num_glyphs);
+
+        /* assign the .notdef glyph */
+        charset.sids[0] = 0;
+
+        switch (charset.format)
+        {
+            case 0:
+                if (num_glyphs > 0)
+                {
+                    error = stream.EnterFrame((num_glyphs - 1) * 2);
+                    if (error != 0)
+                    {
+                        charset.sids = null;
+                        charset.cids = null;
+                        charset.format = 0;
+                        charset.offset = 0;
+                        return error;
+                    }
+
+                    for (j = 1; j < num_glyphs; j++)
+                        charset.sids[j] = stream.GetUShort();
+
+                    stream.ExitFrame();
+                }
+                break;
+
+            case 1:
+            case 2:
+                var nleft = 0;
+                var j = 1;
+                while (j < num_glyphs)
+                {
+                    glyph_sid = stream.ReadUShort();
+                    error = FT_Error;
+                    if (error != 0)
+                    {
+                        charset.sids = null;
+                        charset.cids = null;
+                        charset.format = 0;
+                        charset.offset = 0;
+                        return error;
+                    }
+
+                    if (charset.format == 2)
+                    {
+                        nleft = stream.ReadUShort();
+                        error = FT_Error;
+                        if (error != 0)
+                        {
+                            charset.sids = null;
+                            charset.cids = null;
+                            charset.format = 0;
+                            charset.offset = 0;
+                            return error;
+                        }
+                    }
+                    else
+                    {
+                        nleft = stream.ReadUChar();
+                        error = FT_Error;
+                        if (error != 0)
+                        {
+                            charset.sids = null;
+                            charset.cids = null;
+                            charset.format = 0;
+                            charset.offset = 0;
+                            return error;
+                        }
+                    }
+
+                    /* try to rescue some of the SIDs if `nleft' is too large */
+                    if (glyph_sid > (0xFFFF - nleft))
+                    {
+                        nleft = (0xFFFF - glyph_sid);
+                    }
+
+                    /* Fill in the range of sids -- `nleft + 1' glyphs. */
+                    for (i = 0; j < num_glyphs && i <= nleft; i++, j++, glyph_sid++)
+                        charset.sids[j] = glyph_sid;
+                }
+                break;
+
+            default:
+                charset.sids = null;
+                charset.cids = null;
+                charset.format = 0;
+                charset.offset = 0;
+                return FT_Common.FT_Err_Invalid_File_Format;
+        }
+    }
+    else
+    {
+        /* Parse default tables corresponding to offset == 0, 1, or 2.  */
+        /* CFF specification intimates the following:                   */
+        /*                                                              */
+        /* In order to use a predefined charset, the following must be  */
+        /* true: The charset constructed for the glyphs in the font's   */
+        /* charstrings dictionary must match the predefined charset in  */
+        /* the first num_glyphs.                                        */
+        charset.offset = offset;  /* record charset type */
+
+        switch (offset)
+        {
+        case 0:
+            if (num_glyphs > 229)
+            {
+                charset.sids = null;
+                charset.cids = null;
+                charset.format = 0;
+                charset.offset = 0;
+                return FT_Common.FT_Err_Invalid_File_Format;
+            }
+
+            charset.sids = CreateUIntArray(num_glyphs);
+            for (var k = 0; k < num_glyphs; k++)
+                charset.sids[k] = cff_isoadobe_charset[k];
+
+            break;
+
+        case 1:
+            if (num_glyphs > 166)
+            {
+                charset.sids = null;
+                charset.cids = null;
+                charset.format = 0;
+                charset.offset = 0;
+                return FT_Common.FT_Err_Invalid_File_Format;
+            }
+
+            charset.sids = CreateUIntArray(num_glyphs);
+            for (var k = 0; k < num_glyphs; k++)
+                charset.sids[k] = cff_expert_charset[k];
+
+            break;
+
+        case 2:
+            if (num_glyphs > 87)
+            {
+                charset.sids = null;
+                charset.cids = null;
+                charset.format = 0;
+                charset.offset = 0;
+                return FT_Common.FT_Err_Invalid_File_Format;
+            }
+
+            charset.sids = CreateUIntArray(num_glyphs);
+            for (var k = 0; k < num_glyphs; k++)
+                charset.sids[k] = cff_expertsubset_charset[k];
+
+            break;
+
+        default:
+            charset.sids = null;
+            charset.cids = null;
+            charset.format = 0;
+            charset.offset = 0;
+            return FT_Common.FT_Err_Invalid_File_Format;
+        }
+    }
+
+    /* we have to invert the `sids' array for subsetted CID-keyed fonts */
+    if (invert)
+        error = cff_charset_compute_cids(charset, num_glyphs, stream.memory);
+
+    if (error != 0)
+    {
+        charset.sids = null;
+        charset.cids = null;
+        charset.format = 0;
+        charset.offset = 0;
+    }
+    return error;
+}
+
+function cff_encoding_done(encoding)
+{
+    encoding.format = 0;
+    encoding.offset = 0;
+    encoding.count  = 0;
+}
+
+function cff_encoding_load(encoding, charset, num_glyphs, stream, base_offset, offset)
+{
+    var error = 0;
+    var count = 0;
+    var j = 0;
+    var glyph_sid = 0;
+    var glyph_code = 0;
+
+
+    /* Check for charset->sids.  If we do not have this, we fail. */
+    if (charset.sids == null)
+        return FT_Common.FT_Err_Invalid_File_Format;
+
+    /* Zero out the code to gid/sid mappings. */
+    for (j = 0; j < 256; j++)
+    {
+        encoding.sids[j] = 0;
+        encoding.codes[j] = 0;
+    }
+
+    /* Note: The encoding table in a CFF font is indexed by glyph index;  */
+    /* the first encoded glyph index is 1.  Hence, we read the character  */
+    /* code (`glyph_code') at index j and make the assignment:            */
+    /*                                                                    */
+    /*    encoding->codes[glyph_code] = j + 1                             */
+    /*                                                                    */
+    /* We also make the assignment:                                       */
+    /*                                                                    */
+    /*    encoding->sids[glyph_code] = charset->sids[j + 1]               */
+    /*                                                                    */
+    /* This gives us both a code to GID and a code to SID mapping.        */
+    if (offset > 1)
+    {
+        encoding.offset = base_offset + offset;
+
+        error = stream.Seek(encoding.offset);
+        if (error != 0)
+            return error;
+        encoding.format = stream.ReadUChar();
+        error = FT_Error;
+        if (error != 0)
+            return error;
+        count = stream.ReadUChar();
+        error = FT_Error;
+        if (error != 0)
+            return error;
+
+        switch (encoding.format & 0x7F)
+        {
+            case 0:
+                encoding.count = count + 1;
+                error = stream.EnterFrame(count);
+                if (error != 0)
+                    return error;
+
+                var p = stream.cur;
+                for (j = 1; j <= count; j++)
+                {
+                    glyph_code = stream.data[p];
+                    p++;
+                    /* Make sure j is not too big. */
+                    if (j < num_glyphs)
+                    {
+                        /* Assign code to GID mapping. */
+                        encoding.codes[glyph_code] = j;
+                        /* Assign code to SID mapping. */
+                        encoding.sids[glyph_code] = charset.sids[j];
+                    }
+                }
+                stream.ExitFrame();
+                break;
+
+            case 1:
+                var nleft = 0;
+                var i = 1;
+                encoding.count = 0;
+
+                /* Parse the Format1 ranges. */
+                for (j = 0;  j < count; j++, i += nleft)
+                {
+                    /* Read the first glyph code of the range. */
+                    glyph_code = stream.ReadUChar();
+                    error = FT_Error;
+                    if (error != 0)
+                        return error;
+
+                    nleft = stream.ReadUChar();
+                    error = FT_Error;
+                    if (error != 0)
+                        return error;
+                    /* Read the number of codes in the range. */
+                    /* Increment nleft, so we read `nleft + 1' codes/sids. */
+                    nleft++;
+
+                    /* compute max number of character codes */
+                    if (nleft > encoding.count)
+                        encoding.count = nleft;
+
+                    /* Fill in the range of codes/sids. */
+                    for (var k = i; k < nleft + i; k++, glyph_code++)
+                    {
+                        /* Make sure k is not too big. */
+                        if (k < num_glyphs && glyph_code < 256)
+                        {
+                            /* Assign code to GID mapping. */
+                            encoding.codes[glyph_code] = k;
+                            /* Assign code to SID mapping. */
+                            encoding.sids[glyph_code] = charset.sids[k];
+                        }
+                    }
+                }
+
+                /* simple check; one never knows what can be found in a font */
+                if (encoding.count > 256)
+                    encoding.count = 256;
+
+                break;
+
+            default:
+                return FT_Common.FT_Err_Invalid_File_Format;
+        }
+
+        /* Parse supplemental encodings, if any. */
+        if (encoding.format & 0x80)
+        {
+            count = stream.ReadUChar();
+            error = FT_Error;
+            if (error != 0)
+                return error;
+
+            for (j = 0; j < count; j++)
+            {
+                /* Read supplemental glyph code. */
+                glyph_code = stream.ReadUChar();
+                error = FT_Error;
+                if (error != 0)
+                    return error;
+
+                glyph_sid = stream.ReadUShort();
+                error = FT_Error;
+                if (error != 0)
+                    return error;
+
+                /* Assign code to SID mapping. */
+                encoding.sids[glyph_code] = glyph_sid;
+
+                /* First, look up GID which has been assigned to */
+                /* SID glyph_sid.                                */
+                for (var gindex = 0; gindex < num_glyphs; gindex++)
+                {
+                    if (charset.sids[gindex] == glyph_sid)
+                    {
+                        encoding.codes[glyph_code] = gindex;
+                        break;
+                    }
+                }
+            }
+        }
+    }
+    else
+    {
+        /* We take into account the fact a CFF font can use a predefined */
+        /* encoding without containing all of the glyphs encoded by this */
+        /* encoding (see the note at the end of section 12 in the CFF    */
+        /* specification).                                               */
+
+        switch (offset)
+        {
+        case 0:
+        case 1:
+            var src = (offset == 0) ? cff_standard_encoding : cff_expert_encoding;
+            for (var k = 0; k < 256; k++)
+                encoding.sids[k] = src[k];
+
+            encoding.count = 0;
+            error = cff_charset_compute_cids(charset, num_glyphs, stream.memory);
+            if (error != 0)
+                return error;
+
+            for (j = 0; j < 256; j++)
+            {
+                var sid = encoding.sids[j];
+                var gid = 0;
+
+
+                if (sid)
+                    gid = cff_charset_cid_to_gindex(charset, sid);
+
+                if ( gid != 0 )
+                {
+                    encoding.codes[j] = gid;
+                    encoding.count    = j + 1;
+                }
+                else
+                {
+                    encoding.codes[j] = 0;
+                    encoding.sids [j] = 0;
+                }
+            }
+            break;
+
+        default:
+            return FT_Common.FT_Err_Invalid_File_Format;
+        }
+    }
+
+    return error;
+}
+
+function cff_subfont_load(font, idx, font_index, stream, base_offset, library)
+{
+    var error = 0;
+    var parser = new CFF_ParserRec();
+    var top = font.font_dict;
+    var priv = font.private_dict;
+
+    cff_parser_init(parser, FT_Common.CFF_CODE_TOPDICT, font.font_dict, library);
+
+    /* set defaults */
+    top.clear();
+
+    top.underline_position  = -100 << 16;
+    top.underline_thickness = 50 << 16;
+    top.charstring_type     = 2;
+    top.font_matrix.xx      = 0x10000;
+    top.font_matrix.yy      = 0x10000;
+    top.cid_count           = 8720;
+
+    /* we use the implementation specific SID value 0xFFFF to indicate */
+    /* missing entries                                                 */
+    top.version             = 0xFFFF;
+    top.notice              = 0xFFFF;
+    top.copyright           = 0xFFFF;
+    top.full_name           = 0xFFFF;
+    top.family_name         = 0xFFFF;
+    top.weight              = 0xFFFF;
+    top.embedded_postscript = 0xFFFF;
+
+    top.cid_registry        = 0xFFFF;
+    top.cid_ordering        = 0xFFFF;
+    top.cid_font_name       = 0xFFFF;
+
+    var ret = cff_index_access_element(idx, font_index);
+    error = ret.err;
+    var dict = ret.bytes;
+    var dict_len = ret.len;
+
+    if (error == 0)
+    {
+        error = cff_parser_run(parser, dict, dict.pos + dict_len);
+    }
+
+    cff_index_forget_element(idx, dict);
+
+    if (error != 0)
+        return error;
+
+    /* if it is a CID font, we stop there */
+    if (top.cid_registry != 0xFFFF)
+        return error;
+
+    /* parse the private dictionary, if any */
+    if (top.private_offset != 0 && top.private_size != 0)
+    {
+        priv.clear();
+
+        priv.blue_shift       = 7;
+        priv.blue_fuzz        = 1;
+        priv.lenIV            = -1;
+        priv.expansion_factor = parseInt(0.06 * 0x10000);
+        priv.blue_scale       = parseInt(0.039625 * 0x10000 * 1000);
+
+        cff_parser_init(parser, FT_Common.CFF_CODE_PRIVATE, priv, library);
+
+        error = stream.Seek(base_offset + font.font_dict.private_offset);
+        if (error != 0)
+            return error;
+
+        error = stream.EnterFrame(font.font_dict.private_size);
+        if (error != 0)
+            return error;
+
+        var curs = new CPointer();
+        curs.data = stream.data;
+        curs.pos = stream.cur;
+        error = cff_parser_run(parser, curs, curs.pos + font.font_dict.private_size);
+
+        stream.ExitFrame();
+        if (error != 0)
+            return error;
+
+        /* ensure that `num_blue_values' is even */
+        priv.num_blue_values &= ~1;
+    }
+
+    /* read the local subrs, if any */
+    if (priv.local_subrs_offset != 0)
+    {
+        error = stream.Seek(base_offset + top.private_offset + priv.local_subrs_offset);
+        if (error != 0)
+            return error;
+
+        error = cff_index_init(font.local_subrs_index, stream, 1);
+        if (error != 0)
+            return error;
+
+        ret = cff_index_get_pointers(font.local_subrs_index, font.local_subrs, null, 0);
+        error = ret.err;
+        font.local_subrs = ret.table;
+        if (error != 0)
+            return error;
+    }
+
+    return error;
+}
+
+function cff_subfont_done(memory, subfont)
+{
+    if (subfont != null)
+    {
+        cff_index_done(subfont.local_subrs_index);
+        subfont.local_subrs = null;
+    }
+}
+
+function cff_font_load(library, stream, face_index, font, pure_cff)
+{
+    var error = 0;
+    var memory = stream.memory;
+    var base_offset = stream.pos;
+    var dict = font.top_font.font_dict;
+    var string_index = new CFF_IndexRec();
+
+    // TODO: font.clear();
+    error = stream.EnterFrame(4);
+    if (error != 0)
+        return error;
+
+    /* read CFF font header */
+    font.version_major = stream.GetUChar();
+    font.version_minor = stream.GetUChar();
+    font.header_size = stream.GetUChar();
+    font.absolute_offsize = stream.GetUChar();
+
+    stream.ExitFrame();
+
+    /* check format */
+    if (font.version_major != 1 || font.header_size < 4 || font.absolute_offsize > 4)
+        return FT_Common.FT_Err_Unknown_File_Format;
+
+    /* skip the rest of the header */
+    error = stream.Skip(font.header_size - 4);
+    if (error != 0)
+        return error;
+
+    /* read the name, top dict, string and global subrs index */
+    error = cff_index_init(font.name_index, stream, 0);
+    if (error == 0)
+        error = cff_index_init(font.font_dict_index, stream, 0);
+    if (error == 0)
+        error = cff_index_init(string_index, stream, 1);
+    if (error == 0)
+        error = cff_index_init(font.global_subrs_index, stream, 1);
+
+    if (error != 0)
+        return error;
+
+    var ret = cff_index_get_pointers(string_index, font.strings, font.string_pool, 1);
+    error = ret.err;
+    font.strings = ret.table;
+    font.string_pool = ret.pool;
+
+    font.num_strings = string_index.count;
+
+    /* well, we don't really forget the `disabled' fonts... */
+    font.num_faces = font.name_index.count;
+    if (face_index >= font.num_faces)
+    {
+        error = FT_Common.FT_Err_Invalid_Argument;
+    }
+
+    /* in case of a font format check, simply exit now */
+    if (face_index < 0)
+        return error;
+
+    /* now, parse the top-level font dictionary */
+    error = cff_subfont_load(font.top_font, font.font_dict_index, face_index, stream, base_offset, library);
+    if (error != 0)
+        return error;
+
+    error = stream.Seek(base_offset + dict.charstrings_offset);
+    if (error != 0)
+        return error;
+
+    error = cff_index_init(font.charstrings_index, stream, 0);
+    if (error != 0)
+        return error;
+
+    /* now, check for a CID font */
+    if (dict.cid_registry != 0xFFFF)
+    {
+        var fd_index = new CFF_IndexRec();
+        var sub = null;
+
+        /* this is a CID-keyed font, we must now allocate a table of */
+        /* sub-fonts, then load each of them separately              */
+        error = stream.Seek(base_offset + dict.cid_fd_array_offset);
+        if (error != 0)
+            return error;
+
+        error = cff_index_init(fd_index, stream, 0);
+        if (error != 0)
+            return error;
+
+        if (fd_index.count > FT_Common.CFF_MAX_CID_FONTS)
+        {
+            cff_index_done(fd_index);
+        }
+        else
+        {
+            var _is_break = 0;
+            /* allocate & read each font dict independently */
+            font.num_subfonts = fd_index.count;
+            sub = new Array(fd_index.count);
+
+            for (var idx = 0; idx < fd_index.count; idx++)
+                sub[idx] = new CFF_SubFontRec();
+
+            /* set up pointer table */
+            for (var idx = 0; idx < fd_index.count; idx++)
+                font.subfonts[idx] = sub[idx];
+
+            /* now load each subfont independently */
+            for (var idx = 0; idx < fd_index.count; idx++)
+            {
+                error = cff_subfont_load(font.subfonts[idx], fd_index, idx, stream, base_offset, library);
+                if (error != 0)
+                {
+                    cff_index_done(fd_index);
+                    _is_break = 1;
+                }
+            }
+
+            /* now load the FD Select array */
+            if (_is_break == 0)
+            {
+                error = CFF_Load_FD_Select(font.fd_select, font.charstrings_index.count, stream, base_offset + dict.cid_fd_select_offset);
+            }
+
+            cff_index_done(fd_index);
+
+            if (error != 0)
+                return error;
+        }
+    }
+    else
+        font.num_subfonts = 0;
+
+    /* read the charstrings index now */
+    if (dict.charstrings_offset == 0)
+        return FT_Common.FT_Err_Invalid_File_Format;
+
+
+    font.num_glyphs = font.charstrings_index.count;
+
+    ret = cff_index_get_pointers(font.global_subrs_index, font.global_subrs, null, 0);
+    error = ret.err;
+    font.global_subrs = ret.table;
+
+    if (error != 0)
+        return error;
+
+    /* read the Charset and Encoding tables if available */
+    if (font.num_glyphs > 0)
+    {
+        var invert = (dict.cid_registry != 0xFFFF && pure_cff) ? 1 : 0;
+
+        error = cff_charset_load(font.charset, font.num_glyphs, stream, base_offset, dict.charset_offset, invert);
+        if (error != 0)
+            return error;
+
+        /* CID-keyed CFFs don't have an encoding */
+        if (dict.cid_registry == 0xFFFF)
+        {
+            error = cff_encoding_load(font.encoding, font.charset, font.num_glyphs, stream, base_offset, dict.encoding_offset);
+            if (error != 0)
+                return error;
+        }
+    }
+
+    /* get the font name (/CIDFontName for CID-keyed fonts, */
+    /* /FontName otherwise)                                 */
+    font.font_name = cff_index_get_name(font, face_index);
+
+    cff_index_done(string_index);
+    return error;
+}
+
+function cff_font_done(font)
+{
+    var memory = font.memory;
+
+    cff_index_done(font.global_subrs_index);
+    cff_index_done(font.font_dict_index );
+    cff_index_done(font.name_index);
+    cff_index_done(font.charstrings_index);
+
+    /* release font dictionaries, but only if working with */
+    /* a CID keyed CFF font                                */
+    if (font.num_subfonts > 0)
+    {
+        for (var idx = 0; idx < font.num_subfonts; idx++)
+            cff_subfont_done(memory, font.subfonts[idx]);
+
+        /* the subfonts array has been allocated as a single block */
+        font.subfonts[0] = null;
+    }
+
+    cff_encoding_done(font.encoding);
+    cff_charset_done(font.charset, font.stream);
+
+    cff_subfont_done(memory, font.top_font);
+
+    CFF_Done_FD_Select(font.fd_select, font.stream);
+
+    font.font_info = null;
+
+    font.strings = null;
+    font.string_pool = null;
+}
+
+/******************************************************************************/
+// cffcmaps
+/******************************************************************************/
+function CFF_CMapStdRec()
+{
+    this.cmap = new FT_CMapRec();
+    this.gids = null;
+
+    this.type = FT_Common.FT_CMAP_1;
+}
+
+function cff_cmap_encoding_init(cmap)
+{
+    cmap.gids = __FT_CMapRec(cmap).charmap.face.extra.data.encoding.codes;
+    return 0;
+}
+
+function cff_cmap_encoding_done(cmap)
+{
+    cmap.gids = null;
+}
+
+function cff_cmap_encoding_char_index(cmap, char_code)
+{
+    if (char_code < 256)
+        return cmap.gids[char_code];
+
+    return 0;
+}
+
+function cff_cmap_encoding_char_next(cmap, pchar_code)
+{
+    var char_code = pchar_code;
+    var ret = {gindex: 0, char_code: 0};
+
+    if (char_code < 255)
+    {
+        var code = char_code + 1;
+
+        for (;;)
+        {
+            if (code >= 256)
+                break;
+
+            ret.gindex = cmap.gids[code];
+            if (ret.gindex != 0)
+            {
+                ret.char_code = code;
+                break;
+            }
+            code++;
+        }
+    }
+    return ret;
+}
+
+var cff_cmap_encoding_class_rec = create_cmap_class_rec(101,cff_cmap_encoding_init,cff_cmap_encoding_done,cff_cmap_encoding_char_index,cff_cmap_encoding_char_next,null,null,null,null,null);
+
+function cff_sid_to_glyph_name(face, idx)
+{
+    var cff = face.extra.data;
+    var sid = cff.charset.sids[idx];
+
+    return cff_index_get_sid_string(cff, sid);
+}
+
+function cff_cmap_unicode_init(unicodes)
+{
+    var face = __FT_CharmapRec(unicodes).face;
+    var cff = face.extra.data;
+    var charset = cff.charset;
+    var psnames = cff.psnames;
+
+    /* can't build Unicode map for CID-keyed font */
+    /* because we don't know glyph names.         */
+    if (charset.sids == null)
+        return FT_Common.FT_Err_No_Unicode_Glyph_Name;
+
+    return psnames.unicodes_init(face.memory, unicodes, cff.num_glyphs, cff_sid_to_glyph_name, null, face);
+}
+
+function cff_cmap_unicode_done(unicodes)
+{
+    unicodes.maps = null;
+    unicodes.num_maps = 0;
+}
+
+function cff_cmap_unicode_char_index(unicodes, char_code)
+{
+    var face = __FT_CharmapRec(unicodes).face;
+    var psnames = face.extra.data.psnames;
+
+    return psnames.unicodes_char_index(unicodes, char_code);
+}
+
+function cff_cmap_unicode_char_next(unicodes, pchar_code)
+{
+    var face = __FT_CharmapRec(unicodes).face;
+    var psnames = face.extra.data.psnames;
+
+    return psnames.unicodes_char_next(unicodes, pchar_code);
+}
+
+var cff_cmap_unicode_class_rec = create_cmap_class_rec(102,cff_cmap_unicode_init,cff_cmap_unicode_done,cff_cmap_unicode_char_index,cff_cmap_unicode_char_next,null,null,null,null,null);
+
+/******************************************************************************/
+// cffobjs
+/******************************************************************************/
+
+function CFF_SizeRec()
+{
+    this.face = null;
+    this.generic = null;
+    this.metrics = new FT_Size_Metrics();
+    this.internal = null;
+    
+    this.strike_index = 0;    /* 0xFFFFFFFF to indicate invalid */
+}
+
+function CFF_GlyphSlotRec()
+{
+    this.root = new FT_GlyphSlot();
+
+    this.hint = 0;
+    this.scaled = 0;
+
+    this.x_scale = 0;
+    this.y_scale = 0;
+}
+
+function CFF_InternalRec()
+{
+    this.topfont = null;
+    this.subfonts = new Array(FT_Common.CFF_MAX_CID_FONTS);
+}
+
+function CFF_Transform()
+{
+    this.xx = 0;
+    this.xy = 0;
+    this.yx = 0;
+    this.yy = 0;
+
+    this.ox = 0;
+    this.oy = 0;
+}
+
+function cff_size_get_globals_funcs(size)
+{
+    var face = size.face;
+    var font = face.extra.data;
+    var pshinter = font.pshinter;
+
+    var module = face.driver.library.FT_Get_Module("pshinter");
+    return (module != null && pshinter != null && pshinter.get_globals_funcs != null) ? pshinter.get_globals_funcs(module) : null;
+}
+
+function cff_size_done(cffsize)
+{
+    var internal = cffsize.internal;
+    if (internal != null)
+    {
+        var funcs = cff_size_get_globals_funcs(size);
+        if (funcs != null)
+        {
+            funcs.destroy(internal.topfont);
+
+            for (var i = font.num_subfonts; i > 0; i--)
+                funcs.destroy(internal.subfonts[i - 1]);
+        }
+        /* `internal' is freed by destroy_size (in ftobjs.c) */
+    }
+}
+
+function cff_make_private_dict(subfont, priv)
+{
+    var cpriv = subfont.private_dict;
+    var n = 0;
+    priv.clear();
+
+    var count = priv.num_blue_values = cpriv.num_blue_values;
+    for (n = 0; n < count; n++)
+        priv.blue_values[n] = cpriv.blue_values[n];
+
+    count = priv.num_other_blues = cpriv.num_other_blues;
+    for (n = 0; n < count; n++)
+        priv.other_blues[n] = cpriv.other_blues[n];
+
+    count = priv.num_family_blues = cpriv.num_family_blues;
+    for (n = 0; n < count; n++)
+        priv.family_blues[n] = cpriv.family_blues[n];
+
+    count = priv.num_family_other_blues = cpriv.num_family_other_blues;
+    for (n = 0; n < count; n++)
+        priv.family_other_blues[n] = cpriv.family_other_blues[n];
+
+    priv.blue_scale = cpriv.blue_scale;
+    priv.blue_shift = cpriv.blue_shift;
+    priv.blue_fuzz  = cpriv.blue_fuzz;
+
+    priv.standard_width[0]  = cpriv.standard_width;
+    priv.standard_height[0] = cpriv.standard_height;
+
+    count = priv.num_snap_widths = cpriv.num_snap_widths;
+    for (n = 0; n < count; n++)
+        priv.snap_widths[n] = cpriv.snap_widths[n];
+
+    count = priv.num_snap_heights = cpriv.num_snap_heights;
+    for (n = 0; n < count; n++)
+        priv.snap_heights[n] = cpriv.snap_heights[n];
+
+    priv.force_bold     = cpriv.force_bold;
+    priv.language_group = cpriv.language_group;
+    priv.lenIV          = cpriv.lenIV;
+}
+
+function cff_size_init()
+{
+    var size = new CFF_SizeRec();
+    var funcs = null;//cff_size_get_globals_funcs(size);
+
+    if (funcs != null)
+    {
+        // TODO: global funcs...
+    }
+
+    FT_Error = 0;
+    size.strike_index = 0xFFFFFFFF;
+    return size;
+}
+
+function cff_size_select(size, strike_index)
+{
+    size.strike_index = strike_index;
+    FT_Select_Metrics(size.face, strike_index);
+
+    var funcs = cff_size_get_globals_funcs(size);
+
+    if (funcs != null)
+    {
+        // TODO: global funcs...
+    }
+
+    return 0;
+}
+
+function cff_size_request(size, req)
+{
+    var face = size.face;
+    if (0 != (face.face_flags & FT_Common.FT_FACE_FLAG_FIXED_SIZES))
+    {
+        var sfnt = face.sfnt;
+        
+        var strike_index = sfnt.set_sbit_strike(face, req);
+        if (FT_Error != 0)
+            size.strike_index = 0xFFFFFFFF;
+        else
+            return cff_size_select(size, strike_index);
+    }
+
+    FT_Request_Metrics(size.face, req);
+
+    var funcs = cff_size_get_globals_funcs(size);
+    if (funcs != null)
+    {
+        // TODO: global funcs...
+    }
+    return 0;
+}
+
+function cff_slot_done(slot)
+{
+    slot.internal.glyph_hints = null;
+}
+
+function cff_slot_init(slot)
+{
+    var face     = slot.face;
+    var font     = face.extra.data;
+    var pshinter = font.pshinter;
+
+    if (pshinter != null)
+    {
+        var module = face.driver.library.FT_Get_Module("pshinter");
+        if (module != null)
+        {
+            slot.internal.glyph_hints = pshinter.get_t2_funcs(module);
+        }
+    }
+    return 0;
+}
+
+function cff_strcpy(memory, source)
+{
+    var result = source;
+    return result;
+}
+
+function remove_subset_prefix(name)
+{
+    var idx = 0;
+    var length = name.length + 1;
+    var continue_search = 1;
+
+    while (continue_search)
+    {
+        if (length >= 7 && name.charCodeAt(6) == FT_Common.SYMBOL_CONST_MATH_PLUS)
+        {
+            for (idx = 0; idx < 6; idx++)
+            {
+                /* ASCII uppercase letters */
+                var c = name.charCodeAt(idx);
+                if (!(FT_Common.SYMBOL_CONST_A <= c && c <= FT_Common.SYMBOL_CONST_Z))
+                    continue_search = 0;
+            }
+
+            if (continue_search)
+            {
+                name = name.substring(7);
+                length -= 7;
+            }
+        }
+        else
+            continue_search = 0;
+    }
+
+    return name;
+}
+
+function remove_style(family_name, style_name)
+{
+    var family_name_length = family_name.length;
+    var style_name_length  = style_name.length;
+
+    if (family_name_length > style_name_length)
+    {
+        var idx = 0;
+        for (idx = 1; idx <= style_name_length; idx++)
+        {
+            if (family_name.charCodeAt(family_name_length - idx) != style_name.charCodeAt(style_name_length - idx))
+                break;
+        }
+
+        if (idx > style_name_length)
+        {
+            /* family_name ends with style_name; remove it */
+            idx = family_name_length - style_name_length - 1;
+
+            /* also remove special characters     */
+            /* between real family name and style */
+            while (idx > 0)
+            {
+                var c = family_name.charCodeAt(idx);
+                if (c == FT_Common.SYMBOL_CONST_MATH_MINUS || c == FT_Common.SYMBOL_CONST_SPACE || c == FT_Common.SYMBOL_CONST__ || c == FT_Common.SYMBOL_CONST_MATH_PLUS)
+                    break;
+                
+                --idx;
+            }
+
+            if (idx > 0)
+                family_name = family_name.substring(0, idx);
+        }
+    }
+
+    return family_name;
+}
+
+function cff_face_init(stream, face, face_index, num_params, params)
+{
+    var pure_cff = 1;
+    var sfnt_format = 0;
+    var flags = 0;
+    var library = face.driver.library;
+
+    var sfnt = library.FT_Get_Module_Interface("sfnt");
+    if (sfnt == null)
+        return FT_Common.FT_Err_Unknown_File_Format;
+
+    var psnames = FT_FACE_FIND_GLOBAL_SERVICE(face, FT_SERVICE_ID_POSTSCRIPT_CMAPS);
+    var pshinter = library.FT_Get_Module_Interface("pshinter");
+
+    /* create input stream from resource */
+    var error = stream.Seek(0);
+    if (error != 0)
+        return error;
+
+    /* check whether we have a valid OpenType file */
+    error = sfnt.init_face(stream, face, face_index, num_params, params);
+    if (error == 0)
+    {
+        if (face.format_tag != FT_Common.TTAG_OTTO)
+            return FT_Common.FT_Err_Unknown_File_Format;
+
+        /* if we are performing a simple font format check, exit immediately */
+        if (face_index < 0)
+            return 0;
+
+        /* UNDOCUMENTED!  A CFF in an SFNT can have only a single font. */
+        if (face_index > 0)
+            return FT_Common.FT_Err_Invalid_Argument;
+
+        sfnt_format = 1;
+
+        /* now, the font can be either an OpenType/CFF font, or an SVG CEF */
+        /* font; in the latter case it doesn't have a `head' table         */
+        face.goto_table(face, FT_Common.TTAG_head, stream);
+        error = FT_Error;
+        if (error == 0)
+        {
+            pure_cff = 0;
+
+            /* load font directory */
+            error = sfnt.load_face(stream, face, 0);
+            if (error != 0)
+                return error;
+        }
+        else
+        {
+            /* load the `cmap' table explicitly */
+            error = sfnt.load_cmap(face, stream);
+            if (error != 0)
+                return error;
+
+            /* XXX: we don't load the GPOS table, as OpenType Layout     */
+            /* support will be added later to a layout library on top of */
+            /* FreeType 2                                                */
+        }
+
+        /* now load the CFF part of the file */
+        face.goto_table(face, FT_Common.TTAG_CFF, stream);
+        error = FT_Error;
+        if (error != 0)
+            return error;
+    }
+    else
+    {
+        /* rewind to start of file; we are going to load a pure-CFF font */
+        error = stream.Seek(0);
+        if (error != 0)
+            return error;
+    }
+
+    /* now load and parse the CFF table in the file */
+    var cff = new CFF_FontRec();
+    face.extra.data = cff;
+    
+    error = cff_font_load(library, stream, face_index, cff, pure_cff);
+    if (error != 0)
+        return error;
+
+    cff.pshinter = pshinter;
+    cff.psnames  = psnames;
+
+    face.face_index = face_index;
+
+    /* Complement the root flags with some interesting information. */
+    /* Note that this is only necessary for pure CFF and CEF fonts; */
+    /* SFNT based fonts use the `name' table instead.               */
+    face.num_glyphs = cff.num_glyphs;
+    var dict = cff.top_font.font_dict;
+
+    /* we need the `PSNames' module for CFF and CEF formats */
+    /* which aren't CID-keyed                               */
+    if (dict.cid_registry == 0xFFFF && psnames == null)
+        return FT_Common.FT_Err_Unknown_File_Format;
+
+    if (dict.has_font_matrix == 0)
+        dict.units_per_em = pure_cff ? 1000 : face.units_per_EM;
+
+    /* Normalize the font matrix so that `matrix->xx' is 1; the */
+    /* scaling is done with `units_per_em' then (at this point, */
+    /* it already contains the scaling factor, but without      */
+    /* normalization of the matrix).                            */
+    /*                                                          */
+    /* Note that the offsets must be expressed in integer font  */
+    /* units.                                                   */
+    var matrix = dict.font_matrix;
+    var offset = dict.font_offset;
+    var temp = Math.abs(matrix.yy);
+
+    if (temp != 0x10000)
+    {
+        dict.units_per_em = FT_DivFix(dict.units_per_em, temp);
+
+        matrix.xx = FT_DivFix(matrix.xx, temp);
+        matrix.yx = FT_DivFix(matrix.yx, temp);
+        matrix.xy = FT_DivFix(matrix.xy, temp);
+        matrix.yy = FT_DivFix(matrix.yy, temp);
+        offset.x  = FT_DivFix(offset.x,  temp);
+        offset.y  = FT_DivFix(offset.y,  temp);
+    }
+
+    offset.x >>= 16;
+    offset.y >>= 16;
+
+    for (var i = cff.num_subfonts; i > 0; i--)
+    {
+        var sub = cff.subfonts[i - 1].font_dict;
+        var top = cff.top_font.font_dict;
+
+        if (sub.has_font_matrix == 1)
+        {
+            var scaling = 0;
+            /* if we have a top-level matrix, */
+            /* concatenate the subfont matrix */
+
+            if (top.has_font_matrix == 1)
+            {
+                if (top.units_per_em > 1 && sub.units_per_em > 1)
+                    scaling = Math.min(top.units_per_em, sub.units_per_em);
+                else
+                    scaling = 1;
+
+                FT_Matrix_Multiply_Scaled(top.font_matrix, sub.font_matrix, scaling);
+                FT_Vector_Transform_Scaled(sub.font_offset, top.font_matrix, scaling);
+
+                sub.units_per_em = FT_MulDiv(sub.units_per_em, top.units_per_em, scaling);
+            }
+        }
+        else
+        {
+            sub.font_matrix = top.font_matrix;
+            sub.font_offset = top.font_offset;
+
+            sub.units_per_em = top.units_per_em;
+        }
+
+        matrix = sub.font_matrix;
+        offset = sub.font_offset;
+        temp = Math.abs(matrix.yy);
+
+        if (temp != 0x10000)
+        {
+            sub.units_per_em = FT_DivFix(sub.units_per_em, temp);
+
+            matrix.xx = FT_DivFix(matrix.xx, temp);
+            matrix.yx = FT_DivFix(matrix.yx, temp);
+            matrix.xy = FT_DivFix(matrix.xy, temp);
+            matrix.yy = FT_DivFix(matrix.yy, temp);
+            offset.x  = FT_DivFix(offset.x,  temp);
+            offset.y  = FT_DivFix(offset.y,  temp);
+        }
+
+        offset.x >>= 16;
+        offset.y >>= 16;
+    }
+
+    if (pure_cff == 1)
+    {
+        var style_name = null;
+
+        /* set up num_faces */
+        face.num_faces = cff.num_faces;
+
+        /* compute number of glyphs */
+        if (dict.cid_registry != 0xFFFF)
+            face.num_glyphs = cff.charset.max_cid + 1;
+        else
+            face.num_glyphs = cff.charstrings_index.count;
+
+        /* set global bbox, as well as EM size */
+        face.bbox.xMin = dict.font_bbox.xMin >> 16;
+        face.bbox.yMin = dict.font_bbox.yMin >> 16;
+        /* no `U' suffix here to 0xFFFF! */
+        face.bbox.xMax = (dict.font_bbox.xMax + 0xFFFF) >> 16;
+        face.bbox.yMax = (dict.font_bbox.yMax + 0xFFFF) >> 16;
+
+        face.units_per_EM = dict.units_per_em & 0xFFFF;
+
+        face.ascender  = face.bbox.yMax;
+        face.descender = face.bbox.yMin;
+
+        face.height = ((face.units_per_EM * 12) / 10);
+        if (face.height < (face.ascender - face.descender))
+            face.height = (face.ascender - face.descender);
+
+        face.underline_position = (dict.underline_position >> 16);
+        face.underline_thickness = (dict.underline_thickness >> 16);
+
+        /* retrieve font family & style name */
+        face.family_name = cff_index_get_name(cff, face_index);
+        if (face.family_name != null)
+        {
+            var full = cff_index_get_sid_string(cff, dict.full_name);
+            var fullp = 0;
+            var family = face.family_name;
+            var family_name = null;
+
+            face.family_name = remove_subset_prefix(face.family_name);
+
+            if (dict.family_name != 0)
+            {
+                family_name = cff_index_get_sid_string(cff, dict.family_name);
+                if (family_name != null)
+                    family = family_name;
+            }
+
+            var familyp = 0;
+            var full_len = (full == null) ? 0 : full.length;
+            var family_len = family.length;
+
+            /* We try to extract the style name from the full name.   */
+            /* We need to ignore spaces and dashes during the search. */
+            if (full != null && family != null)
+            {
+                while (fullp < full_len)
+                {
+                    var _c1 = full.charCodeAt(fullp);
+                    var _c2 = 0;
+                    if (familyp < family_len)
+                        _c2 = family.charCodeAt(familyp);
+
+                    /* skip common characters at the start of both strings */
+                    if (_c1 == _c2)
+                    {
+                        familyp++;
+                        fullp++;
+                        continue;
+                    }
+
+                    if (_c1 == FT_Common.SYMBOL_CONST_SPACE || _c1 == FT_Common.SYMBOL_CONST_MATH_MINUS)
+                    {
+                        fullp++;
+                        continue;
+                    }
+
+                    if (_c2 == FT_Common.SYMBOL_CONST_SPACE || _c2 == FT_Common.SYMBOL_CONST_MATH_MINUS)
+                    {
+                        familyp++;
+                        continue;
+                    }
+
+                    if (familyp >= family_len && fullp < full_len)
+                    {
+                        /* The full name begins with the same characters as the  */
+                        /* family name, with spaces and dashes removed.  In this */
+                        /* case, the remaining string in `fullp' will be used as */
+                        /* the style name.                                       */
+                        style_name = full.substring(fullp);
+
+                        /* remove the style part from the family name (if present) */
+                        face.family_name = remove_style(face.family_name, style_name);
+                    }
+                    break;
+                }
+            }
+        }
+        else
+        {
+            var cid_font_name = cff_index_get_sid_string(cff, dict.cid_font_name);
+            /* do we have a `/FontName' for a CID-keyed font? */
+            if (cid_font_name != null)
+                face.family_name = cff_strcpy(memory, cid_font_name);
+        }
+
+        if (style_name != null)
+            face.style_name = style_name;
+        else /* assume "Regular" style if we don't know better */
+            face.style_name = "Regular";
+
+        /*******************************************************************/
+        /*                                                                 */
+        /* Compute face flags.                                             */
+        /*                                                                 */
+        flags = (FT_Common.FT_FACE_FLAG_SCALABLE | FT_Common.FT_FACE_FLAG_HORIZONTAL | FT_Common.FT_FACE_FLAG_HINTER);
+
+        if (sfnt_format != 0)
+            flags |= FT_Common.FT_FACE_FLAG_SFNT;
+
+        /* fixed width font? */
+        if (dict.is_fixed_pitch != 0)
+            flags |= FT_Common.FT_FACE_FLAG_FIXED_WIDTH;
+
+        /* XXX: WE DO NOT SUPPORT KERNING METRICS IN THE GPOS TABLE FOR NOW */
+
+        face.face_flags = flags;
+        /*******************************************************************/
+        /*                                                                 */
+        /* Compute style flags.                                            */
+        /*                                                                 */
+        flags = 0;
+
+        if (dict.italic_angle != 0)
+            flags |= FT_Common.FT_STYLE_FLAG_ITALIC;
+
+        var weight = cff_index_get_sid_string(cff, dict.weight);
+        if (weight != null)
+            if (weight == "Bold" || weight == "Black")
+                flags |= FT_Common.FT_STYLE_FLAG_BOLD;
+
+        /* double check */
+        if (0 == (flags & FT_Common.FT_STYLE_FLAG_BOLD) && face.style_name != null)
+            if (!_strncmp(face.style_name, "Bold", 4) || !_strncmp(face.style_name, "Black", 5))
+                flags |= FT_Common.FT_STYLE_FLAG_BOLD;
+
+        face.style_flags = flags;
+    }
+
+
+    //#ifndef FT_CONFIG_OPTION_NO_GLYPH_NAMES
+    /* CID-keyed CFF fonts don't have glyph names -- the SFNT loader */
+    /* has unset this flag because of the 3.0 `post' table.          */
+    if (dict.cid_registry == 0xFFFF)
+        face.face_flags |= FT_Common.FT_FACE_FLAG_GLYPH_NAMES;
+    //#endif
+
+    if (dict.cid_registry != 0xFFFF && pure_cff == 1)
+        face.face_flags |= FT_Common.FT_FACE_FLAG_CID_KEYED;
+
+
+    /*******************************************************************/
+    /*                                                                 */
+    /* Compute char maps.                                              */
+    /*                                                                 */
+
+    /* Try to synthesize a Unicode charmap if there is none available */
+    /* already.  If an OpenType font contains a Unicode "cmap", we    */
+    /* will use it, whatever be in the CFF part of the file.          */
+    var cmaprec = new FT_CharMapRec();
+    var cmap = null;
+    var nn = 0;
+    var encoding = cff.encoding;
+
+    var is_skip_unicode = 0;
+    for (nn = 0; nn < face.num_charmaps; nn++)
+    {
+        cmap = face.charmaps[nn];
+
+        /* Windows Unicode? */
+        if (cmap.platform_id == FT_Common.TT_PLATFORM_MICROSOFT && cmap.encoding_id == FT_Common.TT_MS_ID_UNICODE_CS)
+            is_skip_unicode = 1;
+
+        /* Apple Unicode platform id? */
+        if (cmap.platform_id == FT_Common.TT_PLATFORM_APPLE_UNICODE)
+            is_skip_unicode = 1; /* Apple Unicode */
+    }
+
+    if (0 == is_skip_unicode)
+    {
+        /* since CID-keyed fonts don't contain glyph names, we can't */
+        /* construct a cmap                                          */
+        if (pure_cff == 1 && cff.top_font.font_dict.cid_registry != 0xFFFF)
+            return error;
+
+        //#ifdef FT_MAX_CHARMAP_CACHEABLE
+        if (nn + 1 > FT_Common.FT_MAX_CHARMAP_CACHEABLE)
+            return error;
+        //#endif
+
+        /* we didn't find a Unicode charmap -- synthesize one */
+        cmaprec.face        = face;
+        cmaprec.platform_id = FT_Common.TT_PLATFORM_MICROSOFT;
+        cmaprec.encoding_id = FT_Common.TT_MS_ID_UNICODE_CS;
+        cmaprec.encoding    = FT_Common.FT_ENCODING_UNICODE;
+
+        nn = face.num_charmaps;
+
+        FT_CMap_New(FT_CFF_CMAP_UNICODE_CLASS_REC_GET, null, cmaprec);
+        error = FT_Error;
+        if (error && FT_Common.FT_Err_No_Unicode_Glyph_Name != error)
+            return error;
+        error = 0;
+
+        /* if no Unicode charmap was previously selected, select this one */
+        if (face.charmap == null && nn != face.num_charmaps)
+            face.charmap = face.charmaps[nn];
+    }
+
+    //#ifdef FT_MAX_CHARMAP_CACHEABLE
+    if (nn > FT_Common.FT_MAX_CHARMAP_CACHEABLE)
+        return error;
+    //#endif
+
+    if (encoding.count > 0)
+    {
+        var clazz = null;
+
+        cmaprec.face = face;
+        cmaprec.platform_id = FT_Common.TT_PLATFORM_ADOBE;  /* Adobe platform id */
+
+        if (encoding.offset == 0)
+        {
+            cmaprec.encoding_id = FT_Common.TT_ADOBE_ID_STANDARD;
+            cmaprec.encoding    = FT_Common.FT_ENCODING_ADOBE_STANDARD;
+            clazz               = FT_CFF_CMAP_ENCODING_CLASS_REC_GET;
+        }
+        else if (encoding.offset == 1)
+        {
+            cmaprec.encoding_id = FT_Common.TT_ADOBE_ID_EXPERT;
+            cmaprec.encoding    = FT_Common.FT_ENCODING_ADOBE_EXPERT;
+            clazz               = FT_CFF_CMAP_ENCODING_CLASS_REC_GET;
+        }
+        else
+        {
+            cmaprec.encoding_id = FT_Common.TT_ADOBE_ID_CUSTOM;
+            cmaprec.encoding    = FT_Common.FT_ENCODING_ADOBE_CUSTOM;
+            clazz               = FT_CFF_CMAP_ENCODING_CLASS_REC_GET;
+        }
+
+        FT_CMap_New(clazz, null, cmaprec);
+        error = FT_Error;
+    }
+
+    return error;
+}
+
+function cff_face_done(face)
+{
+    if (face == null)
+        return;
+
+    var sfnt = face.sfnt;
+
+    if (sfnt != null)
+        sfnt.done_face(face);
+
+    var cff = face.extra.data;
+    if (cff != null)
+    {
+        cff_font_done(cff);
+        face.extra.data = null;
+    }
+}
+
+function cff_driver_init(module)
+{
+    return 0;
+}
+
+function cff_driver_done(module)
+{
+}
+
+/******************************************************************************/
+// cffgload
+/******************************************************************************/
+
+var cff_argument_counts =
+[
+    0,  /* unknown */
+
+    2 | FT_Common.CFF_COUNT_CHECK_WIDTH | FT_Common.CFF_COUNT_EXACT, /* rmoveto */
+    1 | FT_Common.CFF_COUNT_CHECK_WIDTH | FT_Common.CFF_COUNT_EXACT,
+    1 | FT_Common.CFF_COUNT_CHECK_WIDTH | FT_Common.CFF_COUNT_EXACT,
+
+    0 | FT_Common.CFF_COUNT_CLEAR_STACK, /* rlineto */
+    0 | FT_Common.CFF_COUNT_CLEAR_STACK,
+    0 | FT_Common.CFF_COUNT_CLEAR_STACK,
+
+    0 | FT_Common.CFF_COUNT_CLEAR_STACK, /* rrcurveto */
+    0 | FT_Common.CFF_COUNT_CLEAR_STACK,
+    0 | FT_Common.CFF_COUNT_CLEAR_STACK,
+    0 | FT_Common.CFF_COUNT_CLEAR_STACK,
+    0 | FT_Common.CFF_COUNT_CLEAR_STACK,
+    0 | FT_Common.CFF_COUNT_CLEAR_STACK,
+    0 | FT_Common.CFF_COUNT_CLEAR_STACK,
+
+    13, /* flex */
+    7,
+    9,
+    11,
+
+    0 | FT_Common.CFF_COUNT_CHECK_WIDTH, /* endchar */
+
+    2 | FT_Common.CFF_COUNT_CHECK_WIDTH, /* hstem */
+    2 | FT_Common.CFF_COUNT_CHECK_WIDTH,
+    2 | FT_Common.CFF_COUNT_CHECK_WIDTH,
+    2 | FT_Common.CFF_COUNT_CHECK_WIDTH,
+
+    0 | FT_Common.CFF_COUNT_CHECK_WIDTH, /* hintmask */
+    0 | FT_Common.CFF_COUNT_CHECK_WIDTH, /* cntrmask */
+    0, /* dotsection */
+
+    1, /* abs */
+    2,
+    2,
+    2,
+    1,
+    0,
+    2,
+    1,
+
+    1, /* blend */
+
+    1, /* drop */
+    2,
+    1,
+    2,
+    1,
+
+    2, /* put */
+    1,
+    4,
+    3,
+
+    2, /* and */
+    2,
+    1,
+    2,
+    4,
+
+    1, /* callsubr */
+    1,
+    0,
+
+    2, /* hsbw */
+    0,
+    0,
+    0,
+    5, /* seac */
+    4, /* sbw */
+    2  /* setcurrentpoint */
+];
+
+function CFF_Builder()
+{
+    this.memory = null;
+    this.face = null;
+    this.glyph = null;
+    this.loader = null;
+    this.base = null;
+    this.current = null;
+
+    this.pos_x = 0;
+    this.pos_y = 0;
+
+    this.left_bearing = new FT_Vector();
+    this.advance = new FT_Vector();
+
+    this.bbox = new FT_BBox();
+    this.path_begun = 0;
+    this.load_points = 0;
+    this.no_recurse = 0;
+
+    this.metrics_only = 0;
+
+    this.hints_funcs = null;
+    this.hints_globals = null;
+
+    this.clear = function()
+    {
+        this.memory = null;
+        this.face = null;
+        this.glyph = null;
+        this.loader = null;
+        this.base = null;
+        this.current = null;
+
+        this.pos_x = 0;
+        this.pos_y = 0;
+
+        this.left_bearing.x = 0;
+        this.left_bearing.y = 0;
+
+        this.advance.x = 0;
+        this.advance.y = 0;
+
+        this.bbox.xMin = 0;
+        this.bbox.yMin = 0;
+        this.bbox.xMax = 0;
+        this.bbox.yMax = 0;
+
+        this.path_begun = 0;
+        this.load_points = 0;
+        this.no_recurse = 0;
+
+        this.metrics_only = 0;
+
+        this.hints_funcs = null;
+        this.hints_globals = null;
+    }
+}
+
+function CFF_Decoder_Zone()
+{
+    this.base = null;
+    this.limit = 0;
+    this.cursor = 0;
+}
+
+function CFF_Decoder()
+{
+    this.builder = new CFF_Builder();
+    this.cff = null;
+
+    this.stack = CreateIntArray(FT_Common.CFF_MAX_OPERANDS + 1);
+    this.top = 0;
+
+    this.zones = new Array(FT_Common.CFF_MAX_SUBRS_CALLS + 1);
+    for (var i = 0; i < (FT_Common.CFF_MAX_SUBRS_CALLS + 1); i++)
+        this.zones[i] = new CFF_Decoder_Zone();
+
+    this.zone = 0;
+
+    this.flex_state = 0;
+    this.num_flex_vectors = 0;
+
+    this.flex_vectors = new Array(7);
+    for (var i = 0; i < 7; i++)
+        this.flex_vectors[i] = new FT_Vector();
+
+    this.glyph_width = 0;
+    this.nominal_width = 0;
+
+    this.read_width = 0;
+    this.width_only = 0;
+    this.num_hints = 0;
+    this.buildchar = CreateIntArray(FT_Common.CFF_MAX_TRANS_ELEMENTS);
+
+    this.num_locals = 0;
+    this.num_globals = 0;
+
+    this.locals_bias = 0;
+    this.globals_bias = 0;
+
+    this.locals = null;
+    this.globals = null;
+
+    this.glyph_names = null;   /* for pure CFF fonts only  */
+    this.num_glyphs = 0;    /* number of glyphs in font */
+
+    this.hint_mode = 0;
+
+    this.seac = 0;
+
+    this.clear = function()
+    {
+        this.builder.clear();
+        this.cff = null;
+
+        this.stack = CreateIntArray(FT_Common.CFF_MAX_OPERANDS + 1);
+        for (var i = 0; i < (FT_Common.CFF_MAX_OPERANDS + 1); i++)
+            this.stack[i] = 0;
+        this.top = 0;
+
+        for (var i = 0; i < (FT_Common.CFF_MAX_SUBRS_CALLS + 1); i++)
+        {
+            var p = this.zones[i];
+            p.base = null;
+            p.cursor = 0;
+            p.limit = 0;
+        }
+
+        this.zone = 0;
+
+        this.flex_state = 0;
+        this.num_flex_vectors = 0;
+
+        for (var i = 0; i < 7; i++)
+        {
+            this.flex_vectors[i].x = 0;
+            this.flex_vectors[i].y = 0;
+        }
+
+        this.glyph_width = 0;
+        this.nominal_width = 0;
+
+        this.read_width = 0;
+        this.width_only = 0;
+        this.num_hints = 0;
+
+        for (var i = 0; i < FT_Common.CFF_MAX_TRANS_ELEMENTS; i++)
+            this.buildchar[i] = 0;
+
+        this.num_locals = 0;
+        this.num_globals = 0;
+
+        this.locals_bias = 0;
+        this.globals_bias = 0;
+
+        this.locals = null;
+        this.globals = null;
+
+        this.glyph_names = null;   /* for pure CFF fonts only  */
+        this.num_glyphs = 0;    /* number of glyphs in font */
+
+        this.hint_mode = 0;
+
+        this.seac = 0;
+    }
+}
+
+function cff_builder_init(builder, face, size, glyph, hinting)
+{
+    builder.path_begun  = 0;
+    builder.path_begun  = 0;
+    builder.load_points = 1;
+
+    builder.face   = face;
+    builder.glyph  = glyph;
+    builder.memory = face.memory;
+
+    if (glyph != null)
+    {
+        var loader = glyph.internal.loader;
+
+        builder.loader = loader;
+        builder.base = loader.base.outline;
+        builder.current = loader.current.outline;
+        FT_GlyphLoader_Rewind(loader);
+
+        builder.hints_globals = null;
+        builder.hints_funcs = null;
+
+        if (hinting && size != null)
+        {
+            var internal = size.internal;
+
+            builder.hints_globals = internal.topfont;
+            builder.hints_funcs = glyph.internal.glyph_hints;
+        }
+    }
+
+    builder.pos_x = 0;
+    builder.pos_y = 0;
+
+    builder.left_bearing.x = 0;
+    builder.left_bearing.y = 0;
+    builder.advance.x      = 0;
+    builder.advance.y      = 0;
+}
+
+function cff_builder_done(builder)
+{
+    var glyph = builder.glyph;
+    if (glyph != null)
+        EquatingOutline(glyph.outline, builder.base);
+}
+
+function cff_compute_bias(in_charstring_type, num_subrs)
+{
+    if (in_charstring_type == 1)
+        return 0;
+    else if (num_subrs < 1240)
+        return 107;
+    else if (num_subrs < 33900)
+        return 1131;
+
+    return 32768;
+}
+
+function cff_decoder_init(decoder, face, size, slot, hinting, hint_mode)
+{
+    var cff = face.extra.data;
+    /* clear everything */
+    decoder.clear();
+
+    /* initialize builder */
+    cff_builder_init(decoder.builder, face, size, slot, hinting);
+
+    /* initialize Type2 decoder */
+    decoder.cff = cff;
+    decoder.num_globals = cff.global_subrs_index.count;
+    decoder.globals = cff.global_subrs;
+    decoder.globals_bias = cff_compute_bias(cff.top_font.font_dict.charstring_type, decoder.num_globals);
+
+    decoder.hint_mode    = hint_mode;
+}
+
+function cff_decoder_prepare(decoder, size, glyph_index)
+{
+    var builder = decoder.builder;
+    var cff = builder.face.extra.data;
+    var sub = cff.top_font;
+
+    /* manage CID fonts */
+    if (cff.num_subfonts != 0)
+    {
+        var fd_index = cff_fd_select_get(cff.fd_select, glyph_index);
+
+        if (fd_index >= cff.num_subfonts)
+            return FT_Common.FT_Err_Invalid_File_Format;
+
+        sub = cff.subfonts[fd_index];
+
+        if (builder.hints_funcs != null && size != null)
+        {
+            var internal = size.internal;
+
+            /* for CFFs without subfonts, this value has already been set */
+            builder.hints_globals = internal.subfonts[fd_index];
+        }
+    }
+
+    decoder.num_locals = sub.local_subrs_index.count;
+    decoder.locals = sub.local_subrs;
+    decoder.locals_bias = cff_compute_bias(decoder.cff.top_font.font_dict.charstring_type, decoder.num_locals);
+
+    decoder.glyph_width   = sub.private_dict.default_width;
+    decoder.nominal_width = sub.private_dict.nominal_width;
+
+    return 0;
+}
+
+function _cff_check_points(builder, count)
+{
+    return FT_GLYPHLOADER_CHECK_POINTS(builder.loader, count, 0);
+}
+
+function cff_builder_add_point(builder, x, y, flag)
+{
+    var base = builder.base;
+    var outline = builder.current;
+
+    if (builder.load_points = 1)
+    {
+        var point = base.points[outline.points + outline.n_points];
+        var control = base.tags[outline.tags + outline.n_points];
+
+        point.x = x >> 16;
+        point.y = y >> 16;
+        base.tags[outline.tags + outline.n_points] = ((flag != 0) ? FT_Common.FT_CURVE_TAG_ON : FT_Common.FT_CURVE_TAG_CUBIC);
+    }
+
+    outline.n_points++;
+}
+
+function cff_builder_add_point1(builder, x, y)
+{
+    var error = _cff_check_points(builder, 1);
+    if (error == 0)
+        cff_builder_add_point(builder, x, y, 1);
+
+    return error;
+}
+
+function cff_builder_add_contour(builder)
+{
+    if (builder.load_points == 0)
+    {
+        builder.current.n_contours++;
+        return 0;
+    }
+
+    var base = builder.base;
+    var outline = builder.current;
+    var error = FT_GLYPHLOADER_CHECK_POINTS(builder.loader, 0, 1);
+    if (error == 0)
+    {
+        if (outline.n_contours > 0)
+            base.contours[outline.contours + outline.n_contours - 1] = (outline.n_points - 1);
+
+        outline.n_contours++;
+    }
+
+    return error;
+}
+
+function cff_builder_start_point(builder, x, y)
+{
+    var error = 0;
+    if (builder.path_begun == 0)
+    {
+        builder.path_begun = 1;
+        error = cff_builder_add_contour(builder);
+        if (error == 0)
+            error = cff_builder_add_point1(builder, x, y);
+    }
+    return error;
+}
+
+function cff_builder_close_contour(builder)
+{
+    var base = builder.base;
+    var outline = builder.current;
+
+    if (outline == null)
+        return;
+
+    var first = (outline.n_contours <= 1) ? 0 : base.contours[outline.contours + outline.n_contours - 2] + 1;
+
+    /* We must not include the last point in the path if it */
+    /* is located on the first point.                       */
+    if (outline.n_points > 1)
+    {
+        var p1 = base.points[outline.points + first];
+        var p2 = base.points[outline.points + outline.n_points - 1];
+        var control = base.tags[outline.tags + outline.n_points - 1];
+
+        /* `delete' last point only if it coincides with the first    */
+        /* point and if it is not a control point (which can happen). */
+        if (p1.x == p2.x && p1.y == p2.y)
+            if (control == FT_Common.FT_CURVE_TAG_ON)
+                outline.n_points--;
+    }
+
+    if (outline.n_contours > 0)
+    {
+        /* Don't add contours only consisting of one point, i.e., */
+        /* check whether begin point and last point are the same. */
+        if (first == outline.n_points - 1)
+        {
+            outline.n_contours--;
+            outline.n_points--;
+        }
+        else
+            base.contours[outline.contours + outline.n_contours - 1] = (outline.n_points - 1);
+    }
+}
+
+function cff_lookup_glyph_by_stdcharcode(cff, charcode)
+{
+    /* CID-keyed fonts don't have glyph names */
+    if (null == cff.charset.sids)
+        return -1;
+
+    /* check range of standard char code */
+    if (charcode < 0 || charcode > 255)
+        return -1;
+
+    /* Get code to SID mapping from `cff_standard_encoding'. */
+    var glyph_sid = cff_get_standard_encoding(charcode);
+
+    for (var n = 0; n < cff.num_glyphs; n++)
+    {
+        if (cff.charset.sids[n] == glyph_sid)
+            return n;
+    }
+
+    return -1;
+}
+
+function cff_get_glyph_data(face, glyph_index)
+{
+    var cff = face.extra.data;
+    return cff_index_access_element(cff.charstrings_index, glyph_index);
+}
+
+function cff_free_glyph_data(face, pointer, length)
+{
+    var cff = face.extra.data;
+    cff_index_forget_element(cff.charstrings_index, pointer);
+}
+
+function cff_operator_seac(decoder, asb, adx, ady, bchar, achar)
+{
+    var builder = decoder.builder;
+    var bchar_index, achar_index;
+    var face = builder.face;
+
+    if (decoder.seac != 0)
+        return FT_Common.FT_Err_Syntax_Error;
+
+    adx += decoder.builder.left_bearing.x;
+    ady += decoder.builder.left_bearing.y;
+
+    //#ifdef FT_CONFIG_OPTION_INCREMENTAL
+    /* Incremental fonts don't necessarily have valid charsets.        */
+    /* They use the character code, not the glyph index, in this case. */
+    if (face.internal.incremental_interface != null)
+    {
+        bchar_index = bchar;
+        achar_index = achar;
+    }
+    else //#endif /* FT_CONFIG_OPTION_INCREMENTAL */
+    {
+        var cff = face.extra.data;
+        bchar_index = cff_lookup_glyph_by_stdcharcode(cff, bchar);
+        achar_index = cff_lookup_glyph_by_stdcharcode(cff, achar);
+    }
+
+    if (bchar_index < 0 || achar_index < 0)
+        return FT_Common.FT_Err_Syntax_Error;
+
+    /* If we are trying to load a composite glyph, do not load the */
+    /* accent character and return the array of subglyphs.         */
+    if (builder.no_recurse != 0)
+    {
+        var glyph  = builder.glyph;
+        var loader = glyph.internal.loader;
+
+        /* reallocate subglyph array if necessary */
+        error = FT_GlyphLoader_CheckSubGlyphs(loader, 2);
+        if (error != 0)
+            return error;
+
+        var subg = loader.base.subglyphs[loader.current.subglyphs];
+
+        /* subglyph 0 = base character */
+        subg.index = bchar_index;
+        subg.flags = FT_Common.FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES | FT_Common.FT_SUBGLYPH_FLAG_USE_MY_METRICS;
+        subg.arg1  = 0;
+        subg.arg2  = 0;
+
+        subg = loader.base.subglyphs[loader.current.subglyphs + 1];
+
+        /* subglyph 1 = accent character */
+        subg.index = achar_index;
+        subg.flags = FT_Common.FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES;
+        subg.arg1 = (adx >> 16);
+        subg.arg2 = (ady >> 16);
+
+        /* set up remaining glyph fields */
+        glyph.num_subglyphs = 2;
+        glyph.subglyphs     = loader.base.subglyphs;
+        glyph.format = FT_Common.FT_GLYPH_FORMAT_COMPOSITE;
+
+        loader.current.num_subglyphs = 2;
+    }
+
+    FT_GlyphLoader_Prepare(builder.loader);
+
+    /* First load `bchar' in builder */
+    var ret = cff_get_glyph_data(face, bchar_index);
+    var error = ret.err;
+    var charstring = ret.bytes;
+    var charstring_len = ret.len;
+    if (error == 0)
+    {
+        /* the seac operator must not be nested */
+        decoder.seac = 1;
+        error = cff_decoder_parse_charstrings(decoder, charstring, charstring_len);
+        decoder.seac = 0;
+
+        cff_free_glyph_data(face, charstring, charstring_len);
+
+        if (error != 0)
+            return error;
+    }
+
+    /* Save the left bearing, advance and glyph width of the base */
+    /* character as they will be erased by the next load.         */
+
+    var left_bearing = dublicate_vector(builder.left_bearing);
+    var advance = dublicate_vector(builder.advance);
+    var glyph_width = decoder.glyph_width;
+
+    builder.left_bearing.x = 0;
+    builder.left_bearing.y = 0;
+
+    builder.pos_x = adx - asb;
+    builder.pos_y = ady;
+
+    /* Now load `achar' on top of the base outline. */
+    ret = cff_get_glyph_data(face, achar_index);
+    error = ret.err;
+    charstring = ret.bytes;
+    charstring_len = ret.len;
+    if (error == 0)
+    {
+        /* the seac operator must not be nested */
+        decoder.seac = 1;
+        error = cff_decoder_parse_charstrings(decoder, charstring, charstring_len);
+        decoder.seac = 0;
+
+        cff_free_glyph_data(face, charstring, charstring_len);
+
+        if (error != 0)
+            return error;
+    }
+
+    /* Restore the left side bearing, advance and glyph width */
+    /* of the base character.                                 */
+    builder.left_bearing.x = left_bearing.x;
+    builder.left_bearing.y = left_bearing.y;
+    builder.advance.x = advance.x;
+    builder.advance.y = advance.y;
+
+    decoder.glyph_width  = glyph_width;
+
+    builder.pos_x = 0;
+    builder.pos_y = 0;
+
+    return error;
+}
+
+function cff_decoder_parse_charstrings(decoder, charstring_base, charstring_len)
+{
+    var builder = decoder.builder;
+    var charstring_type = decoder.cff.top_font.font_dict.charstring_type;
+
+    /* set default width */
+    decoder.num_hints  = 0;
+    decoder.read_width = 1;
+
+    /* compute random seed from stack address of parameter */
+    var seed = parseInt(Math.random() * 0xFFFF);
+    if (seed == 0)
+        seed = 0x7384;
+
+    /* initialize the decoder */
+    decoder.top = 0;
+    decoder.zone = 0;
+
+    var zones = decoder.zones;
+    var zone = 0;
+
+    var tops = decoder.stack;
+    var stack = decoder.top;
+
+    var hinter = builder.hints_funcs;
+
+    builder.path_begun = 0;
+
+    zones[zone].base = dublicate_pointer(charstring_base);
+    var limit = zones[zone].limit = charstring_base.pos + charstring_len;
+    zones[zone].cursor = 0;
+    var ip = dublicate_pointer(charstring_base);
+
+    var error = 0;
+
+    var x = builder.pos_x;
+    var y = builder.pos_y;
+
+    /* begin hints recording session, if any */
+    if (hinter != null)
+        hinter.open(hinter.hints);
+
+    /* now execute loop */
+    while (ip.pos < limit)
+    {
+        var op = 0;
+        /********************************************************************/
+        /*                                                                  */
+        /* Decode operator or operand                                       */
+        /*                                                                  */
+        var v = ip.data[ip.pos];
+        ip.pos++;
+        if (v >= 32 || v == 28)
+        {
+            var shift = 16;
+            var val = 0;
+
+            /* this is an operand, push it on the stack */
+            if (v == 28)
+            {
+                if (ip.pos + 1 >= limit)
+                    return FT_Common.FT_Err_Invalid_File_Format;
+                val = ((ip.data[ip.pos] << 8) | ip.data[ip.pos + 1]);
+                if (val > FT_Common.m_s)
+                    val = val - FT_Common.a_s;
+                ip.pos += 2;
+            }
+            else if (v < 247)
+                val = v - 139;
+            else if (v < 251)
+            {
+                if (ip.pos >= limit)
+                    return FT_Common.FT_Err_Invalid_File_Format;
+                val = (v - 247) * 256 + ip.data[ip.pos] + 108;
+                ip.pos++;
+            }
+            else if (v < 255)
+            {
+                if (ip.pos >= limit)
+                    return FT_Common.FT_Err_Invalid_File_Format;
+                val = -(v - 251) * 256 - ip.data[ip.pos] - 108;
+                ip.pos++;
+            }
+            else
+            {
+                if (ip.pos + 3 >= limit)
+                    return FT_Common.FT_Err_Invalid_File_Format;
+                val = (ip.data[ip.pos] << 24 )| (ip.data[ip.pos + 1] << 16) | (ip.data[ip.po + 2] << 8) | ip.data[ip.pos + 3];
+                ip.pos += 4;
+                if (charstring_type == 2)
+                    shift = 0;
+            }
+            if (decoder.top >= FT_Common.CFF_MAX_OPERANDS)
+                return FT_Common.FT_Err_Stack_Overflow;
+
+            val <<= shift;
+            tops[decoder.top] = val;
+            decoder.top++;
+        }
+        else
+        {
+            /* The specification says that normally arguments are to be taken */
+            /* from the bottom of the stack.  However, this seems not to be   */
+            /* correct, at least for Acroread 7.0.8 on GNU/Linux: It pops the */
+            /* arguments similar to a PS interpreter.                         */
+            var args = decoder.top;
+            var num_args = args;
+
+            /* find operator */
+            op = FT_Common.cff_op_unknown;
+
+            switch (v)
+            {
+                case 1:
+                    op = FT_Common.cff_op_hstem;
+                    break;
+                case 3:
+                    op = FT_Common.cff_op_vstem;
+                    break;
+                case 4:
+                    op = FT_Common.cff_op_vmoveto;
+                    break;
+                case 5:
+                    op = FT_Common.cff_op_rlineto;
+                    break;
+                case 6:
+                    op = FT_Common.cff_op_hlineto;
+                    break;
+                case 7:
+                    op = FT_Common.cff_op_vlineto;
+                    break;
+                case 8:
+                    op = FT_Common.cff_op_rrcurveto;
+                    break;
+                case 9:
+                    op = FT_Common.cff_op_closepath;
+                    break;
+                case 10:
+                    op = FT_Common.cff_op_callsubr;
+                    break;
+                case 11:
+                    op = FT_Common.cff_op_return;
+                    break;
+                case 12:
+                {
+                    if (ip.pos >= limit)
+                        return FT_Common.FT_Err_Invalid_File_Format;
+                    v = ip.data[ip.pos];
+                    ip.pos++;
+                    switch (v)
+                    {
+                        case 0:
+                            op = FT_Common.cff_op_dotsection;
+                            break;
+                        case 1: /* this is actually the Type1 vstem3 operator */
+                            op = FT_Common.cff_op_vstem;
+                            break;
+                        case 2: /* this is actually the Type1 hstem3 operator */
+                            op = FT_Common.cff_op_hstem;
+                            break;
+                        case 3:
+                            op = FT_Common.cff_op_and;
+                            break;
+                        case 4:
+                            op = FT_Common.cff_op_or;
+                            break;
+                        case 5:
+                            op = FT_Common.cff_op_not;
+                            break;
+                        case 6:
+                            op = FT_Common.cff_op_seac;
+                            break;
+                        case 7:
+                            op = FT_Common.cff_op_sbw;
+                            break;
+                        case 8:
+                            op = FT_Common.cff_op_store;
+                            break;
+                        case 9:
+                            op = FT_Common.cff_op_abs;
+                            break;
+                        case 10:
+                            op = FT_Common.cff_op_add;
+                            break;
+                        case 11:
+                            op = FT_Common.cff_op_sub;
+                            break;
+                        case 12:
+                            op = FT_Common.cff_op_div;
+                            break;
+                        case 13:
+                            op = FT_Common.cff_op_load;
+                            break;
+                        case 14:
+                            op = FT_Common.cff_op_neg;
+                            break;
+                        case 15:
+                            op = FT_Common.cff_op_eq;
+                            break;
+                        case 16:
+                            op = FT_Common.cff_op_callothersubr;
+                            break;
+                        case 17:
+                            op = FT_Common.cff_op_pop;
+                            break;
+                        case 18:
+                            op = FT_Common.cff_op_drop;
+                            break;
+                        case 20:
+                            op = FT_Common.cff_op_put;
+                            break;
+                        case 21:
+                            op = FT_Common.cff_op_get;
+                            break;
+                        case 22:
+                            op = FT_Common.cff_op_ifelse;
+                            break;
+                        case 23:
+                            op = FT_Common.cff_op_random;
+                            break;
+                        case 24:
+                            op = FT_Common.cff_op_mul;
+                            break;
+                        case 26:
+                            op = FT_Common.cff_op_sqrt;
+                            break;
+                        case 27:
+                            op = FT_Common.cff_op_dup;
+                            break;
+                        case 28:
+                            op = FT_Common.cff_op_exch;
+                            break;
+                        case 29:
+                            op = FT_Common.cff_op_index;
+                            break;
+                        case 30:
+                            op = FT_Common.cff_op_roll;
+                            break;
+                        case 33:
+                            op = FT_Common.cff_op_setcurrentpoint;
+                            break;
+                        case 34:
+                            op = FT_Common.cff_op_hflex;
+                            break;
+                        case 35:
+                            op = FT_Common.cff_op_flex;
+                            break;
+                        case 36:
+                            op = FT_Common.cff_op_hflex1;
+                            break;
+                        case 37:
+                            op = FT_Common.cff_op_flex1;
+                            break;
+                        default:
+                            break;
+                    }
+                    break;
+                }
+                case 13:
+                    op = FT_Common.cff_op_hsbw;
+                    break;
+                case 14:
+                    op = FT_Common.cff_op_endchar;
+                    break;
+                case 16:
+                    op = FT_Common.cff_op_blend;
+                    break;
+                case 18:
+                    op = FT_Common.cff_op_hstemhm;
+                    break;
+                case 19:
+                    op = FT_Common.cff_op_hintmask;
+                    break;
+                case 20:
+                    op = FT_Common.cff_op_cntrmask;
+                    break;
+                case 21:
+                    op = FT_Common.cff_op_rmoveto;
+                    break;
+                case 22:
+                    op = FT_Common.cff_op_hmoveto;
+                    break;
+                case 23:
+                    op = FT_Common.cff_op_vstemhm;
+                    break;
+                case 24:
+                    op = FT_Common.cff_op_rcurveline;
+                    break;
+                case 25:
+                    op = FT_Common.cff_op_rlinecurve;
+                    break;
+                case 26:
+                    op = FT_Common.cff_op_vvcurveto;
+                    break;
+                case 27:
+                    op = FT_Common.cff_op_hhcurveto;
+                    break;
+                case 29:
+                    op = FT_Common.cff_op_callgsubr;
+                    break;
+                case 30:
+                    op = FT_Common.cff_op_vhcurveto;
+                    break;
+                case 31:
+                    op = FT_Common.cff_op_hvcurveto;
+                    break;
+                default:
+                    break;
+            }
+
+            if (op == FT_Common.cff_op_unknown)
+                continue;
+
+            /* check arguments */
+            var req_args = cff_argument_counts[op];
+            if ((req_args & FT_Common.CFF_COUNT_CHECK_WIDTH) != 0)
+            {
+                if (num_args > 0 && decoder.read_width != 0)
+                {
+                    /* If `nominal_width' is non-zero, the number is really a      */
+                    /* difference against `nominal_width'.  Else, the number here  */
+                    /* is truly a width, not a difference against `nominal_width'. */
+                    /* If the font does not set `nominal_width', then              */
+                    /* `nominal_width' defaults to zero, and so we can set         */
+                    /* `glyph_width' to `nominal_width' plus number on the stack   */
+                    /* -- for either case.                                         */
+                    var set_width_ok = 0;
+                    switch (op)
+                    {
+                        case FT_Common.cff_op_hmoveto:
+                        case FT_Common.cff_op_vmoveto:
+                            set_width_ok = num_args & 2;
+                            break;
+
+                        case FT_Common.cff_op_hstem:
+                        case FT_Common.cff_op_vstem:
+                        case FT_Common.cff_op_hstemhm:
+                        case FT_Common.cff_op_vstemhm:
+                        case FT_Common.cff_op_rmoveto:
+                        case FT_Common.cff_op_hintmask:
+                        case FT_Common.cff_op_cntrmask:
+                            set_width_ok = num_args & 1;
+                            break;
+
+                        case FT_Common.cff_op_endchar:
+                            /* If there is a width specified for endchar, we either have */
+                            /* 1 argument or 5 arguments.  We like to argue.             */
+                            set_width_ok = ((num_args == 5) || (num_args == 1)) ? 1 : 0;
+                            break;
+
+                        default:
+                            FT_Common.set_width_ok = 0;
+                            break;
+                    }
+
+                    if (set_width_ok != 0)
+                    {
+                        decoder.glyph_width = decoder.nominal_width + (tops[stack] >> 16);
+
+                        if (decoder.width_only != 0)
+                        {
+                            /* we only want the advance width; stop here */
+                            break;
+                        }
+
+                        /* Consumed an argument. */
+                        num_args--;
+                    }
+                }
+
+                decoder.read_width = 0;
+                req_args = 0;
+            }
+
+            req_args &= 0x000F;
+            if (num_args < req_args)
+                return FT_Common.FT_Err_Too_Few_Arguments;
+            args     -= req_args;
+            num_args -= req_args;
+
+            /* At this point, `args' points to the first argument of the  */
+            /* operand in case `req_args' isn't zero.  Otherwise, we have */
+            /* to adjust `args' manually.                                 */
+
+            /* Note that we only pop arguments from the stack which we    */
+            /* really need and can digest so that we can continue in case */
+            /* of superfluous stack elements.                             */
+
+            switch (op)
+            {
+                case FT_Common.cff_op_hstem:
+                case FT_Common.cff_op_vstem:
+                case FT_Common.cff_op_hstemhm:
+                case FT_Common.cff_op_vstemhm:
+                    /* the number of arguments is always even here */
+                    if (hinter != null)
+                        hinter.stems(hinter.hints, (op == FT_Common.cff_op_hstem || op == FT_Common.cff_op_hstemhm) ? 1 : 0, num_args / 2, tops[args - (num_args & ~1)]);
+
+                    decoder.num_hints += num_args / 2;
+                    args = stack;
+                    break;
+
+                case FT_Common.cff_op_hintmask:
+                case FT_Common.cff_op_cntrmask:
+                    /* implement vstem when needed --                        */
+                    /* the specification doesn't say it, but this also works */
+                    /* with the 'cntrmask' operator                          */
+                    /*                                                       */
+                    if (num_args > 0)
+                    {
+                        if (hinter != null)
+                            hinter.stems(hinter.hints, 0, num_args / 2, tops[args - (num_args & ~1)]);
+
+                        decoder.num_hints += num_args / 2;
+                    }
+
+                    /* In a valid charstring there must be at least one byte */
+                    /* after `hintmask' or `cntrmask' (e.g., for a `return'  */
+                    /* instruction).  Additionally, there must be space for  */
+                    /* `num_hints' bits.                                     */
+                    if ((ip.pos + ((decoder.num_hints + 7) >> 3)) >= limit)
+                        return FT_Common.FT_Err_Invalid_File_Format;
+
+                    if (hinter != null)
+                    {
+                        if (op == FT_Common.cff_op_hintmask)
+                            hinter.hintmask(hinter.hints, builder.current.n_points, decoder.num_hints, ip);
+                        else
+                            hinter.counter(hinter.hints, decoder.num_hints, ip);
+                    }
+
+                    ip.pos += (decoder.num_hints + 7 ) >> 3;
+                    args = stack;
+                    break;
+
+                case FT_Common.cff_op_rmoveto:
+                    cff_builder_close_contour(builder);
+                    builder.path_begun = 0;
+                    x += tops[args - 2];
+                    y += tops[args - 1];
+                    args = stack;
+                    break;
+
+                case FT_Common.cff_op_vmoveto:
+                    cff_builder_close_contour(builder);
+                    builder.path_begun = 0;
+                    y += tops[args - 1];
+                    args = stack;
+                    break;
+
+                case FT_Common.cff_op_hmoveto:
+                    cff_builder_close_contour(builder);
+                    builder.path_begun = 0;
+                    x += tops[args - 1];
+                    args = stack;
+                    break;
+
+                case FT_Common.cff_op_rlineto:
+                    if (cff_builder_start_point(builder, x, y) != 0 || _cff_check_points(builder, parseInt(num_args / 2)) != 0)
+                        return error;
+
+                    if (num_args < 2)
+                        return FT_Common.FT_Err_Too_Few_Arguments;
+
+                    args -= num_args & ~1;
+                    while (args < decoder.top)
+                    {
+                        x += tops[args];
+                        y += tops[args + 1];
+                        cff_builder_add_point(builder, x, y, 1);
+                        args += 2;
+                    }
+                    args = stack;
+                    break;
+
+                case FT_Common.cff_op_hlineto:
+                case FT_Common.cff_op_vlineto:
+                {
+                    var phase = (op == FT_Common.cff_op_hlineto) ? 1 : 0;
+
+                    if (num_args < 0)
+                        return FT_Common.FT_Err_Too_Few_Arguments;
+
+                    /* there exist subsetted fonts (found in PDFs) */
+                    /* which call `hlineto' without arguments      */
+                    if (num_args == 0)
+                        break;
+
+                    if (cff_builder_start_point(builder, x, y) != 0 || _cff_check_points(builder, num_args))
+                        return error;
+
+                    args = stack;
+                    while (args < decoder.top)
+                    {
+                        if (phase == 1)
+                            x += tops[args];
+                        else
+                            y += tops[args];
+
+                        if (cff_builder_add_point1(builder, x, y) != 0)
+                            return error;
+
+                        args++;
+                        phase ^= 1;
+                    }
+                    args = stack;
+                    break;
+                }
+
+                case FT_Common.cff_op_rrcurveto:
+                {
+                    if (num_args < 6)
+                        return FT_Error.FT_Err_Too_Few_Arguments;
+
+                    var nargs = num_args - num_args % 6;
+
+                    if (cff_builder_start_point(builder, x, y) != 0 || _cff_check_points(builder, parseInt(nargs / 2)))
+                        return error;
+
+                    args -= nargs;
+                    while (args < decoder.top)
+                    {
+                        x += tops[args];
+                        y += tops[args + 1];
+                        cff_builder_add_point(builder, x, y, 0);
+                        x += tops[args + 2];
+                        y += tops[args + 3];
+                        cff_builder_add_point(builder, x, y, 0);
+                        x += tops[args + 4];
+                        y += tops[args + 5];
+                        cff_builder_add_point(builder, x, y, 1);
+                        args += 6;
+                    }
+                    args = stack;
+                    break;
+                }
+
+                case FT_Common.cff_op_vvcurveto:
+                {
+                    if (num_args < 4)
+                        return FT_Common.FT_Err_Too_Few_Arguments;
+
+                    /* if num_args isn't of the form 4n or 4n+1, */
+                    /* we reduce it to 4n+1                      */
+                    var nargs = num_args - num_args % 4;
+                    if ((num_args - nargs) > 0)
+                        nargs += 1;
+
+                    if (cff_builder_start_point(builder, x, y) != 0)
+                        return error;
+
+                    args -= nargs;
+                    if ((nargs & 1) != 0)
+                    {
+                        x += tops[args];
+                        args++;
+                        nargs--;
+                    }
+
+                    if (_cff_check_points(builder, 3 * parseInt(nargs / 4)))
+                        return error;
+
+                    while (args < decoder.top)
+                    {
+                        y += tops[args];
+                        cff_builder_add_point(builder, x, y, 0);
+                        x += tops[args + 1];
+                        y += tops[args + 2];
+                        cff_builder_add_point(builder, x, y, 0);
+                        y += tops[args + 3];
+                        cff_builder_add_point(builder, x, y, 1);
+                        args += 4;
+                    }
+                    args = stack;
+                    break;
+                }
+
+                case FT_Common.cff_op_hhcurveto:
+                {
+                    if (num_args < 4)
+                        return FT_Common.FT_Err_Too_Few_Arguments;
+
+                    /* if num_args isn't of the form 4n or 4n+1, */
+                    /* we reduce it to 4n+1                      */
+                    var nargs = num_args - num_args % 4;
+                    if ((num_args - nargs) > 0)
+                        nargs += 1;
+
+                    if (cff_builder_start_point(builder, x, y) != 0)
+                        return error;
+
+                    args -= nargs;
+                    if ((nargs & 1) != 0)
+                    {
+                        y += tops[args];
+                        args++;
+                        nargs--;
+                    }
+
+                    if (_cff_check_points(builder, 3 * parseInt(nargs / 4)))
+                        return error;
+
+                    while (args < decoder.top)
+                    {
+                        x += tops[args];
+                        cff_builder_add_point(builder, x, y, 0);
+                        x += tops[args + 1];
+                        y += tops[args + 2];
+                        cff_builder_add_point(builder, x, y, 0);
+                        x += tops[args + 3];
+                        cff_builder_add_point(builder, x, y, 1);
+                        args += 4;
+                    }
+                    args = stack;
+                    break;
+                }
+
+                case FT_Common.cff_op_vhcurveto:
+                case FT_Common.cff_op_hvcurveto:
+                {
+                    if (cff_builder_start_point(builder, x, y) != 0)
+                        return error;
+
+                    if (num_args < 4)
+                        return FT_Common.FT_Err_Too_Few_Arguments;
+
+                    /* if num_args isn't of the form 8n, 8n+1, 8n+4, or 8n+5, */
+                    /* we reduce it to the largest one which fits             */
+                    var nargs = num_args - num_args % 4;
+                    if ((num_args - nargs) > 0)
+                        nargs += 1;
+
+                    args -= nargs;
+                    if (_cff_check_points(builder, parseInt(nargs / 4) * 3))
+                        return FT_Common.FT_Err_Too_Few_Arguments;
+
+                    var phase = (op == FT_Common.cff_op_hvcurveto) ? 1 : 0;
+
+                    while (nargs >= 4)
+                    {
+                        nargs -= 4;
+                        if (phase == 1)
+                        {
+                            x += tops[args];
+                            cff_builder_add_point(builder, x, y, 0);
+                            x += tops[args + 1];
+                            y += tops[args + 2];
+                            cff_builder_add_point(builder, x, y, 0);
+                            y += tops[args + 3];
+                            if (nargs == 1)
+                                x += tops[args + 4];
+                            cff_builder_add_point(builder, x, y, 1);
+                        }
+                        else
+                        {
+                            y += tops[args];
+                            cff_builder_add_point(builder, x, y, 0);
+                            x += tops[args + 1];
+                            y += tops[args + 2];
+                            cff_builder_add_point(builder, x, y, 0);
+                            x += tops[args + 3];
+                            if (nargs == 1)
+                                y += tops[args + 4];
+                            cff_builder_add_point(builder, x, y, 1);
+                        }
+                        args  += 4;
+                        phase ^= 1;
+                    }
+                    args = stack;
+                    break;
+                }
+
+                case FT_Common.cff_op_rlinecurve:
+                {
+                    if (num_args < 8)
+                        return FT_Common.FT_Err_Too_Few_Arguments;
+
+                    var nargs = num_args & ~1;
+                    var num_lines = parseInt((nargs - 6) / 2);
+
+                    if (cff_builder_start_point(builder, x, y) || _cff_check_points(builder, num_lines + 3))
+                        return error;
+
+                    args -= nargs;
+
+                    /* first, add the line segments */
+                    while (num_lines > 0)
+                    {
+                        x += tops[args];
+                        y += tops[args + 1];
+                        cff_builder_add_point(builder, x, y, 1);
+                        args += 2;
+                        num_lines--;
+                    }
+
+                    /* then the curve */
+                    x += tops[args];
+                    y += tops[args + 1];
+                    cff_builder_add_point(builder, x, y, 0);
+                    x += tops[args + 2];
+                    y += tops[args + 3];
+                    cff_builder_add_point(builder, x, y, 0);
+                    x += tops[args + 4];
+                    y += tops[args + 5];
+                    cff_builder_add_point(builder, x, y, 1);
+                    args = stack;
+                    break;
+                }
+
+                case FT_Common.cff_op_rcurveline:
+                {
+                    if ( num_args < 8 )
+                        return FT_Common.FT_Err_Too_Few_Arguments;
+
+                    var nargs  = num_args - 2;
+                    nargs      = nargs - nargs % 6 + 2;
+                    var num_curves = parseInt((nargs - 2) / 6);
+
+                    if (cff_builder_start_point(builder, x, y) != 0 || _cff_check_points(builder, num_curves * 3 + 2))
+                        return error;
+
+                    args -= nargs;
+
+                    /* first, add the curves */
+                    while (num_curves > 0)
+                    {
+                        x += tops[args];
+                        y += tops[args + 1];
+                        cff_builder_add_point(builder, x, y, 0);
+                        x += tops[args + 2];
+                        y += tops[args + 3];
+                        cff_builder_add_point(builder, x, y, 0);
+                        x += tops[args + 4];
+                        y += tops[args + 5];
+                        cff_builder_add_point(builder, x, y, 1);
+                        args += 6;
+                        num_curves--;
+                    }
+
+                    /* then the final line */
+                    x += tops[args];
+                    y += tops[args + 1];
+                    cff_builder_add_point(builder, x, y, 1);
+                    args = stack;
+
+                    break;
+                }
+
+                case FT_Common.cff_op_hflex1:
+                {
+                    /* adding five more points: 4 control points, 1 on-curve point */
+                    /* -- make sure we have enough space for the start point if it */
+                    /* needs to be added                                           */
+                    if (cff_builder_start_point(builder, x, y) != 0 || _cff_check_points(builder, 6))
+                        return error;
+
+                    /* record the starting point's y position for later use */
+                    var start_y = y;
+
+                    /* first control point */
+                    x += tops[args];
+                    y += tops[args + 1];
+                    cff_builder_add_point(builder, x, y, 0);
+
+                    /* second control point */
+                    x += tops[args + 2];
+                    y += tops[args + 3];
+                    cff_builder_add_point(builder, x, y, 0);
+
+                    /* join point; on curve, with y-value the same as the last */
+                    /* control point's y-value                                 */
+                    x += tops[args + 4];
+                    cff_builder_add_point(builder, x, y, 1);
+
+                    /* third control point, with y-value the same as the join */
+                    /* point's y-value                                        */
+                    x += tops[args + 5];
+                    cff_builder_add_point(builder, x, y, 0);
+
+                    /* fourth control point */
+                    x += tops[args + 6];
+                    y += tops[args + 7];
+                    cff_builder_add_point(builder, x, y, 0);
+
+                    /* ending point, with y-value the same as the start   */
+                    x += tops[args + 8];
+                    y  = start_y;
+                    cff_builder_add_point(builder, x, y, 1);
+
+                    args = stack;
+                    break;
+                }
+
+                case FT_Common.cff_op_hflex:
+                {
+                    /* adding six more points; 4 control points, 2 on-curve points */
+                    if (cff_builder_start_point(builder, x, y) != 0 || _cff_check_points(builder, 6))
+                        return error;
+
+                    /* record the starting point's y-position for later use */
+                    var start_y = y;
+
+                    /* first control point */
+                    x += tops[args];
+                    cff_builder_add_point(builder, x, y, 0);
+
+                    /* second control point */
+                    x += tops[args + 1];
+                    y += tops[args + 2];
+                    cff_builder_add_point(builder, x, y, 0);
+
+                    /* join point; on curve, with y-value the same as the last */
+                    /* control point's y-value                                 */
+                    x += tops[args + 3];
+                    cff_builder_add_point(builder, x, y, 1);
+
+                    /* third control point, with y-value the same as the join */
+                    /* point's y-value                                        */
+                    x += tops[args + 4];
+                    cff_builder_add_point(builder, x, y, 0);
+
+                    /* fourth control point */
+                    x += tops[args + 5];
+                    y  = start_y;
+                    cff_builder_add_point(builder, x, y, 0);
+
+                    /* ending point, with y-value the same as the start point's */
+                    /* y-value -- we don't add this point, though               */
+                    x += tops[args + 6];
+                    cff_builder_add_point(builder, x, y, 1);
+
+                    args = stack;
+                    break;
+                }
+
+                case FT_Common.cff_op_flex1:
+                {
+                    /* alter use                    */
+                    var dx = 0, dy = 0;   /* used in horizontal/vertical  */
+
+                    /* adding six more points; 4 control points, 2 on-curve points */
+                    if (cff_builder_start_point(builder, x, y) != 0 || _cff_check_points(builder, 6) != 0)
+                        return error;
+
+                    /* record the starting point's x, y position for later use */
+                    var start_x = x;
+                    var start_y = y;
+
+                    /* XXX: figure out whether this is supposed to be a horizontal */
+                    /*      or vertical flex; the Type 2 specification is vague... */
+
+                    var temp = args;
+                    var count = 0;
+
+                    /* grab up to the last argument */
+                    for (count = 5; count > 0; count--)
+                    {
+                        dx += tops[temp];
+                        dy += tops[temp + 1];
+                        temp += 2;
+                    }
+
+                    if (dx < 0)
+                        dx = -dx;
+                    if (dy < 0)
+                        dy = -dy;
+
+                    /* strange test, but here it is... */
+                    var horizontal = (dx > dy) ? 1 : 0;
+
+                    for (count = 5; count > 0; count--)
+                    {
+                        x += tops[args];
+                        y += tops[args + 1];
+                        cff_builder_add_point(builder, x, y, (count == 3) ? 1 : 0);
+                        args += 2;
+                    }
+
+                    /* is last operand an x- or y-delta? */
+                    if (horizontal == 1)
+                    {
+                        x += tops[args];
+                        y  = start_y;
+                    }
+                    else
+                    {
+                        x  = start_x;
+                        y += tops[args];
+                    }
+
+                    cff_builder_add_point(builder, x, y, 1);
+
+                    args = stack;
+                    break;
+                }
+
+                case FT_Common.cff_op_flex:
+                {
+                    if (cff_builder_start_point(builder, x, y) != 0 || _cff_check_points(builder, 6))
+                        return error;
+
+                    for (var count = 6; count > 0; count--)
+                    {
+                        x += tops[args];
+                        y += tops[args + 1];
+                        cff_builder_add_point(builder, x, y, (count == 4 || count == 1) ? 1 : 0);
+                        args += 2;
+                    }
+
+                    args = stack;
+                    break;
+                }
+
+                case FT_Common.cff_op_seac:
+                    error = cff_operator_seac(decoder, tops[args], tops[args + 1], tops[args + 2], (tops[args + 3] >> 16), (tops[args + 4] >> 16));
+
+                    /* add current outline to the glyph slot */
+                    FT_GlyphLoader_Add(builder.loader);
+                    return error;
+
+                case FT_Common.cff_op_endchar:
+                    /* We are going to emulate the seac operator. */
+                    if (num_args >= 4)
+                    {
+                        /* Save glyph width so that the subglyphs don't overwrite it. */
+                        var glyph_width = decoder.glyph_width;
+
+                        error = cff_operator_seac(decoder, 0, tops[args - 4], tops[args - 3], (tops[args - 2] >> 16), (tops[args - 1] >> 16));
+                        decoder.glyph_width = glyph_width;
+                    }
+                    else
+                    {
+                        cff_builder_close_contour(builder);
+
+                        /* close hints recording session */
+                        if (hinter != null)
+                        {
+                            if (hinter.close(hinter.hints, builder.current.n_points))
+                                return FT_Common.FT_Err_Invalid_File_Format;
+
+                            /* apply hints to the loaded glyph outline now */
+                            hinter.apply(hinter.hints, builder.current, builder.hints_globals, decoder.hint_mode);
+                        }
+
+                        /* add current outline to the glyph slot */
+                        FT_GlyphLoader_Add(builder.loader);
+                    }
+
+                    /* return now! */
+                    return error;
+
+                case FT_Common.cff_op_abs:
+                    if (tops[args] < 0)
+                        tops[args] = -tops[args];
+                    args++;
+                    break;
+
+                case FT_Common.cff_op_add:
+                    tops[args] += tops[args + 1];
+                    args++;
+                    break;
+
+                case FT_Common.cff_op_sub:
+                    tops[args] -= tops[args + 1];
+                    args++;
+                    break;
+
+                case FT_Common.cff_op_div:
+                    tops[args] = FT_DivFix(tops[args], tops[args + 1]);
+                    args++;
+                    break;
+
+                case FT_Common.cff_op_neg:
+                    tops[args] = -tops[args];
+                    args++;
+                    break;
+
+                case FT_Common.cff_op_random:
+                {
+                    var Rand = seed;
+                    if (Rand >= 0x8000)
+                        Rand++;
+
+                    tops[args] = Rand;
+                    seed = FT_MulFix(seed, 0x10000 - seed);
+                    if (seed == 0)
+                        seed += 0x2873;
+                    args++;
+
+                    break;
+                }
+
+                case FT_Common.cff_op_mul:
+                    topsargs[0] = FT_MulFix( args[0], args[1] );
+                    args++;
+                    break;
+
+                case FT_Common.cff_op_sqrt:
+                    if (tops[args] > 0)
+                    {
+                        var count = 9;
+                        var root = tops[args];
+                        var new_root = 0;
+                        for (;;)
+                        {
+                            new_root = (root + FT_DivFix(tops[args], root) + 1) >> 1;
+                            if (new_root == root || count <= 0)
+                                break;
+                            root = new_root;
+                        }
+                        tops[args] = new_root;
+                    }
+                    else
+                        tops[args] = 0;
+                    args++;
+                    break;
+
+                case FT_Common.cff_op_drop:
+                    /* nothing */
+                    break;
+
+                case FT_Common.cff_op_exch:
+                {
+                    var tmp = tops[args];
+                    tops[args] = tops[args + 1];
+                    tops[args + 1] = tmp;
+                    args += 2;
+
+                    break;
+                }
+
+                case FT_Common.cff_op_index:
+                {
+                    var idx = (tops[args] >> 16);
+
+                    if (idx < 0)
+                        idx = 0;
+                    else if (idx > num_args - 2)
+                        idx = num_args - 2;
+                    tops[args] = tops[args-(idx + 1)];
+                    args++;
+
+                    break;
+                }
+
+                case FT_Common.cff_op_roll:
+                {
+                    var count = (tops[args] >> 16);
+                    var idx = (tops[args + 1] >> 16);
+
+                    if (count <= 0)
+                        count = 1;
+
+                    args -= count;
+                    if (args < stack)
+                        return FT_Common.FT_Err_Too_Few_Arguments;
+
+                    if (idx >= 0)
+                    {
+                        while (idx > 0)
+                        {
+                            var tmp = tops[args + count - 1];
+                            for (var i = count - 2; i >= 0; i--)
+                                tops[args + i + 1] = tops[args + i];
+                            tops[args] = tmp;
+                            idx--;
+                        }
+                    }
+                    else
+                    {
+                        while (idx < 0)
+                        {
+                            var tmp = tops[args];
+                            for (var i = 0; i < count - 1; i++)
+                                tops[args + i] = tops[args + i + 1];
+                            tops[args + count - 1] = tmp;
+                            idx++;
+                        }
+                    }
+                    args += count;
+
+                    break;
+                }
+
+                case FT_Common.cff_op_dup:
+                    tops[args + 1] = tops[args];
+                    args += 2;
+                    break;
+
+                case FT_Common.cff_op_put:
+                {
+                    var val = tops[args];
+                    var idx = (tops[args + 1] >> 16);
+
+                    if (idx >= 0 && idx < FT_Common.CFF_MAX_TRANS_ELEMENTS)
+                        decoder.buildchar[idx] = val;
+
+                    break;
+                }
+
+                case FT_Common.cff_op_get:
+                {
+                    var idx = (tops[args] >> 16);
+                    var val = 0;
+
+                    if (idx >= 0 && idx < FT_Common.CFF_MAX_TRANS_ELEMENTS)
+                        val = decoder.buildchar[idx];
+
+                    tops[args] = val;
+                    args++;
+
+                    break;
+                }
+
+                case FT_Common.cff_op_store:
+                    return FT_Common.FT_Err_Unimplemented_Feature;
+
+                case FT_Common.cff_op_load:
+                    return FT_Common.FT_Err_Unimplemented_Feature;
+
+                case FT_Common.cff_op_dotsection:
+                    /* this operator is deprecated and ignored by the parser */
+                    break;
+
+                case FT_Common.cff_op_closepath:
+                    /* this is an invalid Type 2 operator; however, there        */
+                    /* exist fonts which are incorrectly converted from probably */
+                    /* Type 1 to CFF, and some parsers seem to accept it         */
+                    args = stack;
+                    break;
+
+                case FT_Common.cff_op_hsbw:
+                    /* this is an invalid Type 2 operator; however, there        */
+                    /* exist fonts which are incorrectly converted from probably */
+                    /* Type 1 to CFF, and some parsers seem to accept it         */
+                    decoder.glyph_width = decoder.nominal_width + (tops[args + 1] >> 16);
+
+                    decoder.builder.left_bearing.x = tops[args];
+                    decoder.builder.left_bearing.y = 0;
+
+                    x = decoder.builder.pos_x + tops[args];
+                    y = decoder.builder.pos_y;
+                    args = stack;
+                    break;
+
+                case FT_Common.cff_op_sbw:
+                    /* this is an invalid Type 2 operator; however, there        */
+                    /* exist fonts which are incorrectly converted from probably */
+                    /* Type 1 to CFF, and some parsers seem to accept it         */
+                    decoder.glyph_width = decoder.nominal_width + (tops[args + 2] >> 16);
+
+                    decoder.builder.left_bearing.x = tops[args];
+                    decoder.builder.left_bearing.y = tops[args + 1];
+
+                    x = decoder.builder.pos_x + tops[args];
+                    y = decoder.builder.pos_y + tops[args + 1];
+                    args = stack;
+                    break;
+
+                case FT_Common.cff_op_setcurrentpoint:
+                    /* this is an invalid Type 2 operator; however, there        */
+                    /* exist fonts which are incorrectly converted from probably */
+                    /* Type 1 to CFF, and some parsers seem to accept it         */
+                    x = decoder.builder.pos_x + tops[args];
+                    y = decoder.builder.pos_y + tops[args + 1];
+                    args = stack;
+                    break;
+
+                case FT_Common.cff_op_callothersubr:
+                    /* this is an invalid Type 2 operator; however, there        */
+                    /* exist fonts which are incorrectly converted from probably */
+                    /* Type 1 to CFF, and some parsers seem to accept it         */
+
+                    /* subsequent `pop' operands should add the arguments,       */
+                    /* this is the implementation described for `unknown' other  */
+                    /* subroutines in the Type1 spec.                            */
+                    /*                                                           */
+                    /* XXX Fix return arguments (see discussion below).          */
+                    args -= 2 + (tops[args - 2] >> 16);
+                    if (args < stack)
+                        return FT_Common.FT_Err_Too_Few_Arguments;
+                    break;
+
+                case FT_Common.cff_op_pop:
+                    /* this is an invalid Type 2 operator; however, there        */
+                    /* exist fonts which are incorrectly converted from probably */
+                    /* Type 1 to CFF, and some parsers seem to accept it         */
+
+                    /* XXX Increasing `args' is wrong: After a certain number of */
+                    /* `pop's we get a stack overflow.  Reason for doing it is   */
+                    /* code like this (actually found in a CFF font):            */
+                    /*                                                           */
+                    /*   17 1 3 callothersubr                                    */
+                    /*   pop                                                     */
+                    /*   callsubr                                                */
+                    /*                                                           */
+                    /* Since we handle `callothersubr' as a no-op, and           */
+                    /* `callsubr' needs at least one argument, `pop' can't be a  */
+                    /* no-op too as it basically should be.                      */
+                    /*                                                           */
+                    /* The right solution would be to provide real support for   */
+                    /* `callothersubr' as done in `t1decode.c', however, given   */
+                    /* the fact that CFF fonts with `pop' are invalid, it is     */
+                    /* questionable whether it is worth the time.                */
+                    args++;
+                    break;
+
+                case FT_Common.cff_op_and:
+                {
+                    var cond = (tops[args] != 0 && tops[args + 1] != 0) ? 1 : 0;
+
+                    tops[args] = (cond == 1) ? 0x10000 : 0;
+                    args++;
+
+                    break;
+                }
+                case FT_Common.cff_op_or:
+                {
+                    var cond = (tops[args] != 0 || tops[args + 1]) ? 1 : 0;
+
+                    tops[args] = (cond == 1) ? 0x10000 : 0;
+                    args++;
+
+                    break;
+                }
+
+                case FT_Common.cff_op_eq:
+                {
+                    tops[args] = (tops[args] == 0) ? 0x10000 : 0;
+                    args++;
+
+                    break;
+                }
+
+                case FT_Common.cff_op_ifelse:
+                {
+                    if (tops[args + 2] > tops[args + 3])
+                        tops[args] = tops[args + 1];
+                    args++;
+
+                    break;
+                }
+
+                case FT_Common.cff_op_callsubr:
+                {
+                    var idx = ((tops[args] >> 16) + decoder.locals_bias);
+
+                    if (idx >= decoder.num_locals)
+                        return FT_Common.FT_Err_Invalid_File_Format;
+
+                    if (zone >= FT_Common.CFF_MAX_SUBRS_CALLS)
+                        return FT_Common.FT_Err_Invalid_File_Format;
+
+                    zones[zone].cursor = ip.pos - zones[zone].base.pos;  /* save current instruction pointer */
+
+                    zone++;
+                    zones[zone].base = dublicate_pointer(decoder.locals[idx]);
+                    zones[zone].limit = (decoder.locals[idx + 1] != null) ? decoder.locals[idx + 1].pos : zones[zone].base.pos;
+                    zones[zone].cursor = 0;
+
+                    if (zones[zone].base == null || zones[zone].limit == zones[zone].base.pos)
+                        return FT_Common.FT_Err_Invalid_File_Format;
+
+                    decoder.zone = zone;
+                    ip = dublicate_pointer(zones[zone].base);
+                    limit = zones[zone].limit;
+
+                    break;
+                }
+
+                case FT_Common.cff_op_callgsubr:
+                {
+                    var idx = ((tops[args] >> 16) + decoder.globals_bias);
+
+                    if (idx >= decoder.num_globals)
+                        return FT_Common.FT_Err_Invalid_File_Format;
+
+                    if (zone >= FT_Common.CFF_MAX_SUBRS_CALLS)
+                        return FT_Common.FT_Err_Invalid_File_Format;
+
+                    zones[zone].cursor = ip.pos - zones[zone].base.pos;  /* save current instruction pointer */
+
+                    zone++;
+                    zones[zone].base = dublicate_pointer(decoder.globals[idx]);
+                    zones[zone].limit = (decoder.globals[idx + 1] != null) ? decoder.globals[idx + 1].pos : zones[zone].base.pos;
+                    zones[zone].cursor = 0;
+
+                    if (zones[zone].base == null || zones[zone].limit == zones[zone].base.pos)
+                        return FT_Common.FT_Err_Invalid_File_Format;
+
+                    decoder.zone = zone;
+                    ip = dublicate_pointer(zones[zone].base);
+                    limit = zones[zone].limit;
+
+                    break;
+                }
+
+                case FT_Common.cff_op_return:
+                    if (decoder.zone <= 0)
+                        return FT_Common.FT_Err_Invalid_File_Format;
+
+                    decoder.zone--;
+                    zone  = decoder.zone;
+                    ip = dublicate_pointer(zones[zone].base);
+                    ip.pos += zones[zone].cursor;
+                    limit = zones[zone].limit;
+                    break;
+
+                default:
+                    return FT_Common.FT_Err_Unimplemented_Feature;
+            }
+
+            decoder.top = args;
+
+            if (decoder.top >= FT_Common.CFF_MAX_OPERANDS)
+                return FT_Common.FT_Err_Stack_Overflow;
+
+        } /* general operator processing */
+
+    } /* while ip < limit */
+
+    return error;
+}
+
+function cff_slot_load(glyph, size, glyph_index, load_flags)
+{
+    var face = glyph.face;
+    var cff  = face.extra.data;
+
+    var font_matrix = null;
+    var font_offset = null;
+
+    var hinting = 0;
+    var force_scaling = 0;
+
+    /* in a CID-keyed font, consider `glyph_index' as a CID and map */
+    /* it immediately to the real glyph_index -- if it isn't a      */
+    /* subsetted font, glyph_indices and CIDs are identical, though */
+    if (cff.top_font.font_dict.cid_registry != 0xFFFF && cff.charset.cids != null)
+    {
+        /* don't handle CID 0 (.notdef) which is directly mapped to GID 0 */
+        if (glyph_index != 0)
+        {
+            glyph_index = cff_charset_cid_to_gindex(cff.charset, glyph_index);
+            if (glyph_index == 0)
+                return FT_Common.FT_Err_Invalid_Argument;
+        }
+    }
+    else if (glyph_index >= cff.num_glyphs)
+        return FT_Common.FT_Err_Invalid_Argument;
+
+    if ((load_flags & FT_Common.FT_LOAD_NO_RECURSE) != 0)
+        load_flags |= (FT_Common.FT_LOAD_NO_SCALE | FT_Common.FT_LOAD_NO_HINTING);
+
+    glyph.x_scale = 0x10000;
+    glyph.y_scale = 0x10000;
+    if (size != 0)
+    {
+        glyph.x_scale = size.metrics.x_scale;
+        glyph.y_scale = size.metrics.y_scale;
+    }
+
+    var error = 0;
+
+    //#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
+
+    /* try to load embedded bitmap if any              */
+    /*                                                 */
+    /* XXX: The convention should be emphasized in     */
+    /*      the documents because it can be confusing. */
+    if (size != null)
+    {
+        var cff_face = size.face;
+        var sfnt = cff_face.sfnt;
+        var stream = cff_face.stream;
+
+        if (size.strike_index != 0xFFFFFFFF && sfnt.load_eblc != null && (load_flags & FT_Common.FT_LOAD_NO_BITMAP) == 0)
+        {
+            var metrics = new TT_SBit_MetricsRec();
+
+            error = sfnt.load_sbit_image(face, size.strike_index, glyph_index, load_flags, stream, glyph.bitmap, metrics);
+
+            if (error == 0)
+            {
+                glyph.outline.n_points   = 0;
+                glyph.outline.n_contours = 0;
+
+                glyph.metrics.width  = metrics.width << 6;
+                glyph.metrics.height = metrics.height << 6;
+
+                glyph.metrics.horiBearingX = metrics.horiBearingX << 6;
+                glyph.metrics.horiBearingY = metrics.horiBearingY << 6;
+                glyph.metrics.horiAdvance  = metrics.horiAdvance  << 6;
+
+                glyph.metrics.vertBearingX = metrics.vertBearingX << 6;
+                glyph.metrics.vertBearingY = metrics.vertBearingY << 6;
+                glyph.metrics.vertAdvance  = metrics.vertAdvance  << 6;
+
+                glyph.format = FT_Common.FT_GLYPH_FORMAT_BITMAP;
+
+                if (load_flags & FT_Common.FT_LOAD_VERTICAL_LAYOUT)
+                {
+                    glyph.bitmap_left = metrics.vertBearingX;
+                    glyph.bitmap_top  = metrics.vertBearingY;
+                }
+                else
+                {
+                    glyph.bitmap_left = metrics.horiBearingX;
+                    glyph.bitmap_top  = metrics.horiBearingY;
+                }
+                return error;
+            }
+        }
+    }
+
+    //#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
+
+    /* return immediately if we only want the embedded bitmaps */
+    if ((load_flags & FT_Common.FT_LOAD_SBITS_ONLY) != 0)
+        return FT_Common.FT_Err_Invalid_Argument;
+
+    /* if we have a CID subfont, use its matrix (which has already */
+    /* been multiplied with the root matrix)                       */
+
+    /* this scaling is only relevant if the PS hinter isn't active */
+    if (cff.num_subfonts > 0)
+    {
+        var fd_index = cff_fd_select_get(cff.fd_select, glyph_index);
+
+        if (fd_index >= cff.num_subfonts)
+            fd_index = (cff.num_subfonts - 1);
+
+        var top_upm = cff.top_font.font_dict.units_per_em;
+        var sub_upm = cff.subfonts[fd_index].font_dict.units_per_em;
+
+        font_matrix = dublicate_matrix(cff.subfonts[fd_index].font_dict.font_matrix);
+        font_offset = dublicate_vector(cff.subfonts[fd_index].font_dict.font_offset);
+
+        if (top_upm != sub_upm)
+        {
+            glyph.x_scale = FT_MulDiv(glyph.x_scale, top_upm, sub_upm);
+            glyph.y_scale = FT_MulDiv(glyph.y_scale, top_upm, sub_upm);
+
+            force_scaling = 1;
+        }
+    }
+    else
+    {
+        font_matrix = dublicate_matrix(cff.top_font.font_dict.font_matrix);
+        font_offset = dublicate_vector(cff.top_font.font_dict.font_offset);
+    }
+
+    glyph.outline.n_points   = 0;
+    glyph.outline.n_contours = 0;
+
+    hinting = ((load_flags & FT_Common.FT_LOAD_NO_SCALE) == 0 && (load_flags & FT_Common.FT_LOAD_NO_HINTING) == 0) ? 1 : 0;
+
+    glyph.format = FT_Common.FT_GLYPH_FORMAT_OUTLINE;  /* by default */
+
+    var decoder = new CFF_Decoder();
+    cff_decoder_init(decoder, face, size, glyph, hinting, FT_LOAD_TARGET_MODE(load_flags));
+
+    if ((load_flags & FT_Common.FT_LOAD_ADVANCE_ONLY) != 0)
+        decoder.width_only = 1;
+
+    decoder.builder.no_recurse = ((load_flags & FT_Common.FT_LOAD_NO_RECURSE) != 0) ? 1 : 0;
+
+    /* now load the unscaled outline */
+    var ret = cff_get_glyph_data(face, glyph_index);
+    error = ret.err;
+    var charstring = ret.bytes;
+    var charstring_len = ret.len;
+
+    if (error == 0)
+    {
+        error = cff_decoder_prepare(decoder, size, glyph_index);
+        if (error == 0)
+        {
+            error = cff_decoder_parse_charstrings(decoder, charstring, charstring_len);
+            cff_free_glyph_data(face, charstring, charstring_len);
+            charstring = null;
+
+            if (error == 0)
+            {
+                //#ifdef FT_CONFIG_OPTION_INCREMENTAL
+                /* Control data and length may not be available for incremental */
+                /* fonts.                                                       */
+                if (face.internal.incremental_interface != null)
+                {
+                    glyph.control_data = null;
+                    glyph.control_len = 0;
+                }
+                else //#endif /* FT_CONFIG_OPTION_INCREMENTAL */
+                {
+                    var csindex = cff.charstrings_index;
+
+                    if (csindex.offsets != null)
+                    {
+                        glyph.control_data = dublicate_pointer(csindex.bytes);
+                        glyph.control_data.pos += csindex.offsets[glyph_index] - 1;
+                        glyph.control_len = charstring_len;
+                    }
+
+                }
+                cff_builder_done(decoder.builder);
+            }
+        }
+    }
+    /* XXX: anything to do for broken glyph entry? */
+
+    //#ifdef FT_CONFIG_OPTION_INCREMENTAL
+
+    /* Incremental fonts can optionally override the metrics. */
+    if (error == 0 && face.internal.incremental_interface != null && face.internal.incremental_interface.funcs.get_glyph_metrics != null)
+    {
+        var metrics = new FT_Incremental_MetricsRec();
+
+        metrics.bearing_x = decoder.builder.left_bearing.x;
+        metrics.bearing_y = 0;
+        metrics.advance   = decoder.builder.advance.x;
+        metrics.advance_v = decoder.builder.advance.y;
+
+        error = face.internal.incremental_interface.funcs.get_glyph_metrics(face.internal.incremental_interface.object, glyph_index, 0, metrics);
+
+        decoder.builder.left_bearing.x = metrics.bearing_x;
+        decoder.builder.advance.x      = metrics.advance;
+        decoder.builder.advance.y      = metrics.advance_v;
+    }
+
+    //#endif /* FT_CONFIG_OPTION_INCREMENTAL */
+
+    if (error == 0)
+    {
+        /* Now, set the metrics -- this is rather simple, as   */
+        /* the left side bearing is the xMin, and the top side */
+        /* bearing the yMax.                                   */
+
+        /* For composite glyphs, return only left side bearing and */
+        /* advance width.                                          */
+        if ((load_flags & FT_Common.FT_LOAD_NO_RECURSE) != 0)
+        {
+            var internal = glyph.internal;
+
+            glyph.metrics.horiBearingX = decoder.builder.left_bearing.x;
+            glyph.metrics.horiAdvance  = decoder.glyph_width;
+            internal.glyph_matrix           = dublicate_matrix(font_matrix);
+            internal.glyph_delta            = dublicate_matrix(font_offset);
+            internal.glyph_transformed      = 1;
+        }
+        else
+        {
+            var cbox = new FT_BBox();
+            var metrics = glyph.metrics;
+            var advance = new FT_Vector();
+            var has_vertical_info = 0;
+
+            /* copy the _unscaled_ advance width */
+            metrics.horiAdvance = decoder.glyph_width;
+            glyph.linearHoriAdvance = decoder.glyph_width;
+            glyph.internal.glyph_transformed = 0;
+
+            has_vertical_info = (face.vertical_info && face.vertical.number_Of_VMetrics > 0 && face.vertical.long_metrics) ? 1 : 0;
+
+            /* get the vertical metrics from the vtmx table if we have one */
+            if (has_vertical_info == 1)
+            {
+                var _ret = face.sfnt.get_metrics(face, 1, glyph_index);
+                metrics.vertBearingY = _ret.bearing;
+                metrics.vertAdvance  = _ret.advance;
+            }
+            else
+            {
+                /* make up vertical ones */
+                if (face.os2.version != 0xFFFF)
+                    metrics.vertAdvance = (face.os2.sTypoAscender - face.os2.sTypoDescender);
+                else
+                    metrics.vertAdvance = (face.horizontal.Ascender - face.horizontal.Descender);
+            }
+
+            glyph.linearVertAdvance = metrics.vertAdvance;
+
+            glyph.format = FT_Common.FT_GLYPH_FORMAT_OUTLINE;
+
+            glyph.outline.flags = 0;
+            if (size != null && size.metrics.y_ppem < 24)
+                glyph.outline.flags |= FT_Common.FT_OUTLINE_HIGH_PRECISION;
+
+            glyph.outline.flags |= FT_Common.FT_OUTLINE_REVERSE_FILL;
+
+            if (!(font_matrix.xx == 0x10000 && font_matrix.yy == 0x10000 && font_matrix.xy == 0 && font_matrix.yx == 0))
+                FT_Outline_Transform(glyph.outline, font_matrix);
+
+            if (!(font_offset.x == 0 && font_offset.y == 0))
+                FT_Outline_Translate(glyph.outline, font_offset.x, font_offset.y);
+
+            advance.x = metrics.horiAdvance;
+            advance.y = 0;
+            FT_Vector_Transform(advance, font_matrix);
+            metrics.horiAdvance = advance.x + font_offset.x;
+
+            advance.x = 0;
+            advance.y = metrics.vertAdvance;
+            FT_Vector_Transform(advance, font_matrix);
+            metrics.vertAdvance = advance.y + font_offset.y;
+
+            if ((load_flags & FT_Common.FT_LOAD_NO_SCALE) == 0 || force_scaling == 1)
+            {
+                /* scale the outline and the metrics */
+                var cur = glyph.outline;
+                var vecs = cur.points;
+                var _vec = 0;
+                var x_scale = glyph.x_scale;
+                var y_scale = glyph.y_scale;
+
+                /* First of all, scale the points */
+                if (hinting == 0 || decoder.builder.hints_funcs == null)
+                    for (var n = cur.n_points; n > 0; n--, _vec++)
+                    {
+                        vecs[_vec].x = FT_MulFix(vecs[_vec].x, x_scale);
+                        vecs[_vec].y = FT_MulFix(vecs[_vec].y, y_scale);
+                    }
+
+                /* Then scale the metrics */
+                metrics.horiAdvance = FT_MulFix(metrics.horiAdvance, x_scale);
+                metrics.vertAdvance = FT_MulFix(metrics.vertAdvance, y_scale);
+            }
+
+            /* compute the other metrics */
+            FT_Outline_Get_CBox(glyph.outline, cbox);
+
+            metrics.width = cbox.xMax - cbox.xMin;
+            metrics.height = cbox.yMax - cbox.yMin;
+
+            metrics.horiBearingX = cbox.xMin;
+            metrics.horiBearingY = cbox.yMax;
+
+            if (has_vertical_info == 1)
+                metrics.vertBearingX = metrics.horiBearingX - parseInt(metrics.horiAdvance / 2);
+            else
+            {
+                if ((load_flags & FT_Common.FT_LOAD_VERTICAL_LAYOUT) != 0)
+                    ft_synthesize_vertical_metrics(metrics, metrics.vertAdvance);
+            }
+        }
+    }
+
+    return error;
+}
+
+/******************************************************************************/
+// driver
+/******************************************************************************/
+function cff_get_kerning(face, left_glyph, right_glyph, kerning)
+{
+    var sfnt = face.sfnt;
+
+    kerning.x = 0;
+    kerning.y = 0;
+
+    if (sfnt != null)
+        kerning.x = sfnt.get_kerning(face, left_glyph, right_glyph);
+
+    return 0;
+}
+
+function cff_Load_Glyph(slot, cffsize, glyph_index, load_flags)
+{
+    var size = cffsize;
+    if (slot == null)
+        return FT_Common.FT_Err_Invalid_Slot_Handle;
+
+    /* check whether we want a scaled outline or bitmap */
+    if (size == null)
+        load_flags |= FT_Common.FT_LOAD_NO_SCALE | FT_Common.FT_LOAD_NO_HINTING;
+
+    /* reset the size object if necessary */
+    if (load_flags & FT_Common.FT_LOAD_NO_SCALE)
+        size = null;
+
+    if (size != null)
+    {
+        /* these two objects must have the same parent */
+        if (cffsize.face != slot.face)
+            return FT_Common.FT_Err_Invalid_Face_Handle;
+    }
+
+    /* now load the glyph outline if necessary */
+    var error = cff_slot_load(slot, size, glyph_index, load_flags);
+
+    /* force drop-out mode to 2 - irrelevant now */
+    /* slot->outline.dropout_mode = 2; */
+    return error;
+}
+
+function cff_get_advances(face, start, count, flags, advances)
+{
+    var slot = face.glyph;
+    var error = 0;
+    flags |= FT_Common.FT_LOAD_ADVANCE_ONLY;
+
+    for (var nn = 0; nn < count; nn++)
+    {
+        error = cff_Load_Glyph(slot, face.size, start + nn, flags);
+        if (error )
+            break;
+
+        advances[nn] = (flags & FT_Common.FT_LOAD_VERTICAL_LAYOUT) ? slot.linearVertAdvance : slot.linearHoriAdvance;
+    }
+
+    return error;
+}
+
+function cff_get_glyph_name(face, glyph_index, buffer, buffer_max)
+{
+    var font = face.extra.data;
+
+    if (font.psnames == null)
+        return FT_Common.FT_Err_Unknown_File_Format;
+
+    /* first, locate the sid in the charset table */
+    var sid = font.charset.sids[glyph_index];
+
+    /* now, lookup the name itself */
+    var gname = cff_index_get_sid_string(font, sid);
+
+    if (gname != null)
+        _mem_strcpyn1(buffer, gname, buffer_max);
+        
+    return 0;
+}
+
+function cff_get_name_index(face, glyph_name)
+{
+    var cff = face.extra.data;
+    var charset = cf.charset;
+
+    var psnames = FT_FACE_FIND_GLOBAL_SERVICE(face, FT_SERVICE_ID_POSTSCRIPT_CMAPS);
+    if (psnames == null)
+        return 0;
+
+    var sid = 0;
+    var name = "";
+    for (var i = 0; i < cff.num_glyphs; i++)
+    {
+        sid = charset.sids[i];
+
+        if (sid > 390)
+            name = cff_index_get_string(cff, sid - 391);
+        else
+            name = psnames.adobe_std_strings(sid);
+
+        if (name == null || name == "")
+            continue;
+
+        if (glyph_name == name)
+            return i;
+    }
+    return 0;
+}
+
+var cff_service_glyph_dict = new FT_Service_GlyphDictRec(cff_get_glyph_name, cff_get_name_index);
+
+function cff_ps_has_glyph_names(face)
+{
+    return ((face.face_flags & FT_Common.FT_FACE_FLAG_GLYPH_NAMES) > 0) ? 1 : 0;
+}
+
+function cff_ps_get_font_info(face)
+{
+    var cff = face.extra.data;
+    var font_info = null;
+    if (cff != null && cff.font_info == null)
+    {
+        var dict = cff.top_font.font_dict;
+        font_info = new PS_FontInfoRec();
+
+        font_info.version = cff_index_get_sid_string(cff, dict.version);
+        font_info.notice = cff_index_get_sid_string(cff, dict.notice);
+        font_info.full_name = cff_index_get_sid_string(cff, dict.full_name);
+        font_info.family_name = cff_index_get_sid_string(cff, dict.family_name);
+        font_info.weight = cff_index_get_sid_string(cff, dict.weight);
+
+        font_info.italic_angle        = dict.italic_angle;
+        font_info.is_fixed_pitch      = dict.is_fixed_pitch;
+        font_info.underline_position  = dict.underline_position;
+        font_info.underline_thickness = dict.underline_thickness;
+
+        cff.font_info = font_info;
+    }
+    return { err : 0, font_info : font_info };
+}
+
+var cff_service_ps_info = new FT_Service_PsInfoRec(cff_ps_get_font_info, null, cff_ps_has_glyph_names, null, null);
+
+function cff_get_ps_name(face)
+{
+    return face.extra.data.font_name;
+}
+
+var cff_service_ps_name = new FT_Service_PsFontNameRec(cff_get_ps_name);
+
+function cff_get_cmap_info(charmap, cmap_info)
+{
+    var cmap = charmap.cmap;
+    var library = __FT_CMapRec(cmap).charmap.face.driver.library;
+
+    cmap_info.language = 0;
+    cmap_info.format = 0;
+
+    var error = 0;
+    if (cmap.clazz != FT_CFF_CMAP_ENCODING_CLASS_REC_GET && cmap.clazz != FT_CFF_CMAP_UNICODE_CLASS_REC_GET)
+    {
+        var sfnt = library.FT_Get_Module("sfnt");
+        var service = ft_module_get_service(sfnt, FT_SERVICE_ID_TT_CMAP);
+
+        if (service != null && service.get_cmap_info != null)
+            error = service.get_cmap_info(charmap, cmap_info);
+    }
+    return error;
+}
+
+var cff_service_get_cmap_info = new FT_Service_TTCMapsRec(cff_get_cmap_info);
+
+function cff_get_ros(face, registry, ordering, supplement)
+{
+    var ret = {err : 0, registry : "", ordering : "", supplement : 0};
+    var cff = face.extra.data;
+
+    if (cff != null)
+    {
+        var dict = cff.top_font.font_dict;
+
+        if (dict.cid_registry == 0xFFFF)
+        {
+            ret.err = FT_Common.FT_Err_Invalid_Argument;
+            return ret;
+        }
+
+        if (cff.registry == null)
+            cff.registry = cff_index_get_sid_string(cff, dict.cid_registry);
+        ret.registry = cff.registry;
+
+        if (cff.ordering == null)
+            cff.ordering = cff_index_get_sid_string(cff, dict.cid_ordering);
+        ret.ordering = cff.ordering;
+
+        /*
+         * XXX: According to Adobe TechNote #5176, the supplement in CFF
+         *      can be a real number. We truncate it to fit public API
+         *      since freetype-2.3.6.
+         */
+        ret.supplement = dict.cid_supplement;
+    }
+
+    return error;
+}
+
+function cff_get_is_cid(face)
+{
+    var ret = {err : 0, is_cid : 0};
+    var cff = face.extra.data;
+
+    if (cff != null)
+    {
+        var dict = cff.top_font.font_dict;
+
+        if (dict.cid_registry != 0xFFFF)
+            ret.is_cid = 1;
+    }
+
+    return ret;
+}
+
+function cff_get_cid_from_glyph_index(face, glyph_index)
+{
+    var ret = { err : 0, cid : 0};
+    var cff = face.extra.data;
+
+    if (cff != null)
+    {
+        var dict = cff.top_font.font_dict;
+
+        if (dict.cid_registry == 0xFFFF || glyph_index > cff.num_glyphs)
+        {
+            ret.err = FT_Common.FT_Err_Invalid_Argument;
+            return ret;
+        }
+
+        ret.cid = cff.charset.sids[glyph_index];
+    }
+    return ret;
+}
+
+var cff_service_cid_info = new FT_Service_CIDRec(cff_get_ros, cff_get_is_cid, cff_get_cid_from_glyph_index);
+
+var FT_CFF_SERVICE_PS_INFO_GET         = cff_service_ps_info;
+var FT_CFF_SERVICE_GLYPH_DICT_GET      = cff_service_glyph_dict;
+var FT_CFF_SERVICE_PS_NAME_GET         = cff_service_ps_name;
+var FT_CFF_SERVICE_GET_CMAP_INFO_GET   = cff_service_get_cmap_info;
+var FT_CFF_SERVICE_CID_INFO_GET        = cff_service_cid_info;
+var FT_CFF_CMAP_ENCODING_CLASS_REC_GET = cff_cmap_encoding_class_rec;
+var FT_CFF_CMAP_UNICODE_CLASS_REC_GET  = cff_cmap_unicode_class_rec;
+var FT_CFF_FIELD_HANDLERS_GET          = cff_field_handlers;
+
+var cff_services = new Array(6);
+cff_services[0] = new FT_ServiceDescRec(FT_SERVICE_ID_XF86_NAME,FT_XF86_FORMAT_CFF);
+cff_services[1] = new FT_ServiceDescRec(FT_SERVICE_ID_POSTSCRIPT_INFO,FT_CFF_SERVICE_PS_INFO_GET);
+cff_services[2] = new FT_ServiceDescRec(FT_SERVICE_ID_POSTSCRIPT_FONT_NAME,FT_CFF_SERVICE_PS_NAME_GET);
+cff_services[3] = new FT_ServiceDescRec(FT_SERVICE_ID_GLYPH_DICT,FT_CFF_SERVICE_GLYPH_DICT_GET);
+cff_services[4] = new FT_ServiceDescRec(FT_SERVICE_ID_TT_CMAP,FT_CFF_SERVICE_GET_CMAP_INFO_GET);
+cff_services[5] = new FT_ServiceDescRec(FT_SERVICE_ID_CID,FT_CFF_SERVICE_CID_INFO_GET);
+
+var FT_CFF_SERVICES_GET = cff_services;
+
+function cff_get_interface(driver, module_interface)
+{
+    var result = ft_service_list_lookup(FT_CFF_SERVICES_GET, module_interface);
+    if (result != null)
+        return result;
+
+    if (driver == null)
+        return null;
+
+    /* we pass our request to the `sfnt' module */
+    var sfnt = driver.library.FT_Get_Module("sfnt");
+    if (sfnt == null)
+        return null;
+
+    return sfnt.clazz.get_interface(sfnt, module_interface);
+}
+
+function CFF_Driver_Class()
+{
+    this.flags = 0x501;
+    this.name = "cff";
+    this.version = 0x10000;
+    this.requires = 0x20000;
+
+    this.module_interface = null;
+
+    this.init = cff_driver_init;
+    this.done = cff_driver_done;
+    this.get_interface = cff_get_interface;
+
+    this.face_object_size = 0;
+    this.size_object_size = 0;
+    this.slot_object_size = 0;
+
+    this.init_face = cff_face_init;
+    this.done_face = cff_face_done;
+
+    this.init_size = cff_size_init;
+    this.done_size = cff_size_done;
+
+    this.init_slot = cff_slot_init;
+    this.done_slot = cff_slot_done;
+
+    //#ifdef FT_CONFIG_OPTION_OLD_INTERNALS
+    this.set_char_sizes = ft_stub_set_char_sizes;
+    this.set_pixel_sizes = ft_stub_set_pixel_sizes;
+    //#endif
+
+    this.load_glyph = cff_Load_Glyph;
+
+    this.get_kerning = cff_get_kerning;
+    this.attach_file = null;
+    this.get_advances = cff_get_advances;
+
+    this.request_size = cff_size_request;
+    this.select_size = cff_size_select;
+}
+
+function CFF_Driver()
+{
+    this.clazz = null;      // FT_Module_Class
+    this.library = null;    // FT_Library
+    this.memory = null;     // FT_Memory
+    this.generic = null;    // FT_Generic
+
+    this.clazz = new CFF_Driver_Class();
+    this.faces_list = [];
+    this.extensions = null;
+    this.glyph_loader = null;
+
+    this.extension_component = null;
+
+    this.open_face = function(stream, face_index)
+    {
+        FT_Error = 0;
+        var face = new TT_Face();
+        var internal = new FT_Face_Internal();
+
+        face.driver = this;
+        face.memory = this.memory;
+        face.stream = stream;
+
+        //#ifdef FT_CONFIG_OPTION_INCREMENTAL
+        face.internal = internal;
+        face.internal.incremental_interface = null;
+        //#endif
+
+        var err1 = this.clazz.init_face(stream, face, face_index);
+
+        if (err1 != 0)
+        {
+            face = null;
+            FT_Error = err1;
+            return null;
+        }
+
+        var err2 = find_unicode_charmap(face);
+        if (err2 != 0 && err2 != FT_Common.FT_Err_Invalid_CharMap_Handle)
+        {
+            face = null;
+            FT_Error = err2;
+            return null;
+        }
+
+		FT_Error = 0;
+        return face;
+    }
+}
+
+function create_cff_driver(library)
+{
+    var driver = new CFF_Driver();
+    driver.library = library;
+    driver.memory = library.Memory;
+
+    return driver;
+}
\ No newline at end of file
diff --git a/Common/FontsFreeType/Private/FreeType/drivers/cid.js b/Common/FontsFreeType/Private/FreeType/drivers/cid.js
new file mode 100644
index 0000000000000000000000000000000000000000..65d1f80bcdcf1f6eb62780ef1fd01e3f5dd3457a
--- /dev/null
+++ b/Common/FontsFreeType/Private/FreeType/drivers/cid.js
@@ -0,0 +1,1515 @@
+/******************************************************************************/
+// cidgload
+/******************************************************************************/
+function cid_load_glyph(decoder, glyph_index)
+{
+    var face = decoder.builder.face;
+    var cid  = face.cid;
+    var memory = face.memory;
+    var fd_select;
+    var stream       = face.cid_stream;
+    var error        = 0;
+    var charstring   = null;
+    var glyph_length = 0;
+    var psaux = face.psaux;
+
+    //#ifdef FT_CONFIG_OPTION_INCREMENTAL
+    var inc = face.internal.incremental_interface;
+    //#endif
+
+    //#ifdef FT_CONFIG_OPTION_INCREMENTAL
+    if (inc != null)
+    {
+        var glyph_data = new FT_Data();
+
+        error = inc.funcs.get_glyph_data(inc.object, glyph_index, glyph_data);
+        if (error != 0)
+            return error;
+
+        var p = glyph_data.pointer;
+        fd_select = cid_get_offset(p, cid.fd_bytes);
+
+        if (glyph_data.length != 0)
+        {
+            glyph_length = glyph_data.length - cid.fd_bytes;
+            charstring = memory.Alloc(glyph_length);
+
+            var _data = glyph_data.pointer.data;
+            var _start = glyph_data.pointer.pos + cid.fd_bytes;
+            for (var i = 0; i < glyph_length; i++)
+                charstring[i] = _data[_start + i];
+        }
+
+        inc.funcs.free_glyph_data(inc.object, glyph_data);
+        glyph_data = null;
+    }
+    else
+    {
+        //#endif /* FT_CONFIG_OPTION_INCREMENTAL */
+        var entry_len = cid.fd_bytes + cid.gd_bytes;
+
+        error = stream.Seek(cid.data_offset + cid.cidmap_offset + glyph_index * entry_len);
+        if (error != 0)
+            return error;
+
+        error = stream.EnterFrame(2 * entry_len);
+        if (error != 0)
+            return error;
+
+        var p = new CPointer();
+        p.data = stream.data;
+        p.pos = stream.cur;
+        fd_select = cid_get_offset(p, cid.fd_bytes);
+        var off1 = cid_get_offset(p, cid.gd_bytes);
+        p.pos += cid.fd_bytes;
+        glyph_length = cid_get_offset(p, cid.gd_bytes) - off1;
+
+        stream.ExitFrame();
+
+        if (fd_select >= cid.num_dicts)
+            return FT_Common.FT_Err_Invalid_Offset;
+        if (glyph_length == 0)
+            return error;
+
+        charstring = memory.Alloc(glyph_length);
+        error = stream.ReadAt(cid.data_offset + off1, charstring, glyph_length);
+        if (error != 0)
+            return error;
+    }
+
+    var cid_subrs = face.subrs[fd_select];
+
+
+    /* Set up subrs */
+    decoder.num_subrs = cid_subrs.num_subrs;
+    decoder.subrs     = cid_subrs.code;
+    decoder.subrs_len = 0;
+
+    /* Set up font matrix */
+    var dict = cid.font_dicts[fd_select];
+
+    decoder.font_matrix = dublicate_matrix(dict.font_matrix);
+    decoder.font_offset = dublicate_vector(dict.font_offset);
+    decoder.lenIV       = dict.private_dict.lenIV;
+
+    /* Decode the charstring. */
+
+    /* Adjustment for seed bytes. */
+    var cs_offset = (decoder.lenIV >= 0 ? decoder.lenIV : 0);
+
+    /* Decrypt only if lenIV >= 0. */
+    if (decoder.lenIV >= 0)
+        psaux.t1_decrypt(charstring, glyph_length, 4330);
+
+    error = decoder.funcs.parse_charstrings(decoder, charstring + cs_offset, glyph_length - cs_offset);
+    charstring = null;
+
+    //#ifdef FT_CONFIG_OPTION_INCREMENTAL
+    if (!error && inc && inc.funcs.get_glyph_metrics)
+    {
+        var metrics = new FT_Incremental_MetricsRec();
+
+        metrics.bearing_x = (FT_RoundFix(decoder.builder.left_bearing.x) >> 16);
+        metrics.bearing_y = 0;
+        metrics.advance   = (FT_RoundFix(decoder.builder.advance.x) >> 16);
+        metrics.advance_v = (FT_RoundFix(decoder.builder.advance.y) >> 16);
+
+        error = inc.funcs.get_glyph_metrics(inc.object, glyph_index, false, metrics);
+
+        decoder.builder.left_bearing.x = (metrics.bearing_x << 16);
+        decoder.builder.advance.x      = (metrics.advance << 16);
+        decoder.builder.advance.y      = (metrics.advance_v << 16);
+    }
+    //#endif /* FT_CONFIG_OPTION_INCREMENTAL */
+
+    return error;
+}
+
+function cid_slot_load_glyph(glyph, cidsize, glyph_index, load_flags)
+{
+    var error = null;
+    var decoder = new T1_DecoderRec();
+    var face = glyph.face;
+
+    var psaux = face.psaux;
+
+    if (glyph_index >= face.num_glyphs)
+        return FT_Common.FT_Err_Invalid_Argument;
+
+    if (load_flags & FT_Common.FT_LOAD_NO_RECURSE)
+        load_flags |= (FT_Common.FT_LOAD_NO_SCALE | FT_Common.FT_LOAD_NO_HINTING);
+
+    glyph.x_scale = cidsize.metrics.x_scale;
+    glyph.y_scale = cidsize.metrics.y_scale;
+
+    glyph.outline.n_points   = 0;
+    glyph.outline.n_contours = 0;
+
+    var hinting = ((load_flags & FT_Common.FT_LOAD_NO_SCALE) == 0 && (load_flags & FT_Common.FT_LOAD_NO_HINTING) == 0) ? 1 : 0;
+    glyph.format = FT_Common.FT_GLYPH_FORMAT_OUTLINE;
+
+    error = psaux.t1_decoder_funcs.init(decoder, glyph.face, cidsize, glyph, null, null, hinting, FT_LOAD_TARGET_MODE(load_flags), cid_load_glyph);
+    if (error != 0)
+        return error;
+
+    /* TODO: initialize decoder.len_buildchar and decoder.buildchar */
+    /*       if we ever support CID-keyed multiple master fonts     */
+
+    /* set up the decoder */
+    decoder.builder.no_recurse = ((load_flags & FT_Common.FT_LOAD_NO_RECURSE) != 0);
+
+    error = cid_load_glyph(decoder, glyph_index);
+    if (error != 0)
+        return error;
+
+    var font_matrix = dublicate_matrix(decoder.font_matrix);
+    var font_offset = dublicate_vector(decoder.font_offset);
+
+    /* save new glyph tables */
+    psaux.t1_decoder_funcs.done(decoder);
+    decoder = null;
+
+    /* now set the metrics -- this is rather simple, as    */
+    /* the left side bearing is the xMin, and the top side */
+    /* bearing the yMax                                    */
+    glyph.outline.flags &= FT_Common.FT_OUTLINE_OWNER;
+    glyph.outline.flags |= FT_Common.FT_OUTLINE_REVERSE_FILL;
+
+    /* for composite glyphs, return only left side bearing and */
+    /* advance width                                           */
+    if (load_flags & FT_Common.FT_LOAD_NO_RECURSE)
+    {
+        var internal = glyph.internal;
+
+        glyph.metrics.horiBearingX = (FT_RoundFix(decoder.builder.left_bearing.x) >> 16);
+        glyph.metrics.horiAdvance = (FT_RoundFix(decoder.builder.advance.x) >> 16);
+
+        internal.glyph_matrix      = dublicate_matrix(font_matrix);
+        internal.glyph_delta       = dublicate_vector(font_offset);
+        internal.glyph_transformed = 1;
+    }
+    else
+    {
+        var metrics = glyph.metrics;
+
+        /* copy the _unscaled_ advance width */
+        metrics.horiAdvance = (FT_RoundFix(decoder.builder.advance.x) >> 16);
+        glyph.linearHoriAdvance = (FT_RoundFix(decoder.builder.advance.x) >> 16);
+        glyph.internal.glyph_transformed = 0;
+
+        /* make up vertical ones */
+        metrics.vertAdvance = (face.cid.font_bbox.yMax - face.cid.font_bbox.yMin) >> 16;
+        glyph.linearVertAdvance = metrics.vertAdvance;
+        glyph.format            = FT_Common.FT_GLYPH_FORMAT_OUTLINE;
+
+        if (cidsize.metrics.y_ppem < 24)
+            cidglyph.outline.flags |= FT_Common.FT_OUTLINE_HIGH_PRECISION;
+
+        /* apply the font matrix */
+        FT_Outline_Transform(glyph.outline, font_matrix);
+        FT_Outline_Translate(glyph.outline, font_offset.x, font_offset.y);
+
+        var advance = new FT_Vector();
+        advance.x = metrics.horiAdvance;
+        advance.y = 0;
+        FT_Vector_Transform(advance, font_matrix);
+        metrics.horiAdvance = advance.x + font_offset.x;
+
+        advance.x = 0;
+        advance.y = metrics.vertAdvance;
+        FT_Vector_Transform(advance, font_matrix);
+        metrics.vertAdvance = advance.y + font_offset.y;
+
+        if ((load_flags & FT_Common.FT_LOAD_NO_SCALE) == 0)
+        {
+            /* scale the outline and the metrics */
+            var cur = decoder.builder.base;
+            var vec = cur.points;
+            var x_scale = glyph.x_scale;
+            var y_scale = glyph.y_scale;
+
+            /* First of all, scale the points */
+            if (!hinting || decoder.builder.hints_funcs == null)
+            {
+                for (var n = cur.n_points; n > 0; n--, vec++)
+                {
+                    cur.points[vec].x = FT_MulFix(cur.points[vec].x, x_scale);
+                    cur.points[vec].y = FT_MulFix(cur.points[vec].y, y_scale);
+                }
+            }
+
+            /* Then scale the metrics */
+            metrics.horiAdvance = FT_MulFix(metrics.horiAdvance, x_scale);
+            metrics.vertAdvance = FT_MulFix(metrics.vertAdvance, y_scale);
+        }
+
+        /* compute the other metrics */
+        var cbox = new FT_BBox();
+        FT_Outline_Get_CBox(glyph.outline, cbox);
+
+        metrics.width  = cbox.xMax - cbox.xMin;
+        metrics.height = cbox.yMax - cbox.yMin;
+
+        metrics.horiBearingX = cbox.xMin;
+        metrics.horiBearingY = cbox.yMax;
+
+        if (load_flags & FT_Common.FT_LOAD_VERTICAL_LAYOUT)
+        {
+            /* make up vertical ones */
+            ft_synthesize_vertical_metrics(metrics, metrics.vertAdvance);
+        }
+    }
+
+    return error;
+}
+
+/******************************************************************************/
+// cidparse
+/******************************************************************************/
+function CID_Parser()
+{
+    this.root = new PS_ParserRec();
+    this.stream = null;
+
+    this.postscript = null;
+    this.postscript_len = 0;
+
+    this.data_offset = 0;
+    this.binary_length = 0;
+
+    this.cid = null;
+    this.num_dict = 0;
+
+    this.clear = function()
+    {
+        this.root.cursor = 0;
+        this.root.base = null;
+        this.root.limit = 0;
+        this.root.error = 0;
+        this.root.memory = null;
+
+        this.funcs = null;
+
+        this.stream = null;
+
+        this.postscript = null;
+        this.postscript_len = 0;
+
+        this.data_offset = 0;
+        this.binary_length = 0;
+
+        this.cid = null;
+        this.num_dict = 0;
+    }
+}
+
+function cid_parser_new(parser, stream, memory, psaux)
+{
+    parser.clear();
+    psaux.ps_parser_funcs.init(parser.root, null, 0, memory);
+
+    parser.stream = stream;
+
+    var base_offset = stream.pos;
+    var offset = 0;
+
+    /* first of all, check the font format in the header */
+    var error = stream.EnterFrame(31);
+    if (error != 0)
+        return error;
+
+    var cur_str = stream.GetString1(31);
+    if (cur_str != "%!PS-Adobe-3.0 Resource-CIDFont")
+        return FT_Common.FT_Err_Unknown_File_Format;
+
+    stream.ExitFrame();
+
+    /* now, read the rest of the file until we find */
+    /* `StartData' or `/sfnts'                      */
+    var limit = 0;
+    while (true)
+    {
+        var buffer = memory.Alloc(256 + 10);
+        var read_len = 256 + 10; /* same as signed FT_Stream->size */
+        var p = dublicate_pointer(buffer);
+
+        for (offset = stream.pos; ; offset += 256)
+        {
+            var stream_len = stream.size - stream.pos;/* same as signed FT_Stream->size */
+            if (stream_len == 0)
+                return FT_Common.FT_Err_Unknown_File_Format;
+
+            read_len = Math.min(read_len, stream_len);
+
+            error = stream.Read(p, read_len);
+            if (error != 0)
+                return error;
+
+            if (read_len < 256)
+                p[read_len] = FT_Common.SYMBOL_CONST_S0;
+
+            limit = p.pos + read_len - 10;
+
+            p.pos = buffer.pos;
+
+            var bIsGoToFound = 0;
+            for (; p.pos < limit; p.pos++)
+            {
+                if ((p.data[p.pos] == FT_Common.SYMBOL_CONST_S) && (_strncmp_data(p, "StartData", 9) == 0))
+                {
+                    /* save offset of binary data after `StartData' */
+                    offset += (p.pos - buffer.pos + 10);
+                    bIsGoToFound = 1;
+                    break;
+                }
+                else if ((p.data[p.pos + 1] == FT_Common.SYMBOL_CONST_s) && (_strncmp_data(p, "/sfnts", 6) == 0))
+                {
+                    offset += (p.pos - buffer.pos + 7);
+                    bIsGoToFound = 1;
+                    break;
+                }
+            }
+
+            if (bIsGoToFound == 1)
+                break;
+
+            var _dd = p.data;
+            var __s1 = buffer.pos;
+            var __s2 = p.pos;
+
+            var arr_move = memory.Alloc(10);
+            for (var i = 0; i < 10; i++)
+                arr_move[i] = _dd[__s2 + i];
+
+            for (var i = 0; i < 10; i++)
+                _dd[__s1 + i] = arr_move[i];
+
+            arr_move = null;
+
+            read_len = 256;
+            p.pos = buffer.pos + 10;
+        }
+
+        /* We have found the start of the binary data or the `/sfnts' token. */
+        /* Now rewind and extract the frame corresponding to this PostScript */
+        /* section.                                                          */
+        var ps_len = offset - base_offset;
+
+        error = stream.Seek(base_offset);
+        if (error != 0)
+            return error;
+
+        parser.postscript = new CPointer();
+        error = stream.ExtractFrame(ps_len, parser.postscript);
+
+        if (error != 0)
+            return error;
+
+        parser.data_offset    = offset;
+        parser.postscript_len = ps_len;
+        parser.root.base      = dublicate_pointer(parser.postscript);
+        parser.root.cursor    = 0;
+        parser.root.limit     = parser.postscript.pos + ps_len;
+        parser.num_dict       = -1;
+
+        /* Finally, we check whether `StartData' or `/sfnts' was real --  */
+        /* it could be in a comment or string.  We also get the arguments */
+        /* of `StartData' to find out whether the data is represented in  */
+        /* binary or hex format.                                          */
+
+        var arg1 = dublicate_pointer(parser.root.base);
+        arg1.pos += parser.root.cursor;
+        parser.root.funcs.skip_PS_token(p.root);
+        parser.root.funcs.skip_spaces(p.root);
+
+        var arg2 = dublicate_pointer(parser.root.base);
+        arg2.pos += parser.root.cursor;
+        parser.root.funcs.skip_PS_token(p.root);
+        parser.root.funcs.skip_spaces(p.root);
+
+        limit = parser.root.limit;
+        var cur = dublicate_pointer(parser.root.base);
+        cur.pos += parser.root.cursor;
+
+        while (cur.pos < limit)
+        {
+            if (parser.root.error != 0)
+                return parser.root.error;
+
+            if ((cur.data[cur.pos] == FT_Common.SYMBOL_CONST_S) && (_strncmp_data(cur, "StartData", 9) == 0))
+            {
+                if (_strncmp_data(arg1, "(Hex)", 5) == 0)
+                {
+                    var _num_s = "";
+                    var ii = 0;
+                    while (true)
+                    {
+                        if (arg2.data[arg2.pos + ii] == FT_Common.SYMBOL_CONST_S0)
+                            break;
+                        _num_s += String.fromCharCode(arg2.data[arg2.pos + ii]);
+                    }
+                    parser.binary_length = parseInt(_num_s);
+                }
+
+                limit = parser.root.limit;
+                cur.pos = parser.root.base.pos + parser.root.cursor;
+                return error;
+            }
+            else if ((cur.data[cur.pos + 1] == FT_Common.SYMBOL_CONST_s) && (_strncmp_data(cur, "/sfnts", 6) == 0))
+            {
+                return FT_Common.FT_Err_Unknown_File_Format;
+            }
+
+            parser.root.funcs.skip_PS_token(p.root);
+            parser.root.funcs.skip_spaces(p.root);
+
+            arg1.pos = arg2.pos;
+            arg2.pos = cur.pos;
+            cur.pos = parser.root.base.pos + parser.root.cursor;
+        }
+
+        /* we haven't found the correct `StartData'; go back and continue */
+        /* searching                                                      */
+        stream.ReleaseFrame();
+        parser.postscript = null;
+
+        error = stream.Seek(offset);
+        if (error != 0)
+            break;
+    }
+
+    return error;
+}
+
+function cid_parser_done(parser)
+{
+    /* always free the private dictionary */
+    if (parser.postscript != null)
+    {
+        parser.stream.ReleaseFrame();
+        parser.postscript = null;
+    }
+    parser.root.funcs.done(parser.root);
+}
+
+
+/******************************************************************************/
+// cidload
+/******************************************************************************/
+function CID_Loader()
+{
+    this.parser = new CID_Parser();
+    this.num_chars = 0;
+
+    this.clear = function()
+    {
+        this.parser.clear();
+        this.num_chars = 0;
+    }
+}
+
+function cid_get_offset(start, offsize)
+{
+    var result = 0;
+    for (; offsize > 0; offsize--)
+    {
+        result <<= 8;
+        result |= start.data[start.pos++];
+    }
+    return result;
+}
+function cid_load_keyword(face, loader, keyword)
+{
+    var error = 0;
+    var parser = loader.parser;
+    var object = null;
+    var cid = face.cid;
+
+    if (keyword.type == FT_Common.T1_FIELD_TYPE_CALLBACK)
+    {
+        keyword.reader(face, parser);
+        error = parser.error;
+        return error;
+    }
+
+    switch (keyword.location)
+    {
+        case FT_Common.T1_FIELD_LOCATION_CID_INFO:
+            object = cid;
+            break;
+        case FT_Common.T1_FIELD_LOCATION_FONT_INFO:
+            object = cid.font_info;
+            break;
+        case FT_Common.T1_FIELD_LOCATION_FONT_EXTRA:
+            object = face.font_extra;
+            break;
+        case FT_Common.T1_FIELD_LOCATION_BBOX:
+            object = cid.font_bbox;
+            break;
+        default:
+        {
+            if (parser.num_dict < 0 || parser.num_dict >= cid.num_dicts)
+                return FT_Error.FT_Err_Syntax_Error;
+
+            var dict = cid.font_dicts[parser.num_dict];
+            switch (keyword.location)
+            {
+                case FT_Common.T1_FIELD_LOCATION_PRIVATE:
+                    object = dict.private_dict;
+                    break;
+                default:
+                    object = dict;
+            }
+        }
+    }
+
+    var dummy_object = new Array(1);
+    dummy_object[0] = object;
+
+    if (keyword.type == FT_Common.T1_FIELD_TYPE_INTEGER_ARRAY || keyword.type == FT_Common.T1_FIELD_TYPE_FIXED_ARRAY)
+        error = loader.parser.root.funcs.load_field_table(loader.parser.root, keyword, dummy_object, 0, 0);
+    else
+        error = loader.parser.root.funcs.load_field(loader.parser.root, keyword, dummy_object, 0, 0);
+
+    return error;
+}
+
+function parse_font_matrix(face, parser)
+{
+    var temp = new Array(6);
+    if (parser.num_dict >= 0 && parser.num_dict < face.cid.num_dicts)
+    {
+        var dict = face.cid.font_dicts[parser.num_dict];
+        var matrix = dict.font_matrix;
+        var offset = dict.font_offset;
+
+        parser.root.funcs.to_fixed_array(parser.root, 6, temp, 3);
+
+        var temp_scale = Math.abs(temp[3]);
+
+        /* Set units per EM based on FontMatrix values.  We set the value to */
+        /* `1000/temp_scale', because temp_scale was already multiplied by   */
+        /* 1000 (in `t1_tofixed', from psobjs.c).                            */
+        face.units_per_EM = (FT_DivFix(0x10000, FT_DivFix(temp_scale, 1000)));
+        if (face.units_per_EM > 0xFFFF)
+            face.units_per_EM = 0xFFFF;
+
+        /* we need to scale the values by 1.0/temp[3] */
+        if (temp_scale != 0x10000)
+        {
+            temp[0] = FT_DivFix(temp[0], temp_scale);
+            temp[1] = FT_DivFix(temp[1], temp_scale);
+            temp[2] = FT_DivFix(temp[2], temp_scale);
+            temp[4] = FT_DivFix(temp[4], temp_scale);
+            temp[5] = FT_DivFix(temp[5], temp_scale);
+            temp[3] = 0x10000;
+        }
+
+        matrix.xx = temp[0];
+        matrix.yx = temp[1];
+        matrix.xy = temp[2];
+        matrix.yy = temp[3];
+
+        /* note that the font offsets are expressed in integer font units */
+        offset.x  = temp[4] >> 16;
+        offset.y  = temp[5] >> 16;
+    }
+
+    return 0;
+}
+
+function parse_fd_array(face, parser)
+{
+    var cid = face.cid;
+    var error = 0;
+
+    var num_dicts = parser.root.funcs.to_int(parser.root);
+
+    if (cid.font_dicts == null)
+    {
+        cid.font_dicts = new Array(num_dicts);
+        for (var i = 0; i < num_dicts; i++)
+        {
+            cid.font_dicts[i] = new CID_FaceDictRec();
+            cid.font_dicts[i].private_dict.lenIV = 4;
+        }
+        cid.num_dicts = num_dicts;
+    }
+    return error;
+}
+
+function parse_expansion_factor(face, parser)
+{
+    if (parser.num_dict >= 0 && parser.num_dict < face.cid.num_dicts)
+    {
+        var dict = face.cid.font_dicts[parser.num_dict];
+
+        dict.expansion_factor              = parser.root.funcs.to_fixed(parser.root, 0);
+        dict.private_dict.expansion_factor = dict.expansion_factor;
+    }
+    return 0;
+}
+
+function cid_parse_dict(face, loader, base, size)
+{
+    var parser = loader.parser;
+
+    parser.root.cursor = dublicate_pointer(base);
+    parser.root.limit  = base.pos + size;
+    parser.root.error  = 0;
+
+    var cur = dublicate_pointer(base);
+    var limit = cur.pos + size;
+
+    var newlimit = 0;
+
+    while (true)
+    {
+        parser.root.cursor = cur.pos;
+        parser.root.funcs.skip_spaces(parser.root);
+
+        if (parser.root.cursor.pos >= limit)
+            newlimit = limit - 1 - 17;
+        else
+            newlimit = parser.root.cursor.pos - 17;
+
+        /* look for `%ADOBeginFontDict' */
+        for (; cur.pos < newlimit; cur.pos++)
+        {
+            if (cur.data[cur.pos] == FT_Common.SYMBOL_CONST_MATH_3 && _strncmp_data(cur, "%ADOBeginFontDict", 17) == 0)
+            {
+                /* if /FDArray was found, then cid->num_dicts is > 0, and */
+                /* we can start increasing parser->num_dict               */
+                if (face.cid.num_dicts > 0)
+                    parser.num_dict++;
+            }
+        }
+
+        cur.pos = parser.root.cursor.pos;
+        /* no error can occur in cid_parser_skip_spaces */
+        if (cur.pos >= limit)
+            break;
+
+        parser.root.funcs.skip_PS_token(parser.root);
+        if (parser.root.cursor.pos >= limit || parser.root.error != 0)
+            break;
+
+        /* look for immediates */
+        if (cur.data[cur.pos] == FT_Common.SYMBOL_CONST_BS && cur.pos + 2 < limit)
+        {
+            cur.pos++;
+            var len = parser.root.cursor.pos - cur.pos;
+
+            if (len > 0 && len < 22)
+            {
+                /* now compare the immediate name to the keyword table */
+                var keyword = 0;
+                var keywords_count = cid_field_records.length;
+
+                while (true)
+                {
+                    if (keyword >= keywords_count)
+                        break;
+
+                    var _key = cid_field_records[keyword];
+
+                    if (cur.data[cur.pos] == _key.ident.charCodeAt(0) && len == _key.ident.length)
+                    {
+                        var n;
+                        for (n = 1; n < len; n++)
+                            if (cur.data[cur.pos + n] != _key.ident.charCodeAt(n))
+                                break;
+
+                        if (n >= len)
+                        {
+                            /* we found it - run the parsing callback */
+                            parser.root.error = cid_load_keyword(face, loader, keyword);
+                            if (parser.root.error)
+                                return parser.root.error;
+                            break;
+                        }
+                    }
+                    keyword++;
+                }
+            }
+        }
+
+        cur.pos = parser.root.cursor.pos;
+    }
+    return parser.root.error;
+}
+
+function cid_read_subrs(face)
+{
+    var cid = face.cid;
+    var memory = face.memory;
+    var stream = face.cid_stream;
+    var error = 0;
+    var n = 0;
+
+    var _num_dicts = cid.num_dicts;
+    face.subrs = new Array(_num_dicts);
+    var subrs = face.subrs;
+
+    for (n = 0; n < _num_dicts; n++)
+        subrs[n] = new CID_SubrsRec();
+
+    var subr = 0;
+    var max_offsets = 0;
+    var offsets = [];
+    var psaux = face.psaux;
+
+    for (n = 0; n < _num_dicts; n++, subr++)
+    {
+        var dict = cid.font_dicts[n];
+        var lenIV = dict.private_dict.lenIV;
+        var count, num_subrs = dict.num_subrs;
+
+        /* Check for possible overflow. */
+        if (num_subrs == 0xFFFFFFFF)
+        {
+            face.subrs = null;
+            offsets = null;
+            return FT_Common.FT_Err_Syntax_Error;
+        }
+
+        /* reallocate offsets array if needed */
+        if (num_subrs + 1 > max_offsets)
+        {
+            var new_max = (num_subrs + 4) & (~3);
+
+            if ( new_max <= max_offsets )
+            {
+                face.subrs = null;
+                offsets = null;
+                return FT_Common.FT_Err_Syntax_Error;
+            }
+
+            for (var i = max_offsets; i < new_max; i++)
+                offsets[i] = 0;
+
+            max_offsets = new_max;
+        }
+
+        /* read the subrmap's offsets */
+        error = stream.Seek(cid.data_offset + dict.subrmap_offset);
+        if (error == 0)
+            error = stream.EnterFrame((num_subrs + 1) * dict.sd_bytes);
+
+        if (error != 0)
+        {
+            face.subrs = null;
+            offsets = null;
+            return error;
+        }
+
+        var p = new CPointer;
+        p.data = stream.data;
+        p.pos = stream.cur;
+        for (count = 0; count <= num_subrs; count++)
+            offsets[count] = cid_get_offset(p, dict.sd_bytes);
+
+        stream.ExitFrame();
+
+        /* offsets must be ordered */
+        for (count = 1; count <= num_subrs; count++)
+        {
+            if (offsets[count - 1] > offsets[count])
+            {
+                face.subrs = null;
+                offsets = null;
+                return error;
+            }
+        }
+
+        /* now, compute the size of subrs charstrings, */
+        /* allocate, and read them                     */
+        var data_len = offsets[num_subrs] - offsets[0];
+
+        subrs[subr].code = new Array(num_subrs + 1);
+        subrs[subr].code[0] = memory.Alloc(data_len);
+
+        error = stream.Seek(cid.data_offset + offsets[0]);
+        if (error == 0)
+            error = stream.Read(subrs[subr].code[0], data_len);
+
+        if (error != 0)
+        {
+            face.subrs = null;
+            offsets = null;
+            return error;
+        }
+
+        /* set up pointers */
+        for (count = 1; count <= num_subrs; count++)
+        {
+            var len = offsets[count] - offsets[count - 1];
+            subrs[subr].code[count] = subrs[subr].code[count - 1] + len;
+        }
+
+        /* decrypt subroutines, but only if lenIV >= 0 */
+        if (lenIV >= 0)
+        {
+            for (count = 0; count < num_subrs; count++)
+            {
+                var len = offsets[count + 1] - offsets[count];
+                psaux.t1_decrypt(subrs[subr].code[count], len, 4330);
+            }
+        }
+
+        subrs[subr].num_subrs = num_subrs;
+    }
+
+    offsets = null;
+    return error;
+}
+
+function t1_init_loader(loader, face)
+{
+    loader.clear();
+}
+function t1_done_loader(loader)
+{
+    cid_parser_done(loader.parser);
+}
+
+function cid_hex_to_binary(data, data_len, offset, face)
+{
+    var stream = face.stream;
+
+    var error = stream.Seek(offset);
+    if (error != 0)
+        return error;
+
+    var buffer = face.memoty.Alloc(256);
+    var val = null;
+
+    var d = dublicate_pointer(data);
+    var dlimit = d.pos + data_len;
+    var p = dublicate_pointer(buffer);
+    var plimit = p.pos;
+
+    var upper_nibble = 1;
+    var done = 0;
+
+    while (d.pos < dlimit)
+    {
+        if (p.pos >= plimit)
+        {
+            var oldpos = stream.pos;
+            var size = stream.size - oldpos;
+
+            if (size == 0)
+                return FT_Common.FT_Err_Syntax_Error;
+
+            error = stream.Read(buffer, (256 > size) ? size : 256);
+            if (error != 0)
+                return error;
+
+            p.pos = buffer.pos;
+            plimit = p.pos + stream.pos - oldpos;
+        }
+
+        var _p = p.data[p.pos];
+        if (_p >= FT_Common.SYMBOL_CONST_0 && _p <= FT_Common.SYMBOL_CONST_9)
+            val = _p - FT_Common.SYMBOL_CONST_0;
+        else if (_p >= FT_Common.SYMBOL_CONST_a && _p <= FT_Common.SYMBOL_CONST_f)
+            val = _p - FT_Common.SYMBOL_CONST_a;
+        else if (_p >= FT_Common.SYMBOL_CONST_A && _p <= FT_Common.SYMBOL_CONST_F)
+            val = _p - FT_Common.SYMBOL_CONST_A + 10;
+        else if (_p == FT_Common.SYMBOL_CONST_SPACE || _p == FT_Common.SYMBOL_CONST_ST ||
+            _p == FT_Common.SYMBOL_CONST_SR || _p == FT_Common.SYMBOL_CONST_SN ||
+            _p == FT_Common.SYMBOL_CONST_SF || _p == FT_Common.SYMBOL_CONST_S0)
+        {
+            p.pos++;
+            continue;
+        }
+        else if (_p == FT_Common.SYMBOL_CONST_MATH_2)
+        {
+            val  = 0;
+            done = 1;
+        }
+        else
+        {
+            return FT_Common.FT_Err_Syntax_Error;
+        }
+
+        if (upper_nibble == 1)
+            d.data[d.pos] = (val << 4) & 0xFF;
+        else
+        {
+            d.data[d.pos] = (d.data[d.pos] + val) & 0xFF;
+            d.pos++;
+        }
+
+        upper_nibble = (1 - upper_nibble);
+
+        if (done == 1)
+            break;
+
+        p.pos++;
+    }
+
+    return 0;
+}
+
+function cid_face_open(face, face_index)
+{
+    var loader = new CID_Loader();
+    var memory = face.memory;
+
+    t1_init_loader(loader, face);
+
+    var parser = loader.parser;
+    var error = cid_parser_new(parser, face.stream, memory, face.psaux);
+    if (error != 0)
+    {
+        t1_done_loader(loader);
+        return error;
+    }
+
+    error = cid_parse_dict(face, loader, parser.postscript, parser.postscript_len);
+    if (error != 0)
+    {
+        return error;
+    }
+
+    if (face_index < 0)
+    {
+        t1_done_loader(loader);
+        return error;
+    }
+
+    if (parser.binary_length != 0)
+    {
+        face.binary_data = memory.Alloc(parser.binary_length);
+        /* we must convert the data section from hexadecimal to binary */
+        error = cid_hex_to_binary(face.binary_data, parser.binary_length, parser.data_offset, face);
+        if (error != 0)
+        {
+            t1_done_loader(loader);
+            return error;
+        }
+
+        face.cid_stream = new FT_Stream(face.binary_data.data, parser.binary_length);
+        face.cid.data_offset = 0;
+    }
+    else
+    {
+        face.cid_stream = new FT_Stream(face.stream.data, face.stream.size);
+        face.cid.data_offset = loader.parser.data_offset;
+    }
+
+    error = cid_read_subrs(face);
+
+    t1_done_loader(loader);
+    return error;
+}
+
+/******************************************************************************/
+// objs
+/******************************************************************************/
+function CID_SizeRec()
+{
+    this.root = new FT_Size();
+    this.valid = 0;
+}
+
+function CID_GlyphSlotRec()
+{
+    this.root = new FT_GlyphSlot();
+
+    this.hint = 0;
+    this.scaled = 0;
+
+    this.x_scale = 0;
+    this.y_scale = 0;
+}
+
+function cid_slot_done(_slot)
+{
+    var slot = (slot.hint == undefined) ? _slot : _slot.root;
+    slot.internal.glyph_hints = null;
+}
+
+function cid_slot_init(_slot)
+{
+    var slot = (slot.hint == undefined) ? _slot : _slot.root;
+
+    var face     = slot.face;
+    var pshinter = face.pshinter;
+
+    if (pshinter != null)
+    {
+        var module = slot.face.driver.library.FT_Get_Module("pshinter");
+        if (module != null)
+        {
+            // пока нет хинтов - нету и этого if'а
+            slot.internal.glyph_hints = pshinter.get_t1_funcs(module);
+        }
+    }
+
+    return 0;
+}
+
+function cid_size_get_globals_funcs(size)
+{
+    var face = size.root.face;
+    var pshinter = face.pshinter;
+
+    var module = size.face.driver.library.FT_Get_Module("pshinter");
+    return (module && pshinter && pshinter.get_globals_funcs) ? pshinter.get_globals_funcs(module) : null;
+}
+
+function cid_size_done(size)
+{
+    if (size.root.internal != null)
+    {
+        var funcs = cid_size_get_globals_funcs(size);
+        if (funcs != null)
+            funcs.destroy(size.root.internal);
+
+        size.root.internal = 0;
+    }
+}
+
+function cid_size_init(size)     /* CID_Size */
+{
+    var error = 0;
+    var funcs = cid_size_get_globals_funcs(size);
+
+    if (funcs != null)
+    {
+        var face = size.root.face;
+        var dict = face.cid.font_dicts[face.face_index];
+        var priv = dict.private_dict;
+
+        var ret = funcs.create(size.root.face.memory, priv);
+        error = ret.err;
+        if (error == 0)
+            size.internal = ret.globals;
+    }
+
+    return error;
+}
+
+function cid_size_request(size, req)
+{
+    FT_Request_Metrics(size.face, req);
+
+    var funcs = cid_size_get_globals_funcs(size);
+
+    if (funcs)
+        funcs.set_scale(size.internal, size.metrics.x_scale, size.metrics.y_scale, 0, 0);
+
+    return 0;
+}
+
+function cid_face_done(face)         /* CID_Face */
+{
+    if (face == null)
+        return;
+
+    var cid = face.cid;
+    var info = cid.font_info;
+
+    /* release subrs */
+    face.subrs = null;
+
+    /* release FontInfo strings */
+    info.version = "";
+    info.notice = "";
+    info.full_name = "";
+    info.family_name = "";
+    info.weight = "";
+
+    /* release font dictionaries */
+    cid.font_dicts = null;
+    cid.num_dicts = 0;
+
+    /* release other strings */
+    cid.cid_font_name = "";
+    cid.registry = "";
+    cid.ordering = "";
+
+    face.family_name = "";
+    face.style_name  = "";
+
+    face.binary_data = null;
+    face.cid_stream = null;
+}
+
+function cid_face_init(stream, face, face_index, num_params, params)
+{
+    face.num_faces = 1;
+
+    var psaux = face.psaux;
+    if (psaux == null)
+    {
+        psaux = face.driver.library.FT_Get_Module_Interface("psaux");
+        face.psaux = psaux;
+    }
+
+    var pshinter = face.pshinter;
+    if (pshinter == null)
+    {
+        pshinter = face.driver.library.FT_Get_Module_Interface("pshinter");
+        face.pshinter = pshinter;
+    }
+
+    /* open the tokenizer; this will also check the font format */
+    var error = stream.Seek(0);
+    if (error != 0)
+        return error;
+
+    error = cid_face_open(face, face_index);
+    if (error != 0)
+        return error;
+
+    /* if we just wanted to check the format, leave successfully now */
+    if (face_index < 0)
+        return error;
+
+    /* check the face index */
+    /* XXX: handle CID fonts with more than a single face */
+    if (face_index != 0)
+        return FT_Common.FT_Err_Invalid_Argument;
+    
+    /* now load the font program into the face object */
+    /* initialize the face object fields */
+    /* set up root face fields */
+    var cid = face.cid;
+    var info = cid.font_info;
+
+    face.num_glyphs   = cid.cid_count;
+    face.num_charmaps = 0;
+
+    face.face_index = face_index;
+    face.face_flags = FT_Common.FT_FACE_FLAG_SCALABLE | FT_Common.FT_FACE_FLAG_HORIZONTAL | FT_Common.FT_FACE_FLAG_HINTER;
+
+    if (info.is_fixed_pitch)
+        face.face_flags |= FT_Common.FT_FACE_FLAG_FIXED_WIDTH;
+
+    /* XXX: TODO: add kerning with .afm support */
+
+    /* get style name -- be careful, some broken fonts only */
+    /* have a /FontName dictionary entry!                   */
+    face.family_name = info.family_name;
+    /* assume "Regular" style if we don't know better */
+    face.style_name = "Regular";
+    if (face.family_name != null)
+    {
+        var full   = info.full_name;
+        var family = face.family_name;
+
+        var full_ind = 0;
+        var family_ind = 0;
+
+        var full_count = 0;
+        var family_count = 0;
+
+        if (full != null)
+        {
+            while (full_ind < full_count)
+            {
+                if (full.charCodeAt(full_ind) == family.charCodeAt(family_ind))
+                {
+                    family_ind++;
+                    full_ind++;
+                }
+                else
+                {
+                    if (full.charCodeAt(full_ind) == FT_Common.SYMBOL_CONST_SPACE || full.charCodeAt(full_ind) == FT_Common.SYMBOL_CONST_MATH_MINUS)
+                        full_ind++;
+                    else if (family.charCodeAt(family_ind) == FT_Common.SYMBOL_CONST_SPACE || family.charCodeAt(family_ind) == FT_Common.SYMBOL_CONST_MATH_MINUS)
+                        family_ind++;
+                    else
+                    {
+                        if (family_ind == family_count)
+                            face.style_name = full;
+                        break;
+                    }
+                }
+            }
+        }
+    }
+    else
+    {
+        /* do we have a `/FontName'? */
+        if (cid.cid_font_name)
+            face.family_name = cid.cid_font_name;
+    }
+
+    /* compute style flags */
+    face.style_flags = 0;
+    if (info.italic_angle)
+        face.style_flags |= FT_Common.FT_STYLE_FLAG_ITALIC;
+    if (info.weight != null)
+    {
+        if (info.weight == "Bold" || info.weight == "Black")
+            face.style_flags |= FT_Common.FT_STYLE_FLAG_BOLD;
+    }
+
+    /* no embedded bitmap support */
+    face.num_fixed_sizes = 0;
+    face.available_sizes = 0;
+
+    face.bbox.xMin = cid.font_bbox.xMin >> 16;
+    face.bbox.yMin = cid.font_bbox.yMin >> 16;
+    /* no `U' suffix here to 0xFFFF! */
+    face.bbox.xMax = (cid.font_bbox.xMax + 0xFFFF) >> 16;
+    face.bbox.yMax = (cid.font_bbox.yMax + 0xFFFF) >> 16;
+
+    if (face.units_per_EM)
+        face.units_per_EM = 1000;
+
+    face.ascender  = face.bbox.yMax;
+    face.descender = face.bbox.yMin;
+
+    face.height = parseInt((face.units_per_EM * 12) / 10);
+    if (face.height < face.ascender - face.descender)
+        face.height = (face.ascender - face.descender);
+
+    face.underline_position  = info.underline_position;
+    face.underline_thickness = info.underline_thickness;
+
+    return error;
+}
+
+function cid_driver_init(driver)
+{
+    return 0;
+}
+
+function cid_driver_done(driver)
+{
+}
+
+
+/******************************************************************************/
+// token
+/******************************************************************************/
+var cid_field_records = new Array(50);
+// CID_FaceInfoRec
+cid_field_records[0] = create_t1_field2("CIDFontName", FT_Common.T1_FIELD_LOCATION_CID_INFO, FT_Common.T1_FIELD_TYPE_KEY, function(obj, val, f) { obj.cid_font_name = val}, undefined);
+cid_field_records[1] = create_t1_field2("CIDFontVersion", FT_Common.T1_FIELD_LOCATION_CID_INFO, FT_Common.T1_FIELD_TYPE_FIXED, function(obj, val, f) { obj.cid_version = val}, undefined);
+cid_field_records[2] = create_t1_field2("CIDFontType", FT_Common.T1_FIELD_LOCATION_CID_INFO, FT_Common.T1_FIELD_TYPE_INTEGER, function(obj, val, f) { obj.cid_font_type = val}, undefined);
+cid_field_records[3] = create_t1_field2("Registry", FT_Common.T1_FIELD_LOCATION_CID_INFO, FT_Common.T1_FIELD_TYPE_STRING, function(obj, val, f) { obj.registry = val}, undefined);
+cid_field_records[4] = create_t1_field2("Ordering", FT_Common.T1_FIELD_LOCATION_CID_INFO, FT_Common.T1_FIELD_TYPE_STRING, function(obj, val, f) { obj.ordering = val}, undefined);
+cid_field_records[5] = create_t1_field2("Supplement", FT_Common.T1_FIELD_LOCATION_CID_INFO, FT_Common.T1_FIELD_TYPE_INTEGER, function(obj, val, f) { obj.supplement = val}, undefined);
+cid_field_records[6] = create_t1_field2("UIDBase", FT_Common.T1_FIELD_LOCATION_CID_INFO, FT_Common.T1_FIELD_TYPE_INTEGER, function(obj, val, f) { obj.uid_base = val}, undefined);
+cid_field_records[7] = create_t1_field2("CIDMapOffset", FT_Common.T1_FIELD_LOCATION_CID_INFO, FT_Common.T1_FIELD_TYPE_INTEGER, function(obj, val, f) { obj.cidmap_offset = val}, undefined);
+cid_field_records[8] = create_t1_field2("FDBytes", FT_Common.T1_FIELD_LOCATION_CID_INFO, FT_Common.T1_FIELD_TYPE_INTEGER, function(obj, val, f) { obj.fd_bytes = val}, undefined);
+cid_field_records[9] = create_t1_field2("GDBytes", FT_Common.T1_FIELD_LOCATION_CID_INFO, FT_Common.T1_FIELD_TYPE_INTEGER, function(obj, val, f) { obj.gd_bytes = val}, undefined);
+cid_field_records[10] = create_t1_field2("CIDCount", FT_Common.T1_FIELD_LOCATION_CID_INFO, FT_Common.T1_FIELD_TYPE_INTEGER, function(obj, val, f) { obj.cid_count = val}, undefined);
+
+// PS_FontInfoRec
+cid_field_records[11] = create_t1_field2("version", FT_Common.T1_FIELD_LOCATION_FONT_INFO, FT_Common.T1_FIELD_TYPE_STRING, function(obj, val, f) { obj.version = val}, undefined);
+cid_field_records[12] = create_t1_field2("Notice", FT_Common.T1_FIELD_LOCATION_FONT_INFO, FT_Common.T1_FIELD_TYPE_STRING, function(obj, val, f) { obj.notice = val}, undefined);
+cid_field_records[13] = create_t1_field2("FullName", FT_Common.T1_FIELD_LOCATION_FONT_INFO, FT_Common.T1_FIELD_TYPE_STRING, function(obj, val, f) { obj.full_name = val}, undefined);
+cid_field_records[14] = create_t1_field2("FamilyName", FT_Common.T1_FIELD_LOCATION_FONT_INFO, FT_Common.T1_FIELD_TYPE_STRING, function(obj, val, f) { obj.family_name = val}, undefined);
+cid_field_records[15] = create_t1_field2("Weight", FT_Common.T1_FIELD_LOCATION_FONT_INFO, FT_Common.T1_FIELD_TYPE_STRING, function(obj, val, f) { obj.weight = val}, undefined);
+cid_field_records[16] = create_t1_field2("ItalicAngle", FT_Common.T1_FIELD_LOCATION_FONT_INFO, FT_Common.T1_FIELD_TYPE_INTEGER, function(obj, val, f) { obj.italic_angle = val}, undefined);
+cid_field_records[17] = create_t1_field2("isFixedPitch", FT_Common.T1_FIELD_LOCATION_FONT_INFO, FT_Common.T1_FIELD_TYPE_BOOL, function(obj, val, f) { obj.is_fixed_pitch = val}, undefined);
+cid_field_records[18] = create_t1_field2("UnderlinePosition", FT_Common.T1_FIELD_LOCATION_FONT_INFO, FT_Common.T1_FIELD_TYPE_INTEGER, function(obj, val, f) { obj.underline_position = val}, undefined);
+cid_field_records[19] = create_t1_field2("UnderlineThickness", FT_Common.T1_FIELD_LOCATION_FONT_INFO, FT_Common.T1_FIELD_TYPE_INTEGER, function(obj, val, f) { obj.underline_thickness = val}, undefined);
+
+// PS_FontExtraRec
+cid_field_records[20] = create_t1_field2("FSType", FT_Common.T1_FIELD_LOCATION_FONT_EXTRA, FT_Common.T1_FIELD_TYPE_INTEGER, function(obj, val, f) { obj.fs_type = val}, undefined);
+
+// CID_FaceDictRec
+cid_field_records[21] = create_t1_field2("PaintType", FT_Common.T1_FIELD_LOCATION_FONT_DICT, FT_Common.T1_FIELD_TYPE_INTEGER, function(obj, val, f) { obj.paint_type = val & 0xFF }, undefined);
+cid_field_records[22] = create_t1_field2("FontType", FT_Common.T1_FIELD_LOCATION_FONT_DICT, FT_Common.T1_FIELD_TYPE_INTEGER, function(obj, val, f) { obj.font_type = val & 0xFF}, undefined);
+cid_field_records[23] = create_t1_field2("SubrMapOffset", FT_Common.T1_FIELD_LOCATION_FONT_DICT, FT_Common.T1_FIELD_TYPE_INTEGER, function(obj, val, f) { obj.subrmap_offset = val}, undefined);
+cid_field_records[24] = create_t1_field2("SDBytes", FT_Common.T1_FIELD_LOCATION_FONT_DICT, FT_Common.T1_FIELD_TYPE_INTEGER, function(obj, val, f) { obj.sd_bytes = val}, undefined);
+cid_field_records[25] = create_t1_field2("SubrCount", FT_Common.T1_FIELD_LOCATION_FONT_DICT, FT_Common.T1_FIELD_TYPE_INTEGER, function(obj, val, f) { obj.num_subrs = val}, undefined);
+cid_field_records[26] = create_t1_field2("lenBuildCharArray", FT_Common.T1_FIELD_LOCATION_FONT_DICT, FT_Common.T1_FIELD_TYPE_INTEGER, function(obj, val, f) { obj.len_buildchar = val}, undefined);
+cid_field_records[27] = create_t1_field2("ForceBoldThreshold", FT_Common.T1_FIELD_LOCATION_FONT_DICT, FT_Common.T1_FIELD_TYPE_FIXED, function(obj, val, f) { obj.forcebold_threshold = val}, undefined);
+cid_field_records[28] = create_t1_field2("StrokeWidth", FT_Common.T1_FIELD_LOCATION_FONT_DICT, FT_Common.T1_FIELD_TYPE_FIXED, function(obj, val, f) { obj.stroke_width = val}, undefined);
+
+// PS_PrivateRec
+cid_field_records[29] = create_t1_field2("UniqueID", FT_Common.T1_FIELD_LOCATION_PRIVATE, FT_Common.T1_FIELD_TYPE_INTEGER, function(obj, val, f) { obj.unique_id = val}, undefined);
+cid_field_records[30] = create_t1_field2("lenIV", FT_Common.T1_FIELD_LOCATION_PRIVATE, FT_Common.T1_FIELD_TYPE_INTEGER, function(obj, val, f) { obj.lenIV = val}, undefined);
+cid_field_records[31] = create_t1_field2("LanguageGroup", FT_Common.T1_FIELD_LOCATION_PRIVATE, FT_Common.T1_FIELD_TYPE_INTEGER, function(obj, val, f) { obj.language_group = val}, undefined);
+cid_field_records[32] = create_t1_field2("password", FT_Common.T1_FIELD_LOCATION_PRIVATE, FT_Common.T1_FIELD_TYPE_INTEGER, function(obj, val, f) { obj.password = val}, undefined);
+
+cid_field_records[33] = create_t1_field2("BlueScale", FT_Common.T1_FIELD_LOCATION_PRIVATE, FT_Common.T1_FIELD_TYPE_FIXED_1000, function(obj, val, f) { obj.blue_scale = val}, undefined);
+cid_field_records[34] = create_t1_field2("BlueShift", FT_Common.T1_FIELD_LOCATION_PRIVATE, FT_Common.T1_FIELD_TYPE_INTEGER, function(obj, val, f) { obj.blue_shift = val}, undefined);
+cid_field_records[35] = create_t1_field2("BlueFuzz", FT_Common.T1_FIELD_LOCATION_PRIVATE, FT_Common.T1_FIELD_TYPE_INTEGER, function(obj, val, f) { obj.blue_fuzz = val}, undefined);
+
+cid_field_records[36] = create_t1_field3("BlueValues", FT_Common.T1_FIELD_LOCATION_PRIVATE, FT_Common.T1_FIELD_TYPE_INTEGER_ARRAY, 14, function(obj, val, f) { obj.blue_values[f.offset] = val}, function(obj, val, f) { obj.num_blue_values = val});
+cid_field_records[37] = create_t1_field3("OtherBlues", FT_Common.T1_FIELD_LOCATION_PRIVATE, FT_Common.T1_FIELD_TYPE_INTEGER_ARRAY, 10, function(obj, val, f) { obj.other_blues[f.offset] = val}, function(obj, val, f) { obj.num_other_blues = val});
+cid_field_records[38] = create_t1_field3("FamilyBlues", FT_Common.T1_FIELD_LOCATION_PRIVATE, FT_Common.T1_FIELD_TYPE_INTEGER_ARRAY, 14, function(obj, val, f) { obj.family_blues[f.offset] = val}, function(obj, val, f) { obj.num_family_blues = val});
+cid_field_records[39] = create_t1_field3("FamilyOtherBlues", FT_Common.T1_FIELD_LOCATION_PRIVATE, FT_Common.T1_FIELD_TYPE_INTEGER_ARRAY, 10, function(obj, val, f) { obj.family_other_blues[f.offset] = val}, function(obj, val, f) { obj.num_family_other_blues = val});
+
+cid_field_records[40] = create_t1_field3("StdHW", FT_Common.T1_FIELD_LOCATION_PRIVATE, FT_Common.T1_FIELD_TYPE_INTEGER_ARRAY, 1, function(obj, val, f) { obj.standard_width[0] = val}, undefined);
+cid_field_records[41] = create_t1_field3("StdVW", FT_Common.T1_FIELD_LOCATION_PRIVATE, FT_Common.T1_FIELD_TYPE_INTEGER_ARRAY, 1, function(obj, val, f) { obj.standard_height[0] = val}, undefined);
+cid_field_records[42] = create_t1_field3("MinFeature", FT_Common.T1_FIELD_LOCATION_PRIVATE, FT_Common.T1_FIELD_TYPE_INTEGER_ARRAY, 2, function(obj, val, f) { obj.min_feature[f.offset] = val}, undefined);
+
+cid_field_records[43] = create_t1_field3("StemSnapH", FT_Common.T1_FIELD_LOCATION_PRIVATE, FT_Common.T1_FIELD_TYPE_INTEGER_ARRAY, 12, function(obj, val, f) { obj.snap_widths[f.offset] = val}, function(obj, val, f) { obj.num_snap_widths = val});
+cid_field_records[44] = create_t1_field3("StemSnapV", FT_Common.T1_FIELD_LOCATION_PRIVATE, FT_Common.T1_FIELD_TYPE_INTEGER_ARRAY, 12, function(obj, val, f) { obj.snap_heights[f.offset] = val}, function(obj, val, f) { obj.num_snap_heights = val});
+
+cid_field_records[45] = create_t1_field2("ForceBold", FT_Common.T1_FIELD_LOCATION_PRIVATE, FT_Common.T1_FIELD_TYPE_BOOL, function(obj, val, f) { obj.force_bold = val}, undefined);
+
+// FT_BBox
+cid_field_records[46] = create_t1_field2("FontBBox", FT_Common.T1_FIELD_LOCATION_BBOX, FT_Common.T1_FIELD_TYPE_BOOL, undefined, undefined);
+
+// callbacks
+cid_field_records[47] = create_t1_field("FDArray", FT_Common.T1_FIELD_LOCATION_BBOX, FT_Common.T1_FIELD_TYPE_CALLBACK, parse_fd_array, 0, -1, 0, 0, 0, undefined, undefined);
+cid_field_records[48] = create_t1_field("FontMatrix", FT_Common.T1_FIELD_LOCATION_BBOX, FT_Common.T1_FIELD_TYPE_CALLBACK, parse_font_matrix, 0, -1, 0, 0, 0, undefined, undefined);
+cid_field_records[49] = create_t1_field("ExpansionFactor", FT_Common.T1_FIELD_LOCATION_BBOX, FT_Common.T1_FIELD_TYPE_CALLBACK, parse_expansion_factor, 0, -1, 0, 0, 0, undefined, undefined);
+
+
+/******************************************************************************/
+// driver
+/******************************************************************************/
+function cid_get_postscript_name(face)
+{
+    var result = face.cid.cid_font_name;
+
+    if (result && result[0] == '/')
+        result = result.substring(1);
+
+    return result;
+}
+var cid_service_ps_name = new FT_Service_PsFontNameRec(cid_get_postscript_name);
+
+function cid_ps_get_font_info(face)
+{
+    FT_Error = FT_Common.FT_Err_Ok;
+    return face.cid.font_info.CreateDublicate();
+}
+function cid_ps_get_font_extra(face)
+{
+    FT_Error = FT_Common.FT_Err_Ok;
+    return face.cid.font_extra.CreateDublicate();
+}
+var cid_service_ps_info = new FT_Service_PsInfoRec(cid_ps_get_font_info,cid_ps_get_font_extra,null,null,null);
+
+function cid_get_ros(face, registry, ordering, supplement)
+{
+    FT_Error = FT_Common.FT_Err_Ok;
+    var cid = face.cid;
+    return { registry : cid.registry, ordering : cid.ordering, supplement : cid.supplement }
+}
+function cid_get_is_cid(face)
+{
+    FT_Error = FT_Common.FT_Err_Ok;
+    return 1;
+}
+function cid_get_cid_from_glyph_index(face,  glyph_index)
+{
+    FT_Error = FT_Common.FT_Err_Ok;
+    return glyph_index;
+}
+var cid_service_cid_info = new FT_Service_CIDRec(cid_get_ros, cid_get_is_cid, cid_get_cid_from_glyph_index);
+
+var cid_services = new Array(4);
+cid_services[0] = new FT_ServiceDescRec(FT_SERVICE_ID_XF86_NAME,FT_XF86_FORMAT_CID);
+cid_services[1] = new FT_ServiceDescRec(FT_SERVICE_ID_POSTSCRIPT_FONT_NAME,cid_service_ps_name);
+cid_services[2] = new FT_ServiceDescRec(FT_SERVICE_ID_POSTSCRIPT_INFO,cid_service_ps_info);
+cid_services[3] = new FT_ServiceDescRec(FT_SERVICE_ID_CID,cid_service_cid_info);
+
+function cid_get_interface(module, cid_interface)
+{
+    return ft_service_list_lookup(cid_services, cid_interface);
+}
+
+function CID_Driver_Class()
+{
+    this.flags = 0x501;
+    this.name = "t1cid";
+    this.version = 0x10000;
+    this.requires = 0x20000;
+
+    this.module_interface = null;
+
+    this.init = cid_driver_init;
+    this.done = cid_driver_done;
+    this.get_interface = cid_get_interface;
+
+    this.face_object_size = 0;
+    this.size_object_size = 0;
+    this.slot_object_size = 0;
+
+    this.init_face = cid_face_init;
+    this.done_face = cid_face_done;
+
+    this.init_size = cid_size_init;
+    this.done_size = cid_size_done;
+
+    this.init_slot = cid_slot_init;
+    this.done_slot = cid_slot_done;
+
+    //#ifdef FT_CONFIG_OPTION_OLD_INTERNALS
+    this.set_char_sizes = ft_stub_set_char_sizes;
+    this.set_pixel_sizes = ft_stub_set_pixel_sizes;
+    //#endif
+
+    this.load_glyph = cid_slot_load_glyph;
+
+    this.get_kerning = null;
+    this.attach_file = null;
+    this.get_advances = null;
+
+    this.request_size = cid_size_request;
+    this.select_size = null;
+}
+
+function CID_Driver()
+{
+    this.clazz = null;      // FT_Module_Class
+    this.library = null;    // FT_Library
+    this.memory = null;     // FT_Memory
+    this.generic = null;    // FT_Generic
+
+    this.clazz = new CID_Driver_Class();
+    this.faces_list = [];
+    this.extensions = null;
+    this.glyph_loader = null;
+
+    this.open_face = function(stream, face_index)
+    {
+        FT_Error = 0;
+        var face = new CID_Face();
+        var internal = new FT_Face_Internal();
+
+        face.driver = this;
+        face.memory = this.memory;
+        face.stream = stream;
+
+        //#ifdef FT_CONFIG_OPTION_INCREMENTAL
+        face.internal = internal;
+        face.internal.incremental_interface = null;
+        //#endif
+
+        var err1 = this.clazz.init_face(stream, face, face_index);
+
+        if (err1 != 0)
+        {
+            face = null;
+            FT_Error = err1;
+            return null;
+        }
+
+        var err2 = find_unicode_charmap(face);
+        if (err2 != 0 && err2 != FT_Common.FT_Err_Invalid_CharMap_Handle)
+        {
+            face = null;
+            FT_Error = err2;
+            return null;
+        }
+
+        return face;
+    }
+}
+
+function create_cid_driver(library)
+{
+    var driver = new CID_Driver();
+    driver.library = library;
+    driver.memory = library.Memory;
+
+    driver.clazz = new CID_Driver_Class();
+    return driver;
+}
\ No newline at end of file
diff --git a/Common/FontsFreeType/Private/FreeType/drivers/t1.js b/Common/FontsFreeType/Private/FreeType/drivers/t1.js
new file mode 100644
index 0000000000000000000000000000000000000000..bbabefc3613beae72c71c157936f1de4401cc31f
--- /dev/null
+++ b/Common/FontsFreeType/Private/FreeType/drivers/t1.js
@@ -0,0 +1,3638 @@
+/******************************************************************************/
+// afm
+/******************************************************************************/
+function T1_Done_Metrics(memory, fi)
+{
+    fi.KernPairs = null;
+    fi.NumKernPair = 0;
+
+    fi.TrackKerns = null;
+    fi.NumTrackKern = 0;
+}
+
+function t1_get_index(name, len, user_data)
+{
+    var type1 = user_data;
+
+    /* PS string/name length must be < 16-bit */
+    if (len > 0xFFFF)
+        return 0;
+
+    for (var n = 0; n < type1.num_glyphs; n++)
+    {
+        var gname = type1.glyph_names[n];
+
+        if (gname == name)
+            return n;
+    }
+
+    return 0;
+}
+
+function compare_kern_pairs(a, b)
+{
+    var index1 = (a.index1 << 16) | a.index2;
+    var index2 = (b.index2 << 16) | b.index2;
+
+    if (index1 > index2)
+        return 1;
+    else if (index1 < index2)
+        return -1;
+    else
+        return 0;
+}
+
+function T1_Read_PFM(t1_face, stream, fi)
+{
+    var error = 0;
+    var start = new CPointer();
+    start.data = stream.data;
+    start.pos = stream.cur;
+
+    var limit = stream.limit;
+    var p = dublicate_pointer(start);
+
+    /* Figure out how long the width table is.          */
+    /* This info is a little-endian short at offset 99. */
+    p.pos = start.pos + 99;
+    if (p.pos + 2 > limit)
+        return FT_Common.FT_Err_Invalid_File_Format;
+
+    var width_table_length = FT_PEEK_USHORT_LE(p);
+
+    p.pos += 18 + width_table_length;
+    if (p.pos + 0x12 > limit || FT_PEEK_USHORT_LE(p) < 0x12)
+        return error;
+
+    /* Kerning offset is 14 bytes from start of extensions table. */
+    p.pos += 14;
+    p.pos = start.pos + FT_PEEK_ULONG_LE(p);
+
+    if (p.pos == start.pos)
+        return error;
+
+    if (p.pos + 2 > limit)
+        return FT_Common.FT_Err_Unknown_File_Format;
+
+    fi.NumKernPair = FT_PEEK_USHORT_LE(p);
+    p.pos += 2;
+    if (p.pos + 4 * fi.NumKernPair > limit)
+        return FT_Common.FT_Err_Invalid_File_Format;
+
+    /* Actually, kerning pairs are simply optional! */
+    if (fi.NumKernPair == 0)
+        return error;
+
+    fi.KernPairs = new Array(fi.NumKernPair);
+    for (var i = 0; i < fi.KernPairs; i++)
+    {
+        fi.KernPairs[i] = new AFM_KernPairRec();
+    }
+
+    /* now, read each kern pair */
+    var kp = 0;
+    limit = p.pos + 4 * fi.NumKernPair;
+
+    /* PFM kerning data are stored by encoding rather than glyph index, */
+    /* so find the PostScript charmap of this font and install it       */
+    /* temporarily.  If we find no PostScript charmap, then just use    */
+    /* the default and hope it is the right one.                        */
+    var oldcharmap = t1_face.charmap;
+    var charmap = null;
+
+    for (var n = 0; n < t1_face.num_charmaps; n++)
+    {
+        charmap = t1_face.charmaps[n];
+        /* check against PostScript pseudo platform */
+        if (__FT_CharmapRec(charmap).platform_id == 7)
+        {
+            error = FT_Set_Charmap(t1_face, charmap);
+            if (error)
+            {
+                fi.KernPairs = null;
+                return error;
+            }
+            break;
+        }
+    }
+
+    /* Kerning info is stored as:             */
+    /*                                        */
+    /*   encoding of first glyph (1 byte)     */
+    /*   encoding of second glyph (1 byte)    */
+    /*   offset (little-endian short)         */
+    for (; p.pos < limit; p.pos += 4)
+    {
+        var _t = fi.KernPairs[kp];
+
+        _t.index1 = FT_Get_Char_Index(t1_face, p.data[p.pos]);
+        _t.index2 = FT_Get_Char_Index(t1_face, p.data[p.data + 1]);
+
+        p.pos += 2;
+        _t.x = FT_PEEK_SHORT_LE(p);
+        p.pos -= 2;
+        _t.y = 0;
+
+        kp++;
+    }
+
+    if (oldcharmap != null)
+        error = FT_Set_Charmap(t1_face, oldcharmap);
+
+    if (error != 0)
+    {
+        fi.KernPairs = null;
+        return error;
+    }
+
+    /* now, sort the kern pairs according to their glyph indices */
+    ft_qsort(fi.KernPairs, fi.NumKernPair, compare_kern_pairs);
+
+    return error;
+}
+
+function T1_Read_Metrics(t1_face, stream)
+{
+    var parser = new AFM_ParserRec();
+
+    var fi = new AFM_FontInfoRec();
+    var t1_font = t1_face.type1;
+
+    var error = stream.EnterFrame(stream.size);
+    
+    fi.FontBBox = dublicate_bbox(t1_font.font_bbox);
+    fi.Ascender  = t1_font.font_bbox.yMax;
+    fi.Descender = t1_font.font_bbox.yMin;
+
+    var psaux = t1_face.psaux;
+    if (psaux != null && psaux.afm_parser_funcs != null)
+    {
+        var cur = new CPointer();
+        cur.pos = stream.cur;
+        cur.data = stream.data;
+        error = psaux.afm_parser_funcs.init(parser, g_memory, cur, stream.size);
+
+        if (error == 0)
+        {
+            parser.FontInfo  = fi;
+            parser.get_index = t1_get_index;
+            parser.user_data = t1_face.type1;
+
+            error = psaux.afm_parser_funcs.parse(parser);
+            psaux.afm_parser_funcs.done(parser);
+        }
+    }
+
+    if (error == FT_Common.FT_Err_Unknown_File_Format)
+    {
+        var start = new CPointer();
+        start.pos = stream.cur;
+        start.data = stream.data;
+
+        /* MS Windows allows versions up to 0x3FF without complaining */
+        if (stream.size > 6 && start.data[start.pos + 1] < 4)
+        {
+            start.pos += 2;
+            if (FT_PEEK_ULONG_LE(start) == stream.size)
+            {
+                error = T1_Read_PFM(t1_face, stream, fi);
+            }
+        }
+    }
+
+    if (error == 0)
+    {
+        t1_font.font_bbox = dublicate_bbox(fi.FontBBox);
+
+        t1_face.bbox.xMin = fi.FontBBox.xMin >> 16;
+        t1_face.bbox.yMin = fi.FontBBox.yMin >> 16;
+        /* no `U' suffix here to 0xFFFF! */
+        t1_face.bbox.xMax = (fi.FontBBox.xMax + 0xFFFF) >> 16;
+        t1_face.bbox.yMax = (fi.FontBBox.yMax + 0xFFFF) >> 16;
+
+        /* no `U' suffix here to 0x8000! */
+        t1_face.ascender  = ((fi.Ascender  + 0x8000) >> 16);
+        t1_face.descender = ((fi.Descender + 0x8000) >> 16);
+
+        if (fi.NumKernPair == 0)
+        {
+            t1_face.face_flags |= FT_Common.FT_FACE_FLAG_KERNING;
+            t1_face.afm_data = fi;
+            fi = null;
+        }
+    }
+
+    stream.ExitFrame();
+
+    if (fi != null)
+    {
+        T1_Done_Metrics(g_memory, fi);
+        fi = null;
+    }
+    return error;
+}
+
+function T1_Get_Kerning(fi, glyph1, glyph2)
+{
+    var kerning = new FT_Vector();
+    var min = 0;
+    var mid = 0;
+    var max = fi.NumKernPair - 1;
+    var idx = (glyph1 << 16) | glyph2;
+
+    /* simple binary search */
+    var pairs = fi.KernPairs;
+
+    while (min <= max)
+    {
+        mid  = min + (max - min) / 2;
+        var midi = (pairs[mid].index1) << 16 | pairs[mid].index2;
+
+        if (midi == idx)
+        {
+            kerning.x = mid.x;
+            kerning.y = mid.y;
+
+            return kerning;
+        }
+
+        if (midi < idx)
+            min = mid + 1;
+        else
+            max = mid - 1;
+    }
+
+    kerning.x = 0;
+    kerning.y = 0;
+
+    return kerning;
+}
+
+function T1_Get_Track_Kerning(face, ptsize, degree, kerning)
+{
+    var fi = face.afm_data;
+    var ret = { err: FT_Common.FT_Err_Invalid_Argument, kerning: kerning };
+
+    if (fi == null)
+    {
+        ret.err = FT_Common.FT_Err_Invalid_Argument;
+        return ret;
+    }
+
+    var count = fi.NumTrackKern;
+    for (var i = 0; i < count; i++)
+    {
+        var tk = fi.TrackKerns[i];
+
+        if (tk.degree != degree)
+            continue;
+
+        if (ptsize < tk.min_ptsize)
+        {
+            ret.kerning = tk.min_kern;
+        }
+        else if (ptsize > tk.max_ptsize)
+        {
+            ret.kerning = tk.max_kern;
+        }
+        else
+        {
+            ret.kerning = FT_MulDiv(ptsize - tk.min_ptsize, tk.max_kern - tk.min_kern, tk.max_ptsize - tk.min_ptsize) + tk.min_kern;
+        }
+    }
+
+    return ret;
+}
+
+/******************************************************************************/
+// gload
+/******************************************************************************/
+function T1_Parse_Glyph_And_Get_Char_String(decoder, glyph_index, char_string)
+{
+    var face = decoder.builder.face;
+    var type1 = face.type1;
+    var error = 0;
+
+    decoder.font_matrix = dublicate_matrix(type1.font_matrix);
+    decoder.font_offset = dublicate_vector(type1.font_offset);
+
+    char_string.pointer = dublicate_pointer(type1.charstrings[glyph_index]);
+    char_string.length  = type1.charstrings_len[glyph_index];
+
+    if (error == 0)
+        error = decoder.funcs.parse_charstrings(decoder, char_string.pointer, char_string.length);
+
+    return error;
+}
+
+function T1_Parse_Glyph(decoder, glyph_index)
+{
+    var glyph_data = new FT_Data();
+    var error = T1_Parse_Glyph_And_Get_Char_String(decoder, glyph_index, glyph_data);
+    return error;
+}
+
+function T1_Compute_Max_Advance(face)
+{
+    var ret = { err : 0, max_advance : 0 };
+
+    var type1 = face.type1;
+    var psaux = face.psaux;
+
+    /* initialize load decoder */
+    var decoder = new T1_DecoderRec();
+    
+    ret.err = psaux.t1_decoder_funcs.init(decoder, face, null, null, type1.glyph_names, face.blend, 0, FT_Common.FT_RENDER_MODE_NORMAL, T1_Parse_Glyph);
+    if (ret.err != 0)
+        return ret;
+
+        decoder.builder.metrics_only = 1;
+    decoder.builder.load_points  = 0;
+
+    decoder.num_subrs     = type1.num_subrs;
+    decoder.subrs         = type1.subrs;
+    decoder.subrs_len     = type1.subrs_len;
+
+    decoder.buildchar     = face.buildchar;
+    decoder.len_buildchar = face.len_buildchar;
+
+    /* for each glyph, parse the glyph charstring and extract */
+    /* the advance width                                      */
+    var _count = type1.num_glyphs;
+    for (var glyph_index = 0; glyph_index < _count; glyph_index++)
+    {
+        if (glyph_index == 342)
+        {
+            var tt = 0;
+            tt += 5;
+            tt -= 89;
+            tt += 8;
+        }
+
+        /* now get load the unscaled outline */
+        ret.err = T1_Parse_Glyph(decoder, glyph_index);
+        if (glyph_index == 0 || decoder.builder.advance.x > ret.max_advance)
+            ret.max_advance = decoder.builder.advance.x;
+    }
+
+    psaux.t1_decoder_funcs.done(decoder);
+    ret.err = 0;
+    return ret;
+}
+
+function T1_Get_Advances(face, first, count, load_flags, advances)
+{
+    if (load_flags & FT_Common.FT_LOAD_VERTICAL_LAYOUT)
+    {
+        for ( nn = 0; nn < count; nn++ )
+            advances[nn] = 0;
+
+        return 0;
+    }
+
+    var decoder = new T1_DecoderRec();
+    var psaux = face.psaux;
+    var type1 = face.type1;
+
+    var error = psaux.t1_decoder_funcs.init(decoder, face, null, null, type1.glyph_names, face.blend, 0, FT_Common.FT_RENDER_MODE_NORMAL, T1_Parse_Glyph);
+    if (error != 0)
+        return error;
+
+    decoder.builder.metrics_only = 1;
+    decoder.builder.load_points  = 0;
+
+    decoder.num_subrs = type1.num_subrs;
+    decoder.subrs     = type1.subrs;
+    decoder.subrs_len = type1.subrs_len;
+
+    decoder.buildchar     = face.buildchar;
+    decoder.len_buildchar = face.len_buildchar;
+
+    for (var nn = 0; nn < count; nn++)
+    {
+        error = T1_Parse_Glyph(decoder, first + nn);
+        if (error == 0)
+            advances[nn] = FT_RoundFix(decoder.builder.advance.x) >> 16;
+        else
+            advances[nn] = 0;
+    }
+
+    return 0;
+}
+
+function T1_Load_Glyph(_glyph, size, glyph_index, load_flags)
+{
+    var glyph = _glyph.base_root;
+
+    var decoder = new T1_DecoderRec();
+    var face = _glyph.face;
+    var type1 = face.type1;
+    var psaux = face.psaux;
+    var decoder_funcs = psaux.t1_decoder_funcs;
+
+    var glyph_data = new FT_Data();
+    var must_finish_decoder = 0;
+
+    if (glyph_index >= face.num_glyphs)
+        return FT_Common.FT_Err_Invalid_Argument;
+
+    if (load_flags & FT_Common.FT_LOAD_NO_RECURSE)
+        load_flags |= (FT_Common.FT_LOAD_NO_SCALE | FT_Common.FT_LOAD_NO_HINTING);
+
+    if (size != null)
+    {
+        glyph.x_scale = size.metrics.x_scale;
+        glyph.y_scale = size.metrics.y_scale;
+    }
+    else
+    {
+        glyph.x_scale = 0x10000;
+        glyph.y_scale = 0x10000;
+    }
+
+    _glyph.outline.n_points   = 0;
+    _glyph.outline.n_contours = 0;
+
+    var hinting = ((load_flags & FT_Common.FT_LOAD_NO_SCALE) == 0 && (load_flags & FT_Common.FT_LOAD_NO_HINTING) == 0);
+    _glyph.format = FT_Common.FT_GLYPH_FORMAT_OUTLINE;
+
+    var error = decoder_funcs.init(decoder, face, size, glyph, type1.glyph_names, face.blend, hinting, FT_LOAD_TARGET_MODE(load_flags), T1_Parse_Glyph);
+    if (error != 0)
+        return error;
+
+    must_finish_decoder = 1;
+
+    decoder.builder.no_recurse = ((load_flags & FT_Common.FT_LOAD_NO_RECURSE) != 0) ? 1 : 0;
+
+    decoder.num_subrs     = type1.num_subrs;
+    decoder.subrs         = type1.subrs;
+    decoder.subrs_len     = type1.subrs_len;
+
+    decoder.buildchar     = face.buildchar;
+    decoder.len_buildchar = face.len_buildchar;
+
+    /* now load the unscaled outline */
+    error = T1_Parse_Glyph_And_Get_Char_String(decoder, glyph_index, glyph_data);
+    if (error != 0)
+    {
+        decoder_funcs.done(decoder);
+        return error;
+    }
+
+    var font_matrix = dublicate_matrix(decoder.font_matrix);
+    var font_offset = dublicate_vector(decoder.font_offset);
+
+    /* save new glyph tables */
+    decoder_funcs.done(decoder);
+    
+    must_finish_decoder = 0;
+
+    /* now, set the metrics -- this is rather simple, as   */
+    /* the left side bearing is the xMin, and the top side */
+    /* bearing the yMax                                    */
+    if (error == 0)
+    {
+        glyph.root.outline.flags &= FT_Common.FT_OUTLINE_OWNER;
+        glyph.root.outline.flags |= FT_Common.FT_OUTLINE_REVERSE_FILL;
+
+        /* for composite glyphs, return only left side bearing and */
+        /* advance width                                           */
+        if ((load_flags & FT_Common.FT_LOAD_NO_RECURSE) != 0)
+        {
+            var internal = glyph.root.internal;
+
+            glyph.root.metrics.horiBearingX = FT_RoundFix(decoder.builder.left_bearing.x) >> 16;
+            glyph.root.metrics.horiAdvance = FT_RoundFix(decoder.builder.advance.x);
+
+            internal.glyph_matrix      = dublicate_matrix(font_matrix);
+            internal.glyph_delta       = dublicate_vector(font_offset);
+            internal.glyph_transformed = 1;
+        }
+        else
+        {
+            var cbox = new FT_BBox();
+            var metrics = glyph.root.metrics;
+            var advance = new FT_Vector();
+
+            /* copy the _unscaled_ advance width */
+            metrics.horiAdvance = FT_RoundFix(decoder.builder.advance.x) >> 16;
+            glyph.root.linearHoriAdvance = FT_RoundFix(decoder.builder.advance.x) >> 16;
+            glyph.root.internal.glyph_transformed = 0;
+
+            if ((load_flags & FT_Common.FT_LOAD_VERTICAL_LAYOUT) != 0)
+            {
+                /* make up vertical ones */
+                metrics.vertAdvance = (face.type1.font_bbox.yMax - face.type1.font_bbox.yMin) >> 16;
+                glyph.root.linearVertAdvance = metrics.vertAdvance;
+            }
+            else
+            {
+                metrics.vertAdvance = FT_RoundFix(decoder.builder.advance.y) >> 16;
+                glyph.root.linearVertAdvance = FT_RoundFix(decoder.builder.advance.y) >> 16;
+            }
+
+            glyph.root.format = FT_Common.FT_GLYPH_FORMAT_OUTLINE;
+
+            if (size != null && size.metrics.y_ppem < 24)
+                glyph.root.outline.flags |= FT_Common.FT_OUTLINE_HIGH_PRECISION;
+
+            /* apply the font matrix, if any */
+            if (font_matrix.xx != 0x10000 || font_matrix.yy != font_matrix.xx || font_matrix.xy != 0 || font_matrix.yx != 0)
+                FT_Outline_Transform(glyph.root.outline, font_matrix);
+
+            if (font_offset.x || font_offset.y)
+                FT_Outline_Translate(glyph.root.outline, font_offset.x, font_offset.y);
+
+            advance.x = metrics.horiAdvance;
+            advance.y = 0;
+            FT_Vector_Transform(advance, font_matrix);
+            metrics.horiAdvance = advance.x + font_offset.x;
+            advance.x = 0;
+            advance.y = metrics.vertAdvance;
+            FT_Vector_Transform(advance, font_matrix);
+            metrics.vertAdvance = advance.y + font_offset.y;
+
+            if ((load_flags & FT_Common.FT_LOAD_NO_SCALE) == 0)
+            {
+                /* scale the outline and the metrics */
+                var cur_p_c = decoder.builder.base.n_points;
+                var points = decoder.builder.base.points;
+                var vec = 0;
+                var x_scale = glyph.x_scale;
+                var y_scale = glyph.y_scale;
+
+
+                /* First of all, scale the points, if we are not hinting */
+                if (hinting == 0 || decoder.builder.hints_funcs == null)
+                {
+                    for (var n = cur_p_c; n > 0; n--, vec++)
+                    {
+                        points[vec].x = FT_MulFix(points[vec].x, x_scale);
+                        points[vec].y = FT_MulFix(points[vec].y, y_scale);
+                    }
+                }
+
+                /* Then scale the metrics */
+                metrics.horiAdvance = FT_MulFix(metrics.horiAdvance, x_scale);
+                metrics.vertAdvance = FT_MulFix(metrics.vertAdvance, y_scale);
+            }
+
+            /* compute the other metrics */
+            FT_Outline_Get_CBox(glyph.root.outline, cbox);
+
+            metrics.width  = cbox.xMax - cbox.xMin;
+            metrics.height = cbox.yMax - cbox.yMin;
+
+            metrics.horiBearingX = cbox.xMin;
+            metrics.horiBearingY = cbox.yMax;
+
+            if ((load_flags & FT_Common.FT_LOAD_VERTICAL_LAYOUT) != 0)
+            {
+                /* make up vertical ones */
+                ft_synthesize_vertical_metrics(metrics, metrics.vertAdvance);
+            }
+        }
+
+        /* Set control data to the glyph charstrings.  Note that this is */
+        /* _not_ zero-terminated.                                        */
+        glyph.root.control_data = dublicate_pointer(glyph_data.pointer);
+        glyph.root.control_len  = glyph_data.length;
+    }
+
+    return error;
+}
+
+/******************************************************************************/
+// parse
+/******************************************************************************/
+function T1_ParserRec()
+{
+    this.root = new PS_ParserRec();
+    this.stream = null;
+
+    this.base_dict = null;
+    this.base_len = 0;
+
+    this.private_dict = null;
+    this.private_len = 0;
+
+    this.in_pfb = 0;
+    this.in_memory = 0;
+    this.single_block = 0;
+
+    this.clear = function()
+    {
+        this.root.clear();
+        this.stream = null;
+
+        this.base_dict = null;
+        this.base_len = 0;
+
+        this.private_dict = null;
+        this.private_len = 0;
+
+        this.in_pfb = 0;
+        this.in_memory = 0;
+        this.single_block = 0;
+    }
+}
+
+function read_pfb_tag(stream)
+{
+    var ret = { tag: 0, size: 0, err: 0 };
+
+    var tag = stream.ReadUShort();
+    ret.err = FT_Error;
+    if (ret.err == 0)
+    {
+        if (tag == 0x8001 || tag == 0x8002)
+        {
+            var size = stream.ReadULongLE();
+            ret.err = FT_Error;
+            if (ret.err == 0)
+                ret.size = size;
+        }
+        ret.tag = tag;
+    }
+    return ret;
+}
+
+function check_type1_format(stream, header_string, header_length)
+{
+    var error = stream.Seek(0);
+    if (error != 0)
+        return error;
+
+
+    var ret = read_pfb_tag(stream);
+    if (ret.err != 0)
+        return ret.err;
+
+    /* We assume that the first segment in a PFB is always encoded as   */
+    /* text.  This might be wrong (and the specification doesn't insist */
+    /* on that), but we have never seen a counterexample.               */
+    if (ret.tag != 0x8001 && 0 != stream.Seek(0))
+        return error;
+
+    error = stream.EnterFrame(header_length);
+    if (error == 0)
+    {
+        for (var i = 0; i < header_length; i++)
+        {
+            if (header_string.charCodeAt(i) != stream.data[stream.cur + i])
+                return FT_Common.FT_Err_Unknown_File_Format;
+        }
+
+        stream.ExitFrame();
+    }
+    return error;
+}
+
+function T1_New_Parser(parser, stream, memory, psaux)
+{
+    psaux.ps_parser_funcs.init(parser.root, null, 0, memory);
+
+    parser.stream       = stream;
+    parser.base_len     = 0;
+    parser.base_dict    = null;
+    parser.private_len  = 0;
+    parser.private_dict = null;
+    parser.in_pfb       = 0;
+    parser.in_memory    = 0;
+    parser.single_block = 0;
+
+    /* check the header format */
+    var error = check_type1_format(stream, "%!PS-AdobeFont", 14);
+    if (error != 0)
+    {
+        if (error != FT_Common.FT_Err_Unknown_File_Format)
+            return error;
+
+        error = check_type1_format(stream, "%!FontType", 10);
+        if (error != 0)
+            return error;
+    }
+
+    error = stream.Seek(0);
+    if (error != 0)
+        return error;
+
+    var ret = read_pfb_tag(stream);
+    if (ret.err != 0)
+        return ret.err;
+
+    var size = ret.size;
+
+    if (ret.tag != 0x8001)
+    {
+        /* assume that this is a PFA file for now; an error will */
+        /* be produced later when more things are checked        */
+        error = stream.Seek(0);
+        if (error != 0)
+            return error;
+        size = stream.size;
+    }
+    else
+        parser.in_pfb = 1;
+
+    /* now, try to load `size' bytes of the `base' dictionary we */
+    /* found previously                                          */
+    /* if it is a memory-based resource, set up pointers */
+    parser.base_dict = new CPointer();
+    parser.base_dict.data = stream.data;
+    parser.base_dict.pos = stream.pos;
+    parser.base_len = size;
+    parser.in_memory = 1;
+
+    error = stream.Skip(size);
+    if (error != 0)
+        return error;
+
+    parser.root.base   = dublicate_pointer(parser.base_dict);
+    parser.root.cursor = dublicate_pointer(parser.root.base);
+    parser.root.limit  = parser.root.base.pos + parser.base_len;
+
+    return error;
+}
+
+function T1_Finalize_Parser(parser)
+{
+    parser.private_dict = null;
+    parser.base_dict = null;
+
+    parser.root.funcs.done(parser.root);
+}
+
+function T1_Get_Private_Dict(parser, psaux)
+{
+    var stream = parser.stream;
+    var memory = parser.root.memory;
+
+    var error = 0;
+    var size = 0;
+
+    if (parser.in_pfb == 1)
+    {
+        /* in the case of the PFB format, the private dictionary can be  */
+        /* made of several segments.  We thus first read the number of   */
+        /* segments to compute the total size of the private dictionary  */
+        /* then re-read them into memory.                                */
+        var start_pos = stream.pos;
+        parser.private_len = 0;
+        for (;;)
+        {
+            var ret = read_pfb_tag(stream);
+            if (ret.err != 0)
+                return ret.err;
+
+            if (ret.tag != 0x8002)
+                break;
+
+            parser.private_len += ret.size;
+
+            error = stream.Skip(ret.size);
+        }
+
+        /* Check that we have a private dictionary there */
+        /* and allocate private dictionary buffer        */
+        if (parser.private_len == 0)
+            return FT_Common.FT_Err_Invalid_File_Format;
+
+        error = stream.Seek(start_pos);
+        if (error != 0)
+            return error;
+
+        parser.private_dict = memory.Alloc(parser.private_len);
+        parser.private_len = 0;
+        var p = dublicate_pointer(parser.private_dict);
+        for (;;)
+        {
+            var ret = read_pfb_tag(stream);
+            if (ret.err != 0 || ret.tag != 0x8002)
+            {
+                error = 0;
+                break;
+            }
+
+            p.pos = parser.private_len;
+            error = stream.Read(p, ret.size);
+
+            if (error != 0)
+                return error;
+
+            parser.private_len += ret.size;
+        }
+    }
+    else
+    {
+        /* We have already `loaded' the whole PFA font file into memory; */
+        /* if this is a memory resource, allocate a new block to hold    */
+        /* the private dict.  Otherwise, simply overwrite into the base  */
+        /* dictionary block in the heap.                                 */
+
+        /* first of all, look at the `eexec' keyword */
+        var cur = dublicate_pointer(parser.base_dict);
+        var limit = cur.pos + parser.base_len;
+        var c = 0;
+
+        var _go_to_found = 0;
+
+        while (true)
+        {
+            for (;;)
+            {
+                c = cur.data[cur.pos];
+                if (c == FT_Common.SYMBOL_CONST_e && cur.pos + 9 < limit)  /* 9 = 5 letters for `eexec' + */
+                {
+                    if (cur.data[cur.pos + 1] == FT_Common.SYMBOL_CONST_e && cur.data[cur.pos + 2] == FT_Common.SYMBOL_CONST_x &&
+                        cur.data[cur.pos + 3] == FT_Common.SYMBOL_CONST_e && cur.data[cur.pos + 4] == FT_Common.SYMBOL_CONST_c)
+                        break;
+                }
+                cur.pos++;
+                if (cur.pos >= limit)
+                    return FT_Common.FT_Err_Invalid_File_Format;
+            }
+
+            /* check whether `eexec' was real -- it could be in a comment */
+            /* or string (as e.g. in u003043t.gsf from ghostscript)       */
+            parser.root.cursor = dublicate_pointer(parser.base_dict);
+            parser.root.limit  = cur.pos + 9;
+
+            cur = dublicate_pointer(parser.root.cursor);
+
+            limit = parser.root.limit;
+
+            while (cur.pos < limit)
+            {
+                if (cur.data[cur.pos] == FT_Common.SYMBOL_CONST_e && _strncmp_data(cur, "eexec", 5) == 0)
+                {
+                    _go_to_found = 1;
+                    break;
+                }
+
+                parser.root.funcs.skip_PS_token(parser.root);
+                if (parser.root.error != 0)
+                    break;
+                parser.root.funcs.skip_spaces(parser.root);
+                cur.pos = parser.root.cursor.pos;
+            }
+
+            if (_go_to_found == 1)
+                break;
+
+            /* we haven't found the correct `eexec'; go back and continue */
+            /* searching                                                  */
+            cur.pos   = limit;
+            limit = parser.base_dict.pos + parser.base_len;
+        }
+
+        /* now determine where to write the _encrypted_ binary private  */
+        /* dictionary.  We overwrite the base dictionary for disk-based */
+        /* resources and allocate a new block otherwise                 */
+        parser.root.limit = parser.base_dict.pos + parser.base_len;
+
+        parser.root.funcs.skip_PS_token(parser.root);
+        cur.pos = parser.root.cursor.pos;
+
+        /* according to the Type1 spec, the first cipher byte must not be  */
+        /* an ASCII whitespace character code (blank, tab, carriage return */
+        /* or line feed).  We have seen Type 1 fonts with two line feed    */
+        /* characters...  So skip now all whitespace character codes.      */
+        while (cur.pos < limit  && (cur.data[cur.pos] == FT_Common.SYMBOL_CONST_SPACE || cur.data[cur.pos] == FT_Common.SYMBOL_CONST_ST || cur.data[cur.pos] == FT_Common.SYMBOL_CONST_SR || cur.data[cur.pos] == FT_Common.SYMBOL_CONST_SN))
+            cur.pos++;
+        if (cur.pos >= limit)
+            return FT_Common.FT_Err_Invalid_File_Format;
+
+        size = parser.base_len - (cur.pos - parser.base_dict.pos);
+
+        if (parser.in_memory == 1)
+        {
+            /* note that we allocate one more byte to put a terminating `0' */
+            parser.private_dict = memory.Alloc(size + 1);
+            parser.private_len = size;
+        }
+        else
+        {
+            parser.single_block = 1;
+            parser.private_dict = dublicate_pointer(parser.base_dict);
+            parser.private_len  = size;
+            parser.base_dict    = null;
+            parser.base_len     = 0;
+        }
+
+        /* now determine whether the private dictionary is encoded in binary */
+        /* or hexadecimal ASCII format -- decode it accordingly              */
+
+        /* we need to access the next 4 bytes (after the final \r following */
+        /* the `eexec' keyword); if they all are hexadecimal digits, then   */
+        /* we have a case of ASCII storage                                  */
+
+        if (_isxdigit(cur[0]) && _isxdigit(cur[1]) && _isxdigit(cur[2]) && _isxdigit(cur[3]))
+        {
+            /* ASCII hexadecimal encoding */
+            parser.root.cursor = cur.pos;
+            var ret = psaux.ps_parser_funcs.to_bytes(parser.root, parser.private_dict, parser.private_len, 0);
+            parser.private_len = ret.num_bytes;
+
+            /* put a safeguard */
+            parser.private_dict[len] = FT_Common.SYMBOL_CONST_S0;
+        }
+        else
+        {
+            var mem = memory.Alloc(size);
+            for (var i = 0; i < size; i++)
+                mem.data[i] = cur.data[cur.pos + i];
+
+            var _p = parser.private_dict.data;
+            var _n = parser.private_dict.pos;
+            for (var i = 0; i < size; i++)
+                _p[_n + i] = mem.data[i];
+
+            mem = null;
+        }
+
+    }
+
+    /* we now decrypt the encoded binary private dictionary */
+    var _mem = dublicate_pointer(parser.private_dict);
+    psaux.t1_decrypt(_mem, parser.private_len, 55665);
+
+    /* replace the four random bytes at the beginning with whitespace */
+    var _d = parser.private_dict.data;
+    _d[0] = FT_Common.SYMBOL_CONST_SPACE;
+    _d[1] = FT_Common.SYMBOL_CONST_SPACE;
+    _d[2] = FT_Common.SYMBOL_CONST_SPACE;
+    _d[3] = FT_Common.SYMBOL_CONST_SPACE;
+
+    parser.root.base   = dublicate_pointer(parser.private_dict);
+    parser.root.cursor = dublicate_pointer(parser.private_dict);
+    parser.root.limit  = parser.private_dict.pos + parser.private_len;
+
+    return error;
+}
+
+/******************************************************************************/
+// objs
+/******************************************************************************/
+var T1_SizeRec = FT_Size;
+
+function T1_GlyphSlotRec()
+{
+    this.root = new FT_GlyphSlot();
+    this.root.base_root = this;
+
+    this.hint = 0;
+    this.scaled = 0;
+
+    this.max_points = 0;
+    this.max_contours = 0;
+
+    this.x_scale = 0;
+    this.y_scale = 0;
+}
+
+function T1_Size_Get_Globals_Funcs(size)
+{
+    return null;
+
+    var pshinter = size.face.pshinter;
+    var module = size.face.driver.library.FT_Get_Module("pshinter");
+    if (module != null && pshinter != null && pshinter.get_globals_funcs != null)
+        return pshinter.get_globals_funcs(module);
+    return null;
+}
+
+function T1_Size_Done(size)
+{
+    if (size.internal != null)
+    {
+        var funcs = T1_Size_Get_Globals_Funcs(size);
+        if (funcs != null)
+            funcs.destroy(size.internal);
+
+        size.internal = null;
+    }
+}
+
+function T1_Size_Init()
+{
+    var size  = new FT_Size();
+    var funcs = T1_Size_Get_Globals_Funcs(size);
+
+    if (funcs != null)
+    {
+        // TODO: (hints)
+    }
+
+    return size;
+}
+
+function T1_Size_Request(size, req)
+{
+    var funcs = T1_Size_Get_Globals_Funcs(size);
+    FT_Request_Metrics(size.face, req);
+
+    if (funcs != null)
+        funcs.set_scale(size.internal, size.metrics.x_scale, size.metrics.y_scale, 0, 0);
+
+    return 0;
+}
+
+function T1_GlyphSlot_Done(slot)
+{
+    slot.internal.glyph_hints = null;
+}
+
+function T1_GlyphSlot_Init(slot)
+{
+    var face = slot.face;
+    var pshinter = face.pshinter;
+
+    if (pshinter != null)
+    {
+        var module = face.driver.library.FT_Get_Module("pshinter");
+        if (module != null)
+        {
+            var funcs = pshinter.get_t1_funcs(module);
+            slot.internal.glyph_hints = funcs;
+        }
+    }
+    return 0;
+}
+
+function T1_Face_Done(face)
+{
+    if (face == null)
+        return;
+
+    var memory = face.memory;
+    var type1 = face.type1;
+
+    //#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT
+    /* release multiple masters information */
+    if (face.buildchar != null)
+    {
+        face.buildchar = null;
+        face.len_buildchar = 0;
+    }
+
+    T1_Done_Blend(face);
+    face.blend = 0;
+    //#endif
+
+    /* release font info strings */
+    var info = type1.font_info;
+
+    info.version = null;
+    info.notice = null;
+    info.full_name = null;
+    info.family_name = null;
+    info.weight = null;
+
+    /* release top dictionary */
+    type1.charstrings_len = null;
+    type1.charstrings = null;
+    type1.glyph_names = null;
+
+    type1.subrs = null;
+    type1.subrs_len = null;
+
+    type1.subrs_block = null;
+    type1.charstrings_block = null;
+    type1.glyph_names_block = null;
+
+    type1.encoding.char_index = null;
+    type1.encoding.char_name = null;
+    type1.font_name = null;
+
+    //#ifndef T1_CONFIG_OPTION_NO_AFM
+    /* release afm data if present */
+    if (face.afm_data != null)
+    {
+        T1_Done_Metrics(memory, face.afm_data);
+        face.afm_data = null;
+    }
+    //#endif
+
+    face.family_name = "";
+    face.style_name  = "";
+}
+
+function T1_Face_Init(stream, face, face_index, num_params, params)
+{
+    var type1 = face.type1;
+    var info = type1.font_info;
+
+    face.num_faces = 1;
+
+    var psnames = FT_FACE_FIND_GLOBAL_SERVICE(face, FT_SERVICE_ID_POSTSCRIPT_CMAPS);
+    face.psnames = psnames;
+
+    var psaux = face.driver.library.FT_Get_Module_Interface("psaux");
+    face.psaux = psaux;
+
+    face.pshinter = face.driver.library.FT_Get_Module_Interface("pshinter");
+
+    /* open the tokenizer; this will also check the font format */
+    var error = T1_Open_Face(face);
+    if (error != 0)
+        return error;
+
+    /* if we just wanted to check the format, leave successfully now */
+    if (face_index < 0)
+        return error;
+
+    /* check the face index */
+    if (face_index > 0)
+        return FT_Common.FT_Err_Invalid_Argument;
+
+    /* now load the font program into the face object */
+    /* initialize the face object fields */
+    /* set up root face fields */
+    face.num_glyphs = type1.num_glyphs;
+    face.face_index = 0;
+
+    face.face_flags = FT_Common.FT_FACE_FLAG_SCALABLE | FT_Common.FT_FACE_FLAG_HORIZONTAL | FT_Common.FT_FACE_FLAG_GLYPH_NAMES | FT_Common.FT_FACE_FLAG_HINTER;
+
+    if (info.is_fixed_pitch == 1)
+        face.face_flags |= FT_Common.FT_FACE_FLAG_FIXED_WIDTH;
+
+    if (face.blend != null)
+        face.face_flags |= FT_Common.FT_FACE_FLAG_MULTIPLE_MASTERS;
+
+    /* XXX: TODO -- add kerning with .afm support */
+    /* The following code to extract the family and the style is very   */
+    /* simplistic and might get some things wrong.  For a full-featured */
+    /* algorithm you might have a look at the whitepaper given at       */
+    /*                                                                  */
+    /*   http://blogs.msdn.com/text/archive/2007/04/23/wpf-font-selection-model.aspx */
+
+    /* get style name -- be careful, some broken fonts only */
+    /* have a `/FontName' dictionary entry!                 */
+    face.family_name = info.family_name;
+    face.style_name = null;
+
+    if (face.family_name != null)
+    {
+        var full = 0;
+        var family = 0;
+
+        var full_len = info.full_name.length;
+        var family_len = face.family_name.length;
+
+        if (full < full_len)
+        {
+            var the_same = 1;
+            while (full < full_len)
+            {
+                var _1 = info.full_name.charCodeAt(full);
+                var _2 = (family < family_len) ? face.family_name.charCodeAt(family) : 0;
+
+                if (_1 == _2)
+                {
+                    family++;
+                    full++;
+                }
+                else
+                {
+                    if (_1 == FT_Common.SYMBOL_CONST_SPACE || _1 == FT_Common.SYMBOL_CONST_MATH_MINUS)
+                        full++;
+                    else if (_2 == FT_Common.SYMBOL_CONST_SPACE || _2 == FT_Common.SYMBOL_CONST_MATH_MINUS)
+                        family++;
+                    else
+                    {
+                        the_same = 0;
+
+                        if (family == family_len)
+                            face.style_name = full;
+                        break;
+                    }
+                }
+            }
+
+            if (the_same == 1)
+                face.style_name = "Regular";
+        }
+    }
+    else
+    {
+        /* do we have a `/FontName'? */
+        if (type1.font_name != null)
+            face.family_name = type1.font_name;
+    }
+
+    if (face.style_name != null)
+    {
+        if (info.weight != null)
+            face.style_name = info.weight;
+        else
+            face.style_name = "Regular";
+    }
+
+    /* compute style flags */
+    face.style_flags = 0;
+    if (info.italic_angle != 0)
+        face.style_flags |= FT_Common.FT_STYLE_FLAG_ITALIC;
+    if (info.weight != null)
+    {
+        if (info.weight == "Bold" || info.weight == "Black")
+            face.style_flags |= FT_Common.FT_STYLE_FLAG_BOLD;
+    }
+
+    /* no embedded bitmap support */
+    face.num_fixed_sizes = 0;
+    face.available_sizes = 0;
+
+    face.bbox.xMin = type1.font_bbox.xMin >> 16;
+    face.bbox.yMin = type1.font_bbox.yMin >> 16;
+    /* no `U' suffix here to 0xFFFF! */
+    face.bbox.xMax = (type1.font_bbox.xMax + 0xFFFF) >> 16;
+    face.bbox.yMax = (type1.font_bbox.yMax + 0xFFFF) >> 16;
+
+    /* Set units_per_EM if we didn't set it in parse_font_matrix. */
+    if (face.units_per_EM == 0)
+        face.units_per_EM = 1000;
+
+    face.ascender  = face.bbox.yMax;
+    face.descender = face.bbox.yMin;
+
+    face.height = parseInt((face.units_per_EM * 12) / 10);
+    if (face.height < (face.ascender - face.descender))
+        face.height = (face.ascender - face.descender);
+
+    /* now compute the maximum advance width */
+    face.max_advance_width = (face.bbox.xMax);
+
+    var ret = T1_Compute_Max_Advance(face);
+
+    /* in case of error, keep the standard width */
+    if (ret.err == 0)
+        face.max_advance_width = FT_RoundFix(ret.max_advance) >> 16;
+    else
+        error = 0;   /* clear error */
+
+    face.max_advance_height = face.height;
+
+    face.underline_position  = info.underline_position;
+    face.underline_thickness = info.underline_thickness;
+
+    if (psnames != null && psaux != null)
+    {
+        var cmap_classes = psaux.t1_cmap_classes;
+        var charmap = new FT_CharMapRec();
+
+        charmap.face = face;
+
+        /* first of all, try to synthesize a Unicode charmap */
+        charmap.platform_id = FT_Common.TT_PLATFORM_MICROSOFT;
+        charmap.encoding_id = FT_Common.TT_MS_ID_UNICODE_CS;
+        charmap.encoding    = FT_Common.FT_ENCODING_UNICODE;
+
+        var __cmap = FT_CMap_New(cmap_classes.unicode, null, charmap);
+        __cmap = null;
+        error = FT_Error;
+        FT_Error = 0;
+        if (error != 0 && FT_Common.FT_Err_No_Unicode_Glyph_Name != error)
+            return error;
+        error = 0;
+
+        /* now, generate an Adobe Standard encoding when appropriate */
+        charmap.platform_id = FT_Common.TT_PLATFORM_ADOBE;
+        var clazz = null;
+
+        switch (type1.encoding_type)
+        {
+            case FT_Common.T1_ENCODING_TYPE_STANDARD:
+                charmap.encoding    = FT_Common.FT_ENCODING_ADOBE_STANDARD;
+                charmap.encoding_id = FT_Common.TT_ADOBE_ID_STANDARD;
+                clazz               = cmap_classes.standard;
+                break;
+
+            case FT_Common.T1_ENCODING_TYPE_EXPERT:
+                charmap.encoding    = FT_Common.FT_ENCODING_ADOBE_EXPERT;
+                charmap.encoding_id = FT_Common.TT_ADOBE_ID_EXPERT;
+                clazz               = cmap_classes.expert;
+                break;
+
+            case FT_Common.T1_ENCODING_TYPE_ARRAY:
+                charmap.encoding    = FT_Common.FT_ENCODING_ADOBE_CUSTOM;
+                charmap.encoding_id = FT_Common.TT_ADOBE_ID_CUSTOM;
+                clazz               = cmap_classes.custom;
+                break;
+
+            case FT_Common.T1_ENCODING_TYPE_ISOLATIN1:
+                charmap.encoding    = FT_Common.FT_ENCODING_ADOBE_LATIN_1;
+                charmap.encoding_id = FT_Common.TT_ADOBE_ID_LATIN_1;
+                clazz               = cmap_classes.unicode;
+                break;
+
+            default:
+                break;
+        }
+
+        if (clazz != null)
+        {
+            __cmap = FT_CMap_New(clazz, null, charmap);
+            error = FT_Error;
+            __cmap = null;
+        }
+    }
+
+    return error;
+}
+
+function T1_Driver_Init(driver)
+{
+    return 0;
+}
+
+function T1_Driver_Done(driver)
+{
+}
+
+/******************************************************************************/
+// load
+/******************************************************************************/
+
+function T1_Loader()
+{
+    this.parser = new T1_ParserRec();
+
+    this.num_chars = 0;
+    this.encoding_table = new PS_TableRec();
+    /* encoding character names         */
+
+    this.num_glyphs = 0;
+    this.glyph_names = new PS_TableRec();
+    this.charstrings = new PS_TableRec();
+    this.swap_table = new PS_TableRec();
+
+    this.num_subrs = 0;
+    this.subrs = new PS_TableRec();
+    this.fontdata = 0;
+
+    this.keywords_encountered = 0;
+
+    this.clear = function()
+    {
+        this.parser.clear();
+
+        this.num_chars = 0;
+        this.encoding_table.clear();
+        /* encoding character names         */
+
+        this.num_glyphs = 0;
+        this.glyph_names.clear();
+        this.charstrings.clear();
+        this.swap_table.clear();
+
+        this.num_subrs = 0;
+        this.subrs.clear();
+        this.fontdata = 0;
+
+        this.keywords_encountered = 0;
+    }
+}
+
+function t1_allocate_blend(face, num_designs, num_axis)
+{
+    var blend = face.blend;
+    if (blend == null)
+    {
+        blend = new PS_BlendRec();
+        blend.num_default_design_vector = 0;
+        face.blend = blend;
+    }
+
+    /* allocate design data if needed */
+    if (num_designs > 0)
+    {
+        if (blend.num_designs == 0)
+        {
+            blend.font_infos[0] = face.type1.font_info;
+            blend.privates[0] = face.type1.private_dict;
+            blend.bboxes[0] = face.type1.font_bbox;
+
+            for (var i = 1; i <= num_designs; i++)
+            {
+                blend.font_infos[i] = new PS_FontInfoRec();
+                blend.privates[i] = new PS_PrivateRec();
+                blend.bboxes[i] = new FT_BBox();
+            }
+
+            blend.weight_vector = CreateIntArray(num_designs * 2);
+            blend.default_weight_vector = num_designs;
+
+            blend.num_designs = num_designs;
+        }
+        else if (blend.num_designs != num_designs)
+            return FT_Common.FT_Err_Invalid_File_Format;
+    }
+
+    /* allocate axis data if needed */
+    if (num_axis > 0)
+    {
+        if (blend.num_axis != 0 && blend.num_axis != num_axis)
+            return FT_Common.FT_Err_Invalid_File_Format;
+
+        blend.num_axis = num_axis;
+    }
+
+    /* allocate the blend design pos table if needed */
+    num_designs = blend.num_designs;
+    num_axis    = blend.num_axis;
+    if (num_designs && num_axis && blend.design_pos[0] == null)
+    {
+        for (var i = 0; i < num_designs; i++)
+            blend.design_pos[i] = CreateIntArray(num_axis);
+    }
+    return 0;
+}
+
+function T1_Get_Multi_Master(face, master)
+{
+    var blend = face.blend;
+    if (null == blend)
+        return FT_Common.FT_Err_Invalid_Argument;
+
+    master.num_axis = blend.num_axis;
+    master.num_designs = blend.num_designs;
+
+    for (var n = 0; n < blend.num_axis; n++)
+    {
+        var axis = master.axis[n];
+        var map = blend.design_map[n];
+
+        axis.name = blend.axis_names[n];
+        axis.minimum = map.design_points[0];
+        axis.maximum = map.design_points[map.num_points - 1];
+    }
+    return 0;
+}
+
+function mm_axis_unmap(axismap, ncv)
+{
+    if (ncv <= axismap.blend_points[0])
+        return (axismap.design_points[0] << 16);
+
+    for (var j = 1; j < axismap.num_points; j++)
+    {
+        if (ncv <= axismap.blend_points[j])
+        {
+            var t = FT_MulDiv(ncv - axismap.blend_points[j - 1], 0x10000, axismap.blend_points[j] - axismap.blend_points[j - 1]);
+            return (axismap.design_points[j - 1] << 16) + FT_MulDiv(t, axismap.design_points[j] - axismap.design_points[j - 1], 1);
+        }
+    }
+
+    return (axismap.design_points[axismap.num_points - 1] << 16);
+}
+
+function mm_weights_unmap(weights, w_s, axiscoords, a_s, axis_count)
+{
+    if (axis_count == 1)
+        axiscoords[a_s] = weights[w_s + 1];
+    else if (axis_count == 2)
+    {
+        axiscoords[a_s] = weights[w_s + 3] + weights[w_s + 1];
+        axiscoords[a_s + 1] = weights[w_s + 3] + weights[w_s + 2];
+    }
+    else if (axis_count == 3)
+    {
+        axiscoords[a_s] = weights[w_s + 7] + weights[w_s + 5] + weights[w_s + 3] + weights[w_s + 1];
+        axiscoords[a_s + 1] = weights[w_s + 7] + weights[w_s + 6] + weights[w_s + 3] + weights[w_s + 2];
+        axiscoords[a_s + 2] = weights[w_s + 7] + weights[w_s + 6] + weights[w_s + 5] + weights[w_s + 4];
+    }
+    else
+    {
+        axiscoords[a_s] = weights[w_s + 15] + weights[w_s + 13] + weights[w_s + 11] + weights[w_s + 9] + weights[w_s + 7] + weights[w_s + 5] + weights[w_s + 3] + weights[w_s + 1];
+        axiscoords[a_s + 1] = weights[w_s + 15] + weights[w_s + 14] + weights[w_s + 11] + weights[w_s + 10] + weights[w_s + 7] + weights[w_s + 6] + weights[w_s + 3] + weights[w_s + 2];
+        axiscoords[a_s + 2] = weights[w_s + 15] + weights[w_s + 14] + weights[w_s + 13] + weights[w_s + 12] + weights[w_s + 7] + weights[w_s + 6] + weights[w_s + 5] + weights[w_s + 4];
+        axiscoords[a_s + 3] = weights[w_s + 15] + weights[w_s + 14] + weights[w_s + 13] + weights[w_s + 12] + weights[w_s + 11] + weights[w_s + 10] + weights[w_s + 9] + weights[w_s + 8];
+    }
+}
+
+function T1_Get_MM_Var(face)
+{
+    var mmvar = new FT_MM_Var();
+    var mmaster = new FT_Multi_Master();
+    var axiscoords = CreateIntArray(FT_Common.T1_MAX_MM_AXIS);
+    var blend = face.blend;
+
+    var error = T1_Get_Multi_Master(face, mmaster);
+    if (error != 0)
+        return { err: error, mm : null };
+
+    var _num_axis = master.num_axis;
+    mmvar.axis = new Array(_num_axis);
+    for (var i = 0; i < _num_axis; i++)
+        mmvar.axis[i] = new FT_Var_Axis();
+
+    mmvar.num_axis = mmaster.num_axis;
+    mmvar.num_designs = mmaster.num_designs;
+    mmvar.num_namedstyles = 0xFFFFFFFF;                /* Does not apply */
+    /* Point to axes after MM_Var struct */
+    mmvar.namedstyle = null;
+
+    for (var i = 0 ; i < _num_axis; i++)
+    {
+        var _axis = mmvar.axis[i];
+
+        _axis.name = mmaster.axis[i].name;
+        _axis.minimum = (mmaster.axis[i].minimum << 16);
+        _axis.maximum = (mmaster.axis[i].maximum << 16);
+        _axis.def = parseInt((_axis.minimum + _axis.maximum) / 2);
+        /* Does not apply.  But this value is in range */
+        _axis.strid = 0xFFFFFFFF;
+        _axis.tag = 0xFFFFFFFF;
+
+        if (_axis.name == "Weight")
+            _axis.tag = 2003265652;//FT_MAKE_TAG("w", "g", "h", "t");
+        else if (_axis.name == "Width")
+            _axis.tag = 2003072104;//FT_MAKE_TAG("w", "d", "t", "h");
+        else if (_axis.name == "OpticalSize")
+            _axis.tag = 1869640570;//FT_MAKE_TAG("o", "p", "s", "z");
+    }
+
+    if (blend.num_designs == (1 << blend.num_axis))
+    {
+        mm_weights_unmap(blend.default_weight_vector, 0, axiscoords, 0, blend.num_axis);
+
+        for (var i = 0; i < _num_axis; i++)
+            mmvar.axis[i].def = mm_axis_unmap(blend.design_map[i], axiscoords[i]);
+    }
+
+    return { err : 0, mm : mmvar };
+}
+
+function T1_Set_MM_Blend(face, num_coords, coords)
+{
+    var blend = face.blend;
+    if (blend != null)
+        return FT_Common.FT_Err_Invalid_Argument;
+
+    if (blend != null && blend.num_axis == num_coords)
+    {
+        for (var n = 0; n < blend.num_designs; n++)
+        {
+            var result = 0x10000;  /* 1.0 fixed */
+
+            for (var m = 0; m < blend.num_axis; m++)
+            {
+                var factor = coords[m];
+                if (factor < 0)
+                    factor = 0;
+                if (factor > 0x10000)
+                    factor = 0x10000;
+                if (( n & (1 << m)) == 0)
+                    factor = 0x10000 - factor;
+
+                result = FT_MulFix(result, factor);
+            }
+            blend.weight_vector[n] = result;
+        }
+    }
+
+    return 0;
+}
+
+function T1_Set_MM_Design(face, num_coords, coords)
+{
+    var blend = face.blend;
+    if (null == blend || blend.num_axis != num_coords)
+        return FT_Common.FT_Err_Invalid_Argument;
+
+    /* compute the blend coordinates through the blend design map */
+    var final_blends = CreateIntArray(FT_Common.T1_MAX_MM_DESIGNS);
+
+    for (var n = 0; n < blend.num_axis; n++)
+    {
+        var design = coords[n];
+        var the_blend = 0;
+        var map = blend.design_map[n];
+        var designs = map.design_points;
+        var blends = map.blend_points;
+        var before = -1, after = -1;
+
+        var is_go_to_found = 0;
+        for (var p = 0; p < map.num_points; p++)
+        {
+            var p_design = designs[p];
+
+            /* exact match? */
+            if (design == p_design)
+            {
+                the_blend = blends[p];
+                is_go_to_found = 1;
+                break;
+            }
+
+            if (design < p_design)
+            {
+                after = p;
+                break;
+            }
+
+            before = p;
+        }
+
+        if (0 == is_go_to_found)
+        {
+            /* now interpolate if necessary */
+            if (before < 0)
+                the_blend = blends[0];
+            else if ( after < 0 )
+                the_blend = blends[map.num_points - 1];
+            else
+                the_blend = FT_MulDiv(design - designs[before], blends[after] - blends[before], designs[after] - designs[before]);
+        }
+
+        final_blends[n] = the_blend;
+    }
+
+    var error = T1_Set_MM_Blend(face, num_coords, final_blends);
+    return error;
+}
+
+function T1_Set_Var_Design(face, num_coords, coords)
+{
+    var lcoords = CreateIntArray(4);          /* maximum axis count is 4 */
+
+    if (num_coords <= 4 && num_coords > 0)
+    {
+        for (var i = 0; i < num_coords; i++)
+            lcoords[i] = FT_RoundFix(coords[i]) >> 16;
+        var error = T1_Set_MM_Design(face, num_coords, lcoords);
+        return error;
+    }
+    return FT_Common.FT_Err_Invalid_Argument;
+}
+
+function T1_Done_Blend(face)
+{
+    face.blend = null;
+}
+
+function t1_parse_blend_axis_types(face, loader)
+{
+    var axis_tokens = new Array(FT_Common.T1_MAX_MM_AXIS);
+    for (var i = 0; i < FT_Common.T1_MAX_MM_AXIS; i++)
+        axis_tokens[i] = new T1_TokenRec();
+
+    /* take an array of objects */
+    var num_axis = loader.parser.root.funcs.to_token_array(loader.parser.root, axis_tokens, FT_Common.T1_MAX_MM_AXIS);
+    if (num_axis < 0)
+    {
+        loader.parser.root.error = FT_Common.FT_Err_Ignore;
+        return;
+    }
+    if (num_axis == 0 || num_axis > FT_Common.T1_MAX_MM_AXIS)
+    {
+        loader.parser.root.error = FT_Common.FT_Err_Invalid_File_Format;
+        return;
+    }
+
+    /* allocate blend if necessary */
+    var error = t1_allocate_blend(face, 0, num_axis);
+    if (error != 0)
+    {
+        loader.parser.root.error = error;
+        return;
+    }
+
+    var blend = face.blend;
+    
+    /* each token is an immediate containing the name of the axis */
+    for (var n = 0; n < num_axis; n++)
+    {
+        var token = axis_tokens[n];
+        
+        /* skip first slash, if any */
+        if (token.start.data[token.start.pos] == FT_Common.SYMBOL_CONST_BS)
+            token.start.pos++;
+
+        var len = token.limit - token.start.pos;
+        if (len == 0)
+        {
+            loader.parser.root.error = FT_Common.FT_Err_Invalid_File_Format;
+            return;
+        }
+
+        blend.axis_names[n] = "";
+        for (var i = 0; i < len; i++)
+        {
+            blend.axis_names[n] += String.fromCharCode(token.start.data[token.start.pos + n]);
+        }
+    }
+
+    loader.parser.root.error = error;
+}
+
+function t1_parse_blend_design_positions(face, loader)
+{
+    var design_tokens = new Array(FT_Common.T1_MAX_MM_DESIGNS);
+    for (var i = 0; i < FT_Common.T1_MAX_MM_DESIGNS; i++)
+        design_tokens[i] = new T1_TokenRec();
+
+    var parser = loader.parser;
+
+    /* get the array of design tokens -- compute number of designs */
+    var num_designs = parser.root.funcs.to_token_array(parser.root, design_tokens, FT_Common.T1_MAX_MM_DESIGNS);
+    if (num_designs < 0)
+    {
+        parser.root.error = FT_Common.FT_Err_Ignore;
+        return;
+    }
+    if (num_designs == 0 || num_designs > FT_Common.T1_MAX_MM_DESIGNS)
+    {
+        loader.parser.root.error = FT_Common.FT_Err_Invalid_File_Format;
+        return;
+    }
+
+    var old_cursor = parser.root.cursor;
+    var old_limit = parser.root.limit;
+
+    var blend = face.blend;
+    var num_axis = 0;  /* make compiler happy */
+
+    var error = 0;
+    for (var n = 0; n < num_designs; n++)
+    {
+        /* read axis/coordinates tokens */
+        var token = design_tokens[n];
+        parser.root.cursor = token.start.pos;
+        parser.root.limit = token.limit;
+
+        var axis_tokens = new Array(FT_Common.T1_MAX_MM_AXIS);
+        for (var i = 0; i < FT_Common.T1_MAX_MM_AXIS; i++)
+            axis_tokens[i] = new T1_TokenRec();
+        
+        var n_axis = parser.root.funcs.to_token_array(parser.root, axis_tokens, FT_Common.T1_MAX_MM_AXIS);
+
+        if (n == 0)
+        {
+            if (n_axis <= 0 || n_axis > FT_Common.T1_MAX_MM_AXIS)
+            {
+                loader.parser.root.error = FT_Common.FT_Err_Invalid_File_Format;
+                return;
+            }
+
+            num_axis = n_axis;
+            error = t1_allocate_blend( face, num_designs, num_axis );
+            if (error != 0)
+            {
+                loader.parser.root.error = error;
+                return;
+            }
+            blend = face.blend;
+        }
+        else if (n_axis != num_axis)
+        {
+            loader.parser.root.error = FT_Common.FT_Err_Invalid_File_Format;
+            return;
+        }
+
+        /* now read each axis token into the design position */
+        for (var axis = 0; axis < n_axis; axis++)
+        {
+            var token2 = axis_tokens[axis];
+
+            parser.root.cursor = token2.start.pos;
+            parser.root.limit  = token2.limit;
+            blend.design_pos[n][axis] = parser.root.funcs.to_fixed(parser, 0);
+        }
+    }
+
+    parser.root.cursor = old_cursor;
+    parser.root.limit  = old_limit;
+
+    parser.root.error = error;
+}
+
+function t1_parse_blend_design_map(face, loader)
+{
+    var parser = loader.parser;
+
+    var axis_tokens = new Array(FT_Common.T1_MAX_MM_AXIS);
+    for (var i = 0; i < FT_Common.T1_MAX_MM_AXIS; i++)
+        axis_tokens[i] = new T1_TokenRec();
+
+    var num_axis = parser.root.funcs.to_token_array(parser.root, axis_tokens, FT_Common.T1_MAX_MM_AXIS);
+
+    if (num_axis < 0)
+    {
+        parser.root.error = FT_Common.FT_Err_Ignore;
+        return;
+    }
+    if (num_axis == 0 || num_axis > FT_Common.T1_MAX_MM_AXIS)
+    {
+        parser.root.error = FT_Common.FT_Err_Invalid_File_Format;
+        return;
+    }
+
+    var old_cursor = parser.root.cursor;
+    var old_limit = parser.root.limit;
+
+    var error = t1_allocate_blend(face, 0, num_axis);
+    if (error != 0)
+    {
+        parser.root.error = error;
+        return;
+    }
+    var blend = face.blend;
+
+    /* now read each axis design map */
+    for (var n = 0; n < num_axis; n++)
+    {
+        var map = blend.design_map[n];
+
+        var point_tokens = new Array(FT_Common.T1_MAX_MM_MAP_POINTS);
+        for (var i = 0; i < FT_Common.T1_MAX_MM_MAP_POINTS; i++)
+            point_tokens[i] = new T1_TokenRec();
+
+        var axis_token = axis_tokens[n];
+
+        parser.root.cursor = axis_token.start.pos;
+        parser.root.limit  = axis_token.limit;
+
+        var num_points = parser.root.funcs.to_token_array(parser.root, point_tokens, FT_Common.T1_MAX_MM_MAP_POINTS);
+
+        if (num_points <= 0 || num_points > FT_Common.T1_MAX_MM_MAP_POINTS)
+        {
+            parser.root.error = FT_Common.FT_Err_Invalid_File_Format;
+            return;
+        }
+
+        /* allocate design map data */
+        map.design_points = CreateIntArray(num_points);
+        map.blend_points = CreateIntArray(num_points);
+        map.num_points = num_points;
+
+        for (var p = 0; p < num_points; p++)
+        {
+            var point_token = point_tokens[p];
+
+            /* don't include delimiting brackets */
+            parser.root.cursor = point_token.start.pos + 1;
+            parser.root.limit = point_token.limit - 1;
+
+            map.design_points[p] = parser.root.funcs.to_int(parser.root);
+            map.blend_points [p] = parser.root.funcs.to_fixed(parser.root, 0);
+        }
+    }
+
+    parser.root.cursor = old_cursor;
+    parser.root.limit  = old_limit;
+
+    parser.root.error = error;
+}
+
+function t1_parse_weight_vector(face, loader)
+{
+    var design_tokens = new Array(FT_Common.T1_MAX_MM_DESIGNS);
+    for (var i = 0; i < FT_Common.T1_MAX_MM_DESIGNS; i++)
+        design_tokens[i] = new T1_TokenRec();
+
+    var parser = loader.parser;
+    var blend = face.blend;
+    var num_designs = parser.root.funcs.to_token_array(parser.root, design_tokens, FT_Common.T1_MAX_MM_DESIGNS);
+    if (num_designs < 0)
+    {
+        parser.root.error = FT_Common.FT_Err_Ignore;
+        return;
+    }
+    if (num_designs == 0 || num_designs > FT_Common.T1_MAX_MM_DESIGNS)
+    {
+        parser.root.error = FT_Common.FT_Err_Invalid_File_Format;
+        return;
+    }
+
+    var error = 0;
+    if (blend == null || blend.num_designs == 0)
+    {
+        error = t1_allocate_blend(face, num_designs, 0 );
+        if (error != 0)
+        {
+            parser.root.error = error;
+            return;
+        }
+        blend = face.blend;
+    }
+    else if (blend.num_designs != num_designs)
+    {
+        parser.root.error = FT_Common.FT_Err_Invalid_File_Format;
+        return;
+    }
+
+    var old_cursor = parser.root.cursor;
+    var old_limit = parser.root.limit;
+
+    for (var n = 0; n < num_designs; n++)
+    {
+        var token = design_tokens[n];
+        parser.root.cursor = token.start.pos;
+        parser.root.limit = token.limit;
+
+        var _temp = parser.root.funcs.to_fixed(parser.root, 0);
+        blend.weight_vector[n] = _temp;
+        blend.weight_vector[blend.default_weight_vector + n] = _temp;
+    }
+
+    parser.root.cursor = old_cursor;
+    parser.root.limit  = old_limit;
+
+    parser.root.error = error;
+}
+
+function t1_parse_buildchar(face, loader)
+{
+    face.len_buildchar = loader.parser.funcs.to_fixed_array(loader.parser.root, 0, null, 0);
+}
+
+function t1_load_keyword(face, loader, field)
+{
+    var blend = face.blend;
+    if (blend != null && blend.num_designs == 0)
+        blend = null;
+
+    /* if the keyword has a dedicated callback, call it */
+    if (field.type == FT_Common.T1_FIELD_TYPE_CALLBACK)
+    {
+        field.reader(face, loader);
+        return loader.parser.root.error;
+    }
+
+    var max_objects = 0;
+    var arr = null;
+
+    /* now, the keyword is either a simple field, or a table of fields; */
+    /* we are now going to take care of it                              */
+    switch (field.location)
+    {
+        case FT_Common.T1_FIELD_LOCATION_FONT_INFO:
+            if (blend != null)
+            {
+                arr = blend.font_infos;
+                max_objects = blend.num_designs;
+            }
+            else
+            {
+                arr = new Array(1);
+                arr[0] = face.type1.font_info;
+                max_objects  = 0;
+            }
+            break;
+
+        case FT_Common.T1_FIELD_LOCATION_FONT_EXTRA:
+            arr = new Array(1);
+            arr[0] = face.type1.font_extra;
+            max_objects  = 0;
+            break;
+
+        case FT_Common.T1_FIELD_LOCATION_PRIVATE:
+            if (blend != null)
+            {
+                arr = blend.privates;
+                max_objects = blend.num_designs;
+            }
+            else
+            {
+                arr = new Array(1);
+                arr[0] = face.type1.private_dict;
+                max_objects = 0;
+            }
+            break;
+
+        case FT_Common.T1_FIELD_LOCATION_BBOX:
+            if (blend != null)
+            {
+                arr = blend.bboxes;
+                max_objects = blend.num_designs;
+            }
+            else
+            {
+                arr = new Array(1);
+                arr[0] = face.type1.font_bbox;
+                max_objects = 0;
+            }
+            break;
+
+        case FT_Common.T1_FIELD_LOCATION_LOADER:
+            arr = new Array(1);
+            arr[0] = loader;
+            max_objects  = 0;
+            break;
+
+        case FT_Common.T1_FIELD_LOCATION_FACE:
+            arr = new Array(1);
+            arr[0] = face;
+            max_objects  = 0;
+            break;
+
+        case FT_Common.T1_FIELD_LOCATION_BLEND:
+            arr = new Array(1);
+            arr[0] = loader;
+            max_objects  = 0;
+            break;
+
+        default:
+            arr = new Array(1);
+            arr[0] = face.type1;
+            max_objects  = 0;
+    }
+
+    if (field.type == FT_Common.T1_FIELD_TYPE_INTEGER_ARRAY || field.type == FT_Common.T1_FIELD_TYPE_FIXED_ARRAY)
+        return loader.parser.root.funcs.load_field_table(loader.parser.root, field, arr, max_objects, 0);
+
+    return loader.parser.root.funcs.load_field(loader.parser.root, field, arr, max_objects, 0);
+}
+
+function t1_parse_private(face, loader)
+{
+    loader.keywords_encountered |= FT_Common.T1_PRIVATE;
+}
+
+function _t1_read_binary_data(parser)
+{
+    var ret = { size: 0, base: null, err: 0 };
+
+    var limit = parser.root.limit;
+
+    /* the binary data has one of the following formats */
+    /*                                                  */
+    /*   `size' [white*] RD white ....... ND            */
+    /*   `size' [white*] -| white ....... |-            */
+    /*                                                  */
+
+    parser.root.funcs.skip_spaces(parser.root);
+    var cur = dublicate_pointer(parser.root.cursor);
+
+    if (cur.pos < limit && (cur.data[cur.pos] >= FT_Common.SYMBOL_CONST_0) && (cur.data[cur.pos] <= FT_Common.SYMBOL_CONST_9))
+    {
+        var s = parser.root.funcs.to_int(parser.root);
+        parser.root.funcs.skip_PS_token(parser.root);
+
+        /* there is only one whitespace char after the */
+        /* `RD' or `-|' token                          */
+        ret.base = dublicate_pointer(parser.root.cursor);
+        ret.base.pos += 1;
+
+        if (s >= 0 && s < (limit - ret.base.pos))
+        {
+            parser.root.cursor.pos += (s + 1);
+            ret.size = s;
+            ret.err = (parser.root.error == 0) ? 1 : 0;
+            return ret;
+        }
+    }
+
+    parser.root.error = FT_Common.FT_Err_Invalid_File_Format;
+    return ret;
+}
+
+function t1_parse_font_matrix(face, loader)
+{
+    var parser = loader.parser;
+    var matrix = face.type1.font_matrix;
+    var offset = face.type1.font_offset;
+
+    var temp = CreateIntArray(6);
+
+    var result = parser.root.funcs.to_fixed_array(parser.root, 6, temp, 3);
+
+    if (result < 0)
+    {
+        parser.root.error = FT_Common.FT_Err_Invalid_File_Format;
+        return;
+    }
+
+    var temp_scale = Math.abs(temp[3]);
+
+    if (temp_scale == 0)
+    {
+        parser.root.error = FT_Common.FT_Err_Invalid_File_Format;
+        return;
+    }
+
+    /* Set Units per EM based on FontMatrix values.  We set the value to */
+    /* 1000 / temp_scale, because temp_scale was already multiplied by   */
+    /* 1000 (in t1_tofixed, from psobjs.c).                              */
+    face.units_per_EM = (FT_DivFix(1000 * 0x10000, temp_scale) >> 16);
+
+    /* we need to scale the values by 1.0/temp_scale */
+    if (temp_scale != 0x10000)
+    {
+        temp[0] = FT_DivFix(temp[0], temp_scale);
+        temp[1] = FT_DivFix(temp[1], temp_scale);
+        temp[2] = FT_DivFix(temp[2], temp_scale);
+        temp[4] = FT_DivFix(temp[4], temp_scale);
+        temp[5] = FT_DivFix(temp[5], temp_scale);
+        temp[3] = temp[3] < 0 ? -0x10000 : 0x10000;
+    }
+
+    matrix.xx = temp[0];
+    matrix.yx = temp[1];
+    matrix.xy = temp[2];
+    matrix.yy = temp[3];
+
+    /* note that the offsets must be expressed in integer font units */
+    offset.x = temp[4] >> 16;
+    offset.y = temp[5] >> 16;
+}
+
+function t1_parse_encoding(face, loader)
+{
+    var parser = loader.parser;
+    var limit = parser.root.limit;
+
+    var memory = parser.root.memory;
+
+    var psaux = face.psaux;
+
+    parser.root.funcs.skip_spaces(parser.root);
+    var cur = dublicate_pointer(parser.root.cursor);
+    if (cur.pos >= limit)
+    {
+        parser.root.error = FT_Common.FT_Err_Invalid_File_Format;
+        return;
+    }
+
+    /* if we have a number or `[', the encoding is an array, */
+    /* and we must load it now                               */
+    var _cur_v = cur.data[cur.pos];
+    if ((_cur_v >= FT_Common.SYMBOL_CONST_0 && _cur_v <= FT_Common.SYMBOL_CONST_9) || _cur_v == FT_Common.SYMBOL_CONST_LS2)
+    {
+        var encode = face.type1.encoding;
+        var count, n;
+        var char_table = loader.encoding_table;
+        var only_immediates = 0;
+
+        /* read the number of entries in the encoding; should be 256 */
+        if (_cur_v == FT_Common.SYMBOL_CONST_LS2)
+        {
+            count = 256;
+            only_immediates = 1;
+            parser.root.cursor.pos++;
+        }
+        else
+            count = parser.root.funcs.to_int(parser.root);
+
+        parser.root.funcs.skip_spaces(parser.root);
+        if (parser.root.cursor.pos >= limit)
+            return;
+
+        /* we use a T1_Table to store our charnames */
+        loader.num_chars = encode.num_chars = count;
+
+        encode.char_index = CreateUIntArray(count);
+        encode.char_name = CreateNullArray(count);
+        var error = psaux.ps_table_funcs.init(char_table, count, memory);
+        if (error != 0)
+        {
+            parser.root.error = error;
+            return;
+        }
+
+        /* We need to `zero' out encoding_table.elements */
+        for (n = 0; n < count; n++)
+        {
+            var notdef_name = memory.Alloc(8);
+            notdef_name.data[0] = FT_Common.SYMBOL_CONST_POINT;
+            notdef_name.data[1] = FT_Common.SYMBOL_CONST_n;
+            notdef_name.data[2] = FT_Common.SYMBOL_CONST_o;
+            notdef_name.data[3] = FT_Common.SYMBOL_CONST_t;
+            notdef_name.data[4] = FT_Common.SYMBOL_CONST_d;
+            notdef_name.data[5] = FT_Common.SYMBOL_CONST_e;
+            notdef_name.data[6] = FT_Common.SYMBOL_CONST_f;
+            notdef_name.data[7] = FT_Common.SYMBOL_CONST_S0;
+
+            char_table.funcs.add(char_table, n, notdef_name, 8)
+        }
+
+        /* Now we need to read records of the form                */
+        /*                                                        */
+        /*   ... charcode /charname ...                           */
+        /*                                                        */
+        /* for each entry in our table.                           */
+        /*                                                        */
+        /* We simply look for a number followed by an immediate   */
+        /* name.  Note that this ignores correctly the sequence   */
+        /* that is often seen in type1 fonts:                     */
+        /*                                                        */
+        /*   0 1 255 { 1 index exch /.notdef put } for dup        */
+        /*                                                        */
+        /* used to clean the encoding array before anything else. */
+        /*                                                        */
+        /* Alternatively, if the array is directly given as       */
+        /*                                                        */
+        /*   /Encoding [ ... ]                                    */
+        /*                                                        */
+        /* we only read immediates.                               */
+
+        n = 0;
+        parser.root.funcs.skip_spaces(parser.root);
+
+        while (parser.root.cursor.pos < limit)
+        {
+            cur.pos = parser.root.cursor.pos;
+
+            /* we stop when we encounter a `def' or `]' */
+            if (cur.data[cur.pos] == FT_Common.SYMBOL_CONST_d && cur.pos + 3 < limit)
+            {
+                if (cur.data[cur.pos + 1] == FT_Common.SYMBOL_CONST_e && cur.data[cur.pos + 2] == FT_Common.SYMBOL_CONST_f && IS_PS_DELIM(cur.data[cur.pos + 3]))
+                {
+                    cur.pos += 3;
+                    break;
+                }
+            }
+            if (cur.data[cur.pos] == FT_Common.SYMBOL_CONST_RS2)
+            {
+                cur.pos++;
+                break;
+            }
+
+            /* check whether we've found an entry */
+            if (((cur.data[cur.pos] >= FT_Common.SYMBOL_CONST_0) && (cur.data[cur.pos] <= FT_Common.SYMBOL_CONST_9)) || (only_immediates == 1))
+            {
+                var charcode = 0;
+
+                if (only_immediates == 1)
+                    charcode = n;
+                else
+                {
+                    charcode = parser.root.funcs.to_int(parser.root);
+                    parser.root.funcs.skip_spaces(parser.root);
+                }
+
+                cur.pos = parser.root.cursor.pos;
+
+                if (cur.data[cur.pos] == FT_Common.SYMBOL_CONST_BS && (cur.pos + 2) < limit && (n < count))
+                {
+                    cur.pos++;
+                    parser.root.cursor.pos = cur.pos;
+                    parser.root.funcs.skip_PS_token(parser.root);
+                    if (parser.root.error != 0)
+                        return;
+
+                    var len = parser.root.cursor.pos - cur.pos;
+
+                    parser.root.error = char_table.funcs.add(char_table, charcode, cur, len + 1);
+                    if (parser.root.error != 0)
+                        return;
+                    char_table.elements[charcode][len] = FT_Common.SYMBOL_CONST_S0;
+
+                    n++;
+                }
+                else if (only_immediates == 1)
+                {
+                    /* Since the current position is not updated for           */
+                    /* immediates-only mode we would get an infinite loop if   */
+                    /* we don't do anything here.                              */
+                    /*                                                         */
+                    /* This encoding array is not valid according to the type1 */
+                    /* specification (it might be an encoding for a CID type1  */
+                    /* font, however), so we conclude that this font is NOT a  */
+                    /* type1 font.                                             */
+                    parser.root.error = FT_Common.FT_Err_Unknown_File_Format;
+                    return;
+                }
+            }
+            else
+            {
+                parser.root.funcs.skip_PS_token(parser.root);
+                if (parser.root.error != 0)
+                    return;
+            }
+
+            parser.root.funcs.skip_spaces(parser.root);
+        }
+
+        face.type1.encoding_type = FT_Common.T1_ENCODING_TYPE_ARRAY;
+        parser.root.cursor.pos = cur.pos;
+    }
+    else
+    {
+        if (cur.pos + 17 < limit && _strncmp_data(cur, "StandardEncoding", 16) == 0)
+            face.type1.encoding_type = FT_Common.T1_ENCODING_TYPE_STANDARD;
+        else if (cur + 15 < limit && _strncmp_data(cur, "ExpertEncoding", 14) == 0)
+            face.type1.encoding_type = FT_Common.T1_ENCODING_TYPE_EXPERT;
+        else if (cur + 18 < limit && _strncmp_data(cur, "ISOLatin1Encoding", 17) == 0)
+            face.type1.encoding_type = FT_Common.T1_ENCODING_TYPE_ISOLATIN1;
+        else
+            parser.root.error = FT_Common.FT_Err_Ignore;
+    }
+}
+
+function t1_parse_subrs(face, loader)
+{
+    var parser = loader.parser;
+    var table = loader.subrs;
+    var memory = parser.root.memory;
+
+    var psaux = face.psaux;
+    parser.root.funcs.skip_spaces(parser.root);
+
+    /* test for empty array */
+    if (parser.root.cursor.pos < parser.root.limit && parser.root.cursor.data[parser.root.cursor.pos] == FT_Common.SYMBOL_CONST_LS2)
+    {
+        parser.root.funcs.skip_PS_token(parser.root);
+        parser.root.funcs.skip_spaces(parser.root);
+
+        if (parser.root.cursor.pos >= parser.root.limit || parser.root.cursor.data[parser.root.cursor.pos] != FT_Common.SYMBOL_CONST_RS2)
+        parser.root.error = FT_Common.FT_Err_Invalid_File_Format;
+        return;
+    }
+
+    var num_subrs = parser.root.funcs.to_int(parser.root);
+
+    /* position the parser right before the `dup' of the first subr */
+    parser.root.funcs.skip_PS_token(parser.root);
+    if (parser.root.error != 0)
+        return;
+
+    parser.root.funcs.skip_spaces(parser.root);
+
+    var error = 0;
+    /* initialize subrs array -- with synthetic fonts it is possible */
+    /* we get here twice                                             */
+    if (loader.num_subrs == 0)
+    {
+        error = psaux.ps_table_funcs.init(table, num_subrs, memory);
+        if (error != 0)
+        {
+            parser.root.error = 0;
+            return;
+        }
+    }
+
+    /* the format is simple:   */
+    /*                         */
+    /*   `index' + binary data */
+    /*                         */
+    for (;;)
+    {
+        /* If the next token isn't `dup' we are done. */
+        if (_strncmp_data(parser.root.cursor, "dup", 3) != 0)
+            break;
+
+        parser.root.funcs.skip_PS_token(parser.root);
+
+        var idx = parser.root.funcs.to_int(parser.root);
+
+        var ret = _t1_read_binary_data(parser);
+
+        var size = ret.size;
+        var base = ret.base;
+        if (0 == ret.err)
+            return;
+
+        /* The binary string is followed by one token, e.g. `NP' */
+        /* (bound to `noaccess put') or by two separate tokens:  */
+        /* `noaccess' & `put'.  We position the parser right     */
+        /* before the next `dup', if any.                        */
+        parser.root.funcs.skip_PS_token(parser.root);
+        if (parser.root.error != 0)
+            return;
+
+        parser.root.funcs.skip_spaces(parser.root);
+
+        if (_strncmp_data(parser.root.cursor, "put", 3) == 0)
+        {
+            parser.root.funcs.skip_PS_token(parser.root);
+            parser.root.funcs.skip_spaces(parser);
+        }
+
+        /* with synthetic fonts it is possible we get here twice */
+        if (loader.num_subrs != 0)
+            continue;
+
+        /* some fonts use a value of -1 for lenIV to indicate that */
+        /* the charstrings are unencoded                           */
+        /*                                                         */
+        /* thanks to Tom Kacvinsky for pointing this out           */
+        /*                                                         */
+        if (face.type1.private_dict.lenIV >= 0)
+        {
+            /* some fonts define empty subr records -- this is not totally */
+            /* compliant to the specification (which says they should at   */
+            /* least contain a `return'), but we support them anyway       */
+            if (size < face.type1.private_dict.lenIV)
+            {
+                parser.root.error = FT_Common.FT_Err_Invalid_File_Format;
+                return;
+            }
+
+            /* t1_decrypt() shouldn't write to base -- make temporary copy */
+            var temp = memory.Alloc(size);
+            for (var i = 0; i < size; i++)
+            {
+                temp.data[i] = base.data[base.pos + i];
+            }
+
+            psaux.t1_decrypt(temp, size, 4330);
+            size -= face.type1.private_dict.lenIV;
+
+            temp.pos += face.type1.private_dict.lenIV;
+            error = table.funcs.add(table, idx, temp, size);
+
+            temp = null;
+        }
+        else
+            error = table.funcs.add(table, idx, base, size);
+
+        if (error != 0)
+        {
+            parser.root.error = error;
+        }
+    }
+
+    if (loader.num_subrs == 0)
+        loader.num_subrs = num_subrs;
+}
+
+function t1_parse_charstrings(face, loader)
+{
+    var parser = loader.parser;
+    var code_table = loader.charstrings;
+    var name_table = loader.glyph_names;
+    var swap_table = loader.swap_table;
+    var memory = parser.root.memory;
+
+    var psaux = face.psaux;
+
+    var limit = parser.root.limit;
+    var n = 0;
+    var notdef_index = 0;
+    var notdef_found = 0;
+
+    var num_glyphs = parser.root.funcs.to_int(parser.root);
+    /* some fonts like Optima-Oblique not only define the /CharStrings */
+    /* array but access it also                                        */
+    if (num_glyphs == 0 || parser.root.error != 0)
+        return;
+
+    /* initialize tables, leaving space for addition of .notdef, */
+    /* if necessary, and a few other glyphs to handle buggy      */
+    /* fonts which have more glyphs than specified.              */
+
+    /* for some non-standard fonts like `Optima' which provides  */
+    /* different outlines depending on the resolution it is      */
+    /* possible to get here twice                                */
+
+    var root = parser.root;
+
+    var error = 0;
+    if (loader.num_glyphs == 0)
+    {
+        error = psaux.ps_table_funcs.init(code_table, num_glyphs + 1 + FT_Common.TABLE_EXTEND, memory);
+        if (error != 0)
+        {
+            root.error = error;
+            return;
+        }
+
+        error = psaux.ps_table_funcs.init(name_table, num_glyphs + 1 + FT_Common.TABLE_EXTEND, memory);
+        if (error != 0)
+        {
+            root.error = error;
+            return;
+        }
+
+        /* Initialize table for swapping index notdef_index and */
+        /* index 0 names and codes (if necessary).              */
+        error = psaux.ps_table_funcs.init(swap_table, 4, memory);
+        if (error != 0)
+        {
+            root.error = error;
+            return error;
+        }
+    }
+
+    n = 0;
+
+    for (;;)
+    {
+        /* the format is simple:        */
+        /*   `/glyphname' + binary data */
+
+        root.funcs.skip_spaces(root);
+
+        var cur = dublicate_pointer(root.cursor);
+        if (cur.pos >= limit)
+            break;
+
+        /* we stop when we find a `def' or `end' keyword */
+        if (cur.pos + 3 < limit && IS_PS_DELIM(cur.data[cur.pos + 3]))
+        {
+            if (cur.data[cur.pos] == FT_Common.SYMBOL_CONST_d && cur.data[cur.pos + 1] == FT_Common.SYMBOL_CONST_e && cur.data[cur.pos + 2] == FT_Common.SYMBOL_CONST_f)
+            {
+                /* There are fonts which have this: */
+                /*                                  */
+                /*   /CharStrings 118 dict def      */
+                /*   Private begin                  */
+                /*   CharStrings begin              */
+                /*   ...                            */
+                /*                                  */
+                /* To catch this we ignore `def' if */
+                /* no charstring has actually been  */
+                /* seen.                            */
+                if (n != 0)
+                    break;
+            }
+
+            if (cur.data[cur.pos] == FT_Common.SYMBOL_CONST_e && cur.data[cur.pos + 1] == FT_Common.SYMBOL_CONST_n && cur.data[cur.pos + 2] == FT_Common.SYMBOL_CONST_d)
+                break;
+        }
+
+        root.funcs.skip_PS_token(root);
+        if (root.error != 0)
+            return;
+
+        if (cur.data[cur.pos] == FT_Common.SYMBOL_CONST_BS)
+        {
+            if (cur.pos + 1 >= limit)
+            {
+                root.error = FT_Common.FT_Err_Invalid_File_Format;
+                return;
+            }
+
+            cur.pos++;                              /* skip `/' */
+            var len = root.cursor.pos - cur.pos;
+
+            var ret = _t1_read_binary_data(parser);
+
+            if (ret.err == 0)
+                return;
+
+            var size = ret.size;
+            var base = ret.base;
+
+            /* for some non-standard fonts like `Optima' which provides */
+            /* different outlines depending on the resolution it is     */
+            /* possible to get here twice                               */
+            if (loader.num_glyphs != 0)
+                continue;
+
+            error = name_table.funcs.add(name_table, n, cur, len + 1);
+            if (error != 0)
+            {
+                root.error = error;
+                return;
+            }
+
+            /* add a trailing zero to the name table */
+            name_table.elements[n].data[name_table.elements[n].pos + len] = FT_Common.SYMBOL_CONST_S0;
+
+            /* record index of /.notdef */
+            if (cur.data[cur.pos] == FT_Common.SYMBOL_CONST_POINT && _strcmp_data(".notdef", name_table.elements[n]) == 0)
+            {
+                notdef_index = n;
+                notdef_found = 1;
+            }
+
+            if (face.type1.private_dict.lenIV >= 0 && (n < (num_glyphs + FT_Common.TABLE_EXTEND)))
+            {
+                if (size <= face.type1.private_dict.lenIV)
+                {
+                    root.error = FT_Common.FT_Err_Invalid_File_Format;
+                    return;
+                }
+
+                /* t1_decrypt() shouldn't write to base -- make temporary copy */
+                var temp = memory.Alloc(size);
+
+                for (var i = 0; i < size; i++)
+                    temp.data[i] = base.data[base.pos + i];
+
+
+                psaux.t1_decrypt(temp, size, 4330);
+                size -= face.type1.private_dict.lenIV;
+
+                temp.pos += face.type1.private_dict.lenIV;
+                error = code_table.funcs.add(code_table, n, temp, size);
+
+                temp = null;
+            }
+            else
+                error = code_table.funcs.add(code_table, n, base, size);
+
+            if (error != 0)
+            {
+                root.error = error;
+                return;
+            }
+
+            n++;
+        }
+    }
+
+    loader.num_glyphs = n;
+
+    /* if /.notdef is found but does not occupy index 0, do our magic. */
+    if (notdef_found != 0 && _strcmp_data(".notdef", name_table.elements[0]))
+    {
+        /* Swap glyph in index 0 with /.notdef glyph.  First, add index 0  */
+        /* name and code entries to swap_table.  Then place notdef_index   */
+        /* name and code entries into swap_table.  Then swap name and code */
+        /* entries at indices notdef_index and 0 using values stored in    */
+        /* swap_table.                                                     */
+
+        /* Index 0 name */
+        error = swap_table.funcs.add(swap_table, 0, name_table.elements[0], name_table.lengths[0]);
+        if (error != 0)
+        {
+            root.error = error;
+            return;
+        }
+
+        /* Index 0 code */
+        error = swap_table.funcs.add(swap_table, 1, code_table.elements[0], code_table.lengths[0]);
+        if (error != 0)
+        {
+            root.error = error;
+            return;
+        }
+
+        /* Index notdef_index name */
+        error = swap_table.funcs.add(swap_table, 2, name_table.elements[notdef_index], name_table.lengths[notdef_index]);
+        if (error != 0)
+        {
+            root.error = error;
+            return;
+        }
+
+        /* Index notdef_index code */
+        error = swap_table.funcs.add(swap_table, 3, code_table.elements[notdef_index], code_table.lengths[notdef_index]);
+        if (error != 0)
+        {
+            root.error = error;
+            return;
+        }
+
+        error = name_table.funcs.add(name_table, notdef_index, swap_table.elements[0], swap_table.lengths[0]);
+        if (error != 0)
+        {
+            root.error = error;
+            return;
+        }
+
+        error = code_table.funcs.add(code_table, notdef_index, swap_table.elements[1], swap_table.lengths[1]);
+        if (error != 0)
+        {
+            root.error = error;
+            return;
+        }
+
+        error = name_table.funcs.add(name_table, 0, swap_table.elements[2], swap_table.lengths[2]);
+        if (error != 0)
+        {
+            root.error = error;
+            return;
+        }
+
+        error = code_table.funcs.add(code_table, 0, swap_table.elements[3], swap_table.lengths[3]);
+        if (error != 0)
+        {
+            root.error = error;
+            return;
+        }
+    }
+    else if (notdef_found == 0)
+    {
+        /* notdef_index is already 0, or /.notdef is undefined in   */
+        /* charstrings dictionary.  Worry about /.notdef undefined. */
+        /* We take index 0 and add it to the end of the table(s)    */
+        /* and add our own /.notdef glyph to index 0.               */
+
+        /* 0 333 hsbw endchar */
+        var notdef_glyph = memory.Alloc(5);
+        notdef_glyph.data[0] = 0x8B;
+        notdef_glyph.data[1] = 0xF7;
+        notdef_glyph.data[2] = 0xE1;
+        notdef_glyph.data[3] = 0x0D;
+        notdef_glyph.data[4] = 0x0E;
+
+        var notdef_name = memory.Alloc(8);
+        notdef_name.data[0] = FT_Common.SYMBOL_CONST_POINT;
+        notdef_name.data[1] = FT_Common.SYMBOL_CONST_n;
+        notdef_name.data[2] = FT_Common.SYMBOL_CONST_o;
+        notdef_name.data[3] = FT_Common.SYMBOL_CONST_t;
+        notdef_name.data[4] = FT_Common.SYMBOL_CONST_d;
+        notdef_name.data[5] = FT_Common.SYMBOL_CONST_e;
+        notdef_name.data[6] = FT_Common.SYMBOL_CONST_f;
+        notdef_name.data[7] = FT_Common.SYMBOL_CONST_S0;
+
+        error = swap_table.funcs.add(swap_table, 0, name_table.elements[0], name_table.lengths[0]);
+        if (error != 0)
+        {
+            root.error = error;
+            return;
+        }
+
+        error = swap_table.funcs.add(swap_table, 1, code_table.elements[0], code_table.lengths[0]);
+        if (error != 0)
+        {
+            root.error = error;
+            return;
+        }
+
+        error = name_table.funcs.add(name_table, 0, notdef_name, 8);
+        if (error != 0)
+        {
+            root.error = error;
+            return;
+        }
+
+        error = code_table.funcs.add(code_table, 0, notdef_glyph, 5);
+        if (error != 0)
+        {
+            root.error = error;
+            return;
+        }
+
+        error = name_table.funcs.add(name_table, n, swap_table.elements[0], swap_table.lengths[0]);
+        if (error != 0)
+        {
+            root.error = error;
+            return;
+        }
+
+        error = code_table.funcs.add(code_table, n, swap_table.elements[1], swap_table.lengths[1]);
+        if (error != 0)
+        {
+            root.error = error;
+            return;
+        }
+
+        /* we added a glyph. */
+        loader.num_glyphs += 1;
+    }
+}
+
+function _t1_parse_dict(face, loader, base, size)
+{
+    var parser = loader.parser;
+    var have_integer = 0;
+
+    parser.root.cursor = dublicate_pointer(base);
+    parser.root.limit  = base.pos + size;
+    parser.root.error  = 0;
+
+    var limit = parser.root.limit;
+
+    parser.root.funcs.skip_spaces(parser.root);
+
+    var start_binary = dublicate_pointer(parser.root.cursor);
+    
+    while (parser.root.cursor.pos < limit)
+    {
+        var cur = dublicate_pointer(parser.root.cursor);
+
+        /* look for `eexec' */
+        if (IS_PS_TOKEN(cur, limit, "eexec", 6) == 1)
+            break;
+
+        /* look for `closefile' which ends the eexec section */
+        else if (IS_PS_TOKEN(cur, limit, "closefile", 10) == 1)
+            break;
+
+        /* in a synthetic font the base font starts after a           */
+        /* `FontDictionary' token that is placed after a Private dict */
+        else if (IS_PS_TOKEN(cur, limit, "FontDirectory", 14) == 1)
+        {
+            if (loader.keywords_encountered & FT_Common.T1_PRIVATE)
+                loader.keywords_encountered |= FT_Common.T1_FONTDIR_AFTER_PRIVATE;
+            parser.root.cursor.pos += 13;
+        }
+        /* check whether we have an integer */
+        else if (cur.data[cur.pos] >= FT_Common.SYMBOL_CONST_0 && cur.data[cur.pos] <= FT_Common.SYMBOL_CONST_9)
+        {
+            start_binary.pos = cur.pos;
+            parser.root.funcs.skip_PS_token(parser.root);
+            if (parser.root.error != 0)
+                return parser.root.error;
+            have_integer = 1;
+        }
+
+        /* in valid Type 1 fonts we don't see `RD' or `-|' directly */
+        /* since those tokens are handled by parse_subrs and        */
+        /* parse_charstrings                                        */
+        else if (cur.data[cur.pos] == FT_Common.SYMBOL_CONST_R && ((cur.pos + 6) < limit) && cur.data[cur.pos + 1] == FT_Common.SYMBOL_CONST_D && have_integer == 1)
+        {
+            parser.root.cursor.pos = start_binary.pos;
+
+            var ret = _t1_read_binary_data(parser);
+            if (0 == ret.err)
+                return FT_Common.FT_Err_Invalid_File_Format;
+            have_integer = 0;
+        }
+        else if (cur.data[cur.pos] == FT_Common.SYMBOL_CONST_MATH_MINUS && ((cur.pos + 6) < limit) && cur.data[cur.pos + 1] == FT_Common.SYMBOL_CONST_LOGOR &&  have_integer == 1)
+        {
+            var ret = _t1_read_binary_data(parser);
+            if (0 == ret.err)
+                return FT_Common.FT_Err_Invalid_File_Format;
+            have_integer = 0;
+        }
+
+        /* look for immediates */
+        else if (cur.data[cur.pos] == FT_Common.SYMBOL_CONST_BS && ((cur.pos + 2) < limit))
+        {
+            cur.pos++;
+
+            parser.root.cursor.pos = cur.pos;
+            parser.root.funcs.skip_PS_token(parser.root);
+            if (parser.root.error != 0)
+                return parser.root.error;
+
+            var len = parser.root.cursor.pos - cur.pos;
+
+            if (len > 0 && len < 22 && parser.root.cursor.pos < limit)
+            {
+                /* now compare the immediate name to the keyword table */
+                for (var _i = 0; _i < t1_keywords.length; _i++)
+                {
+                    var keyword = t1_keywords[_i];
+                    var name = keyword.ident;
+                    if (name == null)
+                        break;
+
+                    if (cur.data[cur.pos] == name.charCodeAt(0) && len == name.length && _strncmp_data(cur, name, len) == 0)
+                    {
+                        var dict = ((loader.keywords_encountered & FT_Common.T1_PRIVATE) != 0) ? FT_Common.T1_FIELD_DICT_PRIVATE : FT_Common.T1_FIELD_DICT_FONTDICT;
+
+                        if ((dict & keyword.dict) == 0)
+                        {
+                            break;
+                        }
+
+                        if (((loader.keywords_encountered & FT_Common.T1_FONTDIR_AFTER_PRIVATE) == 0) || (name == "CharStrings"))
+                        {
+                            parser.root.error = t1_load_keyword(face, loader, keyword);
+                            if (parser.root.error != 0)
+                            {
+                                if (parser.root.error == FT_Common.FT_Err_Ignore)
+                                    parser.root.error = 0;
+                                else
+                                    return parser.root.error;
+                            }
+                        }
+                        break;
+                    }
+                }
+            }
+
+            have_integer = 0;
+        }
+        else
+        {
+            parser.root.funcs.skip_PS_token(parser.root);
+            if (parser.root.error != 0)
+                return parser.root.error;
+            have_integer = 0;
+        }
+
+        parser.root.funcs.skip_spaces(parser.root);
+    }
+
+    return parser.root.error;
+}
+
+function t1_init_loader(loader, face)
+{
+    loader.clear();
+
+    loader.num_glyphs = 0;
+    loader.num_chars  = 0;
+
+    /* initialize the tables -- simply set their `init' field to 0 */
+    loader.encoding_table.init  = 0;
+    loader.charstrings.init     = 0;
+    loader.glyph_names.init     = 0;
+    loader.subrs.init           = 0;
+    loader.swap_table.init      = 0;
+    loader.fontdata             = 0;
+    loader.keywords_encountered = 0;
+}
+
+function t1_done_loader(loader)
+{
+    var parser = loader.parser;
+
+    /* finalize tables */
+    if (loader.encoding_table.funcs.release != null)
+        loader.encoding_table.funcs.release(loader.encoding_table);
+
+    if (loader.charstrings.funcs.release != null)
+        loader.charstrings.funcs.release(loader.charstrings);
+
+    if (loader.glyph_names.funcs.release != null)
+        loader.glyph_names.funcs.release(loader.glyph_names);
+
+    if (loader.swap_table.funcs.release != null)
+        loader.swap_table.funcs.release(loader.swap_table);
+
+    if (loader.subrs.funcs.release != null)
+        loader.subrs.funcs.release(loader.subrs);
+
+    /* finalize parser */
+    T1_Finalize_Parser(parser);
+}
+
+function T1_Open_Face(face)
+{
+    var loader = new T1_Loader();
+    var type1 = face.type1;
+    var priv = type1.private_dict;
+
+    var psaux = face.psaux;
+
+    t1_init_loader(loader, face);
+
+    /* default values */
+    face.ndv_idx          = -1;
+    face.cdv_idx          = -1;
+    face.len_buildchar    = 0;
+
+    priv.blue_shift       = 7;
+    priv.blue_fuzz        = 1;
+    priv.lenIV            = 4;
+    priv.expansion_factor = parseInt(0.06 * 0x10000);
+    priv.blue_scale       = parseInt(0.039625 * 0x10000 * 1000);
+
+    var parser = loader.parser;
+    var error = T1_New_Parser(parser, face.stream, face.memory, psaux);
+    if (error != 0)
+    {
+        t1_done_loader(loader);
+        return error;
+    }
+
+    error = _t1_parse_dict(face, loader, parser.base_dict, parser.base_len);
+    if (error != 0)
+    {
+        t1_done_loader(loader);
+        return error;
+    }
+
+    error = T1_Get_Private_Dict(parser, psaux);
+    if (error != 0)
+    {
+        t1_done_loader(loader);
+        return error;
+    }
+
+    error = _t1_parse_dict(face, loader, parser.private_dict, parser.private_len);
+    if (error != 0)
+    {
+        t1_done_loader(loader);
+        return error;
+    }
+
+    /* ensure even-ness of `num_blue_values' */
+    priv.num_blue_values &= 0xFFFFFFFE;
+
+    //#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT
+
+    if (face.blend != null && face.blend.num_default_design_vector != 0 && face.blend.num_default_design_vector != face.blend.num_axis)
+    {
+        face.blend.num_default_design_vector = 0;
+    }
+
+    /* the following can happen for MM instances; we then treat the */
+    /* font as a normal PS font                                     */
+    if (face.blend != null && (face.blend.num_designs == 0 || face.blend.num_axis == 0))
+        T1_Done_Blend(face);
+
+    /* another safety check */
+    if (face.blend != null)
+    {
+        for (var i = 0; i < face.blend.num_axis; i++)
+        {
+            if (face.blend.design_map[i].num_points == 0)
+            {
+                T1_Done_Blend(face);
+                break;
+            }
+        }
+    }
+
+    if (face.blend != null)
+    {
+        if (face.len_buildchar > 0)
+        {
+            face.buildchar = CreateIntArray(face.len_buildchar);
+        }
+    }
+    else
+    {
+        face.len_buildchar = 0;
+    }
+
+    //#endif /* !T1_CONFIG_OPTION_NO_MM_SUPPORT */
+
+    /* now, propagate the subrs, charstrings, and glyphnames tables */
+    /* to the Type1 data                                            */
+    type1.num_glyphs = loader.num_glyphs;
+
+    if (loader.subrs.init != null)
+    {
+        loader.subrs.init = null;
+        type1.num_subrs   = loader.num_subrs;
+        type1.subrs_block = loader.subrs.block;
+        type1.subrs       = loader.subrs.elements;
+        type1.subrs_len   = loader.subrs.lengths;
+    }
+
+    if (loader.charstrings.init == 0)
+    {
+        error = FT_Common.FT_Err_Invalid_File_Format;
+    }
+
+    loader.charstrings.init  = 0;
+    type1.charstrings_block = loader.charstrings.block;
+    type1.charstrings       = loader.charstrings.elements;
+    type1.charstrings_len   = loader.charstrings.lengths;
+
+    /* we copy the glyph names `block' and `elements' fields; */
+    /* the `lengths' field must be released later             */
+    type1.glyph_names_block = loader.glyph_names.block;
+    type1.glyph_names = loader.glyph_names.elements;
+
+    for (var ii = 0; ii < type1.num_glyphs; ii++)
+    {
+        var s = "";
+        var p = type1.glyph_names[ii];
+        var indC = 0;
+        while (true)
+        {
+            var _c = p.data[p.pos + indC];
+            indC++;
+
+            if (_c == FT_Common.SYMBOL_CONST_S0)
+                break;
+
+            s += String.fromCharCode(_c);
+        }
+        type1.glyph_names[ii] = s;
+    }
+
+    loader.glyph_names.block = 0;
+    loader.glyph_names.elements = 0;
+
+    /* we must now build type1.encoding when we have a custom array */
+    if (type1.encoding_type == FT_Common.T1_ENCODING_TYPE_ARRAY)
+    {
+        /* OK, we do the following: for each element in the encoding  */
+        /* table, look up the index of the glyph having the same name */
+        /* the index is then stored in type1.encoding.char_index, and */
+        /* the name to type1.encoding.char_name                       */
+
+        var min_char = 0;
+        var max_char = 0;
+
+        var charcode = 0;
+        for ( ; charcode < loader.encoding_table.max_elems; charcode++)
+        {
+            type1.encoding.char_index[charcode] = 0;
+            type1.encoding.char_name[charcode] = ".notdef";
+
+            var char_name = loader.encoding_table.elements[charcode];
+            if (char_name != null)
+            {
+                for (var idx = 0; idx < type1.num_glyphs; idx++)
+                {
+                    var glyph_name = type1.glyph_names[idx];
+                    if (_strncmp_data(char_name, glyph_name, glyph_name.length) == 0)
+                    {
+                        type1.encoding.char_index[charcode] = idx;
+                        type1.encoding.char_name[charcode] = glyph_name;
+
+                        /* Change min/max encoded char only if glyph name is */
+                        /* not /.notdef                                      */
+                        if (".notdef" != glyph_name)
+                        {
+                            if (charcode < min_char)
+                                min_char = charcode;
+                            if (charcode >= max_char)
+                                max_char = charcode + 1;
+                        }
+                        break;
+                    }
+                }
+            }
+        }
+
+        type1.encoding.code_first = min_char;
+        type1.encoding.code_last  = max_char;
+        type1.encoding.num_chars  = loader.num_chars;
+    }
+
+    t1_done_loader(loader);
+    return error;
+}
+
+/******************************************************************************/
+// tokens
+/******************************************************************************/
+var t1_keywords = new Array(45);
+// PS_FontInfoRec
+t1_keywords[0] = create_t1_field4("version", FT_Common.T1_FIELD_LOCATION_FONT_INFO, FT_Common.T1_FIELD_TYPE_STRING, FT_Common.T1_FIELD_DICT_FONTDICT, function(obj, val, f) { obj.version = val}, undefined);
+t1_keywords[1] = create_t1_field4("Notice", FT_Common.T1_FIELD_LOCATION_FONT_INFO, FT_Common.T1_FIELD_TYPE_STRING, FT_Common.T1_FIELD_DICT_FONTDICT, function(obj, val, f) { obj.notice = val}, undefined);
+t1_keywords[2] = create_t1_field4("FullName", FT_Common.T1_FIELD_LOCATION_FONT_INFO, FT_Common.T1_FIELD_TYPE_STRING, FT_Common.T1_FIELD_DICT_FONTDICT, function(obj, val, f) { obj.full_name = val}, undefined);
+t1_keywords[3] = create_t1_field4("FamilyName", FT_Common.T1_FIELD_LOCATION_FONT_INFO, FT_Common.T1_FIELD_TYPE_STRING, FT_Common.T1_FIELD_DICT_FONTDICT, function(obj, val, f) { obj.family_name = val}, undefined);
+t1_keywords[4] = create_t1_field4("Weight", FT_Common.T1_FIELD_LOCATION_FONT_INFO, FT_Common.T1_FIELD_TYPE_STRING, FT_Common.T1_FIELD_DICT_FONTDICT, function(obj, val, f) { obj.weight = val}, undefined);
+t1_keywords[5] = create_t1_field4("ItalicAngle", FT_Common.T1_FIELD_LOCATION_FONT_INFO, FT_Common.T1_FIELD_TYPE_INTEGER, FT_Common.T1_FIELD_DICT_FONTDICT, function(obj, val, f) { obj.italic_angle = val}, undefined);
+t1_keywords[6] = create_t1_field4("isFixedPitch", FT_Common.T1_FIELD_LOCATION_FONT_INFO, FT_Common.T1_FIELD_TYPE_BOOL, FT_Common.T1_FIELD_DICT_FONTDICT, function(obj, val, f) { obj.is_fixed_pitch = val}, undefined);
+t1_keywords[7] = create_t1_field4("UnderlinePosition", FT_Common.T1_FIELD_LOCATION_FONT_INFO, FT_Common.T1_FIELD_TYPE_INTEGER, FT_Common.T1_FIELD_DICT_FONTDICT, function(obj, val, f) { obj.underline_position = val}, undefined);
+t1_keywords[8] = create_t1_field4("UnderlineThickness", FT_Common.T1_FIELD_LOCATION_FONT_INFO, FT_Common.T1_FIELD_TYPE_INTEGER, FT_Common.T1_FIELD_DICT_FONTDICT, function(obj, val, f) { obj.underline_thickness = val}, undefined);
+
+// PS_FontExtraRec
+t1_keywords[9] = create_t1_field4("FSType", FT_Common.T1_FIELD_LOCATION_FONT_EXTRA, FT_Common.T1_FIELD_TYPE_INTEGER, FT_Common.T1_FIELD_DICT_FONTDICT, function(obj, val, f) { obj.fs_type = val}, undefined);
+
+// PS_PrivateRec
+t1_keywords[10] = create_t1_field4("UniqueID", FT_Common.T1_FIELD_LOCATION_PRIVATE, FT_Common.T1_FIELD_TYPE_INTEGER, FT_Common.T1_FIELD_DICT_FONTDICT | FT_Common.T1_FIELD_DICT_PRIVATE, function(obj, val, f) { obj.unique_id = val}, undefined);
+t1_keywords[11] = create_t1_field4("lenIV", FT_Common.T1_FIELD_LOCATION_PRIVATE, FT_Common.T1_FIELD_TYPE_INTEGER, FT_Common.T1_FIELD_DICT_PRIVATE, function(obj, val, f) { obj.lenIV = val}, undefined);
+t1_keywords[12] = create_t1_field4("LanguageGroup", FT_Common.T1_FIELD_LOCATION_PRIVATE, FT_Common.T1_FIELD_TYPE_INTEGER, FT_Common.T1_FIELD_DICT_PRIVATE, function(obj, val, f) { obj.language_group = val}, undefined);
+t1_keywords[13] = create_t1_field4("password", FT_Common.T1_FIELD_LOCATION_PRIVATE, FT_Common.T1_FIELD_TYPE_INTEGER, FT_Common.T1_FIELD_DICT_PRIVATE, function(obj, val, f) { obj.password = val}, undefined);
+
+t1_keywords[14] = create_t1_field4("BlueScale", FT_Common.T1_FIELD_LOCATION_PRIVATE, FT_Common.T1_FIELD_TYPE_FIXED_1000, FT_Common.T1_FIELD_DICT_PRIVATE, function(obj, val, f) { obj.blue_scale = val}, undefined);
+t1_keywords[15] = create_t1_field4("BlueShift", FT_Common.T1_FIELD_LOCATION_PRIVATE, FT_Common.T1_FIELD_TYPE_INTEGER, FT_Common.T1_FIELD_DICT_PRIVATE, function(obj, val, f) { obj.blue_shift = val}, undefined);
+t1_keywords[16] = create_t1_field4("BlueFuzz", FT_Common.T1_FIELD_LOCATION_PRIVATE, FT_Common.T1_FIELD_TYPE_INTEGER, FT_Common.T1_FIELD_DICT_PRIVATE, function(obj, val, f) { obj.blue_fuzz = val}, undefined);
+
+t1_keywords[17] = create_t1_field5("BlueValues", FT_Common.T1_FIELD_LOCATION_PRIVATE, FT_Common.T1_FIELD_TYPE_INTEGER_ARRAY, 14, FT_Common.T1_FIELD_DICT_PRIVATE, function(obj, val, f) { obj.blue_values[f.offset] = val}, function(obj, val, f) { obj.num_blue_values = val});
+t1_keywords[18] = create_t1_field5("OtherBlues", FT_Common.T1_FIELD_LOCATION_PRIVATE, FT_Common.T1_FIELD_TYPE_INTEGER_ARRAY, 10, FT_Common.T1_FIELD_DICT_PRIVATE, function(obj, val, f) { obj.other_blues[f.offset] = val}, function(obj, val, f) { obj.num_other_blues = val});
+t1_keywords[19] = create_t1_field5("FamilyBlues", FT_Common.T1_FIELD_LOCATION_PRIVATE, FT_Common.T1_FIELD_TYPE_INTEGER_ARRAY, 14, FT_Common.T1_FIELD_DICT_PRIVATE, function(obj, val, f) { obj.family_blues[f.offset] = val}, function(obj, val, f) { obj.num_family_blues = val});
+t1_keywords[20] = create_t1_field5("FamilyOtherBlues", FT_Common.T1_FIELD_LOCATION_PRIVATE, FT_Common.T1_FIELD_TYPE_INTEGER_ARRAY, 10, FT_Common.T1_FIELD_DICT_PRIVATE, function(obj, val, f) { obj.family_other_blues[f.offset] = val}, function(obj, val, f) { obj.num_family_other_blues = val});
+
+t1_keywords[21] = create_t1_field5("StdHW", FT_Common.T1_FIELD_LOCATION_PRIVATE, FT_Common.T1_FIELD_TYPE_INTEGER_ARRAY, 1, FT_Common.T1_FIELD_DICT_PRIVATE, function(obj, val, f) { obj.standard_width[0] = val}, undefined);
+t1_keywords[22] = create_t1_field5("StdVW", FT_Common.T1_FIELD_LOCATION_PRIVATE, FT_Common.T1_FIELD_TYPE_INTEGER_ARRAY, 1, FT_Common.T1_FIELD_DICT_PRIVATE, function(obj, val, f) { obj.standard_height[0] = val}, undefined);
+t1_keywords[23] = create_t1_field5("MinFeature", FT_Common.T1_FIELD_LOCATION_PRIVATE, FT_Common.T1_FIELD_TYPE_INTEGER_ARRAY, 2, FT_Common.T1_FIELD_DICT_PRIVATE, function(obj, val, f) { obj.min_feature[f.offset] = val}, undefined);
+
+t1_keywords[24] = create_t1_field5("StemSnapH", FT_Common.T1_FIELD_LOCATION_PRIVATE, FT_Common.T1_FIELD_TYPE_INTEGER_ARRAY, 12, FT_Common.T1_FIELD_DICT_PRIVATE, function(obj, val, f) { obj.snap_widths[f.offset] = val}, function(obj, val, f) { obj.num_snap_widths = val});
+t1_keywords[25] = create_t1_field5("StemSnapV", FT_Common.T1_FIELD_LOCATION_PRIVATE, FT_Common.T1_FIELD_TYPE_INTEGER_ARRAY, 12, FT_Common.T1_FIELD_DICT_PRIVATE, function(obj, val, f) { obj.snap_heights[f.offset] = val}, function(obj, val, f) { obj.num_snap_heights = val});
+
+t1_keywords[26] = create_t1_field4("ForceBold", FT_Common.T1_FIELD_LOCATION_PRIVATE, FT_Common.T1_FIELD_TYPE_BOOL, FT_Common.T1_FIELD_DICT_PRIVATE, function(obj, val, f) { obj.force_bold = val}, undefined);
+
+// T1_FontRec
+t1_keywords[27] = create_t1_field4("FontName", FT_Common.T1_FIELD_LOCATION_FONT_DICT, FT_Common.T1_FIELD_TYPE_KEY, FT_Common.T1_FIELD_DICT_FONTDICT, function(obj, val, f) { obj.font_name = val}, undefined);
+t1_keywords[28] = create_t1_field4("PaintType", FT_Common.T1_FIELD_LOCATION_FONT_DICT, FT_Common.T1_FIELD_TYPE_INTEGER, FT_Common.T1_FIELD_DICT_FONTDICT, function(obj, val, f) { obj.paint_type = val}, undefined);
+t1_keywords[29] = create_t1_field4("FontType", FT_Common.T1_FIELD_LOCATION_FONT_DICT, FT_Common.T1_FIELD_TYPE_INTEGER, FT_Common.T1_FIELD_DICT_FONTDICT, function(obj, val, f) { obj.font_type = val}, undefined);
+t1_keywords[30] = create_t1_field4("StrokeWidth", FT_Common.T1_FIELD_LOCATION_FONT_DICT, FT_Common.T1_FIELD_TYPE_FIXED, FT_Common.T1_FIELD_DICT_FONTDICT, function(obj, val, f) { obj.stroke_width = val}, undefined);
+
+// FT_BBox
+t1_keywords[31] = create_t1_field4("FontBBox", FT_Common.T1_FIELD_LOCATION_BBOX, FT_Common.T1_FIELD_TYPE_BBOX, FT_Common.T1_FIELD_DICT_FONTDICT, undefined, undefined);
+
+// T1_FaceRec
+t1_keywords[32] = create_t1_field4("NDV", FT_Common.T1_FIELD_LOCATION_FACE, FT_Common.T1_FIELD_TYPE_INTEGER, FT_Common.T1_FIELD_DICT_PRIVATE, function(obj, val, f) { obj.ndv_idx = val}, undefined);
+t1_keywords[33] = create_t1_field4("CDV", FT_Common.T1_FIELD_LOCATION_FACE, FT_Common.T1_FIELD_TYPE_FIXED, FT_Common.T1_FIELD_DICT_PRIVATE, function(obj, val, f) { obj.cdv_idx = val}, undefined);
+
+// PS_BlendRec
+t1_keywords[34] = create_t1_field5("CDV", FT_Common.T1_FIELD_LOCATION_BLEND, FT_Common.T1_FIELD_TYPE_FIXED, FT_Common.T1_MAX_MM_DESIGNS, FT_Common.T1_FIELD_DICT_FONTDICT, function(obj, val, f) { obj.default_design_vector[f.offset] = val}, function(obj, val, f) { obj.num_default_design_vector = val});
+
+// callbacks
+t1_keywords[35] = create_t1_field("FontMatrix", FT_Common.T1_FIELD_LOCATION_BLEND, FT_Common.T1_FIELD_TYPE_CALLBACK, t1_parse_font_matrix, 0, -1, 0, 0, FT_Common.T1_FIELD_DICT_FONTDICT, undefined, undefined);
+t1_keywords[36] = create_t1_field("Encoding", FT_Common.T1_FIELD_LOCATION_BLEND, FT_Common.T1_FIELD_TYPE_CALLBACK, t1_parse_encoding, 0, -1, 0, 0, FT_Common.T1_FIELD_DICT_FONTDICT, undefined, undefined);
+t1_keywords[37] = create_t1_field("Subrs", FT_Common.T1_FIELD_LOCATION_BLEND, FT_Common.T1_FIELD_TYPE_CALLBACK, t1_parse_subrs, 0, -1, 0, 0, FT_Common.T1_FIELD_DICT_PRIVATE, undefined, undefined);
+t1_keywords[38] = create_t1_field("CharStrings", FT_Common.T1_FIELD_LOCATION_BLEND, FT_Common.T1_FIELD_TYPE_CALLBACK, t1_parse_charstrings, 0, -1, 0, 0, FT_Common.T1_FIELD_DICT_PRIVATE, undefined, undefined);
+t1_keywords[39] = create_t1_field("Private", FT_Common.T1_FIELD_LOCATION_BLEND, FT_Common.T1_FIELD_TYPE_CALLBACK, t1_parse_private, 0, -1, 0, 0, FT_Common.T1_FIELD_DICT_FONTDICT, undefined, undefined);
+
+t1_keywords[40] = create_t1_field("BlendDesignPositions", FT_Common.T1_FIELD_LOCATION_BLEND, FT_Common.T1_FIELD_TYPE_CALLBACK, t1_parse_blend_design_positions, 0, -1, 0, 0, FT_Common.T1_FIELD_DICT_FONTDICT, undefined, undefined);
+t1_keywords[41] = create_t1_field("BlendDesignMap", FT_Common.T1_FIELD_LOCATION_BLEND, FT_Common.T1_FIELD_TYPE_CALLBACK, t1_parse_blend_design_map, 0, -1, 0, 0, FT_Common.T1_FIELD_DICT_FONTDICT, undefined, undefined);
+t1_keywords[42] = create_t1_field("BlendAxisTypes", FT_Common.T1_FIELD_LOCATION_BLEND, FT_Common.T1_FIELD_TYPE_CALLBACK, t1_parse_blend_axis_types, 0, -1, 0, 0, FT_Common.T1_FIELD_DICT_FONTDICT, undefined, undefined);
+t1_keywords[43] = create_t1_field("WeightVector", FT_Common.T1_FIELD_LOCATION_BLEND, FT_Common.T1_FIELD_TYPE_CALLBACK, t1_parse_weight_vector, 0, -1, 0, 0, FT_Common.T1_FIELD_DICT_FONTDICT, undefined, undefined);
+t1_keywords[44] = create_t1_field("BuildCharArray", FT_Common.T1_FIELD_LOCATION_BLEND, FT_Common.T1_FIELD_TYPE_CALLBACK, t1_parse_buildchar, 0, -1, 0, 0, FT_Common.T1_FIELD_DICT_PRIVATE, undefined, undefined);
+
+/******************************************************************************/
+// driver
+/******************************************************************************/
+
+function t1_get_glyph_name(face, glyph_index, buffer, buffer_max)
+{
+    return face.type1.glyph_names[glyph_index];
+    //_mem_strcpyn1(buffer, face.type1.glyph_names[glyph_index], buffer_max);
+    //return 0;
+}
+
+function t1_get_name_index(face, glyph_name)
+{
+    var _count = face.type1.num_glyphs;
+    for (var i = 0; i < _count; i++)
+    {
+        if (face.type1.glyph_names[i] == glyph_name)
+            return i;
+    }
+    return 0;
+}
+
+var t1_service_glyph_dict = new FT_Service_GlyphDictRec(t1_get_glyph_name, t1_get_name_index);
+
+function t1_get_ps_name(face)
+{
+    return face.type1.font_name;
+}
+var t1_service_ps_name = new FT_Service_PsFontNameRec(t1_get_ps_name);
+
+var t1_service_multi_masters = new FT_Service_MultiMastersRec(T1_Get_Multi_Master, T1_Set_MM_Design, T1_Set_MM_Blend, T1_Get_MM_Var, T1_Set_Var_Design);
+
+function t1_ps_get_font_info(face)
+{
+    FT_Error = 0;
+    return face.type1.font_info.CreateDublicate();
+}
+function t1_ps_get_font_extra(face)
+{
+    FT_Error = 0;
+    return face.type1.font_extra.CreateDublicate();
+}
+function t1_ps_has_glyph_names(face)
+{
+    return 1;
+}
+function t1_ps_get_font_private(face)
+{
+    FT_Error = 0;
+    return face.type1.private_dict;
+}
+
+function t1_ps_get_font_value(face, key, idx)
+{
+    var retval = -1;
+    var value = null;
+    var type1 = face.type1;
+
+    switch (key)
+    {
+        case FT_Common.PS_DICT_FONT_TYPE:
+            value = type1.font_type;
+            break;
+
+        case FT_Common.PS_DICT_FONT_MATRIX:
+            switch (idx)
+            {
+                case 0:
+                    value = type1.font_matrix.xx;
+                    break;
+                case 1:
+                    value = type1.font_matrix.xy;
+                    break;
+                case 2:
+                    value = type1.font_matrix.yx;
+                    break;
+                case 3:
+                    value = type1.font_matrix.yy;
+                    break;
+            }
+            break;
+
+        case FT_Common.PS_DICT_FONT_BBOX:
+            switch (idx)
+            {
+                case 0:
+                    value = type1.font_bbox.xMin;
+                    break;
+                case 1:
+                    value = type1.font_bbox.yMin;
+                    break;
+                case 2:
+                    value = type1.font_bbox.xMax;
+                    break;
+                case 3:
+                    value = type1.font_bbox.yMax;
+                    break;
+            }
+            break;
+
+        case FT_Common.PS_DICT_PAINT_TYPE:
+            value = type1.paint_type;
+            break;
+
+        case FT_Common.PS_DICT_FONT_NAME:
+            value = type1.font_name;
+            break;
+
+        case FT_Common.PS_DICT_UNIQUE_ID:
+            value = type1.private_dict.unique_id;
+            break;
+
+        case FT_Common.PS_DICT_NUM_CHAR_STRINGS:
+            value = type1.num_glyphs;
+            break;
+
+        case FT_Common.PS_DICT_CHAR_STRING_KEY:
+            if (idx < type1.num_glyphs)
+            {
+                value = type1.glyph_names[idx];
+            }
+            break;
+
+        case FT_Common.PS_DICT_CHAR_STRING:
+            if (idx < type1.num_glyphs)
+            {
+                value = type1.charstrings[idx];
+            }
+            break;
+
+        case FT_Common.PS_DICT_ENCODING_TYPE:
+            value = type1.encoding_type;
+            break;
+
+        case FT_Common.PS_DICT_ENCODING_ENTRY:
+            if (type1.encoding_type == FT_Common.T1_ENCODING_TYPE_ARRAY && idx < type1.encoding.num_chars)
+            {
+                value = type1.encoding.char_name[idx];
+            }
+            break;
+
+        case FT_Common.PS_DICT_NUM_SUBRS:
+            value = type1.num_subrs;
+            break;
+
+        case FT_Common.PS_DICT_SUBR:
+            if (idx < type1.num_subrs)
+            {
+                value = type1.subrs[idx];
+            }
+            break;
+
+        case FT_Common.PS_DICT_STD_HW:
+            value = type1.private_dict.standard_width[0];
+            break;
+
+        case FT_Common.PS_DICT_STD_VW:
+            value = type1.private_dict.standard_height[0];
+            break;
+
+        case FT_Common.PS_DICT_NUM_BLUE_VALUES:
+            value = type1.private_dict.num_blue_values;
+            break;
+
+        case FT_Common.PS_DICT_BLUE_VALUE:
+            if (idx < type1.private_dict.num_blue_values)
+            {
+                value = type1.private_dict.blue_values[idx];
+            }
+            break;
+
+        case FT_Common.PS_DICT_BLUE_SCALE:
+            value = type1.private_dict.blue_scale;
+            break;
+
+        case FT_Common.PS_DICT_BLUE_FUZZ:
+            value = type1.private_dict.blue_fuzz;
+            break;
+
+        case FT_Common.PS_DICT_BLUE_SHIFT:
+            value = type1.private_dict.blue_shift;
+            break;
+
+        case FT_Common.PS_DICT_NUM_OTHER_BLUES:
+            value = type1.private_dict.num_other_blues;
+            break;
+
+        case FT_Common.PS_DICT_OTHER_BLUE:
+            if (idx < type1.private_dict.num_other_blues)
+            {
+                value = type1.private_dict.other_blues[idx];
+            }
+            break;
+
+        case FT_Common.PS_DICT_NUM_FAMILY_BLUES:
+            value = type1.private_dict.num_family_blues;
+            break;
+
+        case FT_Common.PS_DICT_FAMILY_BLUE:
+            if (idx < type1.private_dict.num_family_blues)
+            {
+                value = type1.private_dict.family_blues[idx];
+            }
+            break;
+
+        case FT_Common.PS_DICT_NUM_FAMILY_OTHER_BLUES:
+            value = type1.private_dict.num_family_other_blues;
+            break;
+
+        case FT_Common.PS_DICT_FAMILY_OTHER_BLUE:
+            if (idx < type1.private_dict.num_family_other_blues)
+            {
+                value = type1.private_dict.family_other_blues[idx];
+            }
+            break;
+
+        case FT_Common.PS_DICT_NUM_STEM_SNAP_H:
+            value = type1.private_dict.num_snap_widths;
+            break;
+
+        case FT_Common.PS_DICT_STEM_SNAP_H:
+            if (idx < type1.private_dict.num_snap_widths)
+            {
+                value = type1.private_dict.snap_widths[idx];
+            }
+            break;
+
+        case FT_Common.PS_DICT_NUM_STEM_SNAP_V:
+            value = type1.private_dict.num_snap_heights;
+            break;
+
+        case FT_Common.PS_DICT_STEM_SNAP_V:
+            if (idx < type1.private_dict.num_snap_heights)
+            {
+                value = type1.private_dict.snap_heights[idx];
+            }
+            break;
+
+        case FT_Common.PS_DICT_RND_STEM_UP:
+            value = type1.private_dict.round_stem_up;
+            break;
+
+        case FT_Common.PS_DICT_FORCE_BOLD:
+            value = type1.private_dict.force_bold;
+            break;
+
+        case FT_Common.PS_DICT_MIN_FEATURE:
+            value = type1.private_dict.min_feature[idx];
+            break;
+
+        case FT_Common.PS_DICT_LEN_IV:
+            value = type1.private_dict.lenIV;
+            break;
+
+        case FT_Common.PS_DICT_PASSWORD:
+            value = type1.private_dict.password;
+            break;
+
+        case FT_Common.PS_DICT_LANGUAGE_GROUP:
+            value= type1.private_dict.language_group;
+            break;
+
+        case FT_Common.PS_DICT_IS_FIXED_PITCH:
+            value = type1.font_info.is_fixed_pitch;
+            break;
+
+        case FT_Common.PS_DICT_UNDERLINE_POSITION:
+            value = type1.font_info.underline_position;
+            break;
+
+        case FT_Common.PS_DICT_UNDERLINE_THICKNESS:
+            value = type1.font_info.underline_thickness;
+            break;
+
+        case FT_Common.PS_DICT_FS_TYPE:
+            value = type1.font_extra.fs_type;
+            break;
+
+        case FT_Common.PS_DICT_VERSION:
+            value = type1.font_info.version;
+            break;
+
+        case FT_Common.PS_DICT_NOTICE:
+            value = type1.font_info.notice;
+            break;
+
+        case FT_Common.PS_DICT_FULL_NAME:
+            value = type1.font_info.full_name;
+            break;
+
+        case FT_Common.PS_DICT_FAMILY_NAME:
+            value = type1.font_info.family_name;
+            break;
+
+        case FT_Common.PS_DICT_WEIGHT:
+            value = type1.font_info.weight;
+            break;
+
+        case FT_Common.PS_DICT_ITALIC_ANGLE:
+            value = type1.font_info.italic_angle;
+            break;
+
+        default:
+            break;
+    }
+
+    return retval;
+}
+
+var t1_service_ps_info = new FT_Service_PsInfoRec(t1_ps_get_font_info, t1_ps_get_font_extra, t1_ps_has_glyph_names, t1_ps_get_font_private, t1_ps_get_font_value);
+var t1_service_kerning = new FT_Service_KerningRec(T1_Get_Track_Kerning);
+
+var t1_services = new Array(6);
+t1_services[0] = new FT_ServiceDescRec(FT_SERVICE_ID_POSTSCRIPT_FONT_NAME,t1_service_ps_name);
+t1_services[1] = new FT_ServiceDescRec(FT_SERVICE_ID_GLYPH_DICT,t1_service_glyph_dict);
+t1_services[2] = new FT_ServiceDescRec(FT_SERVICE_ID_XF86_NAME,FT_XF86_FORMAT_TYPE_1);
+t1_services[3] = new FT_ServiceDescRec(FT_SERVICE_ID_POSTSCRIPT_INFO,t1_service_ps_info);
+t1_services[4] = new FT_ServiceDescRec(FT_SERVICE_ID_KERNING,t1_service_kerning);
+t1_services[5] = new FT_ServiceDescRec(FT_SERVICE_ID_MULTI_MASTERS,t1_service_multi_masters);
+
+function Get_Interface(driver, t1_interface)
+{
+    return ft_service_list_lookup(t1_services, t1_interface);
+}
+
+function Get_Kerning(face, left_glyph, right_glyph, kerning)
+{
+    kerning.x = 0;
+    kerning.y = 0;
+
+    if (face.afm_data != null)
+        T1_Get_Kerning(face.afm_data, left_glyph, right_glyph, kerning);
+
+    return 0;
+}
+
+function T1_Driver_Class()
+{
+    this.flags = 0x501;
+    this.name = "type1";
+    this.version = 0x10000;
+    this.requires = 0x20000;
+
+    this.module_interface = null;
+
+    this.init = T1_Driver_Init;
+    this.done = T1_Driver_Done;
+    this.get_interface = Get_Interface;
+
+    this.face_object_size = 0;
+    this.size_object_size = 0;
+    this.slot_object_size = 0;
+
+    this.init_face = T1_Face_Init;
+    this.done_face = T1_Face_Done;
+
+    this.init_size = T1_Size_Init;
+    this.done_size = T1_Size_Done;
+
+    this.init_slot = T1_GlyphSlot_Init;
+    this.done_slot = T1_GlyphSlot_Done;
+
+    //#ifdef FT_CONFIG_OPTION_OLD_INTERNALS
+    this.set_char_sizes = ft_stub_set_char_sizes;
+    this.set_pixel_sizes = ft_stub_set_pixel_sizes;
+    //#endif
+
+    this.load_glyph = T1_Load_Glyph;
+
+    this.get_kerning = Get_Kerning;
+    this.attach_file = T1_Read_Metrics;
+    this.get_advances = T1_Get_Advances;
+
+    this.request_size = T1_Size_Request;
+    this.select_size = null;
+}
+
+function T1_Driver()
+{
+    this.clazz = null;      // FT_Module_Class
+    this.library = null;    // FT_Library
+    this.memory = null;     // FT_Memory
+    this.generic = null;    // FT_Generic
+
+    this.clazz = new T1_Driver_Class();
+    this.faces_list = [];
+    this.extensions = null;
+    this.glyph_loader = null;
+
+    this.open_face = function(stream, face_index)
+    {
+        FT_Error = 0;
+        var face = new T1_Face();
+        var internal = new FT_Face_Internal();
+
+        face.driver = this;
+        face.memory = this.memory;
+        face.stream = stream;
+
+        //#ifdef FT_CONFIG_OPTION_INCREMENTAL
+        face.internal = internal;
+        face.internal.incremental_interface = null;
+        //#endif
+
+        var err1 = this.clazz.init_face(stream, face, face_index);
+
+        if (err1 != 0)
+        {
+            face = null;
+            FT_Error = err1;
+            return null;
+        }
+
+        var err2 = find_unicode_charmap(face);
+        if (err2 != 0 && err2 != FT_Common.FT_Err_Invalid_CharMap_Handle)
+        {
+            face = null;
+            FT_Error = err2;
+            return null;
+        }
+
+		FT_Error = 0;
+        return face;
+    }
+}
+
+function create_t1_driver(library)
+{
+    var driver = new T1_Driver();
+    driver.library = library;
+    driver.memory = library.Memory;
+
+    driver.clazz = new T1_Driver_Class();
+    return driver;
+}
\ No newline at end of file
diff --git a/Common/FontsFreeType/Private/FreeType/drivers/truetype.js b/Common/FontsFreeType/Private/FreeType/drivers/truetype.js
new file mode 100644
index 0000000000000000000000000000000000000000..e22d074a16d862a8b2c060f1ca486442d661432f
--- /dev/null
+++ b/Common/FontsFreeType/Private/FreeType/drivers/truetype.js
@@ -0,0 +1,3787 @@
+/******************************************************************************/
+// classes
+/******************************************************************************/
+function TT_Size_Metrics()
+{
+    this.x_ratio = 0;
+    this.y_ratio = 0;
+
+    this.ppem   = 0;
+    this.ratio  = 0;
+    this.scale  = 0;
+
+    this.compensations = new Array(4);
+
+    this.valid = 0;
+
+    this.rotated = 0;
+    this.stretched = 0;
+}
+TT_Size_Metrics.prototype =
+{
+    Copy : function(src)
+    {
+        this.x_ratio = src.x_ratio;
+        this.y_ratio = src.y_ratio;
+
+        this.ppem   = src.ppem;
+        this.ratio  = src.ratio;
+        this.scale  = src.scale;
+
+        this.compensations[0] = src.compensations[0];
+        this.compensations[1] = src.compensations[1];
+        this.compensations[2] = src.compensations[2];
+        this.compensations[3] = src.compensations[3];
+
+        this.valid = src.valid;
+
+        this.rotated = src.rotated;
+        this.stretched = src.stretched;
+    }
+};
+
+function TT_DefRecord()
+{
+    this.range  = 0;        /* in which code range is it located?     */
+    this.start  = 0;        /* where does it start?                   */
+    this.end    = 0;          /* where does it end?                     */
+    this.opc    = 0;          /* function #, or instruction code        */
+    this.active = false;       /* is it active?                          */
+    this.inline_delta = false; /* is function that defines inline delta? */
+}
+
+function TT_CodeRange()
+{
+    this.base = null;
+    this.size = 0;
+}
+
+function TT_SizeRec()
+{
+    this.face = null;
+    this.generic = null;
+    this.metrics = new FT_Size_Metrics();
+    this.internal = null;
+
+    /* we have our own copy of metrics so that we can modify */
+    /* it without affecting auto-hinting (when used)         */
+    this._metrics = new FT_Size_Metrics();
+
+    this.ttmetrics = new TT_Size_Metrics();
+
+    this.strike_index = 0;
+    //#ifdef TT_USE_BYTECODE_INTERPRETER
+    this.num_function_defs = 0; /* number of function definitions */
+    this.max_function_defs = 0;
+    this.function_defs = null;     /* table of function definitions  */
+
+    this.num_instruction_defs = 0;  /* number of ins. definitions */
+    this.max_instruction_defs = 0;
+    this.instruction_defs =  null;      /* table of ins. definitions  */
+
+    this.max_func = 0;
+    this.max_ins = 0;
+
+    this.codeRangeTable = new Array(3);
+    this.codeRangeTable[0] = new TT_CodeRange();
+    this.codeRangeTable[1] = new TT_CodeRange();
+    this.codeRangeTable[2] = new TT_CodeRange();
+
+    this.GS = new TT_GraphicsState();
+
+    this.cvt_size = 0;      /* the scaled control value table */
+    this.cvt = null;
+
+    this.storage_size = 0; /* The storage area is now part of */
+    this.storage = null;      /* the instance                    */
+
+    this.twilight = new TT_GlyphZoneRec();     /* The instance's twilight zone    */
+
+    /* debugging variables */
+
+    /* When using the debugger, we must keep the */
+    /* execution context tied to the instance    */
+    /* object rather than asking it on demand.   */
+    this.debug = false;
+    this.context = null;
+
+    this.bytecode_ready = false;
+    this.cvt_ready = false;
+    this.ttfautohinted = false;
+    //#endif
+}
+function TT_Face()
+{
+    this.num_faces = 0;
+    this.face_index = 0;
+
+    this.face_flags = 0;
+    this.style_flags = 0;
+
+    this.num_glyphs = 0;
+
+    this.family_name = "";
+    this.style_name = "";
+
+    this.num_fixed_sizes = 0;
+    this.available_sizes = null;
+
+    this.num_charmaps = 0;
+    this.charmaps = null;
+
+    this.generic = new FT_Generic();
+
+    /*# The following member variables (down to `underline_thickness') */
+    /*# are only relevant to scalable outlines; cf. @FT_Bitmap_Size    */
+    /*# for bitmap fonts.                                              */
+    this.bbox = new FT_BBox();
+
+    this.units_per_EM = 0;
+    this.ascender = 0;
+    this.descender = 0;
+    this.height = null;
+
+    this.max_advance_width = 0;
+    this.max_advance_height = 0;
+
+    this.underline_position = 0;
+    this.underline_thickness = 0;
+
+    this.glyph = null;
+    this.size = null;
+    this.charmap = null;
+
+    /*@private begin */
+    this.driver = null;
+    this.memory = null;
+    this.stream = null;
+
+    this.sizes_list = [];
+
+    this.autohint = [];
+    this.extensions = null;
+
+    this.internal = null;
+    /*@private end */
+
+    this.ttc_header = new TTC_HeaderRec();
+
+    this.format_tag = 0;
+    this.num_tables = 0;
+    this.dir_tables = null;
+
+    this.header = new TT_Header();
+    this.horizontal = new TT_HoriHeader();
+
+    this.max_profile = new TT_MaxProfile();
+    //#ifdef FT_CONFIG_OPTION_OLD_INTERNALS
+    this.max_components = 0;
+    //#endif
+
+    this.vertical_info = false;
+    this.vertical = new TT_VertHeader();
+
+    this.num_names = 0;
+    this.name_table = new TT_NameTableRec();
+
+    this.os2 = new TT_OS2();
+    this.postscript = new TT_Postscript();
+
+    this.cmap_table = null;
+    this.cmap_size = 0;
+
+    this.sfnt = null;
+    this.psnames = null;
+
+    // horizontal device metrics
+    //#ifdef FT_CONFIG_OPTION_OLD_INTERNALS
+    this.hdmx = new TT_HdmxRec();
+    //#endif
+
+    // grid-fitting and scaling table
+    this.gasp = new TT_Gasp(); // the `gasp' table
+
+    // PCL 5 tabl
+    this.pclt = new TT_PCLT();
+
+    // embedded bitmaps support
+    //#ifdef FT_CONFIG_OPTION_OLD_INTERNALS
+    this.num_sbit_strikes = 0;
+    this.sbit_strikes = null;
+    //#endif
+
+    this.num_sbit_scales = 0;
+    this.sbit_scales = null;
+
+    // postscript names table
+    this.postscript_names = new TT_Post_NamesRec();
+
+    // TrueType-specific fields (ignored by the OTF-Type2 driver)
+    // the glyph locations
+    //#ifdef FT_CONFIG_OPTION_OLD_INTERNALS
+    this.num_locations_stub = 0;
+    this.glyph_locations_stub = null;
+    //#endif
+
+    // the font program, if any
+    this.font_program_size = 0;
+    this.font_program = null;
+
+    // the cvt program, if any
+    this.cvt_program_size = 0;
+    this.cvt_program = null;
+
+    // the original, unscaled, control value table
+    this.cvt_size = 0;
+    this.cvt = null;
+
+    //#ifdef FT_CONFIG_OPTION_OLD_INTERNALS
+    // the format 0 kerning table, if any
+    this.num_kern_pairs = 0;
+    this.kern_table_index = 0;
+    this.kern_pairs = [];
+    //#endif
+
+    // A pointer to the bytecode interpreter to use.  This is also
+    // used to hook the debugger for the `ttdebug' utility.
+    this.interpreter = null;
+
+    //#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
+    // Use unpatented hinting only.
+    this.unpatented_hinting = false;
+    //#endif
+
+    // Other tables or fields. This is used by derivative formats like OpenType.
+    this.extra = new FT_Generic();
+
+    this.postscript_name = "";
+
+    // since version 2.1.8, but was originally placed after
+    // `glyph_locations_stub'
+    this.glyf_len = 0;
+
+    // since version 2.1.8, but was originally placed before `extra'
+    //#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
+    this.doblend = 0;
+    this.blend = null;
+    //#endif
+
+    // since version 2.2
+
+    this.horz_metrics = null;
+    this.horz_metrics_size = 0;
+
+    this.vert_metrics = null;
+    this.vert_metrics_size = 0;
+
+    this.num_locations = 0; // in broken TTF, gid > 0xFFFF
+    this.glyph_locations = null;
+
+    this.hdmx_table = null;
+    this.hdmx_table_size = 0;
+    this.hdmx_record_count = 0;
+    this.hdmx_record_size = 0;
+    this.hdmx_record_sizes = null;
+
+    this.sbit_table = null;
+    this.sbit_table_size = 0;
+    this.sbit_num_strikes = 0;
+
+    this.kern_table = null;
+    this.kern_table_size = 0;
+    this.num_kern_tables = 0;
+    this.kern_avail_bits = 0;
+    this.kern_order_bits = 0;
+
+    //#ifdef TT_CONFIG_OPTION_BDF
+    this.bdf = new TT_BDFRec();
+    //#endif
+
+    // since 2.3.0
+    this.horz_metrics_offset = 0;
+    this.vert_metrics_offset = 0;
+
+    this.goto_table = null;
+    this.access_glyph_frame = null;
+    this.forget_glyph_frame = null;
+    this.read_glyph_header = null;
+    this.read_simple_glyph = null;
+    this.read_composite_glyph = null;
+}
+/******************************************************************************/
+// gxvar
+/******************************************************************************/
+function GX_AVarCorrespondenceRec()
+{
+    this.fromCoord  = 0;
+    this.toCoord    = 0;
+}
+function GX_AVarSegmentRec()
+{
+    this.pairCount = 0;
+    this.correspondence = null;
+}
+function GX_BlendRec()
+{
+    this.num_axis = 0;
+    this.normalizedcoords = null;
+
+    this.mmvar = null;
+    this.mmvar_len = 0;
+
+    this.avar_checked = 0;
+    this.avar_segment = null;
+
+    this.tuplecount = 0;
+    this.tuplecoords = null;
+
+    this.gv_glyphcnt = 0;
+    this.glyphoffsets = null;
+}
+function GX_GVar_Head()
+{
+    this.version = 0;
+    this.axisCount = 0;
+    this.globalCoordCount = 0;
+    this.offsetToCoord = 0;
+    this.glyphCount = 0;
+    this.flags = 0;
+    this.offsetToData = 0;
+}
+function GX_FVar_Head()
+{
+    this.version = 0;
+    this.offsetToData = 0;
+    this.countSizePairs = 0;
+    this.axisCount = 0;
+    this.axisSize = 0;
+    this.instanceCount = 0;
+    this.instanceSize = 0;
+}
+function GX_FVar_Axis()
+{
+    this.axisTag = 0;
+    this.minValue = 0;
+    this.defaultValue = 0;
+    this.maxValue = 0;
+    this.flags = 0;
+    this.nameID = 0;
+}
+function ft_var_readpackedpoints(stream)
+{
+    var points = null;
+    var point_cnt = 0;
+
+    var n;
+    var runcnt;
+    var j;
+    var first;
+    point_cnt = n = stream.GetUChar();
+
+    if (n == 0)
+        return {points:points, point_cnt:point_cnt};
+
+    if (n & 0x80)
+        n = stream.GetUChar() | ((n & 0x7F) << 8);
+
+    points = new Array(n);
+    var i = 0;
+    while (i < n)
+    {
+        runcnt = stream.GetUChar();
+        if (runcnt & 0x80)
+        {
+            runcnt = runcnt & 0x7F;
+            first  = points[i++] = stream.GetUShort();
+
+            if (runcnt < 1 || i + runcnt >= n)
+                return {points:points, point_cnt:point_cnt};
+
+            /* first point not included in runcount */
+            for (j = 0; j < runcnt; ++j)
+            {
+                first += stream.GetUShort();
+                points[i++] = first & 0xFFFF;
+            }
+        }
+        else
+        {
+            first = points[i++] = stream.GetUChar();
+
+            if (runcnt < 1 || i + runcnt >= n)
+                return {points:points, point_cnt:point_cnt};
+
+            for (j = 0; j < runcnt; ++j)
+            {
+                first += stream.GetUChar();
+                points[i++] = first & 0xFFFF;
+            }
+        }
+    }
+
+    return {points:points, point_cnt:point_cnt};
+}
+function ft_var_readpackeddeltas(stream, delta_cnt)
+{
+    var runcnt;
+    var j;
+
+    var deltas = new Array(delta_cnt);
+    var i = 0;
+    while (i < delta_cnt)
+    {
+        runcnt = stream.GetUChar();
+        if ((runcnt & 128)!=0)
+        {
+            for (j = 0;j <= (runcnt & 63) && i < delta_cnt;j++)
+                deltas[i++] = 0;
+        }
+        else if ((runcnt & 64)!=0)
+        {
+            for (j = 0;j <= (runcnt & 63) && i < delta_cnt;j++)
+                deltas[i++] = stream.GetShort();
+        }
+        else
+        {
+            for (j = 0;j <= (runcnt & 63) && i < delta_cnt;j++)
+                deltas[i++] = stream.GetChar();
+        }
+
+        if (j <= (runcnt & 63))
+        {
+            deltas = null;
+            return null;
+        }
+    }
+    return deltas;
+}
+function ft_var_load_avar(face)
+{
+    var stream = face.stream;
+    var blend  = face.blend;
+    var segment = null;
+    var i, j;
+
+    blend.avar_checked = 1;
+    var table_len = face.goto_table(face, FT_Common.TTAG_avar, stream);
+    var error = FT_Error;
+    if (error != 0)
+        return;
+
+    error = stream.EnterFrame(table_len);
+    if (error != 0)
+        return;
+
+    var version   = stream.GetLong();
+    var axisCount = stream.GetLong();
+
+    if (version != 0x00010000 || axisCount != blend.mmvar.num_axis)
+    {
+        stream.ExitFrame();
+        return;
+    }
+
+    blend.avar_segment = new Array(axisCount);
+    for (i=0;i<axisCount;i++)
+        blend.avar_segment[i] = new GX_AVarSegmentRec();
+
+    for (i = 0; i < axisCount; ++i)
+    {
+        segment = blend.avar_segment[i];
+        segment.pairCount = stream.GetUShort();
+        segment.correspondence = new Array(segment.pairCount);
+
+        for (j = 0; j < segment.pairCount; ++j)
+        {
+            segment.correspondence[j].fromCoord = stream.GetShort() << 2;
+            segment.correspondence[j].toCoord = stream.GetShort() << 2;
+        }
+    }
+    stream.ExitFrame();
+}
+function ft_var_load_gvar(face)
+{
+    var stream = face.stream;
+    var blend  = face.blend;
+    var error = 0;
+    var i, j;
+    var gvar_head = new GX_GVar_Head();
+
+    var table_len = face.goto_table(face, FT_Common.TTAG_gvar, stream);
+    error = FT_Error;
+    if (error != 0)
+        return error;
+
+    var gvar_start = stream.pos;
+
+    error = stream.EnterFrame(20);
+    if (error != 0)
+        return error;
+
+    gvar_head.version = stream.GetLong();
+    gvar_head.axisCount = stream.GetUShort();
+    gvar_head.globalCoordCount = stream.GetUShort();
+    gvar_head.offsetToCoord = stream.GetULong();
+    gvar_head.glyphCount = stream.GetUShort();
+    gvar_head.flags = stream.GetUShort();
+    gvar_head.offsetToData = stream.GetULong();
+
+    stream.ExitFrame();
+
+    blend.tuplecount  = gvar_head.globalCoordCount;
+    blend.gv_glyphcnt = gvar_head.glyphCount;
+    var offsetToData = gvar_start + gvar_head.offsetToData;
+
+    if (gvar_head.version != 0x00010000 || gvar_head.axisCount != blend.mmvar.num_axis)
+        return FT_Common.FT_Err_Invalid_Table;
+
+    blend.glyphoffsets = new Array(blend.gv_glyphcnt + 1);
+    if ((gvar_head.flags & 1) != 0)
+    {
+        error = stream.EnterFrame((blend.gv_glyphcnt + 1)*4);
+        if (error != 0)
+            return error;
+
+        for (i = 0; i <= blend.gv_glyphcnt; ++i)
+            blend.glyphoffsets[i] = offsetToData + stream.GetLong();
+
+        stream.ExitFrame();
+    }
+    else
+    {
+        error = stream.EnterFrame((blend.gv_glyphcnt + 1)*2);
+        if (error != 0)
+            return error;
+
+        for (i = 0; i <= blend.gv_glyphcnt; ++i)
+            blend.glyphoffsets[i] = offsetToData + stream.GetUShort() * 2;
+
+        stream.ExitFrame();
+    }
+
+    if (blend.tuplecount != 0)
+    {
+        blend.tuplecoords = new Array(gvar_head.axisCount * blend.tuplecount);
+        error = stream.Seek(gvar_start + gvar_head.offsetToCoord);
+        if (error != 0)
+            return error;
+
+        error = stream.EnterFrame(blend.tuplecount * gvar_head.axisCount * 2);
+
+        for (i = 0; i < blend.tuplecount; i++)
+        {
+            for (j=0;j<gvar_head.axisCount;j++)
+            {
+                blend.tuplecoords[i * gvar_head.axisCount + j] = stream.GetShort() << 2;
+            }
+        }
+
+        stream.ExitFrame();
+    }
+    return error;
+}
+function ft_var_apply_tuple(blend, tupleIndex, tuple_coords, im_start_coords, im_end_coords)
+{
+    var apply = 0x10000;
+    var temp = 0;
+    var i = 0;
+    var c = blend.num_axis;
+    var nn = blend.normalizedcoords;
+    for (; i < c;i++)
+    {
+        if (tuple_coords[i] == 0)
+            continue;
+        else if (nn[i] == 0 || (nn[i] < 0 && tuple_coords[i] > 0) || (nn[i] > 0 && tuple_coords[i] < 0))
+        {
+            apply = 0;
+            break;
+        }
+        else if (0 == (tupleIndex & FT_Common.GX_TI_INTERMEDIATE_TUPLE))
+            apply = FT_MulDiv(apply, nn[i] > 0 ? nn[i] : -nn[i], 0x10000);
+
+        else if (nn[i] <= im_start_coords[i] || nn[i] >= im_end_coords[i])
+        {
+            apply = 0;
+            break;
+        }
+        else if (nn[i] < tuple_coords[i])
+        {
+            temp = FT_MulDiv(nn[i] - im_start_coords[i], 0x10000, tuple_coords[i] - im_start_coords[i]);
+            apply = FT_MulDiv(apply, temp, 0x10000);
+        }
+        else
+        {
+            temp = FT_MulDiv(im_end_coords[i] - nn[i], 0x10000, im_end_coords[i] - tuple_coords[i]);
+            apply = FT_MulDiv(apply, temp, 0x10000);
+        }
+    }
+    return apply;
+}
+function TT_Get_MM_Var(face, bIsRet)
+{
+    var stream = face.stream;
+    var table_len;
+    FT_Error = 0;
+    var fvar_start;
+    var i, j;
+    var mmvar = null;
+    var fvar_head = new GX_FVar_Head();
+
+    if (face.blend == null)
+    {
+        table_len = face.goto_table(face, FT_Common.TTAG_gvar, stream);
+        if (FT_Error != 0)
+            return null;
+
+        table_len = face.goto_table(face, FT_Common.TTAG_fvar, stream);
+        if (FT_Error != 0)
+            return null;
+
+        fvar_start = stream.pos;
+
+        FT_Error = stream.EnterFrame(16);
+        if (FT_Error != 0)
+            return null;
+        fvar_head.version = stream.GetULong();
+        fvar_head.offsetToData = stream.GetUShort();
+        fvar_head.countSizePairs = stream.GetUShort();
+        fvar_head.axisCount = stream.GetUShort();
+        fvar_head.axisSize = stream.GetUShort();
+        fvar_head.instanceCount = stream.GetUShort();
+        fvar_head.instanceSize = stream.GetUShort();
+        stream.ExitFrame();
+
+
+        if (fvar_head.version != 0x00010000 || fvar_head.countSizePairs != 2 || fvar_head.axisSize != 20 ||
+                fvar_head.axisCount > 0x3FFE || fvar_head.instanceSize != 4 + 4 * fvar_head.axisCount || fvar_head.instanceCount > 0x7EFF ||
+            fvar_head.offsetToData + fvar_head.axisCount * 20 + fvar_head.instanceCount * fvar_head.instanceSize > table_len)
+        {
+            FT_Error = FT_Common.FT_Err_Invalid_Table;
+            return null;
+        }
+
+        face.blend = new GX_BlendRec();
+        face.blend.mmvar_len = 0;
+        mmvar = new FT_MM_Var();
+
+        face.blend.mmvar = mmvar;
+
+        mmvar.num_axis = fvar_head.axisCount;
+        mmvar.num_designs = 0xFFFFFFFF;
+        mmvar.num_namedstyles = fvar_head.instanceCount;
+        mmvar.axis = new Array(mmvar.num_axis);
+        mmvar.namedstyle = new Array(mmvar.num_namedstyles);
+
+        FT_Error = stream.EnterFrame(fvar_start + fvar_head.offsetToData);
+        if (FT_Error != 0)
+            return null;
+
+        var mass_a = mmvar.axis;
+        var count_a = mmvar.num_axis;
+        for (i = 0; i < count_a; i++)
+        {
+            mass_a[i] = new FT_Var_Axis();
+            var a = mass_a[i];
+
+            FT_Error = stream.EnterFrame(20);
+            if (FT_Error != 0)
+                return null;
+
+            a.tag = stream.GetULong();
+            a.minimum = stream.GetULong();
+            a.def = stream.GetULong();
+            a.maximum = stream.GetULong();
+            stream.Skip(2);
+            a.strid = stream.GetUShort();
+
+            var tag = a.tag;
+            a.name = "";
+            a.name += String.fromCharCode((tag >>> 24) & 0xFF);
+            a.name += String.fromCharCode((tag >>> 16) & 0xFF);
+            a.name += String.fromCharCode((tag >>> 8) & 0xFF);
+            a.name += String.fromCharCode(tag & 0xFF);
+
+            stream.ExitFrame();
+        }
+
+        if (0 == bIsRet)
+            return null;
+
+        var mass_s = mmvar.namedstyle;
+        var count_s = mmvar.num_namedstyles;
+        for (i = 0;i < count_s;i++)
+        {
+            FT_Error = stream.EnterFrame(4 + 4 * count_a);
+            if (FT_Error != 0)
+                return null;
+
+            mass_s[i] = new FT_Var_Named_Style();
+            var s = mass_s[i];
+
+            s.strid = stream.GetUShort();
+            stream.Skip(2);
+
+            s.coords = new Array(count_a);
+            for (j = 0; j < count_a; j++)
+                s.coords[j] = stream.GetULong();
+
+            stream.ExitFrame();
+        }
+    }
+
+    mmvar = null;
+    mmvar = face.blend.mmvar.dublicate();
+
+    mass_a = mmvar.axis;
+    count_a = mmvar.num_axis;
+    for (i = 0; i < count_a; i++)
+    {
+        var a = mass_a[i];
+
+        if (a.tag == FT_Common.TTAG_wght)
+            a.name = "Weight";
+        else if (a.tag == FT_Common.TTAG_wdth)
+            a.name = "Width";
+        else if (a.tag == FT_Common.TTAG_opsz)
+            a.name = "OpticalSize";
+        else if (a.tag == FT_Common.TTAG_slnt)
+            a.name = "Slant";
+    }
+
+    return mmvar;
+}
+function TT_Set_MM_Blend(face, num_coords, coords)
+{
+    var error = 0;
+    face.doblend = 0;
+
+    if (face.blend == null)
+    {
+        TT_Get_MM_Var(face, 0);
+        if (FT_Error != 0)
+            return FT_Error;
+    }
+    var manageCvt = 0;
+
+    var blend = face.blend;
+    var mmvar = blend.mmvar;
+
+    if (num_coords != mmvar.num_axis)
+        return FT_Common.FT_Err_Invalid_Argument;
+
+    for (var i = 0; i < num_coords; i++)
+    {
+        if (coords[i] < -0x00010000 || coords[i] > 0x00010000)
+            return FT_Common.FT_Err_Invalid_Argument;
+    }
+
+    if (blend.glyphoffsets == null)
+    {
+        error = ft_var_load_gvar(face);
+        if (error != 0)
+            return error;
+    }
+
+    if (blend.normalizedcoords == null)
+    {
+        blend.normalizedcoords = new Array(num_coords);
+        manageCvt = 1;
+    }
+    else
+    {
+        manageCvt = 0;
+        for (var i = 0; i < num_coords; ++i)
+        {
+            if (blend.normalizedcoords[i] != coords[i])
+            {
+                manageCvt = 2;
+                break;
+            }
+        }
+    }
+
+    blend.num_axis = num_coords;
+    for (var i = 0;i < num_coords; i++)
+        blend.normalizedcoords[i] = coords[i];
+    face.doblend = 1;
+    if (face.cvt != null)
+    {
+        switch (manageCvt)
+        {
+            case 2:
+                tt_face_load_cvt(face, face.stream);
+                break;
+
+            case 1:
+                tt_face_vary_cvt(face, face.stream);
+                break;
+
+            case 0:
+                break;
+        }
+    }
+    return error;
+}
+function TT_Set_Var_Design(face, num_coords, coords)
+{
+    var error = 0;
+    var i, j;
+    var a = null;
+    var av = null;
+    if (face.blend == null)
+    {
+        TT_Get_MM_Var(face, 0);
+        if (FT_Error != 0)
+            return FT_Error;
+    }
+
+    var blend = face.blend;
+    var mmvar = blend.mmvar;
+
+    if (num_coords != mmvar.num_axis)
+        return FT_Common.FT_Err_Invalid_Argument;
+
+    var _c = mmvar.num_axis;
+    var normalized = new Array(_c);
+
+    for (i = 0; i < _c; i++)
+    {
+        a = mmvar.axis[i];
+        if (coords[i] > a.maximum || coords[i] < a.minimum)
+            return FT_Common.FT_Err_Invalid_Argument;
+        
+        if (coords[i] < a.def)
+        {
+            normalized[i] = -FT_MulDiv(coords[i] - a.def, 0x10000, a.minimum - a.def);
+        }
+        else if (a.maximum == a.def)
+            normalized[i] = 0;
+        else
+        {
+            normalized[i] = FT_MulDiv(coords[i] - a.def, 0x10000, a.maximum - a.def);
+        }
+    }
+
+    if (0 == blend.avar_checked)
+        ft_var_load_avar(face);
+
+    if (blend.avar_segment != null)
+    {
+        for (i = 0; i < _c; i++)
+        {
+            av = blend.avar_segment[i];
+            var _coords = av.correspondence;
+            for (j = 1; j < av.pairCount; j++)
+            if (normalized[i] < _coords[j].fromCoord)
+            {
+                var mem = FT_MulDiv(normalized[i] - _coords[j - 1].fromCoord, 0x10000, _coords[j].fromCoord - _coords[j - 1].fromCoord);
+                normalized[i] = FT_MulDiv(mem, _coords[j].toCoord - _coords[j - 1].toCoord, 0x10000) + _coords[j - 1].toCoord;
+                break;
+            }
+        }
+    }
+
+    error = TT_Set_MM_Blend(face, num_coords, normalized);
+    normalized = null;
+    return error;
+}
+function tt_face_vary_cvt(face, stream)
+{
+    var error = 0;
+    var here;
+    var i, j;
+    var blend = face.blend;
+    var point_count;
+    var localpoints;
+    var deltas;
+
+    if (blend == null)
+        return 0;
+
+    if (face.cvt == null)
+        return 0;
+
+    var table_len = face.goto_table(face, FT_Common.TTAG_cvar, stream);
+    error = FT_Error;
+    if (error != 0)
+        return 0;
+
+    error = stream.EnterFrame(table_len);
+    if (error != 0)
+        return 0;
+
+    var table_start = stream.cur;
+    if (0x00010000 != stream.GetLong())
+    {
+        stream.ExitFrame();
+        return 0;
+    }
+
+    var num_axis = blend.num_axis;
+    var tuple_coords = new Array(num_axis);
+    var im_start_coords = new Array(num_axis);
+    var im_end_coords = new Array(num_axis);
+
+    var tupleCount   = stream.GetUShort();
+    var offsetToData = table_start + stream.GetUShort();
+
+    for (i = 0; i < (tupleCount & 0xFFF); ++i)
+    {
+        var tupleDataSize = stream.GetUShort();
+        var tupleIndex    = stream.GetUShort();
+
+        if ((tupleIndex & FT_Common.GX_TI_EMBEDDED_TUPLE_COORD) != 0)
+        {
+            for (j = 0; j < num_axis; j++)
+                tuple_coords[j] = stream.GetShort() << 2;
+        }
+        else
+        {
+            if ((tupleIndex & FT_Common.GX_TI_INTERMEDIATE_TUPLE) != 0)
+            {
+                stream.Skip(4 * num_axis);
+            }
+            offsetToData += tupleDataSize;
+            continue;
+        }
+        if ((tupleIndex & FT_Common.GX_TI_INTERMEDIATE_TUPLE) != 0)
+        {
+            for (j = 0; j < num_axis; j++)
+                im_start_coords[j] = stream.GetShort() << 2;
+            for (j = 0; j < num_axis; j++)
+                im_end_coords[j] = stream.GetShort() << 2;
+        }
+
+        var apply = ft_var_apply_tuple(blend, tupleIndex, tuple_coords, im_start_coords, im_end_coords);
+        if (apply == 0 || 0 == (tupleIndex & FT_Common.GX_TI_PRIVATE_POINT_NUMBERS))
+        {
+            offsetToData += tupleDataSize;
+            continue;
+        }
+
+        here = stream.cur;
+        stream.cur = offsetToData;
+
+        var __mem1 = ft_var_readpackedpoints(stream);
+        localpoints = __mem1.points;
+        point_count = __mem1.point_cnt;
+        var cvt_size = face.cvt_size;
+        deltas = ft_var_readpackeddeltas(stream, point_count == 0 ? cvt_size : point_count);
+        if (deltas == null)
+        {
+        }
+        else if (localpoints == null)
+        {
+            for (j = 0; j < cvt_size; j++)
+                face.cvt[j] = (face.cvt[j] + FT_MulFix(deltas[j], apply)) & 0xFFFF;
+        }
+        else
+        {
+            for (j = 0; j < point_count; ++j)
+            {
+                var pindex = localpoints[j];
+                face.cvt[pindex] = (face.cvt[pindex] + FT_MulFix(deltas[j], apply)) & 0xFFFF;
+            }
+        }
+
+        localpoints = null;
+        deltas = null;
+        offsetToData += tupleDataSize;
+        stream.cur = here;
+    }
+
+    stream.ExitFrame();
+
+    tuple_coords = null;
+    im_start_coords = null;
+    im_end_coords = null;
+
+    return error;
+}
+function TT_Vary_Get_Glyph_Deltas(face, glyph_index, n_points)
+{
+    var stream = face.stream;
+    var blend  = face.blend;
+    var error;
+    var here;
+    var i, j;
+    var point_count, spoint_count = 0;
+    var sharedpoints = null;
+    var localpoints  = null;
+    var points = null;
+    var deltas_x = null, deltas_y = null;
+
+
+    if (face.doblend == 0 || blend == null)
+    {
+        FT_Error = FT_Common.FT_Err_Invalid_Argument;
+        return null;
+    }
+
+    var delta_xy = new Array(n_points);
+    for (i=0;i<n_points;i++)
+        delta_xy[i] = new FT_Vector();
+    
+    if (glyph_index >= blend.gv_glyphcnt || blend.glyphoffsets[glyph_index] == blend.glyphoffsets[glyph_index + 1])
+        return 0;
+
+    error = stream.Seek(blend.glyphoffsets[glyph_index]);
+    if (error == 0)
+        error = stream.EnterFrame(blend.glyphoffsets[glyph_index + 1] - blend.glyphoffsets[glyph_index]);
+
+    if (error != 0)
+    {
+        delta_xy = null;
+        FT_Error = error;
+        return null;
+    }
+
+    var glyph_start = stream.cur;
+
+    var num_axis = blend.num_axis;
+    var tuple_coords = new Array(num_axis);
+    var im_start_coords = new Array(num_axis);
+    var im_end_coords = new Array(num_axis);
+
+    var tupleCount   = stream.GetUShort();
+    var offsetToData = glyph_start + stream.GetUShort();
+
+    if ((tupleCount & FT_Common.GX_TC_TUPLES_SHARE_POINT_NUMBERS) != 0)
+    {
+        here = stream.cur;
+        stream.cur = offsetToData;
+
+        var __mem = ft_var_readpackedpoints(stream);
+        sharedpoints = __mem.points;
+        spoint_count = __mem.point_cnt;
+        offsetToData = stream.cur;
+        stream.cur = here;
+    }
+
+    for ( i = 0; i < ( tupleCount & GX_TC_TUPLE_COUNT_MASK ); ++i )
+    {
+        var tupleDataSize = stream.GetUShort();
+        var tupleIndex    = stream.GetUShort();
+
+        if (0 != (tupleIndex & FT_Common.GX_TI_EMBEDDED_TUPLE_COORD))
+        {
+            for (j = 0; j < num_axis; j++)
+                tuple_coords[j] = stream.GetShort() << 2;
+        }
+        else if (((tupleIndex & FT_Common.GX_TI_TUPLE_INDEX_MASK) != 0) >= blend.tuplecount)
+        {
+            FT_Error = FT_Common.FT_Err_Invalid_Table;
+            tuple_coords = null;
+            im_start_coords = null;
+            im_end_coords = null;
+            delta_xy = null;
+            stream.ExitFrame();
+            return null;
+        }
+        else
+        {
+            var _src = blend.tuplecoords;
+            var _s_start = (tupleIndex & 0xFFF) * num_axis;
+            for (j=0;j<num_axis;j++)
+                tuple_coords[j] = _src[_s_start+j];
+        }
+
+        if (0 != (tupleIndex & FT_Common.GX_TI_INTERMEDIATE_TUPLE))
+        {
+            for (j = 0; j < num_axis; j++)
+                im_start_coords[j] = stream.GetShort() << 2;
+            for (j = 0; j < num_axis; j++)
+                im_end_coords[j] = stream.GetShort() << 2;
+        }
+
+        var apply = ft_var_apply_tuple(blend, tupleIndex, tuple_coords, im_start_coords, im_end_coords);
+        if (apply == 0)
+        {
+            offsetToData += tupleDataSize;
+            continue;
+        }
+
+        here = stream.cur;
+        if (0 != (tupleIndex & FT_Common.GX_TI_PRIVATE_POINT_NUMBERS))
+        {
+            stream.cur = offsetToData;
+            var __mem = ft_var_readpackedpoints(stream);
+            localpoints = __mem.points;
+            point_count = __mem.point_cnt;
+            points = localpoints;
+        }
+        else
+        {
+            points      = sharedpoints;
+            point_count = spoint_count;
+        }
+
+        deltas_x = ft_var_readpackeddeltas(stream, point_count == 0 ? n_points : point_count);
+        deltas_y = ft_var_readpackeddeltas(stream, point_count == 0 ? n_points : point_count);
+
+        if (points == null || deltas_y == null || deltas_x == null)
+        {
+        }
+        else if (points == null)
+        {
+            for (j = 0; j < n_points; j++)
+            {
+                delta_xy[j].x += FT_MulFix(deltas_x[j], apply);
+                delta_xy[j].y += FT_MulFix(deltas_y[j], apply);
+            }
+        }
+        else
+        {
+            for (j = 0; j < point_count; j++)
+            {
+                if (localpoints[j] >= n_points)
+                    continue;
+
+                delta_xy[localpoints[j]].x += FT_MulFix(deltas_x[j], apply);
+                delta_xy[localpoints[j]].y += FT_MulFix(deltas_y[j], apply);
+            }
+        }
+
+        localpoints = null;
+        deltas_x = null;
+        deltas_y = null;
+
+        offsetToData += tupleDataSize;
+        stream.cur = here;
+    }
+
+    tuple_coords = null;
+    im_start_coords = null;
+    im_end_coords = null;
+    delta_xy = null;
+    stream.ExitFrame();
+    if (error != 0)
+        delta_xy = null;
+
+    FT_Error = error;
+    return delta_xy;
+}
+function tt_done_blend(memory, blend)
+{
+}
+/******************************************************************************/
+// glyphloader
+/******************************************************************************/
+function load_sbit_image(size, glyph, glyph_index, load_flags)
+{
+    var metrics = new TT_SBit_MetricsRec();
+
+    var face   = glyph.face;
+    var stream = face.stream;
+    var error = face.sfnt.load_sbit_image(face, size.strike_index, glyph_index, load_flags, stream, glyph.bitmap, metrics);
+    if (error == 0)
+    {
+        glyph.outline.n_points   = 0;
+        glyph.outline.n_contours = 0;
+
+        glyph.metrics.width  = metrics.width  << 6;
+        glyph.metrics.height = metrics.height << 6;
+
+        glyph.metrics.horiBearingX = metrics.horiBearingX << 6;
+        glyph.metrics.horiBearingY = metrics.horiBearingY << 6;
+        glyph.metrics.horiAdvance  = metrics.horiAdvance  << 6;
+
+        glyph.metrics.vertBearingX = metrics.vertBearingX << 6;
+        glyph.metrics.vertBearingY = metrics.vertBearingY << 6;
+        glyph.metrics.vertAdvance  = metrics.vertAdvance  << 6;
+
+        glyph.format = FT_Common.FT_GLYPH_FORMAT_BITMAP;
+
+        if ((load_flags & FT_Common.FT_LOAD_VERTICAL_LAYOUT) != 0)
+        {
+            glyph.bitmap_left = metrics.vertBearingX;
+            glyph.bitmap_top  = metrics.vertBearingY;
+        }
+        else
+        {
+            glyph.bitmap_left = metrics.horiBearingX;
+            glyph.bitmap_top  = metrics.horiBearingY;
+        }
+    }
+
+    return error;
+}
+function TT_Get_HMetrics(face, idx)
+{
+    return face.sfnt.get_metrics(face, 0, idx);
+}
+function TT_Get_VMetrics(face, idx)
+{
+    if (face.vertical_info === true)
+        return face.sfnt.get_metrics(face, 1, idx);
+
+    return {bearing : 0, advance : face.units_per_EM};
+}
+
+function tt_get_metrics(loader, glyph_index)
+{
+    var face = loader.face;
+
+    var h = TT_Get_HMetrics(face, glyph_index);
+    var v = TT_Get_VMetrics(face, glyph_index);
+
+    loader.left_bearing = h.bearing;
+    loader.advance      = h.advance;
+    loader.top_bearing  = v.bearing;
+    loader.vadvance     = v.advance;
+
+    if (face.driver.library.tt_hint_props.TT_CONFIG_OPTION_SUBPIXEL_HINTING) //#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+    {
+        if (loader.exec != null)
+            loader.exec.sph_tweak_flags = 0;
+
+        /* this may not be the right place for this, but it works */
+        if (loader.exec != null && loader.exec.ignore_x_mode)
+            global_SubpixHintingHacks.sph_set_tweaks(loader, glyph_index);
+    }//#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+
+    if (loader.linear_def == 0)
+    {
+        loader.linear_def = 1;
+        loader.linear = h.advance;
+    }
+}
+function tt_get_metrics_incr_overrides(loader, glyph_index)
+{
+    var face = loader.face;
+
+    var h = TT_Get_HMetrics(face, glyph_index);
+    var v = TT_Get_VMetrics(face, glyph_index);
+
+    if (face.internal.incremental_interface && face.internal.incremental_interface.funcs.get_glyph_metrics)
+    {
+        var metrics = new FT_Incremental_MetricsRec();
+
+        metrics.bearing_x = loader.left_bearing;
+        metrics.bearing_y = 0;
+        metrics.advance   = loader.advance;
+        metrics.advance_v = 0;
+
+        var error = face.internal.incremental_interface.funcs.get_glyph_metrics(face.internal.incremental_interface.object,
+            glyph_index, false, metrics);
+        if (error != 0)
+            return 0;
+
+        loader.left_bearing = metrics.bearing_x;
+        loader.advance      = metrics.advance;
+        loader.top_bearing  = v.tsb;
+        loader.vadvance     = v.ah;
+
+        if (0 == loader.linear_def)
+        {
+            loader.linear_def = 1;
+            loader.linear = h.aw;
+        }
+    }
+    return 0;
+}
+function translate_array(n, coords, delta_x, delta_y)
+{
+    if (delta_x != 0)
+        for (var k = 0; k < n; k++)
+            coords[k].x += delta_x;
+
+    if (delta_y != 0)
+        for (var k = 0; k < n; k++)
+            coords[k].y += delta_y;
+}
+function translate_array_ex(n, coords, start_p, delta_x, delta_y)
+{
+    if (delta_x != 0)
+        for (var k = 0; k < n; k++)
+            coords[start_p + k].x += delta_x;
+
+    if (delta_y != 0)
+        for (var k = 0; k < n; k++)
+            coords[start_p + k].y += delta_y;
+}
+
+function TT_Access_Glyph_Frame(loader, glyph_index, offset, byte_count)
+{
+    var error = 0;
+    var stream = loader.stream;
+
+    error = stream.Seek(offset);
+    if (error == 0)
+        error = stream.EnterFrame(byte_count);
+
+    if (error != 0)
+        return error;
+
+    loader.cursor = stream.cur;
+    loader.limit  = stream.size;
+
+    return 0;
+}
+
+function TT_Forget_Glyph_Frame(loader)
+{
+    loader.stream.ExitFrame();
+}
+
+function TT_Load_Glyph_Header(loader)
+{
+    var stream = loader.stream;
+
+    if (stream.cur + 10 > stream.size)
+        return FT_Common.FT_Err_Invalid_Outline;
+
+    loader.n_contours = stream.GetShort();
+    loader.bbox.xMin = stream.GetShort();
+    loader.bbox.yMin = stream.GetShort();
+    loader.bbox.xMax = stream.GetShort();
+    loader.bbox.yMax = stream.GetShort();
+
+    loader.cursor += 10;
+
+    return 0;
+}
+
+function TT_Load_Simple_Glyph(load)
+{
+    var error = 0;
+    var p = new FT_Stream(load.stream.data, load.stream.size);
+    p.cur = load.cursor;
+
+    var gloader = load.gloader;
+    var n_contours = load.n_contours;
+    var face = load.face;
+    var n_ins;
+    var n_points;
+
+    var c, count;
+    var x;
+    var prev_cont;
+    var xy_size = 0;
+
+    error = FT_GLYPHLOADER_CHECK_POINTS(gloader, 0, n_contours);
+    if (error != 0)
+        return error;
+
+    if (null == gloader.base.outline.contours)
+    {
+        error = FT_GLYPHLOADER_CHECK_POINTS(gloader, 0, n_contours);
+    }
+
+    var conts = gloader.base.outline.contours;
+    var cont = gloader.current.outline.contours;
+    var cont_limit = cont + n_contours;
+
+    if (n_contours >= 0xFFF || p.cur + (n_contours + 1) * 2 > load.limit)
+        return FT_Common.FT_Err_Invalid_Outline;
+
+    prev_cont = p.GetUShort();
+
+    if (n_contours > 0)
+        conts[cont] = prev_cont;
+
+    for (cont++; cont < cont_limit; cont++)
+    {
+        conts[cont] = p.GetUShort();
+        if (conts[cont] <= prev_cont)
+            return FT_Common.FT_Err_Invalid_Table;
+        prev_cont = conts[cont];
+    }
+
+    n_points = 0;
+    if (n_contours > 0)
+    {
+        n_points = conts[cont-1] + 1;
+        if (n_points < 0)
+            return FT_Common.FT_Err_Invalid_Outline;
+    }
+
+    /* note that we will add four phantom points later */
+    error = FT_GLYPHLOADER_CHECK_POINTS(gloader, n_points + 4, 0);
+    if (error != 0)
+        return error;
+
+    var outline = gloader.current.outline;
+    for (cont = outline.contours + 1; cont < cont_limit; cont++)
+        if (conts[cont-1] >= conts[cont])
+            return FT_Common.FT_Err_Invalid_Outline;
+
+    load.glyph.control_len  = 0;
+    load.glyph.control_data = 0;
+
+    if (p.cur + 2 > load.limit)
+        return FT_Common.FT_Err_Invalid_Outline;
+
+    n_ins = p.GetUShort();
+    if (n_ins > face.max_profile.maxSizeOfInstructions)
+        return FT_Common.FT_Err_Too_Many_Hints;
+
+    if ((load.limit - p.cur) < n_ins)
+        return FT_Common.FT_Err_Too_Many_Hints;
+
+    //#ifdef TT_USE_BYTECODE_INTERPRETER
+    if (face.driver.library.tt_hint_props.TT_USE_BYTECODE_INTERPRETER)
+    {
+        if ((load.load_flags & FT_Common.FT_LOAD_NO_HINTING) == 0)
+        {
+            load.glyph.control_len  = n_ins;
+            load.glyph.control_data = dublicate_pointer(load.exec.glyphIns);
+
+			if (load.glyph.control_data != null)
+			{
+				var _dd = load.glyph.control_data.data;
+				var _dc = load.glyph.control_data.pos;
+
+				for (var j = 0; j < n_ins; j++)
+					_dd[_dc + j] = p.data[p.cur + j];
+			}
+        }
+    }
+
+    p.cur += n_ins;
+
+    var flags = gloader.base.outline.tags;
+    var flag = outline.tags;
+    var flag_limit = flag + n_points;
+
+    var limit = load.limit;
+    while (flag < flag_limit)
+    {
+        if (p.cur + 1 > limit)
+            return FT_Common.FT_Err_Invalid_Outline;
+
+        flags[flag++] = c = p.GetUChar();
+        if ((c & 8)!=0)
+        {
+            if (p.cur + 1 > limit)
+                return FT_Common.FT_Err_Invalid_Outline;
+
+            count = p.GetUChar();
+            if (flag + count > flag_limit)
+                return FT_Common.FT_Err_Invalid_Outline;
+
+            for (; count > 0; count--)
+                flags[flag++] = c;
+        }
+    }
+
+    var vecs = gloader.base.outline.points;
+    var vec = outline.points;
+    var vec_limit = vec + n_points;
+    flag = outline.tags;
+    x = 0;
+
+    if (p.cur + xy_size > limit)
+        return FT_Common.FT_Err_Invalid_Outline;
+
+    for ( ; vec < vec_limit; vec++, flag++ )
+    {
+        var y = 0;
+        var f = flags[flag];
+
+        if ((f & 2)!=0)
+        {
+            if (p.cur + 1 > limit)
+                return FT_Common.FT_Err_Invalid_Outline;
+
+            y = p.GetUChar();
+            if (( f & 16 ) == 0)
+                y = -y;
+        }
+        else if (( f & 16 ) == 0)
+        {
+            if (p.cur + 2 > limit)
+                return FT_Common.FT_Err_Invalid_Outline;
+
+            y = p.GetShort();
+        }
+
+        x += y;
+        vecs[vec].x = x;
+        flags[flag]  = (f & ~( 2 | 16 )) & 0xFF;
+    }
+
+    vec = outline.points;
+    flag = outline.tags;
+    x = 0;
+
+    for ( ; vec < vec_limit; vec++, flag++)
+    {
+        var y = 0;
+        var f = flags[flag];
+
+        if ((f & 4)!=0)
+        {
+            if (p.cur + 1 > limit)
+                return FT_Common.FT_Err_Invalid_Outline;
+
+            y = p.GetUChar();
+            if ((f & 32) == 0)
+                y = -y;
+        }
+        else if ((f & 32) == 0)
+        {
+            if (p.cur + 2 > limit)
+                return FT_Common.FT_Err_Invalid_Outline;
+
+            y = p.GetShort();
+        }
+
+        x += y;
+        vecs[vec].y = x;
+        flags[flag]  = (f & FT_Common.FT_CURVE_TAG_ON) & 0xFF;
+    }
+
+    outline.n_points   = n_points & 0xFFFF;
+    outline.n_contours = n_contours & 0xFFFF;
+
+    load.cursor = p.cur;
+    return error;
+}
+
+function TT_Load_Composite_Glyph(loader)
+{
+    var error = 0;
+    var s = new FT_Stream(loader.stream.data, loader.stream.size);
+    s.cur = loader.cursor;
+    var size_read = loader.limit - loader.cursor;
+    var count_read = 0;
+
+    var gloader = loader.gloader;
+    var subglyph = null;
+    var num_subglyphs = 0;
+
+    do
+    {
+        var xx, xy, yy, yx;
+        var count;
+
+        error = FT_GlyphLoader_CheckSubGlyphs(gloader, num_subglyphs + 1);
+        if (error != 0)
+            return error;
+
+        if (count_read + 4 > size_read)
+            return FT_Common.FT_Err_Invalid_Composite;
+
+        subglyph = gloader.base.subglyphs[gloader.current.subglyphs + num_subglyphs];
+
+        subglyph.arg1 = subglyph.arg2 = 0;
+
+        subglyph.flags = s.GetUShort();
+        subglyph.index = s.GetUShort();
+
+        count_read += 4;
+
+        count = 2;
+        if (subglyph.flags & FT_Common.ARGS_ARE_WORDS)
+            count += 2;
+        if (subglyph.flags & FT_Common.WE_HAVE_A_SCALE)
+            count += 2;
+        else if (subglyph.flags & FT_Common.WE_HAVE_AN_XY_SCALE)
+            count += 4;
+        else if (subglyph.flags & FT_Common.WE_HAVE_A_2X2)
+            count += 8;
+
+        if (count_read + count > size_read)
+            return FT_Common.FT_Err_Invalid_Composite;
+
+        if (subglyph.flags & FT_Common.ARGS_ARE_WORDS)
+        {
+            subglyph.arg1 = s.GetShort();
+            subglyph.arg2 = s.GetShort();
+        }
+        else
+        {
+            subglyph.arg1 = s.GetChar();
+            subglyph.arg2 = s.GetChar();
+        }
+
+        xx = yy = 0x10000;
+        xy = yx = 0;
+
+        if (subglyph.flags & FT_Common.WE_HAVE_A_SCALE)
+        {
+            xx = s.GetShort() << 2;
+            yy = xx;
+        }
+        else if (subglyph.flags & FT_Common.WE_HAVE_AN_XY_SCALE)
+        {
+            xx = s.GetShort() << 2;
+            yy = s.GetShort() << 2;
+        }
+        else if (subglyph.flags & FT_Common.WE_HAVE_A_2X2)
+        {
+            xx = s.GetShort() << 2;
+            yx = s.GetShort() << 2;
+            xy = s.GetShort() << 2;
+            yy = s.GetShort() << 2;
+        }
+
+        subglyph.transform.xx = xx;
+        subglyph.transform.xy = xy;
+        subglyph.transform.yx = yx;
+        subglyph.transform.yy = yy;
+
+        num_subglyphs++;
+
+        count_read += count;
+
+    } while (subglyph.flags & FT_Common.MORE_COMPONENTS);
+
+    gloader.current.num_subglyphs = num_subglyphs;
+
+    if (loader.face.driver.library.tt_hint_props.TT_USE_BYTECODE_INTERPRETER)
+    {
+        loader.ins_pos = loader.stream.pos + s.cur - loader.limit;
+    }
+    
+    loader.cursor = s.cur;
+    return error
+}
+
+function TT_Process_Simple_Glyph(loader)
+{
+    var gloader = loader.gloader;
+    var error = 0;
+
+    var outline  = gloader.current.outline;
+    var base  = gloader.base.outline;
+    var n_points = outline.n_points;
+
+    var points = base.points;
+    var p_s = outline.points;
+    var s = p_s + n_points;
+    var tags = base.tags;
+    var t_s = outline.tags;
+    var t = t_s + n_points;
+
+    points[s    ].x = loader.pp1.x;
+    points[s + 1].x = loader.pp2.x;
+    points[s + 2].x = loader.pp3.x;
+    points[s + 3].x = loader.pp4.x;
+    points[s    ].y = loader.pp1.y;
+    points[s + 1].y = loader.pp2.y;
+    points[s + 2].y = loader.pp3.y;
+    points[s + 3].y = loader.pp4.y;
+
+    tags[t    ] = 0;
+    tags[t + 1] = 0;
+    tags[t + 2] = 0;
+    tags[t + 3] = 0;
+
+    n_points += 4;
+    s += 4;
+
+    //#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
+    if (loader.face.doblend != 0)
+    {
+        var deltas = TT_Vary_Get_Glyph_Deltas(loader.face, loader.glyph_index, n_points);
+        error = FT_Error;
+        if (error != 0)
+            return error;
+
+        for (var i = 0; i < n_points; i++)
+        {
+            points[i + p_s].x += deltas[i].x;
+            points[i + p_s].y += deltas[i].y;
+        }
+
+        deltas = null;
+    }
+    //#endif
+
+    if ((loader.load_flags & FT_Common.FT_LOAD_NO_HINTING) == 0)
+    {
+        tt_prepare_zone_cur(loader.zone, gloader, 0, 0);
+
+        var _p_len = loader.zone.n_points + 4;
+
+        var _orus = loader.zone.orus;
+        var _cur = loader.zone.cur;
+        for (var i = 0; i < _p_len; i++)
+        {
+            _orus[loader.zone._offset_orus + i].x = _cur[loader.zone._offset_cur + i].x;
+            _orus[loader.zone._offset_orus + i].y = _cur[loader.zone._offset_cur + i].y;
+        }
+    }
+
+    var _face = loader.face;
+    if (_face.driver.library.tt_hint_props.TT_CONFIG_OPTION_SUBPIXEL_HINTING)
+    {
+        var x_scale_factor = 1000;
+        var ppem = loader.size.metrics.x_ppem;
+        if ((loader.load_flags & FT_Common.FT_LOAD_NO_HINTING) == 0)
+        {
+            x_scale_factor = global_SubpixHintingHacks.scale_test_tweak(_face, _face.family_name, ppem, _face.style_name, loader.glyph_index,
+                global_SubpixHintingHacks.X_SCALING_Rules, global_SubpixHintingHacks.X_SCALING_RULES_SIZE);
+        }
+
+        if ((loader.load_flags & FT_Common.FT_LOAD_NO_SCALE) == 0 || x_scale_factor != 1000)
+        {
+            var x_scale = FT_MulDiv(loader.size.metrics.x_scale, x_scale_factor, 1000);
+            var y_scale = loader.size.metrics.y_scale;
+
+            /* compensate for any scaling by de/emboldening; */
+            /* the amount was determined via experimentation */
+            if (x_scale_factor != 1000 && ppem > 11)
+                FT_Outline_EmboldenXY(outline, FT_MulFix(1280 * ppem, 1000 - x_scale_factor), 0);
+
+            for (var vec = 0 ; vec < n_points; vec++)
+            {
+                points[vec + p_s].x = FT_MulFix(points[vec + p_s].x, x_scale);
+                points[vec + p_s].y = FT_MulFix(points[vec + p_s].y, y_scale);
+            }
+
+            loader.pp1.x = points[s - 4].x;
+            loader.pp2.x = points[s - 3].x;
+            loader.pp3.x = points[s - 2].x;
+            loader.pp4.x = points[s - 1].x;
+            loader.pp1.y = points[s - 4].y;
+            loader.pp2.y = points[s - 3].y;
+            loader.pp3.y = points[s - 2].y;
+            loader.pp4.y = points[s - 1].y;
+        }
+    }
+    else
+    {
+        if ((loader.load_flags & FT_Common.FT_LOAD_NO_SCALE) == 0)
+        {
+            var x_scale = loader.size.metrics.x_scale;
+            var y_scale = loader.size.metrics.y_scale;
+
+            for (var vec = 0 ; vec < n_points; vec++)
+            {
+                points[vec + p_s].x = FT_MulFix(points[vec + p_s].x, x_scale);
+                points[vec + p_s].y = FT_MulFix(points[vec + p_s].y, y_scale);
+            }
+
+            loader.pp1.x = points[s - 4].x;
+            loader.pp2.x = points[s - 3].x;
+            loader.pp3.x = points[s - 2].x;
+            loader.pp4.x = points[s - 1].x;
+            loader.pp1.y = points[s - 4].y;
+            loader.pp2.y = points[s - 3].y;
+            loader.pp3.y = points[s - 2].y;
+            loader.pp4.y = points[s - 1].y;
+        }
+    }
+
+    if ((loader.load_flags & FT_Common.FT_LOAD_NO_HINTING) == 0)
+    {
+        loader.zone.n_points += 4;
+        error = TT_Hint_Glyph(loader, false);
+    }
+
+    return error;
+}
+
+function TT_Process_Composite_Component(loader, subglyph, start_point, num_base_points)
+{
+    var gloader = loader.gloader;
+    var base_vecs = gloader.base.outline.points;
+    var base_vec = 0;
+    var num_points = gloader.base.outline.n_points;
+    var x, y;
+
+    var have_scale = (0 == (subglyph.flags & (FT_Common.WE_HAVE_A_SCALE | FT_Common.WE_HAVE_AN_XY_SCALE | FT_Common.WE_HAVE_A_2X2))) ? 0 : 1;
+
+    if (have_scale != 0)
+    {
+        for (var i = num_base_points; i < num_points; i++)
+            FT_Vector_Transform(base_vecs[i], subglyph.transform);
+    }
+
+    if (0 == (subglyph.flags & FT_Common.ARGS_ARE_XY_VALUES))
+    {
+        var k = subglyph.arg1;
+        var l = subglyph.arg2;
+        k += start_point;
+        l += num_base_points;
+        if (k >= num_base_points || l >= num_points)
+            return FT_Common.FT_Err_Invalid_Composite;
+
+        var p1 = gloader.base.outline.points[k];
+        var p2 = gloader.base.outline.points[l];
+
+        x = p1.x - p2.x;
+        y = p1.y - p2.y;
+    }
+    else
+    {
+        x = subglyph.arg1;
+        y = subglyph.arg2;
+
+        if (x == 0 && y == 0)
+            return 0;
+
+        if (have_scale != 0 && 0 != (subglyph.flags & FT_Common.SCALED_COMPONENT_OFFSET))
+        {
+            var mac_xscale = FT_SqrtFixed(FT_MulFix(subglyph.transform.xx, subglyph.transform.xx) +
+                                            FT_MulFix(subglyph.transform.xy, subglyph.transform.xy));
+            var mac_yscale = FT_SqrtFixed(FT_MulFix(subglyph.transform.yy, subglyph.transform.yy) +
+                                            FT_MulFix(subglyph.transform.yx, subglyph.transform.yx));
+
+
+            x = FT_MulFix(x, mac_xscale);
+            y = FT_MulFix(y, mac_yscale);
+        }
+
+        if (0 == (loader.load_flags & FT_Common.FT_LOAD_NO_SCALE))
+        {
+            var x_scale = loader.size.metrics.x_scale;
+            var y_scale = loader.size.metrics.y_scale;
+
+            x = FT_MulFix(x, x_scale);
+            y = FT_MulFix(y, y_scale);
+
+            if (subglyph.flags & FT_Common.ROUND_XY_TO_GRID)
+            {
+                x = FT_PIX_ROUND(x);
+                y = FT_PIX_ROUND(y);
+            }
+        }
+    }
+
+    if (x != 0)
+    {
+        for (var j=num_base_points;j<num_points;j++)
+            base_vecs[j].x += x;
+    }
+    if (y != 0)
+    {
+        for (var j=num_base_points;j<num_points;j++)
+            base_vecs[j].y += y;
+    }
+    
+    return 0;
+}
+
+function TT_Process_Composite_Glyph(loader, start_point, start_contour)
+{
+    var outline = loader.gloader.base.outline;
+
+    /* make room for phantom points */
+    var error = FT_GLYPHLOADER_CHECK_POINTS(loader.gloader, outline.n_points + 4, 0);
+    if (error != 0)
+        return error;
+
+    var _points = outline.points;
+    var _n_points = outline.n_points;
+    var _tags = outline.tags;
+
+    _points[_n_points].x = loader.pp1.x;
+    _points[_n_points].y = loader.pp1.y;
+
+    _points[_n_points + 1].x = loader.pp2.x;
+    _points[_n_points + 1].y = loader.pp2.y;
+
+    _points[_n_points + 2].x = loader.pp3.x;
+    _points[_n_points + 2].y = loader.pp3.y;
+
+    _points[_n_points + 3].x = loader.pp4.x;
+    _points[_n_points + 3].y = loader.pp4.y;
+
+    _tags[_n_points] = 0;
+    _tags[_n_points + 1] = 0;
+    _tags[_n_points + 2] = 0;
+    _tags[_n_points + 3] = 0;
+
+    if (loader.face.driver.library.tt_hint_props.TT_USE_BYTECODE_INTERPRETER) //#ifdef TT_USE_BYTECODE_INTERPRETER
+    {
+        /* TT_Load_Composite_Glyph only gives us the offset of instructions */
+        /* so we read them here                                             */
+        var stream = loader.stream;
+        error = stream.Seek(loader.ins_pos);
+        if (error != 0)
+            return error;
+
+        var n_ins = stream.ReadUShort();
+        error = FT_Error;
+        FT_Error = 0;
+        if (error != 0)
+            return error;
+
+        /* check it */
+        var max_ins = loader.face.max_profile.maxSizeOfInstructions;
+        if (n_ins > max_ins)
+        {
+            /* acroread ignores this field, so we only do a rough safety check */
+            if (n_ins > loader.byte_len)
+                return FT_Common.FT_Err_Too_Many_Hints;
+        
+            var ret = Update_MaxBYTE(loader.exec.memory, loader.exec.glyphSize, loader.exec.glyphIns, n_ins);
+            if (ret != null)
+            {
+                loader.exec.glyphSize = ret.size;
+                loader.exec.glyphIns = ret.block;
+            }
+
+            if ( error )
+                return error;
+        }
+        else if (n_ins == 0)
+            return 0;
+
+        error = stream.Read(loader.exec.glyphIns, n_ins);
+        if (error != 0)
+            return error;
+
+        loader.glyph.control_data = dublicate_pointer(loader.exec.glyphIns);
+        loader.glyph.control_len = n_ins;
+    }
+    //#endif
+
+    tt_prepare_zone(loader.zone, loader.gloader.base, start_point, start_contour);
+
+    /* Some points are likely touched during execution of  */
+    /* instructions on components.  So let's untouch them. */
+    for (var i = start_point; i < loader.zone.n_points; i++)
+        loader.zone.tags[i] &= ~FT_Common.FT_CURVE_TAG_TOUCH_BOTH;
+
+    loader.zone.n_points += 4;
+
+    return TT_Hint_Glyph(loader, true);
+}
+
+function TT_Hint_Glyph(loader, is_composite)
+{
+    var zone = loader.zone;
+    var n_ins = 0;
+
+    var _tt_hints = loader.face.driver.library.tt_hint_props;
+    if (_tt_hints.TT_USE_BYTECODE_INTERPRETER) //#ifdef TT_USE_BYTECODE_INTERPRETER
+    {
+        n_ins = loader.glyph.control_len;
+    }
+    //#endif
+
+    var origin = zone.cur[zone._offset_cur + zone.n_points - 4].x;
+    origin = FT_PIX_ROUND(origin) - origin;
+    if (origin != 0)
+        translate_array_ex(zone.n_points, zone.cur, zone._offset_cur, origin, 0);
+
+    if (_tt_hints.TT_USE_BYTECODE_INTERPRETER) //#ifdef TT_USE_BYTECODE_INTERPRETER
+    {
+        /* save original point position in org */
+        if (n_ins > 0)
+        {
+            var _arr_d = zone.org;
+            var _arr_s = zone.cur;
+            var _count = zone.n_points;
+            var _d_s = zone._offset_org;
+            var _s_s = zone._offset_cur;
+
+            for (var i = 0; i < _count; i++)
+            {
+                _arr_d[i + _d_s].x = _arr_s[i + _s_s].x;
+                _arr_d[i + _d_s].y = _arr_s[i + _s_s].y;
+            }
+        }
+
+        /* Reset graphics state. */
+        loader.size.GS.Copy(loader.exec.GS);
+
+        /* XXX: UNDOCUMENTED! Hinting instructions of a composite glyph */
+        /*      completely refer to the (already) hinted subglyphs.     */
+        if (is_composite)
+        {
+            loader.exec.metrics.x_scale = 1 << 16;
+            loader.exec.metrics.y_scale = 1 << 16;
+
+            var _arr_d = zone.orus;
+            var _arr_s = zone.cur;
+            var _count = zone.n_points;
+            var _d_s = zone._offset_orus;
+            var _s_s = zone._offset_cur;
+
+            for (var i = 0; i < _count; i++)
+            {
+                _arr_d[i + _d_s].x = _arr_s[i + _s_s].x;
+                _arr_d[i + _d_s].y = _arr_s[i + _s_s].y;
+            }
+        }
+        else
+        {
+            loader.exec.metrics.x_scale = loader.size.metrics.x_scale;
+            loader.exec.metrics.y_scale = loader.size.metrics.y_scale;
+        }
+    }//#endif
+
+    /* round pp2 and pp4 */
+    zone.cur[zone._offset_cur + zone.n_points - 3].x = FT_PIX_ROUND(zone.cur[zone._offset_cur + zone.n_points - 3].x);
+    zone.cur[zone._offset_cur + zone.n_points - 1].y = FT_PIX_ROUND(zone.cur[zone._offset_cur + zone.n_points - 1].y);
+
+    //#ifdef TT_USE_BYTECODE_INTERPRETER
+    if ( n_ins > 0 )
+    {
+        var base_outline = loader.gloader.base.outline;
+        var current_outline = loader.gloader.current.outline;
+
+        var error = TT_Set_CodeRange(loader.exec, FT_Common.tt_coderange_glyph, loader.exec.glyphIns, n_ins);
+        if (error)
+            return error;
+
+        loader.exec.is_composite = is_composite;
+        loader.exec.pts.Copy(zone);
+
+        var debug = (!(loader.load_flags & FT_Common.FT_LOAD_NO_SCALE) && loader.size.debug) ? true : false;
+
+        error = TT_Run_Context(loader.exec, debug);
+        if (error && loader.exec.pedantic_hinting)
+            return error;
+
+        /* store drop-out mode in bits 5-7; set bit 2 also as a marker */
+        base_outline.tags[current_outline.tags] |= (loader.exec.GS.scan_type << 5) | FT_Common.FT_CURVE_TAG_HAS_SCANMODE;
+    }
+    //#endif
+
+    /* save glyph phantom points */
+    if (!loader.preserve_pps)
+    {
+        var _off = zone.n_points + zone._offset_cur;
+
+        loader.pp1.x = zone.cur[_off - 4].x;
+        loader.pp1.y = zone.cur[_off - 4].y;
+
+        loader.pp2.x = zone.cur[_off - 3].x;
+        loader.pp2.y = zone.cur[_off - 3].y;
+
+        loader.pp3.x = zone.cur[_off - 2].x;
+        loader.pp3.y = zone.cur[_off - 2].y;
+
+        loader.pp4.x = zone.cur[_off - 1].x;
+        loader.pp4.y = zone.cur[_off - 1].y;
+    }
+
+    if (_tt_hints.TT_CONFIG_OPTION_SUBPIXEL_HINTING) //#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+    {
+        if (loader.exec.sph_tweak_flags & FT_Common.SPH_TWEAK_DEEMBOLDEN)
+            FT_Outline_EmboldenXY(loader.gloader.current.outline, -24, 0);
+        else if (loader.exec.sph_tweak_flags & FT_Common.SPH_TWEAK_EMBOLDEN)
+            FT_Outline_EmboldenXY(loader.gloader.current.outline, 24, 0);
+    }//#endif
+    return 0;
+}
+
+function tt_prepare_zone(zone, load, start_point, start_contour)
+{
+    zone.n_points    = (load.outline.n_points - start_point) & 0xFFFF;
+    zone.n_contours  = FT_Common.UShort_To_Short((load.outline.n_contours - start_contour) & 0xFFFF);
+
+    zone.org = load.extra_points;
+    zone._offset_org = start_point;
+
+    zone.cur = load.outline.points;
+    zone._offset_cur = start_point;
+
+    zone.orus = load.extra_points;
+    zone._offset_orus = load.extra_points2 + start_point;
+
+    zone.tags = load.outline.tags;
+    zone._offset_tags = start_point;
+
+    zone.contours = load.outline.contours;
+    zone._offset_contours = start_contour;
+
+    zone.first_point = start_point;
+}
+
+function tt_prepare_zone_cur(zone, load, start_point, start_contour)
+{
+    var _base = load.base;
+    var _cur = load.current;
+
+    zone.n_points    = (_cur.outline.n_points - start_point) & 0xFFFF;
+    zone.n_contours  = FT_Common.UShort_To_Short((_cur.outline.n_contours - start_contour) & 0xFFFF);
+
+    zone.org = _base.extra_points;
+    zone._offset_org = _cur.extra_points + start_point;
+
+    zone.cur = _base.outline.points;
+    zone._offset_cur = _cur.outline.points + start_point;
+
+    zone.orus = _base.extra_points;
+    zone._offset_orus = _cur.extra_points2 + start_point;
+
+    zone.tags = _base.outline.tags;
+    zone._offset_tags = _cur.outline.tags + start_point;
+
+    zone.contours = _base.outline.contours;
+    zone._offset_contours = _cur.outline.contours + start_contour;
+
+    zone.first_point = start_point;
+}
+
+function tt_size_run_prep(size, pedantic)
+{
+    var face = size.face;
+    var exec;
+    var error = 0;
+
+    /* debugging instances have their own context */
+    if (size.debug)
+        exec = size.context;
+    else
+        exec = face.driver.context;
+
+    if (exec == null)
+        return FT_Common.FT_Err_Could_Not_Find_Context;
+
+    TT_Load_Context(exec, face, size);
+
+    exec.callTop = 0;
+    exec.top     = 0;
+
+    exec.instruction_trap = false;
+    exec.pedantic_hinting = pedantic;
+
+    TT_Set_CodeRange(exec, FT_Common.tt_coderange_cvt, face.cvt_program, face.cvt_program_size);
+    TT_Clear_CodeRange(exec, FT_Common.tt_coderange_glyph);
+
+    if (face.cvt_program_size > 0)
+    {
+        error = TT_Goto_CodeRange(exec, FT_Common.tt_coderange_cvt, 0);
+
+        if (!error && !size.debug)
+        {
+            error = face.interpreter(exec);
+        }
+    }
+    else
+        error = 0;
+
+    /* save as default graphics state */
+    exec.GS.Copy(size.GS);
+
+    // _DEBUG!
+    /*
+    var __arr = exec.stack;
+    var __len = exec.stackSize;
+    for (var __i = 0; __i < __len; ++__i)
+        console.log("" + __i + ": " + __arr[__i]);
+    */
+    //
+
+    TT_Save_Context(exec, size);
+    return error;
+}
+
+function tt_loader_init(loader, size, glyph, load_flags, glyf_table_only)
+{
+    var face = glyph.face;
+    var stream = face.stream;
+    var pedantic = (0 == (load_flags & FT_Common.FT_LOAD_PEDANTIC)) ? 0 : 1;
+
+    loader.Clear();
+
+    var bIsHint = face.driver.library.tt_hint_props.TT_USE_BYTECODE_INTERPRETER;
+    var bIsSubpixHint = face.driver.library.tt_hint_props.TT_CONFIG_OPTION_SUBPIXEL_HINTING;
+
+    if (bIsHint)//#ifdef TT_USE_BYTECODE_INTERPRETER
+    {/* load execution context */
+        if ((load_flags & FT_Common.FT_LOAD_NO_HINTING) == 0 && !glyf_table_only)
+        {
+            var grayscale = false;
+
+            //#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+            var subpixel_hinting = false;
+            var grayscale_hinting = false;
+            //#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+
+            if (!size.cvt_ready)
+            {
+                var error = tt_size_ready_bytecode(size, pedantic);
+                if (error != 0)
+                    return error;
+            }
+
+            /* query new execution context */
+            var exec = size.debug ? size.context : face.driver.context;
+            if (exec == null)
+                return FT_Common.FT_Err_Could_Not_Find_Context;
+
+            if (bIsSubpixHint) // #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+            {
+                subpixel_hinting = ((FT_LOAD_TARGET_MODE(load_flags) != FT_Common.FT_RENDER_MODE_MONO) && FT_Common.SPH_OPTION_SET_SUBPIXEL);
+
+                if (subpixel_hinting)
+                    grayscale = grayscale_hinting = false;
+                else if (FT_Common.SPH_OPTION_SET_GRAYSCALE)
+                {
+                    grayscale = grayscale_hinting = true;
+                    subpixel_hinting = false;
+                }
+
+                if ((face.face_flags & FT_Common.FT_FACE_FLAG_TRICKY) != 0)
+                    subpixel_hinting = grayscale_hinting = false;
+
+                exec.ignore_x_mode = subpixel_hinting || grayscale_hinting;
+                exec.rasterizer_version = FT_Common.SPH_OPTION_SET_RASTERIZER_VERSION;
+                if (exec.sph_tweak_flags & FT_Common.SPH_TWEAK_RASTERIZER_35)
+                    exec.rasterizer_version = 35;
+
+                if (true)
+                {
+                    exec.compatible_widths     = FT_Common.SPH_OPTION_SET_COMPATIBLE_WIDTHS;
+                    exec.symmetrical_smoothing = false;
+                    exec.bgr                   = false;
+                    exec.subpixel_positioned   = true;
+                }
+                else
+                {
+                    /*
+                    exec.compatible_widths = (FT_LOAD_TARGET_MODE(load_flags) !=  FT_Common.TT_LOAD_COMPATIBLE_WIDTHS);
+                    exec.symmetrical_smoothing = (FT_LOAD_TARGET_MODE(load_flags) != FT_Common.TT_LOAD_SYMMETRICAL_SMOOTHING);
+                    exec.bgr = (FT_LOAD_TARGET_MODE(load_flags) != FT_Common.TT_LOAD_BGR);
+                    exec.subpixel_positioned = (FT_LOAD_TARGET_MODE(load_flags) != FT_Common.TT_LOAD_SUBPIXEL_POSITIONED);
+                    */
+                }
+            }/* !TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+            else
+            {
+                grayscale = (FT_LOAD_TARGET_MODE(load_flags) != FT_Common.FT_RENDER_MODE_MONO);
+            }/* !TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+
+            TT_Load_Context(exec, face, size);
+
+            if (bIsSubpixHint)//#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+            {
+                /* a change from mono to subpixel rendering (and vice versa) */
+                /* requires a re-execution of the CVT program                */
+                if (subpixel_hinting != exec.subpixel_hinting)
+                {
+                    exec.subpixel_hinting = subpixel_hinting;
+
+                    for (var i = 0; i < size.cvt_size; i++)
+                        size.cvt[i] = FT_MulFix(face.cvt[i], size.ttmetrics.scale);
+
+                    tt_size_run_prep(size, pedantic);
+                }
+
+                /* a change from mono to grayscale rendering (and vice versa) */
+                /* requires a re-execution of the CVT program                 */
+                if (grayscale != exec.grayscale_hinting)
+                {
+                    exec.grayscale_hinting = grayscale_hinting;
+
+                    for (var i = 0; i < size.cvt_size; i++)
+                        size.cvt[i] = FT_MulFix(face.cvt[i], size.ttmetrics.scale);
+                    tt_size_run_prep( size, pedantic );
+                }
+            }/* !TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+            else
+            {
+                /* a change from mono to grayscale rendering (and vice versa) */
+                /* requires a re-execution of the CVT program                 */
+                if (grayscale != exec.grayscale)
+                {
+                    exec.grayscale = grayscale;
+
+                    for (i = 0; i < size.cvt_size; i++)
+                        size.cvt[i] = FT_MulFix(face.cvt[i], size.ttmetrics.scale);
+
+                    tt_size_run_prep(size, pedantic);
+                }
+            }//#endif /* !TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+
+            /* see whether the cvt program has disabled hinting */
+            if (exec.GS.instruct_control & 1)
+                load_flags |= FT_Common.FT_LOAD_NO_HINTING;
+
+            /* load default graphics state -- if needed */
+            if (exec.GS.instruct_control & 2)
+                exec.GS.default_tt();
+
+            exec.pedantic_hinting = ((load_flags & FT_Common.FT_LOAD_PEDANTIC) != 0) ? true : false;
+            loader.exec = exec;
+            loader.instructions = dublicate_pointer(exec.glyphIns);
+        }
+    }//#endif /* TT_USE_BYTECODE_INTERPRETER */
+
+    if (face.internal.incremental_interface)
+        loader.glyf_offset = 0;
+    else
+    {
+        face.goto_table(face, FT_Common.TTAG_glyf, stream);
+        var error = FT_Error;
+        FT_Error = 0;
+        if (error == FT_Common.FT_Err_Table_Missing)
+            loader.glyf_offset = 0;
+        else if ( error )
+            return error;
+        else
+            loader.glyf_offset = stream.pos;
+    }
+
+    if (0 == glyf_table_only)
+    {
+        var gloader = glyph.internal.loader;
+        FT_GlyphLoader_Rewind(gloader);
+        loader.gloader = gloader;
+    }
+
+    loader.load_flags = load_flags;
+
+    loader.face = face;
+    loader.size = size;
+    loader.glyph = glyph;
+    loader.stream = stream;
+
+    return 0;
+}
+function compute_glyph_metrics(loader, glyph_index)
+{
+    var bbox = new FT_BBox();
+    var face = loader.face;
+    var y_scale = 0x10000;
+    var glyph = loader.glyph;
+    var size = loader.size;
+
+    if ((loader.load_flags & FT_Common.FT_LOAD_NO_SCALE) == 0)
+        y_scale = size.metrics.y_scale;
+
+    if (glyph.format != FT_Common.FT_GLYPH_FORMAT_COMPOSITE)
+        FT_Outline_Get_CBox(glyph.outline, bbox);
+    else
+    {
+        bbox.xMin = loader.bbox.xMin;
+        bbox.yMin = loader.bbox.yMin;
+        bbox.xMax = loader.bbox.xMax;
+        bbox.yMax = loader.bbox.yMax;
+    }
+
+    glyph.linearHoriAdvance = loader.linear;
+
+    glyph.metrics.horiBearingX = bbox.xMin;
+    glyph.metrics.horiBearingY = bbox.yMax;
+    glyph.metrics.horiAdvance  = loader.pp2.x - loader.pp1.x;
+
+    if (face.postscript.isFixedPitch == 0 && (loader.load_flags & FT_Common.FT_LOAD_NO_HINTING) == 0)
+    {
+        // TODO:
+    }
+
+    glyph.metrics.width  = bbox.xMax - bbox.xMin;
+    glyph.metrics.height = bbox.yMax - bbox.yMin;
+
+    var top;
+    var advance;
+
+    if (face.vertical_info === true && face.vertical.number_Of_VMetrics > 0)
+    {
+        top = FT_DivFix(loader.pp3.y - bbox.yMax, y_scale);
+
+        if (loader.pp3.y <= loader.pp4.y)
+            advance = 0;
+        else
+            advance = FT_DivFix(loader.pp3.y - loader.pp4.y, y_scale);
+    }
+    else
+    {
+        var height = FT_DivFix(bbox.yMax - bbox.yMin, y_scale);
+        if (face.os2.version != 0xFFFF)
+            advance = face.os2.sTypoAscender - face.os2.sTypoDescender;
+        else
+            advance = face.horizontal.Ascender - face.horizontal.Descender;
+
+        top = parseInt((advance - height)/2);
+    }
+
+    //#ifdef FT_CONFIG_OPTION_INCREMENTAL
+    var metrics = new FT_Incremental_MetricsRec();
+
+    var incr = face.internal.incremental_interface;
+    if (incr && incr.funcs.get_glyph_metrics)
+    {
+        metrics.bearing_x = 0;
+        metrics.bearing_y = top;
+        metrics.advance   = advance;
+
+        var error = incr.funcs.get_glyph_metrics(incr.object, glyph_index, true, metrics);
+        if (error != 0)
+            return error;
+
+        top     = metrics.bearing_y;
+        advance = metrics.advance;
+    }
+    //#endif
+
+    glyph.linearVertAdvance = advance;
+
+    /* scale the metrics */
+    if (0 == (loader.load_flags & FT_Common.FT_LOAD_NO_SCALE))
+    {
+        top     = FT_MulFix(top, y_scale);
+        advance = FT_MulFix(advance, y_scale);
+    }
+
+    glyph.metrics.vertBearingX = glyph.metrics.horiBearingX - parseInt(glyph.metrics.horiAdvance / 2);
+    glyph.metrics.vertBearingY = top;
+    glyph.metrics.vertAdvance  = advance;
+
+    return 0;
+}
+function TT_Load_Glyph(size, glyph, glyph_index, load_flags)
+{
+    var loader = new TT_LoaderRec();
+    var face = glyph.face;
+    var error = 0;
+
+    //#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
+    if (size.strike_index != 0xFFFFFFFF && ((load_flags & FT_Common.FT_LOAD_NO_BITMAP) == 0))
+    {
+        error = load_sbit_image(size, glyph, glyph_index, load_flags);
+        if (error == 0)
+        {
+            if ((face.face_flags & FT_Common.FT_FACE_FLAG_SCALABLE) != 0)
+            {
+                tt_loader_init(loader, size, glyph, load_flags, true);
+                load_truetype_glyph(loader, glyph_index, 0, true);
+                glyph.linearHoriAdvance = loader.linear;
+                glyph.linearVertAdvance = loader.top_bearing + loader.bbox.yMax - loader.vadvance;
+            }
+
+            return 0;
+        }
+    }
+    //#endif
+
+    if ((0 == (load_flags & FT_Common.FT_LOAD_NO_SCALE)) && (size.ttmetrics.valid == 0))
+        return FT_Common.FT_Err_Invalid_Size_Handle;
+
+    if ((load_flags & FT_Common.FT_LOAD_SBITS_ONLY) != 0)
+        return FT_Common.FT_Err_Invalid_Argument;
+
+    error = tt_loader_init(loader, size, glyph, load_flags, false);
+    if (error != 0)
+        return error;
+
+    glyph.format        = FT_Common.FT_GLYPH_FORMAT_OUTLINE;
+    glyph.num_subglyphs = 0;
+    glyph.outline.flags = 0;
+
+    /* main loading loop */
+    error = load_truetype_glyph(loader, glyph_index, 0, false);
+    if (error == 0)
+    {
+        if (glyph.format == FT_Common.FT_GLYPH_FORMAT_COMPOSITE)
+        {
+            glyph.num_subglyphs = loader.gloader.base.num_subglyphs;
+            glyph.subglyphs     = loader.gloader.base.subglyphs;
+        }
+        else
+        {
+            EquatingOutline(glyph.outline, loader.gloader.base.outline);
+            glyph.outline.flags &= ~FT_Common.FT_OUTLINE_SINGLE_PASS;
+
+            if (loader.pp1.x != 0)
+                FT_Outline_Translate(glyph.outline, -loader.pp1.x, 0);
+        }
+
+        if (face.driver.library.tt_hint_props.TT_USE_BYTECODE_INTERPRETER && ((load_flags & FT_Common.FT_LOAD_NO_HINTING) == 0))
+        {
+            if (loader.exec.GS.scan_control)
+            {
+                /* convert scan conversion mode to FT_OUTLINE_XXX flags */
+                switch (loader.exec.GS.scan_type)
+                {
+                case 0: /* simple drop-outs including stubs */
+                    glyph.outline.flags |= FT_Common.FT_OUTLINE_INCLUDE_STUBS;
+                    break;
+                case 1: /* simple drop-outs excluding stubs */
+                    /* nothing; it's the default rendering mode */
+                    break;
+                case 4: /* smart drop-outs including stubs */
+                    glyph.outline.flags |= (FT_Common.FT_OUTLINE_SMART_DROPOUTS | FT_Common.FT_OUTLINE_INCLUDE_STUBS);
+                    break;
+                case 5: /* smart drop-outs excluding stubs  */
+                    glyph.outline.flags |= FT_Common.FT_OUTLINE_SMART_DROPOUTS;
+                    break;
+
+                default: /* no drop-out control */
+                    glyph.outline.flags |= FT_Common.FT_OUTLINE_IGNORE_DROPOUTS;
+                    break;
+                }
+            }
+            else
+                glyph.outline.flags |= FT_Common.FT_OUTLINE_IGNORE_DROPOUTS;
+        }
+        compute_glyph_metrics(loader, glyph_index);
+    }
+
+    if ((0 == (load_flags & FT_Common.FT_LOAD_NO_SCALE)) && size.metrics.y_ppem < 24)
+        glyph.outline.flags |= FT_Common.FT_OUTLINE_HIGH_PRECISION;
+
+    return error;
+}
+
+function load_truetype_glyph(loader, glyph_index, recurse_count, header_only)
+{
+    var error = 0;
+    var x_scale, y_scale;
+    var offset;
+    var face = loader.face;
+    var gloader = loader.gloader;
+    var opened_frame = 0;
+
+    var glyph_data;
+    var glyph_data_loaded = 0;
+
+    if (recurse_count > 1 && recurse_count > face.max_profile.maxComponentDepth )
+        return FT_Common.FT_Err_Invalid_Composite;
+
+    if (glyph_index >= face.num_glyphs)
+        error = FT_Common.FT_Err_Invalid_Glyph_Index;
+
+    loader.glyph_index = glyph_index;
+
+    if ((loader.load_flags & FT_Common.FT_LOAD_NO_SCALE) == 0)
+    {
+        x_scale = loader.size.metrics.x_scale;
+        y_scale = loader.size.metrics.y_scale;
+    }
+    else
+    {
+        x_scale = 0x10000;
+        y_scale = 0x10000;
+    }
+
+    tt_get_metrics(loader, glyph_index);
+
+    if (face.internal.incremental_interface != null)
+    {
+        glyph_data = face.internal.incremental_interface.funcs.get_glyph_data(face.internal.incremental_interface.object, glyph_index);
+        error = FT_Error;
+        if (error != 0)
+            return error;
+
+        glyph_data_loaded = 1;
+        offset = 0;
+        loader.byte_len  = glyph_data.length;
+
+        loader.stream = new FT_Stream(glyph_data.pointer, glyph_data.length);
+    }
+    else
+    {
+        var __mem = tt_face_get_location(face, glyph_index);
+        offset = __mem.loc;
+        loader.byte_len = __mem.size;
+    }
+
+    if (loader.byte_len > 0)
+    {
+        if (0 == loader.glyf_offset && null == face.internal.incremental_interface)
+            return FT_Common.FT_Err_Invalid_Table;
+
+        error = face.access_glyph_frame(loader, glyph_index, loader.glyf_offset + offset, loader.byte_len);
+        if (error != 0)
+            return error;
+
+        opened_frame = 1;
+
+        error = face.read_glyph_header(loader);
+        if (error != 0 || header_only)
+            return error;
+    }
+
+    if (loader.byte_len == 0 || loader.n_contours == 0)
+    {
+        loader.bbox.xMin = 0;
+        loader.bbox.xMax = 0;
+        loader.bbox.yMin = 0;
+        loader.bbox.yMax = 0;
+
+        if (header_only == 1)
+            return error;
+
+        loader.pp1.x = loader.bbox.xMin - loader.left_bearing;
+        loader.pp1.y = 0;
+        loader.pp2.x = loader.pp1.x + loader.advance;
+        loader.pp2.y = 0;
+        loader.pp3.x = 0;
+        loader.pp3.y = loader.top_bearing + loader.bbox.yMax;
+        loader.pp4.x = 0;
+        loader.pp4.y = loader.pp3.y - loader.vadvance;
+
+        //#ifdef FT_CONFIG_OPTION_INCREMENTAL
+        tt_get_metrics_incr_overrides(loader, glyph_index);
+        //#endif
+
+        //#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
+        if (loader.face.doblend != 0)
+        {
+            var deltas = TT_Vary_Get_Glyph_Deltas(loader.face, glyph_index, 4);
+            error = FT_Error;
+            if (error != 0)
+                return error;
+
+            loader.pp1.x += deltas[0].x; loader.pp1.y += deltas[0].y;
+            loader.pp2.x += deltas[1].x; loader.pp2.y += deltas[1].y;
+            loader.pp3.x += deltas[2].x; loader.pp3.y += deltas[2].y;
+            loader.pp4.x += deltas[3].x; loader.pp4.y += deltas[3].y;
+
+            deltas = null;
+        }
+        //#endif
+
+        if ((loader.load_flags & FT_Common.FT_LOAD_NO_SCALE) == 0)
+        {
+            loader.pp1.x = FT_MulFix(loader.pp1.x, x_scale);
+            loader.pp2.x = FT_MulFix(loader.pp2.x, x_scale);
+            loader.pp3.y = FT_MulFix(loader.pp3.y, y_scale);
+            loader.pp4.y = FT_MulFix(loader.pp4.y, y_scale);
+        }
+
+        error = 0;
+        return error;
+    }
+
+    loader.pp1.x = loader.bbox.xMin - loader.left_bearing;
+    loader.pp1.y = 0;
+    loader.pp2.x = loader.pp1.x + loader.advance;
+    loader.pp2.y = 0;
+    loader.pp3.x = 0;
+    loader.pp3.y = loader.top_bearing + loader.bbox.yMax;
+    loader.pp4.x = 0;
+    loader.pp4.y = loader.pp3.y - loader.vadvance;
+
+    //#ifdef FT_CONFIG_OPTION_INCREMENTAL
+    tt_get_metrics_incr_overrides(loader, glyph_index);
+    //#endif
+
+    if (loader.n_contours > 0)
+    {
+        error = face.read_simple_glyph( loader );
+        if (error != 0)
+            return error;
+
+        face.forget_glyph_frame(loader);
+        opened_frame = 0;
+
+        error = TT_Process_Simple_Glyph(loader);
+        if (error != 0)
+            return error;
+
+        FT_GlyphLoader_Add(gloader);
+    }
+    else if (loader.n_contours == -1)
+    {
+        var start_point = gloader.base.outline.n_points;
+        var start_contour = gloader.base.outline.n_contours;
+
+        error = face.read_composite_glyph(loader);
+        if (error != 0)
+            return error;
+
+        var ins_pos = loader.ins_pos;
+
+        face.forget_glyph_frame( loader );
+        opened_frame = 0;
+
+        //#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
+
+        if (face.doblend != 0)
+        {
+            var deltas = TT_Vary_Get_Glyph_Deltas(face, glyph_index, gloader.current.num_subglyphs + 4);
+            error = FT_Error;
+            if (error != 0)
+                return error;
+
+            var subglyph = gloader.current.subglyphs[gloader.base.num_subglyphs];
+            var limit = gloader.current.num_subglyphs;
+
+            var i = 0;
+            for (; i < limit; ++i, ++subglyph )
+            {
+                if (subglyph.flags & FT_Common.ARGS_ARE_XY_VALUES)
+                {
+                    subglyph.arg1 += (deltas[i].x & 0xFFFF);
+                    subglyph.arg2 += (deltas[i].y & 0xFFFF);
+                }
+            }
+
+            loader.pp1.x += deltas[i + 0].x; loader.pp1.y += deltas[i + 0].y;
+            loader.pp2.x += deltas[i + 1].x; loader.pp2.y += deltas[i + 1].y;
+            loader.pp3.x += deltas[i + 2].x; loader.pp3.y += deltas[i + 2].y;
+            loader.pp4.x += deltas[i + 3].x; loader.pp4.y += deltas[i + 3].y;
+
+            deltas = null;
+        }
+        //#endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */
+
+        if ((loader.load_flags & FT_Common.FT_LOAD_NO_SCALE) == 0)
+        {
+            loader.pp1.x = FT_MulFix(loader.pp1.x, x_scale);
+            loader.pp2.x = FT_MulFix(loader.pp2.x, x_scale);
+            loader.pp3.y = FT_MulFix(loader.pp3.y, y_scale);
+            loader.pp4.y = FT_MulFix(loader.pp4.y, y_scale);
+        }
+
+        if ((loader.load_flags & FT_Common.FT_LOAD_NO_RECURSE) != 0)
+        {
+            FT_GlyphLoader_Add( gloader );
+            loader.glyph.format = FT_Common.FT_GLYPH_FORMAT_COMPOSITE;
+
+            return error;
+        }
+
+        var n, num_base_points;
+        var subglyph       = 0;
+
+        var num_points     = start_point;
+        var num_subglyphs  = gloader.current.num_subglyphs;
+        var num_base_subgs = gloader.base.num_subglyphs;
+
+        var old_stream = loader.stream;
+        var old_byte_len = loader.byte_len;
+
+        FT_GlyphLoader_Add(gloader);
+
+        for ( n = 0; n < num_subglyphs; n++ )
+        {
+            var pp = new Array(4);
+            subglyph = gloader.base.subglyphs[num_base_subgs + n];
+
+            pp[0] = loader.pp1;
+            pp[1] = loader.pp2;
+            pp[2] = loader.pp3;
+            pp[3] = loader.pp4;
+
+            num_base_points = gloader.base.outline.n_points;
+
+            error = load_truetype_glyph(loader, subglyph.index, recurse_count + 1, 0);
+            if (error != 0)
+                return error;
+
+            subglyph = gloader.base.subglyphs[num_base_subgs + n];
+
+            if (0 == (subglyph.flags & 0x0200))
+            {
+                loader.pp1 = pp[0];
+                loader.pp2 = pp[1];
+                loader.pp3 = pp[2];
+                loader.pp4 = pp[3];
+            }
+
+            if (gloader.base.outline.n_points == num_base_points)
+                continue;
+
+            TT_Process_Composite_Component(loader, subglyph, start_point, num_base_points);
+        }
+
+        loader.stream   = old_stream;
+        loader.byte_len = old_byte_len;
+
+        loader.ins_pos = ins_pos;
+
+        var bIsSubFlags = true;
+        if (bIsSubFlags && face.driver.library.tt_hint_props.TT_USE_BYTECODE_INTERPRETER)
+            bIsSubFlags = ((subglyph.flags & FT_Common.WE_HAVE_INSTR) != 0);
+
+        if (((loader.load_flags & FT_Common.FT_LOAD_NO_HINTING) == 0) && bIsSubFlags && num_points > start_point)
+            TT_Process_Composite_Glyph(loader, start_point, start_contour);
+    }
+    else
+        return FT_Common.FT_Err_Invalid_Outline;
+
+    if (opened_frame == 1)
+        face.forget_glyph_frame(loader);
+
+    //#ifdef FT_CONFIG_OPTION_INCREMENTAL
+    if (glyph_data_loaded != 0)
+    {
+        face.internal.incremental_interface.funcs.free_glyph_data(face.internal.incremental_interface.object, glyph_data);
+        glyph_data = null;
+    }
+    //#endif
+    return error;
+}
+function TT_Init_Glyph_Loading(face)
+{
+    face.access_glyph_frame   = TT_Access_Glyph_Frame;
+    face.read_glyph_header    = TT_Load_Glyph_Header;
+    face.read_simple_glyph    = TT_Load_Simple_Glyph;
+    face.read_composite_glyph = TT_Load_Composite_Glyph;
+    face.forget_glyph_frame   = TT_Forget_Glyph_Frame;
+}
+/******************************************************************************/
+// driver
+/******************************************************************************/
+var tt_service_truetype_engine = new FT_Service_TrueTypeEngineRec(0);
+var tt_service_truetype_glyf = new FT_Service_TTGlyfRec(tt_face_get_location);
+var tt_service_gx_multi_masters = new FT_Service_MultiMastersRec(null,null,TT_Set_MM_Blend,TT_Get_MM_Var,TT_Set_Var_Design);
+var tt_services = new Array(4);
+tt_services[0] = new FT_ServiceDescRec(FT_SERVICE_ID_XF86_NAME,FT_XF86_FORMAT_TRUETYPE);
+tt_services[1] = new FT_ServiceDescRec(FT_SERVICE_ID_MULTI_MASTERS,tt_service_gx_multi_masters);
+tt_services[2] = new FT_ServiceDescRec(FT_SERVICE_ID_TRUETYPE_ENGINE,tt_service_truetype_engine);
+tt_services[3] = new FT_ServiceDescRec(FT_SERVICE_ID_TT_GLYF,tt_service_truetype_glyf);
+
+var FT_TT_SERVICES_GET                  = tt_services;
+var FT_TT_SERVICE_GX_MULTI_MASTERS_GET  = tt_service_gx_multi_masters;
+var FT_TT_SERVICE_TRUETYPE_GLYF_GET     = tt_service_truetype_glyf;
+
+function tt_check_trickyness_sfnt_ids(face)
+{
+    var checksum = 0;
+    var i = 0;
+    var j = 0;
+    var k = 0;
+    var num_matched_ids = new Array(13);
+    for (var l = 0; l < 13; l++)
+        num_matched_ids[l] = 0;
+
+    var TRICK_SFNT_ID_cvt = 0;
+    var TRICK_SFNT_ID_fpgm = 1;
+    var TRICK_SFNT_ID_prep = 2;
+
+    var has_cvt  = false;
+    var has_fpgm = false;
+    var has_prep = false;
+
+    var sfnt_id = face.driver.sfnt_id;
+
+    for (i = 0; i < face.num_tables; i++)
+    {
+        checksum = 0;
+        switch(face.dir_tables[i].Tag)
+        {
+            case FT_Common.TTAG_cvt:
+                k = TRICK_SFNT_ID_cvt;
+                has_cvt  = true;
+                break;
+
+            case FT_Common.TTAG_fpgm:
+                k = TRICK_SFNT_ID_fpgm;
+                has_fpgm = true;
+                break;
+
+            case FT_Common.TTAG_prep:
+                k = TRICK_SFNT_ID_prep;
+                has_prep = true;
+                break;
+
+            default:
+                continue;
+        }
+
+        for ( j = 0; j < 13; j++ )
+            if ( face.dir_tables[i].Length == sfnt_id[j][k].Length )
+            {
+                if (checksum != 0)
+                    checksum = tt_get_sfnt_checksum(face, i);
+
+                if (sfnt_id[j][k].CheckSum == checksum)
+                    num_matched_ids[j]++;
+
+                if (num_matched_ids[j] == 3)
+                    return true;
+            }
+    }
+    for (j = 0; j < 13; j++)
+    {
+        if ( !has_cvt  && !sfnt_id[j][TRICK_SFNT_ID_cvt].Length )
+            num_matched_ids[j] ++;
+        if ( !has_fpgm && !sfnt_id[j][TRICK_SFNT_ID_fpgm].Length )
+            num_matched_ids[j] ++;
+        if ( !has_prep && !sfnt_id[j][TRICK_SFNT_ID_prep].Length )
+            num_matched_ids[j] ++;
+        if (num_matched_ids[j] == 3)
+            return true;
+    }
+    return false;
+}
+function tt_get_sfnt_checksum(face, i)
+{
+    if (!face.goto_table)
+        return 0;
+
+    var len = face.goto_table(face, face.dir_tables[i].Tag, face.stream);
+        return 0;
+
+    if (FT_Error != FT_Common.FT_Err_Ok)
+        return 0;
+
+    return tt_synth_sfnt_checksum(face.stream, face.dir_tables[i].Length);
+}
+function tt_synth_sfnt_checksum(stream, length)
+{
+    var error = 0;
+    var checksum = 0;
+    var i = 0;
+
+    var len = length;
+    if (FT_Common.FT_Err_Ok != stream.EnterFrame(len))
+        return 0;
+
+    for ( ; len > 3; len -= 4 )
+        checksum += stream.GetULong();
+
+    for ( i = 3; len > 0; len --,i--)
+        checksum += (stream.GetUChar() << (i * 8));
+
+    stream.ExitFrame();
+    return checksum;
+}
+function tt_check_trickyness(face)
+{
+    if (!face)
+        return false;
+
+    if ((face.family_name != "") && (tt_check_trickyness_family(face.family_name) === true))
+        return true;
+
+    return tt_check_trickyness_sfnt_ids(face);
+}
+function tt_check_trickyness_family(name)
+{
+    if (name == "DFKaiSho-SB")
+        return true;
+    if (name == "DFKaiShu")
+        return true;
+    if (name == "DFKai-SB")
+        return true;
+    if (name == "HuaTianKaiTi?")
+        return true;
+    if (name == "HuaTianSongTi?")
+        return true;
+    if (name == "MingLiU")
+        return true;
+    if (name == "PMingLiU")
+        return true;
+    if (name == "MingLi43")
+        return true;
+    return false;
+}
+function tt_face_load_hdmx(face, stream)
+{
+    var error = FT_Common.FT_Err_Ok;
+    var version = 0;
+    var nn = 0;
+    var num_records = 0;
+    var table_size = 0;
+    var record_size = 0;
+
+    table_size = face.goto_table(face, FT_Common.TTAG_hdmx, stream);
+    if ( (FT_Error != FT_Common.FT_Err_Ok) || table_size < 8 )
+    {
+		FT_Error = 0;
+		return FT_Common.FT_Err_Ok;
+	}
+
+    face.hdmx_table = new CPointer();
+    error = stream.ExtractFrame(table_size, face.hdmx_table);
+    if (error != FT_Common.FT_Err_Ok)
+        return error;
+
+    var p = dublicate_pointer(face.hdmx_table);
+    var end = p.pos + table_size;
+
+    version     = FT_NEXT_USHORT(p);
+    num_records = FT_NEXT_USHORT(p);
+    record_size = FT_NEXT_ULONG(p);
+
+    if (record_size >= 0xFFFF0000)
+        record_size &= 0xFFFF;
+
+    if (version != 0 || num_records > 255 || record_size > 0x10001)
+    {
+        error = FT_Common.FT_Err_Invalid_File_Format;
+        face.hdmx_table = null;
+        face.hdmx_table_size = 0;
+        stream.ReleaseFrame();
+        return error;
+    }
+
+    if (0 != num_records)
+        face.hdmx_record_sizes = new Array(num_records);
+
+    for ( nn = 0; nn < num_records; nn++ )
+    {
+        if ( (p.pos + record_size) > end )
+            break;
+
+        face.hdmx_record_sizes[nn] = p.data[p.pos];
+        p.pos += record_size;
+    }
+
+    face.hdmx_record_count = nn;
+    face.hdmx_table_size   = table_size;
+    face.hdmx_record_size  = record_size;
+
+    return error;
+}
+
+function tt_face_load_loca(face, stream)
+{
+    var error = FT_Common.FT_Err_Ok;
+    var table_len = 0;
+    var shift = 0;
+
+    face.glyf_len = face.goto_table(face, FT_Common.TTAG_glyf, stream);
+    error = FT_Error;
+
+    if ( error == FT_Common.FT_Err_Table_Missing)
+        face.glyf_len = 0;
+    else if (error != FT_Common.FT_Err_Ok)
+        return error;
+
+    table_len = face.goto_table(face, FT_Common.TTAG_loca, stream);
+    error = FT_Error;
+    if (error != FT_Common.FT_Err_Ok)
+    {
+        error = FT_Common.FT_Err_Locations_Missing;
+        return error;
+    }
+
+    if (face.header.Index_To_Loc_Format != 0)
+    {
+        shift = 2;
+        if (table_len >= 0x40000)
+        {
+            error = FT_Common.FT_Err_Invalid_Table;
+            return error;
+        }
+        face.num_locations = table_len >>> shift;
+    }
+    else
+    {
+        shift = 1;
+
+        if (table_len >= 0x20000)
+        {
+            error = FT_Common.FT_Err_Invalid_Table;
+            return error;
+        }
+        face.num_locations = table_len >>> shift;
+    }
+
+    if (face.num_locations != (face.num_glyphs + 1))
+    {
+        if (face.num_locations <= face.num_glyphs)
+        {
+            var new_loca_len = (face.num_glyphs + 1) << shift;
+
+            var pos = stream.pos;
+            var dist = 0x7FFFFFFF;
+
+            var entry = 0;
+            for (; entry < face.num_tables; entry++)
+            {
+                var diff = face.dir_tables[entry].Offset - pos;
+                if (diff > 0 && diff < dist)
+                    dist = diff;
+            }
+
+            if (entry == face.num_tables)
+            {
+                dist = stream.size - pos;
+            }
+
+            if (new_loca_len <= dist)
+            {
+                face.num_locations = face.num_glyphs + 1;
+                table_len          = new_loca_len;
+            }
+        }
+    }
+
+    face.glyph_locations = new CPointer();
+    error = stream.ExtractFrame(table_len, face.glyph_locations);
+    return error;
+}
+function tt_face_get_location(face, gindex)
+{
+    var pos1 = 0;
+    var pos2 = 0;
+    var asize = 0;
+
+    pos1 = pos2 = 0;
+    var p = new CPointer();
+    p.data = face.glyph_locations.data;
+    var pos_s = face.glyph_locations.pos;
+    var p_limit = 0;
+    if (gindex < face.num_locations)
+    {
+        if (face.header.Index_To_Loc_Format != 0)
+        {
+            p.pos = pos_s + gindex * 4;
+            p_limit = pos_s + face.num_locations * 4;
+
+            pos1 = FT_NEXT_ULONG(p);
+            pos2 = pos1;
+
+            if (p.pos + 4 <= p_limit)
+                pos2 = FT_NEXT_ULONG(p);
+        }
+        else
+        {
+            p.pos  = pos_s + gindex * 2;
+            p_limit = pos_s + face.num_locations * 2;
+
+            pos1 = FT_NEXT_USHORT(p);
+            pos2 = pos1;
+
+            if (p.pos + 2 <= p_limit)
+                pos2 = FT_NEXT_USHORT(p);
+
+            pos1 <<= 1;
+            pos2 <<= 1;
+        }
+    }
+
+    if (pos1 >= face.glyf_len)
+        return {loc:0,size:0};
+
+    if (pos2 >= face.glyf_len)
+        pos2 = face.glyf_len;
+
+    if (pos2 >= pos1)
+        asize = pos2 - pos1;
+    else
+        asize = face.glyf_len - pos1;
+
+    return {loc:pos1,size:asize};
+}
+function tt_face_load_cvt(face, stream)
+{
+    //#ifdef TT_USE_BYTECODE_INTERPRETER
+    if (face.driver.library.tt_hint_props.TT_USE_BYTECODE_INTERPRETER || true)
+    {
+        var table_len = face.goto_table(face, FT_Common.TTAG_cvt, stream);
+        var error = FT_Error;
+		FT_Error = 0;
+
+        if (error != 0)
+        {
+            face.cvt_size = 0;
+            face.cvt = null;
+            return 0;
+        }
+
+        face.cvt_size = table_len / 2;
+        face.cvt = CreateIntArray(face.cvt_size);
+
+        error = stream.EnterFrame(table_len);
+        if (error != 0)
+            return error;
+
+        for (var i = 0; i < face.cvt_size; i++)
+            face.cvt[i] = stream.GetShort();
+        
+        //#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
+        if (face.doblend)
+            error = tt_face_vary_cvt(face, stream);
+        //#endif
+
+        return error;
+    }
+    //#endif
+    return 0;
+}
+function tt_face_load_fpgm(face, stream)
+{
+    //#ifdef TT_USE_BYTECODE_INTERPRETER
+    if (face.driver.library.tt_hint_props.TT_USE_BYTECODE_INTERPRETER || true)
+    {
+        /* The font program is optional */
+        var table_len = face.goto_table(face, FT_Common.TTAG_fpgm, stream);
+        var error = FT_Error;
+		FT_Error = 0;
+		
+        if (error != 0)
+        {
+            face.font_program = null;
+            face.font_program_size = 0;
+            error = 0;
+            return error;
+        }
+        else
+        {
+            face.font_program_size = table_len;
+            face.font_program = new CPointer();
+            return stream.ExtractFrame(table_len, face.font_program);
+        }
+    }
+    //#endif
+    return 0;
+}
+function tt_face_load_prep(face, stream)
+{
+    //#ifdef TT_USE_BYTECODE_INTERPRETER
+    if (face.driver.library.tt_hint_props.TT_USE_BYTECODE_INTERPRETER || true)
+    {
+        var table_len = face.goto_table(face, FT_Common.TTAG_prep, stream);
+        var error = FT_Error;
+		FT_Error = 0;
+		
+        if (error != 0)
+        {
+            face.cvt_program = null;
+            face.cvt_program_size = 0;
+            return 0;
+        }
+        else
+        {
+            face.cvt_program_size = table_len;
+            face.cvt_program = new CPointer();
+            return stream.ExtractFrame(table_len, face.cvt_program);
+        }
+    }
+    //#endif
+    return 0;
+}
+function tt_check_single_notdef(face)
+{
+    var result = false;
+
+    var asize = 0;
+    var i = 0;
+    var glyph_index = 0;
+    var count = 0;
+
+    for( i = 0; i < face.num_locations; i++ )
+    {
+        asize = tt_face_get_location(face, i).size;
+        if ( asize > 0 )
+        {
+            count += 1;
+            if ( count > 1 )
+                break;
+            glyph_index = i;
+        }
+    }
+
+    /* Only have a single outline. */
+    if (count == 1)
+    {
+        if (glyph_index == 0)
+            result = true;
+        else
+        {
+            /* FIXME: Need to test glyphname == .notdef ? */
+            FT_Error = FT_Common.FT_Err_Ok;
+            var buffer = g_memory.Alloc(10);
+            buffer.pos = 0;
+
+            FT_Get_Glyph_Name(face, glyph_index, buffer, 8);
+            var buf = "";
+            for (var i = 0; i < 10; i++)
+            {
+                buf += String.fromCharCode(buffer.data[i]);
+            }
+
+            if (FT_Error != FT_Common.FT_Err_Ok && buf[0] == '.' && (0 == _strncmp(buf,".notdef",8)))
+                result = true;
+        }
+    }
+
+    FT_Error = FT_Common.FT_Err_Ok;
+    return result;
+}
+
+function tt_driver_init(ttdriver)
+{
+    var _tt_hint_props = ttdriver.library.tt_hint_props;
+    if (_tt_hint_props.TT_USE_BYTECODE_INTERPRETER || true)
+    {
+        if (!TT_New_Context(ttdriver))
+            FT_Common.FT_Err_Could_Not_Find_Context;
+    }
+    return 0;
+}
+function tt_driver_done(ttdriver)
+{
+    var _tt_hint_props = ttdriver.library.tt_hint_props;
+    if (_tt_hint_props.TT_USE_BYTECODE_INTERPRETER || true)
+    {
+        if (ttdriver.context != null)
+        {
+            TT_Done_Context(ttdriver.context);
+            ttdriver.context = null;
+        }
+    }
+}
+function tt_get_interface(driver, tt_interface)
+{
+    var result = ft_service_list_lookup(FT_TT_SERVICES_GET, tt_interface);
+    if (result != null)
+        return result;
+
+    if (driver == null)
+        return null;
+
+    var sfntd = driver.library.FT_Get_Module("sfnt");
+    if (null != sfntd)
+    {
+        var sfnt = sfntd.clazz.module_interface;
+        if (null != sfnt)
+            return sfnt.get_interface(driver, tt_interface);
+    }
+    return null;
+}
+function tt_face_init(stream, face, face_index)
+{
+    var error = FT_Common.FT_Err_Ok;
+    var library = face.driver.library;
+    var sfnt = library.FT_Get_Module_Interface("sfnt");
+
+    error = stream.Seek(0);
+    if (error != FT_Common.FT_Err_Ok)
+        return error;
+
+    error = sfnt.init_face(stream, face, face_index);
+    if (error != FT_Common.FT_Err_Ok)
+        return error;
+
+    if (face.format_tag != 0x00010000 && face.format_tag != 0x00020000 && face.format_tag != FT_Common.TTAG_true)
+    {
+        error = FT_Common.FT_Err_Unknown_File_Format;
+        return error;
+    }
+
+    if (library.tt_hint_props.TT_USE_BYTECODE_INTERPRETER || true)
+        face.face_flags |= FT_Common.FT_FACE_FLAG_HINTER;
+
+    if ( face_index < 0 )
+        return FT_Common.FT_Err_Ok;
+
+    error = sfnt.load_face(stream, face, face_index);
+    if (error != FT_Common.FT_Err_Ok)
+        return error;
+
+    if (tt_check_trickyness(face) === true)
+        face.face_flags |= FT_Common.FT_FACE_FLAG_TRICKY;
+
+    error = tt_face_load_hdmx(face, stream);
+    if (error != FT_Common.FT_Err_Ok)
+        return error;
+
+    if ((face.face_flags & FT_Common.FT_FACE_FLAG_SCALABLE) != 0)
+    {
+        //#ifdef FT_CONFIG_OPTION_INCREMENTAL
+        if (null == face.internal.incremental_interface)
+            error = tt_face_load_loca(face, stream);
+        if (error == FT_Common.FT_Err_Ok)
+            error = tt_face_load_cvt(face, stream);
+        if (error == FT_Common.FT_Err_Ok)
+            error = tt_face_load_fpgm(face, stream);
+        if (error == FT_Common.FT_Err_Ok)
+            error = tt_face_load_prep(face, stream);
+
+        /* Check the scalable flag based on `loca'. */
+        if ((null == face.internal.incremental_interface) && (0 != face.num_fixed_sizes) && (face.glyph_locations != null) &&
+            tt_check_single_notdef(face))
+        {
+            face.face_flags &= ~FT_Common.FT_FACE_FLAG_SCALABLE;
+        }
+        //#endif
+    }
+
+    //#if defined( TT_CONFIG_OPTION_UNPATENTED_HINTING )
+    // TODO:
+    //#endif
+
+    TT_Init_Glyph_Loading(face);
+    return error;
+}
+function tt_face_done(face)
+{
+}
+function tt_size_init()
+{
+    var size  = new TT_SizeRec();
+
+    //#ifdef TT_USE_BYTECODE_INTERPRETER
+    size.bytecode_ready = 0;
+    size.cvt_ready      = 0;
+    //#endif
+
+    size.ttmetrics.valid = 0;
+    size.strike_index = 0xFFFFFFFF;
+
+    return size;
+}
+function tt_size_done(size)
+{
+    //#ifdef TT_USE_BYTECODE_INTERPRETER
+    if (size.bytecode_ready)
+        tt_size_done_bytecode(size);
+    //#endif
+    size.ttmetrics.valid = 0;
+}
+function tt_slot_init(slot)
+{
+    return FT_GlyphLoader_CreateExtra(slot.internal.loader);
+}
+function Load_Glyph(slot, size, glyph_index, load_flags)
+{
+    var face = slot.face;
+    var error = 0;
+
+    if (!slot)
+        return FT_Common.FT_Err_Invalid_Slot_Handle;
+
+    if (!size)
+        return FT_Common.FT_Err_Invalid_Size_Handle;
+
+    if (!face)
+        return FT_Common.FT_Err_Invalid_Argument;
+
+    //#ifdef FT_CONFIG_OPTION_INCREMENTAL
+    if (glyph_index >= face.num_glyphs && (null == face.internal.incremental_interface))
+        return FT_Common.FT_Err_Invalid_Argument;
+
+    if ((load_flags & FT_Common.FT_LOAD_NO_HINTING) != 0)
+    {
+        if ((face.face_flags & FT_Common.FT_FACE_FLAG_TRICKY) != 0)
+            load_flags &= ~FT_Common.FT_LOAD_NO_HINTING;
+
+        if ((load_flags & FT_Common.FT_LOAD_NO_AUTOHINT) != 0)
+            load_flags |= FT_Common.FT_LOAD_NO_HINTING;
+    }
+
+    if ((load_flags & (FT_Common.FT_LOAD_NO_RECURSE | FT_Common.FT_LOAD_NO_SCALE)) != 0)
+    {
+        load_flags |= (FT_Common.FT_LOAD_NO_BITMAP | FT_Common.FT_LOAD_NO_SCALE);
+
+        if ((face.face_flags & FT_Common.FT_FACE_FLAG_TRICKY) == 0)
+            load_flags |= FT_Common.FT_LOAD_NO_HINTING;
+    }
+
+    error = TT_Load_Glyph(size, slot, glyph_index, load_flags);
+    return error;
+}
+function tt_get_kerning(face, left_glyph, right_glyph, kerning)
+{
+    kerning.x = 0;
+    kerning.y = 0;
+
+    if (face.sfnt)
+        kerning.x = face.sfnt.get_kerning(face, left_glyph, right_glyph);
+
+    return 0;
+}
+function tt_get_advances(face, start, count, flags, advances)
+{
+    /* XXX: TODO: check for sbits */
+    if ((face.face_flags & FT_Common.FT_LOAD_VERTICAL_LAYOUT) != 0)
+    {
+        for (var nn = 0; nn < count; nn++)
+        {
+            var res = TT_Get_VMetrics(face, start + nn);
+            advances[nn] = res.ah;
+        }
+    }
+    else
+    {
+        for (var nn = 0; nn < count; nn++)
+        {
+            var res = TT_Get_HMetrics(face, start);
+            advances[nn] = res.aw;
+        }
+    }
+
+    return 0;
+}
+function tt_size_request(size, req)
+{
+    var error = 0;
+
+    //#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
+    if ((size.face.face_flags & FT_Common.FT_FACE_FLAG_FIXED_SIZES) != 0)
+    {
+        var sfnt = size.face.sfnt;
+        var strike_index = sfnt.set_sbit_strike(size.face, req);
+
+        error = FT_Error;
+        FT_Error = 0;
+
+        if (error != 0)
+            size.strike_index = 0xFFFFFFFF;
+    else
+        return this.select_size(size, strike_index);
+    }
+    //#endif
+
+    FT_Request_Metrics(size.face, req);
+
+    if ((size.face.face_flags & FT_Common.FT_FACE_FLAG_SCALABLE) != 0)
+    {
+        error = tt_size_reset(size);
+
+        var s = size._metrics;
+        var d = size.metrics;
+
+        d.x_ppem = s.x_ppem;
+        d.y_ppem = s.y_ppem;
+
+        d.x_scale = s.x_scale;
+        d.y_scale = s.y_scale;
+
+        d.ascender = s.ascender;
+        d.descender = s.descender;
+        d.height = s.height;
+        d.max_advance = s.max_advance;
+    }
+
+    return error;
+}
+function tt_size_select(size, strike_index)
+{
+    var ttface = size.face;
+    var error = 0;
+    size.strike_index = strike_index;
+
+    if ((ttface.face_flags & FT_Common.FT_FACE_FLAG_SCALABLE) != 0)
+    {
+        FT_Select_Metrics(ttface, strike_index);
+        tt_size_reset(size);
+    }
+    else
+    {
+        var sfnt = ttface.sfnt;
+        var metrics = size.metrics;
+
+        error = sfnt.load_strike_metrics(ttface, strike_index, metrics);
+        if (error != 0)
+            size.strike_index = 0xFFFFFFFF;
+    }
+    return error;
+}
+
+function tt_size_reset(size)
+{
+    size.ttmetrics.valid = 0;
+    var face = size.face;
+
+    var d = size._metrics;
+    var s = size.metrics;
+
+    d.x_ppem = s.x_ppem;
+    d.y_ppem = s.y_ppem;
+
+    d.x_scale = s.x_scale;
+    d.y_scale = s.y_scale;
+
+    d.ascender = s.ascender;
+    d.descender = s.descender;
+    d.height = s.height;
+    d.max_advance = s.max_advance;
+
+    if (d.x_ppem < 1 || d.y_ppem < 1)
+        return FT_Common.FT_Err_Invalid_PPem;
+
+    if (face.header.Flags & 8)
+    {
+        d.x_scale = FT_DivFix(d.x_ppem << 6, face.units_per_EM);
+        d.y_scale = FT_DivFix(d.y_ppem << 6, face.units_per_EM);
+
+        d.ascender = FT_PIX_ROUND(FT_MulFix(face.ascender, d.y_scale));
+        d.descender = FT_PIX_ROUND(FT_MulFix(face.descender, d.y_scale));
+        d.height = FT_PIX_ROUND(FT_MulFix(face.height, d.y_scale));
+        d.max_advance = FT_PIX_ROUND(FT_MulFix(face.max_advance_width, d.x_scale));
+    }
+
+    var tt = size.ttmetrics;
+    /* compute new transformation */
+    if (d.x_ppem >= d.y_ppem)
+    {
+        tt.scale   = d.x_scale;
+        tt.ppem    = d.x_ppem;
+        tt.x_ratio = 0x10000;
+        tt.y_ratio = FT_MulDiv(d.y_ppem, 0x10000, d.x_ppem);
+    }
+    else
+    {
+        tt.scale   = d.y_scale;
+        tt.ppem    = d.y_ppem;
+        tt.x_ratio = FT_MulDiv(d.x_ppem, 0x10000, d.y_ppem);
+        tt.y_ratio = 0x10000;
+    }
+
+    //#ifdef TT_USE_BYTECODE_INTERPRETER
+    // TODO:
+    //#endif
+
+    size.ttmetrics.valid = 1;
+    return 0;
+}
+
+function TT_Driver_Class()
+{
+    this.flags = 0x101;
+    this.name = "truetype";
+    this.version = 0x10000;
+    this.requires = 0x20000;
+
+    this.module_interface = null;
+
+    this.init = tt_driver_init;
+    this.done = tt_driver_done;
+    this.get_interface = tt_get_interface;
+
+    this.face_object_size = 0;
+    this.size_object_size = 0;
+    this.slot_object_size = 0;
+
+    this.init_face = tt_face_init;
+    this.done_face = tt_face_done;
+
+    this.init_size = tt_size_init;
+    this.done_size = tt_size_done;
+
+    this.init_slot = tt_slot_init;
+    this.done_slot = null;
+
+    //#ifdef FT_CONFIG_OPTION_OLD_INTERNALS
+    this.set_char_sizes = ft_stub_set_char_sizes;
+    this.set_pixel_sizes = ft_stub_set_pixel_sizes;
+    //#endif
+
+    this.load_glyph = Load_Glyph;
+
+    this.get_kerning = tt_get_kerning;
+    this.attach_file = null;
+    this.get_advances = tt_get_advances;
+
+    this.request_size = tt_size_request;
+    this.select_size = tt_size_select;
+}
+
+function tt_sfnt_id_rec(c,l)
+{
+    this.CheckSum = c;
+    this.Length = l;
+}
+
+function TT_Driver()
+{
+    this.clazz = null;      // FT_Module_Class
+    this.library = null;    // FT_Library
+    this.memory = null;     // FT_Memory
+    this.generic = null;    // FT_Generic
+
+    this.clazz = new TT_Driver_Class();
+    this.faces_list = [];
+    this.extensions = null;
+    this.glyph_loader = null;
+
+    this.context = null;
+    this.zone = new TT_GlyphZoneRec();
+    this.extension_component = null;
+
+    this.open_face = function(stream, face_index)
+    {
+        if (null == this.sfnt_id)
+        {
+            this.sfnt_id = new Array(13);
+            this.sfnt_id[0] = new Array(3);
+            this.sfnt_id[0][0] = new tt_sfnt_id_rec(0x05bcf058, 0x000002e4);
+            this.sfnt_id[0][1] = new tt_sfnt_id_rec(0x28233bf1, 0x000087c4);
+            this.sfnt_id[0][2] = new tt_sfnt_id_rec(0xa344a1ea, 0x000001e1);
+
+            this.sfnt_id[1] = new Array(3);
+            this.sfnt_id[1][0] = new tt_sfnt_id_rec(0x05bcf058, 0x000002e4);
+            this.sfnt_id[1][1] = new tt_sfnt_id_rec(0x28233bf1, 0x000087c4);
+            this.sfnt_id[1][2] = new tt_sfnt_id_rec(0xa344a1eb, 0x000001e1);
+
+            this.sfnt_id[2] = new Array(3);
+            this.sfnt_id[2][0] = new tt_sfnt_id_rec(0x11e5ead4, 0x00000350);
+            this.sfnt_id[2][1] = new tt_sfnt_id_rec(0x5a30ca3b, 0x00009063);
+            this.sfnt_id[2][2] = new tt_sfnt_id_rec(0x13a42602, 0x0000007e);
+
+            this.sfnt_id[3] = new Array(3);
+            this.sfnt_id[3][0] = new tt_sfnt_id_rec(0xfffbfffc, 0x00000008);
+            this.sfnt_id[3][1] = new tt_sfnt_id_rec(0x9c9e48b8, 0x0000bea2);
+            this.sfnt_id[3][2] = new tt_sfnt_id_rec(0x70020112, 0x00000008);
+
+            this.sfnt_id[4] = new Array(3);
+            this.sfnt_id[4][0] = new tt_sfnt_id_rec(0xfffbfffc, 0x00000008);
+            this.sfnt_id[4][1] = new tt_sfnt_id_rec(0x0a5a0483, 0x00017c39);
+            this.sfnt_id[4][2] = new tt_sfnt_id_rec(0x70020112, 0x00000008);
+
+            this.sfnt_id[5] = new Array(3);
+            this.sfnt_id[5][0] = new tt_sfnt_id_rec(0x00000000, 0x00000000);
+            this.sfnt_id[5][1] = new tt_sfnt_id_rec(0x40c92555, 0x000000e5);
+            this.sfnt_id[5][2] = new tt_sfnt_id_rec(0xa39b58e3, 0x0000117c);
+
+            this.sfnt_id[6] = new Array(3);
+            this.sfnt_id[6][0] = new tt_sfnt_id_rec(0x00000000, 0x00000000);
+            this.sfnt_id[6][1] = new tt_sfnt_id_rec(0x33c41652, 0x000000e5);
+            this.sfnt_id[6][2] = new tt_sfnt_id_rec(0x26d6c52a, 0x00000f6a);
+
+            this.sfnt_id[7] = new Array(3);
+            this.sfnt_id[7][0] = new tt_sfnt_id_rec(0x00000000, 0x00000000);
+            this.sfnt_id[7][1] = new tt_sfnt_id_rec(0x6db1651d, 0x0000019d);
+            this.sfnt_id[7][2] = new tt_sfnt_id_rec(0x6c6e4b03, 0x00002492);
+
+            this.sfnt_id[8] = new Array(3);
+            this.sfnt_id[8][0] = new tt_sfnt_id_rec(0x00000000, 0x00000000);
+            this.sfnt_id[8][1] = new tt_sfnt_id_rec(0x40c92555, 0x000000e5);
+            this.sfnt_id[8][2] = new tt_sfnt_id_rec(0xde51fad0, 0x0000117c);
+
+            this.sfnt_id[9] = new Array(3);
+            this.sfnt_id[9][0] = new tt_sfnt_id_rec(0x00000000, 0x00000000);
+            this.sfnt_id[9][1] = new tt_sfnt_id_rec(0x85e47664, 0x000000e5);
+            this.sfnt_id[9][2] = new tt_sfnt_id_rec(0xa6c62831, 0x00001caa);
+
+            this.sfnt_id[10] = new Array(3);
+            this.sfnt_id[10][0] = new tt_sfnt_id_rec(0x00000000, 0x00000000);
+            this.sfnt_id[10][1] = new tt_sfnt_id_rec(0x2d891cfd, 0x0000019d);
+            this.sfnt_id[10][2] = new tt_sfnt_id_rec(0xa0604633, 0x00001de8);
+
+            this.sfnt_id[11] = new Array(3);
+            this.sfnt_id[11][0] = new tt_sfnt_id_rec(0x00000000, 0x00000000);
+            this.sfnt_id[11][1] = new tt_sfnt_id_rec(0x40aa774c, 0x000001cb);
+            this.sfnt_id[11][2] = new tt_sfnt_id_rec(0x9b5caa96, 0x00001f9a);
+
+            this.sfnt_id[12] = new Array(3);
+            this.sfnt_id[12][0] = new tt_sfnt_id_rec(0x00000000, 0x00000000);
+            this.sfnt_id[12][1] = new tt_sfnt_id_rec(0x0d3de9cb, 0x00000141);
+            this.sfnt_id[12][2] = new tt_sfnt_id_rec(0xd4127766, 0x00002280);
+        }
+
+        FT_Error = 0;
+        var face = new TT_Face();
+        var internal = new FT_Face_Internal();
+
+        face.driver = this;
+        face.memory = this.memory;
+        face.stream = stream;
+
+        //#ifdef FT_CONFIG_OPTION_INCREMENTAL
+        face.internal = internal;
+        face.internal.incremental_interface = null;
+        //#endif
+
+        var err1 = this.clazz.init_face(stream, face, face_index);
+
+        if (err1 != 0)
+        {
+            face = null;
+            FT_Error = err1;
+            return null;
+        }
+
+        var err2 = find_unicode_charmap(face);
+        if (err2 != 0 && err2 != FT_Common.FT_Err_Invalid_CharMap_Handle)
+        {
+            face = null;
+            FT_Error = err2;
+            return null;
+        }
+
+		FT_Error = 0;
+        return face;
+    }
+}
+
+function create_tt_driver(library)
+{
+    var driver = new TT_Driver();
+    driver.library = library;
+    driver.memory = library.Memory;
+
+    driver.clazz = new TT_Driver_Class();
+    return driver;
+}
\ No newline at end of file
diff --git a/Common/FontsFreeType/Private/FreeType/drivers/ttinterp.js b/Common/FontsFreeType/Private/FreeType/drivers/ttinterp.js
new file mode 100644
index 0000000000000000000000000000000000000000..db16c8e6cff88e1f292f5f270c17c339584e77fc
--- /dev/null
+++ b/Common/FontsFreeType/Private/FreeType/drivers/ttinterp.js
@@ -0,0 +1,6444 @@
+var TT_Round_Off             = 5;
+var TT_Round_To_Half_Grid    = 0;
+var TT_Round_To_Grid         = 1;
+var TT_Round_To_Double_Grid  = 2;
+var TT_Round_Up_To_Grid      = 4;
+var TT_Round_Down_To_Grid    = 3;
+var TT_Round_Super           = 6;
+var TT_Round_Super_45        = 7;
+
+function LibraryHintingParams()
+{
+    this.TT_USE_BYTECODE_INTERPRETER            = false;
+    this.TT_CONFIG_OPTION_SUBPIXEL_HINTING      = false;
+    this.TT_CONFIG_OPTION_UNPATENTED_HINTING    = false;
+
+    this.TT_HINTER_FLAG = (this.TT_USE_BYTECODE_INTERPRETER) ? FT_Common.FT_MODULE_DRIVER_HAS_HINTER : 0;
+    this.TT_CONFIG_OPTION_INTERPRETER_SWITCH    = false;
+}
+
+function TT_CallRec()
+{
+    this.Caller_Range   = 0;
+    this.Caller_IP      = 0;
+    this.Cur_Count      = 0;
+    this.Cur_Restart    = 0;
+    this.Cur_End        = 0;
+}
+
+function SPH_TweakRule()
+{
+    this.family = "";
+    this.ppem = 0;
+    this.style = "";
+    this.glyph = 0;
+}
+
+function SPH_ScaleRule()
+{
+    this.family = "";
+    this.ppem = 0;
+    this.style = "";
+    this.glyph = 0;
+    this.scale = 0;
+}
+
+var MAX_NAME_SIZE       = 32;
+var MAX_CLASS_MEMBERS   = 100;
+
+function Font_Class()
+{
+    this.name = "";
+    this.member = null;
+}
+function create_font_class(name, arr)
+{
+    var fc = new Font_Class();
+    fc.name = name;
+    fc.member = arr;
+    return fc;
+}
+
+function FT_UnitVector()
+{
+    this.x = 0;
+    this.y = 0;
+}
+
+function TT_GraphicsState()
+{
+    this.rp0 = 0;
+    this.rp1 = 0;
+    this.rp2 = 0;
+
+    this.dualVector = new FT_UnitVector();
+    this.projVector = new FT_UnitVector();
+    this.freeVector = new FT_UnitVector();
+
+    // #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
+    this.both_x_axis = false;
+    // #endif
+
+    this.loop = 0;
+    this.minimum_distance = 0;
+    this.round_state = 0;
+
+    this.auto_flip = false;
+    this.control_value_cutin = 0;
+    this.single_width_cutin = 0;
+    this.single_width_value = 0;
+    this.delta_base = 0;
+    this.delta_shift = 0;
+
+    this.instruct_control = 0;
+    /* According to Greg Hitchcock from Microsoft, the `scan_control'     */
+    /* variable as documented in the TrueType specification is a 32-bit   */
+    /* integer; the high-word part holds the SCANTYPE value, the low-word */
+    /* part the SCANCTRL value.  We separate it into two fields.          */
+    this.scan_control = false;
+    this.scan_type = 0;
+
+    this.gep0 = 0;
+    this.gep1 = 0;
+    this.gep2 = 0;
+}
+TT_GraphicsState.prototype =
+{
+    default_tt : function()
+    {
+        this.rp0 = 0;
+        this.rp1 = 0;
+        this.rp2 = 0;
+
+        this.dualVector.x = 0x4000; this.dualVector.y = 0;
+        this.projVector.x = 0x4000; this.projVector.y = 0;
+        this.freeVector.x = 0x4000; this.freeVector.y = 0;
+
+        this.both_x_axis = true;
+
+        this.loop = 1;
+        this.minimum_distance = 64;
+        this.round_state = 1;
+
+        this.auto_flip = true;
+        this.control_value_cutin = 68;
+        this.single_width_cutin = 0;
+        this.single_width_value = 0;
+        this.delta_base = 9;
+        this.delta_shift = 3;
+
+        this.instruct_control = 0;
+        /* According to Greg Hitchcock from Microsoft, the `scan_control'     */
+        /* variable as documented in the TrueType specification is a 32-bit   */
+        /* integer; the high-word part holds the SCANTYPE value, the low-word */
+        /* part the SCANCTRL value.  We separate it into two fields.          */
+        this.scan_control = false;
+        this.scan_type = 0;
+
+        this.gep0 = 1;
+        this.gep1 = 1;
+        this.gep2 = 1;
+    },
+
+    Copy : function(dst)
+    {
+        dst.rp0 = this.rp0;
+        dst.rp1 = this.rp1;
+        dst.rp2 = this.rp2;
+
+        dst.dualVector.x = this.dualVector.x; dst.dualVector.y = this.dualVector.y;
+        dst.projVector.x = this.projVector.x; dst.projVector.y = this.projVector.y;
+        dst.freeVector.x = this.freeVector.x; dst.freeVector.y = this.freeVector.y;
+
+        dst.both_x_axis = this.both_x_axis;
+
+        dst.loop = this.loop;
+        dst.minimum_distance = this.minimum_distance;
+        dst.round_state = this.round_state;
+
+        dst.auto_flip = this.auto_flip;
+        dst.control_value_cutin = this.control_value_cutin;
+        dst.single_width_cutin = this.single_width_cutin;
+        dst.single_width_value = this.single_width_value;
+        dst.delta_base = this.delta_base;
+        dst.delta_shift = this.delta_shift;
+
+        dst.instruct_control = this.instruct_control;
+        /* According to Greg Hitchcock from Microsoft, the `scan_control'     */
+        /* variable as documented in the TrueType specification is a 32-bit   */
+        /* integer; the high-word part holds the SCANTYPE value, the low-word */
+        /* part the SCANCTRL value.  We separate it into two fields.          */
+        dst.scan_control = this.scan_control;
+        dst.scan_type = this.scan_type;
+
+        dst.gep0 = this.gep0;
+        dst.gep1 = this.gep1;
+        dst.gep2 = this.gep2;
+    }
+}
+
+function TT_DefRecord()
+{
+    this.range = 0;             /* in which code range is it located?     */
+    this.start = 0;             /* where does it start?                   */
+    this.end   = 0;             /* where does it end?                     */
+    this.opc   = 0;             /* function #, or instruction code        */
+    this.active = false;        /* is it active?                          */
+    this.inline_delta = false;  /* is function that defines inline delta? */
+}
+
+function TT_CodeRange()
+{
+    this.base = null;
+    this.size = 0;
+}
+function coderange_copy(d, s)
+{
+    d.base = dublicate_pointer(s.base);
+    d.size = s.size;
+}
+
+function TT_ExecContextRec()
+{
+    this.face   = null;
+    this.size   = null;
+    this.memory = null;
+
+    /* instructions state */
+    this.error  = 0;      /* last execution error */
+    this.top    = 0;        /* top of exec. stack   */
+
+    this.stackSize  = 0;  /* size of exec. stack  */
+    this.stack      = null;      /* current exec. stack  */
+
+    this.args       = 0;
+    this.new_top    = 0;    /* new top after exec.  */
+
+    this.zp0 = new TT_GlyphZoneRec();
+    this.zp1 = new TT_GlyphZoneRec();
+    this.zp2 = new TT_GlyphZoneRec();
+    this.pts = new TT_GlyphZoneRec();
+    this.twilight = new TT_GlyphZoneRec();
+
+    this.metrics = new FT_Size_Metrics();
+    this.tt_metrics = new TT_Size_Metrics(); /* size metrics */
+
+    this.GS = new TT_GraphicsState();         /* current graphics state */
+
+    this.curRange = 0;  /* current code range number   */
+    this.code = null;   /* current code range          */
+    this.IP = 0;        /* current instruction pointer */
+    this.codeSize = 0;  /* size of current range       */
+
+    this.opcode = 0;    /* current opcode              */
+    this.length = 0;    /* length of current opcode    */
+
+    this.step_ins = false;  /* true if the interpreter must */
+                            /* increment IP after ins. exec */
+    this.cvtSize = 0;
+    this.cvt = null;
+
+    this.glyphSize = 0; /* glyph instructions buffer size */
+    this.glyphIns = null;  /* glyph instructions buffer */
+
+    this.numFDefs = 0;  /* number of function defs         */
+    this.maxFDefs = 0;  /* maximum number of function defs */
+    this.FDefs = null;     /* table of FDefs entries          */
+
+    this.numIDefs = 0;  /* number of instruction defs */
+    this.maxIDefs = 0;  /* maximum number of ins defs */
+    this.IDefs = null;     /* table of IDefs entries     */
+
+    this.maxFunc = 0;   /* maximum function index     */
+    this.maxIns = 0;    /* maximum instruction index  */
+
+    this.callTop = 0;    /* top of call stack during execution */
+    this.callSize = 0;   /* size of call stack */
+    this.callStack = null;  /* call stack */
+
+    this.maxPoints = 0;    /* capacity of this context's `pts' */
+    this.maxContours = 0;  /* record, expressed in points and  */
+                                     /* contours.                        */
+
+    /* table of valid code ranges */
+    /* useful for the debugger   */
+    this.codeRangeTable = new Array(FT_Common.TT_MAX_CODE_RANGES);
+    for (var i = 0; i < FT_Common.TT_MAX_CODE_RANGES; i++)
+        this.codeRangeTable[i] = new TT_CodeRange();
+    
+    this.storeSize = 0;  /* size of current storage */
+    this.storage = null;    /* storage area            */
+
+    this.period = 0;     /* values used for the */
+    this.phase = 0;      /* `SuperRounding'     */
+    this.threshold = 0;
+
+    //#if 0
+    /* this seems to be unused */
+    //FT_Int             cur_ppem;   /* ppem along the current proj vector */
+    //#endif
+
+    this.instruction_trap = false; /* If `True', the interpreter will */
+                                         /* exit after each instruction     */
+
+    this.default_GS = new TT_GraphicsState();       /* graphics state resulting from   */
+                                                    /* the prep program                */
+    this.is_composite = false;     /* true if the glyph is composite  */
+    this.pedantic_hinting = false; /* true if pedantic interpretation */
+
+    /* latest interpreter additions */
+    this.F_dot_P = 0;           /* dot product of freedom and projection */
+                                /* vectors                               */
+    this.func_round = null;     /* current rounding function             */
+
+    this.func_project = null;   /* current projection function */
+    this.func_dualproj = null;  /* current dual proj. function */
+    this.func_freeProj = null;  /* current freedom proj. func  */
+
+    this.func_move = null;      /* current point move function */
+    this.func_move_orig = null; /* move original position function */
+
+    this.func_read_cvt = null;  /* read a cvt entry              */
+    this.func_write_cvt = null; /* write a cvt entry (in pixels) */
+    this.func_move_cvt = null;  /* incr a cvt entry (in pixels)  */
+
+    this.grayscale = false;      /* are we hinting for grayscale? */
+
+    // #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+    this.func_round_sphn = null;          /* subpixel rounding function */
+
+    this.grayscale_hinting = false;       /* Using grayscale hinting?      */
+    this.subpixel_hinting = false;        /* Using subpixel hinting?       */
+    this.native_hinting = false;          /* Using native hinting?         */
+    this.ignore_x_mode  = false;          /* Standard rendering mode for   */
+                                          /* subpixel hinting.  On if gray */
+                                          /* or subpixel hinting is on )   */
+    this.compatibility_mode = false;      /* Additional exceptions to      */
+                                          /* native TT rules for legacy    */
+                                          /* fonts.  Implies               */
+                                          /* ignore_x_mode.                */
+
+    /* The following 4 aren't fully implemented but here for MS rasterizer */
+    /* compatibility.                                                      */
+    this.compatible_widths = false;     /* compatible widths?        */
+    this.symmetrical_smoothing = false; /* symmetrical_smoothing?    */
+    this.bgr = false;                   /* bgr instead of rgb?       */
+    this.subpixel_positioned = false;   /* subpixel positioned       */
+                                              /* (DirectWrite ClearType)?  */
+
+    this.rasterizer_version = 0;    /* MS rasterizer version */
+
+    this.iup_called = false;            /* IUP called for glyph?  */
+
+    this.sph_tweak_flags = 0;       /* flags to control */
+                                    /* hint tweaks      */
+    // #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+}
+
+function Init_Context(exec, memory)
+{
+    exec.memory   = memory;
+    exec.callSize = 32;
+
+    exec.callStack = new Array(exec.callSize);
+    for (var i = 0; i < exec.callSize; i++)
+        exec.callStack[i] = new TT_CallRec();
+
+    /* all values in the context are set to 0 already, but this is */
+    /* here as a remainder                                         */
+    exec.maxPoints   = 0;
+    exec.maxContours = 0;
+
+    exec.stackSize = 0;
+    exec.glyphSize = 0;
+
+    exec.stack     = null;
+    exec.glyphIns  = null;
+
+    exec.face = null;
+    exec.size = null;
+
+    return 0;
+}
+
+function TT_New_Context(driver)
+{
+    if (driver.context == null)
+    {
+        driver.context = new TT_ExecContextRec();
+
+        /* initialize it; in case of error this deallocates `exec' too */
+        var error = Init_Context(driver.context, driver.memory);
+        if (error != 0)
+            driver.context = null;
+    }
+    return driver.context;
+}
+
+function TT_Done_Context(exec)
+{
+    /* points zone */
+    exec.maxPoints   = 0;
+    exec.maxContours = 0;
+
+    /* free stack */
+    exec.stack      = null;
+    exec.stackSize  = 0;
+
+    /* free call stack */
+    exec.callStack  = null;
+    exec.callSize   = 0;
+    exec.callTop    = 0;
+
+    /* free glyph code range */
+    exec.glyphIns   = null;
+    exec.glyphSize  = 0;
+
+    exec.size       = null;
+    exec.face       = null;
+
+    return 0;
+}
+
+function TT_Load_Context(exec, face, size)
+{
+    exec.face = face;
+    var maxp = face.max_profile;
+    exec.size = size;
+
+    if (size != null)
+    {
+        exec.numFDefs   = size.num_function_defs;
+        exec.maxFDefs   = size.max_function_defs;
+        exec.numIDefs   = size.num_instruction_defs;
+        exec.maxIDefs   = size.max_instruction_defs;
+        exec.FDefs      = size.function_defs;
+        exec.IDefs      = size.instruction_defs;
+        exec.tt_metrics.Copy(size.ttmetrics);
+        exec.metrics.Copy(size.metrics);
+
+        exec.maxFunc    = size.max_func;
+        exec.maxIns     = size.max_ins;
+
+        for (var i = 0; i < FT_Common.TT_MAX_CODE_RANGES; i++)
+            coderange_copy(exec.codeRangeTable[i], size.codeRangeTable[i]);
+
+        /* set graphics state */
+        size.GS.Copy(exec.GS);
+
+        exec.cvtSize = size.cvt_size;
+        exec.cvt     = size.cvt;
+
+        exec.storeSize = size.storage_size;
+        exec.storage   = size.storage;
+
+        exec.twilight.Copy(size.twilight);
+
+        /* In case of multi-threading it can happen that the old size object */
+        /* no longer exists, thus we must clear all glyph zone references.   */
+        exec.zp0.Clear();
+        exec.zp1.Clear();
+        exec.zp2.Clear();
+    }
+
+    /* XXX: We reserve a little more elements on the stack to deal safely */
+    /*      with broken fonts like arialbs, courbs, timesbs, etc.         */
+    var ret = Update_MaxLONG(exec.memory, exec.stackSize, exec.stack, maxp.maxStackElements + 32);
+    if (null != ret)
+    {
+        exec.stackSize = ret.size;
+        exec.stack = ret.block;
+
+        if (ret.err != 0)
+            return ret.err;
+    }
+    
+    ret = Update_MaxBYTE(exec.memory, exec.glyphSize, exec.glyphIns, maxp.maxSizeOfInstructions);
+    if (ret != null)
+    {
+        exec.glyphSize = ret.size;
+        exec.glyphIns = ret.block;
+
+        if (ret.err != 0)
+            return ret.err;
+    }
+
+    exec.pts.n_points   = 0;
+    exec.pts.n_contours = 0;
+
+    exec.zp1.Copy(exec.pts);
+    exec.zp2.Copy(exec.pts);
+    exec.zp0.Copy(exec.pts);
+
+    exec.instruction_trap = false;
+
+    return 0;
+}
+
+function Update_MaxBYTE(memory, size, buff, new_max)
+{
+    if (size >= new_max)
+        return null;
+
+    return FT_Common.realloc(memory, buff, size, new_max);
+}
+function Update_MaxLONG(memory, size, buff, new_max)
+{
+    if (size >= new_max)
+        return null;
+
+    return FT_Common.realloc_long(memory, buff, size, new_max);
+}
+
+function tt_size_ready_bytecode(size, pedantic)
+{
+    var error = 0;
+    if (!size.bytecode_ready)
+    {
+        error = tt_size_init_bytecode(size, pedantic);
+        if (error != 0)
+            return error;
+    }
+
+    /* rescale CVT when needed */
+    if (!size.cvt_ready)
+    {
+        var face = size.face;
+
+        /* Scale the cvt values to the new ppem.          */
+        /* We use by default the y ppem to scale the CVT. */
+        for (var i = 0; i < size.cvt_size; i++)
+            size.cvt[i] = FT_MulFix(face.cvt[i], size.ttmetrics.scale);
+
+        /* all twilight points are originally zero */
+        for (var i = 0; i < size.twilight.n_points; i++ )
+        {
+            size.twilight.org[size.twilight._offset_org + i].x = 0;
+            size.twilight.org[size.twilight._offset_org + i].y = 0;
+            size.twilight.cur[size.twilight._offset_cur + i].x = 0;
+            size.twilight.cur[size.twilight._offset_cur + i].y = 0;
+        }
+
+        /* clear storage area */
+        for (var i = 0; i < size.storage_size; i++)
+            size.storage[i] = 0;
+
+        size.GS.default_tt();
+
+        error = tt_size_run_prep(size, pedantic);
+        if (error != 0)
+            size.cvt_ready = 1;
+    }
+    return error;
+}
+
+function tt_size_init_bytecode(size, pedantic)
+{
+    var maxp = size.face.max_profile;
+
+    size.bytecode_ready = 1;
+    size.cvt_ready      = 0;
+
+    size.max_function_defs    = maxp.maxFunctionDefs;
+    size.max_instruction_defs = maxp.maxInstructionDefs;
+
+    size.num_function_defs    = 0;
+    size.num_instruction_defs = 0;
+
+    size.max_func = 0;
+    size.max_ins  = 0;
+
+    size.cvt_size     = size.face.cvt_size;
+    size.storage_size = maxp.maxStorage;
+
+    /* Set default metrics */
+    var metrics = size.ttmetrics;
+    metrics.rotated   = false;
+    metrics.stretched = false;
+
+      /* set default compensation (all 0) */
+    for (var i = 0; i < 4; i++)
+        metrics.compensations[i] = 0;
+
+    /* allocate function defs, instruction defs, cvt, and storage area */
+    size.function_defs = new Array(size.max_function_defs);
+    for (var i = 0; i < size.max_function_defs; i++)
+        size.function_defs[i] = new TT_DefRecord();
+
+    size.instruction_defs = new Array(size.max_instruction_defs);
+    for (var i = 0; i < size.max_instruction_defs; i++)
+        size.instruction_defs[i] = new TT_DefRecord();
+
+    size.cvt = new CreateIntArray(size.cvt_size);
+    size.storage = new CreateIntArray(size.storage_size);
+
+    /* reserve twilight zone */
+    var n_twilight = maxp.maxTwilightPoints;
+
+    /* there are 4 phantom points (do we need this?) */
+    n_twilight += 4;
+
+    var error = tt_glyphzone_new(size.face.memory, n_twilight, 0, size.twilight);
+    if (error != 0)
+    {
+        tt_size_done_bytecode(size);
+        return error;
+    }
+
+    size.twilight.n_points = n_twilight;
+
+    size.GS.default_tt();
+    size.face.interpreter = TT_RunIns;
+
+    /* Fine, now run the font program! */
+    error = tt_size_run_fpgm(size, pedantic);
+    if (error != 0)
+        tt_size_done_bytecode(size);
+
+    return error;
+}
+
+function tt_size_run_fpgm(size, pedantic)
+{
+    var face = size.face;
+    var exec = null;
+
+    /* debugging instances have their own context */
+    if (size.debug)
+        exec = size.context;
+    else
+        exec = face.driver.context;
+
+    if (exec == null)
+        return FT_Common.FT_Err_Could_Not_Find_Context;
+
+    TT_Load_Context(exec, face, size);
+
+    exec.callTop = 0;
+    exec.top     = 0;
+
+    exec.period    = 64;
+    exec.phase     = 0;
+    exec.threshold = 0;
+
+    exec.instruction_trap = false;
+    exec.F_dot_P          = 0x4000;
+
+    exec.pedantic_hinting = pedantic;
+
+    var metrics = exec.metrics;
+    var tt_metrics = exec.tt_metrics;
+
+    metrics.x_ppem   = 0;
+    metrics.y_ppem   = 0;
+    metrics.x_scale  = 0;
+    metrics.y_scale  = 0;
+
+    tt_metrics.ppem  = 0;
+    tt_metrics.scale = 0;
+    tt_metrics.ratio = 0x10000;
+
+    /* allow font program execution */
+    TT_Set_CodeRange(exec, FT_Common.tt_coderange_font, face.font_program, face.font_program_size);
+
+    /* disable CVT and glyph programs coderange */
+    TT_Clear_CodeRange(exec, FT_Common.tt_coderange_cvt);
+    TT_Clear_CodeRange(exec, FT_Common.tt_coderange_glyph);
+
+    var error = 0;
+    if (face.font_program_size > 0)
+    {
+        error = TT_Goto_CodeRange(exec, FT_Common.tt_coderange_font, 0);
+        if (error == 0)
+            error = face.interpreter(exec);
+    }
+    else
+        error = 0;
+
+    if (error == 0)
+        TT_Save_Context(exec, size);
+
+    return error;
+}
+
+function TT_Clear_CodeRange(exec, range)
+{
+    exec.codeRangeTable[range - 1].base = null;
+    exec.codeRangeTable[range - 1].size = 0;
+
+    return 0;
+}
+
+function TT_Save_Context(exec, size)
+{
+    /* XXX: Will probably disappear soon with all the code range */
+    /*      management, which is now rather obsolete.            */
+    /*                                                           */
+    size.num_function_defs    = exec.numFDefs;
+    size.num_instruction_defs = exec.numIDefs;
+
+    size.max_func = exec.maxFunc;
+    size.max_ins  = exec.maxIns;
+
+    for (var i = 0; i < FT_Common.TT_MAX_CODE_RANGES; i++)
+    {
+        size.codeRangeTable[i].base = dublicate_pointer(exec.codeRangeTable[i].base);
+        size.codeRangeTable[i].size = exec.codeRangeTable[i].size;
+    }
+
+    return 0;
+}
+
+function tt_size_done_bytecode(size)
+{
+    if (size.debug)
+    {
+        /* the debug context must be deleted by the debugger itself */
+        size.context = null;
+        size.debug   = false;
+    }
+
+    size.cvt = null;
+    size.cvt_size = 0;
+
+    /* free storage area */
+    size.storage = null;
+    size.storage_size = 0;
+
+    /* twilight zone */
+    tt_glyphzone_done(size.twilight);
+
+    size.function_defs = null;
+    size.instruction_defs = null;
+
+    size.num_function_defs    = 0;
+    size.max_function_defs    = 0;
+    size.num_instruction_defs = 0;
+    size.max_instruction_defs = 0;
+
+    size.max_func = 0;
+    size.max_ins  = 0;
+
+    size.bytecode_ready = false;
+    size.cvt_ready      = false;
+}
+
+function tt_glyphzone_done(zone)
+{
+    if (zone.memory != null)
+    {
+        zone.contours = null;
+        zone.tags = null;
+        zone.cur = null;
+        zone.org = null;
+        zone.orus = null;
+
+        zone.max_points = zone.n_points   = 0;
+        zone.max_contours = zone.n_contours = 0;
+        zone.memory = null;
+    }
+}
+
+function tt_glyphzone_new(memory, maxPoints, maxContours, zone)
+{
+    zone.Clear();
+    zone.memory = memory;
+
+    zone.org = new Array(maxPoints);
+    FT_CreateVectorArray(zone.org, 0, maxPoints);
+
+    zone.cur = new Array(maxPoints);
+    FT_CreateVectorArray(zone.cur, 0, maxPoints);
+
+    zone.orus = new Array(maxPoints);
+    FT_CreateVectorArray(zone.orus, 0, maxPoints);
+
+    zone.tags = CreateIntArray(maxPoints);
+    zone.contours = CreateIntArray(maxContours);
+
+    zone.max_points   = maxPoints;
+    zone.max_contours = maxContours;
+    return 0;
+}
+
+function TT_Set_CodeRange(exec, range, base, length)
+{
+    exec.codeRangeTable[range - 1].base = dublicate_pointer(base);
+    exec.codeRangeTable[range - 1].size = length;
+
+    return 0;
+}
+
+function TT_Goto_CodeRange(exec, range, IP)
+{
+    var coderange = exec.codeRangeTable[range - 1];
+
+    /* NOTE: Because the last instruction of a program may be a CALL */
+    /*       which will return to the first byte *after* the code    */
+    /*       range, we test for IP <= Size instead of IP < Size.     */
+    /*                                                               */
+    exec.code     = dublicate_pointer(coderange.base);
+    exec.codeSize = coderange.size;
+    exec.IP       = IP;
+    exec.curRange = range;
+
+    return 0;
+}
+
+function TT_Run_Context(exec, debug)
+{
+    var error = TT_Goto_CodeRange(exec, FT_Common.tt_coderange_glyph, 0);
+    if (error != 0)
+        return error;
+
+    exec.zp0.Copy(exec.pts);
+    exec.zp1.Copy(exec.pts);
+    exec.zp2.Copy(exec.pts);
+
+    exec.GS.gep0 = 1;
+    exec.GS.gep1 = 1;
+    exec.GS.gep2 = 1;
+
+    exec.GS.projVector.x = 0x4000;
+    exec.GS.projVector.y = 0x0000;
+
+    exec.GS.freeVector.x = exec.GS.projVector.x;
+    exec.GS.freeVector.y = exec.GS.projVector.y;
+    exec.GS.dualVector.x = exec.GS.projVector.x;
+    exec.GS.dualVector.y = exec.GS.projVector.y;
+
+    if (exec.face.driver.library.tt_hint_props.TT_CONFIG_OPTION_SUBPIXEL_HINTING)//#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
+    {
+        exec.GS.both_x_axis = true;
+    }//#endif
+
+    exec.GS.round_state = 1;
+    exec.GS.loop        = 1;
+
+    /* some glyphs leave something on the stack. so we clean it */
+    /* before a new execution.                                  */
+    exec.top     = 0;
+    exec.callTop = 0;
+
+    return exec.face.interpreter(exec);
+}
+
+//--------------------------------------------------------------//
+
+var opcode_length =
+[1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
+1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
+1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
+1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
+
+-1,-2, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
+1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
+1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
+1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
+
+1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
+1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
+1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
+2, 3, 4, 5,  6, 7, 8, 9,  3, 5, 7, 9, 11,13,15,17,
+
+1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
+1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
+1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
+1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1];
+
+function Pop_Push_PACK(x, y)
+{
+    return ((x << 4) | y);
+}
+var Pop_Push_Count =
+[
+    /* opcodes are gathered in groups of 16 */
+    /* please keep the spaces as they are   */
+
+    /*  SVTCA  y  */  Pop_Push_PACK( 0, 0 ),
+    /*  SVTCA  x  */  Pop_Push_PACK( 0, 0 ),
+    /*  SPvTCA y  */  Pop_Push_PACK( 0, 0 ),
+    /*  SPvTCA x  */  Pop_Push_PACK( 0, 0 ),
+    /*  SFvTCA y  */  Pop_Push_PACK( 0, 0 ),
+    /*  SFvTCA x  */  Pop_Push_PACK( 0, 0 ),
+    /*  SPvTL //  */  Pop_Push_PACK( 2, 0 ),
+    /*  SPvTL +   */  Pop_Push_PACK( 2, 0 ),
+    /*  SFvTL //  */  Pop_Push_PACK( 2, 0 ),
+    /*  SFvTL +   */  Pop_Push_PACK( 2, 0 ),
+    /*  SPvFS     */  Pop_Push_PACK( 2, 0 ),
+    /*  SFvFS     */  Pop_Push_PACK( 2, 0 ),
+    /*  GPV       */  Pop_Push_PACK( 0, 2 ),
+    /*  GFV       */  Pop_Push_PACK( 0, 2 ),
+    /*  SFvTPv    */  Pop_Push_PACK( 0, 0 ),
+    /*  ISECT     */  Pop_Push_PACK( 5, 0 ),
+
+    /*  SRP0      */  Pop_Push_PACK( 1, 0 ),
+    /*  SRP1      */  Pop_Push_PACK( 1, 0 ),
+    /*  SRP2      */  Pop_Push_PACK( 1, 0 ),
+    /*  SZP0      */  Pop_Push_PACK( 1, 0 ),
+    /*  SZP1      */  Pop_Push_PACK( 1, 0 ),
+    /*  SZP2      */  Pop_Push_PACK( 1, 0 ),
+    /*  SZPS      */  Pop_Push_PACK( 1, 0 ),
+    /*  SLOOP     */  Pop_Push_PACK( 1, 0 ),
+    /*  RTG       */  Pop_Push_PACK( 0, 0 ),
+    /*  RTHG      */  Pop_Push_PACK( 0, 0 ),
+    /*  SMD       */  Pop_Push_PACK( 1, 0 ),
+    /*  ELSE      */  Pop_Push_PACK( 0, 0 ),
+    /*  JMPR      */  Pop_Push_PACK( 1, 0 ),
+    /*  SCvTCi    */  Pop_Push_PACK( 1, 0 ),
+    /*  SSwCi     */  Pop_Push_PACK( 1, 0 ),
+    /*  SSW       */  Pop_Push_PACK( 1, 0 ),
+
+    /*  DUP       */  Pop_Push_PACK( 1, 2 ),
+    /*  POP       */  Pop_Push_PACK( 1, 0 ),
+    /*  CLEAR     */  Pop_Push_PACK( 0, 0 ),
+    /*  SWAP      */  Pop_Push_PACK( 2, 2 ),
+    /*  DEPTH     */  Pop_Push_PACK( 0, 1 ),
+    /*  CINDEX    */  Pop_Push_PACK( 1, 1 ),
+    /*  MINDEX    */  Pop_Push_PACK( 1, 0 ),
+    /*  AlignPTS  */  Pop_Push_PACK( 2, 0 ),
+    /*  INS_$28   */  Pop_Push_PACK( 0, 0 ),
+    /*  UTP       */  Pop_Push_PACK( 1, 0 ),
+    /*  LOOPCALL  */  Pop_Push_PACK( 2, 0 ),
+    /*  CALL      */  Pop_Push_PACK( 1, 0 ),
+    /*  FDEF      */  Pop_Push_PACK( 1, 0 ),
+    /*  ENDF      */  Pop_Push_PACK( 0, 0 ),
+    /*  MDAP[0]   */  Pop_Push_PACK( 1, 0 ),
+    /*  MDAP[1]   */  Pop_Push_PACK( 1, 0 ),
+
+    /*  IUP[0]    */  Pop_Push_PACK( 0, 0 ),
+    /*  IUP[1]    */  Pop_Push_PACK( 0, 0 ),
+    /*  SHP[0]    */  Pop_Push_PACK( 0, 0 ),
+    /*  SHP[1]    */  Pop_Push_PACK( 0, 0 ),
+    /*  SHC[0]    */  Pop_Push_PACK( 1, 0 ),
+    /*  SHC[1]    */  Pop_Push_PACK( 1, 0 ),
+    /*  SHZ[0]    */  Pop_Push_PACK( 1, 0 ),
+    /*  SHZ[1]    */  Pop_Push_PACK( 1, 0 ),
+    /*  SHPIX     */  Pop_Push_PACK( 1, 0 ),
+    /*  IP        */  Pop_Push_PACK( 0, 0 ),
+    /*  MSIRP[0]  */  Pop_Push_PACK( 2, 0 ),
+    /*  MSIRP[1]  */  Pop_Push_PACK( 2, 0 ),
+    /*  AlignRP   */  Pop_Push_PACK( 0, 0 ),
+    /*  RTDG      */  Pop_Push_PACK( 0, 0 ),
+    /*  MIAP[0]   */  Pop_Push_PACK( 2, 0 ),
+    /*  MIAP[1]   */  Pop_Push_PACK( 2, 0 ),
+
+    /*  NPushB    */  Pop_Push_PACK( 0, 0 ),
+    /*  NPushW    */  Pop_Push_PACK( 0, 0 ),
+    /*  WS        */  Pop_Push_PACK( 2, 0 ),
+    /*  RS        */  Pop_Push_PACK( 1, 1 ),
+    /*  WCvtP     */  Pop_Push_PACK( 2, 0 ),
+    /*  RCvt      */  Pop_Push_PACK( 1, 1 ),
+    /*  GC[0]     */  Pop_Push_PACK( 1, 1 ),
+    /*  GC[1]     */  Pop_Push_PACK( 1, 1 ),
+    /*  SCFS      */  Pop_Push_PACK( 2, 0 ),
+    /*  MD[0]     */  Pop_Push_PACK( 2, 1 ),
+    /*  MD[1]     */  Pop_Push_PACK( 2, 1 ),
+    /*  MPPEM     */  Pop_Push_PACK( 0, 1 ),
+    /*  MPS       */  Pop_Push_PACK( 0, 1 ),
+    /*  FlipON    */  Pop_Push_PACK( 0, 0 ),
+    /*  FlipOFF   */  Pop_Push_PACK( 0, 0 ),
+    /*  DEBUG     */  Pop_Push_PACK( 1, 0 ),
+
+    /*  LT        */  Pop_Push_PACK( 2, 1 ),
+    /*  LTEQ      */  Pop_Push_PACK( 2, 1 ),
+    /*  GT        */  Pop_Push_PACK( 2, 1 ),
+    /*  GTEQ      */  Pop_Push_PACK( 2, 1 ),
+    /*  EQ        */  Pop_Push_PACK( 2, 1 ),
+    /*  NEQ       */  Pop_Push_PACK( 2, 1 ),
+    /*  ODD       */  Pop_Push_PACK( 1, 1 ),
+    /*  EVEN      */  Pop_Push_PACK( 1, 1 ),
+    /*  IF        */  Pop_Push_PACK( 1, 0 ),
+    /*  EIF       */  Pop_Push_PACK( 0, 0 ),
+    /*  AND       */  Pop_Push_PACK( 2, 1 ),
+    /*  OR        */  Pop_Push_PACK( 2, 1 ),
+    /*  NOT       */  Pop_Push_PACK( 1, 1 ),
+    /*  DeltaP1   */  Pop_Push_PACK( 1, 0 ),
+    /*  SDB       */  Pop_Push_PACK( 1, 0 ),
+    /*  SDS       */  Pop_Push_PACK( 1, 0 ),
+
+    /*  ADD       */  Pop_Push_PACK( 2, 1 ),
+    /*  SUB       */  Pop_Push_PACK( 2, 1 ),
+    /*  DIV       */  Pop_Push_PACK( 2, 1 ),
+    /*  MUL       */  Pop_Push_PACK( 2, 1 ),
+    /*  ABS       */  Pop_Push_PACK( 1, 1 ),
+    /*  NEG       */  Pop_Push_PACK( 1, 1 ),
+    /*  FLOOR     */  Pop_Push_PACK( 1, 1 ),
+    /*  CEILING   */  Pop_Push_PACK( 1, 1 ),
+    /*  ROUND[0]  */  Pop_Push_PACK( 1, 1 ),
+    /*  ROUND[1]  */  Pop_Push_PACK( 1, 1 ),
+    /*  ROUND[2]  */  Pop_Push_PACK( 1, 1 ),
+    /*  ROUND[3]  */  Pop_Push_PACK( 1, 1 ),
+    /*  NROUND[0] */  Pop_Push_PACK( 1, 1 ),
+    /*  NROUND[1] */  Pop_Push_PACK( 1, 1 ),
+    /*  NROUND[2] */  Pop_Push_PACK( 1, 1 ),
+    /*  NROUND[3] */  Pop_Push_PACK( 1, 1 ),
+
+    /*  WCvtF     */  Pop_Push_PACK( 2, 0 ),
+    /*  DeltaP2   */  Pop_Push_PACK( 1, 0 ),
+    /*  DeltaP3   */  Pop_Push_PACK( 1, 0 ),
+    /*  DeltaCn[0] */ Pop_Push_PACK( 1, 0 ),
+    /*  DeltaCn[1] */ Pop_Push_PACK( 1, 0 ),
+    /*  DeltaCn[2] */ Pop_Push_PACK( 1, 0 ),
+    /*  SROUND    */  Pop_Push_PACK( 1, 0 ),
+    /*  S45Round  */  Pop_Push_PACK( 1, 0 ),
+    /*  JROT      */  Pop_Push_PACK( 2, 0 ),
+    /*  JROF      */  Pop_Push_PACK( 2, 0 ),
+    /*  ROFF      */  Pop_Push_PACK( 0, 0 ),
+    /*  INS_$7B   */  Pop_Push_PACK( 0, 0 ),
+    /*  RUTG      */  Pop_Push_PACK( 0, 0 ),
+    /*  RDTG      */  Pop_Push_PACK( 0, 0 ),
+    /*  SANGW     */  Pop_Push_PACK( 1, 0 ),
+    /*  AA        */  Pop_Push_PACK( 1, 0 ),
+
+    /*  FlipPT    */  Pop_Push_PACK( 0, 0 ),
+    /*  FlipRgON  */  Pop_Push_PACK( 2, 0 ),
+    /*  FlipRgOFF */  Pop_Push_PACK( 2, 0 ),
+    /*  INS_$83   */  Pop_Push_PACK( 0, 0 ),
+    /*  INS_$84   */  Pop_Push_PACK( 0, 0 ),
+    /*  ScanCTRL  */  Pop_Push_PACK( 1, 0 ),
+    /*  SDPVTL[0] */  Pop_Push_PACK( 2, 0 ),
+    /*  SDPVTL[1] */  Pop_Push_PACK( 2, 0 ),
+    /*  GetINFO   */  Pop_Push_PACK( 1, 1 ),
+    /*  IDEF      */  Pop_Push_PACK( 1, 0 ),
+    /*  ROLL      */  Pop_Push_PACK( 3, 3 ),
+    /*  MAX       */  Pop_Push_PACK( 2, 1 ),
+    /*  MIN       */  Pop_Push_PACK( 2, 1 ),
+    /*  ScanTYPE  */  Pop_Push_PACK( 1, 0 ),
+    /*  InstCTRL  */  Pop_Push_PACK( 2, 0 ),
+    /*  INS_$8F   */  Pop_Push_PACK( 0, 0 ),
+
+    /*  INS_$90  */   Pop_Push_PACK( 0, 0 ),
+    /*  INS_$91  */   Pop_Push_PACK( 0, 0 ),
+    /*  INS_$92  */   Pop_Push_PACK( 0, 0 ),
+    /*  INS_$93  */   Pop_Push_PACK( 0, 0 ),
+    /*  INS_$94  */   Pop_Push_PACK( 0, 0 ),
+    /*  INS_$95  */   Pop_Push_PACK( 0, 0 ),
+    /*  INS_$96  */   Pop_Push_PACK( 0, 0 ),
+    /*  INS_$97  */   Pop_Push_PACK( 0, 0 ),
+    /*  INS_$98  */   Pop_Push_PACK( 0, 0 ),
+    /*  INS_$99  */   Pop_Push_PACK( 0, 0 ),
+    /*  INS_$9A  */   Pop_Push_PACK( 0, 0 ),
+    /*  INS_$9B  */   Pop_Push_PACK( 0, 0 ),
+    /*  INS_$9C  */   Pop_Push_PACK( 0, 0 ),
+    /*  INS_$9D  */   Pop_Push_PACK( 0, 0 ),
+    /*  INS_$9E  */   Pop_Push_PACK( 0, 0 ),
+    /*  INS_$9F  */   Pop_Push_PACK( 0, 0 ),
+
+    /*  INS_$A0  */   Pop_Push_PACK( 0, 0 ),
+    /*  INS_$A1  */   Pop_Push_PACK( 0, 0 ),
+    /*  INS_$A2  */   Pop_Push_PACK( 0, 0 ),
+    /*  INS_$A3  */   Pop_Push_PACK( 0, 0 ),
+    /*  INS_$A4  */   Pop_Push_PACK( 0, 0 ),
+    /*  INS_$A5  */   Pop_Push_PACK( 0, 0 ),
+    /*  INS_$A6  */   Pop_Push_PACK( 0, 0 ),
+    /*  INS_$A7  */   Pop_Push_PACK( 0, 0 ),
+    /*  INS_$A8  */   Pop_Push_PACK( 0, 0 ),
+    /*  INS_$A9  */   Pop_Push_PACK( 0, 0 ),
+    /*  INS_$AA  */   Pop_Push_PACK( 0, 0 ),
+    /*  INS_$AB  */   Pop_Push_PACK( 0, 0 ),
+    /*  INS_$AC  */   Pop_Push_PACK( 0, 0 ),
+    /*  INS_$AD  */   Pop_Push_PACK( 0, 0 ),
+    /*  INS_$AE  */   Pop_Push_PACK( 0, 0 ),
+    /*  INS_$AF  */   Pop_Push_PACK( 0, 0 ),
+
+    /*  PushB[0]  */  Pop_Push_PACK( 0, 1 ),
+    /*  PushB[1]  */  Pop_Push_PACK( 0, 2 ),
+    /*  PushB[2]  */  Pop_Push_PACK( 0, 3 ),
+    /*  PushB[3]  */  Pop_Push_PACK( 0, 4 ),
+    /*  PushB[4]  */  Pop_Push_PACK( 0, 5 ),
+    /*  PushB[5]  */  Pop_Push_PACK( 0, 6 ),
+    /*  PushB[6]  */  Pop_Push_PACK( 0, 7 ),
+    /*  PushB[7]  */  Pop_Push_PACK( 0, 8 ),
+    /*  PushW[0]  */  Pop_Push_PACK( 0, 1 ),
+    /*  PushW[1]  */  Pop_Push_PACK( 0, 2 ),
+    /*  PushW[2]  */  Pop_Push_PACK( 0, 3 ),
+    /*  PushW[3]  */  Pop_Push_PACK( 0, 4 ),
+    /*  PushW[4]  */  Pop_Push_PACK( 0, 5 ),
+    /*  PushW[5]  */  Pop_Push_PACK( 0, 6 ),
+    /*  PushW[6]  */  Pop_Push_PACK( 0, 7 ),
+    /*  PushW[7]  */  Pop_Push_PACK( 0, 8 ),
+
+    /*  MDRP[00]  */  Pop_Push_PACK( 1, 0 ),
+    /*  MDRP[01]  */  Pop_Push_PACK( 1, 0 ),
+    /*  MDRP[02]  */  Pop_Push_PACK( 1, 0 ),
+    /*  MDRP[03]  */  Pop_Push_PACK( 1, 0 ),
+    /*  MDRP[04]  */  Pop_Push_PACK( 1, 0 ),
+    /*  MDRP[05]  */  Pop_Push_PACK( 1, 0 ),
+    /*  MDRP[06]  */  Pop_Push_PACK( 1, 0 ),
+    /*  MDRP[07]  */  Pop_Push_PACK( 1, 0 ),
+    /*  MDRP[08]  */  Pop_Push_PACK( 1, 0 ),
+    /*  MDRP[09]  */  Pop_Push_PACK( 1, 0 ),
+    /*  MDRP[10]  */  Pop_Push_PACK( 1, 0 ),
+    /*  MDRP[11]  */  Pop_Push_PACK( 1, 0 ),
+    /*  MDRP[12]  */  Pop_Push_PACK( 1, 0 ),
+    /*  MDRP[13]  */  Pop_Push_PACK( 1, 0 ),
+    /*  MDRP[14]  */  Pop_Push_PACK( 1, 0 ),
+    /*  MDRP[15]  */  Pop_Push_PACK( 1, 0 ),
+
+    /*  MDRP[16]  */  Pop_Push_PACK( 1, 0 ),
+    /*  MDRP[17]  */  Pop_Push_PACK( 1, 0 ),
+    /*  MDRP[18]  */  Pop_Push_PACK( 1, 0 ),
+    /*  MDRP[19]  */  Pop_Push_PACK( 1, 0 ),
+    /*  MDRP[20]  */  Pop_Push_PACK( 1, 0 ),
+    /*  MDRP[21]  */  Pop_Push_PACK( 1, 0 ),
+    /*  MDRP[22]  */  Pop_Push_PACK( 1, 0 ),
+    /*  MDRP[23]  */  Pop_Push_PACK( 1, 0 ),
+    /*  MDRP[24]  */  Pop_Push_PACK( 1, 0 ),
+    /*  MDRP[25]  */  Pop_Push_PACK( 1, 0 ),
+    /*  MDRP[26]  */  Pop_Push_PACK( 1, 0 ),
+    /*  MDRP[27]  */  Pop_Push_PACK( 1, 0 ),
+    /*  MDRP[28]  */  Pop_Push_PACK( 1, 0 ),
+    /*  MDRP[29]  */  Pop_Push_PACK( 1, 0 ),
+    /*  MDRP[30]  */  Pop_Push_PACK( 1, 0 ),
+    /*  MDRP[31]  */  Pop_Push_PACK( 1, 0 ),
+
+    /*  MIRP[00]  */  Pop_Push_PACK( 2, 0 ),
+    /*  MIRP[01]  */  Pop_Push_PACK( 2, 0 ),
+    /*  MIRP[02]  */  Pop_Push_PACK( 2, 0 ),
+    /*  MIRP[03]  */  Pop_Push_PACK( 2, 0 ),
+    /*  MIRP[04]  */  Pop_Push_PACK( 2, 0 ),
+    /*  MIRP[05]  */  Pop_Push_PACK( 2, 0 ),
+    /*  MIRP[06]  */  Pop_Push_PACK( 2, 0 ),
+    /*  MIRP[07]  */  Pop_Push_PACK( 2, 0 ),
+    /*  MIRP[08]  */  Pop_Push_PACK( 2, 0 ),
+    /*  MIRP[09]  */  Pop_Push_PACK( 2, 0 ),
+    /*  MIRP[10]  */  Pop_Push_PACK( 2, 0 ),
+    /*  MIRP[11]  */  Pop_Push_PACK( 2, 0 ),
+    /*  MIRP[12]  */  Pop_Push_PACK( 2, 0 ),
+    /*  MIRP[13]  */  Pop_Push_PACK( 2, 0 ),
+    /*  MIRP[14]  */  Pop_Push_PACK( 2, 0 ),
+    /*  MIRP[15]  */  Pop_Push_PACK( 2, 0 ),
+
+    /*  MIRP[16]  */  Pop_Push_PACK( 2, 0 ),
+    /*  MIRP[17]  */  Pop_Push_PACK( 2, 0 ),
+    /*  MIRP[18]  */  Pop_Push_PACK( 2, 0 ),
+    /*  MIRP[19]  */  Pop_Push_PACK( 2, 0 ),
+    /*  MIRP[20]  */  Pop_Push_PACK( 2, 0 ),
+    /*  MIRP[21]  */  Pop_Push_PACK( 2, 0 ),
+    /*  MIRP[22]  */  Pop_Push_PACK( 2, 0 ),
+    /*  MIRP[23]  */  Pop_Push_PACK( 2, 0 ),
+    /*  MIRP[24]  */  Pop_Push_PACK( 2, 0 ),
+    /*  MIRP[25]  */  Pop_Push_PACK( 2, 0 ),
+    /*  MIRP[26]  */  Pop_Push_PACK( 2, 0 ),
+    /*  MIRP[27]  */  Pop_Push_PACK( 2, 0 ),
+    /*  MIRP[28]  */  Pop_Push_PACK( 2, 0 ),
+    /*  MIRP[29]  */  Pop_Push_PACK( 2, 0 ),
+    /*  MIRP[30]  */  Pop_Push_PACK( 2, 0 ),
+    /*  MIRP[31]  */  Pop_Push_PACK( 2, 0 )
+];
+
+function GUESS_VECTOR(exc, v)
+{
+    // TODO: unpatented
+}
+
+function Ins_SxVTL(exc, aIdx1, aIdx2, aOpc, Vec)
+{
+    if ((aIdx1 >= exc.zp2.n_points) || (aIdx2 >= exc.zp1.n_points))
+    {
+        if (exc.pedantic_hinting)
+            exc.error = FT_Err_Invalid_Reference;
+        return 1;
+    }
+
+    var p1 = exc.zp1.cur[exc.zp1._offset_cur + aIdx2];
+    var p2 = exc.zp2.cur[exc.zp2._offset_cur + aIdx1];
+
+    var A = p1.x - p2.x;
+    var B = p1.y - p2.y;
+
+    /* If p1 == p2, SPVTL and SFVTL behave the same as */
+    /* SPVTCA[X] and SFVTCA[X], respectively.          */
+    /*                                                 */
+    /* Confirmed by Greg Hitchcock.                    */
+
+    if (A == 0 && B == 0)
+    {
+        A = 0x4000;
+        aOpc = 0;
+    }
+
+    if ((aOpc & 1) != 0)
+    {
+        var C =  B;   /* counter clockwise rotation */
+        B =  A;
+        A = -C;
+    }
+
+    Normalize(exc, A, B, Vec);
+
+    return 0;
+}
+
+function TT_VecLen(X, Y)
+{
+    if (X > FT_Common.m_i || Y > FT_Common.m_i)
+        alert("error");
+
+    var v = new FT_Vector();
+    v.x = X;
+    v.y = Y;
+    return FT_Vector_Length(v);
+}
+
+function Normalize(exc, Vx, Vy, R)
+{
+    if (Vx > FT_Common.m_i || Vy > FT_Common.m_i)
+        alert("error");
+
+    var W = 0;
+    var S1, S2;
+
+    if (Math.abs(Vx) < 0x10000 && Math.abs(Vy) < 0x10000)
+    {
+        Vx *= 0x100;
+        Vy *= 0x100;
+
+        Vx = (Vx & 0xFFFFFFFF);
+        Vy = (Vy & 0xFFFFFFFF);
+
+        W = TT_VecLen(Vx, Vy);
+
+        if (W == 0)
+        {
+            /* XXX: UNDOCUMENTED! It seems that it is possible to try   */
+            /*      to normalize the vector (0,0).  Return immediately. */
+            return 0;
+        }
+
+        R.x = FT_Common.UShort_To_Short(FT_DivFix(Vx, W << 2) & 0xFFFF);
+        R.y = FT_Common.UShort_To_Short(FT_DivFix(Vy, W << 2) & 0xFFFF);
+
+        return 0;
+    }
+
+    W = TT_VecLen(Vx, Vy);
+
+    Vx = FT_DivFix(Vx, W << 2);
+    Vy = FT_DivFix(Vy, W << 2);
+
+    W = Vx * Vx + Vy * Vy;
+    W = (W & 0xFFFFFFFF);
+
+    /* Now, we want that Sqrt( W ) = 0x4000 */
+    /* Or 0x10000000 <= W < 0x10004000      */
+
+    if (Vx < 0)
+    {
+        Vx = -Vx;
+        S1 = 1;
+    }
+    else
+        S1 = 0;
+
+    if (Vy < 0)
+    {
+        Vy = -Vy;
+        S2 = 1;
+    }
+    else
+        S2 = 0;
+
+    while (W < 0x10000000)
+    {
+        /* We need to increase W by a minimal amount */
+        if (Vx < Vy)
+            Vx++;
+        else
+            Vy++;
+
+        W = Vx * Vx + Vy * Vy;
+    }
+
+    while (W >= 0x10004000)
+    {
+        /* We need to decrease W by a minimal amount */
+        if (Vx < Vy)
+            Vx--;
+        else
+            Vy--;
+
+        W = Vx * Vx + Vy * Vy;
+    }
+
+    /* Note that in various cases, we can only  */
+    /* compute a Sqrt(W) of 0x3FFF, eg. Vx = Vy */
+    if (S1 == 1)
+        Vx = -Vx;
+
+    if (S2 == 1)
+        Vy = -Vy;
+
+    R.x = FT_Common.UShort_To_Short(Vx & 0xFFFF);   /* Type conversion */
+    R.y = FT_Common.UShort_To_Short(Vy & 0xFFFF);   /* Type conversion */
+
+    return 0;
+}
+
+// ------
+function Compute_Funcs(exc)
+{
+    // TODO: unpatented
+    if (exc.GS.freeVector.x == 0x4000)
+        exc.F_dot_P = exc.GS.projVector.x;
+    else if (exc.GS.freeVector.y == 0x4000)
+        exc.F_dot_P = exc.GS.projVector.y;
+    else
+        exc.F_dot_P = (exc.GS.projVector.x * exc.GS.freeVector.x + exc.GS.projVector.y * exc.GS.freeVector.y) >> 14;
+
+    if (exc.GS.projVector.x == 0x4000)
+        exc.func_project = Project_x;
+    else if (exc.GS.projVector.y == 0x4000)
+        exc.func_project = Project_y;
+    else
+        exc.func_project = Project;
+
+    if (exc.GS.dualVector.x == 0x4000)
+        exc.func_dualproj = Project_x;
+    else if (exc.GS.dualVector.y == 0x4000)
+        exc.func_dualproj = Project_y;
+    else
+        exc.func_dualproj = Dual_Project;
+
+    exc.func_move      = Direct_Move;
+    exc.func_move_orig = Direct_Move_Orig;
+
+    if (exc.F_dot_P == 0x4000)
+    {
+        if ( exc.GS.freeVector.x == 0x4000 )
+        {
+            exc.func_move      = Direct_Move_X;
+            exc.func_move_orig = Direct_Move_Orig_X;
+        }
+        else if ( exc.GS.freeVector.y == 0x4000 )
+        {
+            exc.func_move      = Direct_Move_Y;
+            exc.func_move_orig = Direct_Move_Orig_Y;
+        }
+    }
+
+    /* at small sizes, F_dot_P can become too small, resulting   */
+    /* in overflows and `spikes' in a number of glyphs like `w'. */
+    if (Math.abs(exc.F_dot_P) < 0x400)
+        exc.F_dot_P = 0x4000;
+
+    /* Disable cached aspect ratio */
+    exc.tt_metrics.ratio = 0;
+}
+
+function Project(exc, dx, dy)
+{
+    if (dx > FT_Common.m_i || dy > FT_Common.m_i)
+        alert("error");
+
+    return TT_DotFix14(dx, dy, exc.GS.projVector.x, exc.GS.projVector.y);
+}
+function Project_x(exc, dx, dy)
+{
+    if (dx > FT_Common.m_i || dy > FT_Common.m_i)
+        alert("error");
+
+    return dx;
+}
+function Project_y(exc, dx, dy)
+{
+    if (dx > FT_Common.m_i || dy > FT_Common.m_i)
+        alert("error");
+
+    return dy;
+}
+function Dual_Project(exc, dx, dy)
+{
+    if (dx > FT_Common.m_i || dy > FT_Common.m_i)
+        alert("error");
+    
+    return TT_DotFix14(dx, dy, exc.GS.dualVector.x, exc.GS.dualVector.y);
+}
+
+function Direct_Move(exc, zone, point, distance)
+{
+    if (point < 0 || point > 0xFFFF || distance > FT_Common.m_i)
+        alert("error");
+
+    var v = exc.GS.freeVector.x;
+    if (v != 0)
+    {
+        if (exc.face.driver.library.tt_hint_props.TT_CONFIG_OPTION_SUBPIXEL_HINTING)
+        {
+            if (!exc.ignore_x_mode || (exc.sph_tweak_flags & FT_Common.SPH_TWEAK_ALLOW_X_DMOVE))
+            {
+                 zone.cur[zone._offset_cur + point].x += FT_MulDiv(distance, v, exc.F_dot_P);
+            }
+            zone.tags[zone._offset_tags + point] |= FT_Common.FT_CURVE_TAG_TOUCH_X;
+        }
+        else
+        {
+            zone.cur[zone._offset_cur + point].x += FT_MulDiv(distance, v, exc.F_dot_P);
+
+            // DEBUG
+            zone.cur[zone._offset_cur + point].x &= 0xFFFFFFFF;
+
+            zone.tags[zone._offset_tags + point] |= FT_Common.FT_CURVE_TAG_TOUCH_X;
+        }
+    }
+
+    v = exc.GS.freeVector.y;
+
+    if (v != 0)
+    {
+        zone.cur[zone._offset_cur + point].y += FT_MulDiv(distance, v, exc.F_dot_P);
+
+        // DEBUG
+        zone.cur[zone._offset_cur + point].y &= 0xFFFFFFFF;
+
+        zone.tags[zone._offset_tags + point] |= FT_Common.FT_CURVE_TAG_TOUCH_Y;
+    }
+}
+
+function Direct_Move_Orig(exc, zone, point, distance)
+{
+    if (point < 0 || point > 0xFFFF || distance > FT_Common.m_i)
+        alert("error");
+
+    var v = exc.GS.freeVector.x;
+
+    if (v != 0)
+    {
+        zone.org[zone._offset_org + point].x += FT_MulDiv(distance, v, exc.F_dot_P);
+
+        // DEBUG
+        zone.org[zone._offset_org + point].x &= 0xFFFFFFFF;
+    }
+
+    v = exc.GS.freeVector.y;
+
+    if (v != 0)
+    {
+        zone.org[zone._offset_org + point].y += FT_MulDiv(distance, v, exc.F_dot_P);
+
+        // DEBUG
+        zone.org[zone._offset_cur + point].y &= 0xFFFFFFFF;
+    }
+}
+
+function Direct_Move_X(exc, zone, point, distance)
+{
+    if (point < 0 || point > 0xFFFF || distance > FT_Common.m_i)
+        alert("error");
+
+    if (exc.face.driver.library.tt_hint_props.TT_CONFIG_OPTION_SUBPIXEL_HINTING)
+    {
+        if (!exc.ignore_x_mode || (exc.sph_tweak_flags & FT_Common.SPH_TWEAK_ALLOW_X_DMOVEX) != 0)
+        {
+            zone.cur[zone._offset_cur + point].x += distance;
+
+            // DEBUG
+            zone.cur[zone._offset_cur + point].x &= 0xFFFFFFFF;
+        }
+        zone.tags[zone._offset_tags + point] |= FT_Common.FT_CURVE_TAG_TOUCH_X;
+    }
+    else
+    {
+        zone.cur[zone._offset_cur + point].x += distance;
+
+        // DEBUG
+        zone.cur[zone._offset_cur + point].x &= 0xFFFFFFFF;
+
+        zone.tags[zone._offset_tags + point] |= FT_Common.FT_CURVE_TAG_TOUCH_X;
+    }
+}
+
+function Direct_Move_Y(exc, zone, point, distance)
+{
+    if (point < 0 || point > 0xFFFF || distance > FT_Common.m_i)
+        alert("error");
+
+    zone.cur[zone._offset_cur + point].y += distance;
+
+    // DEBUG
+    zone.cur[zone._offset_cur + point].y &= 0xFFFFFFFF;
+
+    zone.tags[zone._offset_tags + point] |= FT_Common.FT_CURVE_TAG_TOUCH_Y;
+}
+
+function Direct_Move_Orig_X(exc, zone, point, distance)
+{
+    if (point < 0 || point > 0xFFFF || distance > FT_Common.m_i)
+        alert("error");
+
+    zone.org[zone._offset_org + point].x += distance;
+
+    // DEBUG
+    zone.org[zone._offset_org + point].x &= 0xFFFFFFFF;
+}
+
+function Direct_Move_Orig_Y(exc, zone, point, distance)
+{
+    if (point < 0 || point > 0xFFFF || distance > FT_Common.m_i)
+        alert("error");
+    
+    zone.org[zone._offset_org + point].y += distance;
+
+    // DEBUG
+    zone.org[zone._offset_org + point].y &= 0xFFFFFFFF;
+}
+
+// ------
+
+// ------
+function Compute_Round(exc, round_mode)
+{
+    switch (round_mode)
+    {
+    case TT_Round_Off:
+        exc.func_round = Round_None;
+        break;
+
+    case TT_Round_To_Grid:
+        exc.func_round = Round_To_Grid;
+        break;
+
+    case TT_Round_Up_To_Grid:
+        exc.func_round = Round_Up_To_Grid;
+        break;
+
+    case TT_Round_Down_To_Grid:
+        exc.func_round = Round_Down_To_Grid;
+        break;
+
+    case TT_Round_To_Half_Grid:
+        exc.func_round = Round_To_Half_Grid;
+        break;
+
+    case TT_Round_To_Double_Grid:
+        exc.func_round = Round_To_Double_Grid;
+        break;
+
+    case TT_Round_Super:
+        exc.func_round = Round_Super;
+        break;
+
+    case TT_Round_Super_45:
+        exc.func_round = Round_Super_45;
+        break;
+    }
+}
+
+function Round_None(exc, distance, compensation)
+{
+    if (distance > FT_Common.m_i || compensation > FT_Common.m_i)
+        alert("error");
+
+    var val;
+    if (distance >= 0)
+    {
+        val = distance + compensation;
+        if (distance && val < 0)
+            val = 0;
+    }
+    else
+    {
+        val = distance - compensation;
+        if (val > 0)
+            val = 0;
+    }
+    return val;
+}
+
+function Round_To_Grid(exc, distance, compensation)
+{
+    if (distance > FT_Common.m_i || compensation > FT_Common.m_i)
+        alert("error");
+
+    var val;
+    if (distance >= 0)
+    {
+        val = distance + compensation + 32;
+        if (distance && val > 0)
+            val &= ~63;
+        else
+            val = 0;
+    }
+    else
+    {
+        val = -FT_PIX_ROUND(compensation - distance);
+        if (val > 0)
+            val = 0;
+    }
+
+    return  val;
+}
+
+function Round_Up_To_Grid(exc, distance, compensation)
+{
+    if (distance > FT_Common.m_i || compensation > FT_Common.m_i)
+        alert("error");
+
+    var val;
+    if (distance >= 0)
+    {
+        val = distance + compensation + 63;
+        if (distance && val > 0)
+            val &= ~63;
+        else
+            val = 0;
+    }
+    else
+    {
+        val = -FT_PIX_CEIL(compensation - distance);
+        if (val > 0)
+            val = 0;
+    }
+    return val;
+}
+
+function Round_Down_To_Grid(exc, distance, compensation)
+{
+    if (distance > FT_Common.m_i || compensation > FT_Common.m_i)
+        alert("error");
+
+    var val;
+    if (distance >= 0)
+    {
+        val = distance + compensation;
+        if (distance && val > 0)
+            val &= ~63;
+        else
+            val = 0;
+    }
+    else
+    {
+        val = -((compensation - distance) & -64);
+        if (val > 0)
+            val = 0;
+    }
+    return val;
+}
+
+function Round_To_Half_Grid(exc, distance, compensation)
+{
+    if (distance > FT_Common.m_i || compensation > FT_Common.m_i)
+        alert("error");
+    
+    var val;
+    if (distance >= 0)
+    {
+        val = FT_PIX_FLOOR(distance + compensation) + 32;
+        if (distance && val < 0)
+            val = 0;
+    }
+    else
+    {
+        val = -(FT_PIX_FLOOR(compensation - distance) + 32);
+        if (val > 0)
+            val = 0;
+    }
+    return val;
+}
+
+function Round_To_Double_Grid(exc, distance, compensation)
+{
+    if (distance > FT_Common.m_i || compensation > FT_Common.m_i)
+        alert("error");
+    
+    var val;
+    if (distance >= 0)
+    {
+        val = distance + compensation + 16;
+        if (distance && val > 0)
+            val &= ~31;
+        else
+            val = 0;
+    }
+    else
+    {
+        val = -((compensation - distance + 16) & ~31);
+        if (val > 0)
+            val = 0;
+    }
+
+    return val;
+}
+
+function Round_Super(exc, distance, compensation)
+{
+    if (distance > FT_Common.m_i || compensation > FT_Common.m_i)
+        alert("error");
+    
+    var val;
+    if (distance >= 0)
+    {
+        val = (distance - exc.phase + exc.threshold + compensation) & -exc.period;
+        if (distance && val < 0)
+            val = 0;
+        val += exc.phase;
+    }
+    else
+    {
+        val = -((exc.threshold - exc.phase - distance + compensation) & -exc.period);
+        if (val > 0)
+            val = 0;
+        val -= exc.phase;
+    }
+    return val;
+}
+
+function Round_Super_45(exc, distance, compensation)
+{
+    if (distance > FT_Common.m_i || compensation > FT_Common.m_i)
+        alert("error");
+    
+    var val;
+    if (distance >= 0)
+    {
+        val = (((distance - exc.phase + exc.threshold + compensation) / exc.period) >> 0) * exc.period;
+        if (distance && val < 0)
+            val = 0;
+        val += exc.phase;
+    }
+    else
+    {
+        val = -((((exc.threshold - exc.phase - distance + compensation) / exc.period) >> 0) * exc.period);
+        if (val > 0)
+            val = 0;
+        val -= exc.phase;
+    }
+    return val;
+}
+
+function SetSuperRound(exc, GridPeriod, selector)
+{
+    switch ((selector & 0xC0))
+    {
+    case 0:
+        exc.period = (GridPeriod / 2) >> 0;
+        break;
+    case 0x40:
+        exc.period = GridPeriod;
+        break;
+    case 0x80:
+        exc.period = GridPeriod * 2;
+        break;
+    /* This opcode is reserved, but... */
+    case 0xC0:
+        exc.period = GridPeriod;
+        break;
+    }
+
+    switch ((selector & 0x30))
+    {
+    case 0:
+        exc.phase = 0;
+        break;
+    case 0x10:
+        exc.phase = exc.period >> 2;
+        break;
+    case 0x20:
+        exc.phase = exc.period >> 1;
+        break;
+    case 0x30:
+        exc.phase = (exc.period * 3) >> 2;
+        break;
+    }
+
+    if ((selector & 0x0F) == 0)
+        exc.threshold = exc.period - 1;
+    else
+        exc.threshold = (((selector & 0x0F) - 4) * exc.period) >> 3;
+
+    exc.period    >>= 8;
+    exc.phase     >>= 8;
+    exc.threshold >>= 8;
+}
+
+// ------
+
+function SkipCode(exc)
+{
+    exc.IP += exc.length;
+
+    if (exc.IP < exc.codeSize)
+    {
+        exc.opcode = exc.code.data[exc.code.pos + exc.IP];
+
+        exc.length = opcode_length[exc.opcode];
+        if ( exc.length < 0 )
+        {
+            if ( exc.IP + 1 >= exc.codeSize )
+            {
+                exc.error = FT_Common.FT_Err_Code_Overflow;
+                return 1;
+            }
+            exc.length = 2 - exc.length * exc.code.data[exc.code.pos + exc.IP + 1];
+        }
+
+        if (exc.IP + exc.length <= exc.codeSize)
+            return 0;
+    }
+
+    exc.error = FT_Common.FT_Err_Code_Overflow;
+    return 1;
+}
+
+function Ins_Goto_CodeRange(exc, aRange, aIP)
+{
+    if (aRange < 1 || aRange > 3)
+    {
+        exc.error = FT_Common.FT_Err_Bad_Argument;
+        return 1;
+    }
+
+    var range = exc.codeRangeTable[aRange - 1];
+
+    if (range.base == null)     /* invalid coderange */
+    {
+        exc.error = FT_Common.FT_Err_Invalid_CodeRange;
+        return 1;
+    }
+
+    /* NOTE: Because the last instruction of a program may be a CALL */
+    /*       which will return to the first byte *after* the code    */
+    /*       range, we test for aIP <= Size, instead of aIP < Size.  */
+
+    if (aIP > range.size)
+    {
+        exc.error = FT_Common.FT_Err_Code_Overflow;
+        return 1;
+    }
+
+    exc.code     = dublicate_pointer(range.base);
+    exc.codeSize = range.size;
+    exc.IP       = aIP;
+    exc.curRange = aRange;
+
+    return 0;
+}
+
+function Compute_Point_Displacement(exc, x, y, zone, refp)
+{
+    var ret = {x: x, y: y, refp: refp, err: 0};
+    var zp = null;
+    var p;
+
+    if (exc.opcode & 1)
+    {
+        zp = exc.zp0;
+        p  = exc.GS.rp1;
+    }
+    else
+    {
+        zp = exc.zp1;
+        p  = exc.GS.rp2;
+    }
+
+    if (p >= zp.n_points)
+    {
+        if (exc.pedantic_hinting )
+            exc.error = FT_Common.FT_Err_Invalid_Reference;
+        ret.refp = 0;
+        ret.err = 1;
+        return ret;
+    }
+
+    zone.Copy(zp);
+    ret.refp = p;
+
+    var v1 = zp.cur[zp._offset_cur + p];
+    var v2 = zp.org[zp._offset_org + p];
+    var d = exc.func_project(exc, v1.x - v2.x, v1.y - v2.y);
+
+    // TODO : unpatended
+    ret.x = FT_MulDiv(d, exc.GS.freeVector.x, exc.F_dot_P);
+    ret.y = FT_MulDiv(d, exc.GS.freeVector.y, exc.F_dot_P);
+
+    return ret;
+}
+
+function TT_MulFix14(a, b)
+{
+    a = FT_Common.UintToInt(a);
+    b = FT_Common.UintToInt(b);
+
+    var sign = a ^ b;
+
+    if (a < 0)
+        a = -a;
+    if (b < 0)
+        b = -b;
+
+    var ah = ((a >> 16) & 0xFFFF);
+    var al = (a & 0xFFFF);
+
+    var lo = FT_Common.IntToUInt((al * b) & 0xFFFFFFFF);
+    var mid = FT_Common.IntToUInt((ah * b) & 0xFFFFFFFF);
+    var hi = FT_Common.IntToUInt(mid >> 16);
+    mid = FT_Common.IntToUInt(((mid << 16) + (1 << 13)) & 0xFFFFFFFF); /* rounding */
+    lo += mid;
+
+    lo = FT_Common.IntToUInt(lo & 0xFFFFFFFF);
+
+    if (lo < mid)
+        hi += 1;
+
+    mid = FT_Common.IntToUInt(((lo >> 14) | (hi << 18)) & 0xFFFFFFFF);
+    return sign >= 0 ? mid : -mid;
+}
+
+function TT_DotFix14(ax, ay, bx, by)
+{
+    ax = FT_Common.UintToInt(ax);
+    ay = FT_Common.UintToInt(ay);
+    bx = FT_Common.UintToInt(bx);
+    by = FT_Common.UintToInt(by);
+
+    /* compute ax*bx as 64-bit value */
+    var _l = ((ax & 0xFFFF) * bx) & 0xFFFFFFFF;
+    var l = FT_Common.IntToUInt(_l);
+    var m = ((ax >> 16) * bx) & 0xFFFFFFFF;
+
+    var lo1 = l + FT_Common.IntToUInt((m << 16) & 0xFFFFFFFF);
+    lo1 = FT_Common.IntToUInt(lo1 & 0xFFFFFFFF);
+
+    var hi1 = (m >> 16) + (_l >> 31) + ((lo1 < l) ? 1 : 0);
+
+    /* compute ay*by as 64-bit value */
+    _l = ((ay & 0xFFFF) * by) & 0xFFFFFFFF;
+    l = FT_Common.IntToUInt(_l);
+    m = ((ay >> 16) * by) & 0xFFFFFFFF;
+
+    var lo2 = l + FT_Common.IntToUInt(m << 16);
+    lo2 = FT_Common.IntToUInt(lo2 & 0xFFFFFFFF);
+
+    var hi2 = (m >> 16) + (_l >> 31) + ((lo2 < l) ? 1 : 0);
+
+    /* add them */
+    var lo = lo1 + lo2;
+    lo = FT_Common.IntToUInt(lo & 0xFFFFFFFF);
+
+    var hi = hi1 + hi2 + ((lo < lo1) ? 1 : 0);
+
+    /* divide the result by 2^14 with rounding */
+    var s   = hi >> 31;
+    l  = lo + FT_Common.IntToUInt(s);
+    l = FT_Common.IntToUInt(l & 0xFFFFFFFF);
+
+    hi += s + ((l < lo) ? 1 : 0);
+    lo  = l;
+
+    l   = lo + 0x2000;
+    l = FT_Common.IntToUInt(l & 0xFFFFFFFF);
+    
+    hi += ((l < lo) ? 1 : 0);
+
+    return ((hi << 18) | (l >> 14)) & 0xFFFFFFFF;
+}
+
+function Move_Zp2_Point(exc, point, dx, dy, touch)
+{
+    // TODO: unpatented
+    if (exc.GS.freeVector.x != 0)
+    {
+        if (exc.face.driver.library.tt_hint_props.TT_CONFIG_OPTION_SUBPIXEL_HINTING) //#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+        {
+            if (!exc.ignore_x_mode || (exc.ignore_x_mode && (exc.sph_tweak_flags & FT_Common.SPH_TWEAK_ALLOW_X_MOVE_ZP2)))
+            {
+                exc.zp2.cur[exc.zp2._offset_cur + point].x += dx;
+            }
+        }
+        else
+        {
+            exc.zp2.cur[exc.zp2._offset_cur + point].x += dx;
+        }
+        if (touch)
+            exc.zp2.tags[exc.zp2._offset_tags + point] |= FT_Common.FT_CURVE_TAG_TOUCH_X;
+    }
+
+    if (exc.GS.freeVector.y != 0)
+    {
+        exc.zp2.cur[exc.zp2._offset_cur + point].y += dy;
+        if (touch)
+            exc.zp2.tags[exc.zp2._offset_tags + point] |= FT_Common.FT_CURVE_TAG_TOUCH_Y;
+    }
+}
+////////////////////////////////////////////////////////
+function Ins_SVTCA(exc, args, args_pos)
+{
+    var A = 0;
+    var B = 0x4000;
+    if ((exc.opcode & 1) == 1)
+    {
+        A = 0x4000;
+        B = 0;
+    }
+
+    exc.GS.freeVector.x = A;
+    exc.GS.projVector.x = A;
+    exc.GS.dualVector.x = A;
+
+    exc.GS.freeVector.y = B;
+    exc.GS.projVector.y = B;
+    exc.GS.dualVector.y = B;
+
+    Compute_Funcs(exc);
+}
+
+function Ins_SPVTCA(exc, args, args_pos)
+{
+    var A = 0;
+    var B = 0x4000;
+    if ((exc.opcode & 1) == 1)
+    {
+        A = 0x4000;
+        B = 0;
+    }
+
+    exc.GS.projVector.x = A;
+    exc.GS.dualVector.x = A;
+
+    exc.GS.projVector.y = B;
+    exc.GS.dualVector.y = B;
+
+    GUESS_VECTOR(exc, exc.GS.freeVector);
+
+    Compute_Funcs(exc);
+}
+
+function Ins_SFVTCA(exc, args, args_pos)
+{
+    var A = 0;
+    var B = 0x4000;
+    if ((exc.opcode & 1) == 1)
+    {
+        A = 0x4000;
+        B = 0;
+    }
+
+    exc.GS.freeVector.x = A;
+    exc.GS.freeVector.y = B;
+
+    GUESS_VECTOR(exc, exc.projVector);
+
+    Compute_Funcs(exc);
+}
+
+function Ins_SPVTL(exc, args, args_pos)
+{
+    if (Ins_SxVTL(exc, 0xFFFF & args[args_pos + 1], 0xFFFF & args[args_pos], exc.opcode, exc.GS.projVector) == 0)
+    {
+        exc.GS.dualVector.x = exc.GS.projVector.x;
+        exc.GS.dualVector.y = exc.GS.projVector.y;
+        GUESS_VECTOR(exc, exc.GS.freeVector);
+        Compute_Funcs(exc);
+    }
+}
+
+function Ins_SFVTL(exc, args, args_pos)
+{
+    if (Ins_SxVTL(exc, 0xFFFF & args[args_pos + 1], 0xFFFF & args[args_pos], exc.opcode, exc.GS.freeVector) == 0)
+    {
+        GUESS_VECTOR(exc, exc.GS.projVector );
+        Compute_Funcs(exc);
+    }
+}
+
+function Ins_SPVFS(exc, args, args_pos)
+{
+    /* Only use low 16bits, then sign extend */
+    var Y = FT_Common.UShort_To_Short(0xFFFF & args[args_pos + 1]);
+    var X = FT_Common.UShort_To_Short(0xFFFF & args[args_pos]);
+
+    Normalize(exc, X, Y, exc.GS.projVector);
+
+    exc.GS.dualVector.x = exc.GS.projVector.x;
+    exc.GS.dualVector.y = exc.GS.projVector.y;
+    GUESS_VECTOR(exc, exc.GS.freeVector );
+    Compute_Funcs(exc);
+}
+
+function Ins_SFVFS(exc, args, args_pos)
+{
+    /* Only use low 16bits, then sign extend */
+    var Y = FT_Common.UShort_To_Short(0xFFFF & args[args_pos + 1]);
+    var X = FT_Common.UShort_To_Short(0xFFFF & args[args_pos]);
+
+    Normalize(exc, X, Y, exc.GS.freeVector);
+    GUESS_VECTOR(exc, exc.GS.projVector );
+    Compute_Funcs(exc);
+}
+
+function Ins_GPV(exc, args, args_pos)
+{
+    // TODO: unpatented
+    args[args_pos] = exc.GS.projVector.x;
+    args[args_pos + 1] = exc.GS.projVector.y;
+}
+
+function Ins_GFV(exc, args, args_pos)
+{
+    // TODO: unpatented
+    args[args_pos] = exc.GS.freeVector.x;
+    args[args_pos + 1] = exc.GS.freeVector.y;
+}
+
+function Ins_SFVTPV(exc, args, args_pos)
+{
+    GUESS_VECTOR(exc, exc.GS.projVector);
+    exc.GS.freeVector.x = exc.GS.projVector.x;
+    exc.GS.freeVector.y = exc.GS.projVector.y;
+    Compute_Funcs(exc);
+}
+
+function Ins_ISECT(exc, args, args_pos)
+{
+    var point = 0xFFFF & args[args_pos];
+
+    var a0 = 0xFFFF & args[args_pos + 1];
+    var a1 = 0xFFFF & args[args_pos + 2];
+    var b0 = 0xFFFF & args[args_pos + 3];
+    var b1 = 0xFFFF & args[args_pos + 4];
+
+    if ((b0 >= exc.zp0.n_points)  ||
+        (b1 >= exc.zp0.n_points)  ||
+        (a0 >= exc.zp1.n_points)  ||
+        (a1 >= exc.zp1.n_points)  ||
+        (point >= exc.zp2.n_points))
+    {
+        if (exc.pedantic_hinting)
+            exc.error = FT_Common.FT_Err_Invalid_Reference;
+        return;
+    }
+
+    /* Cramer's rule */
+
+    var off0 = exc.zp0._offset_cur;
+    var off1 = exc.zp1._offset_cur;
+    var off2 = exc.zp2._offset_cur;
+
+    var dbx = exc.zp0.cur[off0+b1].x - exc.zp0.cur[off0+b0].x;
+    var dby = exc.zp0.cur[off0+b1].y - exc.zp0.cur[off0+b0].y;
+
+    var dax = exc.zp1.cur[off1+a1].x - exc.zp1.cur[off1+a0].x;
+    var day = exc.zp1.cur[off1+a1].y - exc.zp1.cur[off1+a0].y;
+
+    var dx = exc.zp0.cur[off0+b0].x - exc.zp1.cur[off1+a0].x;
+    var dy = exc.zp0.cur[off0+b0].y - exc.zp1.cur[off1+a0].y;
+
+    exc.zp2.tags[exc.zp2._offset_tags + point] |= FT_Common.FT_CURVE_TAG_TOUCH_BOTH;
+
+    var discriminant = FT_MulDiv(dax, -dby, 0x40) + FT_MulDiv(day, dbx, 0x40);
+    var dotproduct   = FT_MulDiv(dax, dbx, 0x40) + FT_MulDiv(day, dby, 0x40);
+
+    /* The discriminant above is actually a cross product of vectors     */
+    /* da and db. Together with the dot product, they can be used as     */
+    /* surrogates for sine and cosine of the angle between the vectors.  */
+    /* Indeed,                                                           */
+    /*       dotproduct   = |da||db|cos(angle)                           */
+    /*       discriminant = |da||db|sin(angle)     .                     */
+    /* We use these equations to reject grazing intersections by         */
+    /* thresholding abs(tan(angle)) at 1/19, corresponding to 3 degrees. */
+    if (19 * Math.abs(discriminant) > Math.abs(dotproduct))
+    {
+        var val = FT_MulDiv(dx, -dby, 0x40) + FT_MulDiv(dy, dbx, 0x40);
+
+        var __x = FT_MulDiv(val, dax, discriminant);
+        var __y = FT_MulDiv(val, day, discriminant);
+
+        exc.zp2.cur[off2 + point].x = exc.zp1.cur[off1 + a0].x + __x;
+        exc.zp2.cur[off2 + point].y = exc.zp1.cur[off1 + a0].y + __y;
+    }
+    else
+    {
+        /* else, take the middle of the middles of A and B */
+        exc.zp2.cur[off2 + point].x = (exc.zp1.cur[off1 + a0].x +
+                               exc.zp1.cur[off1 + a1].x +
+                               exc.zp0.cur[off0 + b0].x +
+                               exc.zp0.cur[off0 + b1].x ) >> 2;
+        exc.zp2.cur[off2 + point].y = (exc.zp1.cur[off1 + a0].y +
+                               exc.zp1.cur[off1 + a1].y +
+                               exc.zp0.cur[off0 + b0].y +
+                               exc.zp0.cur[off0 + b1].y ) >> 2;
+    }
+}
+
+function Ins_SRP0(exc, args, args_pos)
+{
+    exc.GS.rp0 = 0xFFFF & args[args_pos];
+}
+
+function Ins_SRP1(exc, args, args_pos)
+{
+    exc.GS.rp1 = 0xFFFF & args[args_pos];
+}
+
+function Ins_SRP2(exc, args, args_pos)
+{
+    exc.GS.rp2 = 0xFFFF & args[args_pos];
+}
+
+function Ins_SZP0(exc, args, args_pos)
+{
+    switch (args[args_pos])
+    {
+    case 0:
+        exc.zp0.Copy(exc.twilight);
+        break;
+
+    case 1:
+        exc.zp0.Copy(exc.pts);
+        break;
+
+    default:
+        if (exc.pedantic_hinting)
+            exc.error = FT_Common.FT_Err_Invalid_Reference;
+        return;
+    }
+
+    exc.GS.gep0 = 0xFFFF & args[args_pos];
+}
+
+function Ins_SZP1(exc, args, args_pos)
+{
+    switch (args[args_pos])
+    {
+    case 0:
+        exc.zp1.Copy(exc.twilight);
+        break;
+
+    case 1:
+        exc.zp1.Copy(exc.pts);
+        break;
+
+    default:
+        if (exc.pedantic_hinting)
+            exc.error = FT_Common.FT_Err_Invalid_Reference;
+        return;
+    }
+
+    exc.GS.gep1 = 0xFFFF & args[args_pos];
+}
+
+function Ins_SZP2(exc, args, args_pos)
+{
+    switch (args[args_pos])
+    {
+    case 0:
+        exc.zp2.Copy(exc.twilight);
+        break;
+
+    case 1:
+        exc.zp2.Copy(exc.pts);
+        break;
+
+    default:
+        if (exc.pedantic_hinting)
+            exc.error = FT_Common.FT_Err_Invalid_Reference;
+        return;
+    }
+
+    exc.GS.gep2 = 0xFFFF & args[args_pos];
+}
+
+function Ins_SZPS(exc, args, args_pos)
+{
+    switch (args[args_pos])
+    {
+    case 0:
+        exc.zp0.Copy(exc.twilight);
+        break;
+
+    case 1:
+        exc.zp0.Copy(exc.pts);
+        break;
+
+    default:
+        if (exc.pedantic_hinting)
+            exc.error = FT_Common.FT_Err_Invalid_Reference;
+        return;
+    }
+
+    exc.zp1.Copy(exc.zp0);
+    exc.zp2.Copy(exc.zp0);
+
+    exc.GS.gep0 = 0xFFFF & args[args_pos];
+    exc.GS.gep1 = 0xFFFF & args[args_pos];
+    exc.GS.gep2 = 0xFFFF & args[args_pos];
+}
+
+function Ins_SLOOP(exc, args, args_pos)
+{
+    if (args[args_pos] < 0)
+        exc.error = FT_Common.FT_Err_Bad_Argument;
+    else
+        exc.GS.loop = args[args_pos];
+}
+
+function Ins_RTG(exc, args, args_pos)
+{
+    exc.GS.round_state = TT_Round_To_Grid;
+    exc.func_round = Round_To_Grid;
+}
+
+function Ins_RTHG(exc, args, args_pos)
+{
+    exc.GS.round_state = TT_Round_To_Half_Grid;
+    exc.func_round = Round_To_Half_Grid;
+}
+
+function Ins_SMD(exc, args, args_pos)
+{
+    exc.GS.minimum_distance = args[args_pos];
+}
+
+function Ins_ELSE(exc, args, args_pos)
+{
+    var nIfs = 1;
+
+    do
+    {
+        if (SkipCode(exc) == 1)
+            return;
+
+        switch (exc.opcode)
+        {
+        case 0x58:    /* IF */
+            nIfs++;
+            break;
+
+        case 0x59:    /* EIF */
+            nIfs--;
+            break;
+        }
+    } while ( nIfs != 0 );
+}
+
+function Ins_JMPR(exc, args, args_pos)
+{
+    if (args[args_pos] == 0 && exc.args == 0)
+        exc.error = FT_Common.FT_Err_Bad_Argument;
+    exc.IP += args[args_pos];
+    if (exc.IP < 0 || (exc.callTop > 0 && exc.IP > exc.callStack[exc.callTop - 1].Cur_End))
+        exc.error = FT_Common.FT_Err_Bad_Argument;
+    exc.step_ins = 0;
+}
+
+function Ins_SCVTCI(exc, args, args_pos)
+{
+    exc.GS.control_value_cutin = args[args_pos];
+}
+
+function Ins_SSWCI(exc, args, args_pos)
+{
+    exc.GS.single_width_cutin = args[args_pos];
+}
+
+function Ins_SSW(exc, args, args_pos)
+{
+    exc.GS.single_width_value = FT_MulFix(args[args_pos], exc.tt_metrics.scale);
+}
+
+function Ins_DUP(exc, args, args_pos)
+{
+    args[args_pos + 1] = args[args_pos];
+}
+
+function Ins_POP(exc, args, args_pos)
+{
+}
+
+function Ins_CLEAR(exc, args, args_pos)
+{
+    exc.new_top = 0;
+}
+
+function Ins_SWAP(exc, args, args_pos)
+{
+    var L = args[args_pos];
+    args[args_pos] = args[args_pos + 1];
+    args[args_pos + 1] = L;
+}
+
+function Ins_DEPTH(exc, args, args_pos)
+{
+    args[args_pos] = exc.top;
+}
+
+function Ins_CINDEX(exc, args, args_pos)
+{
+    var L = args[args_pos];
+
+    if (L <= 0 || L > exc.args)
+    {
+        if (exc.pedantic_hinting)
+            exc.error = FT_Common.FT_Err_Invalid_Reference;
+        args[args_pos] = 0;
+    }
+    else
+        args[args_pos] = exc.stack[exc.args - L];
+}
+
+function Ins_MINDEX(exc, args, args_pos)
+{
+    var L = args[args_pos];
+
+    if (L <= 0 || L > exc.args)
+    {
+        if (exc.pedantic_hinting)
+            exc.error = FT_Common.FT_Err_Invalid_Reference;
+    }
+    else
+    {
+        var K = exc.stack[exc.args - L];
+
+        var _i1 = exc.args - L;
+        var _i2 = exc.args - 1;
+        for (var i = _i1; i < _i2; i++)
+            exc.stack[i] = exc.stack[i + 1];
+
+        exc.stack[exc.args - 1] = K;
+    }
+}
+
+function Ins_ALIGNPTS(exc, args, args_pos)
+{
+    var p1 = 0xFFFF & args[args_pos];
+    var p2 = 0xFFFF & args[args_pos + 1];
+
+    if ((p1 >= exc.zp1.n_points) || (p2 >= exc.zp0.n_points))
+    {
+        if (exc.pedantic_hinting)
+            exc.error = FT_Common.FT_Err_Invalid_Reference;
+        return;
+    }
+
+    var v1 = exc.zp0.cur[exc.zp0._offset_cur + p2];
+    var v2 = exc.zp1.cur[exc.zp1._offset_cur + p1];
+
+    var distance = (exc.func_project(exc, v1.x - v2.x, v1.y - v2.y) / 2) >> 0;
+
+    exc.func_move(exc, exc.zp1, p1, distance);
+    exc.func_move(exc, exc.zp0, p2, -distance);
+}
+
+function Ins_UNKNOWN(exc, args, args_pos)
+{
+    var defs = exc.IDefs;
+    var limit = exc.numIDefs;
+
+    for (var def = 0; def < limit; def++)
+    {
+        if (defs[def].opc == exc.opcode && defs[def].active)
+        {
+            if (exc.callTop >= exc.callSize)
+            {
+                exc.error = FT_Common.FT_Err_Stack_Overflow;
+                return;
+            }
+
+            var call = exc.callStack[exc.callTop++];
+
+            call.Caller_Range = exc.curRange;
+            call.Caller_IP    = exc.IP + 1;
+            call.Cur_Count    = 1;
+            call.Cur_Restart  = defs[def].start;
+            call.Cur_End      = defs[def].end;
+
+            Ins_Goto_CodeRange(defs[def].range, defs[def].start);
+
+            exc.step_ins = false;
+            return;
+        }
+    }
+
+    exc.error = FT_Common.FT_Err_Invalid_Opcode;
+}
+function Ins_UTP(exc, args, args_pos)
+{
+    var point = 0xFFFF & args[args_pos];
+
+    if (point >= exc.zp0.n_points)
+    {
+        if (exc.pedantic_hinting)
+            exc.error = FT_Common.FT_Err_Invalid_Reference;
+        return;
+    }
+
+    var mask = 0xFF;
+
+    if (exc.GS.freeVector.x != 0)
+        mask &= ~FT_Common.FT_CURVE_TAG_TOUCH_X;
+
+    if (exc.GS.freeVector.y != 0)
+        mask &= ~FT_Common.FT_CURVE_TAG_TOUCH_Y;
+
+    exc.zp0.tags[exc.zp0._offset_tags + point] &= mask;
+}
+
+function Ins_LOOPCALL(exc, args, args_pos)
+{
+    /* first of all, check the index */
+    var F = args[args_pos + 1];
+    if (F >= (exc.maxFunc + 1))
+    {
+        exc.error = FT_Common.FT_Err_Invalid_Reference;
+        return;
+    }
+
+    /* Except for some old Apple fonts, all functions in a TrueType */
+    /* font are defined in increasing order, starting from 0.  This */
+    /* means that we normally have                                  */
+    /*                                                              */
+    /*    CUR.maxFunc+1 == CUR.numFDefs                             */
+    /*    CUR.FDefs[n].opc == n for n in 0..CUR.maxFunc             */
+    /*                                                              */
+    /* If this isn't true, we need to look up the function table.   */
+    var defs = exc.FDefs;
+    var def = F;
+    if (exc.maxFunc + 1 != exc.numFDefs || exc.FDefs[def].opc != F)
+    {
+        /* look up the FDefs table */
+        def = 0;
+        var limit = exc.numFDefs;
+
+        while (def < limit && defs[def].opc != F)
+            def++;
+
+        if (def == limit)
+        {
+            exc.error = FT_Common.FT_Err_Invalid_Reference;
+            return;
+        }
+    }
+
+    /* check that the function is active */
+    if (!defs[def].active)
+    {
+        exc.error = FT_Common.FT_Err_Invalid_Reference;
+        return;
+    }
+
+    /* check stack */
+    if (exc.callTop >= exc.callSize)
+    {
+        exc.error = FT_Common.FT_Err_Stack_Overflow;
+        return;
+    }
+
+    if (args[args_pos] > 0)
+    {
+        var pCrec = exc.callStack[exc.callTop];
+
+        pCrec.Caller_Range = exc.curRange;
+        pCrec.Caller_IP    = exc.IP + 1;
+        pCrec.Cur_Count    = args[args_pos];
+        pCrec.Cur_Restart  = defs[def].start;
+        pCrec.Cur_End      = defs[def].end;
+
+        exc.callTop++;
+
+        Ins_Goto_CodeRange(exc, defs[def].range, defs[def].start);
+        exc.step_ins = false;
+    }
+}
+
+function Ins_CALL(exc, args, args_pos)
+{
+    /* first of all, check the index */
+    var F = FT_Common.IntToUInt(args[args_pos]);
+    if (F >= (exc.maxFunc + 1))
+    {
+        exc.error = FT_Common.FT_Err_Invalid_Reference;
+        return;
+    }
+
+    /* Except for some old Apple fonts, all functions in a TrueType */
+    /* font are defined in increasing order, starting from 0.  This */
+    /* means that we normally have                                  */
+    /*                                                              */
+    /*    CUR.maxFunc+1 == CUR.numFDefs                             */
+    /*    CUR.FDefs[n].opc == n for n in 0..CUR.maxFunc             */
+    /*                                                              */
+    /* If this isn't true, we need to look up the function table.   */
+
+    var defs = exc.FDefs;
+    var def = F;
+    if ((exc.maxFunc + 1) != exc.numFDefs || defs[def].opc != F)
+    {
+        /* look up the FDefs table */
+        def   = 0;
+        var limit = exc.numFDefs;
+
+        while (def < limit && defs[def].opc != F)
+            def++;
+
+        if (def == limit)
+        {
+            exc.error = FT_Common.FT_Err_Invalid_Reference;
+            return;
+        }
+    }
+
+    /* check that the function is active */
+    if (!defs[def].active)
+    {
+        exc.error = FT_Common.FT_Err_Invalid_Reference;
+        return;
+    }
+
+    /* check the call stack */
+    if (exc.callTop >= exc.callSize)
+    {
+        exc.error = FT_Common.FT_Err_Stack_Overflow;
+        return;
+    }
+
+    var pCrec = exc.callStack[exc.callTop];
+
+    pCrec.Caller_Range = exc.curRange;
+    pCrec.Caller_IP    = exc.IP + 1;
+    pCrec.Cur_Count    = 1;
+    pCrec.Cur_Restart  = defs[def].start;
+    pCrec.Cur_End      = defs[def].end;
+
+    exc.callTop++;
+
+    Ins_Goto_CodeRange(exc, defs[def].range, defs[def].start);
+
+    exc.step_ins = false;
+}
+
+function Ins_FDEF(exc, args, args_pos)
+{
+    var bIsSubpix = exc.face.driver.library.tt_hint_props.TT_CONFIG_OPTION_SUBPIXEL_HINTING;
+
+    /* some font programs are broken enough to redefine functions! */
+    /* We will then parse the current table.                       */
+    var defs = exc.FDefs;
+    var rec = 0;
+    var limit = exc.numFDefs;
+    var n = args[args_pos];
+
+    for ( ; rec < limit; rec++)
+    {
+        if (defs[rec].opc == n)
+            break;
+    }
+
+    if (rec == limit)
+    {
+        /* check that there is enough room for new functions */
+        if (exc.numFDefs >= exc.maxFDefs)
+        {
+            exc.error = FT_Common.FT_Err_Too_Many_Function_Defs;
+            return;
+        }
+        exc.numFDefs++;
+    }
+
+    /* Although FDEF takes unsigned 32-bit integer,  */
+    /* func # must be within unsigned 16-bit integer */
+    if (n > 0xFFFF)
+    {
+        exc.error = FT_Common.FT_Err_Too_Many_Function_Defs;
+        return;
+    }
+
+    defs[rec].range        = exc.curRange;
+    defs[rec].opc          = 0xFFFF & n;
+    defs[rec].start        = exc.IP + 1;
+    defs[rec].active       = true;
+    defs[rec].inline_delta = false;
+
+    if (n > exc.maxFunc)
+        exc.maxFunc = 0xFFFF & n;
+
+    /* Now skip the whole function definition. */
+    /* We don't allow nested IDEFS & FDEFs.    */
+
+    while (SkipCode(exc) == 0)
+    {
+        if (bIsSubpix)//#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+        {
+            /* arguments to opcodes are skipped by `SKIP_Code' */
+            var opcode_pattern = [];
+            opcode_pattern[0] = [/* #0 TTFautohint bytecode (old) */
+                       0x20, /* DUP     */
+                       0x64, /* ABS     */
+                       0xB0, /* PUSHB_1 */
+                             /*   32    */
+                       0x60, /* ADD     */
+                       0x66, /* FLOOR   */
+                       0x23, /* SWAP    */
+                       0xB0,  /* PUSHB_1 */
+                       0,0,0,0,0
+                   ];
+            var opcode_patterns = 1;
+            var opcode_pointer = [0];
+            var opcode_size = [7];
+
+            for (var i = 0; i < opcode_patterns; i++)
+            {
+                if (opcode_pointer[i] < opcode_size[i] && exc.opcode == opcode_pattern[i][opcode_pointer[i]])
+                {
+                    opcode_pointer[i] += 1;
+
+                    if (opcode_pointer[i] == opcode_size[i])
+                    {
+                        switch ( i )
+                        {
+                        case 0:
+                            exc.size.ttfautohinted = true;
+                            break;
+                        }
+                        opcode_pointer[i] = 0;
+                    }
+                }
+                else
+                    opcode_pointer[i] = 0;
+            }
+        } //#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+
+        switch (exc.opcode)
+        {
+        case 0x89:    /* IDEF */
+        case 0x2C:    /* FDEF */
+            exc.error = FT_Common.FT_Err_Nested_DEFS;
+            return;
+        case 0x2D:   /* ENDF */
+            defs[rec].end = exc.IP;
+            return;
+        default:
+            break;
+        }
+    }
+}
+
+function Ins_ENDF(exc, args, args_pos)
+{
+    if (exc.callTop <= 0)     /* We encountered an ENDF without a call */
+    {
+        exc.error = FT_Common.FT_Err_ENDF_In_Exec_Stream;
+        return;
+    }
+
+    exc.callTop--;
+    var pRec = exc.callStack[exc.callTop];
+
+    pRec.Cur_Count--;
+    exc.step_ins = false;
+
+    var bIsSubpix = exc.face.driver.library.tt_hint_props.TT_CONFIG_OPTION_SUBPIXEL_HINTING;
+
+    if (bIsSubpix) //#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+    {
+        /*
+        *  CUR.ignore_x_mode may be turned off prior to function calls.  This
+        *  ensures it is turned back on.
+        */
+        exc.ignore_x_mode = (exc.subpixel_hinting || exc.grayscale_hinting) && !(exc.sph_tweak_flags & FT_Common.SPH_TWEAK_PIXEL_HINTING);
+    }//#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+
+    if (pRec.Cur_Count > 0)
+    {
+        exc.callTop++;
+        exc.IP = pRec.Cur_Restart;
+    }
+    else
+    {
+        /* Loop through the current function */
+        Ins_Goto_CodeRange(exc, pRec.Caller_Range, pRec.Caller_IP);
+    }
+
+    /* Exit the current call frame.                      */
+
+    /* NOTE: If the last instruction of a program is a   */
+    /*       CALL or LOOPCALL, the return address is     */
+    /*       always out of the code range.  This is a    */
+    /*       valid address, and it is why we do not test */
+    /*       the result of Ins_Goto_CodeRange() here!    */
+}
+
+function Ins_MDAP(exc, args, args_pos)
+{
+    var point = 0xFFFF & args[args_pos];
+
+    if (point >= exc.zp0.n_points)
+    {
+        if (exc.pedantic_hinting)
+            exc.error = FT_Common.FT_Err_Invalid_Reference;
+        return;
+    }
+
+    var distance = 0;
+    if ((exc.opcode & 1) != 0)
+    {
+        var cur_dist = exc.func_project(exc, exc.zp0.cur[exc.zp0._offset_cur + point].x, exc.zp0.cur[exc.zp0._offset_cur + point].y);
+        var bIsSubpix = exc.face.driver.library.tt_hint_props.TT_CONFIG_OPTION_SUBPIXEL_HINTING;
+
+        if (bIsSubpix)
+        {
+            if (exc.ignore_x_mode && exc.GS.freeVector.x != 0)
+            {
+                distance = Round_None(exc, cur_dist, exc.tt_metrics.compensations[0]) - cur_dist;
+            }
+            else
+            {
+                distance = exc.func_round(exc, cur_dist, exc.tt_metrics.compensations[0]) - cur_dist;
+            }
+        }
+        else
+        {
+            distance = exc.func_round(exc, cur_dist, exc.tt_metrics.compensations[0]) - cur_dist;
+        }
+    }
+
+    exc.func_move(exc, exc.zp0, point, distance);
+
+    exc.GS.rp0 = point;
+    exc.GS.rp1 = point;
+}
+
+// --
+function IUP_WorkerRec()
+{
+    this.orgs = null;   /* original and current coordinate */
+    this.curs = null;   /* arrays                          */
+    this.orus = null;
+
+    this.off_orgs = 0;
+    this.off_curs = 0;
+    this.off_orus = 0;
+
+    this.max_points = 0;
+    this.is_offset_one = false;
+}
+
+function _iup_worker_shift(worker, p1, p2, p)
+{
+    if (!worker.is_offset_one)
+    {
+        var dx = worker.curs[worker.off_curs + p].x - worker.orgs[worker.off_orgs + p].x;
+        if (dx != 0)
+        {
+            for (var i = p1; i < p; i++)
+                worker.curs[worker.off_curs + i].x += dx;
+
+            for (var i = p + 1; i <= p2; i++)
+                worker.curs[worker.off_curs + i].x += dx;
+        }
+    }
+    else
+    {
+        var dy = worker.curs[worker.off_curs + p].y - worker.orgs[worker.off_orgs + p].y;
+        if (dy != 0)
+        {
+            for (var i = p1; i < p; i++)
+                worker.curs[worker.off_curs + i].y += dy;
+
+            for (var i = p + 1; i <= p2; i++)
+                worker.curs[worker.off_curs + i].y += dy;
+        }
+    }
+}
+
+function _iup_worker_interpolate(worker, p1, p2, ref1, ref2)
+{
+    if (!worker.is_offset_one)
+    {
+        if (p1 > p2)
+            return;
+
+        if ((ref1 >= worker.max_points) || (ref2 >= worker.max_points))
+            return;
+
+        var orus1 = worker.orus[worker.off_orus + ref1].x;
+        var orus2 = worker.orus[worker.off_orus + ref2].x;
+
+        if (orus1 > orus2)
+        {
+            var tmp_o = orus1;
+            orus1 = orus2;
+            orus2 = tmp_o;
+
+            var tmp_r = ref1;
+            ref1  = ref2;
+            ref2  = tmp_r;
+        }
+
+        var org1   = worker.orgs[worker.off_orgs + ref1].x;
+        var org2   = worker.orgs[worker.off_orgs + ref2].x;
+        var delta1 = worker.curs[worker.off_curs + ref1].x - org1;
+        var delta2 = worker.curs[worker.off_curs + ref2].x - org2;
+
+        if (orus1 == orus2)
+        {
+            /* simple shift of untouched points */
+            for (var i = p1; i <= p2; i++)
+            {
+                var x = worker.orgs[worker.off_orgs + i].x;
+                if ( x <= org1 )
+                    x += delta1;
+                else
+                    x += delta2;
+
+                worker.curs[worker.off_curs + i].x = x;
+            }
+        }
+        else
+        {
+            var scale = 0;
+            var scale_valid = 0;
+
+            /* interpolation */
+            for (var i = p1; i <= p2; i++)
+            {
+                var x = worker.orgs[worker.off_orgs + i].x;
+
+                if ( x <= org1 )
+                    x += delta1;
+                else if ( x >= org2 )
+                    x += delta2;
+                else
+                {
+                    if ( !scale_valid )
+                    {
+                        scale_valid = 1;
+                        scale = FT_DivFix(org2 + delta2 - (org1 + delta1), orus2 - orus1);
+                    }
+
+                    x = (org1 + delta1) + FT_MulFix(worker.orus[worker.off_orus + i].x - orus1, scale);
+                }
+                worker.curs[worker.off_curs + i].x = x;
+            }
+        }
+    }
+    else
+    {
+        if (p1 > p2)
+            return;
+
+        if ((ref1 >= worker.max_points) || (ref2 >= worker.max_points))
+            return;
+
+        var orus1 = worker.orus[worker.off_orus + ref1].y;
+        var orus2 = worker.orus[worker.off_orus + ref2].y;
+
+        if (orus1 > orus2)
+        {
+            var tmp_o = orus1;
+            orus1 = orus2;
+            orus2 = tmp_o;
+
+            var tmp_r = ref1;
+            ref1  = ref2;
+            ref2  = tmp_r;
+        }
+
+        var org1   = worker.orgs[worker.off_orgs + ref1].y;
+        var org2   = worker.orgs[worker.off_orgs + ref2].y;
+        var delta1 = worker.curs[worker.off_curs + ref1].y - org1;
+        var delta2 = worker.curs[worker.off_curs + ref2].y - org2;
+
+        if (orus1 == orus2)
+        {
+            /* simple shift of untouched points */
+            for (var i = p1; i <= p2; i++)
+            {
+                var y = worker.orgs[worker.off_orgs + i].y;
+                if (y <= org1)
+                    y += delta1;
+                else
+                    y += delta2;
+
+                worker.curs[worker.off_curs + i].y = y;
+            }
+        }
+        else
+        {
+            var scale = 0;
+            var scale_valid = 0;
+
+            /* interpolation */
+            for (var i = p1; i <= p2; i++)
+            {
+                var y = worker.orgs[worker.off_orgs + i].y;
+
+                if (y <= org1)
+                    y += delta1;
+                else if (y >= org2)
+                    y += delta2;
+                else
+                {
+                    if ( !scale_valid )
+                    {
+                        scale_valid = 1;
+                        scale = FT_DivFix(org2 + delta2 - (org1 + delta1), orus2 - orus1);
+                    }
+
+                    y = (org1 + delta1) + FT_MulFix(worker.orus[worker.off_orus + i].y - orus1, scale);
+                }
+                worker.curs[worker.off_curs + i].y = y;
+            }
+        }
+    }
+}
+// --
+
+function Ins_IUP(exc, args, args_pos)
+{
+    var mask;
+
+    /* ignore empty outlines */
+    if (exc.pts.n_contours == 0)
+        return;
+
+    var V = new IUP_WorkerRec();
+    if (exc.opcode & 1)
+    {
+        mask   = FT_Common.FT_CURVE_TAG_TOUCH_X;
+        V.orgs = exc.pts.org;
+        V.curs = exc.pts.cur;
+        V.orus = exc.pts.orus;
+
+        V.off_orgs = exc.pts._offset_org;
+        V.off_curs = exc.pts._offset_cur;
+        V.off_orus = exc.pts._offset_orus;
+    }
+    else
+    {
+        mask = FT_Common.FT_CURVE_TAG_TOUCH_Y;
+
+        V.orgs = exc.pts.org;
+        V.curs = exc.pts.cur;
+        V.orus = exc.pts.orus;
+
+        V.off_orgs = exc.pts._offset_org;
+        V.off_curs = exc.pts._offset_cur;
+        V.off_orus = exc.pts._offset_orus;
+        V.is_offset_one = true;
+    }
+    V.max_points = exc.pts.n_points;
+
+    var contour = 0;
+    var point   = 0;
+
+    if (exc.face.driver.library.tt_hint_props.TT_CONFIG_OPTION_SUBPIXEL_HINTING) // #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+    {
+        if (exc.ignore_x_mode)
+        {
+            exc.iup_called = 1;
+            if (exc.sph_tweak_flags & FT_Common.SPH_TWEAK_SKIP_IUP)
+                return;
+        }
+    } //#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+
+    do
+    {
+        var end_point   = exc.pts.contours[exc.pts._offset_contours + contour] - exc.pts.first_point;
+        var first_point = point;
+
+        if (end_point >= exc.pts.n_points)
+            end_point = exc.pts.n_points - 1;
+
+        while (point <= end_point && (exc.pts.tags[exc.pts._offset_tags + point] & mask) == 0)
+            point++;
+
+        if ( point <= end_point )
+        {
+            var first_touched = point;
+            var cur_touched   = point;
+
+            point++;
+
+            while ( point <= end_point )
+            {
+                if ((exc.pts.tags[exc.pts._offset_tags + point] & mask) != 0)
+                {
+                    _iup_worker_interpolate(V, cur_touched + 1, point - 1, cur_touched, point);
+                    cur_touched = point;
+                }
+
+                point++;
+            }
+
+            if (cur_touched == first_touched)
+                _iup_worker_shift(V, first_point, end_point, cur_touched);
+            else
+            {
+                _iup_worker_interpolate(V, 0xFFFF & (cur_touched + 1), end_point, cur_touched, first_touched);
+
+                if (first_touched > 0)
+                    _iup_worker_interpolate(V, first_point, first_touched - 1, cur_touched, first_touched);
+            }
+        }
+        contour++;
+    } while (contour < exc.pts.n_contours);
+}
+
+function Ins_SHP(exc, args, args_pos)
+{
+    if (exc.top < exc.GS.loop)
+    {
+        if (exc.pedantic_hinting)
+            exc.error = FT_Common.FT_Err_Invalid_Reference;
+
+        exc.GS.loop = 1;
+        exc.new_top = exc.args;
+    }
+
+    var zp = new TT_GlyphZoneRec();
+
+    var dx, dy, refp;
+    var ret = Compute_Point_Displacement(exc, dx, dy, zp, refp);
+    if (ret.err == 1)
+        return;
+
+    dx = ret.x;
+    dy = ret.y;
+    refp = ret.refp;
+    while (exc.GS.loop > 0)
+    {
+        exc.args--;
+        var point = 0xFFFF & exc.stack[exc.args];
+
+        if (point >= exc.zp2.n_points)
+        {
+            if (exc.pedantic_hinting)
+            {
+                exc.error = FT_Common.FT_Err_Invalid_Reference;
+                return;
+            }
+        }
+        else
+            Move_Zp2_Point(exc, point, dx, dy, true);
+
+        exc.GS.loop--;
+    }
+
+    exc.GS.loop = 1;
+    exc.new_top = exc.args;
+}
+
+function Ins_SHC(exc, args, args_pos)
+{
+    var contour = 0xFFFF & args[args_pos];
+    var bounds  = (exc.GS.gep2 == 0) ? 1 : exc.zp2.n_contours;
+
+    if (contour >= bounds)
+    {
+        if (exc.pedantic_hinting)
+            exc.error = FT_Common.FT_Err_Invalid_Reference;
+        return;
+    }
+
+    var zp = new TT_GlyphZoneRec();
+
+    var dx, dy, refp;
+    var ret = Compute_Point_Displacement(exc, dx, dy, zp, refp);
+    if (ret.err == 1)
+        return;
+
+    dx = ret.x;
+    dy = ret.y;
+    refp = ret.refp;
+
+    var start, limit;
+    if (contour == 0)
+        start = 0;
+    else
+        start = 0xFFFF & (exc.zp2.contours[exc.zp2._offset_contours + contour - 1] + 1 - exc.zp2.first_point);
+
+    /* we use the number of points if in the twilight zone */
+    if (exc.GS.gep2 == 0)
+        limit = exc.zp2.n_points;
+    else
+        limit = 0xFFFF & (exc.zp2.contours[exc.zp2._offset_contours + contour] - exc.zp2.first_point + 1);
+
+    for (var i = start; i < limit; i++)
+    {
+        if ((zp.cur != exc.zp2.cur || zp._offset_cur != exc.zp2._offset_cur) || refp != i)
+            Move_Zp2_Point(exc, i, dx, dy, true);
+    }
+}
+
+function Ins_SHZ(exc, args, args_pos)
+{
+    if (args[args_pos] >= 2)
+    {
+        if (exc.pedantic_hinting)
+            exc.error = FT_Common.FT_Err_Invalid_Reference;
+        return;
+    }
+
+    var zp = new TT_GlyphZoneRec();
+
+    var dx, dy, refp;
+    var ret = Compute_Point_Displacement(exc, dx, dy, zp, refp);
+    if (ret.err == 1)
+        return;
+
+    dx = ret.x;
+    dy = ret.y;
+    refp = ret.refp;
+
+    /* XXX: UNDOCUMENTED! SHZ doesn't move the phantom points.     */
+    /*      Twilight zone has no real contours, so use `n_points'. */
+    /*      Normal zone's `n_points' includes phantoms, so must    */
+    /*      use end of last contour.                               */
+    var limit = 0;
+    if (exc.GS.gep2 == 0)
+        limit = 0xFFFF & exc.zp2.n_points;
+    else if (exc.GS.gep2 == 1 && exc.zp2.n_contours > 0)
+        limit = 0xFFFF & (exc.zp2.contours[exc.zp2._offset_contours + exc.zp2.n_contours - 1] + 1);
+
+    /* XXX: UNDOCUMENTED! SHZ doesn't touch the points */
+    for (var i = 0; i < limit; i++)
+    {
+        if ((zp.cur != exc.zp2.cur || zp._offset_cur != exc.zp2._offset_cur) || refp != i)
+            Move_Zp2_Point(exc, i, dx, dy, false);
+    }
+}
+
+function Ins_SHPIX(exc, args, args_pos)
+{
+    if (exc.top < (exc.GS.loop + 1))
+    {
+        if (exc.pedantic_hinting)
+            exc.error = FT_Common.FT_Err_Invalid_Reference;
+
+        exc.GS.loop = 1;
+        exc.new_top = exc.args;
+        return;
+    }
+
+    // TODO: unpatented
+    var dx = TT_MulFix14(args[args_pos], exc.GS.freeVector.x);
+    var dy = TT_MulFix14(args[args_pos], exc.GS.freeVector.y);
+
+    while (exc.GS.loop > 0)
+    {
+        exc.args--;
+        var point = 0xFFFF & exc.stack[exc.args];
+
+        if (point >= exc.zp2.n_points)
+        {
+            if (exc.pedantic_hinting)
+            {
+                exc.error = FT_Common.FT_Err_Invalid_Reference;
+                return;
+            }
+        }
+        else
+        {
+            if (!exc.face.driver.library.tt_hint_props.TT_CONFIG_OPTION_SUBPIXEL_HINTING)
+            {
+                Move_Zp2_Point(exc, point, dx, dy, true);
+                exc.GS.loop -= 1;
+                continue;
+            }
+
+            var B1, B2;
+            if (exc.ignore_x_mode)
+            {
+                /* save point for later comparison */
+                if (exc.GS.freeVector.y != 0)
+                    B1 = exc.zp2.cur[exc.zp2._offset_cur + point].y;
+                else
+                    B1 = exc.zp2.cur[exc.zp2._offset_cur + point].x;
+
+                if (exc.GS.freeVector.y != 0 && (exc.sph_tweak_flags & FT_Common.SPH_TWEAK_SKIP_INLINE_DELTAS))
+                {
+                    exc.GS.loop--;
+                    continue;
+                }
+
+                if (exc.ignore_x_mode && !exc.compatibility_mode && exc.GS.freeVector.y != 0)
+                    Move_Zp2_Point(exc, point, dx, dy, true);
+                else if (exc.ignore_x_mode && exc.compatibility_mode)
+                {
+                    if (exc.ignore_x_mode && (exc.sph_tweak_flags & FT_Common.SPH_TWEAK_ROUND_NONPIXEL_Y_MOVES))
+                    {
+                        dx = FT_PIX_ROUND( B1 + dx ) - B1;
+                        dy = FT_PIX_ROUND( B1 + dy ) - B1;
+                    }
+
+                    if (!(exc.sph_tweak_flags & FT_Common.SPH_TWEAK_ALWAYS_SKIP_DELTAP) &&
+                        ((exc.is_composite && exc.GS.freeVector.y != 0) ||
+                        (exc.zp2.tags[exc.zp2._offset_tags + point] & FT_Common.FT_CURVE_TAG_TOUCH_Y) ||
+                        (exc.sph_tweak_flags & FT_Common.SPH_TWEAK_DO_SHPIX)))
+                        Move_Zp2_Point(exc, point, dx, dy, true);
+                }
+
+                /* save new point */
+                if (exc.GS.freeVector.y != 0)
+                    B2 = exc.zp2.cur[exc.zp2._offset_cur + point].y;
+                else
+                    B2 = exc.zp2.cur[exc.zp2._offset_cur + point].x;
+
+                /* reverse any disallowed moves */
+                if (((exc.sph_tweak_flags & FT_Common.SPH_TWEAK_SKIP_NONPIXEL_Y_MOVES) &&
+                     exc.GS.freeVector.y != 0 &&
+                     B1 % 64 != 0  &&
+                     B2 % 64 != 0  &&
+                     B1 != B2 ) ||
+                   ((exc.sph_tweak_flags & FT_Common.SPH_TWEAK_SKIP_OFFPIXEL_Y_MOVES) &&
+                     exc.GS.freeVector.y != 0 &&
+                     B1 % 64 == 0 &&
+                     B2 % 64 != 0 &&
+                     B1 != B2 &&
+                     !exc.size.ttfautohinted))
+                {
+                    Move_Zp2_Point(exc, point, -dx, -dy, true);
+                }
+            }
+            else
+                Move_Zp2_Point(exc, point, dx, dy, true);
+
+            exc.GS.loop--;
+        }
+    }
+
+    exc.GS.loop = 1;
+    exc.new_top = exc.args;
+}
+
+function Ins_IP(exc, args, args_pos)
+{
+    if (exc.top < exc.GS.loop)
+    {
+        if (exc.pedantic_hinting)
+            exc.error = FT_Common.FT_Err_Invalid_Reference;
+
+        exc.GS.loop = 1;
+        exc.new_top = exc.args;
+        return;
+    }
+
+    /*
+     * We need to deal in a special way with the twilight zone.
+     * Otherwise, by definition, the value of CUR.twilight.orus[n] is (0,0),
+     * for every n.
+     */
+    var twilight = (exc.GS.gep0 == 0 || exc.GS.gep1 == 0 || exc.GS.gep2 == 0) ? 1 : 0;
+
+    if (exc.GS.rp1 >= exc.zp0.n_points)
+    {
+        if (exc.pedantic_hinting)
+            exc.error = FT_Common.FT_Err_Invalid_Reference;
+
+        exc.GS.loop = 1;
+        exc.new_top = exc.args;
+        return;
+    }
+
+    var orus_base = null;
+    var orus_base_off = 0;
+    if (twilight)
+    {
+        orus_base = exc.zp0.org;
+        orus_base_off = exc.zp0._offset_org + exc.GS.rp1;
+    }
+    else
+    {
+        orus_base = exc.zp0.orus;
+        orus_base_off = exc.zp0._offset_orus + exc.GS.rp1;
+    }
+
+    var cur_base = exc.zp0.cur;
+    var cur_base_off = exc.zp0._offset_cur + exc.GS.rp1;
+
+    var old_range = 0;
+    var cur_range = 0;
+
+    /* XXX: There are some glyphs in some braindead but popular */
+    /*      fonts out there (e.g. [aeu]grave in monotype.ttf)   */
+    /*      calling IP[] with bad values of rp[12].             */
+    /*      Do something sane when this odd thing happens.      */
+    if ((exc.GS.rp1 >= exc.zp0.n_points) || (exc.GS.rp2 >= exc.zp1.n_points))
+    {
+        old_range = 0;
+        cur_range = 0;
+    }
+    else
+    {
+        var v1, v2;
+        if (twilight != 0)
+        {
+            v1 = exc.zp1.org[exc.zp1._offset_org + exc.GS.rp2];
+            v2 = orus_base[orus_base_off];
+            old_range = exc.func_dualproj(exc, v1.x - v2.x, v1.y - v2.y);
+        }
+        else if (exc.metrics.x_scale == exc.metrics.y_scale)
+        {
+            v1 = exc.zp1.orus[exc.zp1._offset_orus + exc.GS.rp2];
+            v2 = orus_base[orus_base_off];
+            old_range = exc.func_dualproj(exc, v1.x - v2.x, v1.y - v2.y);
+        }
+        else
+        {
+            v1 = exc.zp1.orus[exc.zp1._offset_orus + exc.GS.rp2];
+            v2 = orus_base[orus_base_off];
+
+            var _x = FT_MulFix(v1.x - v2.x, exc.metrics.x_scale);
+            var _y = FT_MulFix(v1.y - v2.y, exc.metrics.y_scale);
+
+            old_range = exc.func_dualproj(exc, _x, _y);
+        }
+
+        v1 = exc.zp1.cur[exc.zp1._offset_cur + exc.GS.rp2];
+        v2 = cur_base[cur_base_off];
+
+        cur_range = exc.func_project(exc, v1.x - v2.x, v1.y - v2.y);
+    }
+
+    for ( ; exc.GS.loop > 0; --exc.GS.loop )
+    {
+        var point = exc.stack[--exc.args];
+        var org_dist, cur_dist, new_dist;
+
+        /* check point bounds */
+        if (point >= exc.zp2.n_points)
+        {
+            if (exc.pedantic_hinting)
+            {
+                exc.error = FT_Common.FT_Err_Invalid_Reference;
+                return;
+            }
+            continue;
+        }
+
+        var v1, v2;
+        if (twilight)
+        {
+            v1 = exc.zp2.org[exc.zp2._offset_org + point];
+            v2 = orus_base[orus_base_off];
+            org_dist = exc.func_dualproj(exc, v1.x - v2.x, v1.y - v2.y);
+        }
+        else if ( exc.metrics.x_scale == exc.metrics.y_scale )
+        {
+            v1 = exc.zp2.orus[exc.zp2._offset_orus + point];
+            v2 = orus_base[orus_base_off];
+            org_dist = exc.func_dualproj(exc, v1.x - v2.x, v1.y - v2.y);
+        }
+        else
+        {
+            v1 = exc.zp2.orus[exc.zp2._offset_orus + point];
+            v2 = orus_base[orus_base_off];
+
+            var _x = FT_MulFix(v1.x - v2.x, exc.metrics.x_scale);
+            var _y = FT_MulFix(v1.y - v2.y, exc.metrics.y_scale);
+
+            org_dist = exc.func_dualproj(exc, _x, _y);
+        }
+
+        v1 = exc.zp2.cur[exc.zp2._offset_cur + point];
+        v2 = cur_base[cur_base_off];
+        cur_dist = exc.func_project(exc, v1.x - v2.x, v1.y - v2.y);
+
+        if (org_dist != 0)
+            new_dist = (old_range != 0) ? FT_MulDiv(org_dist, cur_range, old_range) : cur_dist;
+        else
+            new_dist = 0;
+
+        exc.func_move(exc, exc.zp2, 0xFFFF & point, new_dist - cur_dist);
+    }
+
+    exc.GS.loop = 1;
+    exc.new_top = exc.args;
+}
+
+function Ins_MSIRP(exc, args, args_pos)
+{
+    var control_value_cutin = 0;
+
+    if (exc.face.driver.library.tt_hint_props.TT_CONFIG_OPTION_SUBPIXEL_HINTING)
+    {
+        control_value_cutin = exc.GS.control_value_cutin;
+        if (exc.ignore_x_mode && exc.GS.freeVector.x != 0 && ((exc.sph_tweak_flags & FT_Common.SPH_TWEAK_NORMAL_ROUND) == 0))
+            control_value_cutin = 0;
+    }
+
+    var point = 0xFFFF & args[args_pos];
+
+    if ((point >= exc.zp1.n_points) || (exc.GS.rp0 >= exc.zp0.n_points))
+    {
+        if (exc.pedantic_hinting)
+            exc.error = FT_Common.FT_Err_Invalid_Reference;
+        return;
+    }
+
+    /* UNDOCUMENTED!  The MS rasterizer does that with */
+    /* twilight points (confirmed by Greg Hitchcock)   */
+    if (exc.GS.gep1 == 0)
+    {
+        exc.zp1.org[exc.zp1._offset_org + point] = exc.zp0.org[exc.zp0._offset_org + exc.GS.rp0];
+        exc.func_move_orig(exc, exc.zp1, point, args[args_pos + 1]);
+        exc.zp1.cur[exc.zp1._offset_cur + point] = exc.zp1.org[exc.zp1._offset_org + point];
+    }
+
+    var v1 = exc.zp1.cur[exc.zp1._offset_cur + point];
+    var v2 = exc.zp0.cur[exc.zp0._offset_cur + exc.GS.rp0];
+    var distance = exc.func_project(exc, v1.x - v2.x, v1.y - v2.y);
+
+    if (exc.face.driver.library.tt_hint_props.TT_CONFIG_OPTION_SUBPIXEL_HINTING) // #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+    {
+        control_value_cutin = exc.GS.control_value_cutin;
+        if (exc.ignore_x_mode && exc.GS.freeVector.x != 0 && (Math.abs(distance - args[args_pos + 1]) >= control_value_cutin))
+            distance = args[args_pos + 1];
+    } // #endif
+
+    exc.func_move(exc, exc.zp1, point, args[args_pos + 1] - distance);
+
+    exc.GS.rp1 = exc.GS.rp0;
+    exc.GS.rp2 = point;
+
+    if ((exc.opcode & 1 ) != 0)
+        exc.GS.rp0 = point;
+}
+
+function Ins_ALIGNRP(exc, args, args_pos)
+{
+    if (exc.face.driver.library.tt_hint_props.TT_CONFIG_OPTION_SUBPIXEL_HINTING)//#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+    {
+        if (exc.ignore_x_mode && exc.iup_called && (exc.sph_tweak_flags & FT_Common.SPH_TWEAK_NO_ALIGNRP_AFTER_IUP) != 0)
+        {
+            exc.error = FT_Common.FT_Err_Invalid_Reference;
+            exc.GS.loop = 1;
+            exc.new_top = exc.args;
+            return;
+        }
+    } // #endif
+
+    if (exc.top < exc.GS.loop || (exc.GS.rp0 >= exc.zp0.n_points))
+    {
+        if (exc.pedantic_hinting)
+            exc.error = FT_Common.FT_Err_Invalid_Reference;
+
+        exc.GS.loop = 1;
+        exc.new_top = exc.args;
+        return;
+    }
+
+    while (exc.GS.loop > 0)
+    {
+        exc.args--;
+        var point = 0xFFFF & exc.stack[exc.args];
+
+        if (point >= exc.zp1.n_points)
+        {
+            if (exc.pedantic_hinting)
+            {
+                exc.error = FT_Common.FT_Err_Invalid_Reference;
+                return;
+            }
+        }
+        else
+        {
+            var v1 = exc.zp1.cur[exc.zp1._offset_cur + point];
+            var v2 = exc.zp0.cur[exc.zp0._offset_cur + exc.GS.rp0];
+            var distance = exc.func_project(exc, v1.x - v2.x, v1.y - v2.y);
+
+            exc.func_move(exc, exc.zp1, point, -distance);
+        }
+        exc.GS.loop--;
+    }
+
+    exc.GS.loop = 1;
+    exc.new_top = exc.args;
+}
+
+function Ins_RTDG(exc, args, args_pos)
+{
+    exc.GS.round_state = TT_Round_To_Double_Grid;
+    exc.func_round = Round_To_Double_Grid;
+}
+
+function Ins_MIAP(exc, args, args_pos)
+{
+    var control_value_cutin = exc.GS.control_value_cutin;
+    var cvtEntry            = FT_Common.IntToUInt(args[args_pos + 1]);
+    var point               = 0xFFFF & args[args_pos];
+
+    var bIsSubpix = exc.face.driver.library.tt_hint_props.TT_CONFIG_OPTION_SUBPIXEL_HINTING;
+    if (bIsSubpix) // #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+    {
+        if (exc.ignore_x_mode && exc.GS.freeVector.x != 0 && (exc.sph_tweak_flags & FT_Common.SPH_TWEAK_NORMAL_ROUND) == 0)
+            control_value_cutin = 0;
+    } // #endif
+
+    if ((point >= exc.zp0.n_points) || (cvtEntry >= exc.cvtSize))
+    {
+        if (exc.pedantic_hinting)
+            exc.error = FT_Common.FT_Err_Invalid_Reference;
+
+        exc.GS.rp0 = point;
+        exc.GS.rp1 = point;
+        return;
+    }
+
+    /* UNDOCUMENTED!                                                      */
+    /*                                                                    */
+    /* The behaviour of an MIAP instruction is quite different when used  */
+    /* in the twilight zone.                                              */
+    /*                                                                    */
+    /* First, no control value cut-in test is performed as it would fail  */
+    /* anyway.  Second, the original point, i.e. (org_x,org_y) of         */
+    /* zp0.point, is set to the absolute, unrounded distance found in the */
+    /* CVT.                                                               */
+    /*                                                                    */
+    /* This is used in the CVT programs of the Microsoft fonts Arial,     */
+    /* Times, etc., in order to re-adjust some key font heights.  It      */
+    /* allows the use of the IP instruction in the twilight zone, which   */
+    /* otherwise would be invalid according to the specification.         */
+    /*                                                                    */
+    /* We implement it with a special sequence for the twilight zone.     */
+    /* This is a bad hack, but it seems to work.                          */
+    /*                                                                    */
+    /* Confirmed by Greg Hitchcock.                                       */
+
+    var distance = exc.func_read_cvt(exc, cvtEntry);
+
+    if (exc.GS.gep0 == 0)   /* If in twilight zone */
+    {
+        if (bIsSubpix)
+        {
+            if (exc.compatibility_mode)
+                exc.zp0.org[exc.zp0._offset_org + point].x = TT_MulFix14(distance, exc.GS.freeVector.x);
+        }
+        else
+        {
+            exc.zp0.org[exc.zp0._offset_org + point].x = TT_MulFix14(distance, exc.GS.freeVector.x);
+        }
+
+        exc.zp0.org[exc.zp0._offset_org + point].y = TT_MulFix14(distance, exc.GS.freeVector.y),
+        exc.zp0.cur[exc.zp0._offset_cur + point].x = exc.zp0.org[exc.zp0._offset_org + point].x;
+        exc.zp0.cur[exc.zp0._offset_cur + point].y = exc.zp0.org[exc.zp0._offset_org + point].y;
+    }
+
+    if (bIsSubpix)
+    {
+        if ((exc.sph_tweak_flags & FT_Common.SPH_TWEAK_MIAP_HACK) != 0 && distance > 0 && exc.GS.freeVector.y != 0)
+            distance = 0;
+    }
+
+    var v = exc.zp0.cur[exc.zp0._offset_cur + point];
+    var org_dist = exc.func_project(exc, v.x, v.y);
+
+    if ((exc.opcode & 1) != 0)   /* rounding and control cut-in flag */
+    {
+        if (Math.abs( distance - org_dist) > control_value_cutin)
+            distance = org_dist;
+
+        if (bIsSubpix)
+        {
+            if (exc.ignore_x_mode && exc.GS.freeVector.x != 0)
+                distance = Round_None(exc, distance, exc.tt_metrics.compensations[0]);
+            else
+                distance = exc.func_round(exc, distance, exc.tt_metrics.compensations[0]);
+        }
+        else
+        {
+            distance = exc.func_round(exc, distance, exc.tt_metrics.compensations[0]);
+        }
+    }
+
+    exc.func_move(exc, exc.zp0, point, distance - org_dist);
+    
+    exc.GS.rp0 = point;
+    exc.GS.rp1 = point;
+}
+
+function Ins_NPUSHB(exc, args, args_pos)
+{
+    var L = exc.code.data[exc.code.pos + exc.IP + 1];
+
+    if (L >= (exc.stackSize + 1 - exc.top))
+    {
+        exc.error = FT_Common.FT_Err_Stack_Overflow;
+        return;
+    }
+
+    for (var K = 1; K <= L; K++)
+        args[args_pos + K - 1] = exc.code.data[exc.code.pos + exc.IP + K + 1];
+
+    exc.new_top += L;
+}
+
+// --
+function GetShortIns(exc)
+{
+    /* Reading a byte stream so there is no endianess (DaveP) */
+    exc.IP += 2;
+    return FT_Common.UShort_To_Short((exc.code.data[exc.code.pos + exc.IP - 2] << 8) + exc.code.data[exc.code.pos + exc.IP - 1]);
+}
+// --
+
+function Ins_NPUSHW(exc, args, args_pos)
+{
+    var L = exc.code.data[exc.code.pos + exc.IP + 1];
+
+    if (L >=  (exc.stackSize + 1 - exc.top))
+    {
+        exc.error = FT_Common.FT_Err_Stack_Overflow;
+        return;
+    }
+
+    exc.IP += 2;
+
+    for (var K = 0; K < L; K++)
+        args[args_pos + K] = GetShortIns(exc);
+
+    exc.step_ins = false;
+    exc.new_top += L;
+}
+
+function Ins_WS(exc, args, args_pos)
+{
+    var I = args[args_pos];
+    if (I >= exc.storeSize)
+    {
+        if (exc.pedantic_hinting)
+        {
+            exc.error = FT_Common.FT_Err_Invalid_Reference;
+            return;
+        }
+    }
+    else
+        exc.storage[I] = args[args_pos + 1];
+}
+
+function Ins_RS(exc, args, args_pos)
+{
+    if (exc.face.driver.library.tt_hint_props.TT_CONFIG_OPTION_SUBPIXEL_HINTING)
+    {
+        var I = FT_Common.IntToUInt(args[args_pos]);
+        if (I >= exc.storeSize)
+        {
+            if (exc.pedantic_hinting)
+            {
+                exc.error = FT_Common.FT_Err_Invalid_Reference;
+                return;
+            }
+            else
+                args[args_pos] = 0;
+        }
+        else
+        {
+            /* subpixel hinting - avoid Typeman Dstroke and */
+            /* IStroke and Vacuform rounds                  */
+
+            if (exc.compatibility_mode && (I == 24 || I == 22 || I == 8))
+                args[args_pos] = 0;
+            else
+                args[args_pos] = exc.storage[I];
+        }
+    }
+    else
+    {
+        var I = FT_Common.IntToUInt(args[args_pos]);
+
+        if (I >= exc.storeSize)
+        {
+            if (exc.pedantic_hinting)
+            {
+                exc.error = FT_Common.FT_Err_Invalid_Reference;
+                return;
+            }
+            else
+                args[args_pos] = 0;
+        }
+        else
+            args[args_pos] = exc.storage[I];
+    }
+}
+
+function Ins_WCVTP(exc, args, args_pos)
+{
+    var I = args[args_pos];
+    if (I >= exc.cvtSize)
+    {
+        if (exc.pedantic_hinting)
+        {
+            exc.error = FT_Common.FT_Err_Invalid_Reference;
+            return;
+        }
+    }
+    else
+        exc.func_write_cvt(exc, I, args[args_pos + 1]);
+}
+
+function Ins_RCVT(exc, args, args_pos)
+{
+    var I = args[args_pos];
+    if (I >= exc.cvtSize)
+    {
+        if (exc.pedantic_hinting)
+        {
+            exc.error = FT_Common.FT_Err_Invalid_Reference;
+            return;
+        }
+        else
+            args[args_pos] = 0;
+    }
+    else
+       args[args_pos] = exc.func_read_cvt(exc, I);
+}
+
+function Ins_GC(exc, args, args_pos)
+{
+    var L = args[args_pos];
+    var R = 0;
+    if (L >= exc.zp2.n_points)
+    {
+        if (exc.pedantic_hinting)
+            exc.error = FT_Common.FT_Err_Invalid_Reference;
+    }
+    else
+    {
+        if (exc.opcode & 1)
+            R = exc.func_dualproj(exc, exc.zp2.org[exc.zp2._offset_org + L].x, exc.zp2.org[exc.zp2._offset_org + L].y);
+        else
+            R = exc.func_project(exc, exc.zp2.cur[exc.zp2._offset_cur + L].x, exc.zp2.cur[exc.zp2._offset_cur + L].y);
+    }
+
+    args[args_pos] = R;
+}
+
+function Ins_SCFS(exc, args, args_pos)
+{
+    var L = 0xFFFF & args[args_pos];
+
+    if (L >= exc.zp2.n_points)
+    {
+        if (exc.pedantic_hinting)
+            exc.error = FT_Common.FT_Err_Invalid_Reference;
+        return;
+    }
+
+    var K = exc.func_project(exc, exc.zp2.cur[exc.zp2._offset_cur + L].x, exc.zp2.cur[exc.zp2._offset_cur + L].y);
+
+    exc.func_move(exc, exc.zp2, L, args[args_pos + 1] - K);
+
+    /* UNDOCUMENTED!  The MS rasterizer does that with */
+    /* twilight points (confirmed by Greg Hitchcock)   */
+    if (exc.GS.gep2 == 0)
+    {
+        exc.zp2.org[exc.zp2._offset_org + L].x = exc.zp2.cur[exc.zp2._offset_cur + L].x;
+        exc.zp2.org[exc.zp2._offset_org + L].y = exc.zp2.cur[exc.zp2._offset_cur + L].y;
+    }
+}
+
+function Ins_MD(exc, args, args_pos)
+{
+    var D = 0;
+    var K = 0xFFFF & args[args_pos + 1];
+    var L = 0xFFFF & args[args_pos];
+
+    if ((L >= exc.zp0.n_points) || (K >= exc.zp1.n_points))
+    {
+        if (exc.pedantic_hinting)
+            exc.error = FT_Common.FT_Err_Invalid_Reference;
+        D = 0;
+    }
+    else
+    {
+        if (exc.opcode & 1)
+        {
+            var vec1 = exc.zp0.cur[exc.zp0._offset_cur + L];
+            var vec2 = exc.zp1.cur[exc.zp1._offset_cur + K];
+
+            D = exc.func_project(exc, vec1.x - vec2.x, vec1.y - vec2.y);
+        }
+        else
+        {
+            /* XXX: UNDOCUMENTED: twilight zone special case */
+            if (exc.GS.gep0 == 0 || exc.GS.gep1 == 0)
+            {
+                var vec1 = exc.zp0.org[exc.zp0._offset_org + L];
+                var vec2 = exc.zp1.org[exc.zp1._offset_org + K];
+
+                D = exc.func_dualproj(exc, vec1.x - vec2.x, vec1.y - vec2.y);
+            }
+            else
+            {
+                var vec1 = exc.zp0.orus[exc.zp0._offset_orus + L];
+                var vec2 = exc.zp1.orus[exc.zp1._offset_orus + K];
+
+                if ( exc.metrics.x_scale == exc.metrics.y_scale )
+                {
+                    /* this should be faster */
+                    D = exc.func_dualproj(exc, vec1.x - vec2.x, vec1.y - vec2.y);
+                    D = FT_MulFix(D, exc.metrics.x_scale);
+                }
+                else
+                {
+                    var vec = new FT_Vector();
+                    vec.x = FT_MulFix(vec1.x - vec2.x, exc.metrics.x_scale);
+                    vec.y = FT_MulFix(vec1.y - vec2.y, exc.metrics.y_scale);
+
+                    D = exc.func_dualproj(exc, vec.x, vec.y);
+                }
+            }
+        }
+    }
+
+    if (exc.face.driver.library.tt_hint_props.TT_CONFIG_OPTION_SUBPIXEL_HINTING)//#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+    {
+        /* Disable Type 2 Vacuform Rounds - e.g. Arial Narrow */
+        if (exc.ignore_x_mode && Math.abs(D) == 64)
+            D += 1;
+    } //#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+
+    args[args_pos] = D;
+}
+
+// --
+function Current_Ppem(exc)
+{
+    return FT_MulFix(exc.tt_metrics.ppem, Current_Ratio(exc));
+}
+
+function Current_Ratio(exc)
+{
+    if (!exc.tt_metrics.ratio)
+    {
+        // TODO: unpatented
+        if (exc.GS.projVector.y == 0)
+            exc.tt_metrics.ratio = exc.tt_metrics.x_ratio;
+        else if (exc.GS.projVector.x == 0)
+            exc.tt_metrics.ratio = exc.tt_metrics.y_ratio;
+        else
+        {
+            var x = TT_MulFix14(exc.tt_metrics.x_ratio, exc.GS.projVector.x);
+            var y = TT_MulFix14(exc.tt_metrics.y_ratio, exc.GS.projVector.y);
+            exc.tt_metrics.ratio = TT_VecLen(x, y);
+        }
+    }
+    return exc.tt_metrics.ratio;
+}
+
+function FT_MulDiv_No_Round(a, b, c)
+{
+    var s = 1;
+    if ( a < 0 ) { a = -a; s = -1; }
+    if ( b < 0 ) { b = -b; s = -s; }
+    if ( c < 0 ) { c = -c; s = -s; }
+
+    var d = (c > 0 ? a * b / c : 0x7FFFFFFF);
+    d = d >> 0;
+
+    return ( s > 0 ) ? d : -d;
+}
+// --
+
+function Ins_MPPEM(exc, args, args_pos)
+{
+    args[args_pos] = Current_Ppem(exc);
+}
+
+function Ins_MPS(exc, args, args_pos)
+{
+    args[args_pos] = Current_Ppem(exc);
+}
+
+function Ins_FLIPON(exc, args, args_pos)
+{
+    exc.GS.auto_flip = true;
+}
+
+function Ins_FLIPOFF(exc, args, args_pos)
+{
+    exc.GS.auto_flip = false;
+}
+
+function Ins_DEBUG(exc, args, args_pos)
+{
+    exc.error = FT_Common.FT_Err_Debug_OpCode;
+}
+
+function Ins_LT(exc, args, args_pos)
+{
+    args[args_pos] = (args[args_pos] < args[args_pos + 1]) ? 1 : 0;
+}
+function Ins_LTEQ(exc, args, args_pos)
+{
+    args[args_pos] = (args[args_pos] <= args[args_pos + 1]) ? 1 : 0;
+}
+function Ins_GT(exc, args, args_pos)
+{
+    args[args_pos] = (args[args_pos] > args[args_pos + 1]) ? 1 : 0;
+}
+function Ins_GTEQ(exc, args, args_pos)
+{
+    args[args_pos] = (args[args_pos] >= args[args_pos + 1]) ? 1 : 0;
+}
+function Ins_EQ(exc, args, args_pos)
+{
+    args[args_pos] = (args[args_pos] == args[args_pos + 1]) ? 1 : 0;
+}
+function Ins_NEQ(exc, args, args_pos)
+{
+    args[args_pos] = (args[args_pos] != args[args_pos + 1]) ? 1 : 0;
+}
+function Ins_ODD(exc, args, args_pos)
+{
+    args[args_pos] = ((exc.func_round(exc, args[args_pos], 0) & 127) == 64) ? 1 : 0;
+}
+function Ins_EVEN(exc, args, args_pos)
+{
+    args[args_pos] = ((exc.func_round(exc, args[args_pos], 0) & 127) == 64) ? 1 : 0;
+}
+function Ins_IF(exc, args, args_pos)
+{
+    if (args[args_pos] != 0)
+        return;
+
+    var nIfs = 1;
+    var Out = 0;
+
+    do
+    {
+        if (SkipCode(exc) == 1)
+            return;
+
+        switch ( exc.opcode )
+        {
+        case 0x58:      /* IF */
+            nIfs++;
+            break;
+        case 0x1B:      /* ELSE */
+            Out = (nIfs == 1) ? 1 : 0;
+            break;
+        case 0x59:      /* EIF */
+            nIfs--;
+            Out = (nIfs == 0) ? 1 : 0;
+            break;
+        }
+    } while ( Out == 0 );
+}
+function Ins_EIF(exc, args, args_pos)
+{
+    // nothing
+}
+function Ins_AND(exc, args, args_pos)
+{
+    args[args_pos] = (args[args_pos] && args[args_pos + 1]) ? 1 : 0;
+}
+function Ins_OR(exc, args, args_pos)
+{
+    args[args_pos] = (args[args_pos] || args[args_pos + 1]) ? 1 : 0;
+}
+function Ins_NOT(exc, args, args_pos)
+{
+    args[args_pos] = (args[args_pos] != 0) ? 0 : 1;
+}
+function Ins_SDB(exc, args, args_pos)
+{
+    exc.GS.delta_base = FT_Common.UShort_To_Short(0xFFFF & args[args_pos]);
+}
+function Ins_SDS(exc, args, args_pos)
+{
+    exc.GS.delta_shift = FT_Common.UShort_To_Short(0xFFFF & args[args_pos]);
+}
+
+function Ins_ADD(exc, args, args_pos)
+{
+    args[args_pos] += args[args_pos + 1];
+}
+function Ins_SUB(exc, args, args_pos)
+{
+    args[args_pos] -= args[args_pos + 1];
+}
+function Ins_DIV(exc, args, args_pos)
+{
+    if (args[args_pos + 1] == 0)
+        exc.error = FT_Common.FT_Err_Divide_By_Zero;
+    else
+        args[args_pos] = FT_MulDiv_No_Round(args[args_pos], 64, args[args_pos + 1]);
+}
+function Ins_MUL(exc, args, args_pos)
+{
+    args[args_pos] = FT_MulDiv(args[args_pos], args[args_pos + 1], 64);
+}
+function Ins_ABS(exc, args, args_pos)
+{
+    args[args_pos] = Math.abs(args[args_pos]);
+}
+function Ins_NEG(exc, args, args_pos)
+{
+    args[args_pos] = -args[args_pos];
+}
+function Ins_FLOOR(exc, args, args_pos)
+{
+    args[args_pos] = FT_PIX_FLOOR(args[args_pos]);
+}
+function Ins_CEILING(exc, args, args_pos)
+{
+    args[args_pos] = FT_PIX_CEIL(args[args_pos]);
+}
+function Ins_ROUND(exc, args, args_pos)
+{
+    args[args_pos] = exc.func_round(exc, args[args_pos], exc.tt_metrics.compensations[exc.opcode - 0x68]);
+}
+function Ins_NROUND(exc, args, args_pos)
+{
+    args[args_pos] = Round_None(exc, args[args_pos], exc.tt_metrics.compensations[exc.opcode - 0x6C]);
+}
+
+function Ins_WCVTF(exc, args, args_pos)
+{
+    var I = args[args_pos];
+    if (I >= exc.cvtSize)
+    {
+        if (exc.pedantic_hinting)
+        {
+            exc.error = FT_Common.FT_Err_Invalid_Reference;
+            return;
+        }
+    }
+    else
+    {
+        exc.cvt[I] = FT_MulFix(args[args_pos + 1], exc.tt_metrics.scale);
+    }
+}
+
+function Ins_DELTAP(exc, args, args_pos)
+{
+    var A = 0;
+    var C = 0;
+    var B = 0;
+    var B1 = 0;
+    var B2 = 0;
+
+    var bIsSubpix = exc.face.driver.library.tt_hint_props.TT_CONFIG_OPTION_SUBPIXEL_HINTING;
+    // TODO: unpatented
+
+    var nump = args[args_pos];   /* some points theoretically may occur more
+                                   than once, thus UShort isn't enough */
+    if (nump < 0)
+        nump += FT_Common.a_i;
+
+    for (var k = 1; k <= nump; k++)
+    {
+        if (exc.args < 2)
+        {
+            if (exc.pedantic_hinting)
+                exc.error = FT_Common.FT_Err_Too_Few_Arguments;
+            exc.args = 0;
+            exc.new_top = exc.args;
+            return;
+        }
+
+        exc.args -= 2;
+
+        A = 0xFFFF & exc.stack[exc.args + 1];
+        B = exc.stack[exc.args];
+
+        /* XXX: Because some popular fonts contain some invalid DeltaP */
+        /*      instructions, we simply ignore them when the stacked   */
+        /*      point reference is off limit, rather than returning an */
+        /*      error.  As a delta instruction doesn't change a glyph  */
+        /*      in great ways, this shouldn't be a problem.            */
+        if (A < exc.zp0.n_points)
+        {
+            C = (B & 0xF0) >> 4;
+
+            switch (exc.opcode)
+            {
+            case 0x5D:
+                break;
+            case 0x71:
+                C += 16;
+                break;
+            case 0x72:
+                C += 32;
+                break;
+            }
+
+            C += exc.GS.delta_base;
+            if (C < 0)
+                C += FT_Common.a_i;
+
+            if (Current_Ppem(exc) == C)
+            {
+                B = (B & 0xF) - 8;
+                if (B >= 0)
+                    B++;
+                B = B * 64 / (1 << exc.GS.delta_shift);
+                B = B >> 0;
+
+                if (!bIsSubpix)
+                {
+                    exc.func_move(exc, exc.zp0, A, B);
+                }
+                else
+                {
+                    /*
+                    *  Allow delta move if
+                    *
+                    *  - not using ignore_x_mode rendering
+                    *  - glyph is specifically set to allow it
+                    *  - glyph is composite and freedom vector is not subpixel vector
+                    */
+                    if (!exc.ignore_x_mode || (exc.sph_tweak_flags & FT_Common.SPH_TWEAK_ALWAYS_DO_DELTAP) != 0 ||
+                        (exc.is_composite && exc.GS.freeVector.y != 0))
+                        exc.func_move(exc, exc.zp0, A, B);
+                    else if (exc.ignore_x_mode) /* Otherwise apply subpixel hinting and compatibility mode rules */
+                    {
+                        if (exc.GS.freeVector.y != 0)
+                            B1 = exc.zp0.cur[exc.zp0._offset_cur + A].y;
+                        else
+                            B1 = exc.zp0.cur[exc.zp0._offset_cur + A].x;
+
+                        /* Standard Subpixel Hinting:  Allow y move */
+                        if (!exc.compatibility_mode && exc.GS.freeVector.y != 0)
+                            exc.func_move(exc, exc.zp0, A, B);
+                         /* Compatibility Mode: Allow x or y move if point touched in Y direction */
+                        else if (exc.compatibility_mode && (exc.sph_tweak_flags & FT_Common.SPH_TWEAK_ALWAYS_SKIP_DELTAP) == 0)
+                        {
+                            /* save the y value of the point now; compare after move */
+                            B1 = exc.zp0.cur[exc.zp0._offset_cur + A].y;
+
+                            if ((exc.sph_tweak_flags & FT_Common.SPH_TWEAK_ROUND_NONPIXEL_Y_MOVES) != 0)
+                                B = FT_PIX_ROUND(B1 + B) - B1;
+
+                            /*
+                            *  Allow delta move if using compatibility_mode, IUP has not
+                            *  been called, and point is touched on Y.
+                            */
+                            if (!exc.iup_called && (exc.zp0.tags[exc.zp0._offset_tags + A] & FT_Common.FT_CURVE_TAG_TOUCH_Y) != 0)
+                                exc.func_move(exc, exc.zp0, A, B);
+                        }
+
+                        B2 = exc.zp0.cur[exc.zp0._offset_cur + A].y;
+
+                        /* Reverse this move if it results in a disallowed move */
+                        if (exc.GS.freeVector.y != 0 && (((exc.sph_tweak_flags & FT_Common.SPH_TWEAK_SKIP_OFFPIXEL_Y_MOVES) &&
+                                    (B1 % 64) == 0 && (B2 % 64) != 0 && !exc.size.ttfautohinted) ||
+                                    ((exc.sph_tweak_flags & FT_Common.SPH_TWEAK_SKIP_NONPIXEL_Y_MOVES) && (B1 % 64) != 0 && (B2 % 64) != 0)))
+                            exc.func_move(exc, exc.zp0, A, -B);
+                    }
+                }
+
+            }
+        }
+        else
+        {
+            if (exc.pedantic_hinting)
+                exc.error = FT_Common.FT_Err_Invalid_Reference;
+        }
+    }
+
+    exc.new_top = exc.args;
+}
+
+function Ins_DELTAC(exc, args, args_pos)
+{
+    // TODO: unpatented
+    var nump = args[args_pos];
+
+    for (var k = 1; k <= nump; k++)
+    {
+        if (exc.args < 2)
+        {
+            if (exc.pedantic_hinting)
+                exc.error = FT_Common.FT_Err_Too_Few_Arguments;
+            exc.args = 0;
+            exc.new_top = exc.args;
+            return;
+        }
+
+        exc.args -= 2;
+
+        var A = FT_Common.IntToUInt(exc.stack[exc.args + 1]);
+        var B = exc.stack[exc.args];
+        var C = 0;
+
+        if (A >= exc.cvtSize)
+        {
+            if (exc.pedantic_hinting)
+            {
+                exc.error = FT_Common.FT_Err_Invalid_Reference;
+                return;
+            }
+        }
+        else
+        {
+            C = (B & 0xF0) >> 4;
+
+            switch (exc.opcode)
+            {
+            case 0x73:
+                break;
+            case 0x74:
+                C += 16;
+                break;
+            case 0x75:
+                C += 32;
+                break;
+            }
+
+            C += exc.GS.delta_base;
+
+            if (Current_Ppem(exc) == C)
+            {
+                B = (B & 0xF) - 8;
+                if (B >= 0)
+                    B++;
+                B = B * 64 / (1 << exc.GS.delta_shift);
+                B = B >> 0;
+
+                exc.func_move_cvt(exc, A, B);
+            }
+        }
+    }
+    exc.new_top = exc.args;
+}
+
+function Ins_SROUND(exc, args, args_pos)
+{
+    SetSuperRound(exc, 0x4000, args[args_pos]);
+    exc.GS.round_state = TT_Round_Super;
+    exc.func_round = Round_Super;
+}
+
+function Ins_S45ROUND(exc, args, args_pos)
+{
+    SetSuperRound(exc, 0x2D41, args[args_pos]);
+    exc.GS.round_state = TT_Round_Super_45;
+    exc.func_round = Round_Super_45;
+}
+
+function Ins_JROT(exc, args, args_pos)
+{
+    if (args[args_pos + 1] != 0)
+    {
+        if (args[args_pos] == 0 && exc.args == 0)
+            exc.error = FT_Common.FT_Err_Bad_Argument;
+        exc.IP += args[args_pos];
+        if (exc.IP < 0 || (exc.callTop > 0 && exc.IP > exc.callStack[exc.callTop - 1].Cur_End))
+            exc.error = FT_Common.FT_Err_Bad_Argument;
+        exc.step_ins = false;
+    }
+}
+
+function Ins_JROF(exc, args, args_pos)
+{
+    if (args[args_pos + 1] == 0)
+    {
+        if (args[args_pos] == 0 && exc.args == 0)
+            exc.error = FT_Common.FT_Err_Bad_Argument;
+        exc.IP += args[args_pos];
+        if (exc.IP < 0 || (exc.callTop > 0 && exc.IP > exc.callStack[exc.callTop - 1].Cur_End))
+            exc.error = FT_Common.FT_Err_Bad_Argument;
+        exc.step_ins = false;
+    }
+}
+
+function Ins_ROFF(exc, args, args_pos)
+{
+    exc.GS.round_state = TT_Round_Off;
+    exc.func_round = Round_None;
+}
+
+function Ins_RUTG(exc, args, args_pos)
+{
+    exc.GS.round_state = TT_Round_Up_To_Grid;
+    exc.func_round = Round_Up_To_Grid;
+}
+
+function Ins_RDTG(exc, args, args_pos)
+{
+    exc.GS.round_state = TT_Round_Down_To_Grid;
+    exc.func_round = Round_Down_To_Grid;
+}
+
+function Ins_SANGW(exc, args, args_pos)
+{
+    /* instruction not supported anymore */
+}
+
+function Ins_AA(exc, args, args_pos)
+{
+    /* intentionally no longer supported */
+}
+
+function Ins_FLIPPT(exc, args, args_pos)
+{
+    if (exc.top < exc.GS.loop)
+    {
+        if (exc.pedantic_hinting)
+            exc.error = FT_Common.FT_Err_Too_Few_Arguments;
+
+        exc.GS.loop = 1;
+        exc.new_top = exc.args;
+        return;
+    }
+
+    while (exc.GS.loop > 0)
+    {
+        exc.args--;
+        var point = 0xFFFF & exc.stack[exc.args];
+
+        if (point >= exc.pts.n_points)
+        {
+            if (exc.pedantic_hinting)
+            {
+                exc.error = FT_Common.FT_Err_Invalid_Reference;
+                return;
+            }
+        }
+        else
+            exc.pts.tags[exc.pts._offset_tags + point] ^= FT_Common.FT_CURVE_TAG_ON;
+
+        exc.GS.loop--;
+    }
+
+    exc.GS.loop = 1;
+    exc.new_top = exc.args;
+}
+
+function Ins_FLIPRGON(exc, args, args_pos)
+{
+    var K = 0xFFFF & args[args_pos + 1];
+    var L = 0xFFFF & args[args_pos];
+
+    if ((K >= exc.pts.n_points) || (L >= exc.pts.n_points))
+    {
+        if (exc.pedantic_hinting)
+            exc.error = FT_Common.FT_Err_Invalid_Reference;
+        return;
+    }
+
+    for (var I = L; I <= K; I++)
+        exc.pts.tags[exc.pts._offset_tags + I] |= FT_Common.FT_CURVE_TAG_ON;
+}
+
+function Ins_FLIPRGOFF(exc, args, args_pos)
+{
+    var K = 0xFFFF & args[args_pos + 1];
+    var L = 0xFFFF & args[args_pos];
+
+    if ((K >= exc.pts.n_points) || (L >= exc.pts.n_points))
+    {
+        if (exc.pedantic_hinting)
+            exc.error = FT_Common.FT_Err_Invalid_Reference;
+        return;
+    }
+
+    for (var I = L; I <= K; I++)
+        exc.pts.tags[exc.pts._offset_tags + I] &= ~FT_Common.FT_CURVE_TAG_ON;
+}
+
+function Ins_SCANCTRL(exc, args, args_pos)
+{
+    /* Get Threshold */
+    var A = (args[args_pos] & 0xFF);
+
+    if (A == 0xFF)
+    {
+        exc.GS.scan_control = true;
+        return;
+    }
+    else if (A == 0)
+    {
+        exc.GS.scan_control = false;
+        return;
+    }
+
+    if ((args[args_pos] & 0x100 ) != 0 && exc.tt_metrics.ppem <= A)
+        exc.GS.scan_control = true;
+
+    if ((args[args_pos] & 0x200 ) != 0 && exc.tt_metrics.rotated)
+        exc.GS.scan_control = true;
+
+    if ((args[args_pos] & 0x400 ) != 0 && exc.tt_metrics.stretched)
+        exc.GS.scan_control = true;
+
+    if ((args[args_pos] & 0x800 ) != 0 && exc.tt_metrics.ppem > A)
+        exc.GS.scan_control = false;
+
+    if ((args[args_pos] & 0x1000 ) != 0 && exc.tt_metrics.rotated)
+        exc.GS.scan_control = false;
+
+    if ((args[args_pos] & 0x2000 ) != 0 && exc.tt_metrics.stretched)
+        exc.GS.scan_control = false;
+}
+
+function Ins_SDPVTL(exc, args, args_pos)
+{
+    var aOpc = exc.opcode;
+
+    var p1 = 0xFFFF & args[args_pos + 1];
+    var p2 = 0xFFFF & args[args_pos];
+
+    if ((p2 >= exc.zp1.n_points) || (p1 >= exc.zp2.n_points))
+    {
+        if (exc.pedantic_hinting)
+            exc.error = FT_Common.FT_Err_Invalid_Reference;
+        return;
+    }
+
+    var v1 = exc.zp1.org[exc.zp1._offset_org + p2];
+    var v2 = exc.zp2.org[exc.zp2._offset_org + p1];
+
+    var A = v1.x - v2.x;
+    var B = v1.y - v2.y;
+
+    /* If v1 == v2, SDPVTL behaves the same as */
+    /* SVTCA[X], respectively.                 */
+    /*                                         */
+    /* Confirmed by Greg Hitchcock.            */
+    if ( A == 0 && B == 0 )
+    {
+        A    = 0x4000;
+        aOpc = 0;
+    }
+
+    if ((aOpc & 1) != 0)
+    {
+        var C =  B;   /* counter clockwise rotation */
+        B =  A;
+        A = -C;
+    }
+
+    Normalize(exc, A, B, exc.GS.dualVector);
+
+    v1 = exc.zp1.cur[exc.zp1._offset_cur + p2];
+    v2 = exc.zp2.cur[exc.zp2._offset_cur + p1];
+
+    A = v1.x - v2.x;
+    B = v1.y - v2.y;
+
+    if ((aOpc & 1) != 0)
+    {
+        var C =  B;   /* counter clockwise rotation */
+        B =  A;
+        A = -C;
+    }
+
+    Normalize(exc, A, B, exc.GS.projVector);
+
+    GUESS_VECTOR(exc, exc.GS.freeVector);
+
+    Compute_Funcs(exc);
+}
+
+function Ins_GETINFO(exc, args, args_pos)
+{
+    var K = 0;
+    var bIsSubpix = exc.face.driver.library.tt_hint_props.TT_CONFIG_OPTION_SUBPIXEL_HINTING;
+
+    if (bIsSubpix)
+    {
+        /********************************/
+        /* RASTERIZER VERSION           */
+        /* Selector Bit:  0             */
+        /* Return Bit(s): 0-7           */
+        /*                              */
+        if ((args[args_pos] & 1) != 0 && exc.ignore_x_mode)
+        {
+            K = exc.rasterizer_version;
+        }
+        else
+        {
+            if ((args[args_pos] & 1) != 0)
+                K = 35;
+        }
+    }
+    else
+    {
+        if ((args[args_pos] & 1) != 0)
+            K = 35;
+    }
+
+    /********************************/
+    /* GLYPH ROTATED                */
+    /* Selector Bit:  1             */
+    /* Return Bit(s): 8             */
+    /*                              */
+    if (( args[args_pos] & 2) != 0 && exc.tt_metrics.rotated)
+        K |= 0x80;
+
+    /********************************/
+    /* GLYPH STRETCHED              */
+    /* Selector Bit:  2             */
+    /* Return Bit(s): 9             */
+    /*                              */
+    if ((args[args_pos] & 4) != 0 && exc.tt_metrics.stretched)
+        K |= 1 << 8;
+
+    /********************************/
+    /* HINTING FOR GRAYSCALE        */
+    /* Selector Bit:  5             */
+    /* Return Bit(s): 12            */
+    /*                              */
+    if ((args[args_pos] & 32) != 0 && exc.grayscale)
+        K |= 1 << 12;
+
+    if (bIsSubpix) //#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+    {
+        if (exc.ignore_x_mode && exc.rasterizer_version >= 35)
+        {
+            /********************************/
+            /* HINTING FOR GRAYSCALE        */
+            /* Selector Bit:  5             */
+            /* Return Bit(s): 12            */
+            /*                              */
+            if ((args[args_pos] & 32) != 0 && exc.grayscale_hinting)
+                K |= 1 << 12;
+
+            /********************************/
+            /* HINTING FOR SUBPIXEL         */
+            /* Selector Bit:  6             */
+            /* Return Bit(s): 13            */
+            /*                              */
+            if ((args[args_pos] & 64) != 0 && exc.subpixel_hinting && exc.rasterizer_version >= 37)
+            {
+                K |= 1 << 13;
+
+                /* the stuff below is irrelevant if subpixel_hinting is not set */
+
+                /********************************/
+                /* COMPATIBLE WIDTHS ENABLED    */
+                /* Selector Bit:  7             */
+                /* Return Bit(s): 14            */
+                /*                              */
+                /* Functionality still needs to be added */
+                if ((args[args_pos] & 128) != 0 && exc.compatible_widths)
+                    K |= 1 << 14;
+
+                /********************************/
+                /* SYMMETRICAL SMOOTHING        */
+                /* Selector Bit:  8             */
+                /* Return Bit(s): 15            */
+                /*                              */
+                /* Functionality still needs to be added */
+                if ((args[args_pos] & 256) != 0 && exc.symmetrical_smoothing)
+                    K |= 1 << 15;
+
+                /********************************/
+                /* HINTING FOR BGR?             */
+                /* Selector Bit:  9             */
+                /* Return Bit(s): 16            */
+                /*                              */
+                /* Functionality still needs to be added */
+                if ((args[args_pos] & 512) != 0 && exc.bgr)
+                    K |= 1 << 16;
+
+                if (exc.rasterizer_version >= 38)
+                {
+                    /********************************/
+                    /* SUBPIXEL POSITIONED?         */
+                    /* Selector Bit:  10            */
+                    /* Return Bit(s): 17            */
+                    /*                              */
+                    /* Functionality still needs to be added */
+                    if ((args[args_pos] & 1024) != 0 && exc.subpixel_positioned)
+                        K |= 1 << 17;
+                }
+            }
+        }
+    }//#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+    args[args_pos] = K;
+}
+
+function Ins_IDEF(exc, args, args_pos)
+{
+    /*  First of all, look for the same function in our table */
+    var defs = exc.IDefs;
+    var _ind_def = 0;
+    var limit = exc.numIDefs;
+    var def = defs[_ind_def];
+
+    for ( ; _ind_def < limit; _ind_def++)
+    {
+        def = defs[_ind_def];
+        if (def.opc == args[args_pos])
+            break;
+    }
+
+    if (_ind_def == limit)
+    {
+        /* check that there is enough room for a new instruction */
+        if (exc.numIDefs >= exc.maxIDefs)
+        {
+            exc.error = FT_Common.FT_Err_Too_Many_Instruction_Defs;
+            return;
+        }
+        exc.numIDefs++;
+    }
+
+    /* opcode must be unsigned 8-bit integer */
+    if (0 > args[args_pos] || args[args_pos] > 0x00FF)
+    {
+        exc.error = FT_Common.FT_Err_Too_Many_Instruction_Defs;
+        return;
+    }
+
+    def.opc    = 0xFF & args[args_pos];
+    def.start  = exc.IP + 1;
+    def.range  = exc.curRange;
+    def.active = true;
+
+    if (args[args_pos] > exc.maxIns)
+        exc.maxIns = 0xFF & args[args_pos];
+
+    /* Now skip the whole function definition. */
+    /* We don't allow nested IDEFs & FDEFs.    */
+
+    while (SkipCode(exc) == 0)
+    {
+        switch (exc.opcode)
+        {
+        case 0x89:   /* IDEF */
+        case 0x2C:   /* FDEF */
+            exc.error = FT_Common.FT_Err_Nested_DEFS;
+            return;
+      case 0x2D:   /* ENDF */
+            return;
+        }
+    }
+}
+
+function Ins_ROLL(exc, args, args_pos)
+{
+    var A = args[args_pos + 2];
+    var B = args[args_pos + 1];
+    var C = args[args_pos];
+
+    args[args_pos + 2] = C;
+    args[args_pos + 1] = A;
+    args[args_pos] = B;
+}
+
+function Ins_MAX(exc, args, args_pos)
+{
+    if (args[args_pos + 1] > args[args_pos])
+        args[args_pos] = args[args_pos + 1];
+}
+
+function Ins_MIN(exc, args, args_pos)
+{
+    if (args[args_pos + 1] < args[args_pos])
+        args[args_pos] = args[args_pos + 1];
+}
+
+function Ins_SCANTYPE(exc, args, args_pos)
+{
+    if (args[args_pos] >= 0)
+        exc.GS.scan_type = args[args_pos];
+}
+
+function Ins_INSTCTRL(exc, args, args_pos)
+{
+    var K = args[args_pos + 1];
+    var L = args[args_pos];
+
+    if (K < 1 || K > 2)
+    {
+        if (exc.pedantic_hinting)
+            exc.error = FT_Common.FT_Err_Invalid_Reference;
+        return;
+    }
+
+    if (L != 0)
+        L = K;
+
+    exc.GS.instruct_control = ((((0xFF & exc.GS.instruct_control) & ~(K & 0xFF)) | (L & 0xFF)) != 0) ? 1 : 0;
+}
+
+function Ins_PUSHB(exc, args, args_pos)
+{
+    var L = 0xFFFF & (exc.opcode - 0xB0 + 1);
+
+    if (L >= (exc.stackSize + 1 - exc.top))
+    {
+        exc.error = FT_Common.FT_Err_Stack_Overflow;
+        return;
+    }
+
+    for (var K = 1; K <= L; K++)
+        args[args_pos + K - 1] = exc.code.data[exc.code.pos + exc.IP + K];
+}
+
+function Ins_PUSHW(exc, args, args_pos)
+{
+    var L = 0xFFFF & (exc.opcode - 0xB8 + 1);
+
+    if (L >= (exc.stackSize + 1 - exc.top))
+    {
+        exc.error = FT_Common.FT_Err_Stack_Overflow;
+        return;
+    }
+
+    exc.IP++;
+
+    for (var K = 0; K < L; K++)
+        args[args_pos + K] = GetShortIns(exc);
+
+    exc.step_ins = false;
+}
+
+function Ins_MDRP(exc, args, args_pos)
+{
+    var org_dist, distance;
+    var minimum_distance = exc.GS.minimum_distance;
+
+    var bIsSubpix = exc.face.driver.library.tt_hint_props.TT_CONFIG_OPTION_SUBPIXEL_HINTING;
+
+    if (bIsSubpix)
+    {
+        if (exc.ignore_x_mode && exc.GS.freeVector.x != 0 && (exc.sph_tweak_flags & FT_Common.SPH_TWEAK_NORMAL_ROUND) == 0)
+            minimum_distance = 0;
+    }
+
+    var point = 0xFFFF & args[args_pos];
+
+    if ((point >= exc.zp1.n_points) || (exc.GS.rp0 >= exc.zp0.n_points))
+    {
+        if (exc.pedantic_hinting)
+            exc.error = FT_Common.FT_Err_Invalid_Reference;
+
+        exc.GS.rp1 = exc.GS.rp0;
+        exc.GS.rp2 = point;
+        if ((exc.opcode & 16) != 0)
+            exc.GS.rp0 = point;
+    }
+
+    /* XXX: Is there some undocumented feature while in the */
+    /*      twilight zone?                                  */
+
+    var v1, v2;
+    /* XXX: UNDOCUMENTED: twilight zone special case */
+    if (exc.GS.gep0 == 0 || exc.GS.gep1 == 0)
+    {
+        v1 = exc.zp1.org[exc.zp1._offset_org + point];
+        v2 = exc.zp0.org[exc.zp0._offset_org + exc.GS.rp0];
+        org_dist = exc.func_dualproj(exc, v1.x - v2.x, v1.y - v2.y);
+    }
+    else
+    {
+        v1 = exc.zp1.orus[exc.zp1._offset_orus + point];
+        v2 = exc.zp0.orus[exc.zp0._offset_orus + exc.GS.rp0];
+
+        if (exc.metrics.x_scale == exc.metrics.y_scale)
+        {
+            /* this should be faster */
+            org_dist = exc.func_dualproj(exc, v1.x - v2.x, v1.y - v2.y);
+            org_dist = FT_MulFix(org_dist, exc.metrics.x_scale);
+        }
+        else
+        {
+            var _x = FT_MulFix(v1.x - v2.x, exc.metrics.x_scale);
+            var _y = FT_MulFix(v1.y - v2.y, exc.metrics.y_scale);
+            org_dist = exc.func_dualproj(exc, _x, _y);
+        }
+    }
+
+    /* single width cut-in test */
+    if (Math.abs(org_dist - exc.GS.single_width_value) < exc.GS.single_width_cutin)
+    {
+        if (org_dist >= 0)
+            org_dist = exc.GS.single_width_value;
+        else
+            org_dist = -exc.GS.single_width_value;
+    }
+
+    /* round flag */
+    if ((exc.opcode & 4) != 0)
+    {
+        if (bIsSubpix)
+        {
+            if (exc.ignore_x_mode && exc.GS.freeVector.x != 0)
+                distance = Round_None(org_dist, exc.tt_metrics.compensations[exc.opcode & 3]);
+            else
+                distance = exc.func_round(exc, org_dist, exc.tt_metrics.compensations[exc.opcode & 3]);
+        }
+        else
+        {
+            distance = exc.func_round(exc, org_dist, exc.tt_metrics.compensations[exc.opcode & 3]);
+        }
+    }
+    else
+        distance = Round_None(exc, org_dist, exc.tt_metrics.compensations[exc.opcode & 3]);
+
+    /* minimum distance flag */
+    if ((exc.opcode & 8) != 0)
+    {
+        if (org_dist >= 0)
+        {
+            if (distance < minimum_distance)
+                distance = minimum_distance;
+        }
+        else
+        {
+            if (distance > -minimum_distance)
+                distance = -minimum_distance;
+        }
+    }
+
+    /* now move the point */
+    v1 = exc.zp1.cur[exc.zp1._offset_cur + point];
+    v2 = exc.zp0.cur[exc.zp0._offset_cur + exc.GS.rp0];
+    org_dist = exc.func_project(exc, v1.x - v2.x, v1.y - v2.y);
+    
+    exc.func_move(exc, exc.zp1, point, distance - org_dist);
+
+    exc.GS.rp1 = exc.GS.rp0;
+    exc.GS.rp2 = point;
+    if ((exc.opcode & 16) != 0)
+        exc.GS.rp0 = point;
+}
+
+function Ins_MIRP(exc, args, args_pos)
+{
+    var bIsSubpix = exc.face.driver.library.tt_hint_props.TT_CONFIG_OPTION_SUBPIXEL_HINTING;
+
+    var minimum_distance    = exc.GS.minimum_distance;
+    var control_value_cutin = exc.GS.control_value_cutin;
+    var point               = 0xFFFF & args[args_pos];
+    var cvtEntry            = FT_Common.IntToUInt(args[args_pos + 1] + 1);
+    var distance = 0;
+
+    if (bIsSubpix)
+    {
+        if (exc.ignore_x_mode && exc.GS.freeVector.x != 0 && (exc.sph_tweak_flags & FT_Common.SPH_TWEAK_NORMAL_ROUND) == 0)
+            control_value_cutin = minimum_distance = 0;
+    }
+
+    /* XXX: UNDOCUMENTED! cvt[-1] = 0 always */
+    if ((point >= exc.zp1.n_points) || (cvtEntry >= (exc.cvtSize + 1)) || (exc.GS.rp0 >= exc.zp0.n_points))
+    {
+        if (exc.pedantic_hinting)
+            exc.error = FT_Common.FT_Err_Invalid_Reference;
+
+        exc.GS.rp1 = exc.GS.rp0;
+        if ((exc.opcode & 16) != 0)
+            exc.GS.rp0 = point;
+        exc.GS.rp2 = point;
+    }
+
+    var cvt_dist = 0;
+    if (cvtEntry == 0)
+        cvt_dist = 0;
+    else
+        cvt_dist = exc.func_read_cvt(exc, cvtEntry - 1);
+        
+    if (bIsSubpix)
+    {
+        if (exc.sph_tweak_flags & FT_Common.SPH_TWEAK_MIRP_CVT_ZERO)
+            cvt_dist = 0;
+    }
+
+    /* single width test */
+    if (Math.abs(cvt_dist - exc.GS.single_width_value) < exc.GS.single_width_cutin)
+    {
+        if (cvt_dist >= 0)
+            cvt_dist =  exc.GS.single_width_value;
+        else
+            cvt_dist = -exc.GS.single_width_value;
+    }
+
+    /* UNDOCUMENTED!  The MS rasterizer does that with */
+    /* twilight points (confirmed by Greg Hitchcock)   */
+    if (exc.GS.gep1 == 0)
+    {
+        var _v = exc.zp0.org[exc.zp0._offset_org + exc.GS.rp0];
+        exc.zp1.org[exc.zp1._offset_org + point].x = _v.x + TT_MulFix14(cvt_dist, exc.GS.freeVector.x);
+        exc.zp1.org[exc.zp1._offset_org + point].y = _v.y + TT_MulFix14(cvt_dist, exc.GS.freeVector.y);
+
+        exc.zp1.cur[exc.zp1._offset_cur + point].x = exc.zp1.org[exc.zp1._offset_org + point].x;
+        exc.zp1.cur[exc.zp1._offset_cur + point].y = exc.zp1.org[exc.zp1._offset_org + point].y;
+    }
+
+    var v1 = exc.zp1.org[exc.zp1._offset_org + point];
+    var v2 = exc.zp0.org[exc.zp0._offset_org + exc.GS.rp0];
+
+    var org_dist = exc.func_dualproj(exc, v1.x - v2.x, v1.y - v2.y);
+
+    v1 = exc.zp1.cur[exc.zp1._offset_cur + point];
+    v2 = exc.zp0.cur[exc.zp0._offset_cur + exc.GS.rp0];
+
+    var cur_dist = exc.func_project(exc, v1.x - v2.x, v1.y - v2.y);
+
+    /* auto-flip test */
+    if (exc.GS.auto_flip)
+    {
+        if ((org_dist ^ cvt_dist) < 0)
+            cvt_dist = -cvt_dist;
+    }
+
+    if (bIsSubpix) //#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+    {
+        if (exc.GS.freeVector.y != 0 && (exc.sph_tweak_flags & FT_Common.SPH_TWEAK_TIMES_NEW_ROMAN_HACK) != 0)
+        {
+            if (cur_dist < -64)
+                cvt_dist -= 16;
+            else if (cur_dist > 64 && cur_dist < 84)
+                cvt_dist += 32;
+        }
+    } //#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+    /* control value cut-in and round */
+    if ((exc.opcode & 4) != 0)
+    {
+        /* XXX: UNDOCUMENTED!  Only perform cut-in test when both points */
+        /*      refer to the same zone.                                  */
+        if (exc.GS.gep0 == exc.GS.gep1)
+        {
+            /* XXX: According to Greg Hitchcock, the following wording is */
+            /*      the right one:                                        */
+            /*                                                            */
+            /*        When the absolute difference between the value in   */
+            /*        the table [CVT] and the measurement directly from   */
+            /*        the outline is _greater_ than the cut_in value, the */
+            /*        outline measurement is used.                        */
+            /*                                                            */
+            /*      This is from `instgly.doc'.  The description in       */
+            /*      `ttinst2.doc', version 1.66, is thus incorrect since  */
+            /*      it implies `>=' instead of `>'.                       */
+
+            if (Math.abs(cvt_dist - org_dist) > control_value_cutin)
+                cvt_dist = org_dist;
+        }
+
+        distance = exc.func_round(exc, cvt_dist, exc.tt_metrics.compensations[exc.opcode & 3]);
+    }
+    else
+        distance = Round_None(exc, cvt_dist, exc.tt_metrics.compensations[exc.opcode & 3]);
+
+    /* minimum distance test */
+    if ((exc.opcode & 8) != 0)
+    {
+        if (org_dist >= 0)
+        {
+            if (distance < minimum_distance)
+                distance = minimum_distance;
+        }
+        else
+        {
+            if (distance > -minimum_distance)
+                distance = -minimum_distance;
+        }
+    }
+
+    if (!bIsSubpix)
+    {
+        exc.func_move(exc, exc.zp1, point, distance - cur_dist);
+    }
+    else
+    {
+        var B1 = exc.zp1.cur[exc.zp1._offset_cur + point].y;
+
+        /* Round moves if necessary */
+        if (exc.ignore_x_mode && exc.GS.freeVector.y != 0 && (exc.sph_tweak_flags & FT_Common.SPH_TWEAK_ROUND_NONPIXEL_Y_MOVES) != 0)
+            distance = FT_PIX_ROUND(B1 + distance - cur_dist) - B1 + cur_dist;
+
+        if (exc.GS.freeVector.y != 0 && (exc.opcode & 16) == 0 && (exc.opcode & 8) == 0 && (exc.sph_tweak_flags & FT_Common.SPH_TWEAK_COURIER_NEW_2_HACK) != 0)
+            distance += 64;
+
+        exc.func_move(exc, exc.zp1, point, distance - cur_dist);
+
+        var B2 = exc.zp1.cur[exc.zp1._offset_cur + point].y;
+
+        var reverse_move = false;
+        /* Reverse move if necessary */
+        if (exc.ignore_x_mode)
+        {
+            if ((exc.sph_tweak_flags & FT_Common.SPH_TWEAK_SKIP_OFFPIXEL_Y_MOVES) != 0 && exc.GS.freeVector.y != 0 && (B1 % 64) == 0 &&
+                        (B2 % 64) != 0 && !exc.size.ttfautohinted)
+                reverse_move = true;
+
+            if ((exc.sph_tweak_flags & FT_Common.SPH_TWEAK_SKIP_NONPIXEL_Y_MOVES) != 0 && exc.GS.freeVector.y != 0 &&
+                        (B2 % 64) != 0 && (B1 % 64) != 0)
+                reverse_move = true;
+
+            if ((exc.sph_tweak_flags & FT_Common.SPH_TWEAK_DELTAP_SKIP_EXAGGERATED_VALUES) != 0 && !reverse_move && Math.abs(B1 - B2) >= 64)
+                reverse_move = true;
+        }
+
+        if (reverse_move)
+            exc.func_move(exc, exc.zp1, point, -(distance - cur_dist));
+    }
+
+    exc.GS.rp1 = exc.GS.rp0;
+    if ((exc.opcode & 16) != 0)
+        exc.GS.rp0 = point;
+    exc.GS.rp2 = point;
+}
+
+var Instruct_Dispatch =
+[
+    /* Opcodes are gathered in groups of 16. */
+    /* Please keep the spaces as they are.   */
+
+    /*  SVTCA  y  */  Ins_SVTCA,
+    /*  SVTCA  x  */  Ins_SVTCA,
+    /*  SPvTCA y  */  Ins_SPVTCA,
+    /*  SPvTCA x  */  Ins_SPVTCA,
+    /*  SFvTCA y  */  Ins_SFVTCA,
+    /*  SFvTCA x  */  Ins_SFVTCA,
+    /*  SPvTL //  */  Ins_SPVTL,
+    /*  SPvTL +   */  Ins_SPVTL,
+    /*  SFvTL //  */  Ins_SFVTL,
+    /*  SFvTL +   */  Ins_SFVTL,
+    /*  SPvFS     */  Ins_SPVFS,
+    /*  SFvFS     */  Ins_SFVFS,
+    /*  GPV       */  Ins_GPV,
+    /*  GFV       */  Ins_GFV,
+    /*  SFvTPv    */  Ins_SFVTPV,
+    /*  ISECT     */  Ins_ISECT,
+
+    /*  SRP0      */  Ins_SRP0,
+    /*  SRP1      */  Ins_SRP1,
+    /*  SRP2      */  Ins_SRP2,
+    /*  SZP0      */  Ins_SZP0,
+    /*  SZP1      */  Ins_SZP1,
+    /*  SZP2      */  Ins_SZP2,
+    /*  SZPS      */  Ins_SZPS,
+    /*  SLOOP     */  Ins_SLOOP,
+    /*  RTG       */  Ins_RTG,
+    /*  RTHG      */  Ins_RTHG,
+    /*  SMD       */  Ins_SMD,
+    /*  ELSE      */  Ins_ELSE,
+    /*  JMPR      */  Ins_JMPR,
+    /*  SCvTCi    */  Ins_SCVTCI,
+    /*  SSwCi     */  Ins_SSWCI,
+    /*  SSW       */  Ins_SSW,
+
+    /*  DUP       */  Ins_DUP,
+    /*  POP       */  Ins_POP,
+    /*  CLEAR     */  Ins_CLEAR,
+    /*  SWAP      */  Ins_SWAP,
+    /*  DEPTH     */  Ins_DEPTH,
+    /*  CINDEX    */  Ins_CINDEX,
+    /*  MINDEX    */  Ins_MINDEX,
+    /*  AlignPTS  */  Ins_ALIGNPTS,
+    /*  INS_0x28  */  Ins_UNKNOWN,
+    /*  UTP       */  Ins_UTP,
+    /*  LOOPCALL  */  Ins_LOOPCALL,
+    /*  CALL      */  Ins_CALL,
+    /*  FDEF      */  Ins_FDEF,
+    /*  ENDF      */  Ins_ENDF,
+    /*  MDAP[0]   */  Ins_MDAP,
+    /*  MDAP[1]   */  Ins_MDAP,
+
+    /*  IUP[0]    */  Ins_IUP,
+    /*  IUP[1]    */  Ins_IUP,
+    /*  SHP[0]    */  Ins_SHP,
+    /*  SHP[1]    */  Ins_SHP,
+    /*  SHC[0]    */  Ins_SHC,
+    /*  SHC[1]    */  Ins_SHC,
+    /*  SHZ[0]    */  Ins_SHZ,
+    /*  SHZ[1]    */  Ins_SHZ,
+    /*  SHPIX     */  Ins_SHPIX,
+    /*  IP        */  Ins_IP,
+    /*  MSIRP[0]  */  Ins_MSIRP,
+    /*  MSIRP[1]  */  Ins_MSIRP,
+    /*  AlignRP   */  Ins_ALIGNRP,
+    /*  RTDG      */  Ins_RTDG,
+    /*  MIAP[0]   */  Ins_MIAP,
+    /*  MIAP[1]   */  Ins_MIAP,
+
+    /*  NPushB    */  Ins_NPUSHB,
+    /*  NPushW    */  Ins_NPUSHW,
+    /*  WS        */  Ins_WS,
+    /*  RS        */  Ins_RS,
+    /*  WCvtP     */  Ins_WCVTP,
+    /*  RCvt      */  Ins_RCVT,
+    /*  GC[0]     */  Ins_GC,
+    /*  GC[1]     */  Ins_GC,
+    /*  SCFS      */  Ins_SCFS,
+    /*  MD[0]     */  Ins_MD,
+    /*  MD[1]     */  Ins_MD,
+    /*  MPPEM     */  Ins_MPPEM,
+    /*  MPS       */  Ins_MPS,
+    /*  FlipON    */  Ins_FLIPON,
+    /*  FlipOFF   */  Ins_FLIPOFF,
+    /*  DEBUG     */  Ins_DEBUG,
+
+    /*  LT        */  Ins_LT,
+    /*  LTEQ      */  Ins_LTEQ,
+    /*  GT        */  Ins_GT,
+    /*  GTEQ      */  Ins_GTEQ,
+    /*  EQ        */  Ins_EQ,
+    /*  NEQ       */  Ins_NEQ,
+    /*  ODD       */  Ins_ODD,
+    /*  EVEN      */  Ins_EVEN,
+    /*  IF        */  Ins_IF,
+    /*  EIF       */  Ins_EIF,
+    /*  AND       */  Ins_AND,
+    /*  OR        */  Ins_OR,
+    /*  NOT       */  Ins_NOT,
+    /*  DeltaP1   */  Ins_DELTAP,
+    /*  SDB       */  Ins_SDB,
+    /*  SDS       */  Ins_SDS,
+
+    /*  ADD       */  Ins_ADD,
+    /*  SUB       */  Ins_SUB,
+    /*  DIV       */  Ins_DIV,
+    /*  MUL       */  Ins_MUL,
+    /*  ABS       */  Ins_ABS,
+    /*  NEG       */  Ins_NEG,
+    /*  FLOOR     */  Ins_FLOOR,
+    /*  CEILING   */  Ins_CEILING,
+    /*  ROUND[0]  */  Ins_ROUND,
+    /*  ROUND[1]  */  Ins_ROUND,
+    /*  ROUND[2]  */  Ins_ROUND,
+    /*  ROUND[3]  */  Ins_ROUND,
+    /*  NROUND[0] */  Ins_NROUND,
+    /*  NROUND[1] */  Ins_NROUND,
+    /*  NROUND[2] */  Ins_NROUND,
+    /*  NROUND[3] */  Ins_NROUND,
+
+    /*  WCvtF     */  Ins_WCVTF,
+    /*  DeltaP2   */  Ins_DELTAP,
+    /*  DeltaP3   */  Ins_DELTAP,
+    /*  DeltaCn[0] */ Ins_DELTAC,
+    /*  DeltaCn[1] */ Ins_DELTAC,
+    /*  DeltaCn[2] */ Ins_DELTAC,
+    /*  SROUND    */  Ins_SROUND,
+    /*  S45Round  */  Ins_S45ROUND,
+    /*  JROT      */  Ins_JROT,
+    /*  JROF      */  Ins_JROF,
+    /*  ROFF      */  Ins_ROFF,
+    /*  INS_0x7B  */  Ins_UNKNOWN,
+    /*  RUTG      */  Ins_RUTG,
+    /*  RDTG      */  Ins_RDTG,
+    /*  SANGW     */  Ins_SANGW,
+    /*  AA        */  Ins_AA,
+
+    /*  FlipPT    */  Ins_FLIPPT,
+    /*  FlipRgON  */  Ins_FLIPRGON,
+    /*  FlipRgOFF */  Ins_FLIPRGOFF,
+    /*  INS_0x83  */  Ins_UNKNOWN,
+    /*  INS_0x84  */  Ins_UNKNOWN,
+    /*  ScanCTRL  */  Ins_SCANCTRL,
+    /*  SDPVTL[0] */  Ins_SDPVTL,
+    /*  SDPVTL[1] */  Ins_SDPVTL,
+    /*  GetINFO   */  Ins_GETINFO,
+    /*  IDEF      */  Ins_IDEF,
+    /*  ROLL      */  Ins_ROLL,
+    /*  MAX       */  Ins_MAX,
+    /*  MIN       */  Ins_MIN,
+    /*  ScanTYPE  */  Ins_SCANTYPE,
+    /*  InstCTRL  */  Ins_INSTCTRL,
+    /*  INS_0x8F  */  Ins_UNKNOWN,
+
+    /*  INS_0x90  */   Ins_UNKNOWN,
+    /*  INS_0x91  */   Ins_UNKNOWN,
+    /*  INS_0x92  */   Ins_UNKNOWN,
+    /*  INS_0x93  */   Ins_UNKNOWN,
+    /*  INS_0x94  */   Ins_UNKNOWN,
+    /*  INS_0x95  */   Ins_UNKNOWN,
+    /*  INS_0x96  */   Ins_UNKNOWN,
+    /*  INS_0x97  */   Ins_UNKNOWN,
+    /*  INS_0x98  */   Ins_UNKNOWN,
+    /*  INS_0x99  */   Ins_UNKNOWN,
+    /*  INS_0x9A  */   Ins_UNKNOWN,
+    /*  INS_0x9B  */   Ins_UNKNOWN,
+    /*  INS_0x9C  */   Ins_UNKNOWN,
+    /*  INS_0x9D  */   Ins_UNKNOWN,
+    /*  INS_0x9E  */   Ins_UNKNOWN,
+    /*  INS_0x9F  */   Ins_UNKNOWN,
+
+    /*  INS_0xA0  */   Ins_UNKNOWN,
+    /*  INS_0xA1  */   Ins_UNKNOWN,
+    /*  INS_0xA2  */   Ins_UNKNOWN,
+    /*  INS_0xA3  */   Ins_UNKNOWN,
+    /*  INS_0xA4  */   Ins_UNKNOWN,
+    /*  INS_0xA5  */   Ins_UNKNOWN,
+    /*  INS_0xA6  */   Ins_UNKNOWN,
+    /*  INS_0xA7  */   Ins_UNKNOWN,
+    /*  INS_0xA8  */   Ins_UNKNOWN,
+    /*  INS_0xA9  */   Ins_UNKNOWN,
+    /*  INS_0xAA  */   Ins_UNKNOWN,
+    /*  INS_0xAB  */   Ins_UNKNOWN,
+    /*  INS_0xAC  */   Ins_UNKNOWN,
+    /*  INS_0xAD  */   Ins_UNKNOWN,
+    /*  INS_0xAE  */   Ins_UNKNOWN,
+    /*  INS_0xAF  */   Ins_UNKNOWN,
+
+    /*  PushB[0]  */  Ins_PUSHB,
+    /*  PushB[1]  */  Ins_PUSHB,
+    /*  PushB[2]  */  Ins_PUSHB,
+    /*  PushB[3]  */  Ins_PUSHB,
+    /*  PushB[4]  */  Ins_PUSHB,
+    /*  PushB[5]  */  Ins_PUSHB,
+    /*  PushB[6]  */  Ins_PUSHB,
+    /*  PushB[7]  */  Ins_PUSHB,
+    /*  PushW[0]  */  Ins_PUSHW,
+    /*  PushW[1]  */  Ins_PUSHW,
+    /*  PushW[2]  */  Ins_PUSHW,
+    /*  PushW[3]  */  Ins_PUSHW,
+    /*  PushW[4]  */  Ins_PUSHW,
+    /*  PushW[5]  */  Ins_PUSHW,
+    /*  PushW[6]  */  Ins_PUSHW,
+    /*  PushW[7]  */  Ins_PUSHW,
+
+    /*  MDRP[00]  */  Ins_MDRP,
+    /*  MDRP[01]  */  Ins_MDRP,
+    /*  MDRP[02]  */  Ins_MDRP,
+    /*  MDRP[03]  */  Ins_MDRP,
+    /*  MDRP[04]  */  Ins_MDRP,
+    /*  MDRP[05]  */  Ins_MDRP,
+    /*  MDRP[06]  */  Ins_MDRP,
+    /*  MDRP[07]  */  Ins_MDRP,
+    /*  MDRP[08]  */  Ins_MDRP,
+    /*  MDRP[09]  */  Ins_MDRP,
+    /*  MDRP[10]  */  Ins_MDRP,
+    /*  MDRP[11]  */  Ins_MDRP,
+    /*  MDRP[12]  */  Ins_MDRP,
+    /*  MDRP[13]  */  Ins_MDRP,
+    /*  MDRP[14]  */  Ins_MDRP,
+    /*  MDRP[15]  */  Ins_MDRP,
+
+    /*  MDRP[16]  */  Ins_MDRP,
+    /*  MDRP[17]  */  Ins_MDRP,
+    /*  MDRP[18]  */  Ins_MDRP,
+    /*  MDRP[19]  */  Ins_MDRP,
+    /*  MDRP[20]  */  Ins_MDRP,
+    /*  MDRP[21]  */  Ins_MDRP,
+    /*  MDRP[22]  */  Ins_MDRP,
+    /*  MDRP[23]  */  Ins_MDRP,
+    /*  MDRP[24]  */  Ins_MDRP,
+    /*  MDRP[25]  */  Ins_MDRP,
+    /*  MDRP[26]  */  Ins_MDRP,
+    /*  MDRP[27]  */  Ins_MDRP,
+    /*  MDRP[28]  */  Ins_MDRP,
+    /*  MDRP[29]  */  Ins_MDRP,
+    /*  MDRP[30]  */  Ins_MDRP,
+    /*  MDRP[31]  */  Ins_MDRP,
+
+    /*  MIRP[00]  */  Ins_MIRP,
+    /*  MIRP[01]  */  Ins_MIRP,
+    /*  MIRP[02]  */  Ins_MIRP,
+    /*  MIRP[03]  */  Ins_MIRP,
+    /*  MIRP[04]  */  Ins_MIRP,
+    /*  MIRP[05]  */  Ins_MIRP,
+    /*  MIRP[06]  */  Ins_MIRP,
+    /*  MIRP[07]  */  Ins_MIRP,
+    /*  MIRP[08]  */  Ins_MIRP,
+    /*  MIRP[09]  */  Ins_MIRP,
+    /*  MIRP[10]  */  Ins_MIRP,
+    /*  MIRP[11]  */  Ins_MIRP,
+    /*  MIRP[12]  */  Ins_MIRP,
+    /*  MIRP[13]  */  Ins_MIRP,
+    /*  MIRP[14]  */  Ins_MIRP,
+    /*  MIRP[15]  */  Ins_MIRP,
+
+    /*  MIRP[16]  */  Ins_MIRP,
+    /*  MIRP[17]  */  Ins_MIRP,
+    /*  MIRP[18]  */  Ins_MIRP,
+    /*  MIRP[19]  */  Ins_MIRP,
+    /*  MIRP[20]  */  Ins_MIRP,
+    /*  MIRP[21]  */  Ins_MIRP,
+    /*  MIRP[22]  */  Ins_MIRP,
+    /*  MIRP[23]  */  Ins_MIRP,
+    /*  MIRP[24]  */  Ins_MIRP,
+    /*  MIRP[25]  */  Ins_MIRP,
+    /*  MIRP[26]  */  Ins_MIRP,
+    /*  MIRP[27]  */  Ins_MIRP,
+    /*  MIRP[28]  */  Ins_MIRP,
+    /*  MIRP[29]  */  Ins_MIRP,
+    /*  MIRP[30]  */  Ins_MIRP,
+    /*  MIRP[31]  */  Ins_MIRP
+];
+
+function TT_RunIns(exc)
+{
+    var ins_counter = 0;  /* executed instructions counter */
+
+    var _tt_hints = exc.face.driver.library.tt_hint_props;
+    if (_tt_hints.TT_CONFIG_OPTION_SUBPIXEL_HINTING) //#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+    {
+        if (exc.ignore_x_mode)
+            exc.iup_called = false;
+    }//#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+
+    /* set CVT functions */
+    exc.tt_metrics.ratio = 0;
+    if (exc.metrics.x_ppem != exc.metrics.y_ppem)
+    {
+        /* non-square pixels, use the stretched routines */
+        exc.func_read_cvt  = Read_CVT_Stretched;
+        exc.func_write_cvt = Write_CVT_Stretched;
+        exc.func_move_cvt  = Move_CVT_Stretched;
+    }
+    else
+    {
+      /* square pixels, use normal routines */
+        exc.func_read_cvt  = Read_CVT;
+        exc.func_write_cvt = Write_CVT;
+        exc.func_move_cvt  = Move_CVT;
+    }
+
+    Compute_Funcs(exc);
+    Compute_Round(exc, exc.GS.round_state);
+
+    do
+    {
+        exc.opcode = exc.code.data[exc.code.pos + exc.IP];
+
+        exc.length = opcode_length[exc.opcode];
+        if (exc.length < 0)
+        {
+            if (exc.IP + 1 >= exc.codeSize)
+                return SetErrorAndReturn(exc, FT_Common.FT_Err_Code_Overflow);
+
+            exc.length = 2 - exc.length * exc.code.data[exc.code.pos + exc.IP + 1];
+        }
+
+        if (exc.IP + exc.length > exc.codeSize)
+            return SetErrorAndReturn(exc, FT_Common.FT_Err_Code_Overflow);
+
+        /* First, let's check for empty stack and overflow */
+        exc.args = exc.top - (Pop_Push_Count[exc.opcode] >> 4);
+
+        /* `args' is the top of the stack once arguments have been popped. */
+        /* One can also interpret it as the index of the last argument.    */
+        if (exc.args < 0)
+        {
+            if (exc.pedantic_hinting)
+            {
+                exc.error = FT_Common.FT_Err_Too_Few_Arguments;
+                return SetErrorAndReturn(exc);
+            }
+
+            /* push zeroes onto the stack */
+            var __l = Pop_Push_Count[exc.opcode] >> 4;
+            for (var i = 0; i < __l; i++)
+                exc.stack[i] = 0;
+            exc.args = 0;
+        }
+
+        exc.new_top = exc.args + (Pop_Push_Count[exc.opcode] & 15);
+
+        /* `new_top' is the new top of the stack, after the instruction's */
+        /* execution.  `top' will be set to `new_top' after the `switch'  */
+        /* statement.                                                     */
+        if (exc.new_top > exc.stackSize)
+        {
+            exc.error = FT_Common.FT_Err_Stack_Overflow;
+            return SetErrorAndReturn(exc);
+        }
+
+        exc.step_ins = true;
+        exc.error    = 0;
+
+        Instruct_Dispatch[exc.opcode](exc, exc.stack, exc.args);
+ 
+        var bSuiteLabel = false;
+        if (exc.error != 0)
+        {
+            switch (exc.error)
+            {
+                case FT_Common.FT_Err_Invalid_Opcode: /* looking for redefined instructions */
+                {
+                    var defs  = exc.IDefs;
+                    var limit = exc.numIDefs;
+
+                    for (var def = 0; def < limit; def++)
+                    {
+                        var _def = defs[def];
+                        if (def.active && exc.opcode == def.opc)
+                        {
+                            if (exc.callTop >= exc.callSize)
+                            {
+                                exc.error = FT_Common.FT_Err_Invalid_Reference;
+                                return SetErrorAndReturn(exc);
+                            }
+
+                            var callrec = exc.callStack[exc.callTop];
+
+                            callrec.Caller_Range = exc.curRange;
+                            callrec.Caller_IP    = exc.IP + 1;
+                            callrec.Cur_Count    = 1;
+                            callrec.Cur_Restart  = _def.start;
+                            callrec.Cur_End      = _def.end;
+
+                            if (Ins_Goto_CodeRange(def.range, def.start) == 1)
+                                return SetErrorAndReturn(exc);
+
+                            bSuiteLabel = true;
+                            break;
+                        }
+                    }
+                }
+
+                if (!bSuiteLabel)
+                {
+                    exc.error = FT_Common.FT_Err_Invalid_Opcode;
+                    return SetErrorAndReturn(exc);
+                }
+
+            default:
+                if (!bSuiteLabel)
+                    return SetErrorAndReturn(exc);
+            }
+        }
+
+        if (!bSuiteLabel)
+        {
+            exc.top = exc.new_top;
+
+            if (exc.step_ins)
+                exc.IP += exc.length;
+
+            /* increment instruction counter and check if we didn't */
+            /* run this program for too long (e.g. infinite loops). */
+            if (++ins_counter > FT_Common.MAX_RUNNABLE_OPCODES)
+                return FT_Common.FT_Err_Execution_Too_Long;
+        }
+
+        if (exc.IP >= exc.codeSize)
+        {
+            if (exc.callTop > 0)
+            {
+                exc.error = FT_Common.FT_Err_Code_Overflow;
+                return SetErrorAndReturn(exc);
+            }
+            else
+                return 0;
+        }
+
+    } while (!exc.instruction_trap);
+
+    return 0;
+}
+
+function SetErrorAndReturn(exc, err)
+{
+    if (undefined !== err)
+        exc.error = err;
+
+    if (exc.error != 0 && !exc.instruction_trap)
+    {
+        exc.size.cvt_ready = false;
+    }
+
+    return exc.error;
+}
+
+function Read_CVT(exc, idx)
+{
+    return exc.cvt[idx];
+}
+
+function Read_CVT_Stretched(exc, idx)
+{
+    return FT_MulFix(exc.cvt[idx], Current_Ratio(exc));
+}
+
+function Write_CVT(exc, idx, value)
+{
+    exc.cvt[idx] = value;
+}
+
+function Write_CVT_Stretched(exc, idx, value)
+{
+    exc.cvt[idx] = FT_DivFix(value, Current_Ratio(exc));
+}
+
+function Move_CVT(exc, idx, value)
+{
+    exc.cvt[idx] += value;
+}
+
+function Move_CVT_Stretched(exc, idx, value)
+{
+    exc.cvt[idx] += FT_DivFix(value, Current_Ratio(exc));
+}
+
+/*********************************************************************/
+/*********************************************************************/
+/*********************************************************************/
+/*********************************************************************/
+/*********************************************************************/
+/*********************************************************************/
+function CSubpixHintingHacks()
+{
+    this.FAMILY_CLASS_Rules = {};
+
+    var _object_MS_Legacy_Fonts = {};
+    _object_MS_Legacy_Fonts["Aharoni"] = true;
+    _object_MS_Legacy_Fonts["Andale Mono"] = true;
+    _object_MS_Legacy_Fonts["Andalus"] = true;
+    _object_MS_Legacy_Fonts["Angsana New"] = true;
+    _object_MS_Legacy_Fonts["AngsanaUPC"] = true;
+    _object_MS_Legacy_Fonts["Arabic Transparent"] = true;
+    _object_MS_Legacy_Fonts["Arial Black"] = true;
+    _object_MS_Legacy_Fonts["Arial Narrow"] = true;
+    _object_MS_Legacy_Fonts["Arial Unicode MS"] = true;
+    _object_MS_Legacy_Fonts["Arial"] = true;
+    _object_MS_Legacy_Fonts["Batang"] = true;
+    _object_MS_Legacy_Fonts["Browallia New"] = true;
+    _object_MS_Legacy_Fonts["BrowalliaUPC"] = true;
+    _object_MS_Legacy_Fonts["Comic Sans MS"] = true;
+    _object_MS_Legacy_Fonts["Cordia New"] = true;
+    _object_MS_Legacy_Fonts["CordiaUPC"] = true;
+    _object_MS_Legacy_Fonts["Courier New"] = true;
+    _object_MS_Legacy_Fonts["DFKai-SB"] = true;
+    _object_MS_Legacy_Fonts["David Transparent"] = true;
+    _object_MS_Legacy_Fonts["David"] = true;
+    _object_MS_Legacy_Fonts["DilleniaUPC"] = true;
+    _object_MS_Legacy_Fonts["Estrangelo Edessa"] = true;
+    _object_MS_Legacy_Fonts["EucrosiaUPC"] = true;
+    _object_MS_Legacy_Fonts["FangSong_GB2312"] = true;
+    _object_MS_Legacy_Fonts["Fixed Miriam Transparent"] = true;
+    _object_MS_Legacy_Fonts["FrankRuehl"] = true;
+    _object_MS_Legacy_Fonts["Franklin Gothic Medium"] = true;
+    _object_MS_Legacy_Fonts["FreesiaUPC"] = true;
+    _object_MS_Legacy_Fonts["Garamond"] = true;
+    _object_MS_Legacy_Fonts["Gautami"] = true;
+    _object_MS_Legacy_Fonts["Georgia"] = true;
+    _object_MS_Legacy_Fonts["Gulim"] = true;
+    _object_MS_Legacy_Fonts["Impact"] = true;
+    _object_MS_Legacy_Fonts["IrisUPC"] = true;
+    _object_MS_Legacy_Fonts["JasmineUPC"] = true;
+    _object_MS_Legacy_Fonts["KaiTi_GB2312"] = true;
+    _object_MS_Legacy_Fonts["KodchiangUPC"] = true;
+    _object_MS_Legacy_Fonts["Latha"] = true;
+    _object_MS_Legacy_Fonts["Levenim MT"] = true;
+    _object_MS_Legacy_Fonts["LilyUPC"] = true;
+    _object_MS_Legacy_Fonts["Lucida Console"] = true;
+    _object_MS_Legacy_Fonts["Lucida Sans Unicode"] = true;
+    _object_MS_Legacy_Fonts["MS Gothic"] = true;
+    _object_MS_Legacy_Fonts["MS Mincho"] = true;
+    _object_MS_Legacy_Fonts["MV Boli"] = true;
+    _object_MS_Legacy_Fonts["Mangal"] = true;
+    _object_MS_Legacy_Fonts["Marlett"] = true;
+    _object_MS_Legacy_Fonts["Microsoft Sans Serif"] = true;
+    _object_MS_Legacy_Fonts["Mingliu"] = true;
+    _object_MS_Legacy_Fonts["Miriam Fixed"] = true;
+    _object_MS_Legacy_Fonts["Miriam Transparent"] = true;
+    _object_MS_Legacy_Fonts["Miriam"] = true;
+    _object_MS_Legacy_Fonts["Narkisim"] = true;
+    _object_MS_Legacy_Fonts["Palatino Linotype"] = true;
+    _object_MS_Legacy_Fonts["Raavi"] = true;
+    _object_MS_Legacy_Fonts["Rod Transparent"] = true;
+    _object_MS_Legacy_Fonts["Rod"] = true;
+    _object_MS_Legacy_Fonts["Shruti"] = true;
+    _object_MS_Legacy_Fonts["SimHei"] = true;
+    _object_MS_Legacy_Fonts["Simplified Arabic Fixed"] = true;
+    _object_MS_Legacy_Fonts["Simplified Arabic"] = true;
+    _object_MS_Legacy_Fonts["Simsun"] = true;
+    _object_MS_Legacy_Fonts["Sylfaen"] = true;
+    _object_MS_Legacy_Fonts["Symbol"] = true;
+    _object_MS_Legacy_Fonts["Tahoma"] = true;
+    _object_MS_Legacy_Fonts["Times New Roman"] = true;
+    _object_MS_Legacy_Fonts["Traditional Arabic"] = true;
+    _object_MS_Legacy_Fonts["Trebuchet MS"] = true;
+    _object_MS_Legacy_Fonts["Tunga"] = true;
+    _object_MS_Legacy_Fonts["Verdana"] = true;
+    _object_MS_Legacy_Fonts["Webdings"] = true;
+    _object_MS_Legacy_Fonts["Wingdings"] = true;
+
+    var _object_Core_MS_Legacy_Fonts = {};
+    _object_Core_MS_Legacy_Fonts["Arial Black"] = true;
+    _object_Core_MS_Legacy_Fonts["Arial Narrow"] = true;
+    _object_Core_MS_Legacy_Fonts["Arial Unicode MS"] = true;
+    _object_Core_MS_Legacy_Fonts["Arial"] = true;
+    _object_Core_MS_Legacy_Fonts["Comic Sans MS"] = true;
+    _object_Core_MS_Legacy_Fonts["Courier New"] = true;
+    _object_Core_MS_Legacy_Fonts["Garamond"] = true;
+    _object_Core_MS_Legacy_Fonts["Georgia"] = true;
+    _object_Core_MS_Legacy_Fonts["Impact"] = true;
+    _object_Core_MS_Legacy_Fonts["Lucida Console"] = true;
+    _object_Core_MS_Legacy_Fonts["Lucida Sans Unicode"] = true;
+    _object_Core_MS_Legacy_Fonts["Microsoft Sans Serif"] = true;
+    _object_Core_MS_Legacy_Fonts["Palatino Linotype"] = true;
+    _object_Core_MS_Legacy_Fonts["Tahoma"] = true;
+    _object_Core_MS_Legacy_Fonts["Times New Roman"] = true;
+    _object_Core_MS_Legacy_Fonts["Trebuchet MS"] = true;
+    _object_Core_MS_Legacy_Fonts["Verdana"] = true;
+
+    var _object_Apple_Legacy_Fonts = {};
+    _object_Apple_Legacy_Fonts["Geneva"] = true;
+    _object_Apple_Legacy_Fonts["Times"] = true;
+    _object_Apple_Legacy_Fonts["Monaco"] = true;
+    _object_Apple_Legacy_Fonts["Century"] = true;
+    _object_Apple_Legacy_Fonts["Chalkboard"] = true;
+    _object_Apple_Legacy_Fonts["Lobster"] = true;
+    _object_Apple_Legacy_Fonts["Century Gothic"] = true;
+    _object_Apple_Legacy_Fonts["Optima"] = true;
+    _object_Apple_Legacy_Fonts["Lucida Grande"] = true;
+    _object_Apple_Legacy_Fonts["Gill Sans"] = true;
+    _object_Apple_Legacy_Fonts["Baskerville"] = true;
+    _object_Apple_Legacy_Fonts["Helvetica"] = true;
+    _object_Apple_Legacy_Fonts["Helvetica Neue"] = true;
+
+    var _object_Legacy_Sans_Fonts = {};
+    _object_Legacy_Sans_Fonts["Andale Mono"] = true;
+    _object_Legacy_Sans_Fonts["Arial Unicode MS"] = true;
+    _object_Legacy_Sans_Fonts["Arial"] = true;
+    _object_Legacy_Sans_Fonts["Century Gothic"] = true;
+    _object_Legacy_Sans_Fonts["Comic Sans MS"] = true;
+    _object_Legacy_Sans_Fonts["Franklin Gothic Medium"] = true;
+    _object_Legacy_Sans_Fonts["Geneva"] = true;
+    _object_Legacy_Sans_Fonts["Lucida Console"] = true;
+    _object_Legacy_Sans_Fonts["Lucida Grande"] = true;
+    _object_Legacy_Sans_Fonts["Lucida Sans Unicode"] = true;
+    _object_Legacy_Sans_Fonts["Lucida Sans Typewriter"] = true;
+    _object_Legacy_Sans_Fonts["Microsoft Sans Serif"] = true;
+    _object_Legacy_Sans_Fonts["Monaco"] = true;
+    _object_Legacy_Sans_Fonts["Tahoma"] = true;
+    _object_Legacy_Sans_Fonts["Trebuchet MS"] = true;
+    _object_Legacy_Sans_Fonts["Verdana"] = true;
+
+    var _object_Misc_Legacy_Fonts = {};
+    _object_Misc_Legacy_Fonts["Dark Courier"] = true;
+
+    var _object_Verdana_Clones = {};
+    _object_Verdana_Clones["DejaVu Sans"] = true;
+    _object_Verdana_Clones["Bitstream Vera Sans"] = true;
+
+    var _object_Verdana_and_Clones = {};
+    _object_Verdana_and_Clones["DejaVu Sans"] = true;
+    _object_Verdana_and_Clones["Bitstream Vera Sans"] = true;
+    _object_Verdana_and_Clones["Verdana"] = true;
+
+    this.FAMILY_CLASS_Rules["MS Legacy Fonts"] = _object_MS_Legacy_Fonts;
+    this.FAMILY_CLASS_Rules["Core MS Legacy Fonts"] = _object_Core_MS_Legacy_Fonts;
+    this.FAMILY_CLASS_Rules["Apple Legacy Fonts"] = _object_Apple_Legacy_Fonts;
+    this.FAMILY_CLASS_Rules["Legacy Sans Fonts"] = _object_Legacy_Sans_Fonts;
+    this.FAMILY_CLASS_Rules["Misc Legacy Fonts"] = _object_Misc_Legacy_Fonts;
+    this.FAMILY_CLASS_Rules["Verdana Clones"] = _object_Verdana_Clones;
+    this.FAMILY_CLASS_Rules["Verdana and Clones"] = _object_Verdana_and_Clones;
+
+    _object_MS_Legacy_Fonts = null;
+    _object_Core_MS_Legacy_Fonts = null;
+    _object_Apple_Legacy_Fonts = null;
+    _object_Legacy_Sans_Fonts = null;
+    _object_Misc_Legacy_Fonts = null;
+    _object_Verdana_Clones = null;
+    _object_Verdana_and_Clones = null;
+
+    this.STYLE_CLASS_Rules = {};
+
+    var _object_Regular_Class = {};
+    _object_Regular_Class["Regular"] = true;
+    _object_Regular_Class["Book"] = true;
+    _object_Regular_Class["Medium"] = true;
+    _object_Regular_Class["Roman"] = true;
+    _object_Regular_Class["Normal"] = true;
+
+    var _object_RegularItalic_Class = {};
+    _object_RegularItalic_Class["Regular"] = true;
+    _object_RegularItalic_Class["Book"] = true;
+    _object_RegularItalic_Class["Medium"] = true;
+    _object_RegularItalic_Class["Italic"] = true;
+    _object_RegularItalic_Class["Oblique"] = true;
+    _object_RegularItalic_Class["Roman"] = true;
+    _object_RegularItalic_Class["Normal"] = true;
+
+    var _object_BoldBoldItalic_Class = {};
+    _object_BoldBoldItalic_Class["Bold"] = true;
+    _object_BoldBoldItalic_Class["Bold Italic"] = true;
+    _object_BoldBoldItalic_Class["Black"] = true;
+
+    var _object_BoldItalicBoldItalic_Class = {};
+    _object_BoldItalicBoldItalic_Class["Bold"] = true;
+    _object_BoldItalicBoldItalic_Class["Bold Italic"] = true;
+    _object_BoldItalicBoldItalic_Class["Black"] = true;
+    _object_BoldItalicBoldItalic_Class["Italic"] = true;
+    _object_BoldItalicBoldItalic_Class["Oblique"] = true;
+
+    var _object_RegularBold_Class = {};
+    _object_RegularBold_Class["Regular"] = true;
+    _object_RegularBold_Class["Book"] = true;
+    _object_RegularBold_Class["Medium"] = true;
+    _object_RegularBold_Class["Normal"] = true;
+    _object_RegularBold_Class["Roman"] = true;
+    _object_RegularBold_Class["Bold"] = true;
+    _object_RegularBold_Class["Black"] = true;
+
+    this.STYLE_CLASS_Rules["Regular Class"] = _object_Regular_Class;
+    this.STYLE_CLASS_Rules["Regular/Italic Class"] = _object_RegularItalic_Class;
+    this.STYLE_CLASS_Rules["Bold/BoldItalic Class"] = _object_BoldBoldItalic_Class;
+    this.STYLE_CLASS_Rules["Bold/Italic/BoldItalic Class"] = _object_BoldItalicBoldItalic_Class;
+    this.STYLE_CLASS_Rules["Regular/Bold Class"] = _object_RegularBold_Class;
+
+    this.is_member_of_family_class = function(detected_font_name, rule_font_name)
+    {
+        /* Does font name match rule family? */
+        if (detected_font_name == rule_font_name)
+            return true;
+
+        /* Is font name a wildcard ""? */
+        if (rule_font_name == "")
+            return true;
+
+        var _fcr = this.FAMILY_CLASS_Rules[rule_font_name];
+        if (undefined !== _fcr)
+        {
+            if (undefined !== _fcr[detected_font_name])
+                return true;
+        }
+
+        return false;
+    }
+
+    this.is_member_of_style_class = function(detected_font_style, rule_font_style)
+    {
+        /* Does font style match rule style? */
+        if (detected_font_style == rule_font_style)
+            return true;
+
+        /* Is font style a wildcard ""? */
+        if (rule_font_style == "")
+            return true;
+
+        /* Is font style contained in a class list? */
+        var _scr = this.STYLE_CLASS_Rules[rule_font_style];
+        if (undefined !== _scr)
+        {
+            if (undefined !== _scr[detected_font_style])
+                return true;
+        }
+
+        return false;
+    }
+
+    this.sph_test_tweak = function(face, family, ppem, style, glyph_index, rule, num_rules)
+    {
+        /* rule checks may be able to be optimized further */
+        for (var i = 0; i < num_rules; i++)
+        {
+            if (family != "" && this.is_member_of_family_class(family, rule[i].family))
+            {
+                if (rule[i].ppem == 0 || rule[i].ppem == ppem)
+                {
+                    if (style != "" && this.is_member_of_style_class(style, rule[i].style))
+                    {
+                        if (rule[i].glyph == 0 || FT_Get_Char_Index(face, rule[i].glyph) == glyph_index)
+                            return true;
+                    }
+                }
+            }
+        }
+        return false;
+    }
+
+    this.scale_test_tweak = function(face, family, ppem, style, glyph_index, rule, num_rules)
+    {
+        /* rule checks may be able to be optimized further */
+        for (var i = 0; i < num_rules; i++)
+        {
+            if (family != "" && this.is_member_of_family_class(family, rule[i].family))
+            {
+                if (rule[i].ppem == 0 || rule[i].ppem == ppem)
+                {
+                    if (style != "" && this.is_member_of_style_class(style, rule[i].style))
+                    {
+                        if (rule[i].glyph == 0 || FT_Get_Char_Index(face, rule[i].glyph) == glyph_index)
+                            return rule[i].scale;
+                    }
+                }
+            }
+        }
+        return 1000;
+    }
+
+    this.sph_set_tweaks = function(loader, glyph_index)
+    {
+        var face = loader.face;
+        var family = face.family_name;
+        var ppem = loader.size.metrics.x_ppem;
+        var style = face.style_name;
+
+        /* don't apply rules if style isn't set */
+        if (face.style_name == "")
+            return;
+
+        if (this.sph_test_tweak(face, family, ppem, style, glyph_index, this.PIXEL_HINTING_Rules, this.PIXEL_HINTING_RULES_SIZE))
+            loader.exec.sph_tweak_flags |= FT_Common.SPH_TWEAK_PIXEL_HINTING;
+
+        if (loader.exec.sph_tweak_flags & FT_Common.SPH_TWEAK_PIXEL_HINTING)
+        {
+            loader.exec.ignore_x_mode = false;
+            return;
+        }
+
+        if (this.sph_test_tweak(face, family, ppem, style, glyph_index, this.ALLOW_X_DMOVE_Rules, this.ALLOW_X_DMOVE_RULES_SIZE))
+            loader.exec.sph_tweak_flags |= FT_Common.SPH_TWEAK_ALLOW_X_DMOVE;
+
+        if (this.sph_test_tweak(face, family, ppem, style, glyph_index, this.ALLOW_X_DMOVEX_Rules, this.ALLOW_X_DMOVEX_RULES_SIZE))
+            loader.exec.sph_tweak_flags |= FT_Common.SPH_TWEAK_ALLOW_X_DMOVEX;
+
+        if (this.sph_test_tweak(face, family, ppem, style, glyph_index, this.ALLOW_X_MOVE_ZP2_Rules, this.ALLOW_X_MOVE_ZP2_RULES_SIZE))
+            loader.exec.sph_tweak_flags |= FT_Common.SPH_TWEAK_ALLOW_X_MOVE_ZP2;
+
+        if (this.sph_test_tweak(face, family, ppem, style, glyph_index, this.ALWAYS_DO_DELTAP_Rules, this.ALWAYS_DO_DELTAP_RULES_SIZE))
+            loader.exec.sph_tweak_flags |= FT_Common.SPH_TWEAK_ALWAYS_DO_DELTAP;
+
+        if (this.sph_test_tweak(face, family, ppem, style, glyph_index, this.ALWAYS_SKIP_DELTAP_Rules, this.ALWAYS_SKIP_DELTAP_RULES_SIZE))
+            loader.exec.sph_tweak_flags |= FT_Common.SPH_TWEAK_ALWAYS_SKIP_DELTAP;
+
+        if (this.sph_test_tweak(face, family, ppem, style, glyph_index, this.DEEMBOLDEN_Rules, this.DEEMBOLDEN_RULES_SIZE))
+            loader.exec.sph_tweak_flags |= FT_Common.SPH_TWEAK_DEEMBOLDEN;
+
+        if (this.sph_test_tweak(face, family, ppem, style, glyph_index, this.DELTAP_SKIP_EXAGGERATED_VALUES_Rules, this.DELTAP_SKIP_EXAGGERATED_VALUES_RULES_SIZE))
+            loader.exec.sph_tweak_flags |= FT_Common.SPH_TWEAK_DELTAP_SKIP_EXAGGERATED_VALUES;
+
+        if (this.sph_test_tweak(face, family, ppem, style, glyph_index, this.DO_SHPIX_Rules, this.DO_SHPIX_RULES_SIZE))
+            loader.exec.sph_tweak_flags |= FT_Common.SPH_TWEAK_DO_SHPIX;
+
+        if (this.sph_test_tweak(face, family, ppem, style, glyph_index, this.EMBOLDEN_Rules, this.EMBOLDEN_RULES_SIZE))
+            loader.exec.sph_tweak_flags |= FT_Common.SPH_TWEAK_EMBOLDEN;
+
+        if (this.sph_test_tweak(face, family, ppem, style, glyph_index, this.MIAP_HACK_Rules, this.MIAP_HACK_RULES_SIZE))
+            loader.exec.sph_tweak_flags |= FT_Common.SPH_TWEAK_MIAP_HACK;
+
+        if (this.sph_test_tweak(face, family, ppem, style, glyph_index, this.NORMAL_ROUND_Rules, this.NORMAL_ROUND_RULES_SIZE))
+            loader.exec.sph_tweak_flags |= FT_Common.SPH_TWEAK_NORMAL_ROUND;
+
+        if (this.sph_test_tweak(face, family, ppem, style, glyph_index, this.NO_ALIGNRP_AFTER_IUP_Rules, this.NO_ALIGNRP_AFTER_IUP_RULES_SIZE))
+            loader.exec.sph_tweak_flags |= FT_Common.SPH_TWEAK_NO_ALIGNRP_AFTER_IUP;
+
+        if (this.sph_test_tweak(face, family, ppem, style, glyph_index, this.NO_CALL_AFTER_IUP_Rules, this.NO_CALL_AFTER_IUP_RULES_SIZE))
+            loader.exec.sph_tweak_flags |= FT_Common.SPH_TWEAK_NO_CALL_AFTER_IUP;
+
+        if (this.sph_test_tweak(face, family, ppem, style, glyph_index, this.NO_DELTAP_AFTER_IUP_Rules, this.NO_DELTAP_AFTER_IUP_RULES_SIZE))
+            loader.exec.sph_tweak_flags |= FT_Common.SPH_TWEAK_NO_DELTAP_AFTER_IUP;
+
+        if (this.sph_test_tweak(face, family, ppem, style, glyph_index, this.RASTERIZER_35_Rules, this.RASTERIZER_35_RULES_SIZE))
+            loader.exec.sph_tweak_flags |= FT_Common.SPH_TWEAK_RASTERIZER_35;
+
+        if (this.sph_test_tweak(face, family, ppem, style, glyph_index, this.SKIP_INLINE_DELTAS_Rules, this.SKIP_INLINE_DELTAS_RULES_SIZE))
+            loader.exec.sph_tweak_flags |= FT_Common.SPH_TWEAK_SKIP_INLINE_DELTAS;
+
+        if (this.sph_test_tweak(face, family, ppem, style, glyph_index, this.SKIP_IUP_Rules, this.SKIP_IUP_RULES_SIZE))
+            loader.exec.sph_tweak_flags |= FT_Common.SPH_TWEAK_SKIP_IUP;
+
+        if (this.sph_test_tweak(face, family, ppem, style, glyph_index, this.MIRP_CVT_ZERO_Rules, this.MIRP_CVT_ZERO_RULES_SIZE))
+            loader.exec.sph_tweak_flags |= FT_Common.SPH_TWEAK_MIRP_CVT_ZERO;
+
+        if (this.sph_test_tweak(face, family, ppem, style, glyph_index, this.SKIP_OFFPIXEL_Y_MOVES_Rules, this.SKIP_OFFPIXEL_Y_MOVES_RULES_SIZE))
+            loader.exec.sph_tweak_flags |= FT_Common.SPH_TWEAK_SKIP_OFFPIXEL_Y_MOVES;
+
+        if (this.sph_test_tweak(face, family, ppem, style, glyph_index, this.SKIP_OFFPIXEL_Y_MOVES_Rules_Exceptions, this.SKIP_OFFPIXEL_Y_MOVES_RULES_EXCEPTIONS_SIZE))
+            loader.exec.sph_tweak_flags &= ~FT_Common.SPH_TWEAK_SKIP_OFFPIXEL_Y_MOVES;
+
+        if (this.sph_test_tweak(face, family, ppem, style, glyph_index, this.SKIP_NONPIXEL_Y_MOVES_Rules, this.SKIP_NONPIXEL_Y_MOVES_RULES_SIZE))
+            loader.exec.sph_tweak_flags |= FT_Common.SPH_TWEAK_SKIP_NONPIXEL_Y_MOVES;
+
+        if (this.sph_test_tweak(face, family, ppem, style, glyph_index, this.SKIP_NONPIXEL_Y_MOVES_Rules_Exceptions, this.SKIP_NONPIXEL_Y_MOVES_RULES_EXCEPTIONS_SIZE))
+            loader.exec.sph_tweak_flags &= ~FT_Common.SPH_TWEAK_SKIP_NONPIXEL_Y_MOVES;
+
+        if (this.sph_test_tweak(face, family, ppem, style, glyph_index, this.ROUND_NONPIXEL_Y_MOVES_Rules, this.ROUND_NONPIXEL_Y_MOVES_RULES_SIZE))
+            loader.exec.sph_tweak_flags |= FT_Common.SPH_TWEAK_ROUND_NONPIXEL_Y_MOVES;
+
+        if (this.sph_test_tweak(face, family, ppem, style, glyph_index, this.ROUND_NONPIXEL_Y_MOVES_Rules_Exceptions, this.ROUND_NONPIXEL_Y_MOVES_RULES_EXCEPTIONS_SIZE))
+            loader.exec.sph_tweak_flags &= ~FT_Common.SPH_TWEAK_ALLOW_X_DMOVE;
+
+        if (loader.exec.sph_tweak_flags & FT_Common.SPH_TWEAK_RASTERIZER_35)
+            loader.exec.rasterizer_version = 35;
+        else
+            loader.exec.rasterizer_version = FT_Common.SPH_OPTION_SET_RASTERIZER_VERSION;
+
+        /* re-execute fpgm always to avoid problems */
+        loader.exec.size.cvt_ready = false;
+        tt_size_ready_bytecode(loader.exec.size, (loader.load_flags & FT_Common.FT_LOAD_PEDANTIC) != 0);
+
+        if ((loader.load_flags & FT_Common.FT_LOAD_NO_HINTING) == 0)
+        {
+            if (this.sph_test_tweak(face, family, ppem, style, glyph_index, this.TIMES_NEW_ROMAN_HACK_Rules, this.TIMES_NEW_ROMAN_HACK_RULES_SIZE))
+                loader.exec.sph_tweak_flags |= FT_Common.SPH_TWEAK_TIMES_NEW_ROMAN_HACK;
+
+            if (this.sph_test_tweak(face, family, ppem, style, glyph_index, this.COURIER_NEW_2_HACK_Rules, this.COURIER_NEW_2_HACK_RULES_SIZE))
+                loader.exec.sph_tweak_flags |= FT_Common.SPH_TWEAK_COURIER_NEW_2_HACK;
+        }
+
+        if (this.sph_test_tweak(face, family, ppem, style, glyph_index, this.COMPATIBILITY_MODE_Rules, this.COMPATIBILITY_MODE_RULES_SIZE))
+        {
+            loader.exec.compatibility_mode = true;
+            loader.exec.ignore_x_mode      = true;
+        }
+        else
+            loader.exec.compatibility_mode = false;
+
+        if ((loader.load_flags & FT_Common.FT_LOAD_NO_HINTING) == 0)
+        {
+            if (this.sph_test_tweak(face, family, ppem, style, glyph_index, this.COMPATIBLE_WIDTHS_Rules, this.COMPATIBLE_WIDTHS_RULES_SIZE))
+                loader.exec.compatible_widths = true;
+        }
+    }
+
+    /***************************************************************/
+    /***************************************************************/
+    /***************************************************************/
+    this._create_SPH_TweakRule = function(family, ppem, style, glyph)
+    {
+        var _ret = new SPH_TweakRule();
+        _ret.family = family;
+        _ret.ppem = ppem;
+        _ret.style = style;
+        _ret.glyph = glyph;
+        return _ret;
+    }
+    this._create_SPH_ScaleRule = function(family, ppem, style, glyph, scale)
+    {
+        var _ret = new SPH_ScaleRule();
+        _ret.family = family;
+        _ret.ppem = ppem;
+        _ret.style = style;
+        _ret.glyph = glyph;
+        _ret.scale = scale;
+        return _ret;
+    }
+
+    this.COMPATIBILITY_MODE_RULES_SIZE = 4;
+    this.COMPATIBILITY_MODE_Rules = [
+        this._create_SPH_TweakRule("MS Legacy Fonts", 0, "", 0),
+        this._create_SPH_TweakRule("Apple Legacy Fonts", 0, "", 0),
+        this._create_SPH_TweakRule("Misc Legacy Fonts", 0, "", 0),
+        this._create_SPH_TweakRule("Verdana Clones", 0, "", 0)
+    ];
+
+    this.PIXEL_HINTING_RULES_SIZE = 4;
+    this.PIXEL_HINTING_Rules = [
+        /* these characters are almost always safe */
+        this._create_SPH_TweakRule("", 0, "", "<".charCodeAt(0)),
+        this._create_SPH_TweakRule("", 0, "", ">".charCodeAt(0)),
+        /* fixes the vanishing stem */
+        this._create_SPH_TweakRule("Times New Roman", 0, "Bold", "A".charCodeAt(0)),
+        this._create_SPH_TweakRule("Times New Roman", 0, "Bold", "V".charCodeAt(0))
+    ];
+
+    /* According to Greg Hitchcock and the MS whitepaper, this should work   */
+    /* on all legacy MS fonts, but creates artifacts with some.  Only using  */
+    /* where absolutely necessary.                                           */
+    this.SKIP_INLINE_DELTAS_RULES_SIZE = 1;
+    this.SKIP_INLINE_DELTAS_Rules = [
+        this._create_SPH_TweakRule("-", 0, "", 0)
+    ];
+
+
+    /* Subpixel hinting ignores SHPIX rules on X.  Force SHPIX for these.    */
+    this.DO_SHPIX_RULES_SIZE = 1;
+    this.DO_SHPIX_Rules = [
+        this._create_SPH_TweakRule("-", 0, "", 0)
+    ];
+
+
+    /* Skip Y moves that start with a point that is not on a Y pixel         */
+    /* boundary and don't move that point to a Y pixel boundary.             */
+    this.SKIP_NONPIXEL_Y_MOVES_RULES_SIZE = 10;
+    this.SKIP_NONPIXEL_Y_MOVES_Rules = [
+        /* fix vwxyz thinness*/
+        this._create_SPH_TweakRule("Consolas", 0, "Regular", 0),
+        /* fix tiny gap at top of m */
+        this._create_SPH_TweakRule("Arial", 0, "Regular", "m".charCodeAt(0)),
+        /* Fix thin middle stems */
+        this._create_SPH_TweakRule("Core MS Legacy Fonts", 0, "Regular/Bold Class", "N".charCodeAt(0)),
+        this._create_SPH_TweakRule("Lucida Grande", 0, "", "N".charCodeAt(0)),
+        this._create_SPH_TweakRule("Lucida Grande", 0, "Bold", "y".charCodeAt(0)),
+        /* Cyrillic small letter I */
+        this._create_SPH_TweakRule("Legacy Sans Fonts", 0, "", 0x438),
+        this._create_SPH_TweakRule("Verdana Clones", 0, "","N".charCodeAt(0)),
+        this._create_SPH_TweakRule("Ubuntu", 0, "Regular Class", "N".charCodeAt(0)),
+        /* Fix misshapen x */
+        this._create_SPH_TweakRule("Verdana", 0, "Bold", "x".charCodeAt(0)),
+        /* Fix misshapen s */
+        this._create_SPH_TweakRule("Tahoma", 0, "", "s".charCodeAt(0))
+    ];
+
+    this.SKIP_NONPIXEL_Y_MOVES_RULES_EXCEPTIONS_SIZE = 6;
+    this.SKIP_NONPIXEL_Y_MOVES_Rules_Exceptions = [
+        this._create_SPH_TweakRule("Tahoma", 0, "", "N".charCodeAt(0)),
+        this._create_SPH_TweakRule("Comic Sans MS", 0, "", "N".charCodeAt(0)),
+        this._create_SPH_TweakRule("Verdana", 0, "Regular/Bold Class", "N".charCodeAt(0)),
+        this._create_SPH_TweakRule("Verdana", 11, "Bold", "x".charCodeAt(0)),
+        /* Cyrillic small letter I */
+        this._create_SPH_TweakRule("Arial", 0, "", 0x438),
+        this._create_SPH_TweakRule("Trebuchet MS", 0, "Bold", 0)
+    ];
+
+
+    /* Skip Y moves that move a point off a Y pixel boundary.                */
+    /* This fixes Tahoma, Trebuchet oddities and some issues with `$'.       */
+    this.SKIP_OFFPIXEL_Y_MOVES_RULES_SIZE = 5;
+    this.SKIP_OFFPIXEL_Y_MOVES_Rules = [
+        this._create_SPH_TweakRule("MS Legacy Fonts", 0, "", 0),
+        this._create_SPH_TweakRule("Apple Legacy Fonts", 0, "", 0),
+        this._create_SPH_TweakRule("Misc Legacy Fonts", 0, "", 0),
+        this._create_SPH_TweakRule("Ubuntu", 0, "Regular Class", 0),
+        this._create_SPH_TweakRule("Verdana Clones", 0, "", 0)
+    ];
+
+
+    this.SKIP_OFFPIXEL_Y_MOVES_RULES_EXCEPTIONS_SIZE = 1;
+    this.SKIP_OFFPIXEL_Y_MOVES_Rules_Exceptions = [
+        this._create_SPH_TweakRule("-", 0, "", 0)
+    ];
+
+
+    /* Round moves that don't move a point to a Y pixel boundary.            */
+    this.ROUND_NONPIXEL_Y_MOVES_RULES_SIZE = 3;
+    this.ROUND_NONPIXEL_Y_MOVES_Rules = [
+        /* Droid font instructions don't snap Y to pixels */
+        this._create_SPH_TweakRule("Droid Sans", 0, "Regular/Italic Class", 0),
+        this._create_SPH_TweakRule("Droid Sans Mono", 0, "", 0),
+        this._create_SPH_TweakRule("Ubuntu", 0, "", 0)
+    ];
+
+
+    this.ROUND_NONPIXEL_Y_MOVES_RULES_EXCEPTIONS_SIZE = 3;
+    this.ROUND_NONPIXEL_Y_MOVES_Rules_Exceptions = [
+        this._create_SPH_TweakRule("Droid Sans", 12, "Bold", 0),
+        this._create_SPH_TweakRule("Droid Sans", 13, "Bold", 0),
+        this._create_SPH_TweakRule("Droid Sans", 16, "Bold", 0)
+    ];
+
+
+    /* Allow a Direct_Move_X along X freedom vector if matched.              */
+    this.ALLOW_X_DMOVEX_RULES_SIZE = 1;
+    this.ALLOW_X_DMOVEX_Rules = [
+        this._create_SPH_TweakRule("-", 0, "Regular", 0)
+    ];
+
+
+    /* Allow a Direct_Move along X freedom vector if matched.                */
+    this.ALLOW_X_DMOVE_RULES_SIZE = 1;
+    this.ALLOW_X_DMOVE_Rules = [
+        /* Fixes vanishing diagonal in 4 */
+        this._create_SPH_TweakRule("Verdana", 0, "Regular", "4".charCodeAt(0))
+    ];
+
+
+    /* Allow a ZP2 move along freedom vector if matched;                     */
+    /* This is called from SHP, SHPIX, SHC, SHZ.                             */
+    this.ALLOW_X_MOVE_ZP2_RULES_SIZE = 1;
+    this.ALLOW_X_MOVE_ZP2_Rules = [
+        this._create_SPH_TweakRule("-", 0, "", 0)
+    ];
+
+
+    /* Return MS rasterizer version 35 if matched.                           */
+    this.RASTERIZER_35_RULES_SIZE = 8;
+    this.RASTERIZER_35_Rules = [
+        /* This seems to be the only way to make these look good */
+        this._create_SPH_TweakRule("Times New Roman", 0, "Regular", "i".charCodeAt(0)),
+        this._create_SPH_TweakRule("Times New Roman", 0, "Regular", "j".charCodeAt(0)),
+        this._create_SPH_TweakRule("Times New Roman", 0, "Regular", "m".charCodeAt(0)),
+        this._create_SPH_TweakRule("Times New Roman", 0, "Regular", "r".charCodeAt(0)),
+        this._create_SPH_TweakRule("Times New Roman", 0, "Regular", "a".charCodeAt(0)),
+        this._create_SPH_TweakRule("Times New Roman", 0, "Regular", "n".charCodeAt(0)),
+        this._create_SPH_TweakRule("Times New Roman", 0, "Regular", "p".charCodeAt(0)),
+        this._create_SPH_TweakRule("Times", 0, "", 0)
+    ];
+
+
+    /* Don't round to the subpixel grid.  Round to pixel grid.               */
+    this.NORMAL_ROUND_RULES_SIZE = 2;
+    this.NORMAL_ROUND_Rules = [
+        /* Fix point "explosions" */
+        this._create_SPH_TweakRule("Courier New", 0, "", 0),
+        this._create_SPH_TweakRule("Verdana", 10, "Regular", "4".charCodeAt(0))
+    ];
+
+
+    /* Skip IUP instructions if matched.                                     */
+    this.SKIP_IUP_RULES_SIZE = 1;
+    this.SKIP_IUP_Rules = [
+        this._create_SPH_TweakRule("Arial", 13, "Regular", "a".charCodeAt(0))
+    ];
+
+
+    /* Skip MIAP Twilight hack if matched.                                   */
+    this.MIAP_HACK_RULES_SIZE = 1;
+    this.MIAP_HACK_Rules = [
+        this._create_SPH_TweakRule("Geneva", 12, "", 0)
+    ];
+
+
+    /* Skip DELTAP instructions if matched.                                  */
+    this.ALWAYS_SKIP_DELTAP_RULES_SIZE = 16;
+    this.ALWAYS_SKIP_DELTAP_Rules = [
+        this._create_SPH_TweakRule("Georgia", 0, "Regular", "k".charCodeAt(0)),
+        /* fixes problems with W M w */
+        this._create_SPH_TweakRule("Trebuchet MS", 0, "Italic", 0),
+        /* fix various problems with e in different versions */
+        this._create_SPH_TweakRule("Trebuchet MS", 14, "Regular", "e".charCodeAt(0)),
+        this._create_SPH_TweakRule("Trebuchet MS", 13, "Regular", "e".charCodeAt(0)),
+        this._create_SPH_TweakRule("Trebuchet MS", 15, "Regular", "e".charCodeAt(0)),
+        this._create_SPH_TweakRule("Arial", 11, "Regular", "s".charCodeAt(0)),
+        this._create_SPH_TweakRule("Verdana", 10, "Regular", 0),
+        this._create_SPH_TweakRule("Verdana", 9, "Regular", 0),
+        /* Cyrillic small letter short I */
+        this._create_SPH_TweakRule("Legacy Sans Fonts", 0, "", 0x438),
+        this._create_SPH_TweakRule("Legacy Sans Fonts", 0, "", 0x439),
+        this._create_SPH_TweakRule("Arial", 10, "Regular", "6".charCodeAt(0)),
+        this._create_SPH_TweakRule("Arial", 0, "Bold/BoldItalic Class", "a".charCodeAt(0)),
+        /* Make horizontal stems consistent with the rest */
+        this._create_SPH_TweakRule("Arial", 24, "Bold", "s".charCodeAt(0)),
+        this._create_SPH_TweakRule("Arial", 25, "Bold", "s".charCodeAt(0)),
+        this._create_SPH_TweakRule("Arial", 24, "Bold", "a".charCodeAt(0)),
+        this._create_SPH_TweakRule("Arial", 25, "Bold", "a".charCodeAt(0))
+    ];
+
+
+    /* Always do DELTAP instructions if matched.                             */
+    this.ALWAYS_DO_DELTAP_RULES_SIZE = 2;
+    this.ALWAYS_DO_DELTAP_Rules = [
+        this._create_SPH_TweakRule("Verdana Clones", 17, "Regular Class", "K".charCodeAt(0)),
+        this._create_SPH_TweakRule("Verdana Clones", 17, "Regular Class", "k".charCodeAt(0))
+    ];
+
+
+    /* Do an extra RTG instruction in DELTAP if matched.                     */
+    this.DELTAP_RTG_RULES_SIZE = 1;
+    this.DELTAP_RTG_Rules = [
+        this._create_SPH_TweakRule("-", 0, "", 0)
+    ];
+
+
+    /* Force CVT distance to zero in MIRP.                                   */
+    this.MIRP_CVT_ZERO_RULES_SIZE = 1;
+    this.MIRP_CVT_ZERO_Rules = [
+        this._create_SPH_TweakRule("-", 0, "", 0)
+    ];
+
+
+    /* Skip moves that meet or exceed 1 pixel.                               */
+    this.DELTAP_SKIP_EXAGGERATED_VALUES_RULES_SIZE = 1;
+    this.DELTAP_SKIP_EXAGGERATED_VALUES_Rules = [
+        /* Fix vanishing stems */
+        this._create_SPH_TweakRule("Ubuntu", 0, "Regular", "M".charCodeAt(0))
+    ];
+
+
+    /* Don't allow ALIGNRP after IUP.                                        */
+    this.NO_ALIGNRP_AFTER_IUP_RULES_SIZE = 4;
+    this.NO_ALIGNRP_AFTER_IUP_Rules = [
+        /* Prevent creation of dents in outline */
+        this._create_SPH_TweakRule("Courier New", 0, "Bold", "C".charCodeAt(0)),
+        this._create_SPH_TweakRule("Courier New", 0, "Bold", "D".charCodeAt(0)),
+        this._create_SPH_TweakRule("Courier New", 0, "Bold", "Q".charCodeAt(0)),
+        this._create_SPH_TweakRule("Courier New", 0, "Bold", "0".charCodeAt(0))
+    ];
+
+
+    /* Don't allow DELTAP after IUP.                                         */
+    this.NO_DELTAP_AFTER_IUP_RULES_SIZE = 2;
+    this.NO_DELTAP_AFTER_IUP_Rules = [
+        this._create_SPH_TweakRule("Arial", 0, "Bold", "N".charCodeAt(0)),
+        this._create_SPH_TweakRule("Verdana", 0, "Regular", "4".charCodeAt(0))
+    ];
+
+
+    /* Don't allow CALL after IUP.                                           */
+    this.NO_CALL_AFTER_IUP_RULES_SIZE = 4;
+    this.NO_CALL_AFTER_IUP_Rules = [
+        /* Prevent creation of dents in outline */
+        this._create_SPH_TweakRule("Courier New", 0, "Bold", "O".charCodeAt(0)),
+        this._create_SPH_TweakRule("Courier New", 0, "Bold", "Q".charCodeAt(0)),
+        this._create_SPH_TweakRule("Courier New", 0, "Bold", "k".charCodeAt(0)),
+        this._create_SPH_TweakRule("Courier New", 0, "Bold Italic", "M".charCodeAt(0))
+    ];
+
+
+    /* De-embolden these glyphs slightly.                                    */
+    this.DEEMBOLDEN_RULES_SIZE = 9;
+    this.DEEMBOLDEN_Rules = [
+        this._create_SPH_TweakRule("Courier New", 0, "Bold", "A".charCodeAt(0)),
+        this._create_SPH_TweakRule("Courier New", 0, "Bold", "W".charCodeAt(0)),
+        this._create_SPH_TweakRule("Courier New", 0, "Bold", "w".charCodeAt(0)),
+        this._create_SPH_TweakRule("Courier New", 0, "Bold", "M".charCodeAt(0)),
+        this._create_SPH_TweakRule("Courier New", 0, "Bold", "X".charCodeAt(0)),
+        this._create_SPH_TweakRule("Courier New", 0, "Bold", "K".charCodeAt(0)),
+        this._create_SPH_TweakRule("Courier New", 0, "Bold", "x".charCodeAt(0)),
+        this._create_SPH_TweakRule("Courier New", 0, "Bold", "z".charCodeAt(0)),
+        this._create_SPH_TweakRule("Courier New", 0, "Bold", "v".charCodeAt(0))
+    ];
+
+
+    /* Embolden these glyphs slightly.                                       */
+    this.EMBOLDEN_RULES_SIZE = 5;
+    this.EMBOLDEN_Rules = [
+        this._create_SPH_TweakRule("Courier New", 12, "Italic", "z".charCodeAt(0)),
+        this._create_SPH_TweakRule("Courier New", 11, "Italic", "z".charCodeAt(0)),
+        this._create_SPH_TweakRule("Courier New", 10, "Italic", "z".charCodeAt(0)),
+        this._create_SPH_TweakRule("Courier New", 0, "Regular", 0),
+        this._create_SPH_TweakRule("Courier New", 0, "Italic", 0)
+    ];
+
+
+    /* Do an extra RDTG instruction in DELTAP if matched.                    */
+    this.DELTAP_RDTG_RULES_SIZE = 1;
+    this.DELTAP_RDTG_Rules = [
+        this._create_SPH_TweakRule("-", 0, "", 0)
+    ];
+
+
+    /* This is a CVT hack that makes thick horizontal stems on 2, 5, 7       */
+    /* similar to Windows XP.                                                */
+    this.TIMES_NEW_ROMAN_HACK_RULES_SIZE = 12;
+    this.TIMES_NEW_ROMAN_HACK_Rules = [
+        this._create_SPH_TweakRule("Times New Roman", 16, "Italic", "2".charCodeAt(0)),
+        this._create_SPH_TweakRule("Times New Roman", 16, "Italic", "5".charCodeAt(0)),
+        this._create_SPH_TweakRule("Times New Roman", 16, "Italic", "7".charCodeAt(0)),
+        this._create_SPH_TweakRule("Times New Roman", 16, "Regular", "2".charCodeAt(0)),
+        this._create_SPH_TweakRule("Times New Roman", 16, "Regular", "5".charCodeAt(0)),
+        this._create_SPH_TweakRule("Times New Roman", 16, "Regular", "7".charCodeAt(0)),
+        this._create_SPH_TweakRule("Times New Roman", 17, "Italic", "2".charCodeAt(0)),
+        this._create_SPH_TweakRule("Times New Roman", 17, "Italic", "5".charCodeAt(0)),
+        this._create_SPH_TweakRule("Times New Roman", 17, "Italic", "7".charCodeAt(0)),
+        this._create_SPH_TweakRule("Times New Roman", 17, "Regular", "2".charCodeAt(0)),
+        this._create_SPH_TweakRule("Times New Roman", 17, "Regular", "5".charCodeAt(0)),
+        this._create_SPH_TweakRule("Times New Roman", 17, "Regular", "7".charCodeAt(0))
+    ];
+
+
+    /* This fudges distance on 2 to get rid of the vanishing stem issue.     */
+    /* A real solution to this is certainly welcome.                         */
+    this.COURIER_NEW_2_HACK_RULES_SIZE = 15;
+    this.COURIER_NEW_2_HACK_Rules = [
+        this._create_SPH_TweakRule("Courier New", 10, "Regular", "2".charCodeAt(0)),
+        this._create_SPH_TweakRule("Courier New", 11, "Regular", "2".charCodeAt(0)),
+        this._create_SPH_TweakRule("Courier New", 12, "Regular", "2".charCodeAt(0)),
+        this._create_SPH_TweakRule("Courier New", 13, "Regular", "2".charCodeAt(0)),
+        this._create_SPH_TweakRule("Courier New", 14, "Regular", "2".charCodeAt(0)),
+        this._create_SPH_TweakRule("Courier New", 15, "Regular", "2".charCodeAt(0)),
+        this._create_SPH_TweakRule("Courier New", 16, "Regular", "2".charCodeAt(0)),
+        this._create_SPH_TweakRule("Courier New", 17, "Regular", "2".charCodeAt(0)),
+        this._create_SPH_TweakRule("Courier New", 18, "Regular", "2".charCodeAt(0)),
+        this._create_SPH_TweakRule("Courier New", 19, "Regular", "2".charCodeAt(0)),
+        this._create_SPH_TweakRule("Courier New", 20, "Regular", "2".charCodeAt(0)),
+        this._create_SPH_TweakRule("Courier New", 21, "Regular", "2".charCodeAt(0)),
+        this._create_SPH_TweakRule("Courier New", 22, "Regular", "2".charCodeAt(0)),
+        this._create_SPH_TweakRule("Courier New", 23, "Regular", "2".charCodeAt(0)),
+        this._create_SPH_TweakRule("Courier New", 24, "Regular", "2".charCodeAt(0))
+    ];
+
+
+    // #ifndef FORCE_NATURAL_WIDTHS -----------------------------------------------
+
+    /* Use compatible widths with these glyphs.  Compatible widths is always */
+    /* on when doing B/W TrueType instructing, but is used selectively here, */
+    /* typically on glyphs with 3 or more vertical stems.                    */
+    this.COMPATIBLE_WIDTHS_RULES_SIZE = 38;
+    this.COMPATIBLE_WIDTHS_Rules = [
+        this._create_SPH_TweakRule("Arial Unicode MS", 12, "Regular Class", "m".charCodeAt(0)),
+        this._create_SPH_TweakRule("Arial Unicode MS", 14, "Regular Class", "m".charCodeAt(0)),
+        /* Cyrillic small letter sha */
+        this._create_SPH_TweakRule("Arial", 10, "Regular Class", 0x448),
+        this._create_SPH_TweakRule("Arial", 11, "Regular Class", "m".charCodeAt(0)),
+        this._create_SPH_TweakRule("Arial", 12, "Regular Class", "m".charCodeAt(0)),
+        /* Cyrillic small letter sha */
+        this._create_SPH_TweakRule("Arial", 12, "Regular Class", 0x448),
+        this._create_SPH_TweakRule("Arial", 13, "Regular Class", 0x448),
+        this._create_SPH_TweakRule("Arial", 14, "Regular Class", "m".charCodeAt(0)),
+        /* Cyrillic small letter sha */
+        this._create_SPH_TweakRule("Arial", 14, "Regular Class", 0x448),
+        this._create_SPH_TweakRule("Arial", 15, "Regular Class", 0x448),
+        this._create_SPH_TweakRule("Arial", 17, "Regular Class", "m".charCodeAt(0)),
+        this._create_SPH_TweakRule("DejaVu Sans", 15, "Regular Class", 0),
+        this._create_SPH_TweakRule("Microsoft Sans Serif", 11, "Regular Class", 0),
+        this._create_SPH_TweakRule("Microsoft Sans Serif", 12, "Regular Class", 0),
+        this._create_SPH_TweakRule("Segoe UI", 11, "Regular Class", 0),
+        this._create_SPH_TweakRule("Monaco", 0, "Regular Class", 0),
+        this._create_SPH_TweakRule("Segoe UI", 12, "Regular Class", "m".charCodeAt(0)),
+        this._create_SPH_TweakRule("Segoe UI", 14, "Regular Class", "m".charCodeAt(0)),
+        this._create_SPH_TweakRule("Tahoma", 11, "Regular Class", 0),
+        this._create_SPH_TweakRule("Times New Roman", 16, "Regular Class", "c".charCodeAt(0)),
+        this._create_SPH_TweakRule("Times New Roman", 16, "Regular Class", "m".charCodeAt(0)),
+        this._create_SPH_TweakRule("Times New Roman", 16, "Regular Class", "o".charCodeAt(0)),
+        this._create_SPH_TweakRule("Times New Roman", 16, "Regular Class", "w".charCodeAt(0)),
+        this._create_SPH_TweakRule("Trebuchet MS", 11, "Regular Class", 0),
+        this._create_SPH_TweakRule("Trebuchet MS", 12, "Regular Class", 0),
+        this._create_SPH_TweakRule("Trebuchet MS", 14, "Regular Class", 0),
+        this._create_SPH_TweakRule("Trebuchet MS", 15, "Regular Class", 0),
+        this._create_SPH_TweakRule("Ubuntu", 12, "Regular Class", "m".charCodeAt(0)),
+        /* Cyrillic small letter sha */
+        this._create_SPH_TweakRule("Verdana", 10, "Regular Class", 0x448),
+        this._create_SPH_TweakRule("Verdana", 11, "Regular Class", 0x448),
+        this._create_SPH_TweakRule("Verdana and Clones", 12, "Regular Class", "i".charCodeAt(0)),
+        this._create_SPH_TweakRule("Verdana and Clones", 12, "Regular Class", "j".charCodeAt(0)),
+        this._create_SPH_TweakRule("Verdana and Clones", 12, "Regular Class", "l".charCodeAt(0)),
+        this._create_SPH_TweakRule("Verdana and Clones", 12, "Regular Class", "m".charCodeAt(0)),
+        this._create_SPH_TweakRule("Verdana and Clones", 13, "Regular Class", "i".charCodeAt(0)),
+        this._create_SPH_TweakRule("Verdana and Clones", 13, "Regular Class", "j".charCodeAt(0)),
+        this._create_SPH_TweakRule("Verdana and Clones", 13, "Regular Class", "l".charCodeAt(0)),
+        this._create_SPH_TweakRule("Verdana and Clones", 14, "Regular Class", "m".charCodeAt(0))
+    ];
+
+
+    /* Scaling slightly in the x-direction prior to hinting results in       */
+    /* more visually pleasing glyphs in certain cases.                       */
+    /* This sometimes needs to be coordinated with compatible width rules.   */
+    /* A value of 1000 corresponds to a scaled value of 1.0.                 */
+    this.X_SCALING_RULES_SIZE = 50;
+    this.X_SCALING_Rules = [
+        this._create_SPH_ScaleRule("DejaVu Sans", 12, "Regular Class", "m".charCodeAt(0), 950),
+        this._create_SPH_ScaleRule("Verdana and Clones", 12, "Regular Class", "a".charCodeAt(0), 1100),
+        this._create_SPH_ScaleRule("Verdana and Clones", 13, "Regular Class", "a".charCodeAt(0), 1050),
+        this._create_SPH_ScaleRule("Arial", 11, "Regular Class", "m".charCodeAt(0), 975),
+        this._create_SPH_ScaleRule("Arial", 12, "Regular Class", "m".charCodeAt(0), 1050),
+        /* Cyrillic small letter el */
+        this._create_SPH_ScaleRule("Arial", 13, "Regular Class", 0x43B, 950),
+        this._create_SPH_ScaleRule("Arial", 13, "Regular Class", "o".charCodeAt(0), 950),
+        this._create_SPH_ScaleRule("Arial", 13, "Regular Class", "e".charCodeAt(0), 950),
+        this._create_SPH_ScaleRule("Arial", 14, "Regular Class", "m".charCodeAt(0), 950),
+        /* Cyrillic small letter el */
+        this._create_SPH_ScaleRule("Arial", 15, "Regular Class", 0x43B, 925),
+        this._create_SPH_ScaleRule("Bitstream Vera Sans", 10, "Regular/Italic Class", 0, 1100),
+        this._create_SPH_ScaleRule("Bitstream Vera Sans", 12, "Regular/Italic Class", 0, 1050),
+        this._create_SPH_ScaleRule("Bitstream Vera Sans", 16, "Regular Class", 0, 1050),
+        this._create_SPH_ScaleRule("Bitstream Vera Sans", 9, "Regular/Italic Class", 0, 1050),
+        this._create_SPH_ScaleRule("DejaVu Sans", 12, "Regular Class", "l".charCodeAt(0), 975),
+        this._create_SPH_ScaleRule("DejaVu Sans", 12, "Regular Class", "i".charCodeAt(0), 975),
+        this._create_SPH_ScaleRule("DejaVu Sans", 12, "Regular Class", "j".charCodeAt(0), 975),
+        this._create_SPH_ScaleRule("DejaVu Sans", 13, "Regular Class", "l".charCodeAt(0), 950),
+        this._create_SPH_ScaleRule("DejaVu Sans", 13, "Regular Class", "i".charCodeAt(0), 950),
+        this._create_SPH_ScaleRule("DejaVu Sans", 13, "Regular Class", "j".charCodeAt(0), 950),
+        this._create_SPH_ScaleRule("DejaVu Sans", 10, "Regular/Italic Class", 0, 1100),
+        this._create_SPH_ScaleRule("DejaVu Sans", 12, "Regular/Italic Class", 0, 1050),
+        this._create_SPH_ScaleRule("Georgia", 10, "", 0, 1050),
+        this._create_SPH_ScaleRule("Georgia", 11, "", 0, 1100),
+        this._create_SPH_ScaleRule("Georgia", 12, "", 0, 1025),
+        this._create_SPH_ScaleRule("Georgia", 13, "", 0, 1050),
+        this._create_SPH_ScaleRule("Georgia", 16, "", 0, 1050),
+        this._create_SPH_ScaleRule("Georgia", 17, "", 0, 1030),
+        this._create_SPH_ScaleRule("Liberation Sans", 12, "Regular Class", "m".charCodeAt(0), 1100),
+        this._create_SPH_ScaleRule("Lucida Grande", 11, "Regular Class", "m".charCodeAt(0), 1100),
+        this._create_SPH_ScaleRule("Microsoft Sans Serif", 11, "Regular Class", "m".charCodeAt(0), 950),
+        this._create_SPH_ScaleRule("Microsoft Sans Serif", 12, "Regular Class", "m".charCodeAt(0), 1050),
+        this._create_SPH_ScaleRule("Segoe UI", 12, "Regular Class", "H".charCodeAt(0), 1050),
+        this._create_SPH_ScaleRule("Segoe UI", 12, "Regular Class", "m".charCodeAt(0), 1050),
+        this._create_SPH_ScaleRule("Segoe UI", 14, "Regular Class", "m".charCodeAt(0), 1050),
+        this._create_SPH_ScaleRule("Tahoma", 11, "Regular Class", "i".charCodeAt(0), 975),
+        this._create_SPH_ScaleRule("Tahoma", 11, "Regular Class", "l".charCodeAt(0), 975),
+        this._create_SPH_ScaleRule("Tahoma", 11, "Regular Class", "j".charCodeAt(0), 900),
+        this._create_SPH_ScaleRule("Tahoma", 11, "Regular Class", "m".charCodeAt(0), 918),
+        this._create_SPH_ScaleRule("Verdana", 10, "Regular/Italic Class".charCodeAt(0), 0, 1100),
+        this._create_SPH_ScaleRule("Verdana", 12, "Regular Class", "m".charCodeAt(0), 975),
+        this._create_SPH_ScaleRule("Verdana", 12, "Regular/Italic Class", 0, 1050),
+        this._create_SPH_ScaleRule("Verdana", 13, "Regular/Italic Class", "i".charCodeAt(0), 950),
+        this._create_SPH_ScaleRule("Verdana", 13, "Regular/Italic Class", "j".charCodeAt(0), 950),
+        this._create_SPH_ScaleRule("Verdana", 13, "Regular/Italic Class", "l".charCodeAt(0), 950),
+        this._create_SPH_ScaleRule("Verdana", 16, "Regular Class", 0, 1050),
+        this._create_SPH_ScaleRule("Verdana", 9, "Regular/Italic Class", 0, 1050),
+        this._create_SPH_ScaleRule("Times New Roman", 16, "Regular Class", "m".charCodeAt(0), 918),
+        this._create_SPH_ScaleRule("Trebuchet MS", 11, "Regular Class", "m".charCodeAt(0), 800),
+        this._create_SPH_ScaleRule("Trebuchet MS", 12, "Regular Class", "m".charCodeAt(0), 800)
+    ];
+
+    // #else -----------------------------------------------------------------
+    /*
+    this.COMPATIBLE_WIDTHS_RULES_SIZE = 1;
+    this.COMPATIBLE_WIDTHS_Rules = [
+        this._create_SPH_TweakRule("-", 0, "", 0)
+    ];
+
+
+    this.X_SCALING_RULES_SIZE = 1;
+    this.X_SCALING_Rules = [
+        this._create_SPH_ScaleRule("-", 0, "", 0, 1000)
+    ];
+    */
+    // -----------------------------------------------------------------------
+}
+
+var global_SubpixHintingHacks = new CSubpixHintingHacks();
\ No newline at end of file
diff --git a/Common/FontsFreeType/Private/FreeType/freetype.js b/Common/FontsFreeType/Private/FreeType/freetype.js
new file mode 100644
index 0000000000000000000000000000000000000000..80162a7e7aa21bfa7967e60d0e6bc6e7c0522622
--- /dev/null
+++ b/Common/FontsFreeType/Private/FreeType/freetype.js
@@ -0,0 +1,1307 @@
+var FT_Error = 0;
+function FT_Library()
+{
+    this.Memory = null;
+    this.generic = new FT_Generic();
+    this.version_major = 2;
+    this.version_minor = 4;
+    this.version_patch = 8;
+
+    this.modules = [];
+    this.renderers = [];
+    this.cur_renderer = null;
+    this.auto_hinter = null;
+
+    this.raster_pool_size = 16384;
+    this.raster_pool = null;
+
+    this.m_bUseCIDs = true;
+
+    this.tt_hint_props = new LibraryHintingParams();
+
+    // #ifdef subpixel
+    //FT_LcdFilter             lcd_filter;
+    //FT_Int                   lcd_extra;        /* number of extra pixels */
+    //FT_Byte                  lcd_weights[7];   /* filter weights, if any */
+    //FT_Bitmap_LcdFilterFunc  lcd_filter_func;  /* filtering callback     */
+    // #endif
+
+    //#ifdef FT_CONFIG_OPTION_PIC
+    //FT_PIC_Container   pic_container;
+    //#endif
+
+    this.Init = function()
+    {
+        this.Memory = new FT_Memory();
+        //this.raster_pool = this.Memory.Alloc(this.raster_pool_size);
+        // теперь пул для каждого рендерера свой
+        // и он хранится непосредственно в рендерере.
+        // если не создавать постоянно рендереры - то смысл такой же. У нас так и есть.
+        this.FT_Add_Default_Modules();
+    }
+    this.FT_Add_Module = function(module)
+    {
+        var clazz = module.clazz;
+        if (clazz == null)
+            return FT_Common.FT_Err_Invalid_Argument;
+
+        var version_control = (this.version_major << 16 | this.version_minor);
+        if (clazz.requires > version_control)
+            return FT_Common.FT_Err_Invalid_Version;
+
+        var mod_count = this.modules.length;
+        for (var i = 0; i < mod_count; i++)
+        {
+            var _module = this.modules[i];
+            if (_module.clazz.name == clazz.name)
+            {
+                if (clazz.version < _module.clazz.version)
+                    return FT_Common.FT_Err_Lower_Module_Version;
+                this.modules.splice(i,1);
+                break;
+            }
+        }
+
+        var error = FT_Common.FT_Err_Ok;
+        if ((clazz.flags & FT_Common.FT_MODULE_RENDERER) != 0)
+        {
+            error = this.ft_add_renderer(module);
+            if (FT_Common.FT_Err_Ok != error)
+            {
+                //delete module;
+                return error;
+            }
+        }
+        if ((clazz.flags & FT_Common.FT_MODULE_HINTER) != 0)
+        {
+            this.auto_hinter = module;
+        }
+        if ((clazz.flags & 1) != 0)
+        {
+            if (0 == (clazz.flags & FT_Common.FT_MODULE_DRIVER_NO_OUTLINES))
+            {
+                module.glyph_loader = new FT_GlyphLoader();
+            }
+        }
+
+        if (null != clazz.init)
+            clazz.init(module);
+
+        this.modules[mod_count] = module;
+        return error;
+    }
+    this.FT_Add_Default_Modules = function()
+    {
+        // drivers
+        var driver_tt = create_tt_driver(this);
+        var driver_cff = create_cff_driver(this);
+        var driver_t1 = create_t1_driver(this);
+        //var driver_cid = create_cid_driver(this);
+        this.FT_Add_Module(driver_tt);
+        this.FT_Add_Module(driver_cff);
+        this.FT_Add_Module(driver_t1);
+        //this.FT_Add_Module(driver_cid);
+
+        // modules
+        var mod_ps_names = create_psnames_module(this);
+        var mod_psaux = create_psaux_module(this);
+        var mod_sfnt = create_sfnt_module(this);
+        this.FT_Add_Module(mod_ps_names);
+        this.FT_Add_Module(mod_psaux);
+        this.FT_Add_Module(mod_sfnt);
+
+        // autohinter
+        this.auto_hinter = null;
+
+        // renderers
+        var mod_rend1 = create_renderer_smooth_module(this);
+        this.FT_Add_Module(mod_rend1);
+    }
+    this.ft_add_renderer = function(module)
+    {
+        var error = FT_Common.FT_Err_Ok;
+        var clazz = module.clazz;
+
+        module.glyph_format = clazz.glyph_format;
+
+        if ((clazz.glyph_format == FT_Common.FT_GLYPH_FORMAT_OUTLINE) && (clazz.raster_class.raster_new))
+        {
+            module.raster = new TRaster();
+            error = clazz.raster_class.raster_new(this.Memory, module.raster);
+
+            if (error != FT_Common.FT_Err_Ok)
+                return error;
+
+            module.raster_render = clazz.raster_class.raster_render;
+            module.render = clazz.render_glyph;
+        }
+
+        this.renderers[this.renderers.length] = module;
+
+        this.ft_set_current_renderer();
+        return error;
+    }
+    this.ft_set_current_renderer = function()
+    {
+        this.cur_renderer = null;
+        var count_r = this.renderers.length;
+        for (var i = 0; i < count_r; i++)
+        {
+            if (this.renderers[i].glyph_format == FT_Common.FT_GLYPH_FORMAT_OUTLINE)
+            {
+                this.cur_renderer = this.renderers[i];
+                return;
+            }
+        }
+    }
+    this.FT_Open_Face = function(args, face_index)
+    {
+        var face = null;
+        var external_stream = (args.stream && (args.flags & 0x02) != 0) ? true : false;
+        if (external_stream === true)
+        {
+            var stream = args.stream;
+
+            // пробегаем по всем драйверам - и ищем первый, который сможет открыть
+            var dr_len = this.modules.length;
+            for (var i = 0; i < dr_len; i++)
+            {
+                if (0 == (this.modules[i].clazz.flags & FT_Common.FT_MODULE_FONT_DRIVER))
+                    continue;
+
+                var driver = this.modules[i];
+                face = driver.open_face(stream, face_index);
+
+                if (0 != FT_Error)
+                {
+                    //#ifdef FT_CONFIG_OPTION_MAC_FONTS
+                    if (driver.clazz.name == "truetype" && ((FT_Error & 0xFF) == FT_Common.FT_Err_Table_Missing))
+                    {
+                        face = this.open_face_PS_from_sfnt_stream(stream, face_index);
+                        if (FT_Error != 0)
+                            return null;
+                    }
+                    //#endif
+                }
+                else
+                {
+                    break;
+                }
+
+                if ((FT_Error & 0xFF) != FT_Common.FT_Err_Unknown_File_Format)
+                {
+                    if (((FT_Error & 0xFF) == FT_Common.FT_Err_Invalid_Stream_Operation) ||
+                        ((FT_Error & 0xFF) == FT_Common.FT_Err_Cannot_Open_Stream))
+                    {
+                        //#ifdef FT_CONFIG_OPTION_MAC_FONTS
+                        face = this.load_mac_face(stream, face_index);
+                        if (FT_Error == 0)
+                            return face;
+                        FT_Error = FT_Common.FT_Err_Unknown_File_Format;
+                        face = null;
+                        return face;
+                        //#endif
+                    }
+                }
+            }
+
+            if (null == face)
+                return face;
+
+            face.face_flags |= (1 << 10);
+            face.driver.faces_list[face.driver.faces_list.length] = face;
+
+            if (face_index >= 0)
+            {
+                var slot = FT_New_GlyphSlot(face);
+                slot = null;
+                if (FT_Error != 0)
+                {
+                    face = null;
+                    return null;
+                }
+
+                /* finally, allocate a size object for the face */
+                {
+                    var size = FT_New_Size(face);
+                    if (FT_Error != 0)
+                    {
+                        face = null;
+                        return null;
+                    }
+
+                    face.size = size;
+                }
+            }
+
+            /* some checks */
+
+            if ((face.face_flags & 1) != 0)
+            {
+                if (face.height < 0)
+                    face.height = -face.height;
+
+                if ((face.face_flags & (1 << 5)) == 0)
+                    face.max_advance_height = face.height;
+            }
+
+            if ((face.face_flags & (1 << 1)) != 0)
+            {
+                var _num = face.num_fixed_sizes;
+                for (var i = 0; i < _num; i++)
+                {
+                    var bsize = face.available_sizes[i];
+
+                    if (bsize.height < 0)
+                        bsize.height = -bsize.height;
+                    if (bsize.x_ppem < 0)
+                        bsize.x_ppem = -bsize.x_ppem;
+                    if (bsize.y_ppem < 0)
+                        bsize.y_ppem = -bsize.y_ppem;
+                }
+            }
+
+            /* initialize internal face data */
+            {
+                var internal = face.internal;
+
+                internal.transform_matrix.xx = 0x10000;
+                internal.transform_matrix.xy = 0;
+                internal.transform_matrix.yx = 0;
+                internal.transform_matrix.yy = 0x10000;
+
+                internal.transform_delta.x = 0;
+                internal.transform_delta.y = 0;
+            }
+
+            FT_Error = FT_Common.FT_Err_Ok;
+            return face;
+        }
+        // пока открываем только из уже созданного стрима
+        FT_Error = FT_Common.FT_Err_Invalid_Argument;
+        return null;
+    }
+
+    this.open_face_PS_from_sfnt_stream = function(stream, face_index)
+    {
+    }
+    this.load_mac_face = function(stream, face_index)
+    {
+    }
+
+    this.FT_Get_Module_Interface = function(name)
+    {
+        var module = this.FT_Get_Module(name);
+        return (null != module) ? module.clazz.module_interface : null;
+    }
+    this.FT_Get_Module = function(name)
+    {
+        var count = this.modules.length;
+        for (var i = 0; i < count; i++)
+        {
+            if (this.modules[i].clazz.name == name)
+                return this.modules[i];
+        }
+        return null;
+    }
+}
+
+// API
+function FT_Select_Size(face, strike_index)
+{
+    if (!face || (face.face_flags & FT_Common.FT_FACE_FLAG_FIXED_SIZES) == 0)
+        return FT_Common.FT_Err_Invalid_Face_Handle;
+
+    if (strike_index < 0 || strike_index >= face.num_fixed_sizes)
+        return FT_Common.FT_Err_Invalid_Argument;
+
+    var clazz = face.driver.clazz;
+    if (clazz.select_size)
+    {
+        return clazz.select_size(face.size, strike_index);
+    }
+
+    FT_Select_Metrics(face, strike_index);
+    return FT_Common.FT_Err_Ok;
+}
+
+function FT_Select_Metrics(face, strike_index)
+{
+    var metrics = face.size.metrics;
+    var bsize   = face.available_sizes[strike_index];
+
+    metrics.x_ppem = (FT_Common.IntToUInt(bsize.x_ppem + 32) >>> 6) & 0xFFFF;
+    metrics.y_ppem = (FT_Common.IntToUInt(bsize.y_ppem + 32) >>> 6) & 0xFFFF;
+
+    if ((face.face_flags & FT_Common.FT_FACE_FLAG_SCALABLE) != 0)
+    {
+        metrics.x_scale = FT_DivFix(bsize.x_ppem, face.units_per_EM);
+        metrics.y_scale = FT_DivFix(bsize.y_ppem, face.units_per_EM);
+
+        ft_recompute_scaled_metrics(face, metrics);
+    }
+    else
+    {
+        metrics.x_scale     = 1 << 16;
+        metrics.y_scale     = 1 << 16;
+        metrics.ascender    = bsize.y_ppem;
+        metrics.descender   = 0;
+        metrics.height      = bsize.height << 6;
+        metrics.max_advance = bsize.x_ppem;
+    }
+}
+
+function ft_recompute_scaled_metrics(face, metrics)
+{
+    metrics.ascender    = FT_PIX_CEIL(FT_MulFix(face.ascender, metrics.y_scale));
+    metrics.descender   = FT_PIX_FLOOR(FT_MulFix(face.descender, metrics.y_scale));
+    metrics.height      = FT_PIX_ROUND(FT_MulFix(face.height, metrics.y_scale));
+    metrics.max_advance = FT_PIX_ROUND(FT_MulFix(face.max_advance_width, metrics.x_scale));
+}
+
+function FT_Request_Size(face, req)
+{
+    var strike_index = 0;
+
+    if (!face)
+        return FT_Common.FT_Err_Invalid_Face_Handle;
+
+    if (!req || req.width < 0 || req.height < 0 || req.type >= FT_Common.FT_SIZE_REQUEST_TYPE_MAX)
+        return FT_Common.FT_Err_Invalid_Argument;
+
+    var clazz = face.driver.clazz;
+
+    if (clazz.request_size)
+    {
+        return clazz.request_size(face.size, req);
+    }
+
+    if (((face.face_flags & FT_Common.FT_FACE_FLAG_SCALABLE) == 0) && ((face.face_flags & FT_Common.FT_FACE_FLAG_FIXED_SIZES) != 0))
+    {
+        FT_Error = FT_Common.FT_Err_Ok;
+        strike_index = FT_Match_Size(face, req, 0);
+        var error = FT_Error;
+        FT_Error = FT_Common.FT_Err_Ok;
+        if (error != FT_Common.FT_Err_Ok)
+            return error;
+
+        return FT_Select_Size(face, strike_index);
+    }
+
+    FT_Request_Metrics(face, req);
+    return FT_Common.FT_Err_Ok;
+}
+
+function FT_Request_Metrics(face, req)
+{
+    var metrics = face.size.metrics;
+
+    if ((face.face_flags & FT_Common.FT_FACE_FLAG_SCALABLE) != 0)
+    {
+        var w = 0, h = 0, scaled_w = 0, scaled_h = 0;
+
+        switch (req.type)
+        {
+            case FT_Common.FT_SIZE_REQUEST_TYPE_NOMINAL:
+                w = h = face.units_per_EM;
+                break;
+
+            case FT_Common.FT_SIZE_REQUEST_TYPE_REAL_DIM:
+                w = h = face.ascender - face.descender;
+                break;
+
+            case FT_Common.FT_SIZE_REQUEST_TYPE_BBOX:
+                w = face.bbox.xMax - face.bbox.xMin;
+                h = face.bbox.yMax - face.bbox.yMin;
+                break;
+
+            case FT_Common.FT_SIZE_REQUEST_TYPE_CELL:
+                w = face.max_advance_width;
+                h = face.ascender - face.descender;
+                break;
+
+            case FT_Common.FT_SIZE_REQUEST_TYPE_SCALES:
+                metrics.x_scale = req.width;
+                metrics.y_scale = req.height;
+                if (metrics.x_scale == 0)
+                    metrics.x_scale = metrics.y_scale;
+                else if (metrics.y_scale == 0)
+                    metrics.y_scale = metrics.x_scale;
+
+                scaled_w = FT_MulFix(face.units_per_EM, metrics.x_scale);
+                scaled_h = FT_MulFix(face.units_per_EM, metrics.y_scale);
+
+                metrics.x_ppem = (FT_Common.IntToUInt(scaled_w + 32) >>> 6) & 0xFFFF;
+                metrics.y_ppem = (FT_Common.IntToUInt(scaled_h + 32) >>> 6) & 0xFFFF;
+
+                ft_recompute_scaled_metrics( face, metrics );
+                return;
+
+            case FT_Common.FT_SIZE_REQUEST_TYPE_MAX:
+                break;
+        }
+
+        /* to be on the safe side */
+        if (w < 0)
+            w = -w;
+
+        if (h < 0)
+            h = -h;
+
+        scaled_w = FT_REQUEST_WIDTH(req);
+        scaled_h = FT_REQUEST_HEIGHT(req);
+
+        if (req.width != 0)
+        {
+            metrics.x_scale = FT_DivFix(scaled_w, w);
+
+            if (req.height != 0)
+            {
+                metrics.y_scale = FT_DivFix(scaled_h, h);
+
+                if (req.type == FT_Common.FT_SIZE_REQUEST_TYPE_CELL)
+                {
+                    if (metrics.y_scale > metrics.x_scale)
+                        metrics.y_scale = metrics.x_scale;
+                    else
+                        metrics.x_scale = metrics.y_scale;
+                }
+            }
+            else
+            {
+                metrics.y_scale = metrics.x_scale;
+                scaled_h = FT_MulDiv(scaled_w, h, w);
+            }
+        }
+        else
+        {
+            metrics.x_scale = metrics.y_scale = FT_DivFix(scaled_h, h);
+            scaled_w = FT_MulDiv(scaled_h, w, h);
+        }
+
+        if (req.type != FT_Common.FT_SIZE_REQUEST_TYPE_NOMINAL)
+        {
+            scaled_w = FT_MulFix(face.units_per_EM, metrics.x_scale);
+            scaled_h = FT_MulFix(face.units_per_EM, metrics.y_scale);
+        }
+
+        metrics.x_ppem = (FT_Common.IntToUInt(scaled_w + 32) >>> 6) & 0xFFFF;
+        metrics.y_ppem = (FT_Common.IntToUInt(scaled_h + 32) >>> 6) & 0xFFFF;
+
+        ft_recompute_scaled_metrics(face, metrics);
+    }
+    else
+    {
+        metrics.x_ppem = 0;
+        metrics.y_ppem = 0;
+
+        metrics.ascender = 0;
+        metrics.descender = 0;
+        metrics.height = 0;
+        metrics.max_advance = 0;
+
+        metrics.x_scale = 1 << 16;
+        metrics.y_scale = 1 << 16;
+    }
+}
+
+function FT_REQUEST_WIDTH(req)
+{
+    return (req.horiResolution != 0) ? parseInt((req.width * req.horiResolution + 36) / 72) : req.width;
+}
+
+function FT_REQUEST_HEIGHT(req)
+{
+    return (req.vertResolution != 0) ? parseInt((req.height * req.vertResolution + 36) / 72) : req.height;
+}
+
+function FT_Match_Size(face, req, ignore_width)
+{
+    if ((face.face_flags & FT_Common.FT_FACE_FLAG_FIXED_SIZES) == 0)
+    {
+        FT_Error = FT_Common.FT_Err_Invalid_Face_Handle;
+        return 0;
+    }
+
+    if (req.type != FT_Common.FT_SIZE_REQUEST_TYPE_NOMINAL)
+    {
+        FT_Error = FT_Common.FT_Err_Unimplemented_Feature;
+        return 0;
+    }
+
+    var w = FT_REQUEST_WIDTH(req);
+    var h = FT_REQUEST_HEIGHT(req);
+
+    if (req.width != 0 && req.height == 0)
+        h = w;
+    else if (req.width == 0 && req.height != 0)
+        w = h;
+
+    w = FT_PIX_ROUND(w);
+    h = FT_PIX_ROUND(h);
+
+    var num_fs = face.num_fixed_sizes;
+    for (var i = 0; i < num_fs; i++)
+    {
+        var bsize = face.available_sizes[i];
+
+        if (h != FT_PIX_ROUND(bsize.y_ppem))
+            continue;
+
+        if (w == FT_PIX_ROUND(bsize.x_ppem) || (ignore_width != 0))
+        {
+            FT_Error = 0;
+            return i;
+        }
+    }
+
+    FT_Error = FT_Common.FT_Err_Invalid_Pixel_Size;
+    return 0;
+}
+
+function FT_Set_Char_Size(face, char_width, char_height, horz_resolution, vert_resolution)
+{
+    var req = new FT_Size_RequestRec();
+
+    if (0 == char_width)
+        char_width = char_height;
+    else if (0 == char_height)
+        char_height = char_width;
+
+    if (0 == horz_resolution)
+        horz_resolution = vert_resolution;
+    else if (0 == vert_resolution)
+        vert_resolution = horz_resolution;
+
+    if (char_width < 64)
+        char_width = 64;
+    if (char_height < 64)
+        char_height = 64;
+
+    if (0 == horz_resolution)
+        horz_resolution = vert_resolution = 72;
+
+    req.type           = FT_Common.FT_SIZE_REQUEST_TYPE_NOMINAL;
+    req.width          = char_width;
+    req.height         = char_height;
+    req.horiResolution = horz_resolution;
+    req.vertResolution = vert_resolution;
+
+    return FT_Request_Size(face, req);
+}
+
+function FT_Set_Pixel_Sizes(face, pixel_width, pixel_height)
+{
+    var req = new FT_Size_RequestRec();
+
+    if (pixel_width == 0)
+        pixel_width = pixel_height;
+    else if (pixel_height == 0)
+        pixel_height = pixel_width;
+
+    if (pixel_width < 1)
+        pixel_width = 1;
+    if (pixel_height < 1)
+        pixel_height = 1;
+
+    /* use `>=' to avoid potential compiler warning on 16bit platforms */
+    if (pixel_width >= 0xFFFF)
+        pixel_width = 0xFFFF;
+    if (pixel_height >= 0xFFFF)
+        pixel_height = 0xFFFF;
+
+    req.type           = FT_Common.FT_SIZE_REQUEST_TYPE_NOMINAL;
+    req.width          = pixel_width << 6;
+    req.height         = pixel_height << 6;
+    req.horiResolution = 0;
+    req.vertResolution = 0;
+
+    return FT_Request_Size(face, req);
+}
+
+function FT_Get_First_Char(face)
+{
+    var result = {gindex:0,char_code:0};
+    if (face && face.charmap && face.num_glyphs != 0)
+    {
+        result.gindex = FT_Get_Char_Index(face, 0);
+        if (result.gindex == 0 || result.gindex >= face.num_glyphs)
+            result = FT_Get_Next_Char(face, 0);
+    }
+    return result;
+}
+
+function FT_Get_Next_Char(face, charcode)
+{
+    var result = {gindex:0,char_code:0};
+    if (face && face.charmap && face.num_glyphs != 0)
+    {
+        var code = charcode;
+        var cmap = face.charmap;
+        var _cmap = __FT_CMapRec(cmap);
+
+        do
+        {
+            var _clazz = _cmap.clazz.clazz;
+            if (undefined == _clazz)
+                _clazz = _cmap.clazz;
+
+            result = _clazz.char_next(cmap, code);
+            code = result.char_code;
+        } while (result.gindex >= face.num_glyphs);
+
+        result.char_code = (result.gindex == 0) ? 0 : code;
+    }
+    return result;
+}
+
+function FT_Get_Char_Index(face, charcode)
+{
+    var result = 0;
+    if (face && face.charmap)
+    {
+        var _clazz = __FT_CMapRec(face.charmap).clazz;
+        if (undefined != _clazz.clazz)
+            _clazz = _clazz.clazz;
+
+        result = _clazz.char_index(face.charmap, charcode);
+    }
+    return result;
+}
+
+function FT_Get_Charmap_Index(charmap)
+{
+    if (!charmap || !charmap.face)
+        return -1;
+
+    var i = 0;
+    for (; i < charmap.face.num_charmaps; i++)
+        if (charmap.face.charmaps[i] == charmap)
+            break;
+
+    //#ifdef FT_MAX_CHARMAP_CACHEABLE
+    if (i > 15)
+        return -i;
+    //#endif
+    return i;
+}
+
+function FT_Set_Charmap(face, cmap)
+{
+    if (!face)
+        return FT_Common.FT_Err_Invalid_Face_Handle;
+
+    var len = face.num_charmaps;
+    if (0 == len)
+        return FT_Common.FT_Err_Invalid_CharMap_Handle;
+
+    if (FT_Get_CMap_Format(cmap) == 14)
+        return FT_Common.FT_Err_Invalid_Argument;
+
+    for (var i = 0; i < len; i++)
+    {
+        if (face.charmaps[i] == cmap)
+        {
+            //#ifdef FT_MAX_CHARMAP_CACHEABLE
+            if (i > 15)
+                continue;
+            //#endif
+            face.charmap = face.charmaps[i];
+            return 0;
+        }
+    }
+    return FT_Common.FT_Err_Invalid_Argument;
+}
+
+function FT_Get_CMap_Format(cmap)
+{
+    var charmap = __FT_CharmapRec(cmap);
+    if (!charmap || !charmap.face)
+        return -1;
+
+    var service = FT_FACE_FIND_SERVICE(charmap.face, "tt-cmaps");
+
+    if (service == null)
+        return -1;
+
+    var cmap_info = new TT_CMapInfo();
+    service.get_cmap_info(cmap, cmap_info);
+    if (FT_Error != 0)
+        return -1;
+    
+    return cmap_info.format;
+}
+
+
+function FT_Glyph_Get_CBox(glyph, bbox_mode, acbox)
+{
+    acbox.xMin = acbox.yMin = acbox.xMax = acbox.yMax = 0;
+
+    if (!glyph || !glyph.clazz)
+        return;
+
+    var clazz = glyph.clazz;
+    if (!clazz.glyph_bbox)
+        return;
+
+    clazz.glyph_bbox(glyph, acbox);
+
+    if (bbox_mode == FT_Common.FT_GLYPH_BBOX_GRIDFIT || bbox_mode == FT_Common.FT_GLYPH_BBOX_PIXELS)
+    {
+        acbox.xMin = FT_PIX_FLOOR(acbox.xMin);
+        acbox.yMin = FT_PIX_FLOOR(acbox.yMin);
+        acbox.xMax = FT_PIX_CEIL(acbox.xMax);
+        acbox.yMax = FT_PIX_CEIL(acbox.yMax);
+    }
+
+    if (bbox_mode == FT_Common.FT_GLYPH_BBOX_TRUNCATE || bbox_mode == FT_Common.FT_GLYPH_BBOX_PIXELS)
+    {
+        acbox.xMin >>= 6;
+        acbox.yMin >>= 6;
+        acbox.xMax >>= 6;
+        acbox.yMax >>= 6;
+    }
+}
+
+function FT_Get_Glyph(slot)
+{
+    FT_Error = 0;
+    var clazz = null;
+
+    if (!slot)
+        return FT_Common.FT_Err_Invalid_Slot_Handle;
+
+    if (slot.format == FT_Common.FT_GLYPH_FORMAT_BITMAP)
+        clazz = ft_bitmap_glyph_class;
+    else if (slot.format == FT_Common.FT_GLYPH_FORMAT_OUTLINE)
+        clazz = ft_outline_glyph_class;
+    else
+    {
+        var render = FT_Lookup_Renderer(slot.library, slot.format);
+        if (render)
+            clazz = render.glyph_class;
+    }
+
+    if (!clazz)
+    {
+        FT_Error = FT_Common.FT_Err_Invalid_Glyph_Format;
+        return null;
+    }
+
+    var glyph = ft_new_glyph(slot.library, clazz);
+    if (FT_Error != 0)
+        return null;
+
+    glyph.advance.x = slot.advance.x << 10;
+    glyph.advance.y = slot.advance.y << 10;
+
+    FT_Error = clazz.glyph_init(glyph, slot);
+
+    if (FT_Error != 0)
+    {
+        FT_Done_Glyph(glyph);
+        glyph = null;
+    }
+    else
+        return glyph;
+
+    return null;
+}
+
+function FT_Done_Glyph(glyph)
+{
+    return 0;
+}
+
+function FT_Get_Name_Index(face, glyph_name)
+{
+    if (face && ((face.face_flags & FT_Common.FT_FACE_FLAG_GLYPH_NAMES) != 0))
+    {
+        var service = face.internal.services.service_GLYPH_DICT;
+        if (null != service)
+            service = FT_FACE_FIND_SERVICE(face, "glyph-dict");
+
+        if (service && service.name_index)
+            return service.name_index(face, glyph_name);
+    }
+    return 0;
+}
+function FT_Get_Glyph_Name(face, glyph_index, buffer, buffer_max)
+{
+    if (face && (glyph_index <= face.num_glyphs) && ((face.face_flags & FT_Common.FT_FACE_FLAG_GLYPH_NAMES) != 0))
+    {
+        var service = face.internal.services.service_GLYPH_DICT;
+        if (null != service)
+            service = FT_FACE_FIND_SERVICE(face, "glyph-dict");
+
+        if (service && service.get_name)
+            return service.get_name(face, glyph_index, buffer, buffer_max);
+    }
+    return 0;
+}
+
+function FT_Get_X11_Font_Format(face)
+{
+    if (face)
+        return FT_FACE_FIND_SERVICE(face, "xf86-driver-name");
+    return null;
+}
+
+function FT_Lookup_Renderer(library, format)
+{
+    var r = library.renderers;
+    var c = r.length;
+
+    for (var i = 0; i < c; i++)
+    {
+        if (r[i].glyph_format == format)
+            return r[i];
+    }
+
+    return null;
+}
+
+function FT_Set_Renderer(library, renderer)
+{
+    if (!library)
+        return FT_Common.FT_Err_Invalid_Library_Handle;
+
+    if (!renderer)
+        return FT_Common.FT_Err_Invalid_Argument;
+
+    if (renderer.glyph_format == FT_Common.FT_GLYPH_FORMAT_OUTLINE)
+        library.cur_renderer = renderer;
+
+    return 0;
+}
+
+function ft_lookup_glyph_renderer(slot)
+{
+    var library = slot.library;
+    var res = library.cur_renderer;
+
+    if (!res || (res.glyph_format != slot.format))
+        res = FT_Lookup_Renderer(library, slot.format);
+
+    return res;
+}
+
+function ft_set_current_renderer(library)
+{
+    library.cur_renderer = FT_Lookup_Renderer(library, FT_Common.FT_GLYPH_FORMAT_OUTLINE);
+}
+
+
+
+function FT_Load_Glyph(face, glyph_index, load_flags)
+{
+    if (!face || !face.size || !face.glyph)
+        return FT_Common.FT_Err_Invalid_Face_Handle;
+
+    var slot = face.glyph;
+    ft_glyphslot_clear(slot);
+
+    var driver  = face.driver;
+    var library = driver.library;
+    var hinter  = library.auto_hinter;
+    var autohint = false;
+
+    /* resolve load flags dependencies */
+    if (load_flags & FT_Common.FT_LOAD_NO_RECURSE)
+        load_flags |= (FT_Common.FT_LOAD_NO_SCALE | FT_Common.FT_LOAD_IGNORE_TRANSFORM);
+
+    if (load_flags & FT_Common.FT_LOAD_NO_SCALE)
+    {
+        load_flags |= (FT_Common.FT_LOAD_NO_HINTING | FT_Common.FT_LOAD_NO_BITMAP);
+        load_flags &= ~FT_Common.FT_LOAD_RENDER;
+    }
+
+    // if (hinter && ...){}
+    // TODO:
+
+    if (true === autohint)
+    {
+        // TODO:
+    }
+    else
+    {
+        var error = driver.clazz.load_glyph(slot, face.size, glyph_index, load_flags);
+        if (error != FT_Common.FT_Err_Ok)
+            return error;
+
+        if (slot.format == FT_Common.FT_GLYPH_FORMAT_OUTLINE)
+        {
+            /* check that the loaded outline is correct */
+            error = FT_Outline_Check(slot.outline);
+            if (error != FT_Common.FT_Err_Ok)
+                return error;
+
+            //#ifdef GRID_FIT_METRICS
+            if (0 == (load_flags & FT_Common.FT_LOAD_NO_HINTING))
+                ft_glyphslot_grid_fit_metrics( slot, ((load_flags & FT_Common.FT_LOAD_VERTICAL_LAYOUT) != 0) ? true : false);
+            //#endif
+        }
+    }
+
+    /* compute the advance */
+    if (0 != (load_flags & FT_Common.FT_LOAD_VERTICAL_LAYOUT))
+    {
+        slot.advance.x = 0;
+        slot.advance.y = slot.metrics.vertAdvance;
+    }
+    else
+    {
+        slot.advance.x = slot.metrics.horiAdvance;
+        slot.advance.y = 0;
+    }
+
+    /* compute the linear advance in 16.16 pixels */
+    if ((load_flags & FT_Common.FT_LOAD_LINEAR_DESIGN) == 0 && (0 != (face.face_flags & FT_Common.FT_FACE_FLAG_SCALABLE)))
+    {
+        var metrics = face.size.metrics;
+
+        /* it's tricky! */
+        slot.linearHoriAdvance = FT_MulDiv(slot.linearHoriAdvance, metrics.x_scale, 64);
+        slot.linearVertAdvance = FT_MulDiv(slot.linearVertAdvance, metrics.y_scale, 64);
+    }
+
+    if ((load_flags & FT_Common.FT_LOAD_IGNORE_TRANSFORM) == 0)
+    {
+        var internal = face.internal;
+
+        /* now, transform the glyph image if needed */
+        if (internal.transform_flags != 0)
+        {
+            /* get renderer */
+            var renderer = ft_lookup_glyph_renderer(slot);
+            if (renderer != null)
+                error = renderer.clazz.transform_glyph(renderer, slot, internal.transform_matrix, internal.transform_delta);
+            else if (slot.format == FT_Common.FT_GLYPH_FORMAT_OUTLINE)
+            {
+                /* apply `standard' transformation if no renderer is available */
+                if ((internal.transform_flags & 1) != 0)
+                    FT_Outline_Transform(slot.outline, internal.transform_matrix);
+
+                if ((internal.transform_flags & 2) != 0)
+                    FT_Outline_Translate(slot.outline, internal.transform_delta.x, internal.transform_delta.y);
+            }
+
+            /* transform advance */
+            FT_Vector_Transform(slot.advance, internal.transform_matrix);
+        }
+    }
+
+    /* do we need to render the image now? */
+    if ((error == 0) && (slot.format != FT_Common.FT_GLYPH_FORMAT_BITMAP) && (slot.format != FT_Common.FT_GLYPH_FORMAT_COMPOSITE) && ((load_flags & FT_Common.FT_LOAD_RENDER) != 0))
+    {
+        var mode = FT_LOAD_TARGET_MODE(load_flags);
+
+        if (mode == FT_Common.FT_RENDER_MODE_NORMAL && (load_flags & FT_Common.FT_LOAD_MONOCHROME))
+            mode = FT_Common.FT_RENDER_MODE_MONO;
+
+        error = FT_Render_Glyph(slot, mode);
+    }
+    return error;
+}
+
+function FT_Load_Char(face, char_code, load_flags)
+{
+    var glyph_index = 0;
+
+    if ( !face )
+        return FT_Common.FT_Err_Invalid_Face_Handle;
+
+    glyph_index = char_code;
+    if (face.charmap)
+        glyph_index = FT_Get_Char_Index(face, char_code);
+
+    return FT_Load_Glyph(face, glyph_index, load_flags);
+}
+
+function FT_Set_Transform(face, matrix, delta)
+{
+    if (!face)
+        return;
+
+    var internal = face.internal;
+    internal.transform_flags = 0;
+
+    var m = internal.transform_matrix;
+    if (!matrix)
+    {
+        m.xx = 0x10000;
+        m.xy = 0;
+        m.yx = 0;
+        m.yy = 0x10000;
+    }
+    else
+    {
+        m.xx = matrix.xx;
+        m.xy = matrix.xy;
+        m.yx = matrix.yx;
+        m.yy = matrix.yy;
+    }
+
+    /* set transform_flags bit flag 0 if `matrix' isn't the identity */
+    if ((m.xy | m.yx) != 0 || m.xx != 0x10000 || m.yy != 0x10000)
+        internal.transform_flags |= 1;
+
+    var d = internal.transform_delta;
+    if (!delta)
+    {
+        d.x = 0;
+        d.y = 0;
+    }
+    else
+    {
+        d.x = delta.x;
+        d.y = delta.y;
+    }
+
+    /* set transform_flags bit flag 1 if `delta' isn't the null vector */
+    if ((d.x | d.y) != 0)
+        internal.transform_flags |= 2;
+}
+
+function FT_Render_Glyph(slot, render_mode)
+{
+    if (!slot || !slot.face)
+        return FT_Common.FT_Err_Invalid_Argument;
+
+    var library = slot.library;
+    return FT_Render_Glyph_Internal(library, slot, render_mode);
+}
+
+function FT_Render_Glyph_Internal(library, slot, render_mode)
+{
+    var error = FT_Common.FT_Err_Ok;
+    var renderer = null;
+    var update = false;
+
+    /* if it is already a bitmap, no need to do anything */
+    switch (slot.format)
+    {
+        case FT_Common.FT_GLYPH_FORMAT_BITMAP:   /* already a bitmap, don't do anything */
+            break;
+
+        default:
+        {
+            /* small shortcut for the very common case */
+            if (slot.format == FT_Common.FT_GLYPH_FORMAT_OUTLINE)
+            {
+                renderer = library.cur_renderer;
+            }
+            else
+            {
+                renderer = FT_Lookup_Renderer(library, slot.format);
+            }
+
+            error = FT_Common.FT_Err_Unimplemented_Feature;
+            while (renderer != null)
+            {
+                error = renderer.render(renderer, slot, render_mode, null);
+                if ((error == 0) || ((error & 0xFF) != FT_Common.FT_Err_Cannot_Render_Glyph))
+                    break;
+
+                renderer = FT_Lookup_Renderer(library, slot.format);
+                update   = true;
+            }
+            if (error == 0 && update && renderer)
+                FT_Set_Renderer(library, renderer);
+        }
+    }
+
+    return error;
+}
+
+function FT_Get_Kerning(face, left_glyph, right_glyph, kern_mode, akerning)
+{
+    var error = FT_Common.FT_Err_Ok;
+
+    if (!face)
+        return FT_Common.FT_Err_Invalid_Face_Handle;
+
+    if (!akerning)
+        return FT_Common.FT_Err_Invalid_Argument;
+
+    var driver = face.driver;
+
+    akerning.x = 0;
+    akerning.y = 0;
+
+    if (driver.clazz.get_kerning)
+    {
+        error = driver.clazz.get_kerning(face, left_glyph, right_glyph, akerning);
+        if (error == FT_Common.FT_Err_Ok)
+        {
+            if (kern_mode != FT_Common.FT_KERNING_UNSCALED)
+            {
+                akerning.x = FT_MulFix(akerning.x, face.size.metrics.x_scale);
+                akerning.y = FT_MulFix(akerning.y, face.size.metrics.y_scale);
+
+                if (kern_mode != FT_Common.FT_KERNING_UNFITTED)
+                {
+                    if (face.size.metrics.x_ppem < 25)
+                        akerning.x = FT_MulDiv(akerning.x, face.size.metrics.x_ppem, 25);
+                    if (face.size.metrics.y_ppem < 25)
+                        akerning.y = FT_MulDiv(akerning.y, face.size.metrics.y_ppem, 25);
+
+                    akerning.x = FT_PIX_ROUND(akerning.x);
+                    akerning.y = FT_PIX_ROUND(akerning.y);
+                }
+            }
+        }
+    }
+
+    return error;
+}
+
+function FT_New_GlyphSlot(face)
+{
+    if (!face || !face.driver)
+        return FT_Common.FT_Err_Invalid_Argument;
+
+    var slot = null;
+    var _slot = null;
+
+    if (face.driver.clazz.name == "type1")
+    {
+        _slot = new T1_GlyphSlotRec();
+        slot = _slot.root;
+    }
+    else
+    {
+        _slot = new FT_GlyphSlot();
+        slot = _slot;
+    }
+
+    slot.face = face;
+    FT_Error = ft_glyphslot_init(slot);
+    if (FT_Error != 0)
+    {
+        ft_glyphslot_done(slot);
+        return null;
+    }
+
+    slot.next  = face.glyph;
+    face.glyph = slot;
+    return slot;
+}
+
+function FT_GlyphLoader_New(memory)
+{
+    var loader = new FT_GlyphLoader();
+    loader.memory = memory;
+    return loader;
+}
+
+function ft_glyphslot_done(slot)
+{
+    return 0;
+}
+
+function FT_New_Size(face)
+{
+    if (!face)
+        return FT_Common.FT_Err_Invalid_Face_Handle;
+
+    if (!face.driver)
+        return FT_Common.FT_Err_Invalid_Driver_Handle;
+
+    var size = null;
+    var clazz  = face.driver.clazz;
+    
+    FT_Error = 0;
+    if (clazz.init_size)
+    {
+        size = clazz.init_size();
+    }
+    size.face = face;
+
+    if (FT_Error == 0)
+    {
+        face.sizes_list[face.sizes_list.length] = size;
+        return size;
+    }
+
+    return null;
+}
+function FT_CMap_New(clazz, init_data, charmap)
+{
+    FT_Error = 0;
+    
+    if (clazz == null || charmap == null || charmap.face == null)
+    {
+        FT_Error = FT_Common.FT_Err_Invalid_Argument;
+        return null;
+    }
+
+    var _clazz = clazz.clazz;
+    var face = charmap.face;
+    var cmap = null;
+
+    if (undefined != clazz.format)
+    {
+        switch (clazz.format)
+        {
+            case 4:
+                cmap = new TT_CMap4Rec();
+                break;
+            case 12:
+                cmap = new TT_CMap12Rec();
+                break;
+            case 13:
+                cmap = new TT_CMap13Rec();
+                break;
+            case 14:
+                cmap = new TT_CMap14Rec();
+                break;
+            default:
+                cmap = new TT_CMapRec();
+                break;
+        }
+    }
+    else
+    {
+        switch (clazz.size)
+        {
+            case 101:
+            case 102:
+                cmap = new CFF_CMapStdRec();
+                break;
+            default:
+                cmap = new TT_CMapRec();
+        }
+    }
+
+    var cmap_ = __FT_CMapRec(cmap);
+    if (undefined == _clazz)
+        _clazz = clazz;
+
+    if (null != cmap)
+    {
+        var charmap_= cmap_.charmap;
+        charmap_.face = charmap.face;
+        charmap_.encoding = charmap.encoding;
+        charmap_.platform_id = charmap.platform_id;
+        charmap_.encoding_id = charmap.encoding_id;
+
+        cmap_.clazz = clazz;
+        if (clazz.init != 0)
+        {
+            var error = _clazz.init(cmap, init_data);
+            if (error != 0)
+            {
+                FT_Error = error;
+                cmap = null;
+                cmap_ = null;
+                return null;
+            }
+        }
+        if (null == face.charmaps)
+            face.charmaps = new Array(1);
+        face.charmaps[face.num_charmaps++] = cmap;
+    }
+
+    return cmap;
+}
diff --git a/Common/FontsFreeType/Private/FreeType/modules/psaux.js b/Common/FontsFreeType/Private/FreeType/modules/psaux.js
new file mode 100644
index 0000000000000000000000000000000000000000..085fd70c841e6fb47b2bf457594e93af2952c474
--- /dev/null
+++ b/Common/FontsFreeType/Private/FreeType/modules/psaux.js
@@ -0,0 +1,4602 @@
+/******************************************************************************/
+// t1tables
+/******************************************************************************/
+function _isdigit(x)
+{
+    if ((x >= FT_Common.SYMBOL_CONST_0) && (x <= FT_Common.SYMBOL_CONST_9))
+        return 1;
+    return 0;
+}
+function _isxdigit(x)
+{
+    if (((x >= FT_Common.SYMBOL_CONST_0) && (x <= FT_Common.SYMBOL_CONST_9)) ||
+        ((x >= FT_Common.SYMBOL_CONST_a) && (x <= FT_Common.SYMBOL_CONST_f)) ||
+        ((x >= FT_Common.SYMBOL_CONST_A) && (x <= FT_Common.SYMBOL_CONST_F)))
+        return 1;
+    return 0;
+}
+
+function PS_FontInfoRec()
+{
+    this.version        = "";
+    this.notice         = "";
+    this.full_name      = "";
+    this.family_name    = "";
+    this.weight         = "";
+    this.italic_angle   = 0;
+    this.is_fixed_pitch = 0;
+    this.underline_position     = 0;
+    this.underline_thickness    = 0;
+
+    this.CreateDublicate = function()
+    {
+        var _ret = new PS_FontInfoRec();
+
+        _ret.version = this.version;
+        _ret.notice = this.notice;
+        _ret.full_name = this.full_name;
+        _ret.family_name = this.family_name;
+        _ret.weight = this.weight;
+        _ret.italic_angle = this.italic_angle;
+        _ret.is_fixed_pitch = this.is_fixed_pitch;
+        _ret.underline_position = this.underline_position;
+        _ret.underline_thickness = this.underline_thickness;
+
+        return _ret;
+    }
+}
+function PS_PrivateRec()
+{
+    this.unique_id = 0;
+    this.lenIV = 0;
+
+    this.num_blue_values = 0;
+    this.num_other_blues = 0;
+    this.num_family_blues = 0;
+    this.num_family_other_blues = 0;
+
+    this.blue_values = [0,0,0,0,0,0,0,0,0,0,0,0,0,0];
+    this.other_blues = [0,0,0,0,0,0,0,0,0,0];
+
+    this.family_blues = [0,0,0,0,0,0,0,0,0,0,0,0,0,0];
+    this.family_other_blues = [0,0,0,0,0,0,0,0,0,0];
+
+    this.blue_scale = 0;
+    this.blue_shift = 0;
+    this.blue_fuzz = 0;
+
+    this.standard_width = [0];
+    this.standard_height = [0];
+
+    this.num_snap_widths = 0;
+    this.num_snap_heights = 0;
+    this.force_bold = 0;
+    this.round_stem_up = 0;
+
+    this.snap_widths = [0,0,0,0,0,0,0,0,0,0,0,0,0];
+    this.snap_heights = [0,0,0,0,0,0,0,0,0,0,0,0,0];
+
+    this.expansion_factor = 0;
+
+    this.language_group = 0;
+    this.password = 0;
+
+    this.min_feature = [0,0];
+
+    this.clear = function()
+    {
+        this.unique_id = 0;
+        this.lenIV = 0;
+
+        this.num_blue_values = 0;
+        this.num_other_blues = 0;
+        this.num_family_blues = 0;
+        this.num_family_other_blues = 0;
+
+        for (var i = 0; i < 14; i++)
+            this.blue_values[i] = 0;
+
+        for (var i = 0; i < 10; i++)
+            this.other_blues[i] = 0;
+
+        for (var i = 0; i < 14; i++)
+            this.family_blues[i] = 0;
+
+        for (var i = 0; i < 10; i++)
+            this.family_other_blues[i] = 0;
+
+        this.blue_scale = 0;
+        this.blue_shift = 0;
+        this.blue_fuzz = 0;
+
+        this.standard_width[0] = 0;
+        this.standard_height[0] = 0;
+
+        this.num_snap_widths = 0;
+        this.num_snap_heights = 0;
+        this.force_bold = 0;
+        this.round_stem_up = 0;
+
+        for (var i = 0; i < 13; i++)
+            this.snap_widths[i] = 0;
+        for (var i = 0; i < 13; i++)
+            this.snap_heights[i] = 0;
+
+        this.expansion_factor = 0;
+
+        this.language_group = 0;
+        this.password = 0;
+
+        this.min_feature[0] = 0;
+        this.min_feature[1] = 0;
+    }
+}
+
+function PS_DesignMapRec()
+{
+    this.num_points = 0;
+    this.design_points = null;
+    this.blend_points = null;
+}
+
+function PS_BlendRec()
+{
+    this.num_designs = 0;
+    this.num_axis = 0;
+
+    this.axis_names = CreateNullArray(FT_Common.T1_MAX_MM_AXIS);
+    this.design_pos = CreateNullArray(FT_Common.T1_MAX_MM_DESIGNS);
+    this.design_map = new Array(FT_Common.T1_MAX_MM_AXIS);
+    for (var i = 0; i < FT_Common.T1_MAX_MM_AXIS; i++)
+        this.design_map[i] = new PS_DesignMapRec();
+
+    this.weight_vector = null;
+    this.default_weight_vector = 0;
+
+    this.font_infos = CreateNullArray(FT_Common.T1_MAX_MM_DESIGNS + 1);
+    this.privates = CreateNullArray(FT_Common.T1_MAX_MM_DESIGNS + 1);
+
+    this.blend_bitflags = 0;
+
+    this.bboxes = CreateNullArray(FT_Common.T1_MAX_MM_DESIGNS + 1);
+
+    this.default_design_vector = CreateUIntArray(FT_Common.T1_MAX_MM_DESIGNS);
+    this.num_default_design_vector = 0;
+}
+
+function CID_FaceDictRec()
+{
+    this.private_dict = new PS_PrivateRec();
+
+    this.len_buildchar = 0;
+    this.forcebold_threshold = 0;
+    this.stroke_width = 0;
+    this.expansion_factor = 0;
+
+    this.paint_type = 0;
+    this.font_type = 0;
+    this.font_matrix = new FT_Matrix();
+    this.font_offset = new FT_Vector();
+
+    this.num_subrs = 0;
+    this.subrmap_offset = 0;
+    this.sd_bytes = 0;
+}
+
+function CID_FaceInfoRec()
+{
+    this.cid_font_name = "";
+    this.cid_version = 0;
+    this.cid_font_type = 0;
+
+    this.registry = "";
+    this.ordering = "";
+    this.supplement = 0;
+
+    this.font_info = new PS_FontInfoRec();
+    this.font_bbox = new FT_BBox();
+    this.uid_base = 0;
+
+    this.num_xuid = 0;
+    this.xuid = CreateUIntArray(16);
+
+    this.cidmap_offset = 0;
+    this.fd_bytes = 0;
+    this.gd_bytes = 0;
+    this.cid_count = 0;
+
+    this.num_dicts = 0;
+    this.font_dicts = null;
+
+    this.data_offset = 0;
+}
+
+function FT_Has_PS_Glyph_Names(face)
+{
+    var result = 0;
+    if (face != null)
+    {
+        var service = FT_FACE_FIND_SERVICE(face, FT_SERVICE_ID_POSTSCRIPT_INFO);
+
+        if (service && service.ps_has_glyph_names)
+            result = service.ps_has_glyph_names(face);
+    }
+    return result;
+}
+function FT_Get_PS_Font_Info(face, afont_info)
+{
+    var error = FT_Common.FT_Err_Invalid_Argument;
+    if (face != null)
+    {
+        var service = FT_FACE_FIND_SERVICE(face, FT_SERVICE_ID_POSTSCRIPT_INFO);
+
+        if (service && service.ps_get_font_info)
+            error = service.ps_get_font_info(face, afont_info);
+    }
+    return error;
+}
+function FT_Get_PS_Font_Private(face, afont_private)
+{
+    var error = FT_Common.FT_Err_Invalid_Argument;
+    if (face != null)
+    {
+        var service = FT_FACE_FIND_SERVICE(face, FT_SERVICE_ID_POSTSCRIPT_INFO);
+
+        if (service && service.ps_get_font_private)
+            error = service.ps_get_font_private(face, afont_private);
+    }
+    return error;
+}
+function FT_Get_PS_Font_Value(face, key, idx, value, value_len)
+{
+    var result  = 0;
+    if (face != null)
+    {
+        var service = FT_FACE_FIND_SERVICE(face, FT_SERVICE_ID_POSTSCRIPT_INFO);
+
+        if (service && service.ps_get_font_value)
+            result = service.ps_get_font_value(face, key, idx, value, value_len);
+    }
+    return result;
+}
+/******************************************************************************/
+// t1types
+/******************************************************************************/
+function T1_EncodingRec()
+{
+    this.num_chars  = 0;
+    this.code_first = 0;
+    this.code_last  = 0;
+
+    this.char_index = null;
+    this.char_name  = null;
+}
+function PS_FontExtraRec()
+{
+    this.fs_type = 0;
+
+    this.CreateDublicate = function()
+    {
+        var _ret = new PS_FontExtraRec();
+        _ret.fs_type = this.fs_type;
+        return _ret;
+    }
+}
+function T1_FontRec()
+{
+    this.font_info      = new PS_FontInfoRec();
+    this.font_extra     = new PS_FontExtraRec();
+    this.private_dict   = new PS_PrivateRec();
+    this.font_name      = "";
+
+    this.encoding_type  = 0;
+    this.encoding       = new T1_EncodingRec();
+
+    this.subrs_block        = null;
+    this.charstrings_block  = null;
+    this.glyph_names_block  = null;
+
+    this.num_subrs = 0;
+    this.subrs = null;
+    this.subrs_len = null;
+
+    this.num_glyphs = 0;
+    this.glyph_names = null;
+    this.charstrings = null;
+    this.charstrings_len = null;
+
+    this.paint_type = 0;
+    this.font_type = 0;
+    this.font_matrix = new FT_Matrix();
+    this.font_offset = new FT_Vector();
+    this.font_bbox = new FT_BBox();
+    this.font_id = 0;
+
+    this.stroke_width = 0;
+}
+function CID_SubrsRec()
+{
+    this.num_subrs = 0;
+    this.code = null;
+}
+
+function AFM_TrackKernRec()
+{
+    this.degree     = 0;
+    this.min_ptsize = 0;
+    this.min_kern   = 0;
+    this.max_ptsize = 0;
+    this.max_kern   = 0;
+}
+function AFM_KernPairRec()
+{
+    this.index1 = 0;
+    this.index2 = 0;
+    this.x = 0;
+    this.y = 0;
+}
+function AFM_FontInfoRec()
+{
+    this.IsCIDFont = 0;
+    this.FontBBox = new FT_BBox();
+    this.Ascender = 0;
+    this.Descender = 0;
+    this.TrackKerns = null;
+    this.NumTrackKern = 0;
+    this.KernPairs = null;
+    this.NumKernPair = 0;
+}
+
+
+
+function T1_Face()
+{
+    this.num_faces = 0;
+    this.face_index = 0;
+
+    this.face_flags = 0;
+    this.style_flags = 0;
+
+    this.num_glyphs = 0;
+
+    this.family_name = "";
+    this.style_name = "";
+
+    this.num_fixed_sizes = 0;
+    this.available_sizes = [];
+
+    this.num_charmaps = 0;
+    this.charmaps = [];
+
+    this.generic = new FT_Generic();
+
+    /*# The following member variables (down to `underline_thickness') */
+    /*# are only relevant to scalable outlines; cf. @FT_Bitmap_Size    */
+    /*# for bitmap fonts.                                              */
+    this.bbox = new FT_BBox();
+
+    this.units_per_EM = 0;
+    this.ascender = 0;
+    this.descender = 0;
+    this.height = 0;
+
+    this.max_advance_width = 0;
+    this.max_advance_height = 0;
+
+    this.underline_position = 0;
+    this.underline_thickness = 0;
+
+    this.glyph = null;
+    this.size = null;
+    this.charmap = null;
+
+    /*@private begin */
+    this.driver = null;
+    this.memory = null;
+    this.stream = null;
+
+    this.sizes_list = [];
+
+    this.autohint = [];
+    this.extensions = null;
+
+    this.internal = null;
+    /*@private end */
+
+    this.type1 = new T1_FontRec();
+    this.psnames = null;
+    this.psaux = null;
+    this.afm_data = null;
+
+    this.charmaprecs = new Array(2);
+    this.charmaprecs[0] = new FT_CharMapRec();
+    this.charmaprecs[1] = new FT_CharMapRec();
+
+    this.charmaps = new Array(2);
+    this.charmaps[0] = null;
+    this.charmaps[1] = null;
+
+    //#ifdef FT_CONFIG_OPTION_OLD_INTERNALS
+    this.unicode_map = null;
+    //#endif
+
+    /* support for Multiple Masters fonts */
+    this.blend = null;
+
+    /* undocumented, optional: indices of subroutines that express      */
+    /* the NormalizeDesignVector and the ConvertDesignVector procedure, */
+    /* respectively, as Type 2 charstrings; -1 if keywords not present  */
+    this.ndv_idx = 0;
+    this.cdv_idx = 0;
+
+    /* undocumented, optional: has the same meaning as len_buildchar */
+    /* for Type 2 fonts; manipulated by othersubrs 19, 24, and 25    */
+    this.len_buildchar = 0;
+    this.buildchar = null;
+
+    /* since version 2.1 - interface to PostScript hinter */
+    this.pshinter = null;
+}
+
+function CID_Face()
+{
+    this.num_faces = 0;
+    this.face_index = 0;
+
+    this.face_flags = 0;
+    this.style_flags = 0;
+
+    this.num_glyphs = 0;
+
+    this.family_name = "";
+    this.style_name = "";
+
+    this.num_fixed_sizes = 0;
+    this.available_sizes = [];
+
+    this.num_charmaps = 0;
+    this.charmaps = [];
+
+    this.generic = new FT_Generic();
+
+    /*# The following member variables (down to `underline_thickness') */
+    /*# are only relevant to scalable outlines; cf. @FT_Bitmap_Size    */
+    /*# for bitmap fonts.                                              */
+    this.bbox = new FT_BBox();
+
+    this.units_per_EM = 0;
+    this.ascender = 0;
+    this.descender = 0;
+    this.height = 0;
+
+    this.max_advance_width = 0;
+    this.max_advance_height = 0;
+
+    this.underline_position = 0;
+    this.underline_thickness = 0;
+
+    this.glyph = null;
+    this.size = null;
+    this.charmap = null;
+
+    /*@private begin */
+    this.driver = null;
+    this.memory = null;
+    this.stream = null;
+
+    this.sizes_list = [];
+
+    this.autohint = [];
+    this.extensions = null;
+
+    this.internal = null;
+    /*@private end */
+
+    this.psnames = null;
+    this.psaux = null;
+    this.cid = new CID_FaceInfoRec();
+    this.font_extra = new PS_FontExtraRec();
+
+    this.subrs = null;
+
+    /* since version 2.1 - interface to PostScript hinter */
+    this.pshinter = null;
+
+    this.binary_data = new CPointer(); /* used if hex data has been converted */
+    this.cid_stream = null;
+}
+
+/******************************************************************************/
+function IS_PS_NEWLINE(ch)
+{
+    if (ch == FT_Common.SYMBOL_CONST_SR || ch == FT_Common.SYMBOL_CONST_SN)
+        return true;
+    return false;
+}
+function IS_PS_SPACE(ch)
+{
+    switch (ch)
+    {
+        case FT_Common.SYMBOL_CONST_SPACE:
+        case FT_Common.SYMBOL_CONST_SR:
+        case FT_Common.SYMBOL_CONST_SN:
+        case FT_Common.SYMBOL_CONST_ST:
+        case FT_Common.SYMBOL_CONST_SF:
+        case FT_Common.SYMBOL_CONST_S0:
+            return true;
+    }
+    return false;
+}
+function IS_PS_SPECIAL(ch)
+{
+    switch (ch)
+    {
+        case FT_Common.SYMBOL_CONST_BS:
+        case FT_Common.SYMBOL_CONST_LS1:
+        case FT_Common.SYMBOL_CONST_LS2:
+        case FT_Common.SYMBOL_CONST_LS3:
+        case FT_Common.SYMBOL_CONST_RS1:
+        case FT_Common.SYMBOL_CONST_RS2:
+        case FT_Common.SYMBOL_CONST_RS3:
+        case FT_Common.SYMBOL_CONST_MATH_1:
+        case FT_Common.SYMBOL_CONST_MATH_2:
+        case FT_Common.SYMBOL_CONST_MATH_3:
+            return true;
+    }
+    return false;
+}
+function IS_PS_DELIM(ch)
+{
+    switch (ch)
+    {
+        case FT_Common.SYMBOL_CONST_SPACE:
+        case FT_Common.SYMBOL_CONST_SR:
+        case FT_Common.SYMBOL_CONST_SN:
+        case FT_Common.SYMBOL_CONST_ST:
+        case FT_Common.SYMBOL_CONST_SF:
+        case FT_Common.SYMBOL_CONST_S0:
+        case FT_Common.SYMBOL_CONST_BS:
+        case FT_Common.SYMBOL_CONST_LS1:
+        case FT_Common.SYMBOL_CONST_LS2:
+        case FT_Common.SYMBOL_CONST_LS3:
+        case FT_Common.SYMBOL_CONST_RS1:
+        case FT_Common.SYMBOL_CONST_RS2:
+        case FT_Common.SYMBOL_CONST_RS3:
+        case FT_Common.SYMBOL_CONST_MATH_1:
+        case FT_Common.SYMBOL_CONST_MATH_2:
+        case FT_Common.SYMBOL_CONST_MATH_3:
+            return true;
+    }
+    return false;
+}
+function IS_PS_DIGIT(ch)
+{
+    return (ch >= FT_Common.SYMBOL_CONST_0 && ch <= FT_Common.SYMBOL_CONST_9) ? true : false;
+}
+function IS_PS_XDIGIT(ch)
+{
+    return (IS_PS_DIGIT(ch) || (ch >= FT_Common.SYMBOL_CONST_A && ch <= FT_Common.SYMBOL_CONST_F)
+        || (ch >= FT_Common.SYMBOL_CONST_a && ch <= FT_Common.SYMBOL_CONST_f)) ? true : false;
+}
+function IS_PS_BASE85(ch)
+{
+    return (ch >= FT_Common.SYMBOL_CONST_VOSCL && ch <= FT_Common.SYMBOL_CONST_u) ? true : false;
+}
+
+function IS_PS_TOKEN(cur, limit, token, len)
+{
+    if (cur.data[cur.pos] == token.charCodeAt(0) && (((cur.pos + len) == limit) || ((cur.pos + len) < limit && IS_PS_DELIM(cur.data[cur.pos + len - 1]))) && _strncmp_data(cur, token, len - 1) == 0)
+        return 1;
+    return 0;
+}
+
+/******************************************************************************/
+// psconv
+/******************************************************************************/
+var ft_char_table =
+[
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    0,  1,  2,  3,  4,  5,  6,  7,  8,  9, -1, -1, -1, -1, -1, -1,
+    -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+    25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1,
+    -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+    25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1
+];
+
+function PS_Conv_Strtol(cursor, limit, base)
+{
+    var _data = cursor.data;
+    var pos = cursor.pos;
+
+    var num = 0;
+    var sign = 0;
+
+    if (pos == limit || base < 2 || base > 36)
+        return 0;
+
+    if (_data[pos] == FT_Common.SYMBOL_CONST_MATH_MINUS || _data[pos] == FT_Common.SYMBOL_CONST_MATH_PLUS)
+    {
+        sign = (_data[pos] == FT_Common.SYMBOL_CONST_MATH_MINUS) ? 1 : 0;
+
+        pos++;
+        if (pos == limit)
+            return 0;
+    }
+
+    for (; pos < limit; pos++)
+    {
+        if (IS_PS_SPACE(_data[pos]) || _data[pos] >= 0x80)
+            break;
+
+        var c = ft_char_table[_data[pos] & 0x7f];
+
+        if (c < 0 || c >= base)
+            break;
+
+        num = num * base + c;
+    }
+
+    if (sign == 1)
+        num = -num;
+
+    cursor.pos = pos;
+    return num;
+}
+function PS_Conv_ToInt(cursor, limit)
+{
+    var num = PS_Conv_Strtol(cursor, limit, 10);
+    var data = cursor.data;
+    var pos = cursor.pos;
+
+    if (pos < limit && data[pos] == FT_Common.SYMBOL_CONST_SHARP)
+    {
+        cursor.pos = pos + 1;
+        return PS_Conv_Strtol(cursor, limit, num);
+    }
+    return num;
+}
+function PS_Conv_ToFixed(cursor, limit, power_ten)
+{
+    var p = dublicate_pointer(cursor);
+    var integral;
+    var decimal = 0, divider = 1;
+    var sign = 0;
+
+    if (p.pos == limit)
+        return 0;
+
+    var _data = p.data;
+    if (_data[p.pos] == FT_Common.SYMBOL_CONST_MATH_MINUS || _data[p.pos] == FT_Common.SYMBOL_CONST_MATH_PLUS)
+    {
+        sign = (_data[p.pos] == FT_Common.SYMBOL_CONST_MATH_MINUS) ? 1 : 0;
+
+        p.pos++;
+        if (p.pos == limit)
+            return 0;
+    }
+
+    if (_data[p.pos] != FT_Common.SYMBOL_CONST_POINT)
+        integral = PS_Conv_ToInt(p, limit) << 16;
+    else
+        integral = 0;
+
+    /* read the decimal part */
+    if (p.pos < limit && _data[p.pos] == FT_Common.SYMBOL_CONST_POINT)
+    {
+        p.pos++;
+        for (; p.pos < limit; p.pos++)
+        {
+            if (IS_PS_SPACE(_data[p.pos]) || _data[p.pos] >= 0x80)
+                break;
+
+            var c = ft_char_table[_data[p.pos] & 0x7f];
+
+            if (c < 0 || c >= 10)
+                break;
+
+            if (!integral && power_ten > 0)
+            {
+                power_ten--;
+                decimal = decimal * 10 + c;
+            }
+            else
+            {
+                if (divider < 10000000)
+                {
+                    decimal = decimal * 10 + c;
+                    divider *= 10;
+                }
+            }
+        }
+    }
+
+    /* read exponent, if any */
+    if (p.pos + 1 < limit && (_data[p.pos] == FT_Common.SYMBOL_CONST_e || _data[p.pos] == FT_Common.SYMBOL_CONST_E))
+    {
+        p.pos++;
+        power_ten += PS_Conv_ToInt(p, limit);
+    }
+
+    while (power_ten > 0)
+    {
+        integral *= 10;
+        decimal  *= 10;
+        power_ten--;
+    }
+
+    while (power_ten < 0)
+    {
+        integral /= 10;
+        divider  *= 10;
+        power_ten++;
+    }
+
+    if (decimal)
+        integral += FT_DivFix(decimal, divider);
+
+    if (sign)
+        integral = -integral;
+
+    cursor.pos = p.pos;
+
+    return integral;
+}
+
+function PS_Conv_ASCIIHexDecode(cursor, limit, buffer, n)
+{
+    var r = 0;
+    var w = buffer.pos;
+    var pad = 0x01;
+    
+    n *= 2;
+
+    var p  = dublicate_pointer(cursor);
+    if (n > (limit - p.pos))
+        n = (limit - p.pos);
+
+    /* we try to process two nibbles at a time to be as fast as possible */
+    var _data = p.data;
+    for ( ; r < n; r++)
+    {
+        var c = _data[p.pos + r];
+
+        if (IS_PS_SPACE(c))
+            continue;
+
+        if (c >= 0x80)
+            break;
+
+        c = ft_char_table[c & 0x7F];
+        var _c = (c >= 0) ? c : c + 256;
+        if (c >= 16)
+            break;
+
+        pad = (pad << 4) | c;
+        if (pad & 0x100)
+        {
+            buffer.data[w++] = pad & 0xFF;
+            pad = 0x01;
+        }
+    }
+
+    if (pad != 0x01)
+        buffer[w++] = ((pad << 4) & 0xFF);
+
+    cursor.pos = p.pos + r;
+    return w;
+}
+
+function PS_Conv_EexecDecode(cursor, limit, buffer, n, seed)
+{
+    var r;
+    var s = seed;
+
+    var _sd = cursor.data;
+    var _sp = cursor.pos;
+
+    if (n > (limit - _sp))
+        n = (limit - _sp);
+
+    var _dd = buffer.data;
+    var _dp = buffer.pos;
+
+    var v = 0;
+    var b = 0;
+
+    for (r = 0; r < n; r++, _sp++, _dp++)
+    {
+        v = _sd[_sp];
+        b = (v ^ (s >> 8));
+
+        s = ((v + s)*52845 + 22719) & 0xFFFF;
+        _dd[_dp] = b & 0xFF;
+    }
+
+    cursor.pos = _sp;
+    return { r : r, seed : s };
+}
+/******************************************************************************/
+// afmparse
+/******************************************************************************/
+function AFM_ValueRec()
+{
+    this.type = 0;
+    this.u;
+}
+function AFM_StreamRec()
+{
+    this.base = null;
+    this.cursor = 0;
+    this.limit = 0;
+
+    this.status = 0;
+}
+
+function AFM_IS_NEWLINE(ch)
+{
+    if (ch == FT_Common.SYMBOL_CONST_SR || ch == FT_Common.SYMBOL_CONST_SN)
+        return true;
+    return false;
+}
+function AFM_IS_EOF(ch)
+{
+    if (ch == -1  || ch == 0x1A)
+        return true;
+    return false;
+}
+function AFM_IS_SPACE(ch)
+{
+    if (ch == FT_Common.SYMBOL_CONST_SPACE  || ch == FT_Common.SYMBOL_CONST_ST)
+        return true;
+    return false;
+}
+function AFM_IS_SEP(ch)
+{
+    return (ch == FT_Common.SYMBOL_CONST_SERP) ? true : false;
+}
+function AFM_GETC(stream)
+{
+    return (stream.cursor < stream.limit) ? stream.base[stream.cursor++] : -1;
+}
+
+function afm_stream_skip_spaces(stream)
+{
+    var ch = 0;
+
+    if (stream.status >= FT_Common.AFM_STREAM_STATUS_EOC)
+        return FT_Common.SYMBOL_CONST_SERP;
+
+    while (true)
+    {
+        ch = AFM_GETC();
+        if (!AFM_IS_SPACE(ch))
+            break;
+    }
+
+    if (AFM_IS_NEWLINE(ch))
+        stream.status = FT_Common.AFM_STREAM_STATUS_EOL;
+    else if (AFM_IS_SEP(ch))
+        stream.status = FT_Common.AFM_STREAM_STATUS_EOC;
+    else if (AFM_IS_EOF(ch))
+        stream.status = FT_Common.AFM_STREAM_STATUS_EOF;
+
+    return ch;
+}
+function afm_stream_read_one(stream)
+{
+    afm_stream_skip_spaces( stream );
+    if (stream.status >= FT_Common.AFM_STREAM_STATUS_EOC)
+        return null;
+
+    var str = new CPointer();
+    str.data = stream.base;
+    str.pos = stream.cursor - 1;
+    var ch;
+
+    while ( 1 )
+    {
+        ch = AFM_GETC();
+        if (AFM_IS_SPACE(ch))
+            break;
+        else if (AFM_IS_NEWLINE(ch))
+        {
+            stream.status = FT_Common.AFM_STREAM_STATUS_EOL;
+            break;
+        }
+        else if (AFM_IS_SEP(ch))
+        {
+            stream.status = FT_Common.AFM_STREAM_STATUS_EOC;
+            break;
+        }
+        else if (AFM_IS_EOF(ch))
+        {
+            stream.status = FT_Common.AFM_STREAM_STATUS_EOF;
+            break;
+        }
+    }
+
+    return str;
+}
+function afm_stream_read_string(stream)
+{
+    afm_stream_skip_spaces(stream);
+    if (stream.status >= FT_Common.AFM_STREAM_STATUS_EOL)
+        return null;
+
+    var str = new CPointer();
+    str.data = stream.base;
+    str.pos = stream.cursor - 1;
+    var ch;
+
+    /* scan to eol */
+    while ( 1 )
+    {
+        ch = AFM_GETC();
+        if (AFM_IS_NEWLINE(ch))
+        {
+            stream.status = FT_Common.AFM_STREAM_STATUS_EOL;
+            break;
+        }
+        else if (AFM_IS_EOF(ch))
+        {
+            stream.status = FT_Common.AFM_STREAM_STATUS_EOF;
+            break;
+        }
+    }
+
+    return str;
+}
+var afm_key_table =
+[
+    "Ascender",
+    "AxisLabel",
+    "AxisType",
+    "B",
+    "BlendAxisTypes",
+    "BlendDesignMap",
+    "BlendDesignPositions",
+    "C",
+    "CC",
+    "CH",
+    "CapHeight",
+    "CharWidth",
+    "CharacterSet",
+    "Characters",
+    "Descender",
+    "EncodingScheme",
+    "EndAxis",
+    "EndCharMetrics",
+    "EndComposites",
+    "EndDirection",
+    "EndFontMetrics",
+    "EndKernData",
+    "EndKernPairs",
+    "EndTrackKern",
+    "EscChar",
+    "FamilyName",
+    "FontBBox",
+    "FontName",
+    "FullName",
+    "IsBaseFont",
+    "IsCIDFont",
+    "IsFixedPitch",
+    "IsFixedV",
+    "ItalicAngle",
+    "KP",
+    "KPH",
+    "KPX",
+    "KPY",
+    "L",
+    "MappingScheme",
+    "MetricsSets",
+    "N",
+    "Notice",
+    "PCC",
+    "StartAxis",
+    "StartCharMetrics",
+    "StartComposites",
+    "StartDirection",
+    "StartFontMetrics",
+    "StartKernData",
+    "StartKernPairs",
+    "StartKernPairs0",
+    "StartKernPairs1",
+    "StartTrackKern",
+    "StdHW",
+    "StdVW",
+    "TrackKern",
+    "UnderlinePosition",
+    "UnderlineThickness",
+    "VV",
+    "VVector",
+    "Version",
+    "W",
+    "W0",
+    "W0X",
+    "W0Y",
+    "W1",
+    "W1X",
+    "W1Y",
+    "WX",
+    "WY",
+    "Weight",
+    "WeightVector",
+    "XHeight"
+];
+
+function afm_parser_read_vals(parser, vals, n)
+{
+    var stream = parser.stream;
+    var str = null;
+
+    if (n > FT_Common.AFM_MAX_ARGUMENTS)
+        return 0;
+
+    var i = 0;
+    for (; i < n; i++)
+    {
+        var val = vals[i];
+
+        if (val.type == FT_Common.AFM_VALUE_TYPE_STRING)
+            str = afm_stream_read_string(stream);
+        else
+            str = afm_stream_read_one(stream);
+
+        if (str == null)
+            break;
+
+        var len = stream.cursor - str.pos - 1;
+
+        switch (val.type)
+        {
+            case FT_Common.AFM_VALUE_TYPE_STRING:
+            case FT_Common.AFM_VALUE_TYPE_NAME:
+                val.u = "";
+                for (var j = 0; j < len; j++)
+                    val.u += String.fromCharCode(str.data[str.pos++]);
+                break;
+
+            case FT_Common.AFM_VALUE_TYPE_FIXED:
+                val.u = PS_Conv_ToFixed(str, str.pos + len, 0);
+                break;
+
+            case FT_Common.AFM_VALUE_TYPE_INTEGER:
+                val.u = PS_Conv_ToInt(str, str.pos + len);
+                break;
+
+            case FT_Common.AFM_VALUE_TYPE_BOOL:
+                val.u = (len == 4 && (0 == _strncmp(str, "true", 4)));
+                break;
+
+            case FT_Common.AFM_VALUE_TYPE_INDEX:
+                if (parser.get_index != null)
+                    val.u = parser.get_index(str, len, parser.user_data);
+                else
+                    val.u = 0;
+                break;
+        }
+    }
+
+    return i;
+}
+
+function afm_parser_next_key(parser, line)
+{
+    var stream = parser.stream;
+    var key = null;
+
+    if (line)
+    {
+        while ( 1 )
+        {
+            /* skip current line */
+            if (stream.status < FT_Common.AFM_STREAM_STATUS_EOL)
+                afm_stream_read_string(stream);
+
+            stream.status = FT_Common.AFM_STREAM_STATUS_NORMAL;
+            key = afm_stream_read_one(stream);
+
+            /* skip empty line */
+            if (key == null  && (stream.status < FT_Common.AFM_STREAM_STATUS_EOF) && (stream.status >= FT_Common.AFM_STREAM_STATUS_EOL))
+                continue;
+
+            break;
+        }
+    }
+    else
+    {
+        while ( 1 )
+        {
+            /* skip current column */
+            while (stream.status < FT_Common.AFM_STREAM_STATUS_EOC)
+                afm_stream_read_one(stream);
+
+            stream.status = FT_Common.AFM_STREAM_STATUS_NORMAL;
+            key = afm_stream_read_one(stream);
+
+            /* skip empty column */
+            if (key == null  && (stream.status < FT_Common.AFM_STREAM_STATUS_EOF) && (stream.status >= FT_Common.AFM_STREAM_STATUS_EOC))
+                continue;
+
+            break;
+        }
+    }
+
+    var ret_len;
+    ret_len = (key != null) ? (stream.cursor - key.pos - 1) : 0;
+
+    return { key : key, len: ret_len };
+}
+
+function afm_tokenize(key, len)
+{
+    var n = 0;
+    for (; n < FT_Common.N_AFM_TOKENS; n++)
+    {
+        if (afm_key_table[n].charCodeAt(0) == key.charCodeAt(0))
+        {
+            for (; n < FT_Common.N_AFM_TOKENS; n++)
+            {
+                if (afm_key_table[n].charCodeAt(0) != key.charCodeAt(0))
+                    return FT_Common.AFM_TOKEN_UNKNOWN;
+
+                if (_strncmp(afm_key_table[n], key, len) == 0)
+                    return n;
+            }
+        }
+    }
+    return FT_Common.AFM_TOKEN_UNKNOWN;
+}
+
+function afm_parser_init(parser, memory, base, limit)
+{
+    var stream = new AFM_StreamRec();
+
+    stream.base = dublicate_pointer(base);
+    stream.cursor = stream.base.pos;
+    stream.limit  = limit;
+
+    /* don't skip the first line during the first call */
+    stream.status = FT_Common.AFM_STREAM_STATUS_EOL;
+
+    parser.memory    = memory;
+    parser.stream    = stream;
+    parser.FontInfo  = null;
+    parser.get_index = null;
+
+    return 0;
+}
+
+function afm_parser_done(parser)
+{
+    parser.stream = null;
+}
+
+function afm_parser_read_int(parser)
+{
+    var val = new AFM_ValueRec();
+    val.type = FT_Common.AFM_VALUE_TYPE_INTEGER;
+
+    if (afm_parser_read_vals(parser, val, 1) == 1)
+    {
+        return { pint: val.u, err: 0 };
+    }
+    return { pint: 0, err: FT_Common.FT_Err_Syntax_Error };
+}
+
+function afm_parse_track_kern(parser)
+{
+    var fi = parser.FontInfo;
+    var n = -1;
+
+    var ret = afm_parser_read_int(parser);
+    if (0 != ret.err)
+        return FT_Common.FT_Err_Syntax_Error;
+
+    fi.NumTrackKern = ret.pint;
+    if (fi.NumTrackKern != 0)
+    {
+        fi.TrackKerns = new Array(fi.NumTrackKern);
+    }
+
+    while (true)
+    {
+        var _key_len = afm_parser_next_key(parser, 1);
+        if (_key_len.key == null)
+            break;
+
+        var shared_vals = new Array(5);
+        shared_vals[0] = new AFM_ValueRec();
+        shared_vals[1] = new AFM_ValueRec();
+        shared_vals[2] = new AFM_ValueRec();
+        shared_vals[3] = new AFM_ValueRec();
+        shared_vals[4] = new AFM_ValueRec();
+
+        switch (afm_tokenize(_key_len.key, _key_len.len))
+        {
+            case FT_Common.AFM_TOKEN_TRACKKERN:
+                n++;
+
+                if (n >= fi.NumTrackKern)
+                    return FT_Common.FT_Err_Syntax_Error;
+
+                var tk = fi.TrackKerns[n];
+
+                shared_vals[0].type = FT_Common.AFM_VALUE_TYPE_INTEGER;
+                shared_vals[1].type = FT_Common.AFM_VALUE_TYPE_FIXED;
+                shared_vals[2].type = FT_Common.AFM_VALUE_TYPE_FIXED;
+                shared_vals[3].type = FT_Common.AFM_VALUE_TYPE_FIXED;
+                shared_vals[4].type = FT_Common.AFM_VALUE_TYPE_FIXED;
+                if (afm_parser_read_vals( parser, shared_vals, 5) != 5)
+                    return FT_Common.FT_Err_Syntax_Error;
+
+                tk.degree     = shared_vals[0].u;
+                tk.min_ptsize = shared_vals[1].u;
+                tk.min_kern   = shared_vals[2].u;
+                tk.max_ptsize = shared_vals[3].u;
+                tk.max_kern   = shared_vals[4].u;
+
+                /* is this correct? */
+                if (tk.degree < 0 && tk.min_kern > 0)
+                    tk.min_kern = -tk.min_kern;
+                break;
+
+            case FT_Common.AFM_TOKEN_ENDTRACKKERN:
+            case FT_Common.AFM_TOKEN_ENDKERNDATA:
+            case FT_Common.AFM_TOKEN_ENDFONTMETRICS:
+                fi.NumTrackKern = n + 1;
+                return FT_Common.FT_Err_Ok;
+
+            case FT_Common.AFM_TOKEN_UNKNOWN:
+                break;
+
+            default:
+                return FT_Common.FT_Err_Syntax_Error;
+        }
+    }
+
+    return FT_Common.FT_Err_Syntax_Error;
+}
+
+function afm_compare_kern_pairs(kp1, kp2)
+{
+    var index1 = kp1.index1 << 16 | kp1.index2;
+    var index2 = kp2.index1 << 16 | kp2.index2;
+
+    if ( index1 > index2 )
+        return 1;
+    else if ( index1 < index2 )
+        return -1;
+    else
+        return 0;
+}
+
+function afm_parse_kern_pairs(parser)
+{
+    var fi = parser.FontInfo;
+    var kp = null;
+    var n = -1;
+
+    var _key_len = afm_parser_read_int(parser);
+    if (null != _key_len.key)
+        return FT_Common.FT_Err_Syntax_Error;
+
+    fi.NumKernPair = _key_len.len;
+    if (fi.NumKernPair != 0)
+    {
+        fi.KernPairs = new Array(fi.NumKernPair);
+        for (var i = 0; i < fi.NumKernPair; i++)
+            fi.NumKernPair[i] = new AFM_KernPairRec();
+    }
+
+    while (true)
+    {
+        _key_len = afm_parser_next_key(parser, 1);
+        if (null == _key_len.key)
+            break;
+
+        var token = afm_tokenize(_key_len.key, _key_len.len);
+        switch (token)
+        {
+            case FT_Common.AFM_TOKEN_KP:
+            case FT_Common.AFM_TOKEN_KPX:
+            case FT_Common.AFM_TOKEN_KPY:
+                var shared_vals = new Array(4);
+                shared_vals[0] = new AFM_ValueRec();
+                shared_vals[1] = new AFM_ValueRec();
+                shared_vals[2] = new AFM_ValueRec();
+                shared_vals[3] = new AFM_ValueRec();
+                n++;
+
+                if (n >= fi.NumKernPair)
+                    return FT_Common.FT_Err_Syntax_Error;
+
+                kp = fi.KernPairs[n];
+
+                shared_vals[0].type = FT_Common.AFM_VALUE_TYPE_INDEX;
+                shared_vals[1].type = FT_Common.AFM_VALUE_TYPE_INDEX;
+                shared_vals[2].type = FT_Common.AFM_VALUE_TYPE_INTEGER;
+                shared_vals[3].type = FT_Common.AFM_VALUE_TYPE_INTEGER;
+                var r = afm_parser_read_vals(parser, shared_vals, 4);
+                if (r < 3)
+                    return FT_Common.FT_Err_Syntax_Error;
+
+                kp.index1 = shared_vals[0].u;
+                kp.index2 = shared_vals[1].u;
+                if (token == FT_Common.AFM_TOKEN_KPY)
+                {
+                    kp.x = 0;
+                    kp.y = shared_vals[2].u;
+                }
+                else
+                {
+                    kp.x = shared_vals[2].u.i;
+                    kp.y = (token == FT_Common.AFM_TOKEN_KP && r == 4) ? shared_vals[3].u : 0;
+                }
+                break;
+
+            case FT_Common.AFM_TOKEN_ENDKERNPAIRS:
+            case FT_Common.AFM_TOKEN_ENDKERNDATA:
+            case FT_Common.AFM_TOKEN_ENDFONTMETRICS:
+                fi.NumKernPair = n + 1;
+                ft_qsort(fi.KernPairs, fi.NumKernPair, afm_compare_kern_pairs);
+                return FT_Common.FT_Err_Ok;
+
+            case FT_Common.AFM_TOKEN_UNKNOWN:
+                break;
+
+            default:
+                return FT_Common.FT_Err_Syntax_Error;
+        }
+    }
+
+    return FT_Common.FT_Err_Syntax_Error;
+}
+
+function afm_parse_kern_data(parser)
+{
+    while (true)
+    {
+        var _key_len = afm_parser_next_key(parser, 1);
+        if (null != _key_len)
+            break;
+
+        switch (afm_tokenize(_key_len.key, _key_len.len))
+        {
+            case FT_Common.AFM_TOKEN_STARTTRACKKERN:
+                var error = afm_parse_track_kern(parser);
+                if (error != FT_Common.FT_Err_Ok)
+                    return error;
+                break;
+
+            case FT_Common.AFM_TOKEN_STARTKERNPAIRS:
+            case FT_Common.AFM_TOKEN_STARTKERNPAIRS0:
+                var error = afm_parse_kern_pairs(parser);
+                if (error != FT_Common.FT_Err_Ok)
+                    return error;
+                break;
+
+            case FT_Common.AFM_TOKEN_ENDKERNDATA:
+            case FT_Common.AFM_TOKEN_ENDFONTMETRICS:
+                return FT_Common.FT_Err_Ok;
+
+            case FT_Common.AFM_TOKEN_UNKNOWN:
+                break;
+
+            default:
+                return FT_Common.FT_Err_Syntax_Error;
+        }
+    }
+    
+    return FT_Common.FT_Err_Syntax_Error;
+}
+
+function afm_parser_skip_section(parser, n, end_section)
+{
+    while ( n-- > 0 )
+    {
+        var _key_len = afm_parser_next_key(parser, 1);
+        if (_key_len.key != null)
+            return FT_Common.FT_Err_Syntax_Error;
+    }
+
+    while (true)
+    {
+        var _key_len = afm_parser_next_key(parser, 1);
+        if (_key_len.key != null)
+            break;
+
+        var token = afm_tokenize(_key_len.key, _key_len.len);
+
+        if (token == end_section || token == FT_Common.AFM_TOKEN_ENDFONTMETRICS)
+            return FT_Common.FT_Err_Ok;
+    }
+
+    return FT_Common.FT_Err_Syntax_Error;
+}
+
+function afm_parser_parse(parser)
+{
+    var fi = parser.FontInfo;
+    var error = FT_Common.FT_Err_Syntax_Error;
+    var metrics_sets = 0;
+
+    if (fi == null)
+        return FT_Common.FT_Err_Invalid_Argument;
+
+    var _key_len = afm_parser_next_key(parser, 1);
+    if (null == _key_len.key || _key_len.len != 16 || _strncmp(_key_len.key, "StartFontMetrics", 16) != 0)
+        return FT_Common.FT_Err_Unknown_File_Format;
+
+    while (true)
+    {
+        _key_len = afm_parser_next_key(parser, 1);
+        if (null == _key_len)
+            break;
+
+        var shared_vals = new Array(4);
+        shared_vals[0] = new AFM_ValueRec();
+        shared_vals[1] = new AFM_ValueRec();
+        shared_vals[2] = new AFM_ValueRec();
+        shared_vals[3] = new AFM_ValueRec();
+
+        var token = afm_tokenize(_key_len.key, _key_len.len);
+        switch (token)
+        {
+            case FT_Common.AFM_TOKEN_METRICSSETS:
+                var ret = afm_parser_read_int(parser);
+                if (ret.err != FT_Common.FT_Err_Ok)
+                {
+                    fi.TrackKerns = null;
+                    fi.NumTrackKern = 0;
+
+                    fi.KernPairs = null;
+                    fi.NumKernPair = 0;
+
+                    fi.IsCIDFont = 0;
+
+                    return error;
+                }
+                metrics_sets = ret.pint;
+                if (metrics_sets != 0 && metrics_sets != 2)
+                {
+                    fi.TrackKerns = null;
+                    fi.NumTrackKern = 0;
+
+                    fi.KernPairs = null;
+                    fi.NumKernPair = 0;
+
+                    fi.IsCIDFont = 0;
+
+                    return FT_Common.FT_Err_Unimplemented_Feature;
+                }
+                break;
+
+            case FT_Common.AFM_TOKEN_ISCIDFONT:
+                shared_vals[0].type = FT_Common.AFM_VALUE_TYPE_BOOL;
+                if (afm_parser_read_vals(parser, shared_vals, 1) != 1)
+                {
+                    fi.TrackKerns = null;
+                    fi.NumTrackKern = 0;
+
+                    fi.KernPairs = null;
+                    fi.NumKernPair = 0;
+
+                    fi.IsCIDFont = 0;
+
+                    return error;
+                }
+
+                fi.IsCIDFont = shared_vals[0].u;
+                break;
+
+            case FT_Common.AFM_TOKEN_FONTBBOX:
+                shared_vals[0].type = FT_Common.AFM_VALUE_TYPE_FIXED;
+                shared_vals[1].type = FT_Common.AFM_VALUE_TYPE_FIXED;
+                shared_vals[2].type = FT_Common.AFM_VALUE_TYPE_FIXED;
+                shared_vals[3].type = FT_Common.AFM_VALUE_TYPE_FIXED;
+                if (afm_parser_read_vals( parser, shared_vals, 4 ) != 4)
+                {
+                    fi.TrackKerns = null;
+                    fi.NumTrackKern = 0;
+
+                    fi.KernPairs = null;
+                    fi.NumKernPair = 0;
+
+                    fi.IsCIDFont = 0;
+
+                    return error;
+                }
+
+                fi.FontBBox.xMin = shared_vals[0].u;
+                fi.FontBBox.yMin = shared_vals[1].u;
+                fi.FontBBox.xMax = shared_vals[2].u;
+                fi.FontBBox.yMax = shared_vals[3].u;
+                break;
+
+            case FT_Common.AFM_TOKEN_ASCENDER:
+                shared_vals[0].type = FT_Common.AFM_VALUE_TYPE_FIXED;
+                if (afm_parser_read_vals(parser, shared_vals, 1) != 1)
+                {
+                    // fail
+                    return error;
+                }
+
+                fi.Ascender = shared_vals[0].u;
+                break;
+
+            case FT_Common.AFM_TOKEN_DESCENDER:
+                shared_vals[0].type = FT_Common.AFM_VALUE_TYPE_FIXED;
+                if (afm_parser_read_vals( parser, shared_vals, 1 ) != 1)
+                {
+                    fi.TrackKerns = null;
+                    fi.NumTrackKern = 0;
+
+                    fi.KernPairs = null;
+                    fi.NumKernPair = 0;
+
+                    fi.IsCIDFont = 0;
+
+                    return error;
+                }
+
+                fi.Descender = shared_vals[0].u;
+                break;
+
+            case FT_Common.AFM_TOKEN_STARTCHARMETRICS:
+                var ret = afm_parser_read_int(parser);
+                if (ret.err != FT_Common.FT_Err_Ok)
+                {
+                    fi.TrackKerns = null;
+                    fi.NumTrackKern = 0;
+
+                    fi.KernPairs = null;
+                    fi.NumKernPair = 0;
+
+                    fi.IsCIDFont = 0;
+
+                    return error;
+                }
+                var n = ret.pint;
+                error = afm_parser_skip_section(parser, n, FT_Common.AFM_TOKEN_ENDCHARMETRICS);
+                if (error != FT_Common.FT_Err_Ok)
+                    return error;
+                break;
+
+            case FT_Common.AFM_TOKEN_STARTKERNDATA:
+                error = afm_parse_kern_data(parser);
+                if (error != FT_Common.FT_Err_Ok)
+                {
+                    fi.TrackKerns = null;
+                    fi.NumTrackKern = 0;
+
+                    fi.KernPairs = null;
+                    fi.NumKernPair = 0;
+
+                    fi.IsCIDFont = 0;
+
+                    return error;
+                }
+            /* fall through since we only support kern data */
+            case FT_Common.AFM_TOKEN_ENDFONTMETRICS:
+                return FT_Common.FT_Err_Ok;
+
+            default:
+                break;
+        }
+    }
+
+    fi.TrackKerns = null;
+    fi.NumTrackKern = 0;
+
+    fi.KernPairs = null;
+    fi.NumKernPair = 0;
+
+    fi.IsCIDFont = 0;
+
+    return error;
+}
+
+/******************************************************************************/
+// t1cmap
+/******************************************************************************/
+function T1_CMapStdRec()
+{
+    this.cmap = new FT_CMapRec();
+
+    this.code_to_sid = null;
+    this.sid_to_string = null;
+
+    this.num_glyphs = 0;
+    this.glyph_names = null;
+
+    this.type = FT_Common.FT_CMAP_1;
+}
+function T1_CMapCustomRec()
+{
+    this.cmap = new FT_CMapRec();
+    this.first = 0;
+    this.count = 0;
+    this.indices = null;
+
+    this.type = FT_Common.FT_CMAP_1;
+}
+
+// standart
+function t1_cmap_std_init(cmap, is_expert)
+{
+    var face = __FT_CMapRec(cmap).charmap.face;
+    var psnames = face.psnames;
+
+    cmap.num_glyphs    = face.type1.num_glyphs;
+    cmap.glyph_names   = face.type1.glyph_names;
+    cmap.sid_to_string = psnames.adobe_std_strings;
+    cmap.code_to_sid   = (is_expert == 1) ? psnames.adobe_expert_encoding : psnames.adobe_std_encoding;
+}
+
+function t1_cmap_std_done(cmap)
+{
+    cmap.num_glyphs    = 0;
+    cmap.glyph_names   = null;
+    cmap.sid_to_string = null;
+    cmap.code_to_sid   = null;
+}
+
+function t1_cmap_std_char_index(cmap, char_code)
+{
+    var result = 0;
+
+    if (char_code < 256)
+    {
+        /* convert character code to Adobe SID string */
+        var code       = cmap.code_to_sid[char_code];
+        var glyph_name = cmap.sid_to_string(code);
+
+        /* look for the corresponding glyph name */
+        for (var n = 0; n < cmap.num_glyphs; n++ )
+        {
+            var gname = cmap.glyph_names[n];
+
+            if (gname != null && gname.charCodeAt(0) == glyph_name.charCodeAt(0) && gname == glyph_name)
+            {
+                result = n;
+                break;
+            }
+        }
+    }
+
+    return result;
+}
+
+function t1_cmap_std_char_next(cmap, char_code)
+{
+    var result = 0;
+    var pchar_code = char_code + 1;
+
+    while (pchar_code < 256)
+    {
+        result = t1_cmap_std_char_index( cmap, pchar_code );
+        if ( result != 0 )
+            return {gindex:result,char_code:pchar_code};
+
+        pchar_code++;
+    }
+    pchar_code = 0;
+    return {gindex:result,char_code:pchar_code};
+}
+
+function t1_cmap_standard_init(cmap)
+{
+    t1_cmap_std_init(cmap, 0);
+    return 0;
+}
+
+var t1_cmap_standard_class_rec = create_cmap_class_rec(0,t1_cmap_standard_init,t1_cmap_std_done,t1_cmap_std_char_index,t1_cmap_std_char_next,null,null,null,null,null);
+
+// expert
+function t1_cmap_expert_init(cmap)
+{
+    t1_cmap_std_init(cmap, 1);
+    return 0;
+}
+
+var t1_cmap_expert_class_rec = create_cmap_class_rec(0,t1_cmap_expert_init,t1_cmap_std_done,t1_cmap_std_char_index,t1_cmap_std_char_next,null,null,null,null,null);
+
+// custom
+function t1_cmap_custom_init(cmap)
+{
+    var face = __FT_CMapRec(cmap).charmap.face;
+    var encoding = face.type1.encoding;
+
+    cmap.first   = encoding.code_first;
+    cmap.count   = (encoding.code_last - cmap.first);
+
+    if (0 > cmap.count)
+        cmap.count = 0;
+
+    cmap.indices = encoding.char_index;
+
+    return 0;
+}
+
+function t1_cmap_custom_done(cmap)
+{
+    cmap.indices = null;
+    cmap.first   = 0;
+    cmap.count   = 0;
+}
+
+function t1_cmap_custom_char_index(cmap, char_code)
+{
+    if (char_code >= cmap.first && char_code < (cmap.first + cmap.count))
+        return cmap.indices[char_code];
+    return 0;
+}
+
+function t1_cmap_custom_char_next(cmap, _char_code)
+{
+    var result = 0;
+    var char_code = _char_code;
+    ++char_code;
+
+    if (char_code < cmap.first)
+        char_code = cmap.first;
+
+    var last = cmap.first + cmap.count;
+    for (; char_code < last; char_code++)
+    {
+        result = cmap.indices[char_code];
+        if (result != 0)
+            return {gindex:result,char_code:char_code};
+    }
+
+    return {gindex:result,char_code:0};
+}
+
+var t1_cmap_custom_class_rec = create_cmap_class_rec(0,t1_cmap_custom_init,t1_cmap_custom_done,t1_cmap_custom_char_index,t1_cmap_custom_char_next,null,null,null,null,null);
+
+// unicode
+function t1_get_glyph_name(face, idx)
+{
+    return face.type1.glyph_names[idx];
+}
+
+function t1_cmap_unicode_init(unicodes)
+{
+    var face = __FT_CMapRec(unicodes).charmap.face;
+    var memory  = face.memory;
+    var psnames = face.psnames;
+
+    return psnames.unicodes_init(memory, unicodes, face.type1.num_glyphs, t1_get_glyph_name, null, face);
+}
+
+function t1_cmap_unicode_done(unicodes)
+{
+    unicodes.maps = null;
+    unicodes.num_maps = 0;
+}
+
+function t1_cmap_unicode_char_index(unicodes, char_code)
+{
+    var face = __FT_CMapRec(unicodes).charmap.face;
+    var psnames = face.psnames;
+
+    return psnames.unicodes_char_index(unicodes, char_code);
+}
+
+function t1_cmap_unicode_char_next(unicodes, pchar_code)
+{
+    var face = __FT_CMapRec(unicodes).charmap.face;
+    var psnames = face.psnames;
+
+    return psnames.unicodes_char_next(unicodes, pchar_code);
+}
+
+var t1_cmap_unicode_class_rec = create_cmap_class_rec(0,t1_cmap_unicode_init,t1_cmap_unicode_done,t1_cmap_unicode_char_index,t1_cmap_unicode_char_next,null,null,null,null,null);
+
+/******************************************************************************/
+// psobj
+/******************************************************************************/
+
+function ps_table_new(table, count, memory)
+{
+    table.memory = memory;
+    table.elements = new Array(count);
+
+    for (var i = 0; i < count; i++)
+        table.elements[i] = new CPointer();
+
+    table.lengths = CreateIntArray(count);
+
+    table.max_elems = count;
+    table.init      = 0xDEADBEEF;
+    table.num_elems = 0;
+    table.block     = null;
+    table.capacity  = 0;
+    table.cursor    = 0;
+
+    table.funcs = ps_table_funcs;
+    return 0;
+}
+
+function shift_elements(table, old_base)
+{
+    var delta  = table.block.pos - old_base.pos;
+    var els = table.elements;
+
+    var limit = table.max_elems;
+    for (var i = 0; i < limit; i++)
+    {
+        if (null != els[i])
+        {
+            els[i].data[els[i].pos] += delta;
+        }
+    }
+}
+
+function reallocate_t1_table(table, new_size)
+{
+    var memory = table.memory;
+    var old_base = table.block;
+
+    table.block = memory.Alloc(new_size);
+    var dst = table.block.data;
+    if (null != old_base)
+    {
+        var src = old_base.data;
+        for (var i = 0; i < table.capacity; i++)
+        {
+            dst[i] = src[i];
+        }
+    }
+
+    var _els = table.elements;
+    var _elc = table.max_elems;
+    for (var j = 0; j < _elc; j++)
+        _els[j].data = dst;
+
+    old_base = null;
+    table.capacity = new_size;
+    return 0;
+}
+
+function ps_table_add(table, idx, object, length)
+{
+    if (idx < 0 || idx >= table.max_elems)
+        return FT_Common.FT_Err_Invalid_Argument;
+
+    if (length < 0)
+        return FT_Common.FT_Err_Invalid_Argument;
+
+    /*
+    table.elements[idx] = copy_pointer(object, length);
+    table.lengths[idx] = length;
+    table.cursor = idx + 1;
+    */
+
+    if (table.cursor + length > table.capacity)
+    {
+        var new_size = table.capacity;
+
+        while (new_size < (table.cursor + length))
+        {
+            /* increase size by 25% and round up to the nearest multiple
+             of 1024 */
+            new_size += (new_size >> 2) + 1;
+            new_size = parseInt((new_size + 1023) / 1024) * 1024;
+        }
+
+        reallocate_t1_table(table, new_size);
+    }
+
+    /* add the object to the base block and adjust offset */
+    table.elements[idx].pos = table.cursor;
+    table.lengths[idx] = length;
+
+    var dd = table.block.data;
+    var dp = table.cursor;
+    var sd = object.data;
+    var sp = object.pos;
+
+    for (var i = 0; i < length; i++)
+        dd[dp++] = sd[sp++];
+
+    table.cursor += length;
+
+    return 0;
+}
+
+function ps_table_done(table)
+{
+    if (null == table.block)
+        return 0;
+
+    reallocate_t1_table(table, table.cursor);
+    return 0;
+}
+
+function ps_table_release(table)
+{
+    if (table.init == 0xDEADBEEF)
+    {
+        table.block = null;
+        table.elements = null;
+        table.lengths = null;
+        table.init = 0;
+    }
+}
+
+function skip_comment(cur, limit)
+{
+    while (cur.pos < limit)
+    {
+        if (IS_PS_NEWLINE(cur.data[cur.pos]))
+            break;
+        cur.pos++;
+    }
+}
+
+function skip_spaces(cur, limit)
+{
+    while (cur.pos < limit)
+    {
+        if (!IS_PS_SPACE(cur.data[cur.pos]))
+        {
+            if (cur.data[cur.pos] == FT_Common.SYMBOL_CONST_MATH_3)
+            {
+                /* According to the PLRM, a comment is equal to a space. */
+                skip_comment(cur, limit);
+            }
+            else
+                break;
+        }
+        cur.pos++;
+    }
+}
+
+function skip_literal_string(cur, limit)
+{
+    var embed = 0;
+    var error = FT_Common.FT_Err_Invalid_File_Format;
+
+    while (cur.pos < limit)
+    {
+        var c = cur.data[cur.pos];
+        cur.pos++;
+
+        if (c == FT_Common.SYMBOL_CONST_SS)
+        {
+            /* Red Book 3rd ed., section `Literal Text Strings', p. 29:     */
+            /* A backslash can introduce three different types              */
+            /* of escape sequences:                                         */
+            /*   - a special escaped char like \r, \n, etc.                 */
+            /*   - a one-, two-, or three-digit octal number                */
+            /*   - none of the above in which case the backslash is ignored */
+
+            if (cur.pos == limit)
+                break;/* error (or to be ignored?) */
+
+            switch (cur.data[cur.pos])
+            {
+            /* skip `special' escape */
+            case FT_Common.SYMBOL_CONST_n:
+            case FT_Common.SYMBOL_CONST_r:
+            case FT_Common.SYMBOL_CONST_t:
+            case FT_Common.SYMBOL_CONST_b:
+            case FT_Common.SYMBOL_CONST_f:
+            case FT_Common.SYMBOL_CONST_SS:
+            case FT_Common.SYMBOL_CONST_LS1:
+            case FT_Common.SYMBOL_CONST_RS1:
+                cur.pos++;
+                break;
+
+            default:
+                /* skip octal escape or ignore backslash */
+                for (var i = 0; i < 3 && cur.pos < limit; i++)
+                {
+                    if (FT_Common.SYMBOL_CONST_0 > cur.data[cur.pos] || FT_Common.SYMBOL_CONST_7 < cur.data[cur.pos])
+                        break;
+
+                    cur.pos++;
+                }
+            }
+        }
+        else if (c == FT_Common.SYMBOL_CONST_LS1)
+            embed++;
+        else if (c == FT_Common.SYMBOL_CONST_RS1)
+        {
+            embed--;
+            if (embed == 0)
+            {
+                error = 0;
+                break;
+            }
+        }
+    }
+    return error;
+}
+
+function skip_string(cur, limit)
+{
+    while (cur.pos < limit)
+    {
+        /* All whitespace characters are ignored. */
+        skip_spaces(cur, limit);
+        if (cur.pos >= limit)
+            break;
+
+        if (!IS_PS_XDIGIT(cur.data[cur.pos]))
+            break;
+    }
+
+    if (cur.pos < limit && cur.data[cur.pos] != FT_Common.SYMBOL_CONST_MATH_2)
+    {
+        return FT_Common.FT_Err_Invalid_File_Format;
+    }
+    else
+        cur.pos++;
+
+    return 0;
+}
+
+function skip_procedure(cur, limit)
+{
+    var embed = 0;
+
+    var error = 0;
+    for (; cur.pos < limit && error == 0; cur.pos++)
+    {
+        switch (cur.data[cur.pos])
+        {
+        case FT_Common.SYMBOL_CONST_LS3:
+            ++embed;
+            break;
+
+        case FT_Common.SYMBOL_CONST_RS3:
+            --embed;
+            if (embed == 0)
+            {
+                cur.pos++;
+                return 0;
+            }
+            break;
+
+        case FT_Common.SYMBOL_CONST_LS1:
+            error = skip_literal_string(cur, limit);
+            break;
+
+        case FT_Common.SYMBOL_CONST_MATH_1:
+            error = skip_string(cur, limit);
+            break;
+
+        case FT_Common.SYMBOL_CONST_MATH_3:
+            skip_comment(cur, limit);
+            break;
+        }
+    }
+
+    if (embed != 0)
+        error = FT_Common.FT_Err_Invalid_File_Format;
+
+    return error;
+}
+
+function ps_parser_skip_PS_token(parser)
+{
+    /* Note: PostScript allows any non-delimiting, non-whitespace        */
+    /*       character in a name (PS Ref Manual, 3rd ed, p31).           */
+    /*       PostScript delimiters are (, ), <, >, [, ], {, }, /, and %. */
+
+    var cur = dublicate_pointer(parser.cursor);
+    var limit = parser.limit;
+    var error = FT_Common.FT_Err_Ok;
+
+    var cursor_pos = cur.pos;
+    skip_spaces(cur, limit);             /* this also skips comments */
+    if (cur.pos >= limit)
+    {
+        if (cur.pos == cursor_pos)
+        {
+            error = FT_Common.FT_Err_Invalid_File_Format;
+        }
+
+        parser.error  = error;
+        parser.cursor.pos = cur.pos;
+        return;
+    }
+
+    /* self-delimiting, single-character tokens */
+    if (cur.data[cur.pos] == FT_Common.SYMBOL_CONST_LS2 || cur.data[cur.pos] == FT_Common.SYMBOL_CONST_RS2)
+    {
+        cur.pos++;
+        if (cur.pos == cursor_pos)
+        {
+            error = FT_Common.FT_Err_Invalid_File_Format;
+        }
+
+        parser.error  = error;
+        parser.cursor.pos = cur.pos;
+        return;
+    }
+
+    /* skip balanced expressions (procedures and strings) */
+
+    if (cur.data[cur.pos] == FT_Common.SYMBOL_CONST_LS3)                              /* {...} */
+    {
+        error = skip_procedure(cur, limit);
+        if (cur.pos == cursor_pos)
+        {
+            error = FT_Common.FT_Err_Invalid_File_Format;
+        }
+
+        parser.error  = error;
+        parser.cursor.pos = cur.pos;
+        return;
+    }
+
+    if (cur.data[cur.pos] == FT_Common.SYMBOL_CONST_LS1)                              /* (...) */
+    {
+        error = skip_literal_string(cur, limit);
+        if (cur.pos == cursor_pos)
+        {
+            error = FT_Common.FT_Err_Invalid_File_Format;
+        }
+
+        parser.error  = error;
+        parser.cursor.pos = cur.pos;
+        return;
+    }
+
+    if (cur.data[cur.pos] == FT_Common.SYMBOL_CONST_MATH_1)                              /* <...> */
+    {
+        if (cur.pos + 1 < limit && cur.data[cur.pos + 1] == FT_Common.SYMBOL_CONST_MATH_1)   /* << */
+        {
+            cur.pos += 2;
+        }
+        else
+            error = skip_string(cur, limit);
+
+        if (cur.pos == cursor_pos)
+        {
+            error = FT_Common.FT_Err_Invalid_File_Format;
+        }
+
+        parser.error  = error;
+        parser.cursor.pos = cur.pos;
+        return;
+    }
+
+    if (cur.data[cur.pos] == FT_Common.SYMBOL_CONST_MATH_2)
+    {
+        cur.pos++;
+        if (cur.pos >= limit || cur.data[cur.pos] != FT_Common.SYMBOL_CONST_MATH_2)             /* >> */
+        {
+            error = FT_Common.FT_Err_Invalid_File_Format;
+
+            parser.error  = error;
+            parser.cursor.pos = cur.pos;
+            return;
+        }
+        cur.pos++;
+        if (cur.pos == cursor_pos)
+        {
+            error = FT_Common.FT_Err_Invalid_File_Format;
+        }
+
+        parser.error  = error;
+        parser.cursor.pos = cur.pos;
+        return;
+    }
+
+    if (cur.data[cur.pos] == FT_Common.SYMBOL_CONST_BS)
+        cur.pos++;
+
+    /* anything else */
+    while (cur.pos < limit)
+    {
+        /* *cur might be invalid (e.g., ')' or '}'), but this   */
+        /* is handled by the test `cur == parser->cursor' below */
+        if (IS_PS_DELIM(cur.data[cur.pos]))
+            break;
+
+        cur.pos++;
+    }
+
+    //exit
+    if (cur.pos == cursor_pos)
+    {
+        error = FT_Common.FT_Err_Invalid_File_Format;
+    }
+
+    parser.error  = error;
+    parser.cursor.pos = cur.pos;
+}
+
+function ps_parser_skip_spaces(parser)
+{
+    skip_spaces(parser.cursor, parser.limit);
+}
+
+function ps_parser_to_token(parser, token)
+{
+    var limit = parser.limit;
+    var embed = 0;
+
+    token.type  = FT_Common.T1_TOKEN_TYPE_NONE;
+    token.start = null;
+    token.limit = 0;
+
+    /* first of all, skip leading whitespace */
+    ps_parser_skip_spaces(parser);
+    var cur = dublicate_pointer(parser.cursor);
+
+    if (cur.pos >= limit)
+        return;
+
+    switch (cur.data[cur.pos])
+    {
+        /************* check for literal string *****************/
+    case FT_Common.SYMBOL_CONST_LS1:
+        token.type  = FT_Common.T1_TOKEN_TYPE_STRING;
+        token.start = dublicate_pointer(cur);
+
+        if (skip_literal_string(cur, limit) == 0)
+            token.limit = cur.pos;
+        break;
+
+        /************* check for programs/array *****************/
+    case FT_Common.SYMBOL_CONST_LS3:
+        token.type  = FT_Common.T1_TOKEN_TYPE_ARRAY;
+        token.start = dublicate_pointer(cur);
+
+        if (skip_procedure(cur, limit) == 0)
+            token.limit = cur.pos;
+        break;
+
+        /************* check for table/array ********************/
+        /* XXX: in theory we should also look for "<<"          */
+        /*      since this is semantically equivalent to "[";   */
+        /*      in practice it doesn't matter (?)               */
+    case FT_Common.SYMBOL_CONST_LS2:
+        token.type  = FT_Common.T1_TOKEN_TYPE_ARRAY;
+        embed        = 1;
+        token.start  = dublicate_pointer(cur);
+        cur.pos++;
+
+        /* we need this to catch `[ ]' */
+        parser.cursor.pos = cur.pos;
+        ps_parser_skip_spaces(parser);
+        cur.pos = parser.cursor.pos;
+
+        while (cur.pos < limit && parser.error == 0)
+        {
+            /* XXX: this is wrong because it does not      */
+            /*      skip comments, procedures, and strings */
+            if (cur.data[cur.pos] == FT_Common.SYMBOL_CONST_LS2)
+                embed++;
+            else if (cur.data[cur.pos] == FT_Common.SYMBOL_CONST_RS2)
+            {
+                embed--;
+                if ( embed <= 0 )
+                {
+                    cur.pos++;
+                    token.limit = cur.pos;
+                    break;
+                }
+            }
+
+            parser.cursor.pos = cur.pos;
+            ps_parser_skip_PS_token(parser);
+            /* we need this to catch `[XXX ]' */
+            ps_parser_skip_spaces(parser);
+            cur.pos = parser.cursor.pos;
+        }
+        break;
+
+        /* ************ otherwise, it is any token **************/
+    default:
+        token.start = dublicate_pointer(cur);
+        token.type  = ((cur.data[cur.pos] == FT_Common.SYMBOL_CONST_BS) ? FT_Common.T1_TOKEN_TYPE_KEY : FT_Common.T1_TOKEN_TYPE_ANY);
+        ps_parser_skip_PS_token(parser);
+        cur.pos = parser.cursor.pos;
+        if (!parser.error)
+            token.limit = cur.pos;
+    }
+
+    if (token.limit == 0)
+    {
+        token.start = null;
+        token.type  = FT_Common.T1_TOKEN_TYPE_NONE;
+    }
+
+    parser.cursor.pos = cur.pos;
+}
+
+function ps_parser_to_token_array(parser, tokens, max_tokens)
+{
+    var master = new T1_TokenRec();
+    var pnum_tokens = -1;
+    /* this also handles leading whitespace */
+    ps_parser_to_token(parser, master);
+
+    if (master.type == FT_Common.T1_TOKEN_TYPE_ARRAY)
+    {
+        var old_cursor = parser.cursor.pos;
+        var old_limit  = parser.limit;
+        var cur        = 0;
+
+        /* don't include outermost delimiters */
+        parser.cursor = dublicate_pointer(master.start);
+        parser.cursor.pos += 1;
+        parser.limit  = master.limit - 1;
+
+        while (parser.cursor.pos < parser.limit)
+        {
+            var token = new T1_TokenRec();
+            ps_parser_to_token(parser, token);
+            if (token.type == 0)
+                break;
+
+            if (tokens != null && cur < max_tokens)
+            {
+                var _cur = tokens[cur];
+                _cur.start = dublicate_pointer(token.start);
+                _cur.limit = token.limit;
+                _cur.type = token.type;
+            }
+
+            cur++;
+        }
+
+        pnum_tokens = cur;
+
+        parser.cursor.pos = old_cursor;
+        parser.limit  = old_limit;
+    }
+
+    return pnum_tokens;
+}
+
+function ps_tocoordarray(cur, limit, max_coords, coords)
+{
+    var count = 0;
+    if (cur.pos >= limit)
+        return count;
+
+    /* check for the beginning of an array; otherwise, only one number */
+    /* will be read                                                    */
+    var c = cur.data[cur.pos];
+    var ender = 0;
+
+    if (c == FT_Common.SYMBOL_CONST_LS2)
+        ender = FT_Common.SYMBOL_CONST_RS2;
+    else if (c == FT_Common.SYMBOL_CONST_LS3)
+        ender = FT_Common.SYMBOL_CONST_RS3;
+
+    if (ender != 0)
+        cur.pos++;
+
+    /* now, read the coordinates */
+    while ( cur < limit )
+    {
+        /* skip whitespace in front of data */
+        skip_spaces(cur, limit);
+        if (cur.pos >= limit)
+            return count;
+
+        if (cur.data[cur.pos] == ender)
+        {
+            cur.pos++;
+            break;
+        }
+
+        var old_cur = cur.pos;
+
+        if ( coords != NULL && count >= max_coords )
+            break;
+
+        /* call PS_Conv_ToFixed() even if coords == NULL */
+        /* to properly parse number at `cur'             */
+        var dummy = PS_Conv_ToFixed(cur, limit, 0) >> 16;
+        if (null != coords)
+            coords[count] = dummy;
+
+        if (old_cur == cur.pos)
+        {
+            count = -1;
+            return count;
+        }
+        else
+            count++;
+
+        if (ender == 0)
+            break;
+    }
+
+    return count;
+}
+
+function ps_tofixedarray(cur, limit, max_values, values, power_ten)
+{
+    var count = 0;
+    if (cur.pos >= limit)
+        return count;
+
+    /* Check for the beginning of an array.  Otherwise, only one number */
+    /* will be read.                                                    */
+    var c = cur.data[cur.pos];
+    var ender = 0;
+
+    if (c == FT_Common.SYMBOL_CONST_LS2)
+        ender = FT_Common.SYMBOL_CONST_RS2;
+    else if (c == FT_Common.SYMBOL_CONST_LS3)
+        ender = FT_Common.SYMBOL_CONST_RS3;
+
+    if (ender != 0)
+        cur.pos++;
+
+    /* now, read the values */
+    while (cur.pos < limit)
+    {
+        /* skip whitespace in front of data */
+        skip_spaces(cur, limit);
+        if (cur.pos >= limit)
+            return count;
+
+        if (cur.data[cur.pos] == ender)
+        {
+            cur.pos++;
+            break;
+        }
+
+        var old_cur = cur.pos;
+        if (values != null && count >= max_values)
+            break;
+
+        /* call PS_Conv_ToFixed() even if coords == NULL */
+        /* to properly parse number at `cur'             */
+        var dummy = PS_Conv_ToFixed(cur, limit, power_ten);
+        if (null != values)
+            values[count] = dummy;
+
+        if (old_cur == cur.pos)
+        {
+            count = -1;
+            return count;
+        }
+        else
+            count++;
+
+        if (ender == 0)
+            break;
+    }
+
+    return count;
+}
+
+function ps_tobool(cur, limit)
+{
+    var result = 0;
+    var data = cur.data;
+    var pos = cur.pos;
+
+    /* return 1 if we find `true', 0 otherwise */
+    if (cur.pos + 3 < limit &&
+        data[pos] == FT_Common.SYMBOL_CONST_t &&
+        data[pos + 1] == FT_Common.SYMBOL_CONST_r &&
+        data[pos + 2] == FT_Common.SYMBOL_CONST_u &&
+        data[pos + 3] == FT_Common.SYMBOL_CONST_e)
+    {
+        result = 1;
+        cur.pos += 5;
+    }
+    else if (cur.pos + 4 < limit &&
+        data[pos] == FT_Common.SYMBOL_CONST_f &&
+        data[pos + 1] == FT_Common.SYMBOL_CONST_a &&
+        data[pos + 2] == FT_Common.SYMBOL_CONST_l &&
+        data[pos + 3] == FT_Common.SYMBOL_CONST_s &&
+        data[pos + 4] == FT_Common.SYMBOL_CONST_e)
+    {
+        result = 0;
+        cur.pos   += 6;
+    }
+
+    return result;
+}
+
+function ps_parser_load_field(parser, field, objects, max_objects, pflags)
+{
+    var token = new T1_TokenRec();
+    /* this also skips leading whitespace */
+    ps_parser_to_token(parser, token);
+    if (token.type == 0)
+        return FT_Common.FT_Err_Invalid_File_Format;
+
+    var count = 1;
+    var idx   = 0;
+    var cur   = dublicate_pointer(token.start);
+    var limit = token.limit;
+
+    /* we must detect arrays in /FontBBox */
+    if (field.type == FT_Common.T1_FIELD_TYPE_BBOX)
+    {
+        var token2 = new T1_TokenRec();
+        var old_cur   = dublicate_pointer(parser.cursor);
+        var old_limit = parser.limit;
+
+        /* don't include delimiters */
+        parser.cursor = dublicate_pointer(token.start);
+        parser.cursor.pos += 1;
+        parser.limit  = token.limit - 1;
+
+        ps_parser_to_token(parser, token2);
+        parser.cursor = dublicate_pointer(old_cur);
+        parser.limit  = old_limit;
+
+        if (token2.type == FT_Common.T1_TOKEN_TYPE_ARRAY)
+        {
+            /* if this is an array and we have no blend, an error occurs */
+            if (max_objects == 0)
+                return FT_Common.FT_Err_Invalid_File_Format;
+
+            count = max_objects;
+            idx   = 1;
+
+            /* don't include delimiters */
+            cur.pos++;
+            limit--;
+        }
+    }
+    else if (token.type == FT_Common.T1_TOKEN_TYPE_ARRAY)
+    {
+        /* if this is an array and we have no blend, an error occurs */
+        if (max_objects == 0)
+            return FT_Common.FT_Err_Invalid_File_Format;
+
+        count = max_objects;
+        idx   = 1;
+
+        /* don't include delimiters */
+        cur.pos++;
+        limit--;
+    }
+
+    for (; count > 0; count--, idx++)
+    {
+        var __obj = objects[idx];
+        var val;
+        skip_spaces(cur, limit);
+
+        switch (field.type)
+        {
+            case FT_Common.T1_FIELD_TYPE_BOOL:
+                val = ps_tobool(cur, limit);
+                fire_t1_field(__obj, val, field);
+                break;
+
+            case FT_Common.T1_FIELD_TYPE_FIXED:
+                val = PS_Conv_ToFixed(cur, limit, 0);
+                fire_t1_field(__obj, val, field);
+                break;
+
+            case FT_Common.T1_FIELD_TYPE_FIXED_1000:
+                val = PS_Conv_ToFixed(cur, limit, 3);
+                fire_t1_field(__obj, val, field);
+                break;
+
+            case FT_Common.T1_FIELD_TYPE_INTEGER:
+                val = PS_Conv_ToInt(cur, limit);
+                fire_t1_field(__obj, val, field);
+                break;
+
+            case FT_Common.T1_FIELD_TYPE_STRING:
+            case FT_Common.T1_FIELD_TYPE_KEY:
+                var len = (limit - cur.pos);
+
+                if (cur.pos >= limit)
+                    break;
+
+                /* we allow both a string or a name   */
+                /* for cases like /FontName (foo) def */
+                if (token.type == FT_Common.T1_TOKEN_TYPE_KEY)
+                {
+                    /* don't include leading `/' */
+                    len--;
+                    cur.pos++;
+                }
+                else if (token.type == FT_Common.T1_TOKEN_TYPE_STRING)
+                {
+                    /* don't include delimiting parentheses    */
+                    /* XXX we don't handle <<...>> here        */
+                    /* XXX should we convert octal escapes?    */
+                    /*     if so, what encoding should we use? */
+                    cur.pos++;
+                    len -= 2;
+                }
+                else
+                {
+                    return FT_Common.FT_Err_Invalid_File_Format;
+                }
+
+                /* for this to work (FT_String**)q must have been */
+                /* initialized to NULL                            */
+                var _s = "";
+                for (var i = 0; i < len; i++)
+                    _s += String.fromCharCode(cur.data[cur.pos + i]);
+
+                fire_t1_field(__obj, _s, field);
+                break;
+
+            case FT_Common.T1_FIELD_TYPE_BBOX:
+                var temp = new Array(4);
+                temp[0] = 0;
+                temp[1] = 0;
+                temp[2] = 0;
+                temp[3] = 0;
+
+                var result = ps_tofixedarray(cur, limit, 4, temp, 0);
+
+                if ( result < 0 )
+                {
+                    return FT_Common.FT_Err_Invalid_File_Format;
+                }
+
+                __obj.xMin = FT_RoundFix(temp[0]);
+                __obj.yMin = FT_RoundFix(temp[1]);
+                __obj.xMax = FT_RoundFix(temp[2]);
+                __obj.yMax = FT_RoundFix(temp[3]);
+
+                break;
+
+            default:
+                /* an error occurred */
+                return FT_Common.FT_Err_Invalid_File_Format;
+        }
+    }
+
+    return 0;
+}
+
+function ps_parser_load_field_table(parser, field, objects, max_objects, pflags)
+{
+    var elements = new Array(FT_Common.T1_MAX_TABLE_ELEMENTS);
+    for (var i = 0; i < FT_Common.T1_MAX_TABLE_ELEMENTS; i++)
+        elements[i] = new T1_TokenRec();
+
+    var fieldrec = create_dublicate_t1_field(field);
+
+    fieldrec.type = FT_Common.T1_FIELD_TYPE_INTEGER;
+    if (field.type == FT_Common.T1_FIELD_TYPE_FIXED_ARRAY || field.type == FT_Common.T1_FIELD_TYPE_BBOX)
+        fieldrec.type = FT_Common.T1_FIELD_TYPE_FIXED;
+
+    var num_elements = ps_parser_to_token_array(parser, elements, FT_Common.T1_MAX_TABLE_ELEMENTS);
+    if (num_elements < 0)
+        return FT_Common.FT_Err_Ignore;
+
+    if (num_elements > field.array_max)
+        num_elements = field.array_max;
+
+    var old_cursor = dublicate_pointer(parser.cursor);
+    var old_limit  = parser.limit;
+
+    /* we store the elements count if necessary;           */
+    /* we further assume that `count_offset' can't be zero */
+    if (field.type != FT_Common.T1_FIELD_TYPE_BBOX && field.set_field_count != undefined)
+    {
+        fire_t1_field_count(objects[0], num_elements, field);
+    }
+
+    /* we now load each element, adjusting the field.offset on each one */
+    var token = 0;
+    for ( ; num_elements > 0; num_elements--, token++)
+    {
+        fieldrec.offset = token;
+        parser.cursor = dublicate_pointer(elements[token].start);
+        parser.limit  = elements[token].limit;
+        ps_parser_load_field(parser, fieldrec, objects, max_objects, 0);
+    }
+
+    parser.cursor = dublicate_pointer(old_cursor);
+    parser.limit  = old_limit;
+
+    return 0;
+}
+
+function ps_parser_to_int(parser)
+{
+    ps_parser_skip_spaces(parser);
+    return PS_Conv_ToInt(parser.cursor, parser.limit);
+}
+
+function ps_parser_to_bytes(parser, bytes, max_bytes, delimiters)
+{
+    ps_parser_skip_spaces(parser);
+    var cur = dublicate_pointer(parser.cursor);
+    
+    if (cur.pos >= parser.limit)
+        return 0;
+
+    if (delimiters)
+    {
+        if (cur.data[cur.pos] != FT_Common.SYMBOL_CONST_MATH_1)
+        {
+            return {err: FT_Common.FT_Err_Invalid_File_Format, num_bytes: 0};
+        }
+
+        cur.pos++;
+    }
+
+    var num_bytes = PS_Conv_ASCIIHexDecode(cur, parser.limit, bytes, max_bytes);
+
+    if (delimiters)
+    {
+        if (cur.pos < parser.limit && cur.data[cur.pos] != FT_Common.SYMBOL_CONST_MATH_2)
+        {
+            return {err: FT_Common.FT_Err_Invalid_File_Format, num_bytes: num_bytes};
+        }
+
+        cur.pos++;
+    }
+
+    parser.cursor.pos = cur.pos;
+    return {err: FT_Common.FT_Err_Ok, num_bytes: num_bytes};
+}
+
+function ps_parser_to_fixed(parser, power_ten)
+{
+    ps_parser_skip_spaces(parser);
+    return PS_Conv_ToFixed(parser.cursor, parser.limit, power_ten);
+}
+
+function ps_parser_to_coord_array(parser, max_coords, coords)
+{
+    ps_parser_skip_spaces(parser);
+    return PS_Conv_ToFixed(parser.cursor, parser.limit, max_coords, coords);
+}
+
+function ps_parser_to_fixed_array(parser, max_values, values, power_ten)
+{
+    ps_parser_skip_spaces(parser);
+    return ps_tofixedarray(parser.cursor, parser.limit, max_values, values, power_ten);
+}
+
+function ps_parser_init(parser, base, limit, memory)
+{
+    parser.error  = 0;
+    parser.base   = dublicate_pointer(base);
+    parser.limit  = limit;
+    parser.cursor = dublicate_pointer(base);
+    parser.memory = memory;
+    parser.funcs  = ps_parser_funcs;
+}
+
+function ps_parser_done(parser)
+{
+}
+
+function t1_builder_init(builder, face, size, _glyph, hinting)
+{
+    var glyph = (null == _glyph) ? null : _glyph.root;
+
+    builder.parse_state = FT_Common.T1_Parse_Start;
+    builder.load_points = 1;
+
+    builder.face = face;
+    builder.glyph = glyph;
+    builder.memory = face.memory;
+
+    if (glyph != null)
+    {
+        var loader = glyph.internal.loader;
+
+        builder.loader  = loader;
+        builder.base    = loader.base.outline;
+        builder.current = loader.current.outline;
+        FT_GlyphLoader_Rewind(loader);
+
+        builder.hints_globals = size.internal;
+        builder.hints_funcs   = null;
+
+        if (hinting)
+            builder.hints_funcs = glyph.internal.glyph_hints;
+    }
+
+    builder.pos_x = 0;
+    builder.pos_y = 0;
+
+    builder.left_bearing.x = 0;
+    builder.left_bearing.y = 0;
+    builder.advance.x      = 0;
+    builder.advance.y      = 0;
+
+    builder.funcs = t1_builder_funcs;
+}
+
+function t1_builder_done(builder)
+{
+    var glyph = builder.glyph;
+
+    if (glyph != null)
+        EquatingOutline(glyph.outline, builder.base);
+}
+
+function t1_builder_check_points(builder, count)
+{
+    return FT_GLYPHLOADER_CHECK_POINTS(builder.loader, count, 0);
+}
+
+function t1_builder_add_point(builder, x, y, flag)
+{
+    var outline = builder.current;
+    var base = builder.base;
+
+    if (builder.load_points)
+    {
+        var point = base.points[outline.points + outline.n_points];
+        point.x = (FT_RoundFix(x) >> 16);
+        point.y = (FT_RoundFix(y) >> 16);
+
+        base.tags[outline.tags + outline.n_points] = flag ? FT_Common.FT_CURVE_TAG_ON : FT_Common.FT_CURVE_TAG_CUBIC;
+    }
+    outline.n_points++;
+}
+
+function t1_builder_add_point1(builder, x, y)
+{
+    var error = t1_builder_check_points(builder, 1);
+    if ( !error )
+        t1_builder_add_point(builder, x, y, 1);
+
+    return error;
+}
+
+function t1_builder_add_contour(builder)
+{
+    var outline = builder.current;
+
+    /* this might happen in invalid fonts */
+    if (outline == null)
+    {
+        return FT_Common.FT_Err_Invalid_File_Format;
+    }
+
+    if (builder.load_points == 0)
+    {
+        outline.n_contours++;
+        return FT_Common.FT_Err_Ok;
+    }
+
+    var error = FT_GLYPHLOADER_CHECK_POINTS(builder.loader, 0, 1);
+    if (error == 0)
+    {
+        if (outline.n_contours > 0)
+            builder.base.contours[outline.contours + outline.n_contours - 1] = (outline.n_points - 1);
+
+        outline.n_contours++;
+    }
+
+    return error;
+}
+
+function t1_builder_start_point(builder, x, y)
+{
+    var error = FT_Common.FT_Err_Invalid_File_Format;
+
+    /* test whether we are building a new contour */
+    if (builder.parse_state == FT_Common.T1_Parse_Have_Path)
+        error = FT_Common.FT_Err_Ok;
+    else
+    {
+        builder.parse_state = FT_Common.T1_Parse_Have_Path;
+        error = t1_builder_add_contour(builder);
+        if ( !error )
+            error = t1_builder_add_point1(builder, x, y);
+    }
+
+    return error;
+}
+
+function t1_builder_close_contour(builder)
+{
+    var outline = builder.current;
+
+    if (outline == null)
+        return;
+
+    var base = builder.base;
+    var first = (outline.n_contours <= 1) ? 0 : base.contours[outline.contours + outline.n_contours - 2] + 1;
+
+    /* We must not include the last point in the path if it */
+    /* is located on the first point.                       */
+    if (outline.n_points > 1)
+    {
+        var p1 = base.points[outline.points + first];
+        var p2 = base.points[outline.points + outline.n_points - 1];
+
+        var control = base.tags[outline.tags + outline.n_points - 1];
+
+        /* `delete' last point only if it coincides with the first */
+        /* point and it is not a control point (which can happen). */
+        if (p1.x == p2.x && p1.y == p2.y)
+            if (control == FT_Common.FT_CURVE_TAG_ON)
+                outline.n_points--;
+    }
+
+    if (outline.n_contours > 0)
+    {
+        /* Don't add contours only consisting of one point, i.e.,  */
+        /* check whether the first and the last point is the same. */
+        if (first == outline.n_points - 1)
+        {
+            outline.n_contours--;
+            outline.n_points--;
+        }
+        else
+            base.contours[outline.contours + outline.n_contours - 1] = (outline.n_points - 1);
+    }
+}
+
+function t1_decrypt(buffer, length, seed)
+{
+    var mem = dublicate_pointer(buffer);
+    PS_Conv_EexecDecode(mem, mem.pos + length, mem, length, seed);
+}
+
+/******************************************************************************/
+// t1decode
+/******************************************************************************/
+
+var t1_args_count = [
+    0, /* none */
+    0, /* endchar */
+    2, /* hsbw */
+    5, /* seac */
+    4, /* sbw */
+    0, /* closepath */
+    1, /* hlineto */
+    1, /* hmoveto */
+    4, /* hvcurveto */
+    2, /* rlineto */
+    2, /* rmoveto */
+    6, /* rrcurveto */
+    4, /* vhcurveto */
+    1, /* vlineto */
+    1, /* vmoveto */
+    0, /* dotsection */
+    2, /* hstem */
+    6, /* hstem3 */
+    2, /* vstem */
+    6, /* vstem3 */
+    2, /* div */
+    -1, /* callothersubr */
+    1, /* callsubr */
+    0, /* pop */
+    0, /* return */
+    2, /* setcurrentpoint */
+    2  /* opcode 15 (undocumented and obsolete) */
+];
+
+function t1_lookup_glyph_by_stdcharcode(decoder, charcode)
+{
+    /* check range of standard char code */
+    if (charcode < 0 || charcode > 255)
+        return -1;
+
+    var glyph_name = decoder.psnames.adobe_std_strings(decoder.psnames.adobe_std_encoding[charcode]);
+
+    for (var n = 0; n < decoder.num_glyphs; n++)
+    {
+        var name = decoder.glyph_names[n];
+
+        if (name != null && name == glyph_name)
+            return n;
+    }
+
+    return -1;
+}
+
+function t1operator_seac(decoder, asb, adx, ady, bchar, achar)
+{
+    var bchar_index, achar_index;
+
+    if (decoder.seac)
+        return FT_Common.FT_Err_Syntax_Error;
+
+    var error = 0;
+    var face = decoder.builder.face;
+
+    /* seac weirdness */
+    adx += decoder.builder.left_bearing.x;
+
+    /* `glyph_names' is set to 0 for CID fonts which do not */
+    /* include an encoding.  How can we deal with these?    */
+    //#ifdef FT_CONFIG_OPTION_INCREMENTAL
+    if (decoder.glyph_names == null && null == face.internal.incremental_interface)
+        return FT_Common.FT_Err_Syntax_Error;
+
+    //#ifdef FT_CONFIG_OPTION_INCREMENTAL
+    if (face.internal.incremental_interface != null)
+    {
+        /* the caller must handle the font encoding also */
+        bchar_index = bchar;
+        achar_index = achar;
+    }
+    else// #endif
+    {
+        bchar_index = t1_lookup_glyph_by_stdcharcode(decoder, bchar);
+        achar_index = t1_lookup_glyph_by_stdcharcode(decoder, achar);
+    }
+
+    if (bchar_index < 0 || achar_index < 0)
+        return FT_Common.FT_Err_Syntax_Error;
+
+    /* if we are trying to load a composite glyph, do not load the */
+    /* accent character and return the array of subglyphs.         */
+    if (decoder.builder.no_recurse)
+    {
+        var glyph = decoder.builder.glyph;
+        var loader = glyph.internal.loader;
+
+        /* reallocate subglyph array if necessary */
+        error = FT_GlyphLoader_CheckSubGlyphs(loader, 2);
+        if (error != 0)
+            return error;
+
+        var subg = loader.current.subglyphs[0];
+
+        /* subglyph 0 = base character */
+        subg.index = bchar_index;
+        subg.flags = FT_Common.FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES | FT_Common.FT_SUBGLYPH_FLAG_USE_MY_METRICS;
+        subg.arg1  = 0;
+        subg.arg2  = 0;
+
+        subg = loader.current.subglyphs[1];
+
+        /* subglyph 1 = accent character */
+        subg.index = achar_index;
+        subg.flags = FT_Common.FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES;
+        subg.arg1  = FT_RoundFix(adx - asb) >> 16;
+        subg.arg2  = FT_RoundFix(ady) >> 16;
+
+        /* set up remaining glyph fields */
+        glyph.num_subglyphs = 2;
+        glyph.subglyphs     = loader.base.subglyphs;
+        glyph.format        = FT_Common.FT_GLYPH_FORMAT_COMPOSITE;
+
+        loader.current.num_subglyphs = 2;
+        return error;
+    }
+
+    /* First load `bchar' in builder */
+    /* now load the unscaled outline */
+
+    FT_GlyphLoader_Prepare(decoder.builder.loader);  /* prepare loader */
+
+    /* the seac operator must not be nested */
+    decoder.seac = 1;
+    error = t1_decoder_parse_glyph(decoder, bchar_index);
+    decoder.seac = 0;
+    if (error != 0)
+        return error;
+
+    /* save the left bearing and width of the base character */
+    /* as they will be erased by the next load.              */
+
+    var left_bearing = dublicate_vector(decoder.builder.left_bearing);
+    var advance      = dublicate_vector(decoder.builder.advance);
+
+    decoder.builder.left_bearing.x = 0;
+    decoder.builder.left_bearing.y = 0;
+
+    decoder.builder.pos_x = adx - asb;
+    decoder.builder.pos_y = ady;
+
+    /* Now load `achar' on top of */
+    /* the base outline           */
+
+    /* the seac operator must not be nested */
+    decoder.seac = 1;
+    error = t1_decoder_parse_glyph(decoder, achar_index);
+    decoder.seac = 0;
+    if (error != 0)
+        return error;
+
+    /* restore the left side bearing and   */
+    /* advance width of the base character */
+
+    decoder.builder.left_bearing = left_bearing;
+    decoder.builder.advance      = advance;
+
+    decoder.builder.pos_x = 0;
+    decoder.builder.pos_y = 0;
+
+    return error;
+}
+
+function t1_decoder_parse_charstrings(decoder, charstring_base, charstring_len)
+{
+    var builder = decoder.builder;
+    var x, y, orig_x, orig_y;
+    var known_othersubr_result_cnt   = 0;
+    var unknown_othersubr_result_cnt = 0;
+    var large_int = 0;
+
+    /* compute random seed from stack address of parameter */
+    var seed = parseInt(Math.random() * 0xFFFF);
+    if (seed == 0)
+        seed = 0x7384;
+
+    /* First of all, initialize the decoder */
+    decoder.top  = 0;
+    decoder.zone = 0;
+    var zone  = 0;
+    var zones = decoder.zones;
+
+    builder.parse_state = FT_Common.T1_Parse_Start;
+
+    var hinter = builder.hints_funcs;
+
+    /* a font that reads BuildCharArray without setting */
+    /* its values first is buggy, but ...               */
+    if (decoder.buildchar != null && decoder.len_buildchar > 0)
+    {
+        for (var i = 0; i < decoder.len_buildchar; i++)
+        {
+            decoder.buildchar[i] = 0;
+        }
+    }
+
+    zones[zone].base = dublicate_pointer(charstring_base);
+    zones[zone].limit  = charstring_base.pos + charstring_len;
+    var limit = zones[zone].limit;
+
+    zones[zone].cursor = 0;
+    var ip = dublicate_pointer(zones[zone].base);
+
+    var error = 0;
+
+    x = orig_x = builder.pos_x;
+    y = orig_y = builder.pos_y;
+
+    /* begin hints recording session, if any */
+    if (hinter != null)
+        hinter.open(hinter.hints);
+
+    large_int = 0;
+
+    /* now, execute loop */
+    while (ip.pos < limit)
+    {
+        var tops = decoder.stack;
+        var top = decoder.top;
+        var op = FT_Common.op_none;
+        var value = 0;
+
+        /*********************************************************************/
+        /*                                                                   */
+        /* Decode operator or operand                                        */
+        /*                                                                   */
+        /*                                                                   */
+        /* first of all, decompress operator or value */
+        var _oper = ip.data[ip.pos];
+        ip.pos++;
+        switch (_oper)
+        {
+        case 1:
+            op = FT_Common.op_hstem;
+            break;
+
+        case 3:
+            op = FT_Common.op_vstem;
+            break;
+        case 4:
+            op = FT_Common.op_vmoveto;
+            break;
+        case 5:
+            op = FT_Common.op_rlineto;
+            break;
+        case 6:
+            op = FT_Common.op_hlineto;
+            break;
+        case 7:
+            op = FT_Common.op_vlineto;
+            break;
+        case 8:
+            op = FT_Common.op_rrcurveto;
+            break;
+        case 9:
+            op = FT_Common.op_closepath;
+            break;
+        case 10:
+            op = FT_Common.op_callsubr;
+            break;
+        case 11:
+            op = FT_Common.op_return;
+            break;
+
+        case 13:
+            op = FT_Common.op_hsbw;
+            break;
+        case 14:
+            op = FT_Common.op_endchar;
+            break;
+
+        case 15:          /* undocumented, obsolete operator */
+            op = FT_Common.op_unknown15;
+            break;
+
+        case 21:
+            op = FT_Common.op_rmoveto;
+            break;
+        case 22:
+            op = FT_Common.op_hmoveto;
+            break;
+
+        case 30:
+            op = FT_Common.op_vhcurveto;
+            break;
+        case 31:
+            op = FT_Common.op_hvcurveto;
+            break;
+
+        case 12:
+            if (ip.pos > limit)
+                return FT_Common.FT_Err_Syntax_Error;
+
+            var _oper2 = ip.data[ip.pos];
+            ip.pos++;
+            switch (_oper2)
+            {
+            case 0:
+                op = FT_Common.op_dotsection;
+                break;
+            case 1:
+                op = FT_Common.op_vstem3;
+                break;
+            case 2:
+                op = FT_Common.op_hstem3;
+                break;
+            case 6:
+                op = FT_Common.op_seac;
+                break;
+            case 7:
+                op = FT_Common.op_sbw;
+                break;
+            case 12:
+                op = FT_Common.op_div;
+                break;
+            case 16:
+                op = FT_Common.op_callothersubr;
+                break;
+            case 17:
+                op = FT_Common.op_pop;
+                break;
+            case 33:
+                op = FT_Common.op_setcurrentpoint;
+                break;
+
+            default:
+                return FT_Common.FT_Err_Syntax_Error;
+            }
+            break;
+
+        case 255:    /* four bytes integer */
+            if (ip.pos + 4 > limit)
+            {
+                return FT_Common.FT_Err_Syntax_Error;
+            }
+
+            value = ((ip.data[ip.pos] << 24) | (ip.data[ip.pos + 1] << 16) | (ip.data[ip.pos + 2] << 8) |  (ip.data[ip.pos + 3]));
+            ip.pos += 4;
+
+            /* According to the specification, values > 32000 or < -32000 must */
+            /* be followed by a `div' operator to make the result be in the    */
+            /* range [-32000;32000].  We expect that the second argument of    */
+            /* `div' is not a large number.  Additionally, we don't handle     */
+            /* stuff like `<large1> <large2> <num> div <num> div' or           */
+            /* <large1> <large2> <num> div div'.  This is probably not allowed */
+            /* anyway.                                                         */
+            if (value > 32000 || value < -32000)
+            {
+                if (large_int)
+                {
+                }
+                else
+                    large_int = 1;
+            }
+            else
+            {
+                if (!large_int)
+                    value <<= 16;
+            }
+
+            break;
+
+        default:
+            if (ip.data[ip.pos - 1] >= 32)
+            {
+                if (ip.data[ip.pos - 1] < 247)
+                    value = ip.data[ip.pos - 1] - 139;
+                else
+                {
+                    ip.pos++;
+                    if (ip.pos > limit)
+                    {
+                        return FT_Common.FT_Err_Syntax_Error;
+                    }
+
+                    if (ip.data[ip.pos - 2] < 251)
+                        value =  ((ip.data[ip.pos - 2] - 247) << 8) + ip.data[ip.pos - 1] + 108;
+                    else
+                        value = -(((ip.data[ip.pos - 2] - 251) << 8) + ip.data[ip.pos - 1] + 108);
+                }
+
+                if (!large_int)
+                    value <<= 16;
+            }
+            else
+            {
+                return FT_Common.FT_Err_Syntax_Error;
+            }
+        }
+
+        if (unknown_othersubr_result_cnt > 0)
+        {
+            switch (op)
+            {
+                case FT_Common.op_callsubr:
+                case FT_Common.op_return:
+                case FT_Common.op_none:
+                case FT_Common.op_pop:
+                    break;
+
+                default:
+                    /* all operands have been transferred by previous pops */
+                    unknown_othersubr_result_cnt = 0;
+                    break;
+            }
+        }
+
+        if ( large_int && !(op == FT_Common.op_none || op == FT_Common.op_div))
+        {
+            large_int = 0;
+        }
+
+        /*********************************************************************/
+        /*                                                                   */
+        /*  Push value on stack, or process operator                         */
+        /*                                                                   */
+        /*                                                                   */
+        if (op == FT_Common.op_none)
+        {
+            if (top >= FT_Common.T1_MAX_CHARSTRINGS_OPERANDS)
+            {
+                return FT_Common.FT_Err_Syntax_Error;
+            }
+
+            tops[top] = value;
+            top++;
+            decoder.top = top;
+        }
+        else if ( op == FT_Common.op_callothersubr )  /* callothersubr */
+        {
+            if (top < 2)
+                return FT_Common.FT_Err_Stack_Overflow;
+
+            top -= 2;
+
+            var subr_no = (tops[top + 1] >> 16) & 0xFFFF;
+            var arg_cnt = (tops[top] >> 16) & 0xFFFF;
+
+            /***********************************************************/
+            /*                                                         */
+            /* remove all operands to callothersubr from the stack     */
+            /*                                                         */
+            /* for handled othersubrs, where we know the number of     */
+            /* arguments, we increase the stack by the value of        */
+            /* known_othersubr_result_cnt                              */
+            /*                                                         */
+            /* for unhandled othersubrs the following pops adjust the  */
+            /* stack pointer as necessary                              */
+
+            if (arg_cnt > top)
+                return FT_Common.FT_Err_Stack_Overflow;
+
+            top -= arg_cnt;
+
+            known_othersubr_result_cnt   = 0;
+            unknown_othersubr_result_cnt = 0;
+
+            /* XXX TODO: The checks to `arg_count == <whatever>'       */
+            /* might not be correct; an othersubr expects a certain    */
+            /* number of operands on the PostScript stack (as opposed  */
+            /* to the T1 stack) but it doesn't have to put them there  */
+            /* by itself; previous othersubrs might have left the      */
+            /* operands there if they were not followed by an          */
+            /* appropriate number of pops                              */
+            /*                                                         */
+            /* On the other hand, Adobe Reader 7.0.8 for Linux doesn't */
+            /* accept a font that contains charstrings like            */
+            /*                                                         */
+            /*     100 200 2 20 callothersubr                          */
+            /*     300 1 20 callothersubr pop                          */
+            /*                                                         */
+            /* Perhaps this is the reason why BuildCharArray exists.   */
+
+            switch (subr_no)
+            {
+                case 0:                     /* end flex feature */
+                    if (arg_cnt != 3)
+                        return FT_Common.FT_Err_Syntax_Error;
+
+                    if (decoder.flex_state == 0 || decoder.num_flex_vectors != 7)
+                    {
+                        return FT_Common.FT_Err_Syntax_Error;
+                    }
+
+                    /* the two `results' are popped by the following setcurrentpoint */
+                    tops[top] = x;
+                    tops[top + 1] = y;
+                    known_othersubr_result_cnt = 2;
+                    break;
+
+                case 1:                     /* start flex feature */
+                    if (arg_cnt != 0)
+                        return FT_Common.FT_Err_Syntax_Error;
+
+                    decoder.flex_state        = 1;
+                    decoder.num_flex_vectors  = 0;
+
+                    error = t1_builder_start_point(builder, x, y);
+                    if (error != FT_Common.FT_Err_Ok)
+                        return error;
+
+                    error = t1_builder_check_points(builder, 6);
+                    if (error != FT_Common.FT_Err_Ok)
+                        return error;
+
+                    break;
+
+                case 2:                     /* add flex vectors */
+                    if (arg_cnt != 0)
+                        return FT_Common.FT_Err_Syntax_Error;
+
+                    if (decoder.flex_state == 0)
+                    {
+                        return FT_Common.FT_Err_Syntax_Error;
+                    }
+
+                    /* note that we should not add a point for index 0; */
+                    /* this will move our current position to the flex  */
+                    /* point without adding any point to the outline    */
+                    var idx = decoder.num_flex_vectors;
+                    decoder.num_flex_vectors++;
+                    if (idx > 0 && idx < 7)
+                        t1_builder_add_point(builder, x, y, (idx == 3 || idx == 6) ? 1 : 0);
+
+                    break;
+
+                case 3:                     /* change hints */
+                    if (arg_cnt != 1)
+                        return FT_Common.FT_Err_Syntax_Error;
+
+                    known_othersubr_result_cnt = 1;
+
+                    if (hinter)
+                        hinter.reset(hinter.hints, builder.current.n_points);
+                    break;
+
+                case 12:
+                case 13:
+                    /* counter control hints, clear stack */
+                    top = 0;
+                    break;
+
+                case 14:
+                case 15:
+                case 16:
+                case 17:
+                case 18:                    /* multiple masters */
+                {
+                    var blend = decoder.blend;
+
+                    if ( !blend )
+                    {
+                        return FT_Common.FT_Err_Syntax_Error;
+                    }
+
+                    var num_points = subr_no - 13;
+                    if (subr_no == 18)
+                        num_points++;
+                    if (arg_cnt != (num_points * blend.num_designs))
+                    {
+                        return FT_Common.FT_Err_Syntax_Error;
+                    }
+
+                    /* We want to compute                                    */
+                    /*                                                       */
+                    /*   a0*w0 + a1*w1 + ... + ak*wk                         */
+                    /*                                                       */
+                    /* but we only have a0, a1-a0, a2-a0, ..., ak-a0.        */
+                    /*                                                       */
+                    /* However, given that w0 + w1 + ... + wk == 1, we can   */
+                    /* rewrite it easily as                                  */
+                    /*                                                       */
+                    /*   a0 + (a1-a0)*w1 + (a2-a0)*w2 + ... + (ak-a0)*wk     */
+                    /*                                                       */
+                    /* where k == num_designs-1.                             */
+                    /*                                                       */
+                    /* I guess that's why it's written in this `compact'     */
+                    /* form.                                                 */
+                    /*                                                       */
+                    var delta  = top + num_points;
+                    var values = top;
+                    for (var nn = 0; nn < num_points; nn++)
+                    {
+                        var tmp = tops[values];
+
+                        for (var mm = 1; mm < blend.num_designs; mm++)
+                            tmp += FT_MulFix(tops[delta++], blend.weight_vector[mm]);
+
+                        tops[values++] = tmp;
+                    }
+
+                    known_othersubr_result_cnt = num_points;
+                    break;
+                }
+
+                case 19:
+                    /* <idx> 1 19 callothersubr                             */
+                    /* => replace elements starting from index cvi( <idx> ) */
+                    /*    of BuildCharArray with WeightVector               */
+                    var blend = decoder.blend;
+
+                    if (arg_cnt != 1 || blend == null)
+                        return FT_Common.FT_Err_Syntax_Error;
+
+                    var idx = (tops[top] >> 16) & 0xFFFF;
+
+                    if (idx < 0 || (idx + blend.num_designs) > decoder.len_buildchar)
+                        return FT_Common.FT_Err_Syntax_Error;
+
+                    for (var ii = 0; ii < blend.num_designs; ii++)
+                        decoder.buildchar[idx + ii] = blend.weight_vector[ii];
+
+                    break;
+
+                case 20:
+                    /* <arg1> <arg2> 2 20 callothersubr pop   */
+                    /* ==> push <arg1> + <arg2> onto T1 stack */
+                    if (arg_cnt != 2)
+                        return FT_Common.FT_Err_Syntax_Error;
+
+                    tops[top] += tops[top + 1]; /* XXX (over|under)flow */
+
+                    known_othersubr_result_cnt = 1;
+                    break;
+
+                case 21:
+                    /* <arg1> <arg2> 2 21 callothersubr pop   */
+                    /* ==> push <arg1> - <arg2> onto T1 stack */
+                    if (arg_cnt != 2)
+                        return FT_Common.FT_Err_Syntax_Error;
+
+                    tops[top] -= tops[top + 1]; /* XXX (over|under)flow */
+
+                    known_othersubr_result_cnt = 1;
+                    break;
+
+                case 22:
+                    /* <arg1> <arg2> 2 22 callothersubr pop   */
+                    /* ==> push <arg1> * <arg2> onto T1 stack */
+                    if (arg_cnt != 2)
+                        return FT_Common.FT_Err_Syntax_Error;
+
+                    tops[top] = FT_MulFix(tops[top], tops[top + 1]);
+
+                    known_othersubr_result_cnt = 1;
+                    break;
+
+                case 23:
+                    /* <arg1> <arg2> 2 23 callothersubr pop   */
+                    /* ==> push <arg1> / <arg2> onto T1 stack */
+                    if (arg_cnt != 2 || tops[top + 1] == 0)
+                        return FT_Common.FT_Err_Syntax_Error;
+
+                    tops[top] = FT_DivFix(tops[top], tops[top + 1]);
+
+                    known_othersubr_result_cnt = 1;
+                    break;
+
+                case 24:
+                    /* <val> <idx> 2 24 callothersubr               */
+                    /* ==> set BuildCharArray[cvi( <idx> )] = <val> */
+                    var blend = decoder.blend;
+
+                    if (arg_cnt != 2 || blend == null)
+                        return FT_Common.FT_Err_Syntax_Error;
+
+                    var idx = (tops[top + 1] >> 16) & 0xFFFF;
+
+                    if (idx < 0 || idx >= decoder.len_buildchar)
+                        return FT_Common.FT_Err_Syntax_Error;
+
+                    decoder.buildchar[idx] = tops[top];
+
+                    break;
+
+                case 25:
+                    /* <idx> 1 25 callothersubr pop        */
+                    /* ==> push BuildCharArray[cvi( idx )] */
+                    /*     onto T1 stack                   */
+                    var blend = decoder.blend;
+
+                    if (arg_cnt != 1 || blend == null)
+                        return FT_Common.FT_Err_Syntax_Error;
+
+                    idx = (tops[top] >> 16) & 0xFFFF;
+
+                    if (idx < 0 || idx >= decoder.len_buildchar)
+                        return FT_Common.FT_Err_Syntax_Error;
+
+                    tops[top] = decoder.buildchar[idx];
+
+                    known_othersubr_result_cnt = 1;
+                    break;
+
+                case 27:
+                    /* <res1> <res2> <val1> <val2> 4 27 callothersubr pop */
+                    /* ==> push <res1> onto T1 stack if <val1> <= <val2>, */
+                    /*     otherwise push <res2>                          */
+                    if (arg_cnt != 4)
+                        return FT_Common.FT_Err_Syntax_Error;
+
+                    if (tops[top + 2] > tops[top + 3])
+                        tops[top] = tops[top + 1];
+
+                    known_othersubr_result_cnt = 1;
+                    break;
+
+                case 28:
+                    /* 0 28 callothersubr pop                               */
+                    /* => push random value from interval [0, 1) onto stack */
+                    if (arg_cnt != 0)
+                        return FT_Common.FT_Err_Syntax_Error;
+
+                    var Rand = seed;
+                    if (Rand >= 0x8000)
+                        Rand++;
+
+                    tops[top] = Rand;
+
+                    seed = FT_MulFix(seed, 0x10000 - seed);
+                    if (seed == 0)
+                        seed += 0x2873;
+
+                    known_othersubr_result_cnt = 1;
+                    break;
+
+                default:
+                    if (arg_cnt >= 0 && subr_no >= 0)
+                    {
+                        unknown_othersubr_result_cnt = arg_cnt;
+                        break;
+                    }
+                    /* fall through */
+
+                    return FT_Common.FT_Err_Syntax_Error;
+            }
+
+            top += known_othersubr_result_cnt;
+            decoder.top = top;
+        }
+        else  /* general operator */
+        {
+            var num_args = t1_args_count[op];
+
+            if (top < num_args)
+                return FT_Common.FT_Err_Stack_Overflow;
+
+            /* XXX Operators usually take their operands from the        */
+            /*     bottom of the stack, i.e., the operands are           */
+            /*     decoder->stack[0], ..., decoder->stack[num_args - 1]; */
+            /*     only div, callsubr, and callothersubr are different.  */
+            /*     In practice it doesn't matter (?).                    */
+
+            top -= num_args;
+
+            switch (op)
+            {
+                case FT_Common.op_endchar:
+
+                    t1_builder_close_contour(builder);
+
+                    /* close hints recording session */
+                    if (hinter != null)
+                    {
+                        if (hinter.close(hinter.hints, builder.current.n_points))
+                            return FT_Common.FT_Err_Syntax_Error;
+
+                        /* apply hints to the loaded glyph outline now */
+                        hinter.apply(hinter.hints, builder.current, builder.hints_globals, decoder.hint_mode);
+                    }
+
+                    /* add current outline to the glyph slot */
+                    FT_GlyphLoader_Add(builder.loader);
+
+                    /* the compiler should optimize away this empty loop but ... */
+                    /* return now! */
+                    return 0;
+
+                case FT_Common.op_hsbw:
+                    builder.parse_state = FT_Common.T1_Parse_Have_Width;
+
+                    builder.left_bearing.x += tops[top];
+                    builder.advance.x       = tops[top + 1];
+                    builder.advance.y       = 0;
+
+                    orig_x = x = builder.pos_x + tops[top];
+                    orig_y = y = builder.pos_y;
+
+                    /* the `metrics_only' indicates that we only want to compute */
+                    /* the glyph's metrics (lsb + advance width), not load the   */
+                    /* rest of it; so exit immediately                           */
+                    if (builder.metrics_only)
+                        return 0;
+
+                    break;
+
+                case FT_Common.op_seac:
+                    return t1operator_seac(decoder, tops[top], tops[top + 1], tops[top + 2],
+                        (tops[top + 3] >> 16) & 0xFFFF, (tops[top + 4] >> 16) & 0xFFFF);
+
+                case FT_Common.op_sbw:
+                    builder.parse_state = FT_Common.T1_Parse_Have_Width;
+
+                    builder.left_bearing.x += tops[top];
+                    builder.left_bearing.y += tops[top + 1];
+                    builder.advance.x       = tops[top + 2];
+                    builder.advance.y       = tops[top + 3];
+
+                    x = builder.pos_x + tops[top];
+                    y = builder.pos_y + tops[top + 1];
+
+                    /* the `metrics_only' indicates that we only want to compute */
+                    /* the glyph's metrics (lsb + advance width), not load the   */
+                    /* rest of it; so exit immediately                           */
+                    if (builder.metrics_only)
+                        return 0;
+
+                    break;
+
+                case FT_Common.op_closepath:
+                    /* if there is no path, `closepath' is a no-op */
+                    if (builder.parse_state == FT_Common.T1_Parse_Have_Path || builder.parse_state == FT_Common.T1_Parse_Have_Moveto)
+                        t1_builder_close_contour(builder);
+
+                    builder.parse_state = FT_Common.T1_Parse_Have_Width;
+                    break;
+
+                case FT_Common.op_hlineto:
+
+                    error = t1_builder_start_point(builder, x, y);
+                    if (error != 0)
+                        return error;
+
+                    x += tops[top];
+                    error = t1_builder_add_point1(builder, x, y);
+                    if (error != 0)
+                        return error;
+
+                    break;
+
+                case FT_Common.op_hmoveto:
+                    x += tops[top];
+                    if (decoder.flex_state == 0)
+                    {
+                        if (builder.parse_state == FT_Common.T1_Parse_Start)
+                            return FT_Common.FT_Err_Syntax_Error;
+                        builder.parse_state = FT_Common.T1_Parse_Have_Moveto;
+                    }
+                    break;
+
+                case FT_Common.op_hvcurveto:
+
+                    error = t1_builder_start_point(builder, x, y);
+                    if (error != 0)
+                        return error;
+                    error = t1_builder_check_points(builder, 3);
+                    if (error != 0)
+                        return error;
+
+                    x += tops[top];
+                    t1_builder_add_point(builder, x, y, 0);
+                    x += tops[top + 1];
+                    y += tops[top + 2];
+                    t1_builder_add_point(builder, x, y, 0);
+                    y += tops[top + 3];
+                    t1_builder_add_point(builder, x, y, 1);
+                    break;
+
+                case FT_Common.op_rlineto:
+                    error = t1_builder_start_point(builder, x, y);
+                    if (error != 0)
+                        return error;
+
+                    x += tops[top];
+                    y += tops[top + 1];
+
+                    error = t1_builder_add_point1(builder, x, y);
+                    if (error != 0)
+                        return error;
+
+                    break;
+
+                case FT_Common.op_rmoveto:
+                    x += tops[top];
+                    y += tops[top + 1];
+                    if (decoder.flex_state == 0)
+                    {
+                        if (builder.parse_state == FT_Common.T1_Parse_Start)
+                            return FT_Common.FT_Err_Syntax_Error;
+                        builder.parse_state = FT_Common.T1_Parse_Have_Moveto;
+                    }
+                    break;
+
+                case FT_Common.op_rrcurveto:
+
+                    error = t1_builder_start_point(builder, x, y);
+                    if (error != 0)
+                        return error;
+                    error = t1_builder_check_points(builder, 3);
+                    if (error != 0)
+                        return error;
+
+                    x += tops[top];
+                    y += tops[top + 1];
+                    t1_builder_add_point(builder, x, y, 0);
+
+                    x += tops[top + 2];
+                    y += tops[top + 3];
+                    t1_builder_add_point(builder, x, y, 0);
+
+                    x += tops[top + 4];
+                    y += tops[top + 5];
+                    t1_builder_add_point(builder, x, y, 1);
+                    break;
+
+                case FT_Common.op_vhcurveto:
+                    error = t1_builder_start_point(builder, x, y);
+                    if (error != 0)
+                        return error;
+                    error = t1_builder_check_points(builder, 3);
+                    if (error != 0)
+                        return error;
+
+                    y += tops[top];
+                    t1_builder_add_point(builder, x, y, 0);
+                    x += tops[top + 1];
+                    y += tops[top + 2];
+                    t1_builder_add_point(builder, x, y, 0);
+                    x += tops[top + 3];
+                    t1_builder_add_point(builder, x, y, 1);
+                    break;
+
+                case FT_Common.op_vlineto:
+                    error = t1_builder_start_point(builder, x, y);
+                    if (error != 0)
+                        return error;
+
+                    y += tops[top];
+                    error = t1_builder_add_point1(builder, x, y);
+                    if (error != 0)
+                        return error;
+                    break;
+
+                case FT_Common.op_vmoveto:
+                    y += tops[top];
+                    if (decoder.flex_state == 0)
+                    {
+                        if (builder.parse_state == FT_Common.T1_Parse_Start)
+                            return FT_Common.FT_Err_Syntax_Error;
+                        builder.parse_state = FT_Common.T1_Parse_Have_Moveto;
+                    }
+                    break;
+
+                case FT_Common.op_div:
+                    /* if `large_int' is set, we divide unscaled numbers; */
+                    /* otherwise, we divide numbers in 16.16 format --    */
+                    /* in both cases, it is the same operation            */
+                    tops[top] = FT_DivFix(tops[top], tops[top + 1]);
+                    ++top;
+
+                    large_int = 0;
+                    break;
+
+                case FT_Common.op_callsubr:
+                {
+                    var idx = (tops[top] >> 16) & 0xFFFF;
+                    if (idx < 0 || idx >= decoder.num_subrs)
+                        return FT_Common.FT_Err_Syntax_Error;
+
+                    if (zone >= FT_Common.T1_MAX_SUBRS_CALLS)
+                        return FT_Common.FT_Err_Syntax_Error;
+
+                    zones[zone].cursor = dublicate_pointer(ip);  /* save current instruction pointer */
+                    zone++;
+
+                    /* The Type 1 driver stores subroutines without the seed bytes. */
+                    /* The CID driver stores subroutines with seed bytes.  This     */
+                    /* case is taken care of when decoder->subrs_len == 0.          */
+                    zones[zone].base = dublicate_pointer(decoder.subrs[idx]);
+
+                    if (decoder.subrs_len != 0)
+                        zones[zone].limit = zones[zone].base.pos + decoder.subrs_len[idx];
+                    else
+                    {
+                        /* We are using subroutines from a CID font.  We must adjust */
+                        /* for the seed bytes.                                       */
+                        zones[zone].base.pos  += (decoder.lenIV >= 0 ? decoder.lenIV : 0);
+                        zones[zone].limit = decoder.subrs[idx + 1].pos;
+                    }
+
+                    zones[zone].cursor = dublicate_pointer(zones[zone].base);
+
+                    if (zones[zone].base == null)
+                        return FT_Common.FT_Err_Syntax_Error;
+
+                    decoder.zone = zone;
+                    ip           = dublicate_pointer(zones[zone].base);
+                    limit        = zones[zone].limit;
+                    break;
+                }
+
+                case FT_Common.op_pop:
+
+                    if (known_othersubr_result_cnt > 0)
+                    {
+                        known_othersubr_result_cnt--;
+                        /* ignore, we pushed the operands ourselves */
+                        break;
+                    }
+
+                    if (unknown_othersubr_result_cnt == 0)
+                        return FT_Common.FT_Err_Syntax_Error;
+
+                    unknown_othersubr_result_cnt--;
+                    top++;   /* `push' the operand to callothersubr onto the stack */
+                    break;
+
+                case FT_Common.op_return:
+
+                    if (zone <= 0)
+                        return FT_Common.FT_Err_Syntax_Error;
+
+                    zone--;
+                    ip           = dublicate_pointer(zones[zone].cursor);
+                    limit        = zones[zone].limit;
+                    decoder.zone = zone;
+                    break;
+
+                case FT_Common.op_dotsection:
+                    break;
+
+                case FT_Common.op_hstem:
+                    /* record horizontal hint */
+                    if (hinter != null)
+                    {
+                        /* tops[0] += builder->left_bearing.y; */
+                        hinter.stem(hinter.hints, 1, tops, top);
+                    }
+                    break;
+
+                case FT_Common.op_hstem3:
+                    /* record horizontal counter-controlled hints */
+                    if (hinter != null)
+                        hinter.stem3(hinter.hints, 1, tops, top);
+                    break;
+
+                case FT_Common.op_vstem:
+                    /* record vertical hint */
+                    if (hinter != null)
+                    {
+                        tops[top] += orig_x;
+                        hinter.stem(hinter.hints, 0, tops, top);
+                    }
+                    break;
+
+                case FT_Common.op_vstem3:
+                    /* record vertical counter-controlled hints */
+                    if (hinter != null)
+                    {
+                        tops[top] += orig_x;
+                        tops[top + 2] += orig_x;
+                        tops[top + 4] += orig_x;
+                        hinter.stem3(hinter.hints, 0, tops, top);
+                    }
+                    break;
+
+                case FT_Common.op_setcurrentpoint:
+                    /* From the T1 specification, section 6.4:                */
+                    /*                                                        */
+                    /*   The setcurrentpoint command is used only in          */
+                    /*   conjunction with results from OtherSubrs procedures. */
+
+                    /* known_othersubr_result_cnt != 0 is already handled     */
+                    /* above.                                                 */
+
+                    /* Note, however, that both Ghostscript and Adobe         */
+                    /* Distiller handle this situation by silently ignoring   */
+                    /* the inappropriate `setcurrentpoint' instruction.  So   */
+                    /* we do the same.                                        */
+                    x = tops[top];
+                    y = tops[top + 1];
+                    decoder.flex_state = 0;
+                    break;
+
+                case FT_Common.op_unknown15:
+                    /* nothing to do except to pop the two arguments */
+                    break;
+
+                default:
+                    return FT_Common.FT_Err_Syntax_Error;
+            }
+
+            /* XXX Operators usually clear the operand stack;  */
+            /*     only div, callsubr, callothersubr, pop, and */
+            /*     return are different.                       */
+            /*     In practice it doesn't matter (?).          */
+
+            decoder.top = top;
+
+        } /* general operator processing */
+
+    } /* while ip < limit */
+
+    return error;
+}
+
+function t1_decoder_parse_glyph(decoder, glyph)
+{
+    return decoder.parse_callback(decoder, glyph);
+}
+
+function t1_decoder_init(decoder, face, size, slot, glyph_names, blend, hinting, hint_mode, parse_callback)
+{
+    decoder.clear();
+
+    var psnames = FT_FACE_FIND_GLOBAL_SERVICE(face, FT_SERVICE_ID_POSTSCRIPT_CMAPS);
+    if (psnames == null)
+        return FT_Common.FT_Err_Unimplemented_Feature;
+
+    decoder.psnames = psnames;
+
+    t1_builder_init(decoder.builder, face, size, slot, hinting);
+
+    /* decoder->buildchar and decoder->len_buildchar have to be  */
+    /* initialized by the caller since we cannot know the length */
+    /* of the BuildCharArray                                     */
+    decoder.num_glyphs     = face.num_glyphs;
+    decoder.glyph_names    = glyph_names;
+    decoder.hint_mode      = hint_mode;
+    decoder.blend          = blend;
+    decoder.parse_callback = parse_callback;
+
+    decoder.funcs          = t1_decoder_funcs;
+
+    return 0;
+}
+
+function t1_decoder_done(decoder)
+{
+    t1_builder_done(decoder.builder);
+}
+
+
+/******************************************************************************/
+// psaux
+/******************************************************************************/
+function PS_Table_FuncsRec(_init, _done, _add, _release)
+{
+    this.init       = _init;
+    this.done       = _done;
+    this.add        = _add;
+    this.release    = _release;
+}
+
+function PS_TableRec()
+{
+    this.block = null;
+    this.cursor = 0;
+    this.capacity = 0;
+    this.init = 0;
+
+    this.max_elems = 0;
+    this.num_elems = 0;
+    this.elements = null;
+    this.lengths = null;
+
+    this.memory = null;
+    this.funcs = new PS_Table_FuncsRec(null, null, null, null);
+
+    this.clear = function()
+    {
+        this.block = null;
+        this.cursor = 0;
+        this.capacity = 0;
+        this.init = 0;
+
+        this.max_elems = 0;
+        this.num_elems = 0;
+        this.elements = null;
+        this.lengths = null;
+
+        this.memory = null;
+        this.funcs = new PS_Table_FuncsRec(null, null, null, null);
+    }
+}
+
+function T1_TokenRec()
+{
+    this.start = new CPointer();
+    this.limit = 0;
+    this.type = 0;
+}
+
+function T1_FieldRec()
+{
+    this.ident = "";
+    this.location = 0;
+    this.type = 0;
+    this.reader = null;
+    this.offset = 0; // у нас это просто индекс члена класса. А не сдвиг в памяти
+    this.size = 0;
+    this.array_max = 0;
+
+    this.count_offset = 0;
+    this.dict = 0;
+
+    this.set_field = null;
+    this.set_field_count = null;
+}
+
+function create_dublicate_t1_field(_field)
+{
+    var ret = new T1_FieldRec();
+
+    ret.ident = _field.ident;
+    ret.location = _field.location;
+    ret.type = _field.type;
+    ret.reader = _field.reader;
+    ret.offset = _field.offset; // у нас это просто индекс в МАССИВЕ (т.е. для не массива это поле не нужно)
+    ret.size = _field.size;     // не пользуем (на будущее оставим)
+    ret.array_max = _field.array_max;
+
+    ret.count_offset = _field.count_offset;
+    ret.dict = _field.dict;
+
+    ret.set_field = _field.set_field;
+    ret.set_field_count = _field.set_field_count;
+
+    return ret;
+}
+
+function fire_t1_field(obj, val, f)
+{
+    f.set_field(obj, val, f);
+}
+function fire_t1_field_count(obj, val, f)
+{
+    f.set_field_count(obj, val, f);
+}
+
+function create_t1_field(_ident, _location, _type, _reader, _offset, _size, _array_max, _count_offset, _dict, func_set_field, func_set_field_count)
+{
+    var ret = new T1_FieldRec();
+    ret.ident = _ident;
+    ret.location = _location;
+    ret.type = _type;
+    ret.reader = _reader;
+    ret.offset = _offset;
+    ret.size = _size;
+    ret.array_max = _array_max;
+    ret.count_offset = _count_offset;
+    ret.dict = _dict;
+
+    ret.set_field = func_set_field;
+    ret.set_field_count = func_set_field_count;
+
+    return ret;
+}
+function create_t1_field2(_ident, _location, _type, func_set_field, func_set_field_count)
+{
+    var ret = new T1_FieldRec();
+    ret.ident = _ident;
+    ret.location = _location;
+    ret.type = _type;
+
+    ret.set_field = func_set_field;
+    ret.set_field_count = func_set_field_count;
+
+    return ret;
+}
+function create_t1_field4(_ident, _location, _type, _dict, func_set_field, func_set_field_count)
+{
+    var ret = new T1_FieldRec();
+    ret.ident = _ident;
+    ret.location = _location;
+    ret.type = _type;
+    ret.dict = _dict;
+
+    ret.set_field = func_set_field;
+    ret.set_field_count = func_set_field_count;
+
+    return ret;
+}
+function create_t1_field3(_ident, _location, _type, _max, func_set_field, func_set_field_count)
+{
+    var ret = new T1_FieldRec();
+    ret.ident = _ident;
+    ret.location = _location;
+    ret.type = _type;
+    ret.array_max = _max;
+
+    ret.set_field = func_set_field;
+    ret.set_field_count = func_set_field_count;
+
+    return ret;
+}
+function create_t1_field5(_ident, _location, _type, _max, _dict, func_set_field, func_set_field_count)
+{
+    var ret = new T1_FieldRec();
+    ret.ident = _ident;
+    ret.location = _location;
+    ret.type = _type;
+    ret.array_max = _max;
+    ret.dict = _dict;
+
+    ret.set_field = func_set_field;
+    ret.set_field_count = func_set_field_count;
+
+    return ret;
+}
+
+function PS_Parser_FuncsRec(_init,_done,_skip_spaces,_skip_PS_token,_to_int,_to_fixed,_to_bytes,_to_coord_array,_to_fixed_array,
+                            _to_token,_to_token_array,_load_field,_load_field_table)
+{
+    this.init = _init;
+    this.done = _done;
+
+    this.skip_spaces    = _skip_spaces;
+    this.skip_PS_token  = _skip_PS_token;
+
+    this.to_int         = _to_int;
+    this.to_fixed       = _to_fixed;
+    this.to_bytes       = _to_bytes;
+    this.to_coord_array = _to_coord_array;
+    this.to_fixed_array = _to_fixed_array;
+    this.to_token       = _to_token;
+    this.to_token_array = _to_token_array;
+    this.load_field     = _load_field;
+    this.load_field_table = _load_field_table;
+}
+
+function T1_Builder_FuncsRec(_init,_done,_check_points,_add_point,_add_point1,_add_contour,_start_point,_close_contour)
+{
+    this.init = _init;
+    this.done = _done;
+
+    this.check_points   = _check_points;
+    this.add_point      = _add_point;
+    this.add_point1     = _add_point1;
+    this.add_contour    = _add_contour;
+    this.start_point    = _start_point;
+    this.close_contour  = _close_contour;
+}
+
+function PS_ParserRec()
+{
+    this.cursor = 0;
+    this.base = null;
+    this.limit = 0;
+    this.error = 0;
+    this.memory = null;
+
+    this.funcs = null;
+
+    this.clear = function()
+    {
+        this.cursor = 0;
+        this.base = null;
+        this.limit = 0;
+        this.error = 0;
+        this.memory = null;
+
+        this.funcs = null;
+    }
+}
+
+function T1_BuilderRec()
+{
+    this.memory = null;
+    this.face = null;
+    this.glyph = null;
+    this.loader = null;
+    this.base = null;
+    this.current = null;
+
+    this.pos_x = 0;
+    this.pos_y = 0;
+
+    this.left_bearing = new FT_Vector();
+    this.advance = new FT_Vector();
+
+    this.bbox = new FT_BBox();
+    this.parse_state = 0;
+    this.load_points = 0;
+    this.no_recurse = 0;
+
+    this.metrics_only = 0;
+
+    this.hints_funcs = null;
+    this.hints_globals = null;
+
+    this.funcs = null;
+
+    this.clear = function()
+    {
+        this.memory = null;
+        this.face = null;
+        this.glyph = null;
+        this.loader = null;
+        this.base = null;
+        this.current = null;
+
+        this.pos_x = 0;
+        this.pos_y = 0;
+
+        this.left_bearing.x = 0;
+        this.left_bearing.y = 0;
+        this.advance.x = 0;
+        this.advance.y = 0;
+
+        this.bbox.xMin = 0;
+        this.bbox.yMin = 0;
+        this.bbox.xMax = 0;
+        this.bbox.yMax = 0;
+
+        this.parse_state = 0;
+        this.load_points = 0;
+        this.no_recurse = 0;
+
+        this.metrics_only = 0;
+
+        this.hints_funcs = null;
+        this.hints_globals = null;
+
+        this.funcs = null;
+    }
+}
+
+function T1_Decoder_ZoneRec()
+{
+    this.cursor = 0;
+    this.base = null;
+    this.limit = 0;
+}
+
+function T1_Decoder_FuncsRec(_init, _done, _parse_charstrings)
+{
+    this.init = _init;
+    this.done = _done;
+    this.parse_charstrings = _parse_charstrings;
+}
+
+function T1_DecoderRec()
+{
+    this.builder = new T1_BuilderRec();
+
+    this.stack = CreateIntArray(FT_Common.T1_MAX_CHARSTRINGS_OPERANDS);
+    this.top = 0;
+
+    this.zones = new Array(FT_Common.T1_MAX_SUBRS_CALLS + 1);
+    for (var i = 0; i <= FT_Common.T1_MAX_SUBRS_CALLS; i++)
+        this.zones[i] = new T1_Decoder_ZoneRec();
+
+    this.zone = 0;
+
+    this.psnames = null;
+    this.num_glyphs = 0;
+    this.glyph_names = null;
+
+    this.lenIV = 0;
+    this.num_subrs = 0;
+    this.subrs = null;
+    this.subrs_len = null;
+
+    this.font_matrix = new FT_Matrix();
+    this.font_offset = new FT_Vector();
+
+    this.flex_state = 0;
+    this.num_flex_vectors = 0;
+    this.flex_vectors = new Array(7);
+    for (var i = 0; i < 7; i++)
+        this.flex_vectors[i] = new FT_Vector();
+
+    this.blend = null;
+
+    this.hint_mode = 0;
+
+    this.parse_callback = null;
+    this.funcs = null;
+
+    this.buildchar = null;
+    this.len_buildchar = 0;
+
+    this.seac = 0;
+
+    this.clear = function()
+    {
+        this.builder.clear();
+
+        for (var i = 0; i < FT_Common.T1_MAX_CHARSTRINGS_OPERANDS; i++)
+            this.stack[i] = 0;
+
+        this.top = 0;
+
+        for (var i = 0; i <= FT_Common.T1_MAX_SUBRS_CALLS; i++)
+        {
+            var _z = this.zones[i];
+            _z.base = null;
+            _z.cursor = 0;
+            _z.limit = 0;
+        }
+        this.zone = 0;
+
+        this.psnames = null;
+        this.num_glyphs = 0;
+        this.glyph_names = null;
+
+        this.lenIV = 0;
+        this.num_subrs = 0;
+        this.subrs = null;
+        this.subrs_len = null;
+
+        this.font_matrix.xx = 0;
+        this.font_matrix.xy = 0;
+        this.font_matrix.yx = 0;
+        this.font_matrix.yy = 0;
+
+        this.font_offset.x = 0;
+        this.font_offset.y = 0;
+
+        this.flex_state = 0;
+        this.num_flex_vectors = 0;
+        for (var i = 0; i < 7; i++)
+        {
+            this.flex_vectors[i].x = 0;
+            this.flex_vectors[i].y = 0;
+        }
+
+        this.blend = null;
+
+        this.hint_mode = 0;
+
+        this.parse_callback = null;
+        this.funcs = null;
+
+        this.buildchar = null;
+        this.len_buildchar = 0;
+
+        this.seac = 0;
+    }
+}
+
+var ps_table_funcs = {
+    init : ps_table_new,
+    done : ps_table_done,
+    add : ps_table_add,
+    release : ps_table_release
+};
+
+var ps_parser_funcs = {
+    init : ps_parser_init,
+    done : ps_parser_done,
+    skip_spaces : ps_parser_skip_spaces,
+    skip_PS_token : ps_parser_skip_PS_token,
+    to_int : ps_parser_to_int,
+    to_fixed : ps_parser_to_fixed,
+    to_bytes : ps_parser_to_bytes,
+    to_coord_array : ps_parser_to_coord_array,
+    to_fixed_array : ps_parser_to_fixed_array,
+    to_token : ps_parser_to_token,
+    to_token_array : ps_parser_to_token_array,
+    load_field : ps_parser_load_field,
+    load_field_table : ps_parser_load_field_table
+};
+
+var t1_builder_funcs = {
+    init : t1_builder_init,
+    done : t1_builder_done,
+    check_points : t1_builder_check_points,
+    add_point : t1_builder_add_point,
+    add_point1 : t1_builder_add_point1,
+    add_contour : t1_builder_add_contour,
+    start_point : t1_builder_start_point,
+    close_contour : t1_builder_close_contour
+};
+
+var t1_decoder_funcs = {
+    init : t1_decoder_init,
+    done : t1_decoder_done,
+    parse_charstrings : t1_decoder_parse_charstrings
+};
+
+var afm_parser_funcs = {
+    init : afm_parser_init,
+    done : afm_parser_done,
+    parse : afm_parser_parse
+};
+
+var t1_cmap_classes = {
+    standard : t1_cmap_standard_class_rec,
+    expert : t1_cmap_expert_class_rec,
+    custom : t1_cmap_custom_class_rec,
+    unicode : t1_cmap_unicode_class_rec
+};
+
+function PSAux_ServiceRec()
+{
+    this.ps_table_funcs = null;
+    this.ps_parser_funcs = null;
+    this.t1_builder_funcs = null;
+    this.t1_decoder_funcs = null;
+
+    this.t1_decrypt = null;
+
+    this.t1_cmap_classes = null;
+
+    this.afm_parser_funcs = null;
+}
+
+function create_psaux_interface(_table_funcs,_parser_funcs,_builder_funcs,_decoder_funcs,_decrypt,_cmap_classes,_afm_parser_funcs)
+{
+    var ret = new PSAux_ServiceRec();
+
+    ret.ps_table_funcs = _table_funcs;
+    ret.ps_parser_funcs = _parser_funcs;
+    ret.t1_builder_funcs = _builder_funcs;
+    ret.t1_decoder_funcs = _decoder_funcs;
+    ret.t1_decrypt = _decrypt;
+    ret.t1_cmap_classes = _cmap_classes;
+    ret.afm_parser_funcs = _afm_parser_funcs;
+
+    return ret;
+}
+var psaux_interface = create_psaux_interface(ps_table_funcs,ps_parser_funcs,t1_builder_funcs,t1_decoder_funcs, t1_decrypt, t1_cmap_classes, afm_parser_funcs);
+
+function create_psaux_module(library)
+{
+    var psaux_mod = new FT_Module();
+    psaux_mod.clazz = new FT_Module_Class();
+
+    var clazz = psaux_mod.clazz;
+    clazz.flags = 0;
+    clazz.name = "psaux";
+    clazz.version = 0x20000;
+    clazz.requires = 0x20000;
+
+    clazz.module_interface = psaux_interface;
+    clazz.init = null;
+    clazz.done = null;
+
+    clazz.get_interface = null;
+
+    psaux_mod.library = library;
+    psaux_mod.memory = library.Memory;
+    psaux_mod.generic = null;
+
+    return psaux_mod;
+}
diff --git a/Common/FontsFreeType/Private/FreeType/modules/psnames.js b/Common/FontsFreeType/Private/FreeType/modules/psnames.js
new file mode 100644
index 0000000000000000000000000000000000000000..3505efac7c30b5c6718a98cce93671c9d00c3676
--- /dev/null
+++ b/Common/FontsFreeType/Private/FreeType/modules/psnames.js
@@ -0,0 +1,4089 @@
+var ft_standard_glyph_names = [".null","nonmarkingreturn","notequal","infinity","lessequal","greaterequal","partialdiff","summation","product","pi","integral",
+"Omega","radical","approxequal","Delta","nonbreakingspace","lozenge","apple","franc","Gbreve","gbreve","Idotaccent","Scedilla",
+"scedilla","Cacute","cacute","Ccaron","ccaron","dcroat",".notdef","space","exclam","quotedbl","numbersign","dollar","percent",
+"ampersand","quoteright","parenleft","parenright","asterisk","plus","comma","hyphen","period","slash","zero","one","two","three",
+"four","five","six","seven","eight","nine","colon","semicolon","less","equal","greater","question","at","A","B","C","D","E","F","G",
+"H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","bracketleft","backslash","bracketright","asciicircum",
+"underscore","quoteleft","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z",
+"braceleft","bar","braceright","asciitilde","exclamdown","cent","sterling","fraction","yen","florin","section","currency",
+"quotesingle","quotedblleft","guillemotleft","guilsinglleft","guilsinglright","fi","fl","endash","dagger","daggerdbl","periodcentered",
+"paragraph","bullet","quotesinglbase","quotedblbase","quotedblright","guillemotright","ellipsis","perthousand","questiondown","grave",
+"acute","circumflex","tilde","macron","breve","dotaccent","dieresis","ring","cedilla","hungarumlaut","ogonek","caron","emdash","AE",
+"ordfeminine","Lslash","Oslash","OE","ordmasculine","ae","dotlessi","lslash","oslash","oe","germandbls","onesuperior","logicalnot",
+"mu","trademark","Eth","onehalf","plusminus","Thorn","onequarter","divide","brokenbar","degree","thorn","threequarters","twosuperior",
+"registered","minus","eth","multiply","threesuperior","copyright","Aacute","Acircumflex","Adieresis","Agrave","Aring","Atilde",
+"Ccedilla","Eacute","Ecircumflex","Edieresis","Egrave","Iacute","Icircumflex","Idieresis","Igrave","Ntilde","Oacute","Ocircumflex",
+"Odieresis","Ograve","Otilde","Scaron","Uacute","Ucircumflex","Udieresis","Ugrave","Yacute","Ydieresis","Zcaron","aacute",
+"acircumflex","adieresis","agrave","aring","atilde","ccedilla","eacute","ecircumflex","edieresis","egrave","iacute","icircumflex",
+"idieresis","igrave","ntilde","oacute","ocircumflex","odieresis","ograve","otilde","scaron","uacute","ucircumflex","udieresis",
+"ugrave","yacute","ydieresis","zcaron","exclamsmall","Hungarumlautsmall","dollaroldstyle","dollarsuperior","ampersandsmall",
+"Acutesmall","parenleftsuperior","parenrightsuperior","twodotenleader","onedotenleader","zerooldstyle","oneoldstyle","twooldstyle",
+"threeoldstyle","fouroldstyle","fiveoldstyle","sixoldstyle","sevenoldstyle","eightoldstyle","nineoldstyle","commasuperior",
+"threequartersemdash","periodsuperior","questionsmall","asuperior","bsuperior","centsuperior","dsuperior","esuperior","isuperior",
+"lsuperior","msuperior","nsuperior","osuperior","rsuperior","ssuperior","tsuperior","ff","ffi","ffl","parenleftinferior",
+"parenrightinferior","Circumflexsmall","hyphensuperior","Gravesmall","Asmall","Bsmall","Csmall","Dsmall","Esmall","Fsmall",
+"Gsmall","Hsmall","Ismall","Jsmall","Ksmall","Lsmall","Msmall","Nsmall","Osmall","Psmall","Qsmall","Rsmall","Ssmall","Tsmall",
+"Usmall","Vsmall","Wsmall","Xsmall","Ysmall","Zsmall","colonmonetary","onefitted","rupiah","Tildesmall","exclamdownsmall",
+"centoldstyle","Lslashsmall","Scaronsmall","Zcaronsmall","Dieresissmall","Brevesmall","Caronsmall","Dotaccentsmall","Macronsmall",
+"figuredash","hypheninferior","Ogoneksmall","Ringsmall","Cedillasmall","questiondownsmall","oneeighth","threeeighths","fiveeighths",
+"seveneighths","onethird","twothirds","zerosuperior","foursuperior","fivesuperior","sixsuperior","sevensuperior","eightsuperior",
+"ninesuperior","zeroinferior","oneinferior","twoinferior","threeinferior","fourinferior","fiveinferior","sixinferior","seveninferior",
+"eightinferior","nineinferior","centinferior","dollarinferior","periodinferior","commainferior","Agravesmall","Aacutesmall",
+"Acircumflexsmall","Atildesmall","Adieresissmall","Aringsmall","AEsmall","Ccedillasmall","Egravesmall","Eacutesmall",
+"Ecircumflexsmall","Edieresissmall","Igravesmall","Iacutesmall","Icircumflexsmall","Idieresissmall","Ethsmall","Ntildesmall",
+"Ogravesmall","Oacutesmall","Ocircumflexsmall","Otildesmall","Odieresissmall","OEsmall","Oslashsmall","Ugravesmall","Uacutesmall",
+"Ucircumflexsmall","Udieresissmall","Yacutesmall","Thornsmall","Ydieresissmall","001.000","001.001","001.002","001.003","Black",
+"Bold","Book","Light","Medium","Regular","Roman","Semibold"];
+
+var ft_mac_names=[29,0,1,30,31,32,33,34,35,36,133,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,
+66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,153,95,96,97,98,99,100,101,102,103,104,105,106,
+107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,202,204,206,207,215,218,224,229,232,230,231,234,233,235,236,
+239,237,238,240,243,241,242,244,245,248,246,247,249,251,254,252,253,141,190,126,127,131,145,144,178,194,199,182,154,160,2,167,170,3,
+185,4,5,129,181,6,7,8,9,10,168,172,11,173,176,152,125,180,12,130,13,14,135,149,150,15,203,205,220,171,177,140,166,134,148,94,37,188,
+16,256,227,128,132,136,137,138,139,142,143,146,147,151,201,208,200,209,210,211,212,213,214,216,217,17,219,222,223,225,174,155,156,
+157,158,159,161,162,163,164,165,169,175,221,250,228,257,189,183,196,226,255,186,191,195,197,179,193,198,184,187,192,18,19,20,21,22,
+23,24,25,26,27,28];
+
+var ft_sid_names=[29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,
+69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,
+109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,
+142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,
+175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,
+208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,
+241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,
+274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,
+307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,
+340,341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,372,
+373,374,375,376,377,378,379,380,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,400,401,402,403,404,405,
+406,407,408,409,410,411,412,413,414,415,416,417,418,419];
+
+var t1_standard_encoding=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,
+17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,
+33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,
+49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,
+65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,
+81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,
+0,111,112,113,114,0,115,116,117,118,119,120,121,122,0,123,
+0,124,125,126,127,128,129,130,131,0,132,133,0,134,135,136,
+137,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,138,0,139,0,0,0,0,140,141,142,143,0,0,0,0,
+0,144,0,0,0,145,0,0,146,147,148,149,0,0,0,0];
+
+var t1_expert_encoding=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+1,229,230,0,231,232,233,234,235,236,237,238,13,14,15,99,
+239,240,241,242,243,244,245,246,247,248,27,28,249,250,251,252,
+0,253,254,255,256,257,0,0,0,258,0,0,259,260,261,262,
+0,0,263,264,265,0,266,109,110,267,268,269,0,270,271,272,
+273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,
+289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,304,305,306,0,0,307,308,309,310,311,0,312,0,0,313,
+0,0,314,315,0,0,316,317,318,0,0,0,158,155,163,319,
+320,321,322,323,324,325,0,0,326,150,164,169,327,328,329,330,
+331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,
+347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,
+363,364,365,366,367,368,369,370,371,372,373,374,375,376,377,378];
+
+var ft_adobe_glyph_list=[0,52,0,106,2,167,3,63,4,220,6,125,9,143,10,23,
+11,137,12,199,14,246,15,87,16,233,17,219,18,104,19,88,
+22,110,23,32,23,71,24,77,27,156,29,73,31,247,32,107,
+32,222,33,55,34,154,35,218,58,10,64,122,72,188,80,109,
+88,104,93,61,98,168,106,91,114,111,115,237,122,180,127,255,
+135,164,143,132,149,213,158,108,161,115,168,175,183,147,197,199,
+202,25,204,166,208,209,209,81,215,26,65,143,0,65,0,140,
+0,175,0,193,1,15,1,147,1,233,1,251,2,7,2,40,
+2,57,2,82,2,91,2,128,2,136,2,154,69,131,0,198,
+0,150,0,158,0,167,225,227,245,244,101,128,1,252,237,225,
+227,242,239,110,128,1,226,243,237,225,236,108,128,247,230,225,
+227,245,244,101,129,0,193,0,185,243,237,225,236,108,128,247,
+225,226,242,229,246,101,134,1,2,0,213,0,221,0,232,0,
+243,0,251,1,7,225,227,245,244,101,128,30,174,227,249,242,
+233,236,236,233,99,128,4,208,228,239,244,226,229,236,239,119,
+128,30,182,231,242,225,246,101,128,30,176,232,239,239,235,225,
+226,239,246,101,128,30,178,244,233,236,228,101,128,30,180,99,
+4,1,25,1,32,1,121,1,137,225,242,239,110,128,1,205,
+233,242,99,2,1,40,1,45,236,101,128,36,182,245,237,230,
+236,229,120,134,0,194,1,66,1,74,1,85,1,93,1,105,
+1,113,225,227,245,244,101,128,30,164,228,239,244,226,229,236,
+239,119,128,30,172,231,242,225,246,101,128,30,166,232,239,239,
+235,225,226,239,246,101,128,30,168,243,237,225,236,108,128,247,
+226,244,233,236,228,101,128,30,170,245,244,101,129,246,201,1,
+129,243,237,225,236,108,128,247,180,249,242,233,236,236,233,99,
+128,4,16,100,3,1,155,1,165,1,209,226,236,231,242,225,
+246,101,128,2,0,233,229,242,229,243,233,115,131,0,196,1,
+181,1,192,1,201,227,249,242,233,236,236,233,99,128,4,210,
+237,225,227,242,239,110,128,1,222,243,237,225,236,108,128,247,
+228,239,116,2,1,216,1,224,226,229,236,239,119,128,30,160,
+237,225,227,242,239,110,128,1,224,231,242,225,246,101,129,0,
+192,1,243,243,237,225,236,108,128,247,224,232,239,239,235,225,
+226,239,246,101,128,30,162,105,2,2,13,2,25,229,227,249,
+242,233,236,236,233,99,128,4,212,238,246,229,242,244,229,228,
+226,242,229,246,101,128,2,2,236,240,232,97,129,3,145,2,
+49,244,239,238,239,115,128,3,134,109,2,2,63,2,71,225,
+227,242,239,110,128,1,0,239,238,239,243,240,225,227,101,128,
+255,33,239,231,239,238,229,107,128,1,4,242,233,238,103,131,
+0,197,2,104,2,112,2,120,225,227,245,244,101,128,1,250,
+226,229,236,239,119,128,30,0,243,237,225,236,108,128,247,229,
+243,237,225,236,108,128,247,97,244,233,236,228,101,129,0,195,
+2,146,243,237,225,236,108,128,247,227,249,226,225,242,237,229,
+238,233,225,110,128,5,49,66,137,0,66,2,189,2,198,2,
+223,3,3,3,10,3,22,3,34,3,46,3,54,227,233,242,
+227,236,101,128,36,183,228,239,116,2,2,206,2,215,225,227,
+227,229,238,116,128,30,2,226,229,236,239,119,128,30,4,101,
+3,2,231,2,242,2,254,227,249,242,233,236,236,233,99,128,
+4,17,238,225,242,237,229,238,233,225,110,128,5,50,244,97,
+128,3,146,232,239,239,107,128,1,129,236,233,238,229,226,229,
+236,239,119,128,30,6,237,239,238,239,243,240,225,227,101,128,
+255,34,242,229,246,229,243,237,225,236,108,128,246,244,243,237,
+225,236,108,128,247,98,244,239,240,226,225,114,128,1,130,67,
+137,0,67,3,85,3,127,3,193,3,210,3,224,4,171,4,
+188,4,200,4,212,97,3,3,93,3,104,3,111,225,242,237,
+229,238,233,225,110,128,5,62,227,245,244,101,128,1,6,242,
+239,110,129,246,202,3,119,243,237,225,236,108,128,246,245,99,
+3,3,135,3,142,3,171,225,242,239,110,128,1,12,229,228,
+233,236,236,97,130,0,199,3,155,3,163,225,227,245,244,101,
+128,30,8,243,237,225,236,108,128,247,231,233,242,99,2,3,
+179,3,184,236,101,128,36,184,245,237,230,236,229,120,128,1,
+8,228,239,116,129,1,10,3,201,225,227,227,229,238,116,128,
+1,10,229,228,233,236,236,225,243,237,225,236,108,128,247,184,
+104,4,3,234,3,246,4,161,4,165,225,225,242,237,229,238,
+233,225,110,128,5,73,101,6,4,4,4,24,4,35,4,103,
+4,115,4,136,225,226,235,232,225,243,233,225,238,227,249,242,
+233,236,236,233,99,128,4,188,227,249,242,233,236,236,233,99,
+128,4,39,100,2,4,41,4,85,229,243,227,229,238,228,229,
+114,2,4,54,4,74,225,226,235,232,225,243,233,225,238,227,
+249,242,233,236,236,233,99,128,4,190,227,249,242,233,236,236,
+233,99,128,4,182,233,229,242,229,243,233,243,227,249,242,233,
+236,236,233,99,128,4,244,232,225,242,237,229,238,233,225,110,
+128,5,67,235,232,225,235,225,243,243,233,225,238,227,249,242,
+233,236,236,233,99,128,4,203,246,229,242,244,233,227,225,236,
+243,244,242,239,235,229,227,249,242,233,236,236,233,99,128,4,
+184,105,128,3,167,239,239,107,128,1,135,233,242,227,245,237,
+230,236,229,248,243,237,225,236,108,128,246,246,237,239,238,239,
+243,240,225,227,101,128,255,35,239,225,242,237,229,238,233,225,
+110,128,5,81,243,237,225,236,108,128,247,99,68,142,0,68,
+4,252,5,10,5,36,5,96,5,121,5,166,5,173,5,231,
+5,244,6,0,6,12,6,28,6,48,6,57,90,129,1,241,
+5,2,227,225,242,239,110,128,1,196,97,2,5,16,5,27,
+225,242,237,229,238,233,225,110,128,5,52,230,242,233,227,225,
+110,128,1,137,99,4,5,46,5,53,5,62,5,89,225,242,
+239,110,128,1,14,229,228,233,236,236,97,128,30,16,233,242,
+99,2,5,70,5,75,236,101,128,36,185,245,237,230,236,229,
+248,226,229,236,239,119,128,30,18,242,239,225,116,128,1,16,
+228,239,116,2,5,104,5,113,225,227,227,229,238,116,128,30,
+10,226,229,236,239,119,128,30,12,101,3,5,129,5,140,5,
+150,227,249,242,233,236,236,233,99,128,4,20,233,227,239,240,
+244,233,99,128,3,238,236,244,97,129,34,6,5,158,231,242,
+229,229,107,128,3,148,232,239,239,107,128,1,138,105,2,5,
+179,5,218,229,242,229,243,233,115,131,246,203,5,194,5,202,
+5,210,193,227,245,244,101,128,246,204,199,242,225,246,101,128,
+246,205,243,237,225,236,108,128,247,168,231,225,237,237,225,231,
+242,229,229,107,128,3,220,234,229,227,249,242,233,236,236,233,
+99,128,4,2,236,233,238,229,226,229,236,239,119,128,30,14,
+237,239,238,239,243,240,225,227,101,128,255,36,239,244,225,227,
+227,229,238,244,243,237,225,236,108,128,246,247,115,2,6,34,
+6,41,236,225,243,104,128,1,16,237,225,236,108,128,247,100,
+244,239,240,226,225,114,128,1,139,122,131,1,242,6,67,6,
+75,6,112,227,225,242,239,110,128,1,197,101,2,6,81,6,
+101,225,226,235,232,225,243,233,225,238,227,249,242,233,236,236,
+233,99,128,4,224,227,249,242,233,236,236,233,99,128,4,5,
+232,229,227,249,242,233,236,236,233,99,128,4,15,69,146,0,
+69,6,165,6,183,6,191,7,89,7,153,7,165,7,183,7,
+211,8,7,8,36,8,94,8,169,8,189,8,208,8,248,9,
+44,9,109,9,115,225,227,245,244,101,129,0,201,6,175,243,
+237,225,236,108,128,247,233,226,242,229,246,101,128,1,20,99,
+5,6,203,6,210,6,224,6,236,7,79,225,242,239,110,128,
+1,26,229,228,233,236,236,225,226,242,229,246,101,128,30,28,
+232,225,242,237,229,238,233,225,110,128,5,53,233,242,99,2,
+6,244,6,249,236,101,128,36,186,245,237,230,236,229,120,135,
+0,202,7,16,7,24,7,32,7,43,7,51,7,63,7,71,
+225,227,245,244,101,128,30,190,226,229,236,239,119,128,30,24,
+228,239,244,226,229,236,239,119,128,30,198,231,242,225,246,101,
+128,30,192,232,239,239,235,225,226,239,246,101,128,30,194,243,
+237,225,236,108,128,247,234,244,233,236,228,101,128,30,196,249,
+242,233,236,236,233,99,128,4,4,100,3,7,97,7,107,7,
+127,226,236,231,242,225,246,101,128,2,4,233,229,242,229,243,
+233,115,129,0,203,7,119,243,237,225,236,108,128,247,235,239,
+116,130,1,22,7,136,7,145,225,227,227,229,238,116,128,1,
+22,226,229,236,239,119,128,30,184,230,227,249,242,233,236,236,
+233,99,128,4,36,231,242,225,246,101,129,0,200,7,175,243,
+237,225,236,108,128,247,232,104,2,7,189,7,200,225,242,237,
+229,238,233,225,110,128,5,55,239,239,235,225,226,239,246,101,
+128,30,186,105,3,7,219,7,230,7,245,231,232,244,242,239,
+237,225,110,128,33,103,238,246,229,242,244,229,228,226,242,229,
+246,101,128,2,6,239,244,233,230,233,229,228,227,249,242,233,
+236,236,233,99,128,4,100,108,2,8,13,8,24,227,249,242,
+233,236,236,233,99,128,4,27,229,246,229,238,242,239,237,225,
+110,128,33,106,109,3,8,44,8,72,8,83,225,227,242,239,
+110,130,1,18,8,56,8,64,225,227,245,244,101,128,30,22,
+231,242,225,246,101,128,30,20,227,249,242,233,236,236,233,99,
+128,4,28,239,238,239,243,240,225,227,101,128,255,37,110,4,
+8,104,8,115,8,135,8,154,227,249,242,233,236,236,233,99,
+128,4,29,228,229,243,227,229,238,228,229,242,227,249,242,233,
+236,236,233,99,128,4,162,103,129,1,74,8,141,232,229,227,
+249,242,233,236,236,233,99,128,4,164,232,239,239,235,227,249,
+242,233,236,236,233,99,128,4,199,111,2,8,175,8,183,231,
+239,238,229,107,128,1,24,240,229,110,128,1,144,240,243,233,
+236,239,110,129,3,149,8,200,244,239,238,239,115,128,3,136,
+114,2,8,214,8,225,227,249,242,233,236,236,233,99,128,4,
+32,229,246,229,242,243,229,100,129,1,142,8,237,227,249,242,
+233,236,236,233,99,128,4,45,115,4,9,2,9,13,9,33,
+9,37,227,249,242,233,236,236,233,99,128,4,33,228,229,243,
+227,229,238,228,229,242,227,249,242,233,236,236,233,99,128,4,
+170,104,128,1,169,237,225,236,108,128,247,101,116,3,9,52,
+9,78,9,92,97,130,3,151,9,60,9,70,242,237,229,238,
+233,225,110,128,5,56,244,239,238,239,115,128,3,137,104,129,
+0,208,9,84,243,237,225,236,108,128,247,240,233,236,228,101,
+129,30,188,9,101,226,229,236,239,119,128,30,26,245,242,111,
+128,32,172,250,104,130,1,183,9,124,9,132,227,225,242,239,
+110,128,1,238,242,229,246,229,242,243,229,100,128,1,184,70,
+136,0,70,9,163,9,172,9,184,9,212,9,219,9,248,10,
+4,10,15,227,233,242,227,236,101,128,36,187,228,239,244,225,
+227,227,229,238,116,128,30,30,101,2,9,190,9,202,232,225,
+242,237,229,238,233,225,110,128,5,86,233,227,239,240,244,233,
+99,128,3,228,232,239,239,107,128,1,145,105,2,9,225,9,
+238,244,225,227,249,242,233,236,236,233,99,128,4,114,246,229,
+242,239,237,225,110,128,33,100,237,239,238,239,243,240,225,227,
+101,128,255,38,239,245,242,242,239,237,225,110,128,33,99,243,
+237,225,236,108,128,247,102,71,140,0,71,10,51,10,61,10,
+107,10,115,10,176,10,193,10,205,11,39,11,52,11,65,11,
+90,11,107,194,243,241,245,225,242,101,128,51,135,97,3,10,
+69,10,76,10,94,227,245,244,101,128,1,244,237,237,97,129,
+3,147,10,84,225,230,242,233,227,225,110,128,1,148,238,231,
+233,225,227,239,240,244,233,99,128,3,234,226,242,229,246,101,
+128,1,30,99,4,10,125,10,132,10,141,10,163,225,242,239,
+110,128,1,230,229,228,233,236,236,97,128,1,34,233,242,99,
+2,10,149,10,154,236,101,128,36,188,245,237,230,236,229,120,
+128,1,28,239,237,237,225,225,227,227,229,238,116,128,1,34,
+228,239,116,129,1,32,10,184,225,227,227,229,238,116,128,1,
+32,229,227,249,242,233,236,236,233,99,128,4,19,104,3,10,
+213,10,226,11,33,225,228,225,242,237,229,238,233,225,110,128,
+5,66,101,3,10,234,10,255,11,16,237,233,228,228,236,229,
+232,239,239,235,227,249,242,233,236,236,233,99,128,4,148,243,
+244,242,239,235,229,227,249,242,233,236,236,233,99,128,4,146,
+245,240,244,245,242,238,227,249,242,233,236,236,233,99,128,4,
+144,239,239,107,128,1,147,233,237,225,242,237,229,238,233,225,
+110,128,5,51,234,229,227,249,242,233,236,236,233,99,128,4,
+3,109,2,11,71,11,79,225,227,242,239,110,128,30,32,239,
+238,239,243,240,225,227,101,128,255,39,242,225,246,101,129,246,
+206,11,99,243,237,225,236,108,128,247,96,115,2,11,113,11,
+129,237,225,236,108,129,247,103,11,122,232,239,239,107,128,2,
+155,244,242,239,235,101,128,1,228,72,140,0,72,11,165,11,
+190,11,198,11,208,12,17,12,40,12,77,12,117,12,129,12,
+157,12,165,12,189,177,184,53,3,11,175,11,180,11,185,179,
+51,128,37,207,180,51,128,37,170,181,49,128,37,171,178,178,
+176,183,51,128,37,161,208,243,241,245,225,242,101,128,51,203,
+97,3,11,216,11,236,12,0,225,226,235,232,225,243,233,225,
+238,227,249,242,233,236,236,233,99,128,4,168,228,229,243,227,
+229,238,228,229,242,227,249,242,233,236,236,233,99,128,4,178,
+242,228,243,233,231,238,227,249,242,233,236,236,233,99,128,4,
+42,98,2,12,23,12,28,225,114,128,1,38,242,229,246,229,
+226,229,236,239,119,128,30,42,99,2,12,46,12,55,229,228,
+233,236,236,97,128,30,40,233,242,99,2,12,63,12,68,236,
+101,128,36,189,245,237,230,236,229,120,128,1,36,100,2,12,
+83,12,93,233,229,242,229,243,233,115,128,30,38,239,116,2,
+12,100,12,109,225,227,227,229,238,116,128,30,34,226,229,236,
+239,119,128,30,36,237,239,238,239,243,240,225,227,101,128,255,
+40,111,2,12,135,12,146,225,242,237,229,238,233,225,110,128,
+5,64,242,233,227,239,240,244,233,99,128,3,232,243,237,225,
+236,108,128,247,104,245,238,231,225,242,245,237,236,225,245,116,
+129,246,207,12,181,243,237,225,236,108,128,246,248,250,243,241,
+245,225,242,101,128,51,144,73,146,0,73,12,239,12,251,12,
+255,13,11,13,29,13,37,13,94,13,181,13,214,13,224,13,
+242,13,254,14,48,14,86,14,99,14,166,14,187,14,205,193,
+227,249,242,233,236,236,233,99,128,4,47,74,128,1,50,213,
+227,249,242,233,236,236,233,99,128,4,46,225,227,245,244,101,
+129,0,205,13,21,243,237,225,236,108,128,247,237,226,242,229,
+246,101,128,1,44,99,3,13,45,13,52,13,84,225,242,239,
+110,128,1,207,233,242,99,2,13,60,13,65,236,101,128,36,
+190,245,237,230,236,229,120,129,0,206,13,76,243,237,225,236,
+108,128,247,238,249,242,233,236,236,233,99,128,4,6,100,3,
+13,102,13,112,13,155,226,236,231,242,225,246,101,128,2,8,
+233,229,242,229,243,233,115,131,0,207,13,128,13,136,13,147,
+225,227,245,244,101,128,30,46,227,249,242,233,236,236,233,99,
+128,4,228,243,237,225,236,108,128,247,239,239,116,130,1,48,
+13,164,13,173,225,227,227,229,238,116,128,1,48,226,229,236,
+239,119,128,30,202,101,2,13,187,13,203,226,242,229,246,229,
+227,249,242,233,236,236,233,99,128,4,214,227,249,242,233,236,
+236,233,99,128,4,21,230,242,225,235,244,245,114,128,33,17,
+231,242,225,246,101,129,0,204,13,234,243,237,225,236,108,128,
+247,236,232,239,239,235,225,226,239,246,101,128,30,200,105,3,
+14,6,14,17,14,32,227,249,242,233,236,236,233,99,128,4,
+24,238,246,229,242,244,229,228,226,242,229,246,101,128,2,10,
+243,232,239,242,244,227,249,242,233,236,236,233,99,128,4,25,
+109,2,14,54,14,75,225,227,242,239,110,129,1,42,14,64,
+227,249,242,233,236,236,233,99,128,4,226,239,238,239,243,240,
+225,227,101,128,255,41,238,233,225,242,237,229,238,233,225,110,
+128,5,59,111,3,14,107,14,118,14,126,227,249,242,233,236,
+236,233,99,128,4,1,231,239,238,229,107,128,1,46,244,97,
+131,3,153,14,137,14,147,14,158,225,230,242,233,227,225,110,
+128,1,150,228,233,229,242,229,243,233,115,128,3,170,244,239,
+238,239,115,128,3,138,115,2,14,172,14,179,237,225,236,108,
+128,247,105,244,242,239,235,101,128,1,151,244,233,236,228,101,
+129,1,40,14,197,226,229,236,239,119,128,30,44,250,232,233,
+244,243,97,2,14,216,14,227,227,249,242,233,236,236,233,99,
+128,4,116,228,226,236,231,242,225,246,229,227,249,242,233,236,
+236,233,99,128,4,118,74,134,0,74,15,6,15,18,15,41,
+15,53,15,67,15,79,225,225,242,237,229,238,233,225,110,128,
+5,65,227,233,242,99,2,15,27,15,32,236,101,128,36,191,
+245,237,230,236,229,120,128,1,52,229,227,249,242,233,236,236,
+233,99,128,4,8,232,229,232,225,242,237,229,238,233,225,110,
+128,5,75,237,239,238,239,243,240,225,227,101,128,255,42,243,
+237,225,236,108,128,247,106,75,140,0,75,15,115,15,125,15,
+135,16,18,16,65,16,76,16,106,16,143,16,156,16,168,16,
+180,16,208,194,243,241,245,225,242,101,128,51,133,203,243,241,
+245,225,242,101,128,51,205,97,7,15,151,15,169,15,191,15,
+211,15,226,15,232,15,249,226,225,243,232,235,233,242,227,249,
+242,233,236,236,233,99,128,4,160,99,2,15,175,15,181,245,
+244,101,128,30,48,249,242,233,236,236,233,99,128,4,26,228,
+229,243,227,229,238,228,229,242,227,249,242,233,236,236,233,99,
+128,4,154,232,239,239,235,227,249,242,233,236,236,233,99,128,
+4,195,240,240,97,128,3,154,243,244,242,239,235,229,227,249,
+242,233,236,236,233,99,128,4,158,246,229,242,244,233,227,225,
+236,243,244,242,239,235,229,227,249,242,233,236,236,233,99,128,
+4,156,99,4,16,28,16,35,16,44,16,52,225,242,239,110,
+128,1,232,229,228,233,236,236,97,128,1,54,233,242,227,236,
+101,128,36,192,239,237,237,225,225,227,227,229,238,116,128,1,
+54,228,239,244,226,229,236,239,119,128,30,50,101,2,16,82,
+16,94,232,225,242,237,229,238,233,225,110,128,5,84,238,225,
+242,237,229,238,233,225,110,128,5,63,104,3,16,114,16,126,
+16,137,225,227,249,242,233,236,236,233,99,128,4,37,229,233,
+227,239,240,244,233,99,128,3,230,239,239,107,128,1,152,234,
+229,227,249,242,233,236,236,233,99,128,4,12,236,233,238,229,
+226,229,236,239,119,128,30,52,237,239,238,239,243,240,225,227,
+101,128,255,43,239,240,240,97,2,16,189,16,200,227,249,242,
+233,236,236,233,99,128,4,128,231,242,229,229,107,128,3,222,
+115,2,16,214,16,226,233,227,249,242,233,236,236,233,99,128,
+4,110,237,225,236,108,128,247,107,76,138,0,76,17,1,17,
+5,17,9,17,29,17,95,17,133,17,147,17,165,17,177,17,
+189,74,128,1,199,76,128,246,191,97,2,17,15,17,22,227,
+245,244,101,128,1,57,237,226,228,97,128,3,155,99,4,17,
+39,17,46,17,55,17,82,225,242,239,110,128,1,61,229,228,
+233,236,236,97,128,1,59,233,242,99,2,17,63,17,68,236,
+101,128,36,193,245,237,230,236,229,248,226,229,236,239,119,128,
+30,60,239,237,237,225,225,227,227,229,238,116,128,1,59,228,
+239,116,130,1,63,17,105,17,114,225,227,227,229,238,116,128,
+1,63,226,229,236,239,119,129,30,54,17,124,237,225,227,242,
+239,110,128,30,56,233,247,238,225,242,237,229,238,233,225,110,
+128,5,60,106,129,1,200,17,153,229,227,249,242,233,236,236,
+233,99,128,4,9,236,233,238,229,226,229,236,239,119,128,30,
+58,237,239,238,239,243,240,225,227,101,128,255,44,115,2,17,
+195,17,212,236,225,243,104,129,1,65,17,204,243,237,225,236,
+108,128,246,249,237,225,236,108,128,247,108,77,137,0,77,17,
+241,17,251,18,24,18,33,18,58,18,71,18,83,18,91,18,
+100,194,243,241,245,225,242,101,128,51,134,225,99,2,18,2,
+18,18,242,239,110,129,246,208,18,10,243,237,225,236,108,128,
+247,175,245,244,101,128,30,62,227,233,242,227,236,101,128,36,
+194,228,239,116,2,18,41,18,50,225,227,227,229,238,116,128,
+30,64,226,229,236,239,119,128,30,66,229,238,225,242,237,229,
+238,233,225,110,128,5,68,237,239,238,239,243,240,225,227,101,
+128,255,45,243,237,225,236,108,128,247,109,244,245,242,238,229,
+100,128,1,156,117,128,3,156,78,141,0,78,18,134,18,138,
+18,146,18,212,18,237,18,248,19,3,19,21,19,33,19,45,
+19,58,19,66,19,84,74,128,1,202,225,227,245,244,101,128,
+1,67,99,4,18,156,18,163,18,172,18,199,225,242,239,110,
+128,1,71,229,228,233,236,236,97,128,1,69,233,242,99,2,
+18,180,18,185,236,101,128,36,195,245,237,230,236,229,248,226,
+229,236,239,119,128,30,74,239,237,237,225,225,227,227,229,238,
+116,128,1,69,228,239,116,2,18,220,18,229,225,227,227,229,
+238,116,128,30,68,226,229,236,239,119,128,30,70,232,239,239,
+235,236,229,230,116,128,1,157,233,238,229,242,239,237,225,110,
+128,33,104,106,129,1,203,19,9,229,227,249,242,233,236,236,
+233,99,128,4,10,236,233,238,229,226,229,236,239,119,128,30,
+72,237,239,238,239,243,240,225,227,101,128,255,46,239,247,225,
+242,237,229,238,233,225,110,128,5,70,243,237,225,236,108,128,
+247,110,244,233,236,228,101,129,0,209,19,76,243,237,225,236,
+108,128,247,241,117,128,3,157,79,141,0,79,19,118,19,132,
+19,150,19,203,20,78,20,152,20,187,21,48,21,69,21,213,
+21,223,21,254,22,53,69,129,1,82,19,124,243,237,225,236,
+108,128,246,250,225,227,245,244,101,129,0,211,19,142,243,237,
+225,236,108,128,247,243,98,2,19,156,19,196,225,242,242,229,
+100,2,19,166,19,177,227,249,242,233,236,236,233,99,128,4,
+232,228,233,229,242,229,243,233,243,227,249,242,233,236,236,233,
+99,128,4,234,242,229,246,101,128,1,78,99,4,19,213,19,
+220,19,235,20,68,225,242,239,110,128,1,209,229,238,244,229,
+242,229,228,244,233,236,228,101,128,1,159,233,242,99,2,19,
+243,19,248,236,101,128,36,196,245,237,230,236,229,120,134,0,
+212,20,13,20,21,20,32,20,40,20,52,20,60,225,227,245,
+244,101,128,30,208,228,239,244,226,229,236,239,119,128,30,216,
+231,242,225,246,101,128,30,210,232,239,239,235,225,226,239,246,
+101,128,30,212,243,237,225,236,108,128,247,244,244,233,236,228,
+101,128,30,214,249,242,233,236,236,233,99,128,4,30,100,3,
+20,86,20,109,20,142,226,108,2,20,93,20,101,225,227,245,
+244,101,128,1,80,231,242,225,246,101,128,2,12,233,229,242,
+229,243,233,115,130,0,214,20,123,20,134,227,249,242,233,236,
+236,233,99,128,4,230,243,237,225,236,108,128,247,246,239,244,
+226,229,236,239,119,128,30,204,103,2,20,158,20,170,239,238,
+229,235,243,237,225,236,108,128,246,251,242,225,246,101,129,0,
+210,20,179,243,237,225,236,108,128,247,242,104,4,20,197,20,
+208,20,212,21,34,225,242,237,229,238,233,225,110,128,5,85,
+109,128,33,38,111,2,20,218,20,228,239,235,225,226,239,246,
+101,128,30,206,242,110,133,1,160,20,243,20,251,21,6,21,
+14,21,26,225,227,245,244,101,128,30,218,228,239,244,226,229,
+236,239,119,128,30,226,231,242,225,246,101,128,30,220,232,239,
+239,235,225,226,239,246,101,128,30,222,244,233,236,228,101,128,
+30,224,245,238,231,225,242,245,237,236,225,245,116,128,1,80,
+105,129,1,162,21,54,238,246,229,242,244,229,228,226,242,229,
+246,101,128,2,14,109,4,21,79,21,107,21,184,21,202,225,
+227,242,239,110,130,1,76,21,91,21,99,225,227,245,244,101,
+128,30,82,231,242,225,246,101,128,30,80,229,231,97,132,33,
+38,21,121,21,132,21,140,21,156,227,249,242,233,236,236,233,
+99,128,4,96,231,242,229,229,107,128,3,169,242,239,245,238,
+228,227,249,242,233,236,236,233,99,128,4,122,116,2,21,162,
+21,177,233,244,236,239,227,249,242,233,236,236,233,99,128,4,
+124,239,238,239,115,128,3,143,233,227,242,239,110,129,3,159,
+21,194,244,239,238,239,115,128,3,140,239,238,239,243,240,225,
+227,101,128,255,47,238,229,242,239,237,225,110,128,33,96,111,
+2,21,229,21,248,231,239,238,229,107,129,1,234,21,239,237,
+225,227,242,239,110,128,1,236,240,229,110,128,1,134,115,3,
+22,6,22,33,22,40,236,225,243,104,130,0,216,22,17,22,
+25,225,227,245,244,101,128,1,254,243,237,225,236,108,128,247,
+248,237,225,236,108,128,247,111,244,242,239,235,229,225,227,245,
+244,101,128,1,254,116,2,22,59,22,70,227,249,242,233,236,
+236,233,99,128,4,126,233,236,228,101,131,0,213,22,83,22,
+91,22,102,225,227,245,244,101,128,30,76,228,233,229,242,229,
+243,233,115,128,30,78,243,237,225,236,108,128,247,245,80,136,
+0,80,22,130,22,138,22,147,22,159,22,211,22,227,22,246,
+23,2,225,227,245,244,101,128,30,84,227,233,242,227,236,101,
+128,36,197,228,239,244,225,227,227,229,238,116,128,30,86,101,
+3,22,167,22,178,22,190,227,249,242,233,236,236,233,99,128,
+4,31,232,225,242,237,229,238,233,225,110,128,5,74,237,233,
+228,228,236,229,232,239,239,235,227,249,242,233,236,236,233,99,
+128,4,166,104,2,22,217,22,221,105,128,3,166,239,239,107,
+128,1,164,105,129,3,160,22,233,247,242,225,242,237,229,238,
+233,225,110,128,5,83,237,239,238,239,243,240,225,227,101,128,
+255,48,115,2,23,8,23,25,105,129,3,168,23,14,227,249,
+242,233,236,236,233,99,128,4,112,237,225,236,108,128,247,112,
+81,131,0,81,23,42,23,51,23,63,227,233,242,227,236,101,
+128,36,198,237,239,238,239,243,240,225,227,101,128,255,49,243,
+237,225,236,108,128,247,113,82,138,0,82,23,95,23,119,23,
+166,23,217,23,230,23,240,23,245,24,19,24,31,24,43,97,
+2,23,101,23,112,225,242,237,229,238,233,225,110,128,5,76,
+227,245,244,101,128,1,84,99,4,23,129,23,136,23,145,23,
+153,225,242,239,110,128,1,88,229,228,233,236,236,97,128,1,
+86,233,242,227,236,101,128,36,199,239,237,237,225,225,227,227,
+229,238,116,128,1,86,100,2,23,172,23,182,226,236,231,242,
+225,246,101,128,2,16,239,116,2,23,189,23,198,225,227,227,
+229,238,116,128,30,88,226,229,236,239,119,129,30,90,23,208,
+237,225,227,242,239,110,128,30,92,229,232,225,242,237,229,238,
+233,225,110,128,5,80,230,242,225,235,244,245,114,128,33,28,
+232,111,128,3,161,233,110,2,23,252,24,5,231,243,237,225,
+236,108,128,246,252,246,229,242,244,229,228,226,242,229,246,101,
+128,2,18,236,233,238,229,226,229,236,239,119,128,30,94,237,
+239,238,239,243,240,225,227,101,128,255,50,243,237,225,236,108,
+129,247,114,24,53,233,238,246,229,242,244,229,100,129,2,129,
+24,66,243,245,240,229,242,233,239,114,128,2,182,83,139,0,
+83,24,103,26,17,26,55,26,182,26,221,26,250,27,84,27,
+105,27,117,27,135,27,143,70,6,24,117,24,209,24,241,25,
+77,25,119,25,221,48,9,24,137,24,145,24,153,24,161,24,
+169,24,177,24,185,24,193,24,201,177,176,176,176,48,128,37,
+12,178,176,176,176,48,128,37,20,179,176,176,176,48,128,37,
+16,180,176,176,176,48,128,37,24,181,176,176,176,48,128,37,
+60,182,176,176,176,48,128,37,44,183,176,176,176,48,128,37,
+52,184,176,176,176,48,128,37,28,185,176,176,176,48,128,37,
+36,49,3,24,217,24,225,24,233,176,176,176,176,48,128,37,
+0,177,176,176,176,48,128,37,2,185,176,176,176,48,128,37,
+97,50,9,25,5,25,13,25,21,25,29,25,37,25,45,25,
+53,25,61,25,69,176,176,176,176,48,128,37,98,177,176,176,
+176,48,128,37,86,178,176,176,176,48,128,37,85,179,176,176,
+176,48,128,37,99,180,176,176,176,48,128,37,81,181,176,176,
+176,48,128,37,87,182,176,176,176,48,128,37,93,183,176,176,
+176,48,128,37,92,184,176,176,176,48,128,37,91,51,4,25,
+87,25,95,25,103,25,111,182,176,176,176,48,128,37,94,183,
+176,176,176,48,128,37,95,184,176,176,176,48,128,37,90,185,
+176,176,176,48,128,37,84,52,10,25,141,25,149,25,157,25,
+165,25,173,25,181,25,189,25,197,25,205,25,213,176,176,176,
+176,48,128,37,105,177,176,176,176,48,128,37,102,178,176,176,
+176,48,128,37,96,179,176,176,176,48,128,37,80,180,176,176,
+176,48,128,37,108,181,176,176,176,48,128,37,103,182,176,176,
+176,48,128,37,104,183,176,176,176,48,128,37,100,184,176,176,
+176,48,128,37,101,185,176,176,176,48,128,37,89,53,5,25,
+233,25,241,25,249,26,1,26,9,176,176,176,176,48,128,37,
+88,177,176,176,176,48,128,37,82,178,176,176,176,48,128,37,
+83,179,176,176,176,48,128,37,107,180,176,176,176,48,128,37,
+106,97,2,26,23,26,44,227,245,244,101,129,1,90,26,32,
+228,239,244,225,227,227,229,238,116,128,30,100,237,240,233,231,
+242,229,229,107,128,3,224,99,5,26,67,26,98,26,107,26,
+147,26,169,225,242,239,110,130,1,96,26,78,26,90,228,239,
+244,225,227,227,229,238,116,128,30,102,243,237,225,236,108,128,
+246,253,229,228,233,236,236,97,128,1,94,232,247,97,130,1,
+143,26,117,26,128,227,249,242,233,236,236,233,99,128,4,216,
+228,233,229,242,229,243,233,243,227,249,242,233,236,236,233,99,
+128,4,218,233,242,99,2,26,155,26,160,236,101,128,36,200,
+245,237,230,236,229,120,128,1,92,239,237,237,225,225,227,227,
+229,238,116,128,2,24,228,239,116,2,26,190,26,199,225,227,
+227,229,238,116,128,30,96,226,229,236,239,119,129,30,98,26,
+209,228,239,244,225,227,227,229,238,116,128,30,104,101,2,26,
+227,26,239,232,225,242,237,229,238,233,225,110,128,5,77,246,
+229,238,242,239,237,225,110,128,33,102,104,5,27,6,27,34,
+27,48,27,59,27,72,97,2,27,12,27,23,225,242,237,229,
+238,233,225,110,128,5,71,227,249,242,233,236,236,233,99,128,
+4,40,227,232,225,227,249,242,233,236,236,233,99,128,4,41,
+229,233,227,239,240,244,233,99,128,3,226,232,225,227,249,242,
+233,236,236,233,99,128,4,186,233,237,225,227,239,240,244,233,
+99,128,3,236,105,2,27,90,27,96,231,237,97,128,3,163,
+248,242,239,237,225,110,128,33,101,237,239,238,239,243,240,225,
+227,101,128,255,51,239,230,244,243,233,231,238,227,249,242,233,
+236,236,233,99,128,4,44,243,237,225,236,108,128,247,115,244,
+233,231,237,225,231,242,229,229,107,128,3,218,84,141,0,84,
+27,186,27,191,27,197,28,7,28,32,28,96,28,147,28,177,
+28,189,28,201,28,246,29,6,29,46,225,117,128,3,164,226,
+225,114,128,1,102,99,4,27,207,27,214,27,223,27,250,225,
+242,239,110,128,1,100,229,228,233,236,236,97,128,1,98,233,
+242,99,2,27,231,27,236,236,101,128,36,201,245,237,230,236,
+229,248,226,229,236,239,119,128,30,112,239,237,237,225,225,227,
+227,229,238,116,128,1,98,228,239,116,2,28,15,28,24,225,
+227,227,229,238,116,128,30,106,226,229,236,239,119,128,30,108,
+101,4,28,42,28,53,28,73,28,82,227,249,242,233,236,236,
+233,99,128,4,34,228,229,243,227,229,238,228,229,242,227,249,
+242,233,236,236,233,99,128,4,172,238,242,239,237,225,110,128,
+33,105,244,243,229,227,249,242,233,236,236,233,99,128,4,180,
+104,3,28,104,28,110,28,136,229,244,97,128,3,152,111,2,
+28,116,28,121,239,107,128,1,172,242,110,129,0,222,28,128,
+243,237,225,236,108,128,247,254,242,229,229,242,239,237,225,110,
+128,33,98,105,2,28,153,28,164,236,228,229,243,237,225,236,
+108,128,246,254,247,238,225,242,237,229,238,233,225,110,128,5,
+79,236,233,238,229,226,229,236,239,119,128,30,110,237,239,238,
+239,243,240,225,227,101,128,255,52,111,2,28,207,28,218,225,
+242,237,229,238,233,225,110,128,5,57,238,101,3,28,227,28,
+234,28,240,230,233,246,101,128,1,188,243,233,120,128,1,132,
+244,247,111,128,1,167,242,229,244,242,239,230,236,229,248,232,
+239,239,107,128,1,174,115,3,29,14,29,26,29,39,229,227,
+249,242,233,236,236,233,99,128,4,38,232,229,227,249,242,233,
+236,236,233,99,128,4,11,237,225,236,108,128,247,116,119,2,
+29,52,29,64,229,236,246,229,242,239,237,225,110,128,33,107,
+239,242,239,237,225,110,128,33,97,85,142,0,85,29,105,29,
+123,29,131,29,198,30,69,30,87,30,198,30,214,30,226,31,
+21,31,30,31,142,31,149,31,219,225,227,245,244,101,129,0,
+218,29,115,243,237,225,236,108,128,247,250,226,242,229,246,101,
+128,1,108,99,3,29,139,29,146,29,188,225,242,239,110,128,
+1,211,233,242,99,2,29,154,29,159,236,101,128,36,202,245,
+237,230,236,229,120,130,0,219,29,172,29,180,226,229,236,239,
+119,128,30,118,243,237,225,236,108,128,247,251,249,242,233,236,
+236,233,99,128,4,35,100,3,29,206,29,229,30,59,226,108,
+2,29,213,29,221,225,227,245,244,101,128,1,112,231,242,225,
+246,101,128,2,20,233,229,242,229,243,233,115,134,0,220,29,
+251,30,3,30,11,30,34,30,42,30,51,225,227,245,244,101,
+128,1,215,226,229,236,239,119,128,30,114,99,2,30,17,30,
+24,225,242,239,110,128,1,217,249,242,233,236,236,233,99,128,
+4,240,231,242,225,246,101,128,1,219,237,225,227,242,239,110,
+128,1,213,243,237,225,236,108,128,247,252,239,244,226,229,236,
+239,119,128,30,228,231,242,225,246,101,129,0,217,30,79,243,
+237,225,236,108,128,247,249,104,2,30,93,30,171,111,2,30,
+99,30,109,239,235,225,226,239,246,101,128,30,230,242,110,133,
+1,175,30,124,30,132,30,143,30,151,30,163,225,227,245,244,
+101,128,30,232,228,239,244,226,229,236,239,119,128,30,240,231,
+242,225,246,101,128,30,234,232,239,239,235,225,226,239,246,101,
+128,30,236,244,233,236,228,101,128,30,238,245,238,231,225,242,
+245,237,236,225,245,116,129,1,112,30,187,227,249,242,233,236,
+236,233,99,128,4,242,233,238,246,229,242,244,229,228,226,242,
+229,246,101,128,2,22,235,227,249,242,233,236,236,233,99,128,
+4,120,109,2,30,232,31,10,225,227,242,239,110,130,1,106,
+30,244,30,255,227,249,242,233,236,236,233,99,128,4,238,228,
+233,229,242,229,243,233,115,128,30,122,239,238,239,243,240,225,
+227,101,128,255,53,239,231,239,238,229,107,128,1,114,240,243,
+233,236,239,110,133,3,165,31,49,31,53,31,90,31,121,31,
+134,49,128,3,210,97,2,31,59,31,81,227,245,244,229,232,
+239,239,235,243,249,237,226,239,236,231,242,229,229,107,128,3,
+211,230,242,233,227,225,110,128,1,177,228,233,229,242,229,243,
+233,115,129,3,171,31,103,232,239,239,235,243,249,237,226,239,
+236,231,242,229,229,107,128,3,212,232,239,239,235,243,249,237,
+226,239,108,128,3,210,244,239,238,239,115,128,3,142,242,233,
+238,103,128,1,110,115,3,31,157,31,172,31,179,232,239,242,
+244,227,249,242,233,236,236,233,99,128,4,14,237,225,236,108,
+128,247,117,244,242,225,233,231,232,116,2,31,191,31,202,227,
+249,242,233,236,236,233,99,128,4,174,243,244,242,239,235,229,
+227,249,242,233,236,236,233,99,128,4,176,244,233,236,228,101,
+130,1,104,31,231,31,239,225,227,245,244,101,128,30,120,226,
+229,236,239,119,128,30,116,86,136,0,86,32,11,32,20,32,
+31,32,60,32,67,32,79,32,91,32,99,227,233,242,227,236,
+101,128,36,203,228,239,244,226,229,236,239,119,128,30,126,101,
+2,32,37,32,48,227,249,242,233,236,236,233,99,128,4,18,
+247,225,242,237,229,238,233,225,110,128,5,78,232,239,239,107,
+128,1,178,237,239,238,239,243,240,225,227,101,128,255,54,239,
+225,242,237,229,238,233,225,110,128,5,72,243,237,225,236,108,
+128,247,118,244,233,236,228,101,128,30,124,87,134,0,87,32,
+123,32,131,32,154,32,194,32,202,32,214,225,227,245,244,101,
+128,30,130,227,233,242,99,2,32,140,32,145,236,101,128,36,
+204,245,237,230,236,229,120,128,1,116,100,2,32,160,32,170,
+233,229,242,229,243,233,115,128,30,132,239,116,2,32,177,32,
+186,225,227,227,229,238,116,128,30,134,226,229,236,239,119,128,
+30,136,231,242,225,246,101,128,30,128,237,239,238,239,243,240,
+225,227,101,128,255,55,243,237,225,236,108,128,247,119,88,134,
+0,88,32,238,32,247,33,18,33,31,33,35,33,47,227,233,
+242,227,236,101,128,36,205,100,2,32,253,33,7,233,229,242,
+229,243,233,115,128,30,140,239,244,225,227,227,229,238,116,128,
+30,138,229,232,225,242,237,229,238,233,225,110,128,5,61,105,
+128,3,158,237,239,238,239,243,240,225,227,101,128,255,56,243,
+237,225,236,108,128,247,120,89,139,0,89,33,81,33,116,33,
+139,33,189,33,228,33,236,33,253,34,40,34,52,34,60,34,
+68,97,2,33,87,33,104,227,245,244,101,129,0,221,33,96,
+243,237,225,236,108,128,247,253,244,227,249,242,233,236,236,233,
+99,128,4,98,227,233,242,99,2,33,125,33,130,236,101,128,
+36,206,245,237,230,236,229,120,128,1,118,100,2,33,145,33,
+165,233,229,242,229,243,233,115,129,1,120,33,157,243,237,225,
+236,108,128,247,255,239,116,2,33,172,33,181,225,227,227,229,
+238,116,128,30,142,226,229,236,239,119,128,30,244,229,114,2,
+33,196,33,208,233,227,249,242,233,236,236,233,99,128,4,43,
+245,228,233,229,242,229,243,233,243,227,249,242,233,236,236,233,
+99,128,4,248,231,242,225,246,101,128,30,242,232,239,239,107,
+129,1,179,33,245,225,226,239,246,101,128,30,246,105,3,34,
+5,34,16,34,27,225,242,237,229,238,233,225,110,128,5,69,
+227,249,242,233,236,236,233,99,128,4,7,247,238,225,242,237,
+229,238,233,225,110,128,5,82,237,239,238,239,243,240,225,227,
+101,128,255,57,243,237,225,236,108,128,247,121,244,233,236,228,
+101,128,30,248,245,115,2,34,75,34,113,226,233,103,2,34,
+83,34,94,227,249,242,233,236,236,233,99,128,4,106,233,239,
+244,233,230,233,229,228,227,249,242,233,236,236,233,99,128,4,
+108,236,233,244,244,236,101,2,34,124,34,135,227,249,242,233,
+236,236,233,99,128,4,102,233,239,244,233,230,233,229,228,227,
+249,242,233,236,236,233,99,128,4,104,90,136,0,90,34,174,
+34,198,34,243,35,14,35,81,35,173,35,185,35,197,97,2,
+34,180,34,191,225,242,237,229,238,233,225,110,128,5,54,227,
+245,244,101,128,1,121,99,2,34,204,34,221,225,242,239,110,
+129,1,125,34,213,243,237,225,236,108,128,246,255,233,242,99,
+2,34,229,34,234,236,101,128,36,207,245,237,230,236,229,120,
+128,30,144,228,239,116,130,1,123,34,253,35,6,225,227,227,
+229,238,116,128,1,123,226,229,236,239,119,128,30,146,101,3,
+35,22,35,33,35,76,227,249,242,233,236,236,233,99,128,4,
+23,100,2,35,39,35,58,229,243,227,229,238,228,229,242,227,
+249,242,233,236,236,233,99,128,4,152,233,229,242,229,243,233,
+243,227,249,242,233,236,236,233,99,128,4,222,244,97,128,3,
+150,232,101,4,35,92,35,103,35,119,35,130,225,242,237,229,
+238,233,225,110,128,5,58,226,242,229,246,229,227,249,242,233,
+236,236,233,99,128,4,193,227,249,242,233,236,236,233,99,128,
+4,22,100,2,35,136,35,155,229,243,227,229,238,228,229,242,
+227,249,242,233,236,236,233,99,128,4,150,233,229,242,229,243,
+233,243,227,249,242,233,236,236,233,99,128,4,220,236,233,238,
+229,226,229,236,239,119,128,30,148,237,239,238,239,243,240,225,
+227,101,128,255,58,115,2,35,203,35,210,237,225,236,108,128,
+247,122,244,242,239,235,101,128,1,181,97,158,0,97,36,26,
+38,154,39,4,39,68,39,132,39,196,40,4,40,68,40,126,
+40,190,41,70,41,217,42,137,42,237,43,17,49,192,49,229,
+50,0,50,225,51,7,52,96,52,168,53,123,53,132,54,5,
+56,13,57,3,57,50,57,201,57,215,49,138,39,1,36,50,
+36,114,36,154,36,218,37,26,37,90,37,154,37,218,38,26,
+38,90,48,138,39,33,36,74,36,78,36,82,36,86,36,90,
+36,94,36,98,36,102,36,106,36,110,48,128,39,94,49,128,
+39,97,50,128,39,98,51,128,39,99,52,128,39,100,53,128,
+39,16,54,128,39,101,55,128,39,102,56,128,39,103,57,128,
+38,96,49,134,38,27,36,130,36,134,36,138,36,142,36,146,
+36,150,48,128,38,101,49,128,38,102,50,128,38,99,55,128,
+39,9,56,128,39,8,57,128,39,7,50,138,38,30,36,178,
+36,182,36,186,36,190,36,194,36,198,36,202,36,206,36,210,
+36,214,48,128,36,96,49,128,36,97,50,128,36,98,51,128,
+36,99,52,128,36,100,53,128,36,101,54,128,36,102,55,128,
+36,103,56,128,36,104,57,128,36,105,51,138,39,12,36,242,
+36,246,36,250,36,254,37,2,37,6,37,10,37,14,37,18,
+37,22,48,128,39,118,49,128,39,119,50,128,39,120,51,128,
+39,121,52,128,39,122,53,128,39,123,54,128,39,124,55,128,
+39,125,56,128,39,126,57,128,39,127,52,138,39,13,37,50,
+37,54,37,58,37,62,37,66,37,70,37,74,37,78,37,82,
+37,86,48,128,39,128,49,128,39,129,50,128,39,130,51,128,
+39,131,52,128,39,132,53,128,39,133,54,128,39,134,55,128,
+39,135,56,128,39,136,57,128,39,137,53,138,39,14,37,114,
+37,118,37,122,37,126,37,130,37,134,37,138,37,142,37,146,
+37,150,48,128,39,138,49,128,39,139,50,128,39,140,51,128,
+39,141,52,128,39,142,53,128,39,143,54,128,39,144,55,128,
+39,145,56,128,39,146,57,128,39,147,54,138,39,15,37,178,
+37,182,37,186,37,190,37,194,37,198,37,202,37,206,37,210,
+37,214,48,128,39,148,49,128,33,146,50,128,39,163,51,128,
+33,148,52,128,33,149,53,128,39,153,54,128,39,155,55,128,
+39,156,56,128,39,157,57,128,39,158,55,138,39,17,37,242,
+37,246,37,250,37,254,38,2,38,6,38,10,38,14,38,18,
+38,22,48,128,39,159,49,128,39,160,50,128,39,161,51,128,
+39,162,52,128,39,164,53,128,39,165,54,128,39,166,55,128,
+39,167,56,128,39,168,57,128,39,169,56,138,39,18,38,50,
+38,54,38,58,38,62,38,66,38,70,38,74,38,78,38,82,
+38,86,48,128,39,171,49,128,39,173,50,128,39,175,51,128,
+39,178,52,128,39,179,53,128,39,181,54,128,39,184,55,128,
+39,186,56,128,39,187,57,128,39,188,57,138,39,19,38,114,
+38,118,38,122,38,126,38,130,38,134,38,138,38,142,38,146,
+38,150,48,128,39,189,49,128,39,190,50,128,39,154,51,128,
+39,170,52,128,39,182,53,128,39,185,54,128,39,152,55,128,
+39,180,56,128,39,183,57,128,39,172,50,138,39,2,38,178,
+38,224,38,228,38,232,38,236,38,240,38,244,38,248,38,252,
+39,0,48,135,39,20,38,196,38,200,38,204,38,208,38,212,
+38,216,38,220,48,128,39,174,49,128,39,177,50,128,39,3,
+51,128,39,80,52,128,39,82,53,128,39,110,54,128,39,112,
+49,128,39,21,50,128,39,22,51,128,39,23,52,128,39,24,
+53,128,39,25,54,128,39,26,55,128,39,27,56,128,39,28,
+57,128,39,34,51,138,39,4,39,28,39,32,39,36,39,40,
+39,44,39,48,39,52,39,56,39,60,39,64,48,128,39,35,
+49,128,39,36,50,128,39,37,51,128,39,38,52,128,39,39,
+53,128,38,5,54,128,39,41,55,128,39,42,56,128,39,43,
+57,128,39,44,52,138,38,14,39,92,39,96,39,100,39,104,
+39,108,39,112,39,116,39,120,39,124,39,128,48,128,39,45,
+49,128,39,46,50,128,39,47,51,128,39,48,52,128,39,49,
+53,128,39,50,54,128,39,51,55,128,39,52,56,128,39,53,
+57,128,39,54,53,138,39,6,39,156,39,160,39,164,39,168,
+39,172,39,176,39,180,39,184,39,188,39,192,48,128,39,55,
+49,128,39,56,50,128,39,57,51,128,39,58,52,128,39,59,
+53,128,39,60,54,128,39,61,55,128,39,62,56,128,39,63,
+57,128,39,64,54,138,39,29,39,220,39,224,39,228,39,232,
+39,236,39,240,39,244,39,248,39,252,40,0,48,128,39,65,
+49,128,39,66,50,128,39,67,51,128,39,68,52,128,39,69,
+53,128,39,70,54,128,39,71,55,128,39,72,56,128,39,73,
+57,128,39,74,55,138,39,30,40,28,40,32,40,36,40,40,
+40,44,40,48,40,52,40,56,40,60,40,64,48,128,39,75,
+49,128,37,207,50,128,39,77,51,128,37,160,52,128,39,79,
+53,128,39,81,54,128,37,178,55,128,37,188,56,128,37,198,
+57,128,39,86,56,137,39,31,40,90,40,94,40,98,40,102,
+40,106,40,110,40,114,40,118,40,122,49,128,37,215,50,128,
+39,88,51,128,39,89,52,128,39,90,53,128,39,111,54,128,
+39,113,55,128,39,114,56,128,39,115,57,128,39,104,57,138,
+39,32,40,150,40,154,40,158,40,162,40,166,40,170,40,174,
+40,178,40,182,40,186,48,128,39,105,49,128,39,108,50,128,
+39,109,51,128,39,106,52,128,39,107,53,128,39,116,54,128,
+39,117,55,128,39,91,56,128,39,92,57,128,39,93,97,7,
+40,206,40,216,40,223,40,230,40,255,41,15,41,26,226,229,
+238,231,225,236,105,128,9,134,227,245,244,101,128,0,225,228,
+229,246,97,128,9,6,231,117,2,40,237,40,246,234,225,242,
+225,244,105,128,10,134,242,237,245,235,232,105,128,10,6,237,
+225,244,242,225,231,245,242,237,245,235,232,105,128,10,62,242,
+245,243,241,245,225,242,101,128,51,3,246,239,247,229,236,243,
+233,231,110,3,41,42,41,52,41,59,226,229,238,231,225,236,
+105,128,9,190,228,229,246,97,128,9,62,231,245,234,225,242,
+225,244,105,128,10,190,98,4,41,80,41,121,41,130,41,140,
+226,242,229,246,233,225,244,233,239,110,2,41,95,41,110,237,
+225,242,235,225,242,237,229,238,233,225,110,128,5,95,243,233,
+231,238,228,229,246,97,128,9,112,229,238,231,225,236,105,128,
+9,133,239,240,239,237,239,230,111,128,49,26,242,229,246,101,
+134,1,3,41,159,41,167,41,178,41,189,41,197,41,209,225,
+227,245,244,101,128,30,175,227,249,242,233,236,236,233,99,128,
+4,209,228,239,244,226,229,236,239,119,128,30,183,231,242,225,
+246,101,128,30,177,232,239,239,235,225,226,239,246,101,128,30,
+179,244,233,236,228,101,128,30,181,99,4,41,227,41,234,42,
+57,42,127,225,242,239,110,128,1,206,233,242,99,2,41,242,
+41,247,236,101,128,36,208,245,237,230,236,229,120,133,0,226,
+42,10,42,18,42,29,42,37,42,49,225,227,245,244,101,128,
+30,165,228,239,244,226,229,236,239,119,128,30,173,231,242,225,
+246,101,128,30,167,232,239,239,235,225,226,239,246,101,128,30,
+169,244,233,236,228,101,128,30,171,245,244,101,133,0,180,42,
+73,42,84,42,101,42,108,42,117,226,229,236,239,247,227,237,
+98,128,3,23,99,2,42,90,42,95,237,98,128,3,1,239,
+237,98,128,3,1,228,229,246,97,128,9,84,236,239,247,237,
+239,100,128,2,207,244,239,238,229,227,237,98,128,3,65,249,
+242,233,236,236,233,99,128,4,48,100,5,42,149,42,159,42,
+173,42,179,42,213,226,236,231,242,225,246,101,128,2,1,228,
+225,235,231,245,242,237,245,235,232,105,128,10,113,229,246,97,
+128,9,5,233,229,242,229,243,233,115,130,0,228,42,193,42,
+204,227,249,242,233,236,236,233,99,128,4,211,237,225,227,242,
+239,110,128,1,223,239,116,2,42,220,42,228,226,229,236,239,
+119,128,30,161,237,225,227,242,239,110,128,1,225,101,131,0,
+230,42,247,42,255,43,8,225,227,245,244,101,128,1,253,235,
+239,242,229,225,110,128,49,80,237,225,227,242,239,110,128,1,
+227,230,233,105,6,43,33,43,53,45,246,45,252,46,11,49,
+111,48,2,43,39,43,46,176,178,176,56,128,32,21,184,185,
+180,49,128,32,164,177,48,3,43,62,45,86,45,221,48,9,
+43,82,43,102,43,164,43,226,44,32,44,94,44,156,44,218,
+45,24,49,3,43,90,43,94,43,98,55,128,4,16,56,128,
+4,17,57,128,4,18,50,10,43,124,43,128,43,132,43,136,
+43,140,43,144,43,148,43,152,43,156,43,160,48,128,4,19,
+49,128,4,20,50,128,4,21,51,128,4,1,52,128,4,22,
+53,128,4,23,54,128,4,24,55,128,4,25,56,128,4,26,
+57,128,4,27,51,10,43,186,43,190,43,194,43,198,43,202,
+43,206,43,210,43,214,43,218,43,222,48,128,4,28,49,128,
+4,29,50,128,4,30,51,128,4,31,52,128,4,32,53,128,
+4,33,54,128,4,34,55,128,4,35,56,128,4,36,57,128,
+4,37,52,10,43,248,43,252,44,0,44,4,44,8,44,12,
+44,16,44,20,44,24,44,28,48,128,4,38,49,128,4,39,
+50,128,4,40,51,128,4,41,52,128,4,42,53,128,4,43,
+54,128,4,44,55,128,4,45,56,128,4,46,57,128,4,47,
+53,10,44,54,44,58,44,62,44,66,44,70,44,74,44,78,
+44,82,44,86,44,90,48,128,4,144,49,128,4,2,50,128,
+4,3,51,128,4,4,52,128,4,5,53,128,4,6,54,128,
+4,7,55,128,4,8,56,128,4,9,57,128,4,10,54,10,
+44,116,44,120,44,124,44,128,44,132,44,136,44,140,44,144,
+44,148,44,152,48,128,4,11,49,128,4,12,50,128,4,14,
+51,128,246,196,52,128,246,197,53,128,4,48,54,128,4,49,
+55,128,4,50,56,128,4,51,57,128,4,52,55,10,44,178,
+44,182,44,186,44,190,44,194,44,198,44,202,44,206,44,210,
+44,214,48,128,4,53,49,128,4,81,50,128,4,54,51,128,
+4,55,52,128,4,56,53,128,4,57,54,128,4,58,55,128,
+4,59,56,128,4,60,57,128,4,61,56,10,44,240,44,244,
+44,248,44,252,45,0,45,4,45,8,45,12,45,16,45,20,
+48,128,4,62,49,128,4,63,50,128,4,64,51,128,4,65,
+52,128,4,66,53,128,4,67,54,128,4,68,55,128,4,69,
+56,128,4,70,57,128,4,71,57,10,45,46,45,50,45,54,
+45,58,45,62,45,66,45,70,45,74,45,78,45,82,48,128,
+4,72,49,128,4,73,50,128,4,74,51,128,4,75,52,128,
+4,76,53,128,4,77,54,128,4,78,55,128,4,79,56,128,
+4,145,57,128,4,82,49,4,45,96,45,158,45,163,45,189,
+48,10,45,118,45,122,45,126,45,130,45,134,45,138,45,142,
+45,146,45,150,45,154,48,128,4,83,49,128,4,84,50,128,
+4,85,51,128,4,86,52,128,4,87,53,128,4,88,54,128,
+4,89,55,128,4,90,56,128,4,91,57,128,4,92,177,48,
+128,4,94,52,4,45,173,45,177,45,181,45,185,53,128,4,
+15,54,128,4,98,55,128,4,114,56,128,4,116,57,5,45,
+201,45,205,45,209,45,213,45,217,50,128,246,198,51,128,4,
+95,52,128,4,99,53,128,4,115,54,128,4,117,56,2,45,
+227,45,241,51,2,45,233,45,237,49,128,246,199,50,128,246,
+200,180,54,128,4,217,178,185,57,128,32,14,179,48,2,46,
+3,46,7,48,128,32,15,49,128,32,13,181,55,7,46,28,
+46,98,47,163,47,240,48,197,49,34,49,105,51,2,46,34,
+46,48,56,2,46,40,46,44,49,128,6,106,56,128,6,12,
+57,8,46,66,46,70,46,74,46,78,46,82,46,86,46,90,
+46,94,50,128,6,96,51,128,6,97,52,128,6,98,53,128,
+6,99,54,128,6,100,55,128,6,101,56,128,6,102,57,128,
+6,103,52,7,46,114,46,146,46,208,47,14,47,46,47,102,
+47,158,48,5,46,126,46,130,46,134,46,138,46,142,48,128,
+6,104,49,128,6,105,51,128,6,27,55,128,6,31,57,128,
+6,33,49,10,46,168,46,172,46,176,46,180,46,184,46,188,
+46,192,46,196,46,200,46,204,48,128,6,34,49,128,6,35,
+50,128,6,36,51,128,6,37,52,128,6,38,53,128,6,39,
+54,128,6,40,55,128,6,41,56,128,6,42,57,128,6,43,
+50,10,46,230,46,234,46,238,46,242,46,246,46,250,46,254,
+47,2,47,6,47,10,48,128,6,44,49,128,6,45,50,128,
+6,46,51,128,6,47,52,128,6,48,53,128,6,49,54,128,
+6,50,55,128,6,51,56,128,6,52,57,128,6,53,51,5,
+47,26,47,30,47,34,47,38,47,42,48,128,6,54,49,128,
+6,55,50,128,6,56,51,128,6,57,52,128,6,58,52,9,
+47,66,47,70,47,74,47,78,47,82,47,86,47,90,47,94,
+47,98,48,128,6,64,49,128,6,65,50,128,6,66,51,128,
+6,67,52,128,6,68,53,128,6,69,54,128,6,70,56,128,
+6,72,57,128,6,73,53,9,47,122,47,126,47,130,47,134,
+47,138,47,142,47,146,47,150,47,154,48,128,6,74,49,128,
+6,75,50,128,6,76,51,128,6,77,52,128,6,78,53,128,
+6,79,54,128,6,80,55,128,6,81,56,128,6,82,183,48,
+128,6,71,53,3,47,171,47,203,47,235,48,5,47,183,47,
+187,47,191,47,195,47,199,53,128,6,164,54,128,6,126,55,
+128,6,134,56,128,6,152,57,128,6,175,49,5,47,215,47,
+219,47,223,47,227,47,231,49,128,6,121,50,128,6,136,51,
+128,6,145,52,128,6,186,57,128,6,210,179,52,128,6,213,
+54,7,48,0,48,5,48,10,48,15,48,53,48,115,48,177,
+179,54,128,32,170,180,53,128,5,190,181,56,128,5,195,54,
+6,48,29,48,33,48,37,48,41,48,45,48,49,52,128,5,
+208,53,128,5,209,54,128,5,210,55,128,5,211,56,128,5,
+212,57,128,5,213,55,10,48,75,48,79,48,83,48,87,48,
+91,48,95,48,99,48,103,48,107,48,111,48,128,5,214,49,
+128,5,215,50,128,5,216,51,128,5,217,52,128,5,218,53,
+128,5,219,54,128,5,220,55,128,5,221,56,128,5,222,57,
+128,5,223,56,10,48,137,48,141,48,145,48,149,48,153,48,
+157,48,161,48,165,48,169,48,173,48,128,5,224,49,128,5,
+225,50,128,5,226,51,128,5,227,52,128,5,228,53,128,5,
+229,54,128,5,230,55,128,5,231,56,128,5,232,57,128,5,
+233,57,3,48,185,48,189,48,193,48,128,5,234,52,128,251,
+42,53,128,251,43,55,4,48,207,48,221,48,241,48,246,48,
+2,48,213,48,217,48,128,251,75,53,128,251,31,49,3,48,
+229,48,233,48,237,54,128,5,240,55,128,5,241,56,128,5,
+242,178,51,128,251,53,57,7,49,6,49,10,49,14,49,18,
+49,22,49,26,49,30,51,128,5,180,52,128,5,181,53,128,
+5,182,54,128,5,187,55,128,5,184,56,128,5,183,57,128,
+5,176,56,3,49,42,49,86,49,91,48,7,49,58,49,62,
+49,66,49,70,49,74,49,78,49,82,48,128,5,178,49,128,
+5,177,50,128,5,179,51,128,5,194,52,128,5,193,54,128,
+5,185,55,128,5,188,179,57,128,5,189,52,2,49,97,49,
+101,49,128,5,191,50,128,5,192,185,178,57,128,2,188,54,
+3,49,119,49,178,49,185,49,4,49,129,49,145,49,151,49,
+172,50,2,49,135,49,140,180,56,128,33,5,184,57,128,33,
+19,179,181,50,128,33,22,181,55,3,49,160,49,164,49,168,
+51,128,32,44,52,128,32,45,53,128,32,46,182,182,52,128,
+32,12,179,177,182,55,128,6,109,180,185,179,55,128,2,189,
+103,2,49,198,49,205,242,225,246,101,128,0,224,117,2,49,
+211,49,220,234,225,242,225,244,105,128,10,133,242,237,245,235,
+232,105,128,10,5,104,2,49,235,49,245,233,242,225,231,225,
+238,97,128,48,66,239,239,235,225,226,239,246,101,128,30,163,
+105,7,50,16,50,41,50,48,50,60,50,85,50,101,50,181,
+98,2,50,22,50,31,229,238,231,225,236,105,128,9,144,239,
+240,239,237,239,230,111,128,49,30,228,229,246,97,128,9,16,
+229,227,249,242,233,236,236,233,99,128,4,213,231,117,2,50,
+67,50,76,234,225,242,225,244,105,128,10,144,242,237,245,235,
+232,105,128,10,16,237,225,244,242,225,231,245,242,237,245,235,
+232,105,128,10,72,110,5,50,113,50,122,50,136,50,152,50,
+167,225,242,225,226,233,99,128,6,57,230,233,238,225,236,225,
+242,225,226,233,99,128,254,202,233,238,233,244,233,225,236,225,
+242,225,226,233,99,128,254,203,237,229,228,233,225,236,225,242,
+225,226,233,99,128,254,204,246,229,242,244,229,228,226,242,229,
+246,101,128,2,3,246,239,247,229,236,243,233,231,110,3,50,
+197,50,207,50,214,226,229,238,231,225,236,105,128,9,200,228,
+229,246,97,128,9,72,231,245,234,225,242,225,244,105,128,10,
+200,107,2,50,231,50,255,225,244,225,235,225,238,97,129,48,
+162,50,243,232,225,236,230,247,233,228,244,104,128,255,113,239,
+242,229,225,110,128,49,79,108,3,51,15,52,71,52,80,101,
+2,51,21,52,66,102,136,5,208,51,41,51,50,51,65,51,
+79,51,168,51,182,52,37,52,51,225,242,225,226,233,99,128,
+6,39,228,225,231,229,243,232,232,229,226,242,229,119,128,251,
+48,230,233,238,225,236,225,242,225,226,233,99,128,254,142,104,
+2,51,85,51,160,225,237,250,97,2,51,94,51,127,225,226,
+239,246,101,2,51,104,51,113,225,242,225,226,233,99,128,6,
+35,230,233,238,225,236,225,242,225,226,233,99,128,254,132,226,
+229,236,239,119,2,51,137,51,146,225,242,225,226,233,99,128,
+6,37,230,233,238,225,236,225,242,225,226,233,99,128,254,136,
+229,226,242,229,119,128,5,208,236,225,237,229,228,232,229,226,
+242,229,119,128,251,79,237,97,2,51,189,51,225,228,228,225,
+225,226,239,246,101,2,51,202,51,211,225,242,225,226,233,99,
+128,6,34,230,233,238,225,236,225,242,225,226,233,99,128,254,
+130,235,243,245,242,97,4,51,239,51,248,52,6,52,22,225,
+242,225,226,233,99,128,6,73,230,233,238,225,236,225,242,225,
+226,233,99,128,254,240,233,238,233,244,233,225,236,225,242,225,
+226,233,99,128,254,243,237,229,228,233,225,236,225,242,225,226,
+233,99,128,254,244,240,225,244,225,232,232,229,226,242,229,119,
+128,251,46,241,225,237,225,244,243,232,229,226,242,229,119,128,
+251,47,240,104,128,33,53,236,229,241,245,225,108,128,34,76,
+240,232,97,129,3,177,52,88,244,239,238,239,115,128,3,172,
+109,4,52,106,52,114,52,125,52,159,225,227,242,239,110,128,
+1,1,239,238,239,243,240,225,227,101,128,255,65,240,229,242,
+243,225,238,100,130,0,38,52,139,52,151,237,239,238,239,243,
+240,225,227,101,128,255,6,243,237,225,236,108,128,247,38,243,
+241,245,225,242,101,128,51,194,110,4,52,178,52,189,53,55,
+53,65,226,239,240,239,237,239,230,111,128,49,34,103,4,52,
+199,52,210,52,224,53,47,226,239,240,239,237,239,230,111,128,
+49,36,235,232,225,238,235,232,245,244,232,225,105,128,14,90,
+236,101,131,34,32,52,235,53,32,53,39,226,242,225,227,235,
+229,116,2,52,247,53,11,236,229,230,116,129,48,8,53,0,
+246,229,242,244,233,227,225,108,128,254,63,242,233,231,232,116,
+129,48,9,53,21,246,229,242,244,233,227,225,108,128,254,64,
+236,229,230,116,128,35,41,242,233,231,232,116,128,35,42,243,
+244,242,239,109,128,33,43,239,244,229,236,229,233,97,128,3,
+135,117,2,53,71,53,83,228,225,244,244,225,228,229,246,97,
+128,9,82,243,246,225,242,97,3,53,95,53,105,53,112,226,
+229,238,231,225,236,105,128,9,130,228,229,246,97,128,9,2,
+231,245,234,225,242,225,244,105,128,10,130,239,231,239,238,229,
+107,128,1,5,112,3,53,140,53,164,53,194,97,2,53,146,
+53,158,225,244,239,243,241,245,225,242,101,128,51,0,242,229,
+110,128,36,156,239,243,244,242,239,240,232,101,2,53,177,53,
+188,225,242,237,229,238,233,225,110,128,5,90,237,239,100,128,
+2,188,112,2,53,200,53,205,236,101,128,248,255,242,111,2,
+53,212,53,220,225,227,232,229,115,128,34,80,120,2,53,226,
+53,246,229,241,245,225,108,129,34,72,53,236,239,242,233,237,
+225,231,101,128,34,82,233,237,225,244,229,236,249,229,241,245,
+225,108,128,34,69,114,4,54,15,54,42,54,46,54,91,225,
+229,97,2,54,23,54,33,229,235,239,242,229,225,110,128,49,
+142,235,239,242,229,225,110,128,49,141,99,128,35,18,105,2,
+54,52,54,66,231,232,244,232,225,236,230,242,233,238,103,128,
+30,154,238,103,130,0,229,54,75,54,83,225,227,245,244,101,
+128,1,251,226,229,236,239,119,128,30,1,242,239,119,8,54,
+111,54,118,54,247,55,57,55,107,55,162,55,185,56,4,226,
+239,244,104,128,33,148,100,3,54,126,54,165,54,212,225,243,
+104,4,54,138,54,145,54,152,54,160,228,239,247,110,128,33,
+227,236,229,230,116,128,33,224,242,233,231,232,116,128,33,226,
+245,112,128,33,225,226,108,5,54,178,54,185,54,192,54,199,
+54,207,226,239,244,104,128,33,212,228,239,247,110,128,33,211,
+236,229,230,116,128,33,208,242,233,231,232,116,128,33,210,245,
+112,128,33,209,239,247,110,131,33,147,54,224,54,231,54,239,
+236,229,230,116,128,33,153,242,233,231,232,116,128,33,152,247,
+232,233,244,101,128,33,233,104,2,54,253,55,48,229,225,100,
+4,55,9,55,19,55,29,55,40,228,239,247,238,237,239,100,
+128,2,197,236,229,230,244,237,239,100,128,2,194,242,233,231,
+232,244,237,239,100,128,2,195,245,240,237,239,100,128,2,196,
+239,242,233,250,229,120,128,248,231,236,229,230,116,131,33,144,
+55,70,55,87,55,99,228,226,108,129,33,208,55,78,243,244,
+242,239,235,101,128,33,205,239,246,229,242,242,233,231,232,116,
+128,33,198,247,232,233,244,101,128,33,230,242,233,231,232,116,
+132,33,146,55,123,55,135,55,143,55,154,228,226,236,243,244,
+242,239,235,101,128,33,207,232,229,225,246,121,128,39,158,239,
+246,229,242,236,229,230,116,128,33,196,247,232,233,244,101,128,
+33,232,244,225,98,2,55,170,55,177,236,229,230,116,128,33,
+228,242,233,231,232,116,128,33,229,245,112,132,33,145,55,198,
+55,226,55,244,55,252,100,2,55,204,55,216,110,129,33,149,
+55,210,226,243,101,128,33,168,239,247,238,226,225,243,101,128,
+33,168,236,229,230,116,129,33,150,55,235,239,230,228,239,247,
+110,128,33,197,242,233,231,232,116,128,33,151,247,232,233,244,
+101,128,33,231,246,229,242,244,229,120,128,248,230,115,5,56,
+25,56,101,56,146,56,229,56,239,99,2,56,31,56,83,233,
+105,2,56,38,56,61,227,233,242,227,245,109,129,0,94,56,
+49,237,239,238,239,243,240,225,227,101,128,255,62,244,233,236,
+228,101,129,0,126,56,71,237,239,238,239,243,240,225,227,101,
+128,255,94,242,233,240,116,129,2,81,56,92,244,245,242,238,
+229,100,128,2,82,237,225,236,108,2,56,110,56,121,232,233,
+242,225,231,225,238,97,128,48,65,235,225,244,225,235,225,238,
+97,129,48,161,56,134,232,225,236,230,247,233,228,244,104,128,
+255,103,244,229,242,233,115,2,56,156,56,225,107,131,0,42,
+56,166,56,194,56,217,97,2,56,172,56,186,236,244,239,238,
+229,225,242,225,226,233,99,128,6,109,242,225,226,233,99,128,
+6,109,109,2,56,200,56,206,225,244,104,128,34,23,239,238,
+239,243,240,225,227,101,128,255,10,243,237,225,236,108,128,254,
+97,109,128,32,66,245,240,229,242,233,239,114,128,246,233,249,
+237,240,244,239,244,233,227,225,236,236,249,229,241,245,225,108,
+128,34,67,116,132,0,64,57,15,57,22,57,34,57,42,233,
+236,228,101,128,0,227,237,239,238,239,243,240,225,227,101,128,
+255,32,243,237,225,236,108,128,254,107,245,242,238,229,100,128,
+2,80,117,6,57,64,57,89,57,96,57,121,57,141,57,157,
+98,2,57,70,57,79,229,238,231,225,236,105,128,9,148,239,
+240,239,237,239,230,111,128,49,32,228,229,246,97,128,9,20,
+231,117,2,57,103,57,112,234,225,242,225,244,105,128,10,148,
+242,237,245,235,232,105,128,10,20,236,229,238,231,244,232,237,
+225,242,235,226,229,238,231,225,236,105,128,9,215,237,225,244,
+242,225,231,245,242,237,245,235,232,105,128,10,76,246,239,247,
+229,236,243,233,231,110,3,57,173,57,183,57,190,226,229,238,
+231,225,236,105,128,9,204,228,229,246,97,128,9,76,231,245,
+234,225,242,225,244,105,128,10,204,246,225,231,242,225,232,225,
+228,229,246,97,128,9,61,121,2,57,221,57,233,226,225,242,
+237,229,238,233,225,110,128,5,97,233,110,130,5,226,57,242,
+58,1,225,236,244,239,238,229,232,229,226,242,229,119,128,251,
+32,232,229,226,242,229,119,128,5,226,98,144,0,98,58,46,
+58,181,58,192,58,201,58,226,60,11,60,73,60,146,62,72,
+62,84,62,127,62,135,62,145,64,15,64,39,64,48,97,7,
+58,62,58,72,58,96,58,103,58,128,58,152,58,163,226,229,
+238,231,225,236,105,128,9,172,227,235,243,236,225,243,104,129,
+0,92,58,84,237,239,238,239,243,240,225,227,101,128,255,60,
+228,229,246,97,128,9,44,231,117,2,58,110,58,119,234,225,
+242,225,244,105,128,10,172,242,237,245,235,232,105,128,10,44,
+104,2,58,134,58,144,233,242,225,231,225,238,97,128,48,112,
+244,244,232,225,105,128,14,63,235,225,244,225,235,225,238,97,
+128,48,208,114,129,0,124,58,169,237,239,238,239,243,240,225,
+227,101,128,255,92,226,239,240,239,237,239,230,111,128,49,5,
+227,233,242,227,236,101,128,36,209,228,239,116,2,58,209,58,
+218,225,227,227,229,238,116,128,30,3,226,229,236,239,119,128,
+30,5,101,6,58,240,59,5,59,28,59,170,59,181,59,193,
+225,237,229,228,243,233,248,244,229,229,238,244,232,238,239,244,
+229,115,128,38,108,99,2,59,11,59,18,225,245,243,101,128,
+34,53,249,242,233,236,236,233,99,128,4,49,104,5,59,40,
+59,49,59,63,59,93,59,152,225,242,225,226,233,99,128,6,
+40,230,233,238,225,236,225,242,225,226,233,99,128,254,144,105,
+2,59,69,59,84,238,233,244,233,225,236,225,242,225,226,233,
+99,128,254,145,242,225,231,225,238,97,128,48,121,237,101,2,
+59,100,59,113,228,233,225,236,225,242,225,226,233,99,128,254,
+146,229,237,105,2,59,121,59,136,238,233,244,233,225,236,225,
+242,225,226,233,99,128,252,159,243,239,236,225,244,229,228,225,
+242,225,226,233,99,128,252,8,238,239,239,238,230,233,238,225,
+236,225,242,225,226,233,99,128,252,109,235,225,244,225,235,225,
+238,97,128,48,217,238,225,242,237,229,238,233,225,110,128,5,
+98,116,132,5,209,59,205,59,225,59,245,59,254,97,129,3,
+178,59,211,243,249,237,226,239,236,231,242,229,229,107,128,3,
+208,228,225,231,229,243,104,129,251,49,59,236,232,229,226,242,
+229,119,128,251,49,232,229,226,242,229,119,128,5,209,242,225,
+230,229,232,229,226,242,229,119,128,251,76,104,2,60,17,60,
+67,97,3,60,25,60,35,60,42,226,229,238,231,225,236,105,
+128,9,173,228,229,246,97,128,9,45,231,117,2,60,49,60,
+58,234,225,242,225,244,105,128,10,173,242,237,245,235,232,105,
+128,10,45,239,239,107,128,2,83,105,5,60,85,60,96,60,
+107,60,121,60,135,232,233,242,225,231,225,238,97,128,48,115,
+235,225,244,225,235,225,238,97,128,48,211,236,225,226,233,225,
+236,227,236,233,227,107,128,2,152,238,228,233,231,245,242,237,
+245,235,232,105,128,10,2,242,245,243,241,245,225,242,101,128,
+51,49,108,3,60,154,62,55,62,66,97,2,60,160,62,50,
+227,107,6,60,175,60,184,60,221,61,114,61,169,61,221,227,
+233,242,227,236,101,128,37,207,100,2,60,190,60,199,233,225,
+237,239,238,100,128,37,198,239,247,238,240,239,233,238,244,233,
+238,231,244,242,233,225,238,231,236,101,128,37,188,108,2,60,
+227,61,74,101,2,60,233,61,13,230,244,240,239,233,238,244,
+233,238,103,2,60,248,61,2,240,239,233,238,244,229,114,128,
+37,196,244,242,233,225,238,231,236,101,128,37,192,238,244,233,
+227,245,236,225,242,226,242,225,227,235,229,116,2,61,33,61,
+53,236,229,230,116,129,48,16,61,42,246,229,242,244,233,227,
+225,108,128,254,59,242,233,231,232,116,129,48,17,61,63,246,
+229,242,244,233,227,225,108,128,254,60,239,247,229,114,2,61,
+83,61,98,236,229,230,244,244,242,233,225,238,231,236,101,128,
+37,227,242,233,231,232,244,244,242,233,225,238,231,236,101,128,
+37,226,114,2,61,120,61,131,229,227,244,225,238,231,236,101,
+128,37,172,233,231,232,244,240,239,233,238,244,233,238,103,2,
+61,148,61,158,240,239,233,238,244,229,114,128,37,186,244,242,
+233,225,238,231,236,101,128,37,182,115,3,61,177,61,207,61,
+215,109,2,61,183,61,195,225,236,236,243,241,245,225,242,101,
+128,37,170,233,236,233,238,231,230,225,227,101,128,38,59,241,
+245,225,242,101,128,37,160,244,225,114,128,38,5,245,240,112,
+2,61,229,62,11,229,114,2,61,236,61,251,236,229,230,244,
+244,242,233,225,238,231,236,101,128,37,228,242,233,231,232,244,
+244,242,233,225,238,231,236,101,128,37,229,239,233,238,244,233,
+238,103,2,62,23,62,39,243,237,225,236,236,244,242,233,225,
+238,231,236,101,128,37,180,244,242,233,225,238,231,236,101,128,
+37,178,238,107,128,36,35,233,238,229,226,229,236,239,119,128,
+30,7,239,227,107,128,37,136,237,239,238,239,243,240,225,227,
+101,128,255,66,111,3,62,92,62,105,62,116,226,225,233,237,
+225,233,244,232,225,105,128,14,26,232,233,242,225,231,225,238,
+97,128,48,124,235,225,244,225,235,225,238,97,128,48,220,240,
+225,242,229,110,128,36,157,241,243,241,245,225,242,101,128,51,
+195,114,4,62,155,63,149,63,222,64,5,225,99,2,62,162,
+63,56,101,3,62,170,62,175,62,243,229,120,128,248,244,236,
+229,230,116,133,0,123,62,192,62,197,62,219,62,227,62,232,
+226,116,128,248,243,109,2,62,203,62,208,233,100,128,248,242,
+239,238,239,243,240,225,227,101,128,255,91,243,237,225,236,108,
+128,254,91,244,112,128,248,241,246,229,242,244,233,227,225,108,
+128,254,55,242,233,231,232,116,133,0,125,63,5,63,10,63,
+32,63,40,63,45,226,116,128,248,254,109,2,63,16,63,21,
+233,100,128,248,253,239,238,239,243,240,225,227,101,128,255,93,
+243,237,225,236,108,128,254,92,244,112,128,248,252,246,229,242,
+244,233,227,225,108,128,254,56,235,229,116,2,63,64,63,106,
+236,229,230,116,132,0,91,63,79,63,84,63,89,63,101,226,
+116,128,248,240,229,120,128,248,239,237,239,238,239,243,240,225,
+227,101,128,255,59,244,112,128,248,238,242,233,231,232,116,132,
+0,93,63,122,63,127,63,132,63,144,226,116,128,248,251,229,
+120,128,248,250,237,239,238,239,243,240,225,227,101,128,255,61,
+244,112,128,248,249,229,246,101,131,2,216,63,161,63,172,63,
+178,226,229,236,239,247,227,237,98,128,3,46,227,237,98,128,
+3,6,233,238,246,229,242,244,229,100,3,63,193,63,204,63,
+210,226,229,236,239,247,227,237,98,128,3,47,227,237,98,128,
+3,17,228,239,245,226,236,229,227,237,98,128,3,97,233,228,
+231,101,2,63,231,63,242,226,229,236,239,247,227,237,98,128,
+3,42,233,238,246,229,242,244,229,228,226,229,236,239,247,227,
+237,98,128,3,58,239,235,229,238,226,225,114,128,0,166,115,
+2,64,21,64,29,244,242,239,235,101,128,1,128,245,240,229,
+242,233,239,114,128,246,234,244,239,240,226,225,114,128,1,131,
+117,3,64,56,64,67,64,78,232,233,242,225,231,225,238,97,
+128,48,118,235,225,244,225,235,225,238,97,128,48,214,236,108,
+2,64,85,64,115,229,116,130,32,34,64,94,64,104,233,238,
+246,229,242,243,101,128,37,216,239,240,229,242,225,244,239,114,
+128,34,25,243,229,249,101,128,37,206,99,143,0,99,64,156,
+65,105,65,116,65,180,65,211,66,48,67,215,68,199,69,43,
+69,92,72,84,72,92,72,102,72,114,72,147,97,9,64,176,
+64,187,64,197,64,204,64,211,64,236,64,246,65,42,65,51,
+225,242,237,229,238,233,225,110,128,5,110,226,229,238,231,225,
+236,105,128,9,154,227,245,244,101,128,1,7,228,229,246,97,
+128,9,26,231,117,2,64,218,64,227,234,225,242,225,244,105,
+128,10,154,242,237,245,235,232,105,128,10,26,236,243,241,245,
+225,242,101,128,51,136,238,228,242,225,226,233,238,228,117,4,
+65,8,65,18,65,24,65,31,226,229,238,231,225,236,105,128,
+9,129,227,237,98,128,3,16,228,229,246,97,128,9,1,231,
+245,234,225,242,225,244,105,128,10,129,240,243,236,239,227,107,
+128,33,234,114,3,65,59,65,65,65,91,229,239,102,128,33,
+5,239,110,130,2,199,65,74,65,85,226,229,236,239,247,227,
+237,98,128,3,44,227,237,98,128,3,12,242,233,225,231,229,
+242,229,244,245,242,110,128,33,181,226,239,240,239,237,239,230,
+111,128,49,24,99,4,65,126,65,133,65,152,65,174,225,242,
+239,110,128,1,13,229,228,233,236,236,97,129,0,231,65,144,
+225,227,245,244,101,128,30,9,233,242,99,2,65,160,65,165,
+236,101,128,36,210,245,237,230,236,229,120,128,1,9,245,242,
+108,128,2,85,100,2,65,186,65,202,239,116,129,1,11,65,
+193,225,227,227,229,238,116,128,1,11,243,241,245,225,242,101,
+128,51,197,101,2,65,217,65,233,228,233,236,236,97,129,0,
+184,65,227,227,237,98,128,3,39,238,116,132,0,162,65,246,
+66,14,66,26,66,37,105,2,65,252,66,4,231,242,225,228,
+101,128,33,3,238,230,229,242,233,239,114,128,246,223,237,239,
+238,239,243,240,225,227,101,128,255,224,239,236,228,243,244,249,
+236,101,128,247,162,243,245,240,229,242,233,239,114,128,246,224,
+104,5,66,60,66,123,66,134,67,62,67,154,97,4,66,70,
+66,81,66,91,66,98,225,242,237,229,238,233,225,110,128,5,
+121,226,229,238,231,225,236,105,128,9,155,228,229,246,97,128,
+9,27,231,117,2,66,105,66,114,234,225,242,225,244,105,128,
+10,155,242,237,245,235,232,105,128,10,27,226,239,240,239,237,
+239,230,111,128,49,20,101,6,66,148,66,168,66,192,67,4,
+67,16,67,37,225,226,235,232,225,243,233,225,238,227,249,242,
+233,236,236,233,99,128,4,189,99,2,66,174,66,182,235,237,
+225,242,107,128,39,19,249,242,233,236,236,233,99,128,4,71,
+100,2,66,198,66,242,229,243,227,229,238,228,229,114,2,66,
+211,66,231,225,226,235,232,225,243,233,225,238,227,249,242,233,
+236,236,233,99,128,4,191,227,249,242,233,236,236,233,99,128,
+4,183,233,229,242,229,243,233,243,227,249,242,233,236,236,233,
+99,128,4,245,232,225,242,237,229,238,233,225,110,128,5,115,
+235,232,225,235,225,243,243,233,225,238,227,249,242,233,236,236,
+233,99,128,4,204,246,229,242,244,233,227,225,236,243,244,242,
+239,235,229,227,249,242,233,236,236,233,99,128,4,185,105,129,
+3,199,67,68,229,245,227,104,4,67,81,67,116,67,131,67,
+140,97,2,67,87,67,102,227,233,242,227,236,229,235,239,242,
+229,225,110,128,50,119,240,225,242,229,238,235,239,242,229,225,
+110,128,50,23,227,233,242,227,236,229,235,239,242,229,225,110,
+128,50,105,235,239,242,229,225,110,128,49,74,240,225,242,229,
+238,235,239,242,229,225,110,128,50,9,111,2,67,160,67,210,
+227,104,3,67,169,67,191,67,201,225,110,2,67,176,67,184,
+231,244,232,225,105,128,14,10,244,232,225,105,128,14,8,233,
+238,231,244,232,225,105,128,14,9,239,229,244,232,225,105,128,
+14,12,239,107,128,1,136,105,2,67,221,68,67,229,245,99,
+5,67,235,68,14,68,29,68,38,68,52,97,2,67,241,68,
+0,227,233,242,227,236,229,235,239,242,229,225,110,128,50,118,
+240,225,242,229,238,235,239,242,229,225,110,128,50,22,227,233,
+242,227,236,229,235,239,242,229,225,110,128,50,104,235,239,242,
+229,225,110,128,49,72,240,225,242,229,238,235,239,242,229,225,
+110,128,50,8,245,240,225,242,229,238,235,239,242,229,225,110,
+128,50,28,242,99,2,68,74,68,169,236,101,132,37,203,68,
+87,68,98,68,103,68,127,237,245,236,244,233,240,236,121,128,
+34,151,239,116,128,34,153,112,2,68,109,68,115,236,245,115,
+128,34,149,239,243,244,225,236,237,225,242,107,128,48,54,247,
+233,244,104,2,68,136,68,152,236,229,230,244,232,225,236,230,
+226,236,225,227,107,128,37,208,242,233,231,232,244,232,225,236,
+230,226,236,225,227,107,128,37,209,245,237,230,236,229,120,130,
+2,198,68,182,68,193,226,229,236,239,247,227,237,98,128,3,
+45,227,237,98,128,3,2,108,3,68,207,68,213,69,11,229,
+225,114,128,35,39,233,227,107,4,68,225,68,236,68,245,68,
+255,225,236,246,229,239,236,225,114,128,1,194,228,229,238,244,
+225,108,128,1,192,236,225,244,229,242,225,108,128,1,193,242,
+229,244,242,239,230,236,229,120,128,1,195,245,98,129,38,99,
+69,18,243,245,233,116,2,69,27,69,35,226,236,225,227,107,
+128,38,99,247,232,233,244,101,128,38,103,109,3,69,51,69,
+65,69,76,227,245,226,229,228,243,241,245,225,242,101,128,51,
+164,239,238,239,243,240,225,227,101,128,255,67,243,241,245,225,
+242,229,228,243,241,245,225,242,101,128,51,160,111,8,69,110,
+69,121,69,208,70,150,71,179,71,210,72,61,72,70,225,242,
+237,229,238,233,225,110,128,5,129,236,239,110,131,0,58,69,
+133,69,158,69,177,237,239,110,2,69,141,69,149,229,244,225,
+242,121,128,32,161,239,243,240,225,227,101,128,255,26,115,2,
+69,164,69,170,233,231,110,128,32,161,237,225,236,108,128,254,
+85,244,242,233,225,238,231,245,236,225,114,2,69,192,69,202,
+232,225,236,230,237,239,100,128,2,209,237,239,100,128,2,208,
+109,2,69,214,70,143,237,97,134,0,44,69,231,70,39,70,
+50,70,62,70,92,70,115,97,3,69,239,70,9,70,17,226,
+239,246,101,2,69,248,69,254,227,237,98,128,3,19,242,233,
+231,232,244,227,237,98,128,3,21,227,227,229,238,116,128,246,
+195,114,2,70,23,70,30,225,226,233,99,128,6,12,237,229,
+238,233,225,110,128,5,93,233,238,230,229,242,233,239,114,128,
+246,225,237,239,238,239,243,240,225,227,101,128,255,12,242,229,
+246,229,242,243,229,100,2,70,75,70,86,225,226,239,246,229,
+227,237,98,128,3,20,237,239,100,128,2,189,115,2,70,98,
+70,105,237,225,236,108,128,254,80,245,240,229,242,233,239,114,
+128,246,226,244,245,242,238,229,100,2,70,126,70,137,225,226,
+239,246,229,227,237,98,128,3,18,237,239,100,128,2,187,240,
+225,243,115,128,38,60,110,2,70,156,70,165,231,242,245,229,
+238,116,128,34,69,116,2,70,171,70,185,239,245,242,233,238,
+244,229,231,242,225,108,128,34,46,242,239,108,142,35,3,70,
+219,70,225,70,240,70,255,71,43,71,88,71,102,71,107,71,
+112,71,117,71,123,71,128,71,169,71,174,193,195,75,128,0,
+6,66,2,70,231,70,236,197,76,128,0,7,83,128,0,8,
+67,2,70,246,70,251,193,78,128,0,24,82,128,0,13,68,
+3,71,7,71,33,71,38,67,4,71,17,71,21,71,25,71,
+29,49,128,0,17,50,128,0,18,51,128,0,19,52,128,0,
+20,197,76,128,0,127,204,69,128,0,16,69,5,71,55,71,
+59,71,64,71,69,71,74,77,128,0,25,206,81,128,0,5,
+207,84,128,0,4,211,67,128,0,27,84,2,71,80,71,84,
+66,128,0,23,88,128,0,3,70,2,71,94,71,98,70,128,
+0,12,83,128,0,28,199,83,128,0,29,200,84,128,0,9,
+204,70,128,0,10,206,193,75,128,0,21,210,83,128,0,30,
+83,5,71,140,71,144,71,154,71,159,71,164,73,128,0,15,
+79,129,0,14,71,150,84,128,0,2,212,88,128,0,1,213,
+66,128,0,26,217,78,128,0,22,213,83,128,0,31,214,84,
+128,0,11,240,249,242,233,231,232,116,129,0,169,71,191,115,
+2,71,197,71,203,225,238,115,128,248,233,229,242,233,102,128,
+246,217,114,2,71,216,72,44,238,229,242,226,242,225,227,235,
+229,116,2,71,231,72,9,236,229,230,116,130,48,12,71,242,
+71,254,232,225,236,230,247,233,228,244,104,128,255,98,246,229,
+242,244,233,227,225,108,128,254,65,242,233,231,232,116,130,48,
+13,72,21,72,33,232,225,236,230,247,233,228,244,104,128,255,
+99,246,229,242,244,233,227,225,108,128,254,66,240,239,242,225,
+244,233,239,238,243,241,245,225,242,101,128,51,127,243,241,245,
+225,242,101,128,51,199,246,229,242,235,231,243,241,245,225,242,
+101,128,51,198,240,225,242,229,110,128,36,158,242,245,250,229,
+233,242,111,128,32,162,243,244,242,229,244,227,232,229,100,128,
+2,151,245,114,2,72,121,72,139,236,121,2,72,128,72,134,
+225,238,100,128,34,207,239,114,128,34,206,242,229,238,227,121,
+128,0,164,249,114,4,72,158,72,166,72,173,72,181,194,242,
+229,246,101,128,246,209,198,236,229,120,128,246,210,226,242,229,
+246,101,128,246,212,230,236,229,120,128,246,213,100,146,0,100,
+72,228,74,110,75,134,75,194,76,114,77,68,77,130,78,59,
+78,72,78,81,78,107,78,132,78,141,79,208,79,216,79,227,
+79,247,80,19,97,11,72,252,73,7,73,17,73,89,73,152,
+73,163,73,174,73,243,74,49,74,55,74,85,225,242,237,229,
+238,233,225,110,128,5,100,226,229,238,231,225,236,105,128,9,
+166,100,5,73,29,73,38,73,44,73,58,73,74,225,242,225,
+226,233,99,128,6,54,229,246,97,128,9,38,230,233,238,225,
+236,225,242,225,226,233,99,128,254,190,233,238,233,244,233,225,
+236,225,242,225,226,233,99,128,254,191,237,229,228,233,225,236,
+225,242,225,226,233,99,128,254,192,103,3,73,97,73,114,73,
+128,229,243,104,129,5,188,73,105,232,229,226,242,229,119,128,
+5,188,231,229,114,129,32,32,73,122,228,226,108,128,32,33,
+117,2,73,134,73,143,234,225,242,225,244,105,128,10,166,242,
+237,245,235,232,105,128,10,38,232,233,242,225,231,225,238,97,
+128,48,96,235,225,244,225,235,225,238,97,128,48,192,108,3,
+73,182,73,191,73,229,225,242,225,226,233,99,128,6,47,229,
+116,130,5,211,73,200,73,220,228,225,231,229,243,104,129,251,
+51,73,211,232,229,226,242,229,119,128,251,51,232,229,226,242,
+229,119,128,5,211,230,233,238,225,236,225,242,225,226,233,99,
+128,254,170,237,237,97,3,73,253,74,6,74,18,225,242,225,
+226,233,99,128,6,79,236,239,247,225,242,225,226,233,99,128,
+6,79,244,225,238,97,2,74,27,74,41,236,244,239,238,229,
+225,242,225,226,233,99,128,6,76,242,225,226,233,99,128,6,
+76,238,228,97,128,9,100,242,231,97,2,74,63,74,72,232,
+229,226,242,229,119,128,5,167,236,229,230,244,232,229,226,242,
+229,119,128,5,167,243,233,225,240,238,229,245,237,225,244,225,
+227,249,242,233,236,236,233,227,227,237,98,128,4,133,98,3,
+74,118,75,115,75,125,108,9,74,138,74,146,75,3,75,11,
+75,27,75,38,75,56,75,70,75,81,199,242,225,246,101,128,
+246,211,97,2,74,152,74,209,238,231,236,229,226,242,225,227,
+235,229,116,2,74,168,74,188,236,229,230,116,129,48,10,74,
+177,246,229,242,244,233,227,225,108,128,254,61,242,233,231,232,
+116,129,48,11,74,198,246,229,242,244,233,227,225,108,128,254,
+62,114,2,74,215,74,236,227,232,233,238,246,229,242,244,229,
+228,226,229,236,239,247,227,237,98,128,3,43,242,239,119,2,
+74,244,74,251,236,229,230,116,128,33,212,242,233,231,232,116,
+128,33,210,228,225,238,228,97,128,9,101,231,242,225,246,101,
+129,246,214,75,21,227,237,98,128,3,15,233,238,244,229,231,
+242,225,108,128,34,44,236,239,247,236,233,238,101,129,32,23,
+75,50,227,237,98,128,3,51,239,246,229,242,236,233,238,229,
+227,237,98,128,3,63,240,242,233,237,229,237,239,100,128,2,
+186,246,229,242,244,233,227,225,108,2,75,94,75,100,226,225,
+114,128,32,22,236,233,238,229,225,226,239,246,229,227,237,98,
+128,3,14,239,240,239,237,239,230,111,128,49,9,243,241,245,
+225,242,101,128,51,200,99,4,75,144,75,151,75,160,75,187,
+225,242,239,110,128,1,15,229,228,233,236,236,97,128,30,17,
+233,242,99,2,75,168,75,173,236,101,128,36,211,245,237,230,
+236,229,248,226,229,236,239,119,128,30,19,242,239,225,116,128,
+1,17,100,4,75,204,76,29,76,39,76,90,97,4,75,214,
+75,224,75,231,76,0,226,229,238,231,225,236,105,128,9,161,
+228,229,246,97,128,9,33,231,117,2,75,238,75,247,234,225,
+242,225,244,105,128,10,161,242,237,245,235,232,105,128,10,33,
+108,2,76,6,76,15,225,242,225,226,233,99,128,6,136,230,
+233,238,225,236,225,242,225,226,233,99,128,251,137,228,232,225,
+228,229,246,97,128,9,92,232,97,3,76,48,76,58,76,65,
+226,229,238,231,225,236,105,128,9,162,228,229,246,97,128,9,
+34,231,117,2,76,72,76,81,234,225,242,225,244,105,128,10,
+162,242,237,245,235,232,105,128,10,34,239,116,2,76,97,76,
+106,225,227,227,229,238,116,128,30,11,226,229,236,239,119,128,
+30,13,101,8,76,132,76,185,76,192,76,217,76,227,76,238,
+77,27,77,63,99,2,76,138,76,175,233,237,225,236,243,229,
+240,225,242,225,244,239,114,2,76,156,76,165,225,242,225,226,
+233,99,128,6,107,240,229,242,243,233,225,110,128,6,107,249,
+242,233,236,236,233,99,128,4,52,231,242,229,101,128,0,176,
+232,105,2,76,199,76,208,232,229,226,242,229,119,128,5,173,
+242,225,231,225,238,97,128,48,103,233,227,239,240,244,233,99,
+128,3,239,235,225,244,225,235,225,238,97,128,48,199,108,2,
+76,244,77,11,229,244,101,2,76,252,77,3,236,229,230,116,
+128,35,43,242,233,231,232,116,128,35,38,244,97,129,3,180,
+77,18,244,245,242,238,229,100,128,1,141,238,239,237,233,238,
+225,244,239,242,237,233,238,245,243,239,238,229,238,245,237,229,
+242,225,244,239,242,226,229,238,231,225,236,105,128,9,248,250,
+104,128,2,164,104,2,77,74,77,124,97,3,77,82,77,92,
+77,99,226,229,238,231,225,236,105,128,9,167,228,229,246,97,
+128,9,39,231,117,2,77,106,77,115,234,225,242,225,244,105,
+128,10,167,242,237,245,235,232,105,128,10,39,239,239,107,128,
+2,87,105,6,77,144,77,193,77,253,78,8,78,19,78,29,
+97,2,77,150,77,172,236,249,244,233,235,225,244,239,238,239,
+115,129,3,133,77,166,227,237,98,128,3,68,237,239,238,100,
+129,38,102,77,181,243,245,233,244,247,232,233,244,101,128,38,
+98,229,242,229,243,233,115,133,0,168,77,212,77,220,77,231,
+77,237,77,245,225,227,245,244,101,128,246,215,226,229,236,239,
+247,227,237,98,128,3,36,227,237,98,128,3,8,231,242,225,
+246,101,128,246,216,244,239,238,239,115,128,3,133,232,233,242,
+225,231,225,238,97,128,48,98,235,225,244,225,235,225,238,97,
+128,48,194,244,244,239,237,225,242,107,128,48,3,246,105,2,
+78,36,78,47,228,101,129,0,247,78,43,115,128,34,35,243,
+233,239,238,243,236,225,243,104,128,34,21,234,229,227,249,242,
+233,236,236,233,99,128,4,82,235,243,232,225,228,101,128,37,
+147,108,2,78,87,78,98,233,238,229,226,229,236,239,119,128,
+30,15,243,241,245,225,242,101,128,51,151,109,2,78,113,78,
+121,225,227,242,239,110,128,1,17,239,238,239,243,240,225,227,
+101,128,255,68,238,226,236,239,227,107,128,37,132,111,10,78,
+163,78,175,78,185,78,196,78,207,79,23,79,28,79,39,79,
+154,79,180,227,232,225,228,225,244,232,225,105,128,14,14,228,
+229,235,244,232,225,105,128,14,20,232,233,242,225,231,225,238,
+97,128,48,105,235,225,244,225,235,225,238,97,128,48,201,236,
+236,225,114,132,0,36,78,222,78,233,78,245,79,0,233,238,
+230,229,242,233,239,114,128,246,227,237,239,238,239,243,240,225,
+227,101,128,255,4,239,236,228,243,244,249,236,101,128,247,36,
+115,2,79,6,79,13,237,225,236,108,128,254,105,245,240,229,
+242,233,239,114,128,246,228,238,103,128,32,171,242,245,243,241,
+245,225,242,101,128,51,38,116,6,79,53,79,70,79,92,79,
+103,79,135,79,142,225,227,227,229,238,116,129,2,217,79,64,
+227,237,98,128,3,7,226,229,236,239,247,99,2,79,81,79,
+86,237,98,128,3,35,239,237,98,128,3,35,235,225,244,225,
+235,225,238,97,128,48,251,236,229,243,115,2,79,112,79,116,
+105,128,1,49,106,129,246,190,79,122,243,244,242,239,235,229,
+232,239,239,107,128,2,132,237,225,244,104,128,34,197,244,229,
+228,227,233,242,227,236,101,128,37,204,245,226,236,229,249,239,
+228,240,225,244,225,104,129,251,31,79,171,232,229,226,242,229,
+119,128,251,31,247,238,244,225,227,107,2,79,191,79,202,226,
+229,236,239,247,227,237,98,128,3,30,237,239,100,128,2,213,
+240,225,242,229,110,128,36,159,243,245,240,229,242,233,239,114,
+128,246,235,116,2,79,233,79,239,225,233,108,128,2,86,239,
+240,226,225,114,128,1,140,117,2,79,253,80,8,232,233,242,
+225,231,225,238,97,128,48,101,235,225,244,225,235,225,238,97,
+128,48,197,122,132,1,243,80,31,80,40,80,59,80,96,225,
+236,244,239,238,101,128,2,163,99,2,80,46,80,53,225,242,
+239,110,128,1,198,245,242,108,128,2,165,101,2,80,65,80,
+85,225,226,235,232,225,243,233,225,238,227,249,242,233,236,236,
+233,99,128,4,225,227,249,242,233,236,236,233,99,128,4,85,
+232,229,227,249,242,233,236,236,233,99,128,4,95,101,151,0,
+101,80,159,80,178,80,212,81,186,81,248,82,25,82,37,82,
+60,82,113,83,225,84,27,84,129,84,245,85,124,85,199,85,
+230,86,36,86,89,87,24,87,157,87,177,87,221,88,56,97,
+2,80,165,80,172,227,245,244,101,128,0,233,242,244,104,128,
+38,65,98,3,80,186,80,195,80,205,229,238,231,225,236,105,
+128,9,143,239,240,239,237,239,230,111,128,49,28,242,229,246,
+101,128,1,21,99,5,80,224,81,41,81,55,81,87,81,176,
+97,2,80,230,81,35,238,228,242,97,3,80,241,80,248,81,
+3,228,229,246,97,128,9,13,231,245,234,225,242,225,244,105,
+128,10,141,246,239,247,229,236,243,233,231,110,2,81,17,81,
+24,228,229,246,97,128,9,69,231,245,234,225,242,225,244,105,
+128,10,197,242,239,110,128,1,27,229,228,233,236,236,225,226,
+242,229,246,101,128,30,29,104,2,81,61,81,72,225,242,237,
+229,238,233,225,110,128,5,101,249,233,247,238,225,242,237,229,
+238,233,225,110,128,5,135,233,242,99,2,81,95,81,100,236,
+101,128,36,212,245,237,230,236,229,120,134,0,234,81,121,81,
+129,81,137,81,148,81,156,81,168,225,227,245,244,101,128,30,
+191,226,229,236,239,119,128,30,25,228,239,244,226,229,236,239,
+119,128,30,199,231,242,225,246,101,128,30,193,232,239,239,235,
+225,226,239,246,101,128,30,195,244,233,236,228,101,128,30,197,
+249,242,233,236,236,233,99,128,4,84,100,4,81,196,81,206,
+81,212,81,222,226,236,231,242,225,246,101,128,2,5,229,246,
+97,128,9,15,233,229,242,229,243,233,115,128,0,235,239,116,
+130,1,23,81,231,81,240,225,227,227,229,238,116,128,1,23,
+226,229,236,239,119,128,30,185,101,2,81,254,82,9,231,245,
+242,237,245,235,232,105,128,10,15,237,225,244,242,225,231,245,
+242,237,245,235,232,105,128,10,71,230,227,249,242,233,236,236,
+233,99,128,4,68,103,2,82,43,82,50,242,225,246,101,128,
+0,232,245,234,225,242,225,244,105,128,10,143,104,4,82,70,
+82,81,82,92,82,102,225,242,237,229,238,233,225,110,128,5,
+103,226,239,240,239,237,239,230,111,128,49,29,233,242,225,231,
+225,238,97,128,48,72,239,239,235,225,226,239,246,101,128,30,
+187,105,4,82,123,82,134,83,192,83,207,226,239,240,239,237,
+239,230,111,128,49,31,231,232,116,142,0,56,82,168,82,177,
+82,187,82,217,82,224,83,6,83,31,83,76,83,110,83,122,
+83,133,83,166,83,174,83,185,225,242,225,226,233,99,128,6,
+104,226,229,238,231,225,236,105,128,9,238,227,233,242,227,236,
+101,129,36,103,82,198,233,238,246,229,242,243,229,243,225,238,
+243,243,229,242,233,102,128,39,145,228,229,246,97,128,9,110,
+229,229,110,2,82,232,82,241,227,233,242,227,236,101,128,36,
+113,112,2,82,247,82,254,225,242,229,110,128,36,133,229,242,
+233,239,100,128,36,153,231,117,2,83,13,83,22,234,225,242,
+225,244,105,128,10,238,242,237,245,235,232,105,128,10,110,104,
+2,83,37,83,63,97,2,83,43,83,54,227,235,225,242,225,
+226,233,99,128,6,104,238,231,250,232,239,117,128,48,40,238,
+239,244,229,226,229,225,237,229,100,128,38,107,105,2,83,82,
+83,100,228,229,239,231,242,225,240,232,233,227,240,225,242,229,
+110,128,50,39,238,230,229,242,233,239,114,128,32,136,237,239,
+238,239,243,240,225,227,101,128,255,24,239,236,228,243,244,249,
+236,101,128,247,56,112,2,83,139,83,146,225,242,229,110,128,
+36,123,229,114,2,83,153,83,159,233,239,100,128,36,143,243,
+233,225,110,128,6,248,242,239,237,225,110,128,33,119,243,245,
+240,229,242,233,239,114,128,32,120,244,232,225,105,128,14,88,
+238,246,229,242,244,229,228,226,242,229,246,101,128,2,7,239,
+244,233,230,233,229,228,227,249,242,233,236,236,233,99,128,4,
+101,107,2,83,231,83,255,225,244,225,235,225,238,97,129,48,
+168,83,243,232,225,236,230,247,233,228,244,104,128,255,116,111,
+2,84,5,84,20,238,235,225,242,231,245,242,237,245,235,232,
+105,128,10,116,242,229,225,110,128,49,84,108,3,84,35,84,
+46,84,107,227,249,242,233,236,236,233,99,128,4,59,101,2,
+84,52,84,59,237,229,238,116,128,34,8,246,229,110,3,84,
+69,84,78,84,99,227,233,242,227,236,101,128,36,106,112,2,
+84,84,84,91,225,242,229,110,128,36,126,229,242,233,239,100,
+128,36,146,242,239,237,225,110,128,33,122,236,233,240,243,233,
+115,129,32,38,84,118,246,229,242,244,233,227,225,108,128,34,
+238,109,5,84,141,84,169,84,180,84,200,84,211,225,227,242,
+239,110,130,1,19,84,153,84,161,225,227,245,244,101,128,30,
+23,231,242,225,246,101,128,30,21,227,249,242,233,236,236,233,
+99,128,4,60,228,225,243,104,129,32,20,84,189,246,229,242,
+244,233,227,225,108,128,254,49,239,238,239,243,240,225,227,101,
+128,255,69,112,2,84,217,84,237,232,225,243,233,243,237,225,
+242,235,225,242,237,229,238,233,225,110,128,5,91,244,249,243,
+229,116,128,34,5,110,6,85,3,85,14,85,25,85,69,85,
+101,85,116,226,239,240,239,237,239,230,111,128,49,35,227,249,
+242,233,236,236,233,99,128,4,61,100,2,85,31,85,50,225,
+243,104,129,32,19,85,39,246,229,242,244,233,227,225,108,128,
+254,50,229,243,227,229,238,228,229,242,227,249,242,233,236,236,
+233,99,128,4,163,103,130,1,75,85,77,85,88,226,239,240,
+239,237,239,230,111,128,49,37,232,229,227,249,242,233,236,236,
+233,99,128,4,165,232,239,239,235,227,249,242,233,236,236,233,
+99,128,4,200,243,240,225,227,101,128,32,2,111,3,85,132,
+85,140,85,149,231,239,238,229,107,128,1,25,235,239,242,229,
+225,110,128,49,83,240,229,110,130,2,91,85,159,85,168,227,
+236,239,243,229,100,128,2,154,242,229,246,229,242,243,229,100,
+130,2,92,85,183,85,192,227,236,239,243,229,100,128,2,94,
+232,239,239,107,128,2,93,112,2,85,205,85,212,225,242,229,
+110,128,36,160,243,233,236,239,110,129,3,181,85,222,244,239,
+238,239,115,128,3,173,241,117,2,85,237,86,25,225,108,130,
+0,61,85,246,86,2,237,239,238,239,243,240,225,227,101,128,
+255,29,115,2,86,8,86,15,237,225,236,108,128,254,102,245,
+240,229,242,233,239,114,128,32,124,233,246,225,236,229,238,227,
+101,128,34,97,114,3,86,44,86,55,86,66,226,239,240,239,
+237,239,230,111,128,49,38,227,249,242,233,236,236,233,99,128,
+4,64,229,246,229,242,243,229,100,129,2,88,86,78,227,249,
+242,233,236,236,233,99,128,4,77,115,6,86,103,86,114,86,
+134,86,215,87,4,87,14,227,249,242,233,236,236,233,99,128,
+4,65,228,229,243,227,229,238,228,229,242,227,249,242,233,236,
+236,233,99,128,4,171,104,132,2,131,86,146,86,153,86,184,
+86,199,227,245,242,108,128,2,134,239,242,116,2,86,161,86,
+168,228,229,246,97,128,9,14,246,239,247,229,236,243,233,231,
+238,228,229,246,97,128,9,70,242,229,246,229,242,243,229,228,
+236,239,239,112,128,1,170,243,241,245,225,244,242,229,246,229,
+242,243,229,100,128,2,133,237,225,236,108,2,86,224,86,235,
+232,233,242,225,231,225,238,97,128,48,71,235,225,244,225,235,
+225,238,97,129,48,167,86,248,232,225,236,230,247,233,228,244,
+104,128,255,106,244,233,237,225,244,229,100,128,33,46,245,240,
+229,242,233,239,114,128,246,236,116,5,87,36,87,62,87,66,
+87,83,87,149,97,130,3,183,87,44,87,54,242,237,229,238,
+233,225,110,128,5,104,244,239,238,239,115,128,3,174,104,128,
+0,240,233,236,228,101,129,30,189,87,75,226,229,236,239,119,
+128,30,27,238,225,232,244,97,3,87,95,87,127,87,136,230,
+239,245,235,104,2,87,105,87,114,232,229,226,242,229,119,128,
+5,145,236,229,230,244,232,229,226,242,229,119,128,5,145,232,
+229,226,242,229,119,128,5,145,236,229,230,244,232,229,226,242,
+229,119,128,5,145,245,242,238,229,100,128,1,221,117,2,87,
+163,87,172,235,239,242,229,225,110,128,49,97,242,111,128,32,
+172,246,239,247,229,236,243,233,231,110,3,87,193,87,203,87,
+210,226,229,238,231,225,236,105,128,9,199,228,229,246,97,128,
+9,71,231,245,234,225,242,225,244,105,128,10,199,120,2,87,
+227,88,44,227,236,225,109,132,0,33,87,242,87,253,88,24,
+88,36,225,242,237,229,238,233,225,110,128,5,92,100,2,88,
+3,88,8,226,108,128,32,60,239,247,110,129,0,161,88,16,
+243,237,225,236,108,128,247,161,237,239,238,239,243,240,225,227,
+101,128,255,1,243,237,225,236,108,128,247,33,233,243,244,229,
+238,244,233,225,108,128,34,3,250,104,131,2,146,88,67,88,
+86,88,97,99,2,88,73,88,80,225,242,239,110,128,1,239,
+245,242,108,128,2,147,242,229,246,229,242,243,229,100,128,1,
+185,244,225,233,108,128,1,186,102,140,0,102,88,132,88,214,
+88,225,88,234,88,246,89,93,89,109,91,117,91,130,91,156,
+93,33,93,41,97,4,88,142,88,149,88,160,88,171,228,229,
+246,97,128,9,94,231,245,242,237,245,235,232,105,128,10,94,
+232,242,229,238,232,229,233,116,128,33,9,244,232,97,3,88,
+181,88,190,88,202,225,242,225,226,233,99,128,6,78,236,239,
+247,225,242,225,226,233,99,128,6,78,244,225,238,225,242,225,
+226,233,99,128,6,75,226,239,240,239,237,239,230,111,128,49,
+8,227,233,242,227,236,101,128,36,213,228,239,244,225,227,227,
+229,238,116,128,30,31,101,3,88,254,89,76,89,86,104,4,
+89,8,89,31,89,45,89,61,225,114,2,89,15,89,22,225,
+226,233,99,128,6,65,237,229,238,233,225,110,128,5,134,230,
+233,238,225,236,225,242,225,226,233,99,128,254,210,233,238,233,
+244,233,225,236,225,242,225,226,233,99,128,254,211,237,229,228,
+233,225,236,225,242,225,226,233,99,128,254,212,233,227,239,240,
+244,233,99,128,3,229,237,225,236,101,128,38,64,102,130,251,
+0,89,101,89,105,105,128,251,3,108,128,251,4,105,136,251,
+1,89,129,89,169,89,180,89,202,90,68,90,85,90,93,90,
+106,230,244,229,229,110,2,89,139,89,148,227,233,242,227,236,
+101,128,36,110,112,2,89,154,89,161,225,242,229,110,128,36,
+130,229,242,233,239,100,128,36,150,231,245,242,229,228,225,243,
+104,128,32,18,236,236,229,100,2,89,189,89,195,226,239,120,
+128,37,160,242,229,227,116,128,37,172,238,225,108,5,89,216,
+89,255,90,16,90,33,90,49,235,225,102,130,5,218,89,226,
+89,246,228,225,231,229,243,104,129,251,58,89,237,232,229,226,
+242,229,119,128,251,58,232,229,226,242,229,119,128,5,218,237,
+229,109,129,5,221,90,7,232,229,226,242,229,119,128,5,221,
+238,245,110,129,5,223,90,24,232,229,226,242,229,119,128,5,
+223,240,101,129,5,227,90,40,232,229,226,242,229,119,128,5,
+227,244,243,225,228,105,129,5,229,90,59,232,229,226,242,229,
+119,128,5,229,242,243,244,244,239,238,229,227,232,233,238,229,
+243,101,128,2,201,243,232,229,249,101,128,37,201,244,225,227,
+249,242,233,236,236,233,99,128,4,115,246,101,142,0,53,90,
+139,90,148,90,158,90,188,90,195,90,205,90,230,91,1,91,
+35,91,47,91,58,91,91,91,99,91,110,225,242,225,226,233,
+99,128,6,101,226,229,238,231,225,236,105,128,9,235,227,233,
+242,227,236,101,129,36,100,90,169,233,238,246,229,242,243,229,
+243,225,238,243,243,229,242,233,102,128,39,142,228,229,246,97,
+128,9,107,229,233,231,232,244,232,115,128,33,93,231,117,2,
+90,212,90,221,234,225,242,225,244,105,128,10,235,242,237,245,
+235,232,105,128,10,107,232,97,2,90,237,90,248,227,235,225,
+242,225,226,233,99,128,6,101,238,231,250,232,239,117,128,48,
+37,105,2,91,7,91,25,228,229,239,231,242,225,240,232,233,
+227,240,225,242,229,110,128,50,36,238,230,229,242,233,239,114,
+128,32,133,237,239,238,239,243,240,225,227,101,128,255,21,239,
+236,228,243,244,249,236,101,128,247,53,112,2,91,64,91,71,
+225,242,229,110,128,36,120,229,114,2,91,78,91,84,233,239,
+100,128,36,140,243,233,225,110,128,6,245,242,239,237,225,110,
+128,33,116,243,245,240,229,242,233,239,114,128,32,117,244,232,
+225,105,128,14,85,108,129,251,2,91,123,239,242,233,110,128,
+1,146,109,2,91,136,91,147,239,238,239,243,240,225,227,101,
+128,255,70,243,241,245,225,242,101,128,51,153,111,4,91,166,
+91,188,91,200,91,207,230,97,2,91,173,91,181,238,244,232,
+225,105,128,14,31,244,232,225,105,128,14,29,238,231,237,225,
+238,244,232,225,105,128,14,79,242,225,236,108,128,34,0,245,
+114,142,0,52,91,240,91,249,92,3,92,33,92,40,92,65,
+92,92,92,126,92,138,92,157,92,168,92,201,92,209,92,220,
+225,242,225,226,233,99,128,6,100,226,229,238,231,225,236,105,
+128,9,234,227,233,242,227,236,101,129,36,99,92,14,233,238,
+246,229,242,243,229,243,225,238,243,243,229,242,233,102,128,39,
+141,228,229,246,97,128,9,106,231,117,2,92,47,92,56,234,
+225,242,225,244,105,128,10,234,242,237,245,235,232,105,128,10,
+106,232,97,2,92,72,92,83,227,235,225,242,225,226,233,99,
+128,6,100,238,231,250,232,239,117,128,48,36,105,2,92,98,
+92,116,228,229,239,231,242,225,240,232,233,227,240,225,242,229,
+110,128,50,35,238,230,229,242,233,239,114,128,32,132,237,239,
+238,239,243,240,225,227,101,128,255,20,238,245,237,229,242,225,
+244,239,242,226,229,238,231,225,236,105,128,9,247,239,236,228,
+243,244,249,236,101,128,247,52,112,2,92,174,92,181,225,242,
+229,110,128,36,119,229,114,2,92,188,92,194,233,239,100,128,
+36,139,243,233,225,110,128,6,244,242,239,237,225,110,128,33,
+115,243,245,240,229,242,233,239,114,128,32,116,116,2,92,226,
+93,8,229,229,110,2,92,234,92,243,227,233,242,227,236,101,
+128,36,109,112,2,92,249,93,0,225,242,229,110,128,36,129,
+229,242,233,239,100,128,36,149,104,2,93,14,93,19,225,105,
+128,14,84,244,239,238,229,227,232,233,238,229,243,101,128,2,
+203,240,225,242,229,110,128,36,161,242,97,2,93,48,93,56,
+227,244,233,239,110,128,32,68,238,99,128,32,163,103,144,0,
+103,93,97,94,43,94,66,94,127,94,144,95,65,96,58,96,
+143,96,156,97,14,97,39,97,67,97,89,98,34,98,56,98,
+158,97,9,93,117,93,127,93,134,93,141,93,205,93,230,93,
+241,93,252,94,30,226,229,238,231,225,236,105,128,9,151,227,
+245,244,101,128,1,245,228,229,246,97,128,9,23,102,4,93,
+151,93,160,93,174,93,190,225,242,225,226,233,99,128,6,175,
+230,233,238,225,236,225,242,225,226,233,99,128,251,147,233,238,
+233,244,233,225,236,225,242,225,226,233,99,128,251,148,237,229,
+228,233,225,236,225,242,225,226,233,99,128,251,149,231,117,2,
+93,212,93,221,234,225,242,225,244,105,128,10,151,242,237,245,
+235,232,105,128,10,23,232,233,242,225,231,225,238,97,128,48,
+76,235,225,244,225,235,225,238,97,128,48,172,237,237,97,130,
+3,179,94,6,94,19,236,225,244,233,238,243,237,225,236,108,
+128,2,99,243,245,240,229,242,233,239,114,128,2,224,238,231,
+233,225,227,239,240,244,233,99,128,3,235,98,2,94,49,94,
+59,239,240,239,237,239,230,111,128,49,13,242,229,246,101,128,
+1,31,99,4,94,76,94,83,94,92,94,114,225,242,239,110,
+128,1,231,229,228,233,236,236,97,128,1,35,233,242,99,2,
+94,100,94,105,236,101,128,36,214,245,237,230,236,229,120,128,
+1,29,239,237,237,225,225,227,227,229,238,116,128,1,35,228,
+239,116,129,1,33,94,135,225,227,227,229,238,116,128,1,33,
+101,6,94,158,94,169,94,180,94,191,94,210,95,56,227,249,
+242,233,236,236,233,99,128,4,51,232,233,242,225,231,225,238,
+97,128,48,82,235,225,244,225,235,225,238,97,128,48,178,239,
+237,229,244,242,233,227,225,236,236,249,229,241,245,225,108,128,
+34,81,114,3,94,218,95,11,95,21,229,243,104,3,94,228,
+94,243,94,252,225,227,227,229,238,244,232,229,226,242,229,119,
+128,5,156,232,229,226,242,229,119,128,5,243,237,245,241,228,
+225,237,232,229,226,242,229,119,128,5,157,237,225,238,228,226,
+236,115,128,0,223,243,232,225,249,233,109,2,95,32,95,47,
+225,227,227,229,238,244,232,229,226,242,229,119,128,5,158,232,
+229,226,242,229,119,128,5,244,244,225,237,225,242,107,128,48,
+19,104,5,95,77,95,210,96,17,96,42,96,48,97,4,95,
+87,95,97,95,120,95,145,226,229,238,231,225,236,105,128,9,
+152,100,2,95,103,95,114,225,242,237,229,238,233,225,110,128,
+5,114,229,246,97,128,9,24,231,117,2,95,127,95,136,234,
+225,242,225,244,105,128,10,152,242,237,245,235,232,105,128,10,
+24,233,110,4,95,156,95,165,95,179,95,195,225,242,225,226,
+233,99,128,6,58,230,233,238,225,236,225,242,225,226,233,99,
+128,254,206,233,238,233,244,233,225,236,225,242,225,226,233,99,
+128,254,207,237,229,228,233,225,236,225,242,225,226,233,99,128,
+254,208,101,3,95,218,95,239,96,0,237,233,228,228,236,229,
+232,239,239,235,227,249,242,233,236,236,233,99,128,4,149,243,
+244,242,239,235,229,227,249,242,233,236,236,233,99,128,4,147,
+245,240,244,245,242,238,227,249,242,233,236,236,233,99,128,4,
+145,232,97,2,96,24,96,31,228,229,246,97,128,9,90,231,
+245,242,237,245,235,232,105,128,10,90,239,239,107,128,2,96,
+250,243,241,245,225,242,101,128,51,147,105,3,96,66,96,77,
+96,88,232,233,242,225,231,225,238,97,128,48,78,235,225,244,
+225,235,225,238,97,128,48,174,109,2,96,94,96,105,225,242,
+237,229,238,233,225,110,128,5,99,229,108,130,5,210,96,114,
+96,134,228,225,231,229,243,104,129,251,50,96,125,232,229,226,
+242,229,119,128,251,50,232,229,226,242,229,119,128,5,210,234,
+229,227,249,242,233,236,236,233,99,128,4,83,236,239,244,244,
+225,108,2,96,167,96,184,233,238,246,229,242,244,229,228,243,
+244,242,239,235,101,128,1,190,243,244,239,112,132,2,148,96,
+199,96,210,96,216,96,248,233,238,246,229,242,244,229,100,128,
+2,150,237,239,100,128,2,192,242,229,246,229,242,243,229,100,
+130,2,149,96,231,96,237,237,239,100,128,2,193,243,245,240,
+229,242,233,239,114,128,2,228,243,244,242,239,235,101,129,2,
+161,97,3,242,229,246,229,242,243,229,100,128,2,162,109,2,
+97,20,97,28,225,227,242,239,110,128,30,33,239,238,239,243,
+240,225,227,101,128,255,71,111,2,97,45,97,56,232,233,242,
+225,231,225,238,97,128,48,84,235,225,244,225,235,225,238,97,
+128,48,180,240,97,2,97,74,97,80,242,229,110,128,36,162,
+243,241,245,225,242,101,128,51,172,114,2,97,95,97,192,97,
+2,97,101,97,109,228,233,229,238,116,128,34,7,246,101,134,
+0,96,97,126,97,137,97,154,97,161,97,170,97,182,226,229,
+236,239,247,227,237,98,128,3,22,99,2,97,143,97,148,237,
+98,128,3,0,239,237,98,128,3,0,228,229,246,97,128,9,
+83,236,239,247,237,239,100,128,2,206,237,239,238,239,243,240,
+225,227,101,128,255,64,244,239,238,229,227,237,98,128,3,64,
+229,225,244,229,114,132,0,62,97,208,97,227,97,239,98,26,
+229,241,245,225,108,129,34,101,97,218,239,242,236,229,243,115,
+128,34,219,237,239,238,239,243,240,225,227,101,128,255,30,111,
+2,97,245,98,15,114,2,97,251,98,8,229,241,245,233,246,
+225,236,229,238,116,128,34,115,236,229,243,115,128,34,119,246,
+229,242,229,241,245,225,108,128,34,103,243,237,225,236,108,128,
+254,101,115,2,98,40,98,48,227,242,233,240,116,128,2,97,
+244,242,239,235,101,128,1,229,117,4,98,66,98,77,98,134,
+98,145,232,233,242,225,231,225,238,97,128,48,80,233,108,2,
+98,84,98,109,236,229,237,239,116,2,98,94,98,101,236,229,
+230,116,128,0,171,242,233,231,232,116,128,0,187,243,233,238,
+231,108,2,98,119,98,126,236,229,230,116,128,32,57,242,233,
+231,232,116,128,32,58,235,225,244,225,235,225,238,97,128,48,
+176,242,225,237,245,243,241,245,225,242,101,128,51,24,249,243,
+241,245,225,242,101,128,51,201,104,144,0,104,98,204,101,90,
+101,125,101,162,101,202,103,90,103,110,104,75,104,87,104,99,
+105,167,105,175,105,186,105,195,106,19,106,23,97,13,98,232,
+99,15,99,25,99,55,99,80,99,158,99,170,99,195,99,210,
+99,239,99,252,100,54,100,63,97,2,98,238,99,1,226,235,
+232,225,243,233,225,238,227,249,242,233,236,236,233,99,128,4,
+169,236,244,239,238,229,225,242,225,226,233,99,128,6,193,226,
+229,238,231,225,236,105,128,9,185,228,101,2,99,32,99,50,
+243,227,229,238,228,229,242,227,249,242,233,236,236,233,99,128,
+4,179,246,97,128,9,57,231,117,2,99,62,99,71,234,225,
+242,225,244,105,128,10,185,242,237,245,235,232,105,128,10,57,
+104,4,99,90,99,99,99,113,99,143,225,242,225,226,233,99,
+128,6,45,230,233,238,225,236,225,242,225,226,233,99,128,254,
+162,105,2,99,119,99,134,238,233,244,233,225,236,225,242,225,
+226,233,99,128,254,163,242,225,231,225,238,97,128,48,111,237,
+229,228,233,225,236,225,242,225,226,233,99,128,254,164,233,244,
+245,243,241,245,225,242,101,128,51,42,235,225,244,225,235,225,
+238,97,129,48,207,99,183,232,225,236,230,247,233,228,244,104,
+128,255,138,236,225,238,244,231,245,242,237,245,235,232,105,128,
+10,77,237,250,97,2,99,218,99,227,225,242,225,226,233,99,
+128,6,33,236,239,247,225,242,225,226,233,99,128,6,33,238,
+231,245,236,230,233,236,236,229,114,128,49,100,114,2,100,2,
+100,18,228,243,233,231,238,227,249,242,233,236,236,233,99,128,
+4,74,240,239,239,110,2,100,27,100,40,236,229,230,244,226,
+225,242,226,245,112,128,33,188,242,233,231,232,244,226,225,242,
+226,245,112,128,33,192,243,241,245,225,242,101,128,51,202,244,
+225,102,3,100,73,100,165,101,0,240,225,244,225,104,134,5,
+178,100,93,100,98,100,112,100,121,100,136,100,152,177,54,128,
+5,178,50,2,100,104,100,108,51,128,5,178,102,128,5,178,
+232,229,226,242,229,119,128,5,178,238,225,242,242,239,247,232,
+229,226,242,229,119,128,5,178,241,245,225,242,244,229,242,232,
+229,226,242,229,119,128,5,178,247,233,228,229,232,229,226,242,
+229,119,128,5,178,241,225,237,225,244,115,135,5,179,100,188,
+100,193,100,198,100,203,100,212,100,227,100,243,177,98,128,5,
+179,178,56,128,5,179,179,52,128,5,179,232,229,226,242,229,
+119,128,5,179,238,225,242,242,239,247,232,229,226,242,229,119,
+128,5,179,241,245,225,242,244,229,242,232,229,226,242,229,119,
+128,5,179,247,233,228,229,232,229,226,242,229,119,128,5,179,
+243,229,231,239,108,135,5,177,101,22,101,27,101,32,101,37,
+101,46,101,61,101,77,177,55,128,5,177,178,52,128,5,177,
+179,48,128,5,177,232,229,226,242,229,119,128,5,177,238,225,
+242,242,239,247,232,229,226,242,229,119,128,5,177,241,245,225,
+242,244,229,242,232,229,226,242,229,119,128,5,177,247,233,228,
+229,232,229,226,242,229,119,128,5,177,98,3,101,98,101,103,
+101,113,225,114,128,1,39,239,240,239,237,239,230,111,128,49,
+15,242,229,246,229,226,229,236,239,119,128,30,43,99,2,101,
+131,101,140,229,228,233,236,236,97,128,30,41,233,242,99,2,
+101,148,101,153,236,101,128,36,215,245,237,230,236,229,120,128,
+1,37,100,2,101,168,101,178,233,229,242,229,243,233,115,128,
+30,39,239,116,2,101,185,101,194,225,227,227,229,238,116,128,
+30,35,226,229,236,239,119,128,30,37,101,136,5,212,101,222,
+101,255,102,19,102,248,103,8,103,53,103,62,103,75,225,242,
+116,129,38,101,101,230,243,245,233,116,2,101,239,101,247,226,
+236,225,227,107,128,38,101,247,232,233,244,101,128,38,97,228,
+225,231,229,243,104,129,251,52,102,10,232,229,226,242,229,119,
+128,251,52,104,6,102,33,102,61,102,69,102,119,102,165,102,
+214,97,2,102,39,102,53,236,244,239,238,229,225,242,225,226,
+233,99,128,6,193,242,225,226,233,99,128,6,71,229,226,242,
+229,119,128,5,212,230,233,238,225,236,97,2,102,80,102,111,
+236,116,2,102,87,102,99,239,238,229,225,242,225,226,233,99,
+128,251,167,244,247,239,225,242,225,226,233,99,128,254,234,242,
+225,226,233,99,128,254,234,232,225,237,250,225,225,226,239,246,
+101,2,102,134,102,148,230,233,238,225,236,225,242,225,226,233,
+99,128,251,165,233,243,239,236,225,244,229,228,225,242,225,226,
+233,99,128,251,164,105,2,102,171,102,205,238,233,244,233,225,
+236,97,2,102,183,102,197,236,244,239,238,229,225,242,225,226,
+233,99,128,251,168,242,225,226,233,99,128,254,235,242,225,231,
+225,238,97,128,48,120,237,229,228,233,225,236,97,2,102,226,
+102,240,236,244,239,238,229,225,242,225,226,233,99,128,251,169,
+242,225,226,233,99,128,254,236,233,243,229,233,229,242,225,243,
+241,245,225,242,101,128,51,123,107,2,103,14,103,38,225,244,
+225,235,225,238,97,129,48,216,103,26,232,225,236,230,247,233,
+228,244,104,128,255,141,245,244,225,225,242,245,243,241,245,225,
+242,101,128,51,54,238,231,232,239,239,107,128,2,103,242,245,
+244,245,243,241,245,225,242,101,128,51,57,116,129,5,215,103,
+81,232,229,226,242,229,119,128,5,215,232,239,239,107,129,2,
+102,103,99,243,245,240,229,242,233,239,114,128,2,177,105,4,
+103,120,103,205,103,216,103,241,229,245,104,4,103,132,103,167,
+103,182,103,191,97,2,103,138,103,153,227,233,242,227,236,229,
+235,239,242,229,225,110,128,50,123,240,225,242,229,238,235,239,
+242,229,225,110,128,50,27,227,233,242,227,236,229,235,239,242,
+229,225,110,128,50,109,235,239,242,229,225,110,128,49,78,240,
+225,242,229,238,235,239,242,229,225,110,128,50,13,232,233,242,
+225,231,225,238,97,128,48,114,235,225,244,225,235,225,238,97,
+129,48,210,103,229,232,225,236,230,247,233,228,244,104,128,255,
+139,242,233,113,134,5,180,104,3,104,8,104,22,104,31,104,
+46,104,62,177,52,128,5,180,50,2,104,14,104,18,49,128,
+5,180,100,128,5,180,232,229,226,242,229,119,128,5,180,238,
+225,242,242,239,247,232,229,226,242,229,119,128,5,180,241,245,
+225,242,244,229,242,232,229,226,242,229,119,128,5,180,247,233,
+228,229,232,229,226,242,229,119,128,5,180,236,233,238,229,226,
+229,236,239,119,128,30,150,237,239,238,239,243,240,225,227,101,
+128,255,72,111,9,104,119,104,130,104,154,104,179,105,11,105,
+24,105,110,105,150,105,161,225,242,237,229,238,233,225,110,128,
+5,112,232,105,2,104,137,104,145,240,244,232,225,105,128,14,
+43,242,225,231,225,238,97,128,48,123,235,225,244,225,235,225,
+238,97,129,48,219,104,167,232,225,236,230,247,233,228,244,104,
+128,255,142,236,225,109,135,5,185,104,199,104,204,104,209,104,
+214,104,223,104,238,104,254,177,57,128,5,185,178,54,128,5,
+185,179,50,128,5,185,232,229,226,242,229,119,128,5,185,238,
+225,242,242,239,247,232,229,226,242,229,119,128,5,185,241,245,
+225,242,244,229,242,232,229,226,242,229,119,128,5,185,247,233,
+228,229,232,229,226,242,229,119,128,5,185,238,239,235,232,245,
+235,244,232,225,105,128,14,46,111,2,105,30,105,100,107,4,
+105,40,105,52,105,58,105,80,225,226,239,246,229,227,239,237,
+98,128,3,9,227,237,98,128,3,9,240,225,236,225,244,225,
+236,233,250,229,228,226,229,236,239,247,227,237,98,128,3,33,
+242,229,244,242,239,230,236,229,248,226,229,236,239,247,227,237,
+98,128,3,34,238,243,241,245,225,242,101,128,51,66,114,2,
+105,116,105,143,105,2,105,122,105,131,227,239,240,244,233,99,
+128,3,233,250,239,238,244,225,236,226,225,114,128,32,21,238,
+227,237,98,128,3,27,244,243,240,242,233,238,231,115,128,38,
+104,245,243,101,128,35,2,240,225,242,229,110,128,36,163,243,
+245,240,229,242,233,239,114,128,2,176,244,245,242,238,229,100,
+128,2,101,117,4,105,205,105,216,105,229,105,254,232,233,242,
+225,231,225,238,97,128,48,117,233,233,244,239,243,241,245,225,
+242,101,128,51,51,235,225,244,225,235,225,238,97,129,48,213,
+105,242,232,225,236,230,247,233,228,244,104,128,255,140,238,231,
+225,242,245,237,236,225,245,116,129,2,221,106,13,227,237,98,
+128,3,11,118,128,1,149,249,240,232,229,110,132,0,45,106,
+39,106,50,106,62,106,85,233,238,230,229,242,233,239,114,128,
+246,229,237,239,238,239,243,240,225,227,101,128,255,13,115,2,
+106,68,106,75,237,225,236,108,128,254,99,245,240,229,242,233,
+239,114,128,246,230,244,247,111,128,32,16,105,149,0,105,106,
+137,106,160,106,194,106,241,110,123,110,243,111,24,111,51,111,
+213,111,217,111,255,112,21,112,105,113,14,113,89,113,97,113,
+110,113,197,113,254,114,26,114,70,225,99,2,106,144,106,150,
+245,244,101,128,0,237,249,242,233,236,236,233,99,128,4,79,
+98,3,106,168,106,177,106,187,229,238,231,225,236,105,128,9,
+135,239,240,239,237,239,230,111,128,49,39,242,229,246,101,128,
+1,45,99,3,106,202,106,209,106,231,225,242,239,110,128,1,
+208,233,242,99,2,106,217,106,222,236,101,128,36,216,245,237,
+230,236,229,120,128,0,238,249,242,233,236,236,233,99,128,4,
+86,100,4,106,251,107,5,110,80,110,113,226,236,231,242,225,
+246,101,128,2,9,101,2,107,11,110,75,239,231,242,225,240,
+104,7,107,32,107,46,107,59,109,244,110,19,110,32,110,44,
+229,225,242,244,232,227,233,242,227,236,101,128,50,143,230,233,
+242,229,227,233,242,227,236,101,128,50,139,233,99,14,107,90,
+107,106,107,205,108,3,108,69,108,98,108,114,108,171,108,220,
+108,232,109,3,109,70,109,208,109,237,225,236,236,233,225,238,
+227,229,240,225,242,229,110,128,50,63,99,4,107,116,107,127,
+107,141,107,148,225,236,236,240,225,242,229,110,128,50,58,229,
+238,244,242,229,227,233,242,227,236,101,128,50,165,236,239,243,
+101,128,48,6,111,3,107,156,107,171,107,191,237,237,97,129,
+48,1,107,164,236,229,230,116,128,255,100,238,231,242,225,244,
+245,236,225,244,233,239,238,240,225,242,229,110,128,50,55,242,
+242,229,227,244,227,233,242,227,236,101,128,50,163,101,3,107,
+213,107,225,107,242,225,242,244,232,240,225,242,229,110,128,50,
+47,238,244,229,242,240,242,233,243,229,240,225,242,229,110,128,
+50,61,248,227,229,236,236,229,238,244,227,233,242,227,236,101,
+128,50,157,102,2,108,9,108,24,229,243,244,233,246,225,236,
+240,225,242,229,110,128,50,64,105,2,108,30,108,59,238,225,
+238,227,233,225,108,2,108,42,108,51,227,233,242,227,236,101,
+128,50,150,240,225,242,229,110,128,50,54,242,229,240,225,242,
+229,110,128,50,43,104,2,108,75,108,86,225,246,229,240,225,
+242,229,110,128,50,50,233,231,232,227,233,242,227,236,101,128,
+50,164,233,244,229,242,225,244,233,239,238,237,225,242,107,128,
+48,5,108,3,108,122,108,148,108,160,225,226,239,114,2,108,
+131,108,140,227,233,242,227,236,101,128,50,152,240,225,242,229,
+110,128,50,56,229,230,244,227,233,242,227,236,101,128,50,167,
+239,247,227,233,242,227,236,101,128,50,166,109,2,108,177,108,
+209,101,2,108,183,108,198,228,233,227,233,238,229,227,233,242,
+227,236,101,128,50,169,244,225,236,240,225,242,229,110,128,50,
+46,239,239,238,240,225,242,229,110,128,50,42,238,225,237,229,
+240,225,242,229,110,128,50,52,112,2,108,238,108,246,229,242,
+233,239,100,128,48,2,242,233,238,244,227,233,242,227,236,101,
+128,50,158,114,2,109,9,109,57,101,3,109,17,109,28,109,
+43,225,227,232,240,225,242,229,110,128,50,67,240,242,229,243,
+229,238,244,240,225,242,229,110,128,50,57,243,239,245,242,227,
+229,240,225,242,229,110,128,50,62,233,231,232,244,227,233,242,
+227,236,101,128,50,168,115,5,109,82,109,111,109,125,109,150,
+109,178,101,2,109,88,109,101,227,242,229,244,227,233,242,227,
+236,101,128,50,153,236,230,240,225,242,229,110,128,50,66,239,
+227,233,229,244,249,240,225,242,229,110,128,50,51,112,2,109,
+131,109,137,225,227,101,128,48,0,229,227,233,225,236,240,225,
+242,229,110,128,50,53,116,2,109,156,109,167,239,227,235,240,
+225,242,229,110,128,50,49,245,228,249,240,225,242,229,110,128,
+50,59,117,2,109,184,109,193,238,240,225,242,229,110,128,50,
+48,240,229,242,246,233,243,229,240,225,242,229,110,128,50,60,
+119,2,109,214,109,226,225,244,229,242,240,225,242,229,110,128,
+50,44,239,239,228,240,225,242,229,110,128,50,45,250,229,242,
+111,128,48,7,109,2,109,250,110,7,229,244,225,236,227,233,
+242,227,236,101,128,50,142,239,239,238,227,233,242,227,236,101,
+128,50,138,238,225,237,229,227,233,242,227,236,101,128,50,148,
+243,245,238,227,233,242,227,236,101,128,50,144,119,2,110,50,
+110,63,225,244,229,242,227,233,242,227,236,101,128,50,140,239,
+239,228,227,233,242,227,236,101,128,50,141,246,97,128,9,7,
+233,229,242,229,243,233,115,130,0,239,110,94,110,102,225,227,
+245,244,101,128,30,47,227,249,242,233,236,236,233,99,128,4,
+229,239,244,226,229,236,239,119,128,30,203,101,3,110,131,110,
+147,110,158,226,242,229,246,229,227,249,242,233,236,236,233,99,
+128,4,215,227,249,242,233,236,236,233,99,128,4,53,245,238,
+103,4,110,170,110,205,110,220,110,229,97,2,110,176,110,191,
+227,233,242,227,236,229,235,239,242,229,225,110,128,50,117,240,
+225,242,229,238,235,239,242,229,225,110,128,50,21,227,233,242,
+227,236,229,235,239,242,229,225,110,128,50,103,235,239,242,229,
+225,110,128,49,71,240,225,242,229,238,235,239,242,229,225,110,
+128,50,7,103,2,110,249,111,0,242,225,246,101,128,0,236,
+117,2,111,6,111,15,234,225,242,225,244,105,128,10,135,242,
+237,245,235,232,105,128,10,7,104,2,111,30,111,40,233,242,
+225,231,225,238,97,128,48,68,239,239,235,225,226,239,246,101,
+128,30,201,105,8,111,69,111,79,111,90,111,97,111,122,111,
+138,111,153,111,169,226,229,238,231,225,236,105,128,9,136,227,
+249,242,233,236,236,233,99,128,4,56,228,229,246,97,128,9,
+8,231,117,2,111,104,111,113,234,225,242,225,244,105,128,10,
+136,242,237,245,235,232,105,128,10,8,237,225,244,242,225,231,
+245,242,237,245,235,232,105,128,10,64,238,246,229,242,244,229,
+228,226,242,229,246,101,128,2,11,243,232,239,242,244,227,249,
+242,233,236,236,233,99,128,4,57,246,239,247,229,236,243,233,
+231,110,3,111,185,111,195,111,202,226,229,238,231,225,236,105,
+128,9,192,228,229,246,97,128,9,64,231,245,234,225,242,225,
+244,105,128,10,192,106,128,1,51,107,2,111,223,111,247,225,
+244,225,235,225,238,97,129,48,164,111,235,232,225,236,230,247,
+233,228,244,104,128,255,114,239,242,229,225,110,128,49,99,108,
+2,112,5,112,10,228,101,128,2,220,245,249,232,229,226,242,
+229,119,128,5,172,109,2,112,27,112,94,97,3,112,35,112,
+55,112,80,227,242,239,110,129,1,43,112,44,227,249,242,233,
+236,236,233,99,128,4,227,231,229,239,242,225,240,240,242,239,
+248,233,237,225,244,229,236,249,229,241,245,225,108,128,34,83,
+244,242,225,231,245,242,237,245,235,232,105,128,10,63,239,238,
+239,243,240,225,227,101,128,255,73,110,5,112,117,112,127,112,
+136,112,148,112,232,227,242,229,237,229,238,116,128,34,6,230,
+233,238,233,244,121,128,34,30,233,225,242,237,229,238,233,225,
+110,128,5,107,116,2,112,154,112,222,101,2,112,160,112,211,
+231,242,225,108,131,34,43,112,173,112,191,112,196,98,2,112,
+179,112,187,239,244,244,239,109,128,35,33,116,128,35,33,229,
+120,128,248,245,116,2,112,202,112,207,239,112,128,35,32,112,
+128,35,32,242,243,229,227,244,233,239,110,128,34,41,233,243,
+241,245,225,242,101,128,51,5,118,3,112,240,112,249,113,2,
+226,245,236,236,229,116,128,37,216,227,233,242,227,236,101,128,
+37,217,243,237,233,236,229,230,225,227,101,128,38,59,111,3,
+113,22,113,33,113,41,227,249,242,233,236,236,233,99,128,4,
+81,231,239,238,229,107,128,1,47,244,97,131,3,185,113,52,
+113,73,113,81,228,233,229,242,229,243,233,115,129,3,202,113,
+65,244,239,238,239,115,128,3,144,236,225,244,233,110,128,2,
+105,244,239,238,239,115,128,3,175,240,225,242,229,110,128,36,
+164,242,233,231,245,242,237,245,235,232,105,128,10,114,115,4,
+113,120,113,165,113,179,113,187,237,225,236,108,2,113,129,113,
+140,232,233,242,225,231,225,238,97,128,48,67,235,225,244,225,
+235,225,238,97,129,48,163,113,153,232,225,236,230,247,233,228,
+244,104,128,255,104,243,232,225,242,226,229,238,231,225,236,105,
+128,9,250,244,242,239,235,101,128,2,104,245,240,229,242,233,
+239,114,128,246,237,116,2,113,203,113,237,229,242,225,244,233,
+239,110,2,113,215,113,226,232,233,242,225,231,225,238,97,128,
+48,157,235,225,244,225,235,225,238,97,128,48,253,233,236,228,
+101,129,1,41,113,246,226,229,236,239,119,128,30,45,117,2,
+114,4,114,15,226,239,240,239,237,239,230,111,128,49,41,227,
+249,242,233,236,236,233,99,128,4,78,246,239,247,229,236,243,
+233,231,110,3,114,42,114,52,114,59,226,229,238,231,225,236,
+105,128,9,191,228,229,246,97,128,9,63,231,245,234,225,242,
+225,244,105,128,10,191,250,232,233,244,243,97,2,114,81,114,
+92,227,249,242,233,236,236,233,99,128,4,117,228,226,236,231,
+242,225,246,229,227,249,242,233,236,236,233,99,128,4,119,106,
+138,0,106,114,135,114,198,114,209,115,3,115,19,115,132,115,
+201,115,206,115,218,115,226,97,4,114,145,114,156,114,166,114,
+173,225,242,237,229,238,233,225,110,128,5,113,226,229,238,231,
+225,236,105,128,9,156,228,229,246,97,128,9,28,231,117,2,
+114,180,114,189,234,225,242,225,244,105,128,10,156,242,237,245,
+235,232,105,128,10,28,226,239,240,239,237,239,230,111,128,49,
+16,99,3,114,217,114,224,114,246,225,242,239,110,128,1,240,
+233,242,99,2,114,232,114,237,236,101,128,36,217,245,237,230,
+236,229,120,128,1,53,242,239,243,243,229,228,244,225,233,108,
+128,2,157,228,239,244,236,229,243,243,243,244,242,239,235,101,
+128,2,95,101,3,115,27,115,38,115,103,227,249,242,233,236,
+236,233,99,128,4,88,229,109,4,115,49,115,58,115,72,115,
+88,225,242,225,226,233,99,128,6,44,230,233,238,225,236,225,
+242,225,226,233,99,128,254,158,233,238,233,244,233,225,236,225,
+242,225,226,233,99,128,254,159,237,229,228,233,225,236,225,242,
+225,226,233,99,128,254,160,104,2,115,109,115,118,225,242,225,
+226,233,99,128,6,152,230,233,238,225,236,225,242,225,226,233,
+99,128,251,139,104,2,115,138,115,188,97,3,115,146,115,156,
+115,163,226,229,238,231,225,236,105,128,9,157,228,229,246,97,
+128,9,29,231,117,2,115,170,115,179,234,225,242,225,244,105,
+128,10,157,242,237,245,235,232,105,128,10,29,229,232,225,242,
+237,229,238,233,225,110,128,5,123,233,115,128,48,4,237,239,
+238,239,243,240,225,227,101,128,255,74,240,225,242,229,110,128,
+36,165,243,245,240,229,242,233,239,114,128,2,178,107,146,0,
+107,116,21,118,110,118,121,118,183,118,194,119,28,119,42,120,
+150,121,90,121,103,121,129,121,178,122,60,122,82,122,95,122,
+118,122,160,122,170,97,12,116,47,116,79,116,101,116,131,116,
+245,117,14,117,44,117,69,117,175,117,189,118,56,118,85,98,
+2,116,53,116,70,225,243,232,235,233,242,227,249,242,233,236,
+236,233,99,128,4,161,229,238,231,225,236,105,128,9,149,99,
+2,116,85,116,91,245,244,101,128,30,49,249,242,233,236,236,
+233,99,128,4,58,228,101,2,116,108,116,126,243,227,229,238,
+228,229,242,227,249,242,233,236,236,233,99,128,4,155,246,97,
+128,9,21,102,135,5,219,116,149,116,158,116,178,116,192,116,
+201,116,217,116,232,225,242,225,226,233,99,128,6,67,228,225,
+231,229,243,104,129,251,59,116,169,232,229,226,242,229,119,128,
+251,59,230,233,238,225,236,225,242,225,226,233,99,128,254,218,
+232,229,226,242,229,119,128,5,219,233,238,233,244,233,225,236,
+225,242,225,226,233,99,128,254,219,237,229,228,233,225,236,225,
+242,225,226,233,99,128,254,220,242,225,230,229,232,229,226,242,
+229,119,128,251,77,231,117,2,116,252,117,5,234,225,242,225,
+244,105,128,10,149,242,237,245,235,232,105,128,10,21,104,2,
+117,20,117,30,233,242,225,231,225,238,97,128,48,75,239,239,
+235,227,249,242,233,236,236,233,99,128,4,196,235,225,244,225,
+235,225,238,97,129,48,171,117,57,232,225,236,230,247,233,228,
+244,104,128,255,118,112,2,117,75,117,96,240,97,129,3,186,
+117,82,243,249,237,226,239,236,231,242,229,229,107,128,3,240,
+249,229,239,245,110,3,117,108,117,122,117,156,237,233,229,245,
+237,235,239,242,229,225,110,128,49,113,112,2,117,128,117,143,
+232,233,229,245,240,232,235,239,242,229,225,110,128,49,132,233,
+229,245,240,235,239,242,229,225,110,128,49,120,243,243,225,238,
+231,240,233,229,245,240,235,239,242,229,225,110,128,49,121,242,
+239,242,233,233,243,241,245,225,242,101,128,51,13,115,5,117,
+201,117,245,118,4,118,12,118,40,232,233,228,225,225,245,244,
+111,2,117,214,117,223,225,242,225,226,233,99,128,6,64,238,
+239,243,233,228,229,226,229,225,242,233,238,231,225,242,225,226,
+233,99,128,6,64,237,225,236,236,235,225,244,225,235,225,238,
+97,128,48,245,241,245,225,242,101,128,51,132,242,97,2,118,
+19,118,28,225,242,225,226,233,99,128,6,80,244,225,238,225,
+242,225,226,233,99,128,6,77,244,242,239,235,229,227,249,242,
+233,236,236,233,99,128,4,159,244,225,232,233,242,225,240,242,
+239,236,239,238,231,237,225,242,235,232,225,236,230,247,233,228,
+244,104,128,255,112,246,229,242,244,233,227,225,236,243,244,242,
+239,235,229,227,249,242,233,236,236,233,99,128,4,157,226,239,
+240,239,237,239,230,111,128,49,14,99,4,118,131,118,153,118,
+162,118,170,97,2,118,137,118,147,236,243,241,245,225,242,101,
+128,51,137,242,239,110,128,1,233,229,228,233,236,236,97,128,
+1,55,233,242,227,236,101,128,36,218,239,237,237,225,225,227,
+227,229,238,116,128,1,55,228,239,244,226,229,236,239,119,128,
+30,51,101,4,118,204,118,231,119,0,119,12,104,2,118,210,
+118,221,225,242,237,229,238,233,225,110,128,5,132,233,242,225,
+231,225,238,97,128,48,81,235,225,244,225,235,225,238,97,129,
+48,177,118,244,232,225,236,230,247,233,228,244,104,128,255,121,
+238,225,242,237,229,238,233,225,110,128,5,111,243,237,225,236,
+236,235,225,244,225,235,225,238,97,128,48,246,231,242,229,229,
+238,236,225,238,228,233,99,128,1,56,104,6,119,56,119,185,
+119,196,119,221,120,52,120,140,97,5,119,68,119,78,119,89,
+119,96,119,121,226,229,238,231,225,236,105,128,9,150,227,249,
+242,233,236,236,233,99,128,4,69,228,229,246,97,128,9,22,
+231,117,2,119,103,119,112,234,225,242,225,244,105,128,10,150,
+242,237,245,235,232,105,128,10,22,104,4,119,131,119,140,119,
+154,119,170,225,242,225,226,233,99,128,6,46,230,233,238,225,
+236,225,242,225,226,233,99,128,254,166,233,238,233,244,233,225,
+236,225,242,225,226,233,99,128,254,167,237,229,228,233,225,236,
+225,242,225,226,233,99,128,254,168,229,233,227,239,240,244,233,
+99,128,3,231,232,97,2,119,203,119,210,228,229,246,97,128,
+9,89,231,245,242,237,245,235,232,105,128,10,89,233,229,245,
+235,104,4,119,235,120,14,120,29,120,38,97,2,119,241,120,
+0,227,233,242,227,236,229,235,239,242,229,225,110,128,50,120,
+240,225,242,229,238,235,239,242,229,225,110,128,50,24,227,233,
+242,227,236,229,235,239,242,229,225,110,128,50,106,235,239,242,
+229,225,110,128,49,75,240,225,242,229,238,235,239,242,229,225,
+110,128,50,10,111,4,120,62,120,111,120,121,120,126,235,104,
+4,120,73,120,82,120,91,120,101,225,233,244,232,225,105,128,
+14,2,239,238,244,232,225,105,128,14,5,245,225,244,244,232,
+225,105,128,14,3,247,225,233,244,232,225,105,128,14,4,237,
+245,244,244,232,225,105,128,14,91,239,107,128,1,153,242,225,
+235,232,225,238,231,244,232,225,105,128,14,6,250,243,241,245,
+225,242,101,128,51,145,105,4,120,160,120,171,120,196,120,245,
+232,233,242,225,231,225,238,97,128,48,77,235,225,244,225,235,
+225,238,97,129,48,173,120,184,232,225,236,230,247,233,228,244,
+104,128,255,119,242,111,3,120,205,120,220,120,236,231,245,242,
+225,237,245,243,241,245,225,242,101,128,51,21,237,229,229,244,
+239,242,245,243,241,245,225,242,101,128,51,22,243,241,245,225,
+242,101,128,51,20,249,229,239,107,5,121,4,121,39,121,54,
+121,63,121,77,97,2,121,10,121,25,227,233,242,227,236,229,
+235,239,242,229,225,110,128,50,110,240,225,242,229,238,235,239,
+242,229,225,110,128,50,14,227,233,242,227,236,229,235,239,242,
+229,225,110,128,50,96,235,239,242,229,225,110,128,49,49,240,
+225,242,229,238,235,239,242,229,225,110,128,50,0,243,233,239,
+243,235,239,242,229,225,110,128,49,51,234,229,227,249,242,233,
+236,236,233,99,128,4,92,108,2,121,109,121,120,233,238,229,
+226,229,236,239,119,128,30,53,243,241,245,225,242,101,128,51,
+152,109,3,121,137,121,151,121,162,227,245,226,229,228,243,241,
+245,225,242,101,128,51,166,239,238,239,243,240,225,227,101,128,
+255,75,243,241,245,225,242,229,228,243,241,245,225,242,101,128,
+51,162,111,5,121,190,121,216,121,254,122,10,122,24,104,2,
+121,196,121,206,233,242,225,231,225,238,97,128,48,83,237,243,
+241,245,225,242,101,128,51,192,235,97,2,121,223,121,231,233,
+244,232,225,105,128,14,1,244,225,235,225,238,97,129,48,179,
+121,242,232,225,236,230,247,233,228,244,104,128,255,122,239,240,
+239,243,241,245,225,242,101,128,51,30,240,240,225,227,249,242,
+233,236,236,233,99,128,4,129,114,2,122,30,122,50,229,225,
+238,243,244,225,238,228,225,242,228,243,249,237,226,239,108,128,
+50,127,239,238,233,243,227,237,98,128,3,67,240,97,2,122,
+67,122,73,242,229,110,128,36,166,243,241,245,225,242,101,128,
+51,170,243,233,227,249,242,233,236,236,233,99,128,4,111,116,
+2,122,101,122,110,243,241,245,225,242,101,128,51,207,245,242,
+238,229,100,128,2,158,117,2,122,124,122,135,232,233,242,225,
+231,225,238,97,128,48,79,235,225,244,225,235,225,238,97,129,
+48,175,122,148,232,225,236,230,247,233,228,244,104,128,255,120,
+246,243,241,245,225,242,101,128,51,184,247,243,241,245,225,242,
+101,128,51,190,108,146,0,108,122,220,124,247,125,20,125,86,
+125,124,126,20,126,29,126,45,126,69,126,87,126,205,126,246,
+127,125,127,133,127,166,127,175,127,183,127,245,97,7,122,236,
+122,246,122,253,123,4,123,29,123,45,124,235,226,229,238,231,
+225,236,105,128,9,178,227,245,244,101,128,1,58,228,229,246,
+97,128,9,50,231,117,2,123,11,123,20,234,225,242,225,244,
+105,128,10,178,242,237,245,235,232,105,128,10,50,235,235,232,
+225,238,231,249,225,239,244,232,225,105,128,14,69,109,10,123,
+67,124,6,124,23,124,61,124,75,124,94,124,110,124,130,124,
+150,124,173,97,2,123,73,123,254,236,229,102,4,123,85,123,
+99,123,191,123,208,230,233,238,225,236,225,242,225,226,233,99,
+128,254,252,232,225,237,250,97,2,123,109,123,150,225,226,239,
+246,101,2,123,119,123,133,230,233,238,225,236,225,242,225,226,
+233,99,128,254,248,233,243,239,236,225,244,229,228,225,242,225,
+226,233,99,128,254,247,226,229,236,239,119,2,123,160,123,174,
+230,233,238,225,236,225,242,225,226,233,99,128,254,250,233,243,
+239,236,225,244,229,228,225,242,225,226,233,99,128,254,249,233,
+243,239,236,225,244,229,228,225,242,225,226,233,99,128,254,251,
+237,225,228,228,225,225,226,239,246,101,2,123,223,123,237,230,
+233,238,225,236,225,242,225,226,233,99,128,254,246,233,243,239,
+236,225,244,229,228,225,242,225,226,233,99,128,254,245,242,225,
+226,233,99,128,6,68,226,228,97,129,3,187,124,14,243,244,
+242,239,235,101,128,1,155,229,100,130,5,220,124,32,124,52,
+228,225,231,229,243,104,129,251,60,124,43,232,229,226,242,229,
+119,128,251,60,232,229,226,242,229,119,128,5,220,230,233,238,
+225,236,225,242,225,226,233,99,128,254,222,232,225,232,233,238,
+233,244,233,225,236,225,242,225,226,233,99,128,252,202,233,238,
+233,244,233,225,236,225,242,225,226,233,99,128,254,223,234,229,
+229,237,233,238,233,244,233,225,236,225,242,225,226,233,99,128,
+252,201,235,232,225,232,233,238,233,244,233,225,236,225,242,225,
+226,233,99,128,252,203,236,225,237,232,229,232,233,243,239,236,
+225,244,229,228,225,242,225,226,233,99,128,253,242,237,101,2,
+124,180,124,193,228,233,225,236,225,242,225,226,233,99,128,254,
+224,229,109,2,124,200,124,219,232,225,232,233,238,233,244,233,
+225,236,225,242,225,226,233,99,128,253,136,233,238,233,244,233,
+225,236,225,242,225,226,233,99,128,252,204,242,231,229,227,233,
+242,227,236,101,128,37,239,98,3,124,255,125,4,125,10,225,
+114,128,1,154,229,236,116,128,2,108,239,240,239,237,239,230,
+111,128,49,12,99,4,125,30,125,37,125,46,125,73,225,242,
+239,110,128,1,62,229,228,233,236,236,97,128,1,60,233,242,
+99,2,125,54,125,59,236,101,128,36,219,245,237,230,236,229,
+248,226,229,236,239,119,128,30,61,239,237,237,225,225,227,227,
+229,238,116,128,1,60,228,239,116,130,1,64,125,96,125,105,
+225,227,227,229,238,116,128,1,64,226,229,236,239,119,129,30,
+55,125,115,237,225,227,242,239,110,128,30,57,101,3,125,132,
+125,170,126,15,230,116,2,125,139,125,155,225,238,231,236,229,
+225,226,239,246,229,227,237,98,128,3,26,244,225,227,235,226,
+229,236,239,247,227,237,98,128,3,24,243,115,132,0,60,125,
+183,125,205,125,217,126,7,229,241,245,225,108,129,34,100,125,
+193,239,242,231,242,229,225,244,229,114,128,34,218,237,239,238,
+239,243,240,225,227,101,128,255,28,111,2,125,223,125,252,114,
+2,125,229,125,242,229,241,245,233,246,225,236,229,238,116,128,
+34,114,231,242,229,225,244,229,114,128,34,118,246,229,242,229,
+241,245,225,108,128,34,102,243,237,225,236,108,128,254,100,250,
+104,128,2,110,230,226,236,239,227,107,128,37,140,232,239,239,
+235,242,229,244,242,239,230,236,229,120,128,2,109,105,2,126,
+51,126,56,242,97,128,32,164,247,238,225,242,237,229,238,233,
+225,110,128,5,108,106,129,1,201,126,75,229,227,249,242,233,
+236,236,233,99,128,4,89,108,132,246,192,126,99,126,123,126,
+134,126,143,97,2,126,105,126,112,228,229,246,97,128,9,51,
+231,245,234,225,242,225,244,105,128,10,179,233,238,229,226,229,
+236,239,119,128,30,59,236,225,228,229,246,97,128,9,52,246,
+239,227,225,236,233,99,3,126,157,126,167,126,174,226,229,238,
+231,225,236,105,128,9,225,228,229,246,97,128,9,97,246,239,
+247,229,236,243,233,231,110,2,126,188,126,198,226,229,238,231,
+225,236,105,128,9,227,228,229,246,97,128,9,99,109,3,126,
+213,126,226,126,237,233,228,228,236,229,244,233,236,228,101,128,
+2,107,239,238,239,243,240,225,227,101,128,255,76,243,241,245,
+225,242,101,128,51,208,111,6,127,4,127,16,127,58,127,69,
+127,75,127,117,227,232,245,236,225,244,232,225,105,128,14,44,
+231,233,227,225,108,3,127,28,127,34,127,53,225,238,100,128,
+34,39,238,239,116,129,0,172,127,42,242,229,246,229,242,243,
+229,100,128,35,16,239,114,128,34,40,236,233,238,231,244,232,
+225,105,128,14,37,238,231,115,128,1,127,247,236,233,238,101,
+2,127,85,127,108,99,2,127,91,127,103,229,238,244,229,242,
+236,233,238,101,128,254,78,237,98,128,3,50,228,225,243,232,
+229,100,128,254,77,250,229,238,231,101,128,37,202,240,225,242,
+229,110,128,36,167,115,3,127,141,127,148,127,156,236,225,243,
+104,128,1,66,241,245,225,242,101,128,33,19,245,240,229,242,
+233,239,114,128,246,238,244,243,232,225,228,101,128,37,145,245,
+244,232,225,105,128,14,38,246,239,227,225,236,233,99,3,127,
+197,127,207,127,214,226,229,238,231,225,236,105,128,9,140,228,
+229,246,97,128,9,12,246,239,247,229,236,243,233,231,110,2,
+127,228,127,238,226,229,238,231,225,236,105,128,9,226,228,229,
+246,97,128,9,98,248,243,241,245,225,242,101,128,51,211,109,
+144,0,109,128,35,130,144,130,169,130,196,130,221,132,18,132,
+40,133,95,133,125,133,174,134,25,134,47,134,72,134,81,135,
+108,135,136,97,12,128,61,128,71,128,135,128,142,128,167,128,
+215,130,51,130,76,130,81,130,95,130,107,130,112,226,229,238,
+231,225,236,105,128,9,174,99,2,128,77,128,129,242,239,110,
+132,0,175,128,91,128,102,128,108,128,117,226,229,236,239,247,
+227,237,98,128,3,49,227,237,98,128,3,4,236,239,247,237,
+239,100,128,2,205,237,239,238,239,243,240,225,227,101,128,255,
+227,245,244,101,128,30,63,228,229,246,97,128,9,46,231,117,
+2,128,149,128,158,234,225,242,225,244,105,128,10,174,242,237,
+245,235,232,105,128,10,46,104,2,128,173,128,205,225,240,225,
+235,104,2,128,183,128,192,232,229,226,242,229,119,128,5,164,
+236,229,230,244,232,229,226,242,229,119,128,5,164,233,242,225,
+231,225,238,97,128,48,126,105,5,128,227,129,40,129,103,129,
+133,130,39,227,232,225,244,244,225,247,97,3,128,242,129,17,
+129,24,236,239,119,2,128,250,129,5,236,229,230,244,244,232,
+225,105,128,248,149,242,233,231,232,244,244,232,225,105,128,248,
+148,244,232,225,105,128,14,75,245,240,240,229,242,236,229,230,
+244,244,232,225,105,128,248,147,229,107,3,129,49,129,80,129,
+87,236,239,119,2,129,57,129,68,236,229,230,244,244,232,225,
+105,128,248,140,242,233,231,232,244,244,232,225,105,128,248,139,
+244,232,225,105,128,14,72,245,240,240,229,242,236,229,230,244,
+244,232,225,105,128,248,138,232,225,238,225,235,225,116,2,129,
+115,129,126,236,229,230,244,244,232,225,105,128,248,132,244,232,
+225,105,128,14,49,116,3,129,141,129,169,129,232,225,233,235,
+232,117,2,129,151,129,162,236,229,230,244,244,232,225,105,128,
+248,137,244,232,225,105,128,14,71,232,111,3,129,178,129,209,
+129,216,236,239,119,2,129,186,129,197,236,229,230,244,244,232,
+225,105,128,248,143,242,233,231,232,244,244,232,225,105,128,248,
+142,244,232,225,105,128,14,73,245,240,240,229,242,236,229,230,
+244,244,232,225,105,128,248,141,242,105,3,129,241,130,16,130,
+23,236,239,119,2,129,249,130,4,236,229,230,244,244,232,225,
+105,128,248,146,242,233,231,232,244,244,232,225,105,128,248,145,
+244,232,225,105,128,14,74,245,240,240,229,242,236,229,230,244,
+244,232,225,105,128,248,144,249,225,237,239,235,244,232,225,105,
+128,14,70,235,225,244,225,235,225,238,97,129,48,222,130,64,
+232,225,236,230,247,233,228,244,104,128,255,143,236,101,128,38,
+66,238,243,249,239,238,243,241,245,225,242,101,128,51,71,241,
+225,230,232,229,226,242,229,119,128,5,190,242,115,128,38,66,
+115,2,130,118,130,136,239,242,225,227,233,242,227,236,229,232,
+229,226,242,229,119,128,5,175,241,245,225,242,101,128,51,131,
+98,2,130,150,130,160,239,240,239,237,239,230,111,128,49,7,
+243,241,245,225,242,101,128,51,212,99,2,130,175,130,183,233,
+242,227,236,101,128,36,220,245,226,229,228,243,241,245,225,242,
+101,128,51,165,228,239,116,2,130,204,130,213,225,227,227,229,
+238,116,128,30,65,226,229,236,239,119,128,30,67,101,7,130,
+237,131,108,131,119,131,134,131,159,131,196,131,208,101,2,130,
+243,131,95,109,4,130,253,131,6,131,20,131,36,225,242,225,
+226,233,99,128,6,69,230,233,238,225,236,225,242,225,226,233,
+99,128,254,226,233,238,233,244,233,225,236,225,242,225,226,233,
+99,128,254,227,237,101,2,131,43,131,56,228,233,225,236,225,
+242,225,226,233,99,128,254,228,229,237,105,2,131,64,131,79,
+238,233,244,233,225,236,225,242,225,226,233,99,128,252,209,243,
+239,236,225,244,229,228,225,242,225,226,233,99,128,252,72,244,
+239,242,245,243,241,245,225,242,101,128,51,77,232,233,242,225,
+231,225,238,97,128,48,129,233,250,233,229,242,225,243,241,245,
+225,242,101,128,51,126,235,225,244,225,235,225,238,97,129,48,
+225,131,147,232,225,236,230,247,233,228,244,104,128,255,146,109,
+130,5,222,131,167,131,187,228,225,231,229,243,104,129,251,62,
+131,178,232,229,226,242,229,119,128,251,62,232,229,226,242,229,
+119,128,5,222,238,225,242,237,229,238,233,225,110,128,5,116,
+242,235,232,97,3,131,219,131,228,132,5,232,229,226,242,229,
+119,128,5,165,235,229,230,245,236,97,2,131,239,131,248,232,
+229,226,242,229,119,128,5,166,236,229,230,244,232,229,226,242,
+229,119,128,5,166,236,229,230,244,232,229,226,242,229,119,128,
+5,165,104,2,132,24,132,30,239,239,107,128,2,113,250,243,
+241,245,225,242,101,128,51,146,105,6,132,54,132,91,132,228,
+132,239,133,8,133,65,228,100,2,132,61,132,86,236,229,228,
+239,244,235,225,244,225,235,225,238,225,232,225,236,230,247,233,
+228,244,104,128,255,101,239,116,128,0,183,229,245,109,5,132,
+105,132,140,132,155,132,164,132,215,97,2,132,111,132,126,227,
+233,242,227,236,229,235,239,242,229,225,110,128,50,114,240,225,
+242,229,238,235,239,242,229,225,110,128,50,18,227,233,242,227,
+236,229,235,239,242,229,225,110,128,50,100,235,239,242,229,225,
+110,128,49,65,112,2,132,170,132,202,97,2,132,176,132,190,
+238,243,233,239,243,235,239,242,229,225,110,128,49,112,242,229,
+238,235,239,242,229,225,110,128,50,4,233,229,245,240,235,239,
+242,229,225,110,128,49,110,243,233,239,243,235,239,242,229,225,
+110,128,49,111,232,233,242,225,231,225,238,97,128,48,127,235,
+225,244,225,235,225,238,97,129,48,223,132,252,232,225,236,230,
+247,233,228,244,104,128,255,144,238,117,2,133,15,133,60,115,
+132,34,18,133,27,133,38,133,47,133,53,226,229,236,239,247,
+227,237,98,128,3,32,227,233,242,227,236,101,128,34,150,237,
+239,100,128,2,215,240,236,245,115,128,34,19,244,101,128,32,
+50,242,105,2,133,72,133,86,226,225,225,242,245,243,241,245,
+225,242,101,128,51,74,243,241,245,225,242,101,128,51,73,108,
+2,133,101,133,116,239,238,231,236,229,231,244,245,242,238,229,
+100,128,2,112,243,241,245,225,242,101,128,51,150,109,3,133,
+133,133,147,133,158,227,245,226,229,228,243,241,245,225,242,101,
+128,51,163,239,238,239,243,240,225,227,101,128,255,77,243,241,
+245,225,242,229,228,243,241,245,225,242,101,128,51,159,111,5,
+133,186,133,212,133,237,133,247,134,0,104,2,133,192,133,202,
+233,242,225,231,225,238,97,128,48,130,237,243,241,245,225,242,
+101,128,51,193,235,225,244,225,235,225,238,97,129,48,226,133,
+225,232,225,236,230,247,233,228,244,104,128,255,147,236,243,241,
+245,225,242,101,128,51,214,237,225,244,232,225,105,128,14,33,
+246,229,242,243,243,241,245,225,242,101,129,51,167,134,15,228,
+243,241,245,225,242,101,128,51,168,240,97,2,134,32,134,38,
+242,229,110,128,36,168,243,241,245,225,242,101,128,51,171,115,
+2,134,53,134,62,243,241,245,225,242,101,128,51,179,245,240,
+229,242,233,239,114,128,246,239,244,245,242,238,229,100,128,2,
+111,117,141,0,181,134,111,134,115,134,125,134,149,134,159,134,
+181,134,192,134,217,134,240,134,250,135,24,135,88,135,98,49,
+128,0,181,225,243,241,245,225,242,101,128,51,130,227,104,2,
+134,132,134,142,231,242,229,225,244,229,114,128,34,107,236,229,
+243,115,128,34,106,230,243,241,245,225,242,101,128,51,140,103,
+2,134,165,134,172,242,229,229,107,128,3,188,243,241,245,225,
+242,101,128,51,141,232,233,242,225,231,225,238,97,128,48,128,
+235,225,244,225,235,225,238,97,129,48,224,134,205,232,225,236,
+230,247,233,228,244,104,128,255,145,108,2,134,223,134,232,243,
+241,245,225,242,101,128,51,149,244,233,240,236,121,128,0,215,
+237,243,241,245,225,242,101,128,51,155,238,225,104,2,135,2,
+135,11,232,229,226,242,229,119,128,5,163,236,229,230,244,232,
+229,226,242,229,119,128,5,163,115,2,135,30,135,79,233,99,
+3,135,39,135,56,135,67,225,236,238,239,244,101,129,38,106,
+135,50,228,226,108,128,38,107,230,236,225,244,243,233,231,110,
+128,38,109,243,232,225,242,240,243,233,231,110,128,38,111,243,
+241,245,225,242,101,128,51,178,246,243,241,245,225,242,101,128,
+51,182,247,243,241,245,225,242,101,128,51,188,118,2,135,114,
+135,127,237,229,231,225,243,241,245,225,242,101,128,51,185,243,
+241,245,225,242,101,128,51,183,119,2,135,142,135,155,237,229,
+231,225,243,241,245,225,242,101,128,51,191,243,241,245,225,242,
+101,128,51,189,110,150,0,110,135,212,136,90,136,114,136,180,
+136,205,137,7,137,17,137,84,137,127,139,161,139,179,139,204,
+139,235,140,5,140,70,142,52,142,60,142,85,142,93,143,61,
+143,71,143,81,97,8,135,230,135,250,136,1,136,8,136,33,
+136,44,136,69,136,81,98,2,135,236,135,245,229,238,231,225,
+236,105,128,9,168,236,97,128,34,7,227,245,244,101,128,1,
+68,228,229,246,97,128,9,40,231,117,2,136,15,136,24,234,
+225,242,225,244,105,128,10,168,242,237,245,235,232,105,128,10,
+40,232,233,242,225,231,225,238,97,128,48,106,235,225,244,225,
+235,225,238,97,129,48,202,136,57,232,225,236,230,247,233,228,
+244,104,128,255,133,240,239,243,244,242,239,240,232,101,128,1,
+73,243,241,245,225,242,101,128,51,129,98,2,136,96,136,106,
+239,240,239,237,239,230,111,128,49,11,243,240,225,227,101,128,
+0,160,99,4,136,124,136,131,136,140,136,167,225,242,239,110,
+128,1,72,229,228,233,236,236,97,128,1,70,233,242,99,2,
+136,148,136,153,236,101,128,36,221,245,237,230,236,229,248,226,
+229,236,239,119,128,30,75,239,237,237,225,225,227,227,229,238,
+116,128,1,70,228,239,116,2,136,188,136,197,225,227,227,229,
+238,116,128,30,69,226,229,236,239,119,128,30,71,101,3,136,
+213,136,224,136,249,232,233,242,225,231,225,238,97,128,48,109,
+235,225,244,225,235,225,238,97,129,48,205,136,237,232,225,236,
+230,247,233,228,244,104,128,255,136,247,243,232,229,241,229,236,
+243,233,231,110,128,32,170,230,243,241,245,225,242,101,128,51,
+139,103,2,137,23,137,73,97,3,137,31,137,41,137,48,226,
+229,238,231,225,236,105,128,9,153,228,229,246,97,128,9,25,
+231,117,2,137,55,137,64,234,225,242,225,244,105,128,10,153,
+242,237,245,235,232,105,128,10,25,239,238,231,245,244,232,225,
+105,128,14,7,104,2,137,90,137,100,233,242,225,231,225,238,
+97,128,48,147,239,239,107,2,137,108,137,115,236,229,230,116,
+128,2,114,242,229,244,242,239,230,236,229,120,128,2,115,105,
+4,137,137,138,50,138,61,138,119,229,245,110,7,137,155,137,
+190,137,222,137,236,137,245,138,22,138,35,97,2,137,161,137,
+176,227,233,242,227,236,229,235,239,242,229,225,110,128,50,111,
+240,225,242,229,238,235,239,242,229,225,110,128,50,15,227,105,
+2,137,197,137,209,229,245,227,235,239,242,229,225,110,128,49,
+53,242,227,236,229,235,239,242,229,225,110,128,50,97,232,233,
+229,245,232,235,239,242,229,225,110,128,49,54,235,239,242,229,
+225,110,128,49,52,240,97,2,137,252,138,10,238,243,233,239,
+243,235,239,242,229,225,110,128,49,104,242,229,238,235,239,242,
+229,225,110,128,50,1,243,233,239,243,235,239,242,229,225,110,
+128,49,103,244,233,235,229,245,244,235,239,242,229,225,110,128,
+49,102,232,233,242,225,231,225,238,97,128,48,107,107,2,138,
+67,138,91,225,244,225,235,225,238,97,129,48,203,138,79,232,
+225,236,230,247,233,228,244,104,128,255,134,232,225,232,233,116,
+2,138,101,138,112,236,229,230,244,244,232,225,105,128,248,153,
+244,232,225,105,128,14,77,238,101,141,0,57,138,150,138,159,
+138,169,138,199,138,206,138,231,139,2,139,36,139,48,139,59,
+139,92,139,100,139,111,225,242,225,226,233,99,128,6,105,226,
+229,238,231,225,236,105,128,9,239,227,233,242,227,236,101,129,
+36,104,138,180,233,238,246,229,242,243,229,243,225,238,243,243,
+229,242,233,102,128,39,146,228,229,246,97,128,9,111,231,117,
+2,138,213,138,222,234,225,242,225,244,105,128,10,239,242,237,
+245,235,232,105,128,10,111,232,97,2,138,238,138,249,227,235,
+225,242,225,226,233,99,128,6,105,238,231,250,232,239,117,128,
+48,41,105,2,139,8,139,26,228,229,239,231,242,225,240,232,
+233,227,240,225,242,229,110,128,50,40,238,230,229,242,233,239,
+114,128,32,137,237,239,238,239,243,240,225,227,101,128,255,25,
+239,236,228,243,244,249,236,101,128,247,57,112,2,139,65,139,
+72,225,242,229,110,128,36,124,229,114,2,139,79,139,85,233,
+239,100,128,36,144,243,233,225,110,128,6,249,242,239,237,225,
+110,128,33,120,243,245,240,229,242,233,239,114,128,32,121,116,
+2,139,117,139,155,229,229,110,2,139,125,139,134,227,233,242,
+227,236,101,128,36,114,112,2,139,140,139,147,225,242,229,110,
+128,36,134,229,242,233,239,100,128,36,154,232,225,105,128,14,
+89,106,129,1,204,139,167,229,227,249,242,233,236,236,233,99,
+128,4,90,235,225,244,225,235,225,238,97,129,48,243,139,192,
+232,225,236,230,247,233,228,244,104,128,255,157,108,2,139,210,
+139,224,229,231,242,233,231,232,244,236,239,238,103,128,1,158,
+233,238,229,226,229,236,239,119,128,30,73,109,2,139,241,139,
+252,239,238,239,243,240,225,227,101,128,255,78,243,241,245,225,
+242,101,128,51,154,110,2,140,11,140,61,97,3,140,19,140,
+29,140,36,226,229,238,231,225,236,105,128,9,163,228,229,246,
+97,128,9,35,231,117,2,140,43,140,52,234,225,242,225,244,
+105,128,10,163,242,237,245,235,232,105,128,10,35,238,225,228,
+229,246,97,128,9,41,111,6,140,84,140,95,140,120,140,161,
+141,113,142,40,232,233,242,225,231,225,238,97,128,48,110,235,
+225,244,225,235,225,238,97,129,48,206,140,108,232,225,236,230,
+247,233,228,244,104,128,255,137,110,3,140,128,140,144,140,153,
+226,242,229,225,235,233,238,231,243,240,225,227,101,128,0,160,
+229,238,244,232,225,105,128,14,19,245,244,232,225,105,128,14,
+25,239,110,7,140,178,140,187,140,201,140,235,140,251,141,36,
+141,95,225,242,225,226,233,99,128,6,70,230,233,238,225,236,
+225,242,225,226,233,99,128,254,230,231,232,245,238,238,97,2,
+140,212,140,221,225,242,225,226,233,99,128,6,186,230,233,238,
+225,236,225,242,225,226,233,99,128,251,159,233,238,233,244,233,
+225,236,225,242,225,226,233,99,128,254,231,234,229,229,237,105,
+2,141,5,141,20,238,233,244,233,225,236,225,242,225,226,233,
+99,128,252,210,243,239,236,225,244,229,228,225,242,225,226,233,
+99,128,252,75,237,101,2,141,43,141,56,228,233,225,236,225,
+242,225,226,233,99,128,254,232,229,237,105,2,141,64,141,79,
+238,233,244,233,225,236,225,242,225,226,233,99,128,252,213,243,
+239,236,225,244,229,228,225,242,225,226,233,99,128,252,78,238,
+239,239,238,230,233,238,225,236,225,242,225,226,233,99,128,252,
+141,116,7,141,129,141,140,141,169,141,204,141,216,141,236,142,
+6,227,239,238,244,225,233,238,115,128,34,12,101,2,141,146,
+141,162,236,229,237,229,238,116,129,34,9,141,157,239,102,128,
+34,9,241,245,225,108,128,34,96,231,242,229,225,244,229,114,
+129,34,111,141,181,238,239,114,2,141,189,141,197,229,241,245,
+225,108,128,34,113,236,229,243,115,128,34,121,233,228,229,238,
+244,233,227,225,108,128,34,98,236,229,243,115,129,34,110,141,
+225,238,239,242,229,241,245,225,108,128,34,112,112,2,141,242,
+141,252,225,242,225,236,236,229,108,128,34,38,242,229,227,229,
+228,229,115,128,34,128,243,117,3,142,15,142,22,142,31,226,
+243,229,116,128,34,132,227,227,229,229,228,115,128,34,129,240,
+229,242,243,229,116,128,34,133,247,225,242,237,229,238,233,225,
+110,128,5,118,240,225,242,229,110,128,36,169,115,2,142,66,
+142,75,243,241,245,225,242,101,128,51,177,245,240,229,242,233,
+239,114,128,32,127,244,233,236,228,101,128,0,241,117,132,3,
+189,142,105,142,116,142,197,143,24,232,233,242,225,231,225,238,
+97,128,48,108,107,2,142,122,142,146,225,244,225,235,225,238,
+97,129,48,204,142,134,232,225,236,230,247,233,228,244,104,128,
+255,135,244,97,3,142,155,142,165,142,172,226,229,238,231,225,
+236,105,128,9,188,228,229,246,97,128,9,60,231,117,2,142,
+179,142,188,234,225,242,225,244,105,128,10,188,242,237,245,235,
+232,105,128,10,60,109,2,142,203,142,237,226,229,242,243,233,
+231,110,130,0,35,142,217,142,229,237,239,238,239,243,240,225,
+227,101,128,255,3,243,237,225,236,108,128,254,95,229,114,2,
+142,244,143,20,225,236,243,233,231,110,2,142,255,143,7,231,
+242,229,229,107,128,3,116,236,239,247,229,242,231,242,229,229,
+107,128,3,117,111,128,33,22,110,130,5,224,143,32,143,52,
+228,225,231,229,243,104,129,251,64,143,43,232,229,226,242,229,
+119,128,251,64,232,229,226,242,229,119,128,5,224,246,243,241,
+245,225,242,101,128,51,181,247,243,241,245,225,242,101,128,51,
+187,249,97,3,143,90,143,100,143,107,226,229,238,231,225,236,
+105,128,9,158,228,229,246,97,128,9,30,231,117,2,143,114,
+143,123,234,225,242,225,244,105,128,10,158,242,237,245,235,232,
+105,128,10,30,111,147,0,111,143,174,143,196,144,18,144,188,
+145,4,145,19,145,59,145,182,145,203,145,241,145,252,146,174,
+148,8,148,72,148,105,148,151,149,24,149,71,149,83,97,2,
+143,180,143,187,227,245,244,101,128,0,243,238,231,244,232,225,
+105,128,14,45,98,4,143,206,143,248,144,1,144,11,225,242,
+242,229,100,130,2,117,143,218,143,229,227,249,242,233,236,236,
+233,99,128,4,233,228,233,229,242,229,243,233,243,227,249,242,
+233,236,236,233,99,128,4,235,229,238,231,225,236,105,128,9,
+147,239,240,239,237,239,230,111,128,49,27,242,229,246,101,128,
+1,79,99,3,144,26,144,99,144,178,97,2,144,32,144,93,
+238,228,242,97,3,144,43,144,50,144,61,228,229,246,97,128,
+9,17,231,245,234,225,242,225,244,105,128,10,145,246,239,247,
+229,236,243,233,231,110,2,144,75,144,82,228,229,246,97,128,
+9,73,231,245,234,225,242,225,244,105,128,10,201,242,239,110,
+128,1,210,233,242,99,2,144,107,144,112,236,101,128,36,222,
+245,237,230,236,229,120,133,0,244,144,131,144,139,144,150,144,
+158,144,170,225,227,245,244,101,128,30,209,228,239,244,226,229,
+236,239,119,128,30,217,231,242,225,246,101,128,30,211,232,239,
+239,235,225,226,239,246,101,128,30,213,244,233,236,228,101,128,
+30,215,249,242,233,236,236,233,99,128,4,62,100,4,144,198,
+144,221,144,227,144,250,226,108,2,144,205,144,213,225,227,245,
+244,101,128,1,81,231,242,225,246,101,128,2,13,229,246,97,
+128,9,19,233,229,242,229,243,233,115,129,0,246,144,239,227,
+249,242,233,236,236,233,99,128,4,231,239,244,226,229,236,239,
+119,128,30,205,101,129,1,83,145,10,235,239,242,229,225,110,
+128,49,90,103,3,145,27,145,42,145,49,239,238,229,107,129,
+2,219,145,36,227,237,98,128,3,40,242,225,246,101,128,0,
+242,245,234,225,242,225,244,105,128,10,147,104,4,145,69,145,
+80,145,90,145,168,225,242,237,229,238,233,225,110,128,5,133,
+233,242,225,231,225,238,97,128,48,74,111,2,145,96,145,106,
+239,235,225,226,239,246,101,128,30,207,242,110,133,1,161,145,
+121,145,129,145,140,145,148,145,160,225,227,245,244,101,128,30,
+219,228,239,244,226,229,236,239,119,128,30,227,231,242,225,246,
+101,128,30,221,232,239,239,235,225,226,239,246,101,128,30,223,
+244,233,236,228,101,128,30,225,245,238,231,225,242,245,237,236,
+225,245,116,128,1,81,105,129,1,163,145,188,238,246,229,242,
+244,229,228,226,242,229,246,101,128,2,15,107,2,145,209,145,
+233,225,244,225,235,225,238,97,129,48,170,145,221,232,225,236,
+230,247,233,228,244,104,128,255,117,239,242,229,225,110,128,49,
+87,236,229,232,229,226,242,229,119,128,5,171,109,6,146,10,
+146,38,146,45,146,134,146,145,146,163,225,227,242,239,110,130,
+1,77,146,22,146,30,225,227,245,244,101,128,30,83,231,242,
+225,246,101,128,30,81,228,229,246,97,128,9,80,229,231,97,
+133,3,201,146,61,146,65,146,76,146,90,146,106,49,128,3,
+214,227,249,242,233,236,236,233,99,128,4,97,236,225,244,233,
+238,227,236,239,243,229,100,128,2,119,242,239,245,238,228,227,
+249,242,233,236,236,233,99,128,4,123,116,2,146,112,146,127,
+233,244,236,239,227,249,242,233,236,236,233,99,128,4,125,239,
+238,239,115,128,3,206,231,245,234,225,242,225,244,105,128,10,
+208,233,227,242,239,110,129,3,191,146,155,244,239,238,239,115,
+128,3,204,239,238,239,243,240,225,227,101,128,255,79,238,101,
+145,0,49,146,213,146,222,146,232,147,6,147,31,147,40,147,
+49,147,74,147,108,147,142,147,154,147,173,147,184,147,217,147,
+227,147,235,147,246,225,242,225,226,233,99,128,6,97,226,229,
+238,231,225,236,105,128,9,231,227,233,242,227,236,101,129,36,
+96,146,243,233,238,246,229,242,243,229,243,225,238,243,243,229,
+242,233,102,128,39,138,100,2,147,12,147,18,229,246,97,128,
+9,103,239,244,229,238,236,229,225,228,229,114,128,32,36,229,
+233,231,232,244,104,128,33,91,230,233,244,244,229,100,128,246,
+220,231,117,2,147,56,147,65,234,225,242,225,244,105,128,10,
+231,242,237,245,235,232,105,128,10,103,232,97,3,147,83,147,
+94,147,99,227,235,225,242,225,226,233,99,128,6,97,236,102,
+128,0,189,238,231,250,232,239,117,128,48,33,105,2,147,114,
+147,132,228,229,239,231,242,225,240,232,233,227,240,225,242,229,
+110,128,50,32,238,230,229,242,233,239,114,128,32,129,237,239,
+238,239,243,240,225,227,101,128,255,17,238,245,237,229,242,225,
+244,239,242,226,229,238,231,225,236,105,128,9,244,239,236,228,
+243,244,249,236,101,128,247,49,112,2,147,190,147,197,225,242,
+229,110,128,36,116,229,114,2,147,204,147,210,233,239,100,128,
+36,136,243,233,225,110,128,6,241,241,245,225,242,244,229,114,
+128,0,188,242,239,237,225,110,128,33,112,243,245,240,229,242,
+233,239,114,128,0,185,244,104,2,147,253,148,2,225,105,128,
+14,81,233,242,100,128,33,83,111,3,148,16,148,50,148,66,
+103,2,148,22,148,40,239,238,229,107,129,1,235,148,31,237,
+225,227,242,239,110,128,1,237,245,242,237,245,235,232,105,128,
+10,19,237,225,244,242,225,231,245,242,237,245,235,232,105,128,
+10,75,240,229,110,128,2,84,112,3,148,80,148,87,148,98,
+225,242,229,110,128,36,170,229,238,226,245,236,236,229,116,128,
+37,230,244,233,239,110,128,35,37,114,2,148,111,148,140,100,
+2,148,117,148,128,230,229,237,233,238,233,238,101,128,0,170,
+237,225,243,227,245,236,233,238,101,128,0,186,244,232,239,231,
+239,238,225,108,128,34,31,115,5,148,163,148,195,148,212,149,
+1,149,14,232,239,242,116,2,148,172,148,179,228,229,246,97,
+128,9,18,246,239,247,229,236,243,233,231,238,228,229,246,97,
+128,9,74,236,225,243,104,129,0,248,148,204,225,227,245,244,
+101,128,1,255,237,225,236,108,2,148,221,148,232,232,233,242,
+225,231,225,238,97,128,48,73,235,225,244,225,235,225,238,97,
+129,48,169,148,245,232,225,236,230,247,233,228,244,104,128,255,
+107,244,242,239,235,229,225,227,245,244,101,128,1,255,245,240,
+229,242,233,239,114,128,246,240,116,2,149,30,149,41,227,249,
+242,233,236,236,233,99,128,4,127,233,236,228,101,130,0,245,
+149,52,149,60,225,227,245,244,101,128,30,77,228,233,229,242,
+229,243,233,115,128,30,79,245,226,239,240,239,237,239,230,111,
+128,49,33,118,2,149,89,149,170,229,114,2,149,96,149,162,
+236,233,238,101,131,32,62,149,109,149,132,149,155,99,2,149,
+115,149,127,229,238,244,229,242,236,233,238,101,128,254,74,237,
+98,128,3,5,100,2,149,138,149,146,225,243,232,229,100,128,
+254,73,226,236,247,225,246,121,128,254,76,247,225,246,121,128,
+254,75,243,227,239,242,101,128,0,175,239,247,229,236,243,233,
+231,110,3,149,185,149,195,149,202,226,229,238,231,225,236,105,
+128,9,203,228,229,246,97,128,9,75,231,245,234,225,242,225,
+244,105,128,10,203,112,145,0,112,149,251,152,123,152,134,152,
+143,152,155,154,80,154,90,155,82,156,101,156,191,156,217,157,
+92,157,100,158,2,158,60,158,88,158,98,97,14,150,25,150,
+57,150,67,150,74,150,81,150,129,150,140,150,154,150,165,150,
+212,150,226,151,238,152,21,152,111,97,2,150,31,150,43,237,
+240,243,243,241,245,225,242,101,128,51,128,243,229,238,244,239,
+243,241,245,225,242,101,128,51,43,226,229,238,231,225,236,105,
+128,9,170,227,245,244,101,128,30,85,228,229,246,97,128,9,
+42,103,2,150,87,150,105,101,2,150,93,150,100,228,239,247,
+110,128,33,223,245,112,128,33,222,117,2,150,111,150,120,234,
+225,242,225,244,105,128,10,170,242,237,245,235,232,105,128,10,
+42,232,233,242,225,231,225,238,97,128,48,113,233,249,225,238,
+238,239,233,244,232,225,105,128,14,47,235,225,244,225,235,225,
+238,97,128,48,209,108,2,150,171,150,196,225,244,225,236,233,
+250,225,244,233,239,238,227,249,242,233,236,236,233,227,227,237,
+98,128,4,132,239,227,232,235,225,227,249,242,233,236,236,233,
+99,128,4,192,238,243,233,239,243,235,239,242,229,225,110,128,
+49,127,114,3,150,234,150,255,151,227,97,2,150,240,150,248,
+231,242,225,240,104,128,0,182,236,236,229,108,128,34,37,229,
+110,2,151,6,151,116,236,229,230,116,136,0,40,151,29,151,
+44,151,49,151,54,151,65,151,77,151,100,151,105,225,236,244,
+239,238,229,225,242,225,226,233,99,128,253,62,226,116,128,248,
+237,229,120,128,248,236,233,238,230,229,242,233,239,114,128,32,
+141,237,239,238,239,243,240,225,227,101,128,255,8,115,2,151,
+83,151,90,237,225,236,108,128,254,89,245,240,229,242,233,239,
+114,128,32,125,244,112,128,248,235,246,229,242,244,233,227,225,
+108,128,254,53,242,233,231,232,116,136,0,41,151,140,151,155,
+151,160,151,165,151,176,151,188,151,211,151,216,225,236,244,239,
+238,229,225,242,225,226,233,99,128,253,63,226,116,128,248,248,
+229,120,128,248,247,233,238,230,229,242,233,239,114,128,32,142,
+237,239,238,239,243,240,225,227,101,128,255,9,115,2,151,194,
+151,201,237,225,236,108,128,254,90,245,240,229,242,233,239,114,
+128,32,126,244,112,128,248,246,246,229,242,244,233,227,225,108,
+128,254,54,244,233,225,236,228,233,230,102,128,34,2,115,3,
+151,246,152,1,152,13,229,241,232,229,226,242,229,119,128,5,
+192,232,244,225,232,229,226,242,229,119,128,5,153,241,245,225,
+242,101,128,51,169,244,225,104,134,5,183,152,39,152,53,152,
+58,152,67,152,82,152,98,49,2,152,45,152,49,49,128,5,
+183,100,128,5,183,178,97,128,5,183,232,229,226,242,229,119,
+128,5,183,238,225,242,242,239,247,232,229,226,242,229,119,128,
+5,183,241,245,225,242,244,229,242,232,229,226,242,229,119,128,
+5,183,247,233,228,229,232,229,226,242,229,119,128,5,183,250,
+229,242,232,229,226,242,229,119,128,5,161,226,239,240,239,237,
+239,230,111,128,49,6,227,233,242,227,236,101,128,36,223,228,
+239,244,225,227,227,229,238,116,128,30,87,101,137,5,228,152,
+177,152,188,152,208,152,220,152,240,153,86,153,97,153,118,154,
+73,227,249,242,233,236,236,233,99,128,4,63,228,225,231,229,
+243,104,129,251,68,152,199,232,229,226,242,229,119,128,251,68,
+229,250,233,243,241,245,225,242,101,128,51,59,230,233,238,225,
+236,228,225,231,229,243,232,232,229,226,242,229,119,128,251,67,
+104,5,152,252,153,19,153,27,153,41,153,71,225,114,2,153,
+3,153,10,225,226,233,99,128,6,126,237,229,238,233,225,110,
+128,5,122,229,226,242,229,119,128,5,228,230,233,238,225,236,
+225,242,225,226,233,99,128,251,87,105,2,153,47,153,62,238,
+233,244,233,225,236,225,242,225,226,233,99,128,251,88,242,225,
+231,225,238,97,128,48,122,237,229,228,233,225,236,225,242,225,
+226,233,99,128,251,89,235,225,244,225,235,225,238,97,128,48,
+218,237,233,228,228,236,229,232,239,239,235,227,249,242,233,236,
+236,233,99,128,4,167,114,5,153,130,153,142,153,184,154,49,
+154,62,225,230,229,232,229,226,242,229,119,128,251,78,227,229,
+238,116,131,0,37,153,155,153,164,153,176,225,242,225,226,233,
+99,128,6,106,237,239,238,239,243,240,225,227,101,128,255,5,
+243,237,225,236,108,128,254,106,105,2,153,190,154,31,239,100,
+134,0,46,153,207,153,218,153,229,153,241,153,252,154,8,225,
+242,237,229,238,233,225,110,128,5,137,227,229,238,244,229,242,
+229,100,128,0,183,232,225,236,230,247,233,228,244,104,128,255,
+97,233,238,230,229,242,233,239,114,128,246,231,237,239,238,239,
+243,240,225,227,101,128,255,14,115,2,154,14,154,21,237,225,
+236,108,128,254,82,245,240,229,242,233,239,114,128,246,232,243,
+240,239,237,229,238,233,231,242,229,229,235,227,237,98,128,3,
+66,240,229,238,228,233,227,245,236,225,114,128,34,165,244,232,
+239,245,243,225,238,100,128,32,48,243,229,244,97,128,32,167,
+230,243,241,245,225,242,101,128,51,138,104,3,154,98,154,148,
+155,29,97,3,154,106,154,116,154,123,226,229,238,231,225,236,
+105,128,9,171,228,229,246,97,128,9,43,231,117,2,154,130,
+154,139,234,225,242,225,244,105,128,10,171,242,237,245,235,232,
+105,128,10,43,105,133,3,198,154,162,154,166,154,252,155,4,
+155,15,49,128,3,213,229,245,240,104,4,154,179,154,214,154,
+229,154,238,97,2,154,185,154,200,227,233,242,227,236,229,235,
+239,242,229,225,110,128,50,122,240,225,242,229,238,235,239,242,
+229,225,110,128,50,26,227,233,242,227,236,229,235,239,242,229,
+225,110,128,50,108,235,239,242,229,225,110,128,49,77,240,225,
+242,229,238,235,239,242,229,225,110,128,50,12,236,225,244,233,
+110,128,2,120,238,244,232,245,244,232,225,105,128,14,58,243,
+249,237,226,239,236,231,242,229,229,107,128,3,213,111,3,155,
+37,155,42,155,68,239,107,128,1,165,240,104,2,155,49,155,
+58,225,238,244,232,225,105,128,14,30,245,238,231,244,232,225,
+105,128,14,28,243,225,237,240,232,225,239,244,232,225,105,128,
+14,32,105,133,3,192,155,96,156,52,156,63,156,74,156,88,
+229,245,112,6,155,112,155,147,155,179,155,207,155,221,156,17,
+97,2,155,118,155,133,227,233,242,227,236,229,235,239,242,229,
+225,110,128,50,115,240,225,242,229,238,235,239,242,229,225,110,
+128,50,19,227,105,2,155,154,155,166,229,245,227,235,239,242,
+229,225,110,128,49,118,242,227,236,229,235,239,242,229,225,110,
+128,50,101,107,2,155,185,155,199,233,249,229,239,235,235,239,
+242,229,225,110,128,49,114,239,242,229,225,110,128,49,66,240,
+225,242,229,238,235,239,242,229,225,110,128,50,5,243,233,239,
+115,2,155,230,156,2,107,2,155,236,155,250,233,249,229,239,
+235,235,239,242,229,225,110,128,49,116,239,242,229,225,110,128,
+49,68,244,233,235,229,245,244,235,239,242,229,225,110,128,49,
+117,116,2,156,23,156,38,232,233,229,245,244,232,235,239,242,
+229,225,110,128,49,119,233,235,229,245,244,235,239,242,229,225,
+110,128,49,115,232,233,242,225,231,225,238,97,128,48,116,235,
+225,244,225,235,225,238,97,128,48,212,243,249,237,226,239,236,
+231,242,229,229,107,128,3,214,247,242,225,242,237,229,238,233,
+225,110,128,5,131,236,245,115,132,0,43,156,115,156,126,156,
+135,156,168,226,229,236,239,247,227,237,98,128,3,31,227,233,
+242,227,236,101,128,34,149,109,2,156,141,156,148,233,238,245,
+115,128,0,177,111,2,156,154,156,158,100,128,2,214,238,239,
+243,240,225,227,101,128,255,11,115,2,156,174,156,181,237,225,
+236,108,128,254,98,245,240,229,242,233,239,114,128,32,122,109,
+2,156,197,156,208,239,238,239,243,240,225,227,101,128,255,80,
+243,241,245,225,242,101,128,51,216,111,5,156,229,156,240,157,
+51,157,62,157,72,232,233,242,225,231,225,238,97,128,48,125,
+233,238,244,233,238,231,233,238,228,229,120,4,157,4,157,16,
+157,28,157,41,228,239,247,238,247,232,233,244,101,128,38,31,
+236,229,230,244,247,232,233,244,101,128,38,28,242,233,231,232,
+244,247,232,233,244,101,128,38,30,245,240,247,232,233,244,101,
+128,38,29,235,225,244,225,235,225,238,97,128,48,221,240,236,
+225,244,232,225,105,128,14,27,243,244,225,236,237,225,242,107,
+129,48,18,157,85,230,225,227,101,128,48,32,240,225,242,229,
+110,128,36,171,114,3,157,108,157,134,157,159,101,2,157,114,
+157,122,227,229,228,229,115,128,34,122,243,227,242,233,240,244,
+233,239,110,128,33,30,233,237,101,2,157,142,157,148,237,239,
+100,128,2,185,242,229,246,229,242,243,229,100,128,32,53,111,
+4,157,169,157,176,157,186,157,199,228,245,227,116,128,34,15,
+234,229,227,244,233,246,101,128,35,5,236,239,238,231,229,228,
+235,225,238,97,128,48,252,112,2,157,205,157,242,101,2,157,
+211,157,218,236,236,239,114,128,35,24,242,243,117,2,157,226,
+157,233,226,243,229,116,128,34,130,240,229,242,243,229,116,128,
+34,131,239,242,244,233,239,110,129,34,55,157,253,225,108,128,
+34,29,115,2,158,8,158,51,105,130,3,200,158,16,158,27,
+227,249,242,233,236,236,233,99,128,4,113,236,233,240,238,229,
+245,237,225,244,225,227,249,242,233,236,236,233,227,227,237,98,
+128,4,134,243,241,245,225,242,101,128,51,176,117,2,158,66,
+158,77,232,233,242,225,231,225,238,97,128,48,119,235,225,244,
+225,235,225,238,97,128,48,215,246,243,241,245,225,242,101,128,
+51,180,247,243,241,245,225,242,101,128,51,186,113,136,0,113,
+158,128,159,177,159,188,159,197,159,204,159,216,159,254,160,6,
+97,4,158,138,158,161,158,225,159,160,100,2,158,144,158,150,
+229,246,97,128,9,88,237,225,232,229,226,242,229,119,128,5,
+168,102,4,158,171,158,180,158,194,158,210,225,242,225,226,233,
+99,128,6,66,230,233,238,225,236,225,242,225,226,233,99,128,
+254,214,233,238,233,244,233,225,236,225,242,225,226,233,99,128,
+254,215,237,229,228,233,225,236,225,242,225,226,233,99,128,254,
+216,237,225,244,115,136,5,184,158,248,159,12,159,26,159,31,
+159,36,159,45,159,60,159,147,49,3,159,0,159,4,159,8,
+48,128,5,184,97,128,5,184,99,128,5,184,50,2,159,18,
+159,22,55,128,5,184,57,128,5,184,179,51,128,5,184,228,
+101,128,5,184,232,229,226,242,229,119,128,5,184,238,225,242,
+242,239,247,232,229,226,242,229,119,128,5,184,113,2,159,66,
+159,132,225,244,225,110,4,159,79,159,88,159,103,159,119,232,
+229,226,242,229,119,128,5,184,238,225,242,242,239,247,232,229,
+226,242,229,119,128,5,184,241,245,225,242,244,229,242,232,229,
+226,242,229,119,128,5,184,247,233,228,229,232,229,226,242,229,
+119,128,5,184,245,225,242,244,229,242,232,229,226,242,229,119,
+128,5,184,247,233,228,229,232,229,226,242,229,119,128,5,184,
+242,238,229,249,240,225,242,225,232,229,226,242,229,119,128,5,
+159,226,239,240,239,237,239,230,111,128,49,17,227,233,242,227,
+236,101,128,36,224,232,239,239,107,128,2,160,237,239,238,239,
+243,240,225,227,101,128,255,81,239,102,130,5,231,159,225,159,
+245,228,225,231,229,243,104,129,251,71,159,236,232,229,226,242,
+229,119,128,251,71,232,229,226,242,229,119,128,5,231,240,225,
+242,229,110,128,36,172,117,4,160,16,160,28,160,117,160,204,
+225,242,244,229,242,238,239,244,101,128,38,105,226,245,244,115,
+135,5,187,160,49,160,54,160,59,160,64,160,73,160,88,160,
+104,177,56,128,5,187,178,53,128,5,187,179,49,128,5,187,
+232,229,226,242,229,119,128,5,187,238,225,242,242,239,247,232,
+229,226,242,229,119,128,5,187,241,245,225,242,244,229,242,232,
+229,226,242,229,119,128,5,187,247,233,228,229,232,229,226,242,
+229,119,128,5,187,229,243,244,233,239,110,133,0,63,160,136,
+160,159,160,176,160,184,160,196,225,114,2,160,143,160,150,225,
+226,233,99,128,6,31,237,229,238,233,225,110,128,5,94,228,
+239,247,110,129,0,191,160,168,243,237,225,236,108,128,247,191,
+231,242,229,229,107,128,3,126,237,239,238,239,243,240,225,227,
+101,128,255,31,243,237,225,236,108,128,247,63,239,244,101,4,
+160,216,161,31,161,51,161,80,228,226,108,133,0,34,160,232,
+160,239,160,246,161,2,161,23,226,225,243,101,128,32,30,236,
+229,230,116,128,32,28,237,239,238,239,243,240,225,227,101,128,
+255,2,240,242,233,237,101,129,48,30,161,12,242,229,246,229,
+242,243,229,100,128,48,29,242,233,231,232,116,128,32,29,236,
+229,230,116,129,32,24,161,40,242,229,246,229,242,243,229,100,
+128,32,27,114,2,161,57,161,67,229,246,229,242,243,229,100,
+128,32,27,233,231,232,116,129,32,25,161,76,110,128,1,73,
+243,233,238,231,108,2,161,90,161,97,226,225,243,101,128,32,
+26,101,129,0,39,161,103,237,239,238,239,243,240,225,227,101,
+128,255,7,114,145,0,114,161,153,162,157,162,168,162,215,163,
+10,164,27,164,51,164,146,166,180,166,217,166,229,167,27,167,
+35,167,197,167,208,167,243,168,87,97,11,161,177,161,188,161,
+198,161,205,162,14,162,30,162,55,162,66,162,91,162,114,162,
+151,225,242,237,229,238,233,225,110,128,5,124,226,229,238,231,
+225,236,105,128,9,176,227,245,244,101,128,1,85,100,4,161,
+215,161,221,161,235,162,5,229,246,97,128,9,48,233,227,225,
+108,129,34,26,161,230,229,120,128,248,229,239,246,229,242,243,
+243,241,245,225,242,101,129,51,174,161,251,228,243,241,245,225,
+242,101,128,51,175,243,241,245,225,242,101,128,51,173,230,101,
+129,5,191,162,21,232,229,226,242,229,119,128,5,191,231,117,
+2,162,37,162,46,234,225,242,225,244,105,128,10,176,242,237,
+245,235,232,105,128,10,48,232,233,242,225,231,225,238,97,128,
+48,137,235,225,244,225,235,225,238,97,129,48,233,162,79,232,
+225,236,230,247,233,228,244,104,128,255,151,236,239,247,229,242,
+228,233,225,231,239,238,225,236,226,229,238,231,225,236,105,128,
+9,241,109,2,162,120,162,143,233,228,228,236,229,228,233,225,
+231,239,238,225,236,226,229,238,231,225,236,105,128,9,240,243,
+232,239,242,110,128,2,100,244,233,111,128,34,54,226,239,240,
+239,237,239,230,111,128,49,22,99,4,162,178,162,185,162,194,
+162,202,225,242,239,110,128,1,89,229,228,233,236,236,97,128,
+1,87,233,242,227,236,101,128,36,225,239,237,237,225,225,227,
+227,229,238,116,128,1,87,100,2,162,221,162,231,226,236,231,
+242,225,246,101,128,2,17,239,116,2,162,238,162,247,225,227,
+227,229,238,116,128,30,89,226,229,236,239,119,129,30,91,163,
+1,237,225,227,242,239,110,128,30,93,101,6,163,24,163,69,
+163,104,163,159,163,184,163,217,102,2,163,30,163,43,229,242,
+229,238,227,229,237,225,242,107,128,32,59,236,229,248,243,117,
+2,163,53,163,60,226,243,229,116,128,34,134,240,229,242,243,
+229,116,128,34,135,231,233,243,244,229,114,2,163,80,163,85,
+229,100,128,0,174,115,2,163,91,163,97,225,238,115,128,248,
+232,229,242,233,102,128,246,218,104,3,163,112,163,135,163,149,
+225,114,2,163,119,163,126,225,226,233,99,128,6,49,237,229,
+238,233,225,110,128,5,128,230,233,238,225,236,225,242,225,226,
+233,99,128,254,174,233,242,225,231,225,238,97,128,48,140,235,
+225,244,225,235,225,238,97,129,48,236,163,172,232,225,236,230,
+247,233,228,244,104,128,255,154,243,104,130,5,232,163,193,163,
+208,228,225,231,229,243,232,232,229,226,242,229,119,128,251,72,
+232,229,226,242,229,119,128,5,232,118,3,163,225,163,238,164,
+14,229,242,243,229,228,244,233,236,228,101,128,34,61,233,97,
+2,163,245,163,254,232,229,226,242,229,119,128,5,151,237,245,
+231,242,225,243,232,232,229,226,242,229,119,128,5,151,236,239,
+231,233,227,225,236,238,239,116,128,35,16,230,233,243,232,232,
+239,239,107,129,2,126,164,40,242,229,246,229,242,243,229,100,
+128,2,127,104,2,164,57,164,80,97,2,164,63,164,73,226,
+229,238,231,225,236,105,128,9,221,228,229,246,97,128,9,93,
+111,131,3,193,164,90,164,119,164,133,239,107,129,2,125,164,
+97,244,245,242,238,229,100,129,2,123,164,108,243,245,240,229,
+242,233,239,114,128,2,181,243,249,237,226,239,236,231,242,229,
+229,107,128,3,241,244,233,227,232,239,239,235,237,239,100,128,
+2,222,105,6,164,160,165,204,165,250,166,5,166,30,166,166,
+229,245,108,9,164,182,164,217,164,232,164,246,165,36,165,50,
+165,136,165,149,165,184,97,2,164,188,164,203,227,233,242,227,
+236,229,235,239,242,229,225,110,128,50,113,240,225,242,229,238,
+235,239,242,229,225,110,128,50,17,227,233,242,227,236,229,235,
+239,242,229,225,110,128,50,99,232,233,229,245,232,235,239,242,
+229,225,110,128,49,64,107,2,164,252,165,28,233,249,229,239,
+107,2,165,6,165,15,235,239,242,229,225,110,128,49,58,243,
+233,239,243,235,239,242,229,225,110,128,49,105,239,242,229,225,
+110,128,49,57,237,233,229,245,237,235,239,242,229,225,110,128,
+49,59,112,3,165,58,165,90,165,105,97,2,165,64,165,78,
+238,243,233,239,243,235,239,242,229,225,110,128,49,108,242,229,
+238,235,239,242,229,225,110,128,50,3,232,233,229,245,240,232,
+235,239,242,229,225,110,128,49,63,233,229,245,112,2,165,114,
+165,123,235,239,242,229,225,110,128,49,60,243,233,239,243,235,
+239,242,229,225,110,128,49,107,243,233,239,243,235,239,242,229,
+225,110,128,49,61,116,2,165,155,165,170,232,233,229,245,244,
+232,235,239,242,229,225,110,128,49,62,233,235,229,245,244,235,
+239,242,229,225,110,128,49,106,249,229,239,242,233,238,232,233,
+229,245,232,235,239,242,229,225,110,128,49,109,231,232,116,2,
+165,212,165,220,225,238,231,236,101,128,34,31,116,2,165,226,
+165,240,225,227,235,226,229,236,239,247,227,237,98,128,3,25,
+242,233,225,238,231,236,101,128,34,191,232,233,242,225,231,225,
+238,97,128,48,138,235,225,244,225,235,225,238,97,129,48,234,
+166,18,232,225,236,230,247,233,228,244,104,128,255,152,110,2,
+166,36,166,152,103,131,2,218,166,46,166,57,166,63,226,229,
+236,239,247,227,237,98,128,3,37,227,237,98,128,3,10,232,
+225,236,102,2,166,72,166,118,236,229,230,116,131,2,191,166,
+85,166,96,166,107,225,242,237,229,238,233,225,110,128,5,89,
+226,229,236,239,247,227,237,98,128,3,28,227,229,238,244,229,
+242,229,100,128,2,211,242,233,231,232,116,130,2,190,166,130,
+166,141,226,229,236,239,247,227,237,98,128,3,57,227,229,238,
+244,229,242,229,100,128,2,210,246,229,242,244,229,228,226,242,
+229,246,101,128,2,19,244,244,239,242,245,243,241,245,225,242,
+101,128,51,81,108,2,166,186,166,197,233,238,229,226,229,236,
+239,119,128,30,95,239,238,231,236,229,103,129,2,124,166,208,
+244,245,242,238,229,100,128,2,122,237,239,238,239,243,240,225,
+227,101,128,255,82,111,3,166,237,166,248,167,17,232,233,242,
+225,231,225,238,97,128,48,141,235,225,244,225,235,225,238,97,
+129,48,237,167,5,232,225,236,230,247,233,228,244,104,128,255,
+155,242,245,225,244,232,225,105,128,14,35,240,225,242,229,110,
+128,36,173,114,3,167,43,167,79,167,109,97,3,167,51,167,
+61,167,68,226,229,238,231,225,236,105,128,9,220,228,229,246,
+97,128,9,49,231,245,242,237,245,235,232,105,128,10,92,229,
+104,2,167,86,167,95,225,242,225,226,233,99,128,6,145,230,
+233,238,225,236,225,242,225,226,233,99,128,251,141,246,239,227,
+225,236,233,99,4,167,125,167,135,167,142,167,153,226,229,238,
+231,225,236,105,128,9,224,228,229,246,97,128,9,96,231,245,
+234,225,242,225,244,105,128,10,224,246,239,247,229,236,243,233,
+231,110,3,167,169,167,179,167,186,226,229,238,231,225,236,105,
+128,9,196,228,229,246,97,128,9,68,231,245,234,225,242,225,
+244,105,128,10,196,243,245,240,229,242,233,239,114,128,246,241,
+116,2,167,214,167,222,226,236,239,227,107,128,37,144,245,242,
+238,229,100,129,2,121,167,232,243,245,240,229,242,233,239,114,
+128,2,180,117,4,167,253,168,8,168,33,168,80,232,233,242,
+225,231,225,238,97,128,48,139,235,225,244,225,235,225,238,97,
+129,48,235,168,21,232,225,236,230,247,233,228,244,104,128,255,
+153,112,2,168,39,168,74,229,101,2,168,46,168,60,237,225,
+242,235,226,229,238,231,225,236,105,128,9,242,243,233,231,238,
+226,229,238,231,225,236,105,128,9,243,233,225,104,128,246,221,
+244,232,225,105,128,14,36,246,239,227,225,236,233,99,4,168,
+103,168,113,168,120,168,131,226,229,238,231,225,236,105,128,9,
+139,228,229,246,97,128,9,11,231,245,234,225,242,225,244,105,
+128,10,139,246,239,247,229,236,243,233,231,110,3,168,147,168,
+157,168,164,226,229,238,231,225,236,105,128,9,195,228,229,246,
+97,128,9,67,231,245,234,225,242,225,244,105,128,10,195,115,
+147,0,115,168,217,170,187,170,198,171,68,171,107,174,49,174,
+60,176,203,179,85,179,131,179,158,180,93,180,160,181,193,181,
+203,182,133,182,206,183,120,183,130,97,9,168,237,168,247,169,
+12,169,84,169,109,169,120,169,145,169,177,169,217,226,229,238,
+231,225,236,105,128,9,184,227,245,244,101,129,1,91,169,0,
+228,239,244,225,227,227,229,238,116,128,30,101,100,5,169,24,
+169,33,169,39,169,53,169,69,225,242,225,226,233,99,128,6,
+53,229,246,97,128,9,56,230,233,238,225,236,225,242,225,226,
+233,99,128,254,186,233,238,233,244,233,225,236,225,242,225,226,
+233,99,128,254,187,237,229,228,233,225,236,225,242,225,226,233,
+99,128,254,188,231,117,2,169,91,169,100,234,225,242,225,244,
+105,128,10,184,242,237,245,235,232,105,128,10,56,232,233,242,
+225,231,225,238,97,128,48,85,235,225,244,225,235,225,238,97,
+129,48,181,169,133,232,225,236,230,247,233,228,244,104,128,255,
+123,236,236,225,236,236,225,232,239,245,225,236,225,249,232,229,
+247,225,243,225,236,236,225,237,225,242,225,226,233,99,128,253,
+250,237,229,235,104,130,5,225,169,188,169,208,228,225,231,229,
+243,104,129,251,65,169,199,232,229,226,242,229,119,128,251,65,
+232,229,226,242,229,119,128,5,225,242,97,5,169,230,170,48,
+170,56,170,106,170,114,97,5,169,242,169,250,170,2,170,33,
+170,41,225,244,232,225,105,128,14,50,229,244,232,225,105,128,
+14,65,233,237,225,233,109,2,170,12,170,23,225,236,225,233,
+244,232,225,105,128,14,68,245,225,238,244,232,225,105,128,14,
+67,237,244,232,225,105,128,14,51,244,232,225,105,128,14,48,
+229,244,232,225,105,128,14,64,105,3,170,64,170,88,170,99,
+105,2,170,70,170,81,236,229,230,244,244,232,225,105,128,248,
+134,244,232,225,105,128,14,53,236,229,230,244,244,232,225,105,
+128,248,133,244,232,225,105,128,14,52,239,244,232,225,105,128,
+14,66,117,3,170,122,170,172,170,179,101,3,170,130,170,154,
+170,165,101,2,170,136,170,147,236,229,230,244,244,232,225,105,
+128,248,136,244,232,225,105,128,14,55,236,229,230,244,244,232,
+225,105,128,248,135,244,232,225,105,128,14,54,244,232,225,105,
+128,14,56,245,244,232,225,105,128,14,57,226,239,240,239,237,
+239,230,111,128,49,25,99,5,170,210,170,231,170,240,171,33,
+171,55,225,242,239,110,129,1,97,170,219,228,239,244,225,227,
+227,229,238,116,128,30,103,229,228,233,236,236,97,128,1,95,
+232,247,97,131,2,89,170,252,171,7,171,26,227,249,242,233,
+236,236,233,99,128,4,217,228,233,229,242,229,243,233,243,227,
+249,242,233,236,236,233,99,128,4,219,232,239,239,107,128,2,
+90,233,242,99,2,171,41,171,46,236,101,128,36,226,245,237,
+230,236,229,120,128,1,93,239,237,237,225,225,227,227,229,238,
+116,128,2,25,228,239,116,2,171,76,171,85,225,227,227,229,
+238,116,128,30,97,226,229,236,239,119,129,30,99,171,95,228,
+239,244,225,227,227,229,238,116,128,30,105,101,9,171,127,171,
+143,171,178,171,243,172,90,172,117,172,142,172,223,172,250,225,
+231,245,236,236,226,229,236,239,247,227,237,98,128,3,60,99,
+2,171,149,171,171,239,238,100,129,32,51,171,157,244,239,238,
+229,227,232,233,238,229,243,101,128,2,202,244,233,239,110,128,
+0,167,229,110,4,171,189,171,198,171,212,171,228,225,242,225,
+226,233,99,128,6,51,230,233,238,225,236,225,242,225,226,233,
+99,128,254,178,233,238,233,244,233,225,236,225,242,225,226,233,
+99,128,254,179,237,229,228,233,225,236,225,242,225,226,233,99,
+128,254,180,231,239,108,135,5,182,172,7,172,21,172,26,172,
+35,172,50,172,66,172,77,49,2,172,13,172,17,51,128,5,
+182,102,128,5,182,178,99,128,5,182,232,229,226,242,229,119,
+128,5,182,238,225,242,242,239,247,232,229,226,242,229,119,128,
+5,182,241,245,225,242,244,229,242,232,229,226,242,229,119,128,
+5,182,244,225,232,229,226,242,229,119,128,5,146,247,233,228,
+229,232,229,226,242,229,119,128,5,182,104,2,172,96,172,107,
+225,242,237,229,238,233,225,110,128,5,125,233,242,225,231,225,
+238,97,128,48,91,235,225,244,225,235,225,238,97,129,48,187,
+172,130,232,225,236,230,247,233,228,244,104,128,255,126,237,105,
+2,172,149,172,192,227,239,236,239,110,131,0,59,172,163,172,
+172,172,184,225,242,225,226,233,99,128,6,27,237,239,238,239,
+243,240,225,227,101,128,255,27,243,237,225,236,108,128,254,84,
+246,239,233,227,229,228,237,225,242,235,235,225,238,97,129,48,
+156,172,211,232,225,236,230,247,233,228,244,104,128,255,159,238,
+116,2,172,230,172,240,233,243,241,245,225,242,101,128,51,34,
+239,243,241,245,225,242,101,128,51,35,246,229,110,142,0,55,
+173,28,173,37,173,47,173,77,173,84,173,94,173,119,173,146,
+173,180,173,192,173,203,173,236,173,244,173,255,225,242,225,226,
+233,99,128,6,103,226,229,238,231,225,236,105,128,9,237,227,
+233,242,227,236,101,129,36,102,173,58,233,238,246,229,242,243,
+229,243,225,238,243,243,229,242,233,102,128,39,144,228,229,246,
+97,128,9,109,229,233,231,232,244,232,115,128,33,94,231,117,
+2,173,101,173,110,234,225,242,225,244,105,128,10,237,242,237,
+245,235,232,105,128,10,109,232,97,2,173,126,173,137,227,235,
+225,242,225,226,233,99,128,6,103,238,231,250,232,239,117,128,
+48,39,105,2,173,152,173,170,228,229,239,231,242,225,240,232,
+233,227,240,225,242,229,110,128,50,38,238,230,229,242,233,239,
+114,128,32,135,237,239,238,239,243,240,225,227,101,128,255,23,
+239,236,228,243,244,249,236,101,128,247,55,112,2,173,209,173,
+216,225,242,229,110,128,36,122,229,114,2,173,223,173,229,233,
+239,100,128,36,142,243,233,225,110,128,6,247,242,239,237,225,
+110,128,33,118,243,245,240,229,242,233,239,114,128,32,119,116,
+2,174,5,174,43,229,229,110,2,174,13,174,22,227,233,242,
+227,236,101,128,36,112,112,2,174,28,174,35,225,242,229,110,
+128,36,132,229,242,233,239,100,128,36,152,232,225,105,128,14,
+87,230,244,232,249,240,232,229,110,128,0,173,104,7,174,76,
+175,50,175,61,175,75,176,20,176,33,176,197,97,6,174,90,
+174,101,174,111,174,122,175,9,175,34,225,242,237,229,238,233,
+225,110,128,5,119,226,229,238,231,225,236,105,128,9,182,227,
+249,242,233,236,236,233,99,128,4,72,100,2,174,128,174,224,
+228,97,4,174,139,174,148,174,179,174,193,225,242,225,226,233,
+99,128,6,81,228,225,237,237,97,2,174,158,174,167,225,242,
+225,226,233,99,128,252,97,244,225,238,225,242,225,226,233,99,
+128,252,94,230,225,244,232,225,225,242,225,226,233,99,128,252,
+96,235,225,243,242,97,2,174,203,174,212,225,242,225,226,233,
+99,128,252,98,244,225,238,225,242,225,226,233,99,128,252,95,
+101,132,37,146,174,236,174,243,174,251,175,4,228,225,242,107,
+128,37,147,236,233,231,232,116,128,37,145,237,229,228,233,245,
+109,128,37,146,246,97,128,9,54,231,117,2,175,16,175,25,
+234,225,242,225,244,105,128,10,182,242,237,245,235,232,105,128,
+10,54,236,243,232,229,236,229,244,232,229,226,242,229,119,128,
+5,147,226,239,240,239,237,239,230,111,128,49,21,227,232,225,
+227,249,242,233,236,236,233,99,128,4,73,101,4,175,85,175,
+150,175,160,175,177,229,110,4,175,96,175,105,175,119,175,135,
+225,242,225,226,233,99,128,6,52,230,233,238,225,236,225,242,
+225,226,233,99,128,254,182,233,238,233,244,233,225,236,225,242,
+225,226,233,99,128,254,183,237,229,228,233,225,236,225,242,225,
+226,233,99,128,254,184,233,227,239,240,244,233,99,128,3,227,
+241,229,108,129,32,170,175,168,232,229,226,242,229,119,128,32,
+170,246,97,134,5,176,175,194,175,209,175,223,175,232,175,247,
+176,7,49,2,175,200,175,205,177,53,128,5,176,53,128,5,
+176,50,2,175,215,175,219,50,128,5,176,101,128,5,176,232,
+229,226,242,229,119,128,5,176,238,225,242,242,239,247,232,229,
+226,242,229,119,128,5,176,241,245,225,242,244,229,242,232,229,
+226,242,229,119,128,5,176,247,233,228,229,232,229,226,242,229,
+119,128,5,176,232,225,227,249,242,233,236,236,233,99,128,4,
+187,105,2,176,39,176,50,237,225,227,239,240,244,233,99,128,
+3,237,110,131,5,233,176,60,176,143,176,152,100,2,176,66,
+176,132,225,231,229,243,104,130,251,73,176,78,176,87,232,229,
+226,242,229,119,128,251,73,115,2,176,93,176,113,232,233,238,
+228,239,116,129,251,44,176,104,232,229,226,242,229,119,128,251,
+44,233,238,228,239,116,129,251,45,176,123,232,229,226,242,229,
+119,128,251,45,239,244,232,229,226,242,229,119,128,5,193,232,
+229,226,242,229,119,128,5,233,115,2,176,158,176,178,232,233,
+238,228,239,116,129,251,42,176,169,232,229,226,242,229,119,128,
+251,42,233,238,228,239,116,129,251,43,176,188,232,229,226,242,
+229,119,128,251,43,239,239,107,128,2,130,105,8,176,221,177,
+9,177,20,177,45,177,75,177,83,177,96,178,11,231,237,97,
+131,3,195,176,233,176,237,176,245,49,128,3,194,230,233,238,
+225,108,128,3,194,236,245,238,225,244,229,243,249,237,226,239,
+236,231,242,229,229,107,128,3,242,232,233,242,225,231,225,238,
+97,128,48,87,235,225,244,225,235,225,238,97,129,48,183,177,
+33,232,225,236,230,247,233,228,244,104,128,255,124,236,245,113,
+2,177,53,177,62,232,229,226,242,229,119,128,5,189,236,229,
+230,244,232,229,226,242,229,119,128,5,189,237,233,236,225,114,
+128,34,60,238,228,239,244,232,229,226,242,229,119,128,5,194,
+239,115,6,177,111,177,146,177,178,177,206,177,220,177,252,97,
+2,177,117,177,132,227,233,242,227,236,229,235,239,242,229,225,
+110,128,50,116,240,225,242,229,238,235,239,242,229,225,110,128,
+50,20,227,105,2,177,153,177,165,229,245,227,235,239,242,229,
+225,110,128,49,126,242,227,236,229,235,239,242,229,225,110,128,
+50,102,107,2,177,184,177,198,233,249,229,239,235,235,239,242,
+229,225,110,128,49,122,239,242,229,225,110,128,49,69,238,233,
+229,245,238,235,239,242,229,225,110,128,49,123,112,2,177,226,
+177,239,225,242,229,238,235,239,242,229,225,110,128,50,6,233,
+229,245,240,235,239,242,229,225,110,128,49,125,244,233,235,229,
+245,244,235,239,242,229,225,110,128,49,124,120,141,0,54,178,
+41,178,50,178,60,178,90,178,97,178,122,178,149,178,183,178,
+195,178,206,178,239,178,247,179,2,225,242,225,226,233,99,128,
+6,102,226,229,238,231,225,236,105,128,9,236,227,233,242,227,
+236,101,129,36,101,178,71,233,238,246,229,242,243,229,243,225,
+238,243,243,229,242,233,102,128,39,143,228,229,246,97,128,9,
+108,231,117,2,178,104,178,113,234,225,242,225,244,105,128,10,
+236,242,237,245,235,232,105,128,10,108,232,97,2,178,129,178,
+140,227,235,225,242,225,226,233,99,128,6,102,238,231,250,232,
+239,117,128,48,38,105,2,178,155,178,173,228,229,239,231,242,
+225,240,232,233,227,240,225,242,229,110,128,50,37,238,230,229,
+242,233,239,114,128,32,134,237,239,238,239,243,240,225,227,101,
+128,255,22,239,236,228,243,244,249,236,101,128,247,54,112,2,
+178,212,178,219,225,242,229,110,128,36,121,229,114,2,178,226,
+178,232,233,239,100,128,36,141,243,233,225,110,128,6,246,242,
+239,237,225,110,128,33,117,243,245,240,229,242,233,239,114,128,
+32,118,116,2,179,8,179,79,229,229,110,2,179,16,179,58,
+99,2,179,22,179,30,233,242,227,236,101,128,36,111,245,242,
+242,229,238,227,249,228,229,238,239,237,233,238,225,244,239,242,
+226,229,238,231,225,236,105,128,9,249,112,2,179,64,179,71,
+225,242,229,110,128,36,131,229,242,233,239,100,128,36,151,232,
+225,105,128,14,86,108,2,179,91,179,111,225,243,104,129,0,
+47,179,99,237,239,238,239,243,240,225,227,101,128,255,15,239,
+238,103,129,1,127,179,119,228,239,244,225,227,227,229,238,116,
+128,30,155,109,2,179,137,179,147,233,236,229,230,225,227,101,
+128,38,58,239,238,239,243,240,225,227,101,128,255,83,111,6,
+179,172,179,222,179,233,180,2,180,47,180,58,102,2,179,178,
+179,192,240,225,243,245,241,232,229,226,242,229,119,128,5,195,
+116,2,179,198,179,207,232,249,240,232,229,110,128,0,173,243,
+233,231,238,227,249,242,233,236,236,233,99,128,4,76,232,233,
+242,225,231,225,238,97,128,48,93,235,225,244,225,235,225,238,
+97,129,48,189,179,246,232,225,236,230,247,233,228,244,104,128,
+255,127,236,233,228,245,115,2,180,12,180,29,236,239,238,231,
+239,246,229,242,236,225,249,227,237,98,128,3,56,243,232,239,
+242,244,239,246,229,242,236,225,249,227,237,98,128,3,55,242,
+245,243,233,244,232,225,105,128,14,41,115,3,180,66,180,76,
+180,84,225,236,225,244,232,225,105,128,14,40,239,244,232,225,
+105,128,14,11,245,225,244,232,225,105,128,14,42,240,97,3,
+180,102,180,122,180,154,227,101,129,0,32,180,109,232,225,227,
+235,225,242,225,226,233,99,128,0,32,228,101,129,38,96,180,
+129,243,245,233,116,2,180,138,180,146,226,236,225,227,107,128,
+38,96,247,232,233,244,101,128,38,100,242,229,110,128,36,174,
+241,245,225,242,101,11,180,188,180,199,180,213,180,238,180,255,
+181,25,181,40,181,73,181,100,181,156,181,171,226,229,236,239,
+247,227,237,98,128,3,59,99,2,180,205,180,209,99,128,51,
+196,109,128,51,157,228,233,225,231,239,238,225,236,227,242,239,
+243,243,232,225,244,227,232,230,233,236,108,128,37,169,232,239,
+242,233,250,239,238,244,225,236,230,233,236,108,128,37,164,107,
+2,181,5,181,9,103,128,51,143,109,129,51,158,181,15,227,
+225,240,233,244,225,108,128,51,206,108,2,181,31,181,35,110,
+128,51,209,239,103,128,51,210,109,4,181,50,181,54,181,59,
+181,63,103,128,51,142,233,108,128,51,213,109,128,51,156,243,
+241,245,225,242,229,100,128,51,161,239,242,244,232,239,231,239,
+238,225,236,227,242,239,243,243,232,225,244,227,232,230,233,236,
+108,128,37,166,245,240,240,229,114,2,181,110,181,133,236,229,
+230,244,244,239,236,239,247,229,242,242,233,231,232,244,230,233,
+236,108,128,37,167,242,233,231,232,244,244,239,236,239,247,229,
+242,236,229,230,244,230,233,236,108,128,37,168,246,229,242,244,
+233,227,225,236,230,233,236,108,128,37,165,247,232,233,244,229,
+247,233,244,232,243,237,225,236,236,226,236,225,227,107,128,37,
+163,242,243,241,245,225,242,101,128,51,219,115,2,181,209,182,
+123,97,4,181,219,181,229,181,236,181,247,226,229,238,231,225,
+236,105,128,9,183,228,229,246,97,128,9,55,231,245,234,225,
+242,225,244,105,128,10,183,238,103,8,182,10,182,24,182,38,
+182,52,182,67,182,81,182,95,182,108,227,233,229,245,227,235,
+239,242,229,225,110,128,49,73,232,233,229,245,232,235,239,242,
+229,225,110,128,49,133,233,229,245,238,231,235,239,242,229,225,
+110,128,49,128,235,233,249,229,239,235,235,239,242,229,225,110,
+128,49,50,238,233,229,245,238,235,239,242,229,225,110,128,49,
+101,240,233,229,245,240,235,239,242,229,225,110,128,49,67,243,
+233,239,243,235,239,242,229,225,110,128,49,70,244,233,235,229,
+245,244,235,239,242,229,225,110,128,49,56,245,240,229,242,233,
+239,114,128,246,242,116,2,182,139,182,162,229,242,236,233,238,
+103,129,0,163,182,150,237,239,238,239,243,240,225,227,101,128,
+255,225,242,239,235,101,2,182,171,182,188,236,239,238,231,239,
+246,229,242,236,225,249,227,237,98,128,3,54,243,232,239,242,
+244,239,246,229,242,236,225,249,227,237,98,128,3,53,117,7,
+182,222,182,254,183,20,183,31,183,72,183,82,183,86,226,243,
+229,116,130,34,130,182,233,182,244,238,239,244,229,241,245,225,
+108,128,34,138,239,242,229,241,245,225,108,128,34,134,99,2,
+183,4,183,12,227,229,229,228,115,128,34,123,232,244,232,225,
+116,128,34,11,232,233,242,225,231,225,238,97,128,48,89,107,
+2,183,37,183,61,225,244,225,235,225,238,97,129,48,185,183,
+49,232,225,236,230,247,233,228,244,104,128,255,125,245,238,225,
+242,225,226,233,99,128,6,82,237,237,225,244,233,239,110,128,
+34,17,110,128,38,60,240,229,242,243,229,116,130,34,131,183,
+99,183,110,238,239,244,229,241,245,225,108,128,34,139,239,242,
+229,241,245,225,108,128,34,135,246,243,241,245,225,242,101,128,
+51,220,249,239,245,247,225,229,242,225,243,241,245,225,242,101,
+128,51,124,116,144,0,116,183,183,184,192,184,213,185,100,185,
+140,187,188,191,70,192,145,192,157,192,169,193,202,193,227,194,
+57,194,237,195,165,195,255,97,10,183,205,183,215,183,236,183,
+243,184,12,184,90,184,107,184,132,184,146,184,150,226,229,238,
+231,225,236,105,128,9,164,227,107,2,183,222,183,229,228,239,
+247,110,128,34,164,236,229,230,116,128,34,163,228,229,246,97,
+128,9,36,231,117,2,183,250,184,3,234,225,242,225,244,105,
+128,10,164,242,237,245,235,232,105,128,10,36,104,4,184,22,
+184,31,184,45,184,75,225,242,225,226,233,99,128,6,55,230,
+233,238,225,236,225,242,225,226,233,99,128,254,194,105,2,184,
+51,184,66,238,233,244,233,225,236,225,242,225,226,233,99,128,
+254,195,242,225,231,225,238,97,128,48,95,237,229,228,233,225,
+236,225,242,225,226,233,99,128,254,196,233,243,249,239,245,229,
+242,225,243,241,245,225,242,101,128,51,125,235,225,244,225,235,
+225,238,97,129,48,191,184,120,232,225,236,230,247,233,228,244,
+104,128,255,128,244,247,229,229,236,225,242,225,226,233,99,128,
+6,64,117,128,3,196,118,130,5,234,184,158,184,183,228,225,
+231,229,115,129,251,74,184,168,104,129,251,74,184,174,232,229,
+226,242,229,119,128,251,74,232,229,226,242,229,119,128,5,234,
+98,2,184,198,184,203,225,114,128,1,103,239,240,239,237,239,
+230,111,128,49,10,99,6,184,227,184,234,184,241,184,250,185,
+60,185,87,225,242,239,110,128,1,101,227,245,242,108,128,2,
+168,229,228,233,236,236,97,128,1,99,232,229,104,4,185,6,
+185,15,185,29,185,45,225,242,225,226,233,99,128,6,134,230,
+233,238,225,236,225,242,225,226,233,99,128,251,123,233,238,233,
+244,233,225,236,225,242,225,226,233,99,128,251,124,237,229,228,
+233,225,236,225,242,225,226,233,99,128,251,125,233,242,99,2,
+185,68,185,73,236,101,128,36,227,245,237,230,236,229,248,226,
+229,236,239,119,128,30,113,239,237,237,225,225,227,227,229,238,
+116,128,1,99,100,2,185,106,185,116,233,229,242,229,243,233,
+115,128,30,151,239,116,2,185,123,185,132,225,227,227,229,238,
+116,128,30,107,226,229,236,239,119,128,30,109,101,9,185,160,
+185,171,185,191,186,201,186,226,187,34,187,101,187,106,187,158,
+227,249,242,233,236,236,233,99,128,4,66,228,229,243,227,229,
+238,228,229,242,227,249,242,233,236,236,233,99,128,4,173,104,
+7,185,207,185,216,185,230,186,14,186,44,186,85,186,183,225,
+242,225,226,233,99,128,6,42,230,233,238,225,236,225,242,225,
+226,233,99,128,254,150,232,225,232,105,2,185,239,185,254,238,
+233,244,233,225,236,225,242,225,226,233,99,128,252,162,243,239,
+236,225,244,229,228,225,242,225,226,233,99,128,252,12,105,2,
+186,20,186,35,238,233,244,233,225,236,225,242,225,226,233,99,
+128,254,151,242,225,231,225,238,97,128,48,102,234,229,229,237,
+105,2,186,54,186,69,238,233,244,233,225,236,225,242,225,226,
+233,99,128,252,161,243,239,236,225,244,229,228,225,242,225,226,
+233,99,128,252,11,109,2,186,91,186,125,225,242,226,245,244,
+97,2,186,102,186,111,225,242,225,226,233,99,128,6,41,230,
+233,238,225,236,225,242,225,226,233,99,128,254,148,101,2,186,
+131,186,144,228,233,225,236,225,242,225,226,233,99,128,254,152,
+229,237,105,2,186,152,186,167,238,233,244,233,225,236,225,242,
+225,226,233,99,128,252,164,243,239,236,225,244,229,228,225,242,
+225,226,233,99,128,252,14,238,239,239,238,230,233,238,225,236,
+225,242,225,226,233,99,128,252,115,235,225,244,225,235,225,238,
+97,129,48,198,186,214,232,225,236,230,247,233,228,244,104,128,
+255,131,108,2,186,232,186,251,229,240,232,239,238,101,129,33,
+33,186,243,226,236,225,227,107,128,38,14,233,243,232,97,2,
+187,4,187,19,231,229,228,239,236,225,232,229,226,242,229,119,
+128,5,160,241,229,244,225,238,225,232,229,226,242,229,119,128,
+5,169,110,4,187,44,187,53,187,72,187,93,227,233,242,227,
+236,101,128,36,105,233,228,229,239,231,242,225,240,232,233,227,
+240,225,242,229,110,128,50,41,112,2,187,78,187,85,225,242,
+229,110,128,36,125,229,242,233,239,100,128,36,145,242,239,237,
+225,110,128,33,121,243,104,128,2,167,116,131,5,216,187,116,
+187,136,187,145,228,225,231,229,243,104,129,251,56,187,127,232,
+229,226,242,229,119,128,251,56,232,229,226,242,229,119,128,5,
+216,243,229,227,249,242,233,236,236,233,99,128,4,181,246,233,
+114,2,187,166,187,175,232,229,226,242,229,119,128,5,155,236,
+229,230,244,232,229,226,242,229,119,128,5,155,104,6,187,202,
+188,98,188,220,189,96,190,3,191,60,97,5,187,214,187,224,
+187,231,188,0,188,29,226,229,238,231,225,236,105,128,9,165,
+228,229,246,97,128,9,37,231,117,2,187,238,187,247,234,225,
+242,225,244,105,128,10,165,242,237,245,235,232,105,128,10,37,
+108,2,188,6,188,15,225,242,225,226,233,99,128,6,48,230,
+233,238,225,236,225,242,225,226,233,99,128,254,172,238,244,232,
+225,235,232,225,116,3,188,44,188,75,188,82,236,239,119,2,
+188,52,188,63,236,229,230,244,244,232,225,105,128,248,152,242,
+233,231,232,244,244,232,225,105,128,248,151,244,232,225,105,128,
+14,76,245,240,240,229,242,236,229,230,244,244,232,225,105,128,
+248,150,101,3,188,106,188,170,188,193,104,4,188,116,188,125,
+188,139,188,155,225,242,225,226,233,99,128,6,43,230,233,238,
+225,236,225,242,225,226,233,99,128,254,154,233,238,233,244,233,
+225,236,225,242,225,226,233,99,128,254,155,237,229,228,233,225,
+236,225,242,225,226,233,99,128,254,156,242,101,2,188,177,188,
+186,229,248,233,243,244,115,128,34,3,230,239,242,101,128,34,
+52,244,97,130,3,184,188,202,188,206,49,128,3,209,243,249,
+237,226,239,236,231,242,229,229,107,128,3,209,105,2,188,226,
+189,56,229,245,244,104,4,188,239,189,18,189,33,189,42,97,
+2,188,245,189,4,227,233,242,227,236,229,235,239,242,229,225,
+110,128,50,121,240,225,242,229,238,235,239,242,229,225,110,128,
+50,25,227,233,242,227,236,229,235,239,242,229,225,110,128,50,
+107,235,239,242,229,225,110,128,49,76,240,225,242,229,238,235,
+239,242,229,225,110,128,50,11,242,244,229,229,110,2,189,66,
+189,75,227,233,242,227,236,101,128,36,108,112,2,189,81,189,
+88,225,242,229,110,128,36,128,229,242,233,239,100,128,36,148,
+111,6,189,110,189,127,189,132,189,146,189,151,189,204,238,225,
+238,231,237,239,238,244,232,239,244,232,225,105,128,14,17,239,
+107,128,1,173,240,232,245,244,232,225,239,244,232,225,105,128,
+14,18,242,110,128,0,254,244,104,3,189,160,189,184,189,194,
+97,2,189,166,189,176,232,225,238,244,232,225,105,128,14,23,
+238,244,232,225,105,128,14,16,239,238,231,244,232,225,105,128,
+14,24,245,238,231,244,232,225,105,128,14,22,245,243,225,238,
+100,2,189,214,189,225,227,249,242,233,236,236,233,99,128,4,
+130,243,243,229,240,225,242,225,244,239,114,2,189,240,189,249,
+225,242,225,226,233,99,128,6,108,240,229,242,243,233,225,110,
+128,6,108,242,229,101,144,0,51,190,41,190,50,190,60,190,
+90,190,97,190,107,190,132,190,159,190,193,190,205,190,224,190,
+235,191,12,191,34,191,42,191,53,225,242,225,226,233,99,128,
+6,99,226,229,238,231,225,236,105,128,9,233,227,233,242,227,
+236,101,129,36,98,190,71,233,238,246,229,242,243,229,243,225,
+238,243,243,229,242,233,102,128,39,140,228,229,246,97,128,9,
+105,229,233,231,232,244,232,115,128,33,92,231,117,2,190,114,
+190,123,234,225,242,225,244,105,128,10,233,242,237,245,235,232,
+105,128,10,105,232,97,2,190,139,190,150,227,235,225,242,225,
+226,233,99,128,6,99,238,231,250,232,239,117,128,48,35,105,
+2,190,165,190,183,228,229,239,231,242,225,240,232,233,227,240,
+225,242,229,110,128,50,34,238,230,229,242,233,239,114,128,32,
+131,237,239,238,239,243,240,225,227,101,128,255,19,238,245,237,
+229,242,225,244,239,242,226,229,238,231,225,236,105,128,9,246,
+239,236,228,243,244,249,236,101,128,247,51,112,2,190,241,190,
+248,225,242,229,110,128,36,118,229,114,2,190,255,191,5,233,
+239,100,128,36,138,243,233,225,110,128,6,243,241,245,225,242,
+244,229,242,115,129,0,190,191,25,229,237,228,225,243,104,128,
+246,222,242,239,237,225,110,128,33,114,243,245,240,229,242,233,
+239,114,128,0,179,244,232,225,105,128,14,83,250,243,241,245,
+225,242,101,128,51,148,105,7,191,86,191,97,191,212,192,54,
+192,66,192,115,192,132,232,233,242,225,231,225,238,97,128,48,
+97,107,2,191,103,191,127,225,244,225,235,225,238,97,129,48,
+193,191,115,232,225,236,230,247,233,228,244,104,128,255,129,229,
+245,116,4,191,139,191,174,191,189,191,198,97,2,191,145,191,
+160,227,233,242,227,236,229,235,239,242,229,225,110,128,50,112,
+240,225,242,229,238,235,239,242,229,225,110,128,50,16,227,233,
+242,227,236,229,235,239,242,229,225,110,128,50,98,235,239,242,
+229,225,110,128,49,55,240,225,242,229,238,235,239,242,229,225,
+110,128,50,2,236,228,101,133,2,220,191,228,191,239,192,0,
+192,12,192,40,226,229,236,239,247,227,237,98,128,3,48,99,
+2,191,245,191,250,237,98,128,3,3,239,237,98,128,3,3,
+228,239,245,226,236,229,227,237,98,128,3,96,111,2,192,18,
+192,28,240,229,242,225,244,239,114,128,34,60,246,229,242,236,
+225,249,227,237,98,128,3,52,246,229,242,244,233,227,225,236,
+227,237,98,128,3,62,237,229,243,227,233,242,227,236,101,128,
+34,151,112,2,192,72,192,102,229,232,97,2,192,80,192,89,
+232,229,226,242,229,119,128,5,150,236,229,230,244,232,229,226,
+242,229,119,128,5,150,240,233,231,245,242,237,245,235,232,105,
+128,10,112,244,236,239,227,249,242,233,236,236,233,227,227,237,
+98,128,4,131,247,238,225,242,237,229,238,233,225,110,128,5,
+127,236,233,238,229,226,229,236,239,119,128,30,111,237,239,238,
+239,243,240,225,227,101,128,255,84,111,7,192,185,192,196,192,
+207,192,232,193,96,193,108,193,192,225,242,237,229,238,233,225,
+110,128,5,105,232,233,242,225,231,225,238,97,128,48,104,235,
+225,244,225,235,225,238,97,129,48,200,192,220,232,225,236,230,
+247,233,228,244,104,128,255,132,110,3,192,240,193,82,193,87,
+101,4,192,250,193,63,193,70,193,76,226,225,114,4,193,6,
+193,35,193,45,193,54,229,248,244,242,97,2,193,16,193,26,
+232,233,231,232,237,239,100,128,2,229,236,239,247,237,239,100,
+128,2,233,232,233,231,232,237,239,100,128,2,230,236,239,247,
+237,239,100,128,2,232,237,233,228,237,239,100,128,2,231,230,
+233,246,101,128,1,189,243,233,120,128,1,133,244,247,111,128,
+1,168,239,115,128,3,132,243,241,245,225,242,101,128,51,39,
+240,225,244,225,235,244,232,225,105,128,14,15,242,244,239,233,
+243,229,243,232,229,236,236,226,242,225,227,235,229,116,2,193,
+131,193,161,236,229,230,116,130,48,20,193,142,193,150,243,237,
+225,236,108,128,254,93,246,229,242,244,233,227,225,108,128,254,
+57,242,233,231,232,116,130,48,21,193,173,193,181,243,237,225,
+236,108,128,254,94,246,229,242,244,233,227,225,108,128,254,58,
+244,225,239,244,232,225,105,128,14,21,240,97,2,193,209,193,
+221,236,225,244,225,236,232,239,239,107,128,1,171,242,229,110,
+128,36,175,114,3,193,235,194,10,194,25,225,228,229,237,225,
+242,107,129,33,34,193,247,115,2,193,253,194,3,225,238,115,
+128,248,234,229,242,233,102,128,246,219,229,244,242,239,230,236,
+229,248,232,239,239,107,128,2,136,233,225,103,4,194,37,194,
+42,194,47,194,52,228,110,128,37,188,236,102,128,37,196,242,
+116,128,37,186,245,112,128,37,178,115,132,2,166,194,69,194,
+108,194,214,194,227,225,228,105,130,5,230,194,79,194,99,228,
+225,231,229,243,104,129,251,70,194,90,232,229,226,242,229,119,
+128,251,70,232,229,226,242,229,119,128,5,230,101,2,194,114,
+194,125,227,249,242,233,236,236,233,99,128,4,70,242,101,134,
+5,181,194,142,194,156,194,161,194,170,194,185,194,201,49,2,
+194,148,194,152,50,128,5,181,101,128,5,181,178,98,128,5,
+181,232,229,226,242,229,119,128,5,181,238,225,242,242,239,247,
+232,229,226,242,229,119,128,5,181,241,245,225,242,244,229,242,
+232,229,226,242,229,119,128,5,181,247,233,228,229,232,229,226,
+242,229,119,128,5,181,232,229,227,249,242,233,236,236,233,99,
+128,4,91,245,240,229,242,233,239,114,128,246,243,116,4,194,
+247,195,41,195,106,195,157,97,3,194,255,195,9,195,16,226,
+229,238,231,225,236,105,128,9,159,228,229,246,97,128,9,31,
+231,117,2,195,23,195,32,234,225,242,225,244,105,128,10,159,
+242,237,245,235,232,105,128,10,31,229,104,4,195,52,195,61,
+195,75,195,91,225,242,225,226,233,99,128,6,121,230,233,238,
+225,236,225,242,225,226,233,99,128,251,103,233,238,233,244,233,
+225,236,225,242,225,226,233,99,128,251,104,237,229,228,233,225,
+236,225,242,225,226,233,99,128,251,105,232,97,3,195,115,195,
+125,195,132,226,229,238,231,225,236,105,128,9,160,228,229,246,
+97,128,9,32,231,117,2,195,139,195,148,234,225,242,225,244,
+105,128,10,160,242,237,245,235,232,105,128,10,32,245,242,238,
+229,100,128,2,135,117,3,195,173,195,184,195,209,232,233,242,
+225,231,225,238,97,128,48,100,235,225,244,225,235,225,238,97,
+129,48,196,195,197,232,225,236,230,247,233,228,244,104,128,255,
+130,243,237,225,236,108,2,195,219,195,230,232,233,242,225,231,
+225,238,97,128,48,99,235,225,244,225,235,225,238,97,129,48,
+195,195,243,232,225,236,230,247,233,228,244,104,128,255,111,119,
+2,196,5,196,110,101,2,196,11,196,59,236,246,101,3,196,
+21,196,30,196,51,227,233,242,227,236,101,128,36,107,112,2,
+196,36,196,43,225,242,229,110,128,36,127,229,242,233,239,100,
+128,36,147,242,239,237,225,110,128,33,123,238,244,121,3,196,
+69,196,78,196,89,227,233,242,227,236,101,128,36,115,232,225,
+238,231,250,232,239,117,128,83,68,112,2,196,95,196,102,225,
+242,229,110,128,36,135,229,242,233,239,100,128,36,155,111,142,
+0,50,196,142,196,151,196,161,196,191,196,243,197,12,197,39,
+197,73,197,85,197,104,197,115,197,148,197,156,197,180,225,242,
+225,226,233,99,128,6,98,226,229,238,231,225,236,105,128,9,
+232,227,233,242,227,236,101,129,36,97,196,172,233,238,246,229,
+242,243,229,243,225,238,243,243,229,242,233,102,128,39,139,100,
+2,196,197,196,203,229,246,97,128,9,104,239,116,2,196,210,
+196,221,229,238,236,229,225,228,229,114,128,32,37,236,229,225,
+228,229,114,129,32,37,196,232,246,229,242,244,233,227,225,108,
+128,254,48,231,117,2,196,250,197,3,234,225,242,225,244,105,
+128,10,232,242,237,245,235,232,105,128,10,104,232,97,2,197,
+19,197,30,227,235,225,242,225,226,233,99,128,6,98,238,231,
+250,232,239,117,128,48,34,105,2,197,45,197,63,228,229,239,
+231,242,225,240,232,233,227,240,225,242,229,110,128,50,33,238,
+230,229,242,233,239,114,128,32,130,237,239,238,239,243,240,225,
+227,101,128,255,18,238,245,237,229,242,225,244,239,242,226,229,
+238,231,225,236,105,128,9,245,239,236,228,243,244,249,236,101,
+128,247,50,112,2,197,121,197,128,225,242,229,110,128,36,117,
+229,114,2,197,135,197,141,233,239,100,128,36,137,243,233,225,
+110,128,6,242,242,239,237,225,110,128,33,113,115,2,197,162,
+197,170,244,242,239,235,101,128,1,187,245,240,229,242,233,239,
+114,128,0,178,244,104,2,197,187,197,192,225,105,128,14,82,
+233,242,228,115,128,33,84,117,145,0,117,197,237,197,245,198,
+30,198,87,198,225,199,6,199,129,199,145,199,196,200,10,200,
+91,200,100,200,219,200,243,201,95,201,123,201,237,225,227,245,
+244,101,128,0,250,98,4,197,255,198,4,198,13,198,23,225,
+114,128,2,137,229,238,231,225,236,105,128,9,137,239,240,239,
+237,239,230,111,128,49,40,242,229,246,101,128,1,109,99,3,
+198,38,198,45,198,77,225,242,239,110,128,1,212,233,242,99,
+2,198,53,198,58,236,101,128,36,228,245,237,230,236,229,120,
+129,0,251,198,69,226,229,236,239,119,128,30,119,249,242,233,
+236,236,233,99,128,4,67,100,5,198,99,198,110,198,133,198,
+139,198,215,225,244,244,225,228,229,246,97,128,9,81,226,108,
+2,198,117,198,125,225,227,245,244,101,128,1,113,231,242,225,
+246,101,128,2,21,229,246,97,128,9,9,233,229,242,229,243,
+233,115,133,0,252,198,159,198,167,198,175,198,198,198,206,225,
+227,245,244,101,128,1,216,226,229,236,239,119,128,30,115,99,
+2,198,181,198,188,225,242,239,110,128,1,218,249,242,233,236,
+236,233,99,128,4,241,231,242,225,246,101,128,1,220,237,225,
+227,242,239,110,128,1,214,239,244,226,229,236,239,119,128,30,
+229,103,2,198,231,198,238,242,225,246,101,128,0,249,117,2,
+198,244,198,253,234,225,242,225,244,105,128,10,137,242,237,245,
+235,232,105,128,10,9,104,3,199,14,199,24,199,102,233,242,
+225,231,225,238,97,128,48,70,111,2,199,30,199,40,239,235,
+225,226,239,246,101,128,30,231,242,110,133,1,176,199,55,199,
+63,199,74,199,82,199,94,225,227,245,244,101,128,30,233,228,
+239,244,226,229,236,239,119,128,30,241,231,242,225,246,101,128,
+30,235,232,239,239,235,225,226,239,246,101,128,30,237,244,233,
+236,228,101,128,30,239,245,238,231,225,242,245,237,236,225,245,
+116,129,1,113,199,118,227,249,242,233,236,236,233,99,128,4,
+243,233,238,246,229,242,244,229,228,226,242,229,246,101,128,2,
+23,107,3,199,153,199,177,199,188,225,244,225,235,225,238,97,
+129,48,166,199,165,232,225,236,230,247,233,228,244,104,128,255,
+115,227,249,242,233,236,236,233,99,128,4,121,239,242,229,225,
+110,128,49,92,109,2,199,202,199,255,97,2,199,208,199,241,
+227,242,239,110,130,1,107,199,219,199,230,227,249,242,233,236,
+236,233,99,128,4,239,228,233,229,242,229,243,233,115,128,30,
+123,244,242,225,231,245,242,237,245,235,232,105,128,10,65,239,
+238,239,243,240,225,227,101,128,255,85,110,2,200,16,200,71,
+228,229,242,243,227,239,242,101,132,0,95,200,35,200,41,200,
+53,200,64,228,226,108,128,32,23,237,239,238,239,243,240,225,
+227,101,128,255,63,246,229,242,244,233,227,225,108,128,254,51,
+247,225,246,121,128,254,79,105,2,200,77,200,82,239,110,128,
+34,42,246,229,242,243,225,108,128,34,0,239,231,239,238,229,
+107,128,1,115,112,5,200,112,200,119,200,127,200,142,200,193,
+225,242,229,110,128,36,176,226,236,239,227,107,128,37,128,240,
+229,242,228,239,244,232,229,226,242,229,119,128,5,196,243,233,
+236,239,110,131,3,197,200,156,200,177,200,185,228,233,229,242,
+229,243,233,115,129,3,203,200,169,244,239,238,239,115,128,3,
+176,236,225,244,233,110,128,2,138,244,239,238,239,115,128,3,
+205,244,225,227,107,2,200,202,200,213,226,229,236,239,247,227,
+237,98,128,3,29,237,239,100,128,2,212,114,2,200,225,200,
+237,225,231,245,242,237,245,235,232,105,128,10,115,233,238,103,
+128,1,111,115,3,200,251,201,10,201,55,232,239,242,244,227,
+249,242,233,236,236,233,99,128,4,94,237,225,236,108,2,201,
+19,201,30,232,233,242,225,231,225,238,97,128,48,69,235,225,
+244,225,235,225,238,97,129,48,165,201,43,232,225,236,230,247,
+233,228,244,104,128,255,105,244,242,225,233,231,232,116,2,201,
+67,201,78,227,249,242,233,236,236,233,99,128,4,175,243,244,
+242,239,235,229,227,249,242,233,236,236,233,99,128,4,177,244,
+233,236,228,101,130,1,105,201,107,201,115,225,227,245,244,101,
+128,30,121,226,229,236,239,119,128,30,117,117,5,201,135,201,
+145,201,152,201,177,201,193,226,229,238,231,225,236,105,128,9,
+138,228,229,246,97,128,9,10,231,117,2,201,159,201,168,234,
+225,242,225,244,105,128,10,138,242,237,245,235,232,105,128,10,
+10,237,225,244,242,225,231,245,242,237,245,235,232,105,128,10,
+66,246,239,247,229,236,243,233,231,110,3,201,209,201,219,201,
+226,226,229,238,231,225,236,105,128,9,194,228,229,246,97,128,
+9,66,231,245,234,225,242,225,244,105,128,10,194,246,239,247,
+229,236,243,233,231,110,3,201,253,202,7,202,14,226,229,238,
+231,225,236,105,128,9,193,228,229,246,97,128,9,65,231,245,
+234,225,242,225,244,105,128,10,193,118,139,0,118,202,51,202,
+199,202,208,202,219,203,148,203,155,203,253,204,9,204,109,204,
+117,204,138,97,4,202,61,202,68,202,93,202,104,228,229,246,
+97,128,9,53,231,117,2,202,75,202,84,234,225,242,225,244,
+105,128,10,181,242,237,245,235,232,105,128,10,53,235,225,244,
+225,235,225,238,97,128,48,247,118,132,5,213,202,116,202,143,
+202,175,202,187,228,225,231,229,243,104,130,251,53,202,129,202,
+134,182,53,128,251,53,232,229,226,242,229,119,128,251,53,104,
+2,202,149,202,157,229,226,242,229,119,128,5,213,239,236,225,
+109,129,251,75,202,166,232,229,226,242,229,119,128,251,75,246,
+225,246,232,229,226,242,229,119,128,5,240,249,239,228,232,229,
+226,242,229,119,128,5,241,227,233,242,227,236,101,128,36,229,
+228,239,244,226,229,236,239,119,128,30,127,101,6,202,233,202,
+244,203,52,203,63,203,69,203,136,227,249,242,233,236,236,233,
+99,128,4,50,104,4,202,254,203,7,203,21,203,37,225,242,
+225,226,233,99,128,6,164,230,233,238,225,236,225,242,225,226,
+233,99,128,251,107,233,238,233,244,233,225,236,225,242,225,226,
+233,99,128,251,108,237,229,228,233,225,236,225,242,225,226,233,
+99,128,251,109,235,225,244,225,235,225,238,97,128,48,249,238,
+245,115,128,38,64,242,244,233,227,225,108,2,203,80,203,86,
+226,225,114,128,0,124,236,233,238,101,4,203,99,203,110,203,
+121,203,130,225,226,239,246,229,227,237,98,128,3,13,226,229,
+236,239,247,227,237,98,128,3,41,236,239,247,237,239,100,128,
+2,204,237,239,100,128,2,200,247,225,242,237,229,238,233,225,
+110,128,5,126,232,239,239,107,128,2,139,105,3,203,163,203,
+174,203,213,235,225,244,225,235,225,238,97,128,48,248,242,225,
+237,97,3,203,185,203,195,203,202,226,229,238,231,225,236,105,
+128,9,205,228,229,246,97,128,9,77,231,245,234,225,242,225,
+244,105,128,10,205,243,225,242,231,97,3,203,225,203,235,203,
+242,226,229,238,231,225,236,105,128,9,131,228,229,246,97,128,
+9,3,231,245,234,225,242,225,244,105,128,10,131,237,239,238,
+239,243,240,225,227,101,128,255,86,111,3,204,17,204,28,204,
+98,225,242,237,229,238,233,225,110,128,5,120,233,227,229,100,
+2,204,37,204,73,233,244,229,242,225,244,233,239,110,2,204,
+51,204,62,232,233,242,225,231,225,238,97,128,48,158,235,225,
+244,225,235,225,238,97,128,48,254,237,225,242,235,235,225,238,
+97,129,48,155,204,86,232,225,236,230,247,233,228,244,104,128,
+255,158,235,225,244,225,235,225,238,97,128,48,250,240,225,242,
+229,110,128,36,177,116,2,204,123,204,130,233,236,228,101,128,
+30,125,245,242,238,229,100,128,2,140,117,2,204,144,204,155,
+232,233,242,225,231,225,238,97,128,48,148,235,225,244,225,235,
+225,238,97,128,48,244,119,143,0,119,204,200,205,177,205,187,
+205,210,205,250,206,61,206,69,208,40,208,81,208,93,208,168,
+208,176,208,183,208,194,208,203,97,8,204,218,204,225,204,235,
+204,246,205,28,205,60,205,72,205,108,227,245,244,101,128,30,
+131,229,235,239,242,229,225,110,128,49,89,232,233,242,225,231,
+225,238,97,128,48,143,107,2,204,252,205,20,225,244,225,235,
+225,238,97,129,48,239,205,8,232,225,236,230,247,233,228,244,
+104,128,255,156,239,242,229,225,110,128,49,88,243,237,225,236,
+108,2,205,38,205,49,232,233,242,225,231,225,238,97,128,48,
+142,235,225,244,225,235,225,238,97,128,48,238,244,244,239,243,
+241,245,225,242,101,128,51,87,118,2,205,78,205,86,229,228,
+225,243,104,128,48,28,249,245,238,228,229,242,243,227,239,242,
+229,246,229,242,244,233,227,225,108,128,254,52,119,3,205,116,
+205,125,205,139,225,242,225,226,233,99,128,6,72,230,233,238,
+225,236,225,242,225,226,233,99,128,254,238,232,225,237,250,225,
+225,226,239,246,101,2,205,154,205,163,225,242,225,226,233,99,
+128,6,36,230,233,238,225,236,225,242,225,226,233,99,128,254,
+134,226,243,241,245,225,242,101,128,51,221,227,233,242,99,2,
+205,196,205,201,236,101,128,36,230,245,237,230,236,229,120,128,
+1,117,100,2,205,216,205,226,233,229,242,229,243,233,115,128,
+30,133,239,116,2,205,233,205,242,225,227,227,229,238,116,128,
+30,135,226,229,236,239,119,128,30,137,101,4,206,4,206,15,
+206,27,206,51,232,233,242,225,231,225,238,97,128,48,145,233,
+229,242,243,244,242,225,243,115,128,33,24,107,2,206,33,206,
+43,225,244,225,235,225,238,97,128,48,241,239,242,229,225,110,
+128,49,94,239,235,239,242,229,225,110,128,49,93,231,242,225,
+246,101,128,30,129,232,233,244,101,8,206,90,206,99,206,183,
+207,17,207,101,207,146,207,198,207,254,226,245,236,236,229,116,
+128,37,230,99,2,206,105,206,125,233,242,227,236,101,129,37,
+203,206,115,233,238,246,229,242,243,101,128,37,217,239,242,238,
+229,242,226,242,225,227,235,229,116,2,206,142,206,162,236,229,
+230,116,129,48,14,206,151,246,229,242,244,233,227,225,108,128,
+254,67,242,233,231,232,116,129,48,15,206,172,246,229,242,244,
+233,227,225,108,128,254,68,100,2,206,189,206,230,233,225,237,
+239,238,100,129,37,199,206,200,227,239,238,244,225,233,238,233,
+238,231,226,236,225,227,235,243,237,225,236,236,228,233,225,237,
+239,238,100,128,37,200,239,247,238,240,239,233,238,244,233,238,
+103,2,206,246,207,6,243,237,225,236,236,244,242,233,225,238,
+231,236,101,128,37,191,244,242,233,225,238,231,236,101,128,37,
+189,236,101,2,207,24,207,66,230,244,240,239,233,238,244,233,
+238,103,2,207,39,207,55,243,237,225,236,236,244,242,233,225,
+238,231,236,101,128,37,195,244,242,233,225,238,231,236,101,128,
+37,193,238,244,233,227,245,236,225,242,226,242,225,227,235,229,
+116,2,207,86,207,93,236,229,230,116,128,48,22,242,233,231,
+232,116,128,48,23,242,233,231,232,244,240,239,233,238,244,233,
+238,103,2,207,119,207,135,243,237,225,236,236,244,242,233,225,
+238,231,236,101,128,37,185,244,242,233,225,238,231,236,101,128,
+37,183,115,3,207,154,207,184,207,192,109,2,207,160,207,172,
+225,236,236,243,241,245,225,242,101,128,37,171,233,236,233,238,
+231,230,225,227,101,128,38,58,241,245,225,242,101,128,37,161,
+244,225,114,128,38,6,116,2,207,204,207,215,229,236,229,240,
+232,239,238,101,128,38,15,239,242,244,239,233,243,229,243,232,
+229,236,236,226,242,225,227,235,229,116,2,207,239,207,246,236,
+229,230,116,128,48,24,242,233,231,232,116,128,48,25,245,240,
+240,239,233,238,244,233,238,103,2,208,13,208,29,243,237,225,
+236,236,244,242,233,225,238,231,236,101,128,37,181,244,242,233,
+225,238,231,236,101,128,37,179,105,2,208,46,208,57,232,233,
+242,225,231,225,238,97,128,48,144,107,2,208,63,208,73,225,
+244,225,235,225,238,97,128,48,240,239,242,229,225,110,128,49,
+95,237,239,238,239,243,240,225,227,101,128,255,87,111,4,208,
+103,208,114,208,139,208,157,232,233,242,225,231,225,238,97,128,
+48,146,235,225,244,225,235,225,238,97,129,48,242,208,127,232,
+225,236,230,247,233,228,244,104,128,255,102,110,129,32,169,208,
+145,237,239,238,239,243,240,225,227,101,128,255,230,247,225,229,
+238,244,232,225,105,128,14,39,240,225,242,229,110,128,36,178,
+242,233,238,103,128,30,152,243,245,240,229,242,233,239,114,128,
+2,183,244,245,242,238,229,100,128,2,141,249,238,110,128,1,
+191,120,137,0,120,208,231,208,242,208,253,209,6,209,33,209,
+46,209,50,209,62,209,70,225,226,239,246,229,227,237,98,128,
+3,61,226,239,240,239,237,239,230,111,128,49,18,227,233,242,
+227,236,101,128,36,231,100,2,209,12,209,22,233,229,242,229,
+243,233,115,128,30,141,239,244,225,227,227,229,238,116,128,30,
+139,229,232,225,242,237,229,238,233,225,110,128,5,109,105,128,
+3,190,237,239,238,239,243,240,225,227,101,128,255,88,240,225,
+242,229,110,128,36,179,243,245,240,229,242,233,239,114,128,2,
+227,121,143,0,121,209,115,210,74,210,97,210,137,212,103,212,
+111,212,128,212,192,212,204,213,201,213,241,213,253,214,8,214,
+29,215,2,97,11,209,139,209,151,209,161,209,168,209,175,209,
+185,209,210,209,221,210,3,210,16,210,62,225,228,239,243,241,
+245,225,242,101,128,51,78,226,229,238,231,225,236,105,128,9,
+175,227,245,244,101,128,0,253,228,229,246,97,128,9,47,229,
+235,239,242,229,225,110,128,49,82,231,117,2,209,192,209,201,
+234,225,242,225,244,105,128,10,175,242,237,245,235,232,105,128,
+10,47,232,233,242,225,231,225,238,97,128,48,132,107,2,209,
+227,209,251,225,244,225,235,225,238,97,129,48,228,209,239,232,
+225,236,230,247,233,228,244,104,128,255,148,239,242,229,225,110,
+128,49,81,237,225,235,235,225,238,244,232,225,105,128,14,78,
+243,237,225,236,108,2,210,26,210,37,232,233,242,225,231,225,
+238,97,128,48,131,235,225,244,225,235,225,238,97,129,48,227,
+210,50,232,225,236,230,247,233,228,244,104,128,255,108,244,227,
+249,242,233,236,236,233,99,128,4,99,227,233,242,99,2,210,
+83,210,88,236,101,128,36,232,245,237,230,236,229,120,128,1,
+119,100,2,210,103,210,113,233,229,242,229,243,233,115,128,0,
+255,239,116,2,210,120,210,129,225,227,227,229,238,116,128,30,
+143,226,229,236,239,119,128,30,245,101,7,210,153,211,161,211,
+170,211,188,211,220,212,40,212,91,104,8,210,171,210,180,210,
+214,210,228,211,45,211,61,211,120,211,138,225,242,225,226,233,
+99,128,6,74,226,225,242,242,229,101,2,210,191,210,200,225,
+242,225,226,233,99,128,6,210,230,233,238,225,236,225,242,225,
+226,233,99,128,251,175,230,233,238,225,236,225,242,225,226,233,
+99,128,254,242,232,225,237,250,225,225,226,239,246,101,4,210,
+247,211,0,211,14,211,30,225,242,225,226,233,99,128,6,38,
+230,233,238,225,236,225,242,225,226,233,99,128,254,138,233,238,
+233,244,233,225,236,225,242,225,226,233,99,128,254,139,237,229,
+228,233,225,236,225,242,225,226,233,99,128,254,140,233,238,233,
+244,233,225,236,225,242,225,226,233,99,128,254,243,237,101,2,
+211,68,211,81,228,233,225,236,225,242,225,226,233,99,128,254,
+244,229,237,105,2,211,89,211,104,238,233,244,233,225,236,225,
+242,225,226,233,99,128,252,221,243,239,236,225,244,229,228,225,
+242,225,226,233,99,128,252,88,238,239,239,238,230,233,238,225,
+236,225,242,225,226,233,99,128,252,148,244,232,242,229,229,228,
+239,244,243,226,229,236,239,247,225,242,225,226,233,99,128,6,
+209,235,239,242,229,225,110,128,49,86,110,129,0,165,211,176,
+237,239,238,239,243,240,225,227,101,128,255,229,111,2,211,194,
+211,203,235,239,242,229,225,110,128,49,85,242,233,238,232,233,
+229,245,232,235,239,242,229,225,110,128,49,134,114,3,211,228,
+212,8,212,20,225,232,226,229,238,249,239,237,111,2,211,242,
+211,251,232,229,226,242,229,119,128,5,170,236,229,230,244,232,
+229,226,242,229,119,128,5,170,233,227,249,242,233,236,236,233,
+99,128,4,75,245,228,233,229,242,229,243,233,243,227,249,242,
+233,236,236,233,99,128,4,249,243,233,229,245,238,103,3,212,
+53,212,62,212,78,235,239,242,229,225,110,128,49,129,240,225,
+238,243,233,239,243,235,239,242,229,225,110,128,49,131,243,233,
+239,243,235,239,242,229,225,110,128,49,130,244,233,246,232,229,
+226,242,229,119,128,5,154,231,242,225,246,101,128,30,243,232,
+239,239,107,129,1,180,212,120,225,226,239,246,101,128,30,247,
+105,5,212,140,212,151,212,162,212,171,212,179,225,242,237,229,
+238,233,225,110,128,5,117,227,249,242,233,236,236,233,99,128,
+4,87,235,239,242,229,225,110,128,49,98,238,249,225,238,103,
+128,38,47,247,238,225,242,237,229,238,233,225,110,128,5,130,
+237,239,238,239,243,240,225,227,101,128,255,89,111,7,212,220,
+213,34,213,45,213,55,213,93,213,139,213,148,100,131,5,217,
+212,230,212,250,213,3,228,225,231,229,243,104,129,251,57,212,
+241,232,229,226,242,229,119,128,251,57,232,229,226,242,229,119,
+128,5,217,249,239,100,2,213,11,213,20,232,229,226,242,229,
+119,128,5,242,240,225,244,225,232,232,229,226,242,229,119,128,
+251,31,232,233,242,225,231,225,238,97,128,48,136,233,235,239,
+242,229,225,110,128,49,137,107,2,213,61,213,85,225,244,225,
+235,225,238,97,129,48,232,213,73,232,225,236,230,247,233,228,
+244,104,128,255,150,239,242,229,225,110,128,49,91,243,237,225,
+236,108,2,213,103,213,114,232,233,242,225,231,225,238,97,128,
+48,135,235,225,244,225,235,225,238,97,129,48,231,213,127,232,
+225,236,230,247,233,228,244,104,128,255,110,244,231,242,229,229,
+107,128,3,243,121,2,213,154,213,191,97,2,213,160,213,170,
+229,235,239,242,229,225,110,128,49,136,107,2,213,176,213,184,
+239,242,229,225,110,128,49,135,244,232,225,105,128,14,34,233,
+238,231,244,232,225,105,128,14,13,112,2,213,207,213,214,225,
+242,229,110,128,36,180,239,231,229,231,242,225,237,237,229,238,
+105,129,3,122,213,230,231,242,229,229,235,227,237,98,128,3,
+69,114,129,1,166,213,247,233,238,103,128,30,153,243,245,240,
+229,242,233,239,114,128,2,184,116,2,214,14,214,21,233,236,
+228,101,128,30,249,245,242,238,229,100,128,2,142,117,5,214,
+41,214,52,214,62,214,100,214,232,232,233,242,225,231,225,238,
+97,128,48,134,233,235,239,242,229,225,110,128,49,140,107,2,
+214,68,214,92,225,244,225,235,225,238,97,129,48,230,214,80,
+232,225,236,230,247,233,228,244,104,128,255,149,239,242,229,225,
+110,128,49,96,115,3,214,108,214,146,214,187,226,233,103,2,
+214,116,214,127,227,249,242,233,236,236,233,99,128,4,107,233,
+239,244,233,230,233,229,228,227,249,242,233,236,236,233,99,128,
+4,109,236,233,244,244,236,101,2,214,157,214,168,227,249,242,
+233,236,236,233,99,128,4,103,233,239,244,233,230,233,229,228,
+227,249,242,233,236,236,233,99,128,4,105,237,225,236,108,2,
+214,196,214,207,232,233,242,225,231,225,238,97,128,48,133,235,
+225,244,225,235,225,238,97,129,48,229,214,220,232,225,236,230,
+247,233,228,244,104,128,255,109,249,101,2,214,239,214,248,235,
+239,242,229,225,110,128,49,139,239,235,239,242,229,225,110,128,
+49,138,249,97,2,215,9,215,19,226,229,238,231,225,236,105,
+128,9,223,228,229,246,97,128,9,95,122,142,0,122,215,58,
+216,66,216,77,216,120,216,147,217,182,218,34,218,76,218,88,
+218,100,218,128,218,136,218,152,218,161,97,10,215,80,215,91,
+215,98,215,105,215,116,215,194,215,224,215,235,216,15,216,27,
+225,242,237,229,238,233,225,110,128,5,102,227,245,244,101,128,
+1,122,228,229,246,97,128,9,91,231,245,242,237,245,235,232,
+105,128,10,91,104,4,215,126,215,135,215,149,215,179,225,242,
+225,226,233,99,128,6,56,230,233,238,225,236,225,242,225,226,
+233,99,128,254,198,105,2,215,155,215,170,238,233,244,233,225,
+236,225,242,225,226,233,99,128,254,199,242,225,231,225,238,97,
+128,48,86,237,229,228,233,225,236,225,242,225,226,233,99,128,
+254,200,233,110,2,215,201,215,210,225,242,225,226,233,99,128,
+6,50,230,233,238,225,236,225,242,225,226,233,99,128,254,176,
+235,225,244,225,235,225,238,97,128,48,182,241,229,102,2,215,
+243,216,1,231,225,228,239,236,232,229,226,242,229,119,128,5,
+149,241,225,244,225,238,232,229,226,242,229,119,128,5,148,242,
+241,225,232,229,226,242,229,119,128,5,152,249,233,110,130,5,
+214,216,37,216,57,228,225,231,229,243,104,129,251,54,216,48,
+232,229,226,242,229,119,128,251,54,232,229,226,242,229,119,128,
+5,214,226,239,240,239,237,239,230,111,128,49,23,99,3,216,
+85,216,92,216,114,225,242,239,110,128,1,126,233,242,99,2,
+216,100,216,105,236,101,128,36,233,245,237,230,236,229,120,128,
+30,145,245,242,108,128,2,145,228,239,116,130,1,124,216,130,
+216,139,225,227,227,229,238,116,128,1,124,226,229,236,239,119,
+128,30,147,101,6,216,161,216,172,216,215,216,226,216,237,217,
+177,227,249,242,233,236,236,233,99,128,4,55,100,2,216,178,
+216,197,229,243,227,229,238,228,229,242,227,249,242,233,236,236,
+233,99,128,4,153,233,229,242,229,243,233,243,227,249,242,233,
+236,236,233,99,128,4,223,232,233,242,225,231,225,238,97,128,
+48,92,235,225,244,225,235,225,238,97,128,48,188,242,111,140,
+0,48,217,10,217,19,217,29,217,36,217,61,217,74,217,85,
+217,97,217,108,217,118,217,129,217,136,225,242,225,226,233,99,
+128,6,96,226,229,238,231,225,236,105,128,9,230,228,229,246,
+97,128,9,102,231,117,2,217,43,217,52,234,225,242,225,244,
+105,128,10,230,242,237,245,235,232,105,128,10,102,232,225,227,
+235,225,242,225,226,233,99,128,6,96,233,238,230,229,242,233,
+239,114,128,32,128,237,239,238,239,243,240,225,227,101,128,255,
+16,239,236,228,243,244,249,236,101,128,247,48,240,229,242,243,
+233,225,110,128,6,240,243,245,240,229,242,233,239,114,128,32,
+112,244,232,225,105,128,14,80,247,233,228,244,104,3,217,148,
+217,157,217,169,234,239,233,238,229,114,128,254,255,238,239,238,
+234,239,233,238,229,114,128,32,12,243,240,225,227,101,128,32,
+11,244,97,128,3,182,104,2,217,188,217,199,226,239,240,239,
+237,239,230,111,128,49,19,101,4,217,209,217,220,217,236,217,
+247,225,242,237,229,238,233,225,110,128,5,106,226,242,229,246,
+229,227,249,242,233,236,236,233,99,128,4,194,227,249,242,233,
+236,236,233,99,128,4,54,100,2,217,253,218,16,229,243,227,
+229,238,228,229,242,227,249,242,233,236,236,233,99,128,4,151,
+233,229,242,229,243,233,243,227,249,242,233,236,236,233,99,128,
+4,221,105,3,218,42,218,53,218,64,232,233,242,225,231,225,
+238,97,128,48,88,235,225,244,225,235,225,238,97,128,48,184,
+238,239,242,232,229,226,242,229,119,128,5,174,236,233,238,229,
+226,229,236,239,119,128,30,149,237,239,238,239,243,240,225,227,
+101,128,255,90,111,2,218,106,218,117,232,233,242,225,231,225,
+238,97,128,48,94,235,225,244,225,235,225,238,97,128,48,190,
+240,225,242,229,110,128,36,181,242,229,244,242,239,230,236,229,
+248,232,239,239,107,128,2,144,243,244,242,239,235,101,128,1,
+182,117,2,218,167,218,178,232,233,242,225,231,225,238,97,128,
+48,90,235,225,244,225,235,225,238,97,128,48,186];
+
+function ft_get_adobe_glyph_index(_name,limit)
+{
+    var name = 0;
+    var c = 0;
+    var count, min, max;
+    var p = 0;
+
+    if (_name == null || _name == "" || 0 >= limit)
+        return 0;
+
+    c = _name.charCodeAt(name);
+    name++;
+    count = ft_adobe_glyph_list[1];
+    p += 2;
+
+    min = 0;
+    max = count;
+
+    var go_to_found = 0;
+    var go_to_next = 0;
+    while (min < max)
+    {
+        var mid = (min + max) >>> 1;
+        var q = p + mid * 2;
+        q = ((ft_adobe_glyph_list[q] << 8) | ft_adobe_glyph_list[q+1]);
+        var c2 = ft_adobe_glyph_list[q] & 127;
+        if (c2 == c)
+        {
+            p = q;
+            go_to_found = 1;
+            break;
+        }
+        if ( c2 < c )
+            min = mid + 1;
+        else
+            max = mid;
+    }
+    if (0 == go_to_found)
+        return 0;
+
+    for (;;)
+    {
+        if (name >= limit)
+        {
+            if ((ft_adobe_glyph_list[p] & 128) == 0 && (ft_adobe_glyph_list[p+1] & 128) != 0)
+                return ((ft_adobe_glyph_list[p+2] << 8) | ft_adobe_glyph_list[p+3]);
+            return 0;
+        }
+        c = _name.charCodeAt(name++);
+        if (ft_adobe_glyph_list[p] & 128)
+        {
+            p++;
+            if (c != (ft_adobe_glyph_list[p] & 127))
+                return 0;
+            continue;
+        }
+
+        p++;
+        count = ft_adobe_glyph_list[p] & 127;
+        if (ft_adobe_glyph_list[p] & 128)
+            p += 2;
+
+        p++;
+        for (; count > 0; count--, p += 2)
+        {
+            var offset = (ft_adobe_glyph_list[p] << 8) | ft_adobe_glyph_list[p+1];
+            var q = offset;
+            if (c == (ft_adobe_glyph_list[q] & 127))
+            {
+                p = q;
+                go_to_next = 1;
+                break;
+            }
+        }
+        if (0 == go_to_next)
+            return 0;
+    }
+    return 0;
+}
+
+function PS_UniMap()
+{
+    this.unicode = 0;
+    this.glyph_index = 0;
+}
+function PS_UnicodesRec()
+{
+    this.cmap = null;
+    this.num_maps = 0;
+    this.maps = null;
+}
+
+function ps_unicode_value(glyph_name)
+{
+    var len = glyph_name.length;
+    if (glyph_name.charCodeAt(0) == FT_Common.SYMBOL_CONST_u && glyph_name.charCodeAt(1) == FT_Common.SYMBOL_CONST_n && glyph_name.charCodeAt(2) == FT_Common.SYMBOL_CONST_i)
+    {
+        var count;
+        var value = 0;
+        var p = 3;
+
+        for ( count = 4; count > 0; count--, p++ )
+        {
+            var c = 0;
+            if (p < len)
+                c = glyph_name.charCodeAt(p);
+            if (c<0)
+                c+=256;
+            var d = c - FT_Common.SYMBOL_CONST_0;
+            if (d < 0)
+                d += 256;
+            if (d >= 10)
+            {
+                d = c - FT_Common.SYMBOL_CONST_A;
+                if (d < 0)
+                    d += 256;
+                if (d >= 6)
+                    d = 16;
+                else
+                    d += 10;
+            }
+
+            if (d >= 16)
+                break;
+
+            value = (value << 4) + d;
+        }
+
+        if (count == 0)
+        {
+            if (p >= len)
+                return value;
+            if (glyph_name.charCodeAt(p) == FT_Common.SYMBOL_CONST_POINT)
+                return (value | 0x7FFFFFFF);
+        }
+    }
+
+    if (glyph_name.charCodeAt(0) == FT_Common.SYMBOL_CONST_u)
+    {
+        var count;
+        var value = 0;
+        var p     = 1;
+
+        for (count = 6; count > 0; count--, p++)
+        {
+            var c = 0;
+            if (p < len)
+                c = glyph_name.charCodeAt(p);
+            if (c<0)
+                c+=256;
+            var d = c - FT_Common.SYMBOL_CONST_0;
+            if (d < 0)
+                d += 256;
+            if (d >= 10)
+            {
+                d = c - FT_Common.SYMBOL_CONST_A;
+                if (d < 0)
+                    d += 256;
+                if (d >= 6)
+                    d = 16;
+                else
+                    d += 10;
+            }
+
+            if (d >= 16)
+                break;
+
+            value = (value << 4) + d;
+        }
+
+        if (count <= 2)
+        {
+            if (p >= len)
+                return value;
+            if (glyph_name.charCodeAt(p) == FT_Common.SYMBOL_CONST_POINT)
+                return (value | 0x7FFFFFFF);
+      }
+    }
+
+    var p = 0;
+    var dot = 0;
+
+    for (; p<len; p++)
+    {
+        if (glyph_name.charCodeAt(p) == FT_Common.SYMBOL_CONST_POINT && p > 0)
+        {
+            dot = p;
+            break;
+        }
+    }
+
+    if (dot == 0)
+        return ft_get_adobe_glyph_index(glyph_name, p);
+    else
+        return ft_get_adobe_glyph_index(glyph_name, dot | 0x7FFFFFFF);
+}
+
+function compare_uni_maps(map1, map2)
+{
+    var unicode1 = map1.unicode & 0x7FFFFFFF;
+    var unicode2 = map2.unicode & 0x7FFFFFFF;
+    if (unicode1 == unicode2)
+    {
+        if (map1.unicode > map2.unicode)
+            return 1;
+        else if (map1.unicode < map2.unicode)
+            return -1;
+        else
+            return 0;
+    }
+    else
+    {
+        if (unicode1 > unicode2)
+            return 1;
+        else if (unicode1 < unicode2)
+            return -1;
+        else
+            return 0;
+    }
+}
+
+function ft_qsort(mass, count, compare)
+{
+    var t;
+    for (var i=0;i<count;i++)
+    {
+        for (var j=i+1;j<count;j++)
+        {
+            if (compare(mass[i],mass[j]) == 1)
+            {
+                t=mass[i];
+                mass[i]=mass[j];
+                mass[j]=t;
+            }
+        }
+    }
+}
+
+var ft_extra_glyph_unicodes=[0x0394,0x03A9,0x2215,0x00AD,0x02C9,0x03BC,0x2219,0x00A0,0x021A,0x021B];
+var ft_extra_glyph_names=["Delta","Omega","fraction","hyphen","macron","mu","periodcentered","space","Tcommaaccent","tcommaaccent"];
+
+function ps_check_extra_glyph_name(gname,glyph,extra_glyphs,states)
+{
+    for (var n = 0; n < 10; n++)
+    {
+        if (ft_extra_glyph_names[n] == gname)
+        {
+            if ( states[n] == 0 )
+            {
+                states[n]     = 1;
+                extra_glyphs[n] = glyph;
+            }
+
+            return;
+        }
+    }
+}
+function ps_check_extra_glyph_unicode(uni_char,states)
+{
+    for (var n = 0; n < 10; n++)
+    {
+        if (uni_char == ft_extra_glyph_unicodes[n])
+        {
+            states[n] = 2;
+            return;
+        }
+    }
+}
+
+function ps_unicodes_init(memory,table,num_glyphs,get_glyph_name,free_glyph_name,glyph_data)
+{
+    var error = 0;
+
+    var extra_glyph_list_states = [0,0,0,0,0,0,0,0,0,0];
+    var extra_glyphs = [0,0,0,0,0,0,0,0,0,0];
+
+    table.num_maps = 0;
+    table.maps = new Array(num_glyphs + 10);
+    for (var i = 0; i < (num_glyphs + 10); i++)
+        table.maps[i] = new PS_UniMap();
+
+    var n;
+    var map = 0;
+    var maps = table.maps;
+    var uni_char;
+
+    for ( n = 0; n < num_glyphs; n++)
+    {
+        var gname = get_glyph_name(glyph_data, n);
+        if (gname != null)
+        {
+            ps_check_extra_glyph_name(gname, n, extra_glyphs, extra_glyph_list_states);
+
+            if (n == 86)
+            {
+                var __nnn = 0;
+                __nnn += 1;
+                __nnn += 1;
+                __nnn += 1;
+            }
+
+            uni_char = ps_unicode_value(gname);
+
+            if ((uni_char & 0x7FFFFFFF) != 0)
+            {
+                ps_check_extra_glyph_unicode(uni_char, extra_glyph_list_states);
+                maps[map].unicode = uni_char;
+                maps[map].glyph_index = n;
+                map++;
+            }
+
+            if (free_glyph_name)
+                free_glyph_name(glyph_data, gname);
+        }
+    }
+
+    for (n = 0; n < 10; n++)
+    {
+        if (extra_glyph_list_states[n] == 1)
+        {
+            maps[map].unicode = ft_extra_glyph_unicodes[n];
+            maps[map].glyph_index = extra_glyphs[n];
+            map++;
+        }
+    }
+
+    var count = map;
+    if ( count == 0 )
+    {
+        table.maps = null;
+        if (!error)
+            error = 163;
+    }
+    else
+    {
+        if (count < num_glyphs / 2)
+        {
+            table.maps[count-1] = new PS_UniMap();
+            error = 0;
+        }
+
+        var del_count = num_glyphs + 10 - count;
+        if (del_count > 10)
+            maps.splice(count, del_count);
+        maps.sort(compare_uni_maps);
+        //ft_qsort(table.maps, count, compare_uni_maps);
+    }
+
+    table.num_maps = count;
+
+    return error;
+}
+
+function ps_unicodes_char_index(table, unicode)
+{
+    var mid, result = -1;
+
+    var maps = table.maps;
+    var min = 0;
+    var max = table.num_maps - 1;
+
+    while (min <= max)
+    {
+        mid = min + ((max - min) >>> 1);
+
+        if (maps[mid].unicode == unicode)
+        {
+            result = mid;
+            break;
+        }
+
+        var base_glyph = maps[mid].unicode & 0x7FFFFFFF;
+        if (base_glyph == unicode)
+            result = mid;
+
+        if (min == max)
+            break;
+
+        if (base_glyph < unicode)
+            min = mid + 1;
+        else
+            max = mid - 1;
+    }
+
+    if (result != -1)
+        return maps[result].glyph_index;
+    return 0;
+}
+
+function ps_unicodes_char_next(table, unicode)
+{
+    var result = 0;
+    var char_code = unicode + 1;
+
+    var min = 0;
+    var max = table.num_maps;
+    var mid;
+    var map;
+    var base_glyph;
+
+    while ( min < max )
+    {
+        mid = min + ((max - min) >>> 1);
+        map = table.maps[mid];
+
+        if (map.unicode == char_code)
+        {
+            result = map.glyph_index;
+            return {unicode:char_code, result:result};
+        }
+
+        base_glyph = (map.unicode & 0x7FFFFFFF);
+
+        if (base_glyph == char_code)
+            result = map.glyph_index;
+
+        if (base_glyph < char_code)
+            min = mid + 1;
+        else
+            max = mid;
+    }
+
+    if (result != 0)
+        return {unicode:char_code, result:result};
+
+    char_code = 0;
+
+    if (min < table.num_maps)
+    {
+        map       = table.maps[min];
+        result    = map.glyph_index;
+        char_code = (map.unicode & 0x7FFFFFFF);
+    }
+
+    return {unicode:char_code, result:result};
+}
+
+function ps_get_macintosh_name(name_index)
+{
+    if (name_index >= 258)
+        name_index = 0;
+
+    return ft_standard_glyph_names[ft_mac_names[name_index]];
+}
+
+function ps_get_standard_strings(sid)
+{
+    if (sid >= 391)
+        return 0;
+
+    return ft_standard_glyph_names[ft_sid_names[sid]];
+}
+
+function _pscmaps_interface()
+{
+    this.unicode_value = ps_unicode_value;
+    this.unicodes_init = ps_unicodes_init;
+    this.unicodes_char_index = ps_unicodes_char_index;
+    this.unicodes_char_next = ps_unicodes_char_next;
+
+    this.macintosh_name = ps_get_macintosh_name;
+    this.adobe_std_strings = ps_get_standard_strings;
+    this.adobe_std_encoding = t1_standard_encoding;
+    this.adobe_expert_encoding = t1_expert_encoding;
+}
+
+var pscmaps_interface = new _pscmaps_interface();
+function create_psnames_module(library)
+{
+    var psnames_mod = new FT_Module();
+    psnames_mod.clazz = new FT_Module_Class();
+
+    var clazz = psnames_mod.clazz;
+    clazz.flags = 0;
+    clazz.name = "psnames";
+    clazz.version = 0x10000;
+    clazz.requires = 0x20000;
+
+    clazz.module_interface = pscmaps_interface;
+    clazz.init = null;
+    clazz.done = null;
+
+    clazz.get_interface = function(module, name)
+    {
+        if (name == "postscript-cmaps")
+            return pscmaps_interface;
+        return null;
+    }
+
+    psnames_mod.library = library;
+    psnames_mod.memory = library.Memory;
+    psnames_mod.generic = null;
+
+    return psnames_mod;
+}
\ No newline at end of file
diff --git a/Common/FontsFreeType/Private/FreeType/modules/render.js b/Common/FontsFreeType/Private/FreeType/modules/render.js
new file mode 100644
index 0000000000000000000000000000000000000000..5edede2a5ea4eb15890544891218e2ce9fdc1039
--- /dev/null
+++ b/Common/FontsFreeType/Private/FreeType/modules/render.js
@@ -0,0 +1,2426 @@
+function CRasterMemory()
+{
+    this.width = 0;
+    this.height = 0;
+    this.pitch = 0;
+
+    this.m_oBuffer = null;
+    this.CheckSize = function(w, h)
+    {
+        if (this.width < (w + 1) || this.height < (h + 1))
+        {
+            this.width = Math.max(this.width, w + 1);
+            this.pitch = 4 * this.width;
+            this.height = Math.max(this.height, h + 1);
+
+            this.m_oBuffer = null;
+            this.m_oBuffer = g_memory.ctx.createImageData(this.width, this.height);
+        }
+    }
+}
+var raster_memory = new CRasterMemory();
+
+// outline ---
+function _FT_Outline_Funcs_Gray()
+{
+    this.move_to = function(to, worker)
+    {
+        /* record current cell, if any */
+        var err = gray_record_cell(worker);
+        if (err == FT_Common.ErrorLongJump)
+            return FT_Common.ErrorLongJump;
+
+        /* start to a new position */
+        var x = to.x << 2;
+        var y = to.y << 2;
+
+        err = gray_start_cell(worker, x >> 8, y >> 8);
+
+        worker.x = x;
+        worker.y = y;
+        return err;
+    }
+
+    this.line_to = function(to, worker)
+    {
+        return gray_render_line(worker, to.x << 2, to.y << 2);
+    }
+
+    this.conic_to = function(control, to, worker)
+    {
+        return gray_render_conic(worker, control, to);
+    }
+
+    this.cubic_to = function(control1, control2, to, worker)
+    {
+        return gray_render_cubic(worker, control1, control2, to);
+    }
+
+    this.shift = 0;
+    this.delta = 0;
+}
+var ft_outline_funcs_gray = new _FT_Outline_Funcs_Gray();
+
+function FT_Outline_Decompose(outline, func_interface, user)
+{
+    if (!outline || !func_interface)
+        return FT_Common.FT_Err_Invalid_Argument;
+
+    var v_last      = new FT_Vector();
+    var v_control   = new FT_Vector();
+    var v_start     = new FT_Vector();
+
+    var point;
+    var limit;
+
+    var tags = 0;
+    var first = 0;
+    var tag = 0;
+
+    var shift = func_interface.shift;
+    var delta = func_interface.delta;
+
+    var error = 0;
+
+    var count = outline.n_contours;
+    var _c = outline.contours;
+    var _p = outline.points;
+    var _t = outline.tags;
+    for (var n = 0; n < count; n++)
+    {
+        var last = _c[n];
+        if (last < 0)
+            return FT_Common.FT_Err_Invalid_Outline;
+        limit = last;
+
+        v_start.x = (_p[first].x << shift) - delta;
+        v_start.y = (_p[first].y << shift) - delta;
+
+        v_last.x = (_p[last].x << shift) - delta;
+        v_last.y = (_p[last].y << shift) - delta;
+
+        v_control.x = v_start.x;
+        v_control.y = v_start.y;
+
+        point = first;
+        tags  = first;
+        tag   = _t[tags] & 3;
+
+        /* A contour cannot start with a cubic control point! */
+        if (tag == FT_Common.FT_CURVE_TAG_CUBIC)
+            return FT_Common.FT_Err_Invalid_Outline;
+
+        /* check first point to determine origin */
+        if (tag == FT_Common.FT_CURVE_TAG_CONIC)
+        {
+            /* first point is conic control.  Yes, this happens. */
+            if ((_t[last] & 3) == FT_Common.FT_CURVE_TAG_ON)
+            {
+                /* start at last point if it is on the curve */
+                v_start.x = v_last.x;
+                v_start.y = v_last.y;
+                limit--;
+            }
+            else
+            {
+                /* if both first and last points are conic,         */
+                /* start at their middle and record its position    */
+                /* for closure                                      */
+                v_start.x = parseInt((v_start.x + v_last.x) / 2);
+                v_start.y = parseInt((v_start.y + v_last.y) / 2);
+
+                v_last.x = v_start.x;
+                v_last.y = v_start.y;
+            }
+            point--;
+            tags--;
+        }
+
+        error = func_interface.move_to(v_start, user);
+        if (error != 0)
+            return error;
+
+        var isClose = 0;
+        while (point < limit)
+        {
+            point++;
+            tags++;
+
+            tag = _t[tags] & 3;
+            switch ( tag )
+            {
+                case FT_Common.FT_CURVE_TAG_ON:  /* emit a single line_to */
+                {
+                    var vec = new FT_Vector();
+
+                    vec.x = (_p[point].x << shift) - delta;
+                    vec.y = (_p[point].y << shift) - delta;
+
+                    error = func_interface.line_to(vec, user);
+                    if (0 != error)
+                        return error;
+                    continue;
+                }
+
+                case FT_Common.FT_CURVE_TAG_CONIC:  /* consume conic arcs */
+                    v_control.x = (_p[point].x << shift) - delta;
+                    v_control.y = (_p[point].y << shift) - delta;
+
+                    var isCont = 0;
+                    while (true)
+                    {
+                        if (point < limit)
+                        {
+                            var vec = new FT_Vector();
+                            var v_middle = new FT_Vector();
+
+                            point++;
+                            tags++;
+                            tag = _t[tags] & 3;
+
+                            vec.x = (_p[point].x << shift) - delta;
+                            vec.y = (_p[point].y << shift) - delta;
+
+                            if (tag == FT_Common.FT_CURVE_TAG_ON)
+                            {
+                                error = func_interface.conic_to(v_control, vec, user);
+                                if (0 != error)
+                                    return error;
+                                isCont = 1;
+                                break;
+                            }
+
+                            if (tag != FT_Common.FT_CURVE_TAG_CONIC)
+                                return FT_Common.FT_Err_Invalid_Outline;
+
+                            v_middle.x = parseInt((v_control.x + vec.x) / 2);
+                            v_middle.y = parseInt((v_control.y + vec.y) / 2);
+
+                            error = func_interface.conic_to(v_control, v_middle, user);
+                            if (0 != error)
+                                return error;
+
+                            v_control.x = vec.x;
+                            v_control.y = vec.y;
+
+                            continue;
+                        }
+                        break;
+                    }
+                    if (1 == isCont/* && (point < limit)*/)
+                        continue;
+
+                    error = func_interface.conic_to(v_control, v_start, user);
+                    isClose = 1;
+                    break;
+
+                default:  /* FT_CURVE_TAG_CUBIC */
+                {
+                    var vec1 = new FT_Vector();
+                    var vec2 = new FT_Vector();
+
+                    if ((point + 1 > limit) || (_t[tags+1]&3) != FT_Common.FT_CURVE_TAG_CUBIC)
+                        return FT_Common.FT_Err_Invalid_Outline;
+
+                    point += 2;
+                    tags  += 2;
+
+                    vec1.x = (_p[point-2].x << shift) - delta;
+                    vec1.y = (_p[point-2].y << shift) - delta;
+
+                    vec2.x = (_p[point-1].x << shift) - delta;
+                    vec2.y = (_p[point-1].y << shift) - delta;
+
+                    if (point <= limit)
+                    {
+                        var vec = new FT_Vector();
+                        vec.x = (_p[point].x << shift) - delta;
+                        vec.y = (_p[point].y << shift) - delta;
+
+                        error = func_interface.cubic_to(vec1, vec2, vec, user);
+                        if (0 != error)
+                            return error;
+                        continue;
+                    }
+
+                    error = func_interface.cubic_to(vec1, vec2, v_start, user);
+                    isClose = 1;
+                    break;
+                }
+            }
+
+            if (isClose == 1)
+                break;
+        }
+
+        if (error != 0)
+            return error;
+
+        /* close the contour with a line segment */
+        if (0 == isClose)
+            error = func_interface.line_to(v_start, user);
+
+        if (error != 0)
+            return error;
+
+        isClose = 0;
+        first = last + 1;
+    }
+    return 0;
+}
+
+function FT_Outline_Get_Orientation(outline)
+{
+    if (outline == null || outline.n_points <= 0)
+        return FT_Common.FT_ORIENTATION_TRUETYPE;
+
+    /* We use the nonzero winding rule to find the orientation.       */
+    /* Since glyph outlines behave much more `regular' than arbitrary */
+    /* cubic or quadratic curves, this test deals with the polygon    */
+    /* only which is spanned up by the control points.                */
+    var points = outline.points;
+
+	var v_cur;
+    var first = 0;
+    var area = 0;
+    for (var c = 0; c < outline.n_contours; c++)
+    {
+        var last = outline.contours[c];
+        var v_prev = points[last];
+
+        for (var n = first; n <= last; n++)
+        {
+            v_cur = points[n];
+            area += (v_cur.y - v_prev.y) * (v_cur.x + v_prev.x);
+            v_prev = v_cur;
+        }
+
+        first = last + 1;
+    }
+
+    if (area > 0)
+        return FT_Common.FT_ORIENTATION_POSTSCRIPT;
+    else if ( area < 0 )
+        return FT_Common.FT_ORIENTATION_TRUETYPE;
+    return FT_Common.FT_ORIENTATION_NONE;
+}
+
+function FT_Outline_Get_Orientation_Cur(outline, base)
+{
+    if (outline == null || outline.n_points <= 0)
+        return FT_Common.FT_ORIENTATION_TRUETYPE;
+
+    /* We use the nonzero winding rule to find the orientation.       */
+    /* Since glyph outlines behave much more `regular' than arbitrary */
+    /* cubic or quadratic curves, this test deals with the polygon    */
+    /* only which is spanned up by the control points.                */
+    var points = base.points;
+    var contours = base.contours;
+    var _p_off = outline.points;
+    var _c_off = outline.contours;
+
+    var v_prev = new FT_Vector();
+    var v_cur = new FT_Vector();
+
+    var first = 0;
+    var area = 0;
+    for (var c = 0; c < outline.n_contours; c++)
+    {
+        var last = contours[_c_off + c];
+        v_prev.x = points[_p_off + last].x;
+        v_prev.y = points[_p_off + last].y;
+
+        for (var n = first; n <= last; n++)
+        {
+            v_cur.x = points[_p_off + n].x;
+            v_cur.y = points[_p_off + n].y;
+            area += (v_cur.y - v_prev.y) * (v_cur.x + v_prev.x);
+            v_prev.x = v_cur.x;
+            v_prev.y = v_cur.y;
+        }
+
+        first = last + 1;
+    }
+
+    if (area > 0)
+        return FT_Common.FT_ORIENTATION_POSTSCRIPT;
+    else if ( area < 0 )
+        return FT_Common.FT_ORIENTATION_TRUETYPE;
+    return FT_Common.FT_ORIENTATION_NONE;
+}
+
+function ft_trig_prenorm(vec)
+{
+    var x = vec.x;
+    var y = vec.y;
+
+    var z = ((x >= 0) ? x : - x) | ((y >= 0) ? y : -y);
+    var shift = 0;
+
+    /* determine msb bit index in `shift' */
+    if (z >= (1 << 16))
+    {
+        z >>= 16;
+        shift += 16;
+    }
+    if (z >= (1 << 8))
+    {
+        z >>= 8;
+        shift += 8;
+    }
+    if (z >= (1 << 4))
+    {
+        z >>= 4;
+        shift += 4;
+    }
+    if (z >= (1 << 2))
+    {
+        z >>= 2;
+        shift += 2;
+    }
+    if (z >= (1 << 1))
+    {
+        z >>= 1;
+        shift += 1;
+    }
+
+    if (shift <= 27)
+    {
+        shift  = 27 - shift;
+        vec.x = x << shift;
+        vec.y = y << shift;
+    }
+    else
+    {
+        shift -= 27;
+        vec.x = x >> shift;
+        vec.y = y >> shift;
+        shift = -shift;
+    }
+
+    return shift;
+}
+
+var ft_trig_arctan_table = [2949120, 1740967, 919879, 466945, 234379, 117304, 58666, 29335, 14668, 7334,
+    3667, 1833, 917, 458, 229, 115, 57, 29, 14, 7, 4, 2, 1];
+
+function ft_trig_pseudo_polarize(vec)
+{
+    var x = vec.x;
+    var y = vec.y;
+
+    /* Get the vector into the right half plane */
+    var theta = 0;
+    if (x < 0)
+    {
+        x = -x;
+        y = -y;
+        theta = 2 * FT_Common.FT_ANGLE_PI2;
+    }
+
+    if (y > 0)
+        theta = - theta;
+
+    var arctanptr = 0;
+    var xtemp = 0;
+    /* Pseudorotations, with right shifts */
+    i = 0;
+    do
+    {
+        if ( y > 0 )
+        {
+            xtemp  = x + (y >> i);
+            y      = y - (x >> i);
+            x      = xtemp;
+            theta += ft_trig_arctan_table[arctanptr++];
+        }
+        else
+        {
+            xtemp  = x - (y >> i);
+            y      = y + (x >> i);
+            x      = xtemp;
+            theta -= ft_trig_arctan_table[arctanptr++];
+        }
+    } while (++i < FT_Common.FT_TRIG_MAX_ITERS);
+
+    /* round theta */
+    if (theta >= 0)
+        theta = ((theta + 16) & ~31);
+    else
+        theta = -((-theta + 16) & ~31);
+
+    vec.x = x;
+    vec.y = theta;
+}
+
+function ft_trig_downscale(val)
+{
+    var s   = val;
+    val = (val >= 0) ? val : -val;
+
+    var v1 = FT_Common.IntToUInt(val >> 16);
+    var v2 = FT_Common.IntToUInt(val & 0xFFFF);
+
+    var k1 = 0x9B74;   /* constant */
+    var k2 = 0xEDA8;   /* constant */
+
+    var hi   = k1 * v1;
+    var lo1  = k1 * v2 + k2 * v1;       /* can't overflow */
+
+    var lo2  = ( k2 * v2 ) / 65536;
+    lo2 = lo2 >> 0;
+    var lo3  = ( lo1 >= lo2 ) ? lo1 : lo2;
+    lo1 += lo2;
+
+    lo1 = FT_Common.IntToUInt(lo1);
+
+    hi  += lo1 >> 16;
+    if (lo1 < lo3)
+        hi += 0x10000;
+
+    val  = hi;
+    val = FT_Common.UintToInt(val);
+
+    return (s >= 0) ? val : -val;
+}
+
+function FT_Vector_Length(vec)
+{
+    var v = new FT_Vector();
+    v.x = vec.x;
+    v.y = vec.y;
+
+    /* handle trivial cases */
+    if (v.x == 0)
+    {
+        return (v.y >= 0) ? v.y : -v.y;
+    }
+    else if (v.y == 0)
+    {
+        return (v.x >= 0) ? v.x : -v.x;
+    }
+
+    /* general case */
+    var shift = ft_trig_prenorm(v);
+    ft_trig_pseudo_polarize(v);
+
+    v.x = ft_trig_downscale(v.x);
+
+    if (shift > 0)
+        return (v.x + (1 << (shift - 1))) >> shift;
+    return v.x << -shift;
+}
+
+function FT_Outline_EmboldenXY(outline, xstrength, ystrength)
+{
+    if (outline == null)
+        return FT_Common.FT_Err_Invalid_Argument;
+
+    xstrength /= 2;
+    ystrength /= 2;
+
+    if (xstrength == 0 && ystrength == 0)
+        return 0;
+
+    var orientation = FT_Outline_Get_Orientation(outline);
+    if (orientation == FT_Common.FT_ORIENTATION_NONE)
+    {
+        if (outline.n_contours != 0)
+            return FT_Common.FT_Err_Invalid_Argument;
+        else
+            return 0;
+    }
+
+    var points = outline.points;
+    var contours = outline.contours;
+
+    var v_first = new FT_Vector();
+    var v_prev  = new FT_Vector();
+    var v_cur   = new FT_Vector();
+    var v_next  = new FT_Vector();
+
+    var first = 0;
+    var last = 0;
+    for (var c = 0; c < outline.n_contours; c++)
+    {
+        var _in = new FT_Vector();
+        var out = new FT_Vector();
+        var shift = new FT_Vector();
+
+        last = contours[c];
+
+        v_first.x = points[first].x;
+        v_first.y = points[first].y;
+
+        v_prev.x = points[last].x;
+        v_prev.y = points[last].y;
+
+        v_cur.x = v_first.x;
+        v_cur.y = v_first.y;
+
+        /* compute the incoming vector and its length */
+        _in.x = v_cur.x - v_prev.x;
+        _in.y = v_cur.y - v_prev.y;
+        var l_in = FT_Vector_Length(_in);
+
+        for (var n = first; n <= last; n++)
+        {
+            if (n < last)
+                v_next = points[n + 1];
+            else
+                v_next = v_first;
+
+            /* compute the outgoing vector and its length */
+            out.x = v_next.x - v_cur.x;
+            out.y = v_next.y - v_cur.y;
+            var l_out = FT_Vector_Length(out);
+
+            var d = l_in * l_out + _in.x * out.x + _in.y * out.y;
+
+            /* shift only if turn is less then ~160 degrees */
+            if (16 * d > l_in * l_out)
+            {
+                /* shift components are aligned along bisector        */
+                /* and directed according to the outline orientation. */
+                shift.x = l_out * _in.y + l_in * out.y;
+                shift.y = l_out * _in.x + l_in * out.x;
+
+                if (orientation == FT_Common.FT_ORIENTATION_TRUETYPE)
+                    shift.x = -shift.x;
+                else
+                    shift.y = -shift.y;
+
+                /* threshold strength to better handle collapsing segments */
+                var l = Math.min(l_in, l_out);
+                var q = out.x * _in.y - out.y * _in.x;
+                if (orientation == FT_Common.FT_ORIENTATION_TRUETYPE)
+                    q = -q;
+
+                if (FT_MulDiv(xstrength, q, l) < d)
+                    shift.x = FT_MulDiv(shift.x, xstrength, d);
+                else
+                    shift.x = FT_MulDiv(shift.x, l, q);
+
+                if (FT_MulDiv(ystrength, q, l) < d)
+                    shift.y = FT_MulDiv(shift.y, ystrength, d);
+                else
+                    shift.y = FT_MulDiv(shift.y, l, q);
+            }
+            else
+                shift.x = shift.y = 0;
+
+            points[n].x = v_cur.x + xstrength + shift.x;
+            points[n].y = v_cur.y + ystrength + shift.y;
+
+            _in    = out;
+            l_in  = l_out;
+            v_cur.x = v_next.x;
+            v_cur.y = v_next.y;
+        }
+
+        first = last + 1;
+    }
+
+    return 0;
+}
+
+function FT_Outline_EmboldenXY_cur(outline, base, xstrength, ystrength)
+{
+    if (outline == null)
+        return FT_Common.FT_Err_Invalid_Argument;
+
+    xstrength /= 2;
+    ystrength /= 2;
+
+    if (xstrength == 0 && ystrength == 0)
+        return 0;
+
+    var orientation = FT_Outline_Get_Orientation_Cur(outline, base);
+    if (orientation == FT_Common.FT_ORIENTATION_NONE)
+    {
+        if (outline.n_contours != 0)
+            return FT_Common.FT_Err_Invalid_Argument;
+        else
+            return 0;
+    }
+
+    var points = base.points;
+    var contours = base.contours;
+
+    var _p_off = outline.points;
+    var _c_off = outline.contours;
+
+    var v_first = new FT_Vector();
+    var v_prev  = new FT_Vector();
+    var v_cur   = new FT_Vector();
+    var v_next  = new FT_Vector();
+
+    var first = 0;
+    var last = 0;
+    for (var c = 0; c < outline.n_contours; c++)
+    {
+        var _in = new FT_Vector();
+        var out = new FT_Vector();
+        var shift = new FT_Vector();
+
+        last = contours[_c_off + c];
+
+        v_first.x = points[_p_off + first].x;
+        v_first.y = points[_p_off + first].y;
+
+        v_prev.x = points[_p_off + last].x;
+        v_prev.y = points[_p_off + last].y;
+
+        v_cur.x = v_first.x;
+        v_cur.y = v_first.y;
+
+        /* compute the incoming vector and its length */
+        _in.x = v_cur.x - v_prev.x;
+        _in.y = v_cur.y - v_prev.y;
+        var l_in = FT_Vector_Length(_in);
+
+        for (var n = first; n <= last; n++)
+        {
+            if (n < last)
+            {
+                v_next.x = points[_p_off + n + 1].x;
+                v_next.y = points[_p_off + n + 1].y;
+            }
+            else
+            {
+                v_next.x = v_first.x;
+                v_next.y = v_first.y;
+            }
+
+            /* compute the outgoing vector and its length */
+            out.x = v_next.x - v_cur.x;
+            out.y = v_next.y - v_cur.y;
+            var l_out = FT_Vector_Length(out);
+
+            var d = l_in * l_out + _in.x * out.x + _in.y * out.y;
+
+            /* shift only if turn is less then ~160 degrees */
+            if (16 * d > l_in * l_out)
+            {
+                /* shift components are aligned along bisector        */
+                /* and directed according to the outline orientation. */
+                shift.x = l_out * _in.y + l_in * out.y;
+                shift.y = l_out * _in.x + l_in * out.x;
+
+                if (orientation == FT_Common.FT_ORIENTATION_TRUETYPE)
+                    shift.x = -shift.x;
+                else
+                    shift.y = -shift.y;
+
+                /* threshold strength to better handle collapsing segments */
+                var l = Math.min(l_in, l_out);
+                var q = out.x * _in.y - out.y * _in.x;
+                if (orientation == FT_Common.FT_ORIENTATION_TRUETYPE)
+                    q = -q;
+
+                if (FT_MulDiv(xstrength, q, l) < d)
+                    shift.x = FT_MulDiv(shift.x, xstrength, d);
+                else
+                    shift.x = FT_MulDiv(shift.x, l, q);
+
+                if (FT_MulDiv(ystrength, q, l) < d)
+                    shift.y = FT_MulDiv(shift.y, ystrength, d);
+                else
+                    shift.y = FT_MulDiv(shift.y, l, q);
+            }
+            else
+                shift.x = shift.y = 0;
+
+            points[_p_off + n].x = v_cur.x + xstrength + shift.x;
+            points[_p_off + n].y = v_cur.y + ystrength + shift.y;
+
+            _in    = out;
+            l_in  = l_out;
+            v_cur.x = v_next.x;
+            v_cur.y = v_next.y;
+        }
+
+        first = last + 1;
+    }
+
+    return 0;
+}
+
+
+function FT_Outline_Embolden(outline, strength)
+{
+    return FT_Outline_EmboldenXY(outline, strength, strength);
+}
+//------------
+
+function FT_Outline_Transform(outline, matrix)
+{
+    if ( !outline || !matrix )
+        return;
+
+    var vec = outline.points;
+    var len = outline.n_points;
+
+    for (var i=0; i < len; i++)
+        FT_Vector_Transform(vec[i], matrix);
+}
+
+function FT_Vector_Transform(vector, matrix)
+{
+    if ( !vector || !matrix )
+        return;
+
+    var xz = FT_MulFix(vector.x, matrix.xx) + FT_MulFix(vector.y, matrix.xy);
+    var yz = FT_MulFix(vector.x, matrix.yx) + FT_MulFix(vector.y, matrix.yy);
+
+    vector.x = xz;
+    vector.y = yz;
+}
+
+function FT_Outline_Translate(outline, xOffset, yOffset)
+{
+    if ( !outline )
+        return;
+
+    var vec = outline.points;
+    var c = outline.n_points;
+
+    for (var n=0;n<c;n++)
+    {
+        vec[n].x += xOffset;
+        vec[n].y += yOffset;
+    }
+}
+
+function FT_Outline_Get_CBox(outline, acbox)
+{
+    var xMin, yMin, xMax, yMax;
+
+    if (outline != null && acbox != null)
+    {
+        if (outline.n_points == 0)
+        {
+            xMin = 0;
+            yMin = 0;
+            xMax = 0;
+            yMax = 0;
+        }
+        else
+        {
+            var p = outline.points;
+            var vec = p[0];
+            var count = outline.n_points;
+
+            xMin = xMax = vec.x;
+            yMin = yMax = vec.y;
+
+            for (var i = 1; i < count; i++)
+            {
+                var x = p[i].x;
+                if ( x < xMin ) xMin = x;
+                if ( x > xMax ) xMax = x;
+
+                var y = p[i].y;
+                if ( y < yMin ) yMin = y;
+                if ( y > yMax ) yMax = y;
+            }
+        }
+        acbox.xMin = xMin;
+        acbox.xMax = xMax;
+        acbox.yMin = yMin;
+        acbox.yMax = yMax;
+    }
+}
+
+function FT_Glyph_Class()
+{
+    this.glyph_size = 0;
+    this.glyph_format = 0;
+    this.glyph_init = null;
+    this.glyph_done = null;
+    this.glyph_copy = null;
+    this.glyph_transform = null;
+    this.glyph_bbox = null;
+    this.glyph_prepare = null;
+}
+
+// для быстроты работы не пользуется эта структура.
+// все ради всех браузеров, кроме ie9. в них типизированные массивы
+// быстрее обычных (а тут скорость доступа - самое главное)
+function TCell()
+{
+    this.x      = 0;
+    this.cover  = 0;
+    this.area   = 0;
+    this.next   = 0;
+}
+
+function TRaster()
+{
+    this.worker = new TWorker();
+
+    this.memory = null;
+
+    this.cell_x     = CreateIntArray(1024);
+    this.cell_cover = CreateIntArray(1024);
+    this.cell_area  = CreateIntArray(1024);
+    this.cell_next  = CreateIntArray(1024);
+
+    this.buffer_size    = 0;
+    this.band_size      = 0;
+}
+
+// - smooth -----------------------------------------------------------
+// ------------ rasterizer --------------------------------------------
+// пул памяти для растеризатора делаем Array int'ов. Почему не массив структур?
+// 1) не выделять память под саму структуру (хотя кто знает как работает js)
+// 2) самое главное - это возможность замены на типизированный массив!!!
+// сам растеризатор ничего не знает о происхождении массива. За создание
+// его отвечает функция CreateIntArray
+function CreateIntArray(size)
+{
+    var arr = null;
+    if (typeof(Int32Array) != 'undefined' && !window.opera)
+        arr = new Int32Array(size);
+    else
+        arr = new Array(size);
+    for (var i=0;i<size;i++)
+        arr[i] = 0;
+    return arr;
+}
+function CreateUIntArray(size)
+{
+    var arr = null;
+    if (typeof(Uint32Array) != 'undefined' && !window.opera)
+        arr = new Uint32Array(size);
+    else
+        arr = new Array(size);
+    for (var i=0;i<size;i++)
+        arr[i] = 0;
+    return arr;
+}
+function CreateCharArray(size)
+{
+    var arr = null;
+    if (typeof(Int8Array) != 'undefined' && !window.opera)
+        arr = new Int8Array(size);
+    else
+        arr = new Array(size);
+    for (var i=0;i<size;i++)
+        arr[i] = 0;
+    return arr;
+}
+function CreateNullArray(size)
+{
+    var arr = new Array(size);
+    for (var i=0;i<size;i++)
+        arr[i] = null;
+    return arr;
+}
+function TWorker()
+{
+    this.ex = 0;
+    this.ey = 0;
+
+    this.min_ex = 0;
+    this.max_ex = 0;
+    this.min_ey = 0;
+    this.max_ey = 0;
+
+    this.count_ex = 0;
+    this.count_ey = 0;
+
+    this.area = 0;
+    this.cover = 0;
+    this.invalid = 0;
+
+    this.max_cells = 0;
+    this.num_cells = 0;
+
+    this.cx = 0;
+    this.cy = 0;
+    this.x = 0;
+    this.y = 0;
+
+    this.last_ey = 0;
+
+    this.bez_stack_x = CreateIntArray(97);
+    this.bez_stack_y = CreateIntArray(97);
+    this.lev_stack = CreateIntArray(32);
+
+    this.outline = null;
+    this.target = null;
+    this.clip_box = new FT_BBox();
+
+    this.gray_spans = new Array(32);
+    for (var i=0;i<32;i++)
+        this.gray_spans[i] = new FT_Span();
+
+    this.num_gray_spans = 0;
+
+    this.render_span = null;
+    
+    this.render_span_data = null;
+    this.span_y = 0;
+
+    this.band_size = 0;
+    this.band_shoot = 0;
+
+    this.cell_x     = null;
+    this.cell_cover = null;
+    this.cell_area  = null;
+    this.cell_next  = null;
+    this.buffer_size = 1024;
+
+    this.ycells = CreateIntArray(this.buffer_size);
+    this.ycount = 0;
+
+    this.raster_memory = raster_memory;
+}
+
+function gray_init_cells(worker, raster)
+{
+    worker.cell_x     = raster.cell_x;
+    worker.cell_cover = raster.cell_cover;
+    worker.cell_area  = raster.cell_area;
+    worker.cell_next  = raster.cell_next;
+    worker.buffer_size = 1024;
+
+    worker.max_cells   = 0;
+    worker.num_cells   = 0;
+    worker.area        = 0;
+    worker.cover       = 0;
+    worker.invalid     = 1;
+}
+
+function gray_compute_cbox(worker)
+{
+    var outline = worker.outline;
+    var p = outline.points;
+    var c = outline.n_points;
+
+    if ( c <= 0 )
+    {
+        worker.min_ex = worker.max_ex = 0;
+        worker.min_ey = worker.max_ey = 0;
+        return;
+    }
+
+    worker.min_ex = worker.max_ex = p[0].x;
+    worker.min_ey = worker.max_ey = p[0].y;
+
+    for (var i = 1; i < c; i++)
+    {
+        var x = p[i].x;
+        var y = p[i].y;
+
+        if ( x < worker.min_ex ) worker.min_ex = x;
+        if ( x > worker.max_ex ) worker.max_ex = x;
+        if ( y < worker.min_ey ) worker.min_ey = y;
+        if ( y > worker.max_ey ) worker.max_ey = y;
+    }
+
+    /* truncate the bounding box to integer pixels */
+    worker.min_ex = worker.min_ex >> 6;
+    worker.min_ey = worker.min_ey >> 6;
+    worker.max_ex = ( worker.max_ex + 63 ) >> 6;
+    worker.max_ey = ( worker.max_ey + 63 ) >> 6;
+}
+
+function TBand()
+{
+    this.min = 0;
+    this.max = 0;
+}
+
+function gray_find_cell(ras)
+{
+    var x = ras.ex;
+
+    if ( x > ras.count_ex )
+        x = ras.count_ex;
+
+    var pcell = ras.ey;
+    var cell = ras.ycells[pcell];
+
+    var bis_y = 1;
+    for (;;)
+    {
+        if (cell == -1 || ras.cell_x[cell] > x)
+            break;
+
+        if (ras.cell_x[cell] == x)
+            return cell;
+
+        bis_y = 0;
+        pcell = cell;
+        cell = ras.cell_next[cell];
+    }
+
+    if (ras.num_cells >= ras.max_cells)
+        return -1;
+
+    var oldcell = cell;
+
+    cell = ras.num_cells++;
+    ras.cell_x[cell] = x;
+    ras.cell_area[cell] = 0;
+    ras.cell_cover[cell] = 0;
+    ras.cell_next[cell] = oldcell;
+
+    if (1 == bis_y)
+        ras.ycells[pcell] = cell;
+    else
+        ras.cell_next[pcell] = cell;
+    return cell;
+}
+
+function gray_record_cell(ras)
+{
+    if (0 == ras.invalid && ((ras.area | ras.cover) != 0))
+    {
+        var cell = gray_find_cell(ras);
+        if (-1 == cell)
+            return FT_Common.ErrorLongJump;
+
+        ras.cell_area[cell] += ras.area;
+        ras.cell_cover[cell] += ras.cover;
+    }
+    return 0;
+}
+
+function gray_set_cell(ras, ex, ey)
+{
+    ey -= ras.min_ey;
+
+    if ( ex > ras.max_ex )
+        ex = ras.max_ex;
+
+    ex -= ras.min_ex;
+    if ( ex < 0 )
+        ex = -1;
+
+    /* are we moving to a different cell ? */
+    if ( ex != ras.ex || ey != ras.ey )
+    {
+        /* record the current one if it is valid */
+        if (0 == ras.invalid)
+        {
+            var err = gray_record_cell(ras);
+            if (err == FT_Common.ErrorLongJump)
+                return FT_Common.ErrorLongJump;
+        }
+
+        ras.area  = 0;
+        ras.cover = 0;
+    }
+
+    ras.ex      = ex;
+    ras.ey      = ey;
+
+    var _ey = ey >= 0 ? ey : ey + FT_Common.a_i;
+    var _cy = ras.count_ey >= 0 ? ras.count_ey : ras.count_ey + FT_Common.a_i;
+
+    ras.invalid = (_ey >= _cy || ex >= ras.count_ex) ? 1 : 0;
+    return 0;
+}
+
+function gray_start_cell(ras, ex, ey)
+{
+    if (ex > ras.max_ex)
+        ex = ras.max_ex;
+
+    if (ex < ras.min_ex)
+        ex = (ras.min_ex - 1);
+
+    ras.area    = 0;
+    ras.cover   = 0;
+    ras.ex      = ex - ras.min_ex;
+    ras.ey      = ey - ras.min_ey;
+    ras.last_ey = ey << 8;
+    ras.invalid = 0;
+
+    return gray_set_cell(ras, ex, ey);
+}
+
+function gray_render_line(ras, to_x, to_y)
+{
+    var ey1, ey2, fy1, fy2, mod;
+    var dx, dy, x, x2;
+    var p, first;
+    var delta, rem, lift, incr;
+
+    ey1 = (ras.last_ey >> 8);
+    ey2 = (to_y >> 8);     /* if (ey2 >= ras.max_ey) ey2 = ras.max_ey-1; */
+    fy1 = (ras.y - ras.last_ey);
+    fy2 = (to_y - (ey2 << 8));
+
+    dx = to_x - ras.x;
+    dy = to_y - ras.y;
+
+    var min = ey1;
+    var max = ey2;
+
+    if (ey1 > ey2)
+    {
+        min = ey2;
+        max = ey1;
+    }
+    if (min >= ras.max_ey || max < ras.min_ey)
+    {
+        ras.x       = to_x;
+        ras.y       = to_y;
+        ras.last_ey = ey2 << 8;
+        return 0;
+    }
+
+    var err = 0;
+    /* everything is on a single scanline */
+    if (ey1 == ey2)
+    {
+        err = gray_render_scanline(ras, ey1, ras.x, fy1, to_x, fy2);
+        if (err == FT_Common.ErrorLongJump)
+            return FT_Common.ErrorLongJump;
+        ras.x       = to_x;
+        ras.y       = to_y;
+        ras.last_ey = ey2 << 8;
+        return 0;
+    }
+
+    /* vertical line - avoid calling gray_render_scanline */
+    incr = 1;
+
+    if (dx == 0)
+    {
+        var ex = ras.x >> 8;
+        var two_fx = ((ras.x - (ex << 8)) << 1);
+        var area;
+
+        first = 256;
+        if (dy < 0)
+        {
+            first = 0;
+            incr  = -1;
+        }
+
+        delta      = (first - fy1);
+        ras.area  += (two_fx * delta);
+        ras.cover += delta;
+        ey1       += incr;
+
+        err = gray_set_cell(ras, ex, ey1);
+        if (err == FT_Common.ErrorLongJump)
+            return FT_Common.ErrorLongJump;
+
+        delta = (first + first - 256);
+        area  = two_fx * delta;
+        while (ey1 != ey2)
+        {
+            ras.area  += area;
+            ras.cover += delta;
+            ey1       += incr;
+
+            err = gray_set_cell(ras, ex, ey1);
+            if (err == FT_Common.ErrorLongJump)
+                return FT_Common.ErrorLongJump;
+        }
+
+        delta      = (fy2 - 256 + first);
+        ras.area  += (two_fx * delta);
+        ras.cover += delta;
+
+        ras.x       = to_x;
+        ras.y       = to_y;
+        ras.last_ey = ey2 << 8;
+        return 0;
+    }
+
+    /* ok, we have to render several scanlines */
+    p     = (256 - fy1) * dx;
+    first = 256;
+    incr  = 1;
+
+    if (dy < 0)
+    {
+        p     = fy1 * dx;
+        first = 0;
+        incr  = -1;
+        dy    = -dy;
+    }
+
+    delta = parseInt(p / dy);
+    mod   = (p % dy);
+    if (mod < 0)
+    {
+        delta--;
+        mod += dy;
+    }
+
+    x = ras.x + delta;
+    err = gray_render_scanline(ras, ey1, ras.x, fy1, x, first);
+    if (err == FT_Common.ErrorLongJump)
+        return FT_Common.ErrorLongJump;
+
+    ey1 += incr;
+    err = gray_set_cell(ras, x >> 8, ey1);
+    if (err == FT_Common.ErrorLongJump)
+        return FT_Common.ErrorLongJump;
+
+    if (ey1 != ey2)
+    {
+        p     = 256 * dx;
+        lift  = parseInt(p / dy);
+        rem   = (p % dy);
+        if (rem < 0)
+        {
+            lift--;
+            rem += dy;
+        }
+        mod -= dy;
+
+        while (ey1 != ey2)
+        {
+            delta = lift;
+            mod  += rem;
+            if (mod >= 0)
+            {
+                mod -= dy;
+                delta++;
+            }
+
+            x2 = x + delta;
+            err = gray_render_scanline(ras, ey1, x, 256 - first, x2, first);
+            if (err == FT_Common.ErrorLongJump)
+                return FT_Common.ErrorLongJump;
+            x = x2;
+
+            ey1 += incr;
+            err = gray_set_cell(ras, x >> 8, ey1);
+            if (err == FT_Common.ErrorLongJump)
+                return FT_Common.ErrorLongJump;
+        }
+    }
+
+    err = gray_render_scanline(ras, ey1, x, 256 - first, to_x, fy2);
+    if (err == FT_Common.ErrorLongJump)
+        return FT_Common.ErrorLongJump;
+
+    ras.x       = to_x;
+    ras.y       = to_y;
+    ras.last_ey = (ey2 << 8);
+    return 0;
+}
+
+function gray_split_conic(bx,by,base)
+{
+    var a,b;
+    bx[base+4] = bx[base+2];
+    b = bx[base+1];
+    a=bx[base+3] = parseInt((bx[base+2]+b)/2);
+    b=bx[base+1] = parseInt((bx[base]+b)/2);
+    bx[base+2] = parseInt((a+b)/2);
+
+    by[base+4] = by[base+2];
+    b = by[base+1];
+    a=by[base+3] = parseInt((by[base+2]+b)/2);
+    b=by[base+1] = parseInt((by[base]+b)/2);
+    by[base+2] = parseInt((a+b)/2);
+}
+
+function gray_render_conic(ras, control, to)
+{
+    var dx, dy;
+    var min, max, y;
+    var top, level;
+    var arc = 0;
+
+    var arcx = ras.bez_stack_x;
+    var arcy = ras.bez_stack_y;
+
+    arcx[arc] = (to.x << 2);
+    arcy[arc] = (to.y << 2);
+    arcx[arc+1] = (control.x << 2);
+    arcy[arc+1] = (control.y << 2);
+    arcx[arc+2] = ras.x;
+    arcy[arc+2] = ras.y;
+    top = 0;
+
+    dx = Math.abs(arcx[arc+2] + arcx[arc] - 2*arcx[arc+1]);
+    dy = Math.abs(arcy[arc+2] + arcy[arc] - 2*arcy[arc+1]);
+    if (dx < dy)
+        dx = dy;
+
+    if (dx < 64)
+    {
+        return gray_render_line(ras, arcx[arc], arcy[arc]);
+    }
+
+    /* short-cut the arc that crosses the current band */
+    min = max = arcy[arc];
+
+    y = arcy[arc+1];
+    if (y < min) min = y;
+    if (y > max) max = y;
+
+    y = arcy[arc+2];
+    if (y < min) min = y;
+    if (y > max) max = y;
+
+    if (((min >> 8) >= ras.max_ey) || ((max >> 8) < ras.min_ey))
+    {
+        return gray_render_line(ras, arcx[arc], arcy[arc]);
+    }
+
+    level = 0;
+    do
+    {
+        dx >>= 2;
+        level++;
+    } while (dx > 64);
+
+    var levels = ras.lev_stack;
+    levels[0] = level;
+
+    var err = 0;
+    do
+    {
+        level = levels[top];
+        if (level > 0)
+        {
+            gray_split_conic(arcx, arcy, arc);
+            arc += 2;
+            top++;
+            levels[top] = levels[top - 1] = level - 1;
+            continue;
+        }
+
+        err = gray_render_line(ras, arcx[arc], arcy[arc]);
+        if (err == FT_Common.ErrorLongJump)
+            return FT_Common.ErrorLongJump;
+        top--;
+        arc -= 2;
+
+    }
+    while (top >= 0);
+    return 0;
+}
+
+function gray_split_cubic(bx,by,base)
+{
+    var a,b,c,d;
+    bx[base+6] = bx[base+3];
+    c = bx[base+1];
+    d = bx[base+2];
+    bx[base+1] = a = parseInt((bx[base]+c)/2);
+    bx[base+5] = b = parseInt((bx[base+3]+d)/2);
+    c = parseInt((c+d)/2);
+    bx[base+2] = a = parseInt((a+c)/2);
+    bx[base+4] = b = parseInt((b+c)/2);
+    bx[base+3] = parseInt((a+b)/2);
+
+    by[base+6] = by[base+3];
+    c = by[base+1];
+    d = by[base+2];
+    by[base+1] = a = parseInt((by[base]+c)/2);
+    by[base+5] = b = parseInt((by[base+3]+d)/2);
+    c = parseInt((c+d)/2);
+    by[base+2] = a = parseInt((a+c)/2);
+    by[base+4] = b = parseInt((b+c)/2);
+    by[base+3] = parseInt((a+b)/2);
+}
+
+function gray_render_cubic(ras, control1, control2, to)
+{
+    var min, max, y;
+
+    var arcx = ras.bez_stack_x;
+    var arcy = ras.bez_stack_y;
+    arcx[0] = to.x << 2;
+    arcy[0] = to.y << 2;
+    arcx[1] = control2.x << 2;
+    arcy[1] = control2.y << 2;
+    arcx[2] = control1.x << 2;
+    arcy[2] = control1.y << 2;
+    arcx[3] = ras.x;
+    arcy[3] = ras.y;
+
+    var arc = 0;
+
+    /* Short-cut the arc that crosses the current band. */
+    min = max = arcy[0];
+
+    y = arcy[arc+1];
+    if (y<min)
+        min = y;
+    if (y>max)
+        max = y;
+
+    y = arcy[arc+2];
+    if (y<min)
+        min = y;
+    if (y>max)
+        max = y;
+
+    y = arcy[arc+3];
+    if (y<min)
+        min = y;
+    if (y>max)
+        max = y;
+
+    var err = 0;
+    if ((min >> 8) >= ras.max_ey || (max >> 8) < ras.min_ey)
+    {
+        return gray_render_line(ras, arcx[arc], arcy[arc]);
+    }
+
+    for (;;)
+    {
+        var dx, dy, dx_, dy_;
+        var dx1, dy1, dx2, dy2;
+        var L, s, s_limit;
+
+        dx = arcx[arc+3] - arcx[arc];
+        dy = arcy[arc+3] - arcy[arc];
+
+        dx_ = Math.abs(dx);
+        dy_ = Math.abs(dy);
+
+        L = ((dx_ > dy_) ? (236 * dx_ + 97 * dy_) : (97 * dx_ + 236 * dy_)) >>> 8;
+
+        if ( L > 32767 )
+        {
+            gray_split_cubic(arcx,arcy,arc);
+            arc += 3;
+            continue;
+        }
+
+        s_limit = L * 42;
+
+        dx1 = arcx[arc+1] - arcx[arc];
+        dy1 = arcy[arc+1] - arcy[arc];
+        s = Math.abs(dy*dx1 - dx*dy1);
+
+        if (s>s_limit)
+        {
+            gray_split_cubic(arcx,arcy,arc);
+            arc += 3;
+            continue;
+        }
+
+        dx2 = arcx[arc+2] - arcx[arc];
+        dy2 = arcy[arc+2] - arcy[arc];
+        s = Math.abs(dy*dx2 - dx*dy2);
+
+        if (s>s_limit)
+        {
+            gray_split_cubic(arcx,arcy,arc);
+            arc += 3;
+            continue;
+        }
+
+        if (((dy*dy1 + dx*dx1) < 0) || ((dy*dy2 + dx*dx2) < 0) ||
+            ((dy*(arcy[arc+3]-arcy[arc+1]) + dx*(arcx[arc+3]-arcx[arc+1])) < 0) ||
+            ((dy*(arcy[arc+3]-arcy[arc+2]) + dx*(arcx[arc+3]-arcx[arc+2])) < 0))
+        {
+            gray_split_cubic(arcx,arcy,arc);
+            arc += 3;
+            continue;
+        }
+
+        /* No reason to split. */
+        err = gray_render_line(ras, arcx[arc], arcy[arc]);
+        if (err == FT_Common.ErrorLongJump)
+            return FT_Common.ErrorLongJump;
+
+        if (arc == 0)
+            return 0;
+
+        arc -= 3;
+    }
+    return 0;
+}
+
+function gray_render_scanline(ras, ey, x1, y1, x2, y2)
+{
+    var ex1, ex2, fx1, fx2, delta, mod, lift, rem;
+    var p, first, dx;
+    var incr;
+
+    dx = x2 - x1;
+
+    ex1 = (x1 >> 8);
+    ex2 = (x2 >> 8);
+    fx1 = x1 - (ex1 << 8);
+    fx2 = x2 - (ex2 << 8);
+
+    /* trivial case.  Happens often */
+    if (y1 == y2)
+    {
+        return gray_set_cell(ras, ex2, ey);
+    }
+
+    /* everything is located in a single cell.  That is easy! */
+    if (ex1 == ex2)
+    {
+        delta = y2 - y1;
+        ras.area  += ((fx1+fx2)*delta);
+        ras.cover += delta;
+        return 0;
+    }
+
+    /* ok, we'll have to render a run of adjacent cells on the same scanline */
+    p = (256 - fx1)*(y2-y1);
+    first = 256;
+    incr  = 1;
+
+    if (dx < 0)
+    {
+        p     = fx1*(y2-y1);
+        first = 0;
+        incr  = -1;
+        dx    = -dx;
+    }
+
+    delta = parseInt(p/dx);
+    mod   = p%dx;
+    if (mod < 0)
+    {
+        delta--;
+        mod += dx;
+    }
+
+    ras.area  += ((fx1+first)*delta);
+    ras.cover += delta;
+
+    ex1 += incr;
+    var err = gray_set_cell(ras, ex1, ey);
+    if (err == FT_Common.ErrorLongJump)
+        return err;
+    y1  += delta;
+
+    if (ex1 != ex2)
+    {
+        p    = 256 * (y2 - y1 + delta);
+        lift = parseInt(p/dx);
+        rem  = (p%dx);
+        if (rem < 0)
+        {
+            lift--;
+            rem += dx;
+        }
+
+        mod -= dx;
+
+        while (ex1 != ex2)
+        {
+            delta = lift;
+            mod  += rem;
+            if (mod >= 0)
+            {
+                mod -= dx;
+                delta++;
+            }
+
+            ras.area  += (256*delta);
+            ras.cover += delta;
+            y1        += delta;
+            ex1       += incr;
+            err = gray_set_cell(ras, ex1, ey);
+            if (err == FT_Common.ErrorLongJump)
+                return err;
+        }
+    }
+
+    delta      = y2 - y1;
+    ras.area  += ((fx2 + 256 - first)*delta);
+    ras.cover += delta;
+    return 0;
+}
+
+function _gray_render_span(y, count, spans, span_start, worker)
+{
+    var map = worker.target;
+    var pixels = map.buffer.data;
+    var p = -y * map.pitch;
+    if (map.pitch >= 0)
+        p += ((map.rows-1)*map.pitch);
+
+    var s = span_start;
+    for (;count > 0;count--,s++)
+    {
+        var coverage = spans[s].coverage;
+
+        if (coverage != 0)
+        {
+            var len = spans[s].len;
+            var q = spans[s].x + p;
+            for (;len>0;len--)
+                pixels[q++] = coverage;
+        }
+    }
+}
+function gray_render_span(y, count, spans, span_start, worker)
+{
+    var map = worker.raster_memory;
+    var pixels = map.m_oBuffer.data;
+    var p = -y * map.pitch;
+    if (worker.target.pitch >= 0)
+        p += ((worker.target.rows-1)*map.pitch);
+
+    p+=3;
+
+    var s = span_start;
+    for (;count > 0;count--,s++)
+    {
+        var coverage = spans[s].coverage;
+
+        if (coverage != 0)
+        {
+            var len = spans[s].len;
+            var q = (spans[s].x * 4) + p;
+            for (;len>0;len--,q+=4)
+                pixels[q] = coverage;
+        }
+    }
+}
+
+function gray_hline(ras, x, y, area, acount)
+{
+    var spans = ras.gray_spans;
+    var span_i = 0;
+    var span;
+
+    var count;
+
+    var coverage = (area >> 9);
+    /* use range 0..256 */
+    if (coverage < 0)
+        coverage = -coverage;
+
+    if ((ras.outline.flags & FT_Common.FT_OUTLINE_EVEN_ODD_FILL) != 0)
+    {
+        coverage &= 511;
+        if (coverage > 256)
+            coverage = 512 - coverage;
+        else if (coverage == 256)
+            coverage = 255;
+    }
+    else
+    {
+        if ( coverage >= 256 )
+            coverage = 255;
+    }
+
+    y += ras.min_ey;
+    x += ras.min_ex;
+
+    if (x >= 32767)
+        x = 32767;
+
+    /* FT_Span.y is an integer, so limit our coordinates appropriately */
+    if (y >= 2147483647)
+        y = 2147483647;
+
+    if (coverage != 0)
+    {
+        /* see whether we can add this span to the current list */
+        count = ras.num_gray_spans;
+        span_i  = count - 1;
+        span = spans[span_i];
+        if ((count > 0) && (ras.span_y == y) && ((span.x + span.len) == x) && (span.coverage == coverage))
+        {
+            span.len = (span.len + acount) & 0xFFFF;
+            return;
+        }
+
+        if (ras.span_y != y || count >= 32)
+        {
+            if (ras.render_span && count > 0)
+                ras.render_span(ras.span_y,count,ras.gray_spans,0,ras.render_span_data);
+
+            ras.num_gray_spans = 0;
+            ras.span_y = y;
+
+            count = 0;
+            span_i = 0;
+            span = spans[0];
+        }
+        else
+        {
+            span_i++;
+            span = spans[span_i];
+        }
+
+        /* add a gray span to the current list */
+        span.x        = x;
+        span.len      = acount & 0xFFFF;
+        span.coverage = coverage & 0xFF;
+
+        ras.num_gray_spans++;
+    }
+}
+
+function gray_sweep(ras, target)
+{
+    if (ras.num_cells == 0)
+        return;
+
+    ras.num_gray_spans = 0;
+
+    var _next = ras.cell_next;
+    var _cover = ras.cell_cover;
+    var _area = ras.cell_area;
+    var _x = ras.cell_x;
+
+    for (var yindex = 0; yindex < ras.ycount; yindex++)
+    {
+        var cell = ras.ycells[yindex];
+        var cover = 0;
+        var x = 0;
+
+        for (; cell != -1; cell = _next[cell])
+        {
+            if (_x[cell] > x && cover != 0)
+                gray_hline(ras, x, yindex, cover * 512, _x[cell] - x);
+
+            cover += _cover[cell];
+            var area = cover * 512 - _area[cell];
+
+            if (area != 0 && _x[cell] >= 0)
+                gray_hline(ras, _x[cell], yindex, area, 1);
+
+            x = _x[cell] + 1;
+        }
+
+        if ( cover != 0 )
+            gray_hline(ras, x, yindex, cover * 512, ras.count_ex - x);
+    }
+
+    if (ras.render_span && ras.num_gray_spans > 0)
+        ras.render_span(ras.span_y, ras.num_gray_spans, ras.gray_spans, 0, ras.render_span_data);
+}
+
+function __grays_raster_render(raster, params)
+{
+    var outline = params.source;
+    var target_map = params.target;
+
+    if (raster == null)
+        return FT_Common.FT_Err_Invalid_Argument;
+
+    if (outline == null)
+        return FT_Common.FT_Err_Invalid_Outline;
+
+    /* return immediately if the outline is empty */
+    if (outline.n_points == 0 || outline.n_contours <= 0)
+        return 0;
+
+    if (outline.contours == null || outline.points == null)
+        return FT_Common.FT_Err_Invalid_Outline;
+
+    if (outline.n_points != outline.contours[outline.n_contours - 1] + 1)
+        return FT_Common.FT_Err_Invalid_Outline;
+
+    var worker = raster.worker;
+
+    /* if direct mode is not set, we must have a target bitmap */
+    if (0 == (params.flags & FT_Common.FT_RASTER_FLAG_DIRECT))
+    {
+        if (target_map == null)
+            return FT_Common.FT_Err_Invalid_Argument;
+
+        /* nothing to do */
+        if (0 == target_map.width || 0 == target_map.rows)
+            return 0;
+
+        if (null == target_map.buffer && null == worker.raster_memory)
+            return FT_Common.FT_Err_Invalid_Argument;
+    }
+
+    /* this version does not support monochrome rendering */
+    if (0 == (params.flags & FT_Common.FT_RASTER_FLAG_AA))
+        return FT_Common.FT_Err_Invalid_Argument;
+
+    /* compute clipping box */
+    if (0 == (params.flags & FT_Common.FT_RASTER_FLAG_DIRECT))
+    {
+        /* compute clip box from target pixmap */
+        worker.clip_box.xMin = 0;
+        worker.clip_box.yMin = 0;
+        worker.clip_box.xMax = target_map.width;
+        worker.clip_box.yMax = target_map.rows;
+    }
+    else if (params.flags & FT_Common.FT_RASTER_FLAG_CLIP)
+    {
+        worker.clip_box.xMin = params.clip_box.xMin;
+        worker.clip_box.yMin = params.clip_box.yMin;
+        worker.clip_box.xMax = params.clip_box.xMax;
+        worker.clip_box.yMax = params.clip_box.yMax;
+    }
+    else
+    {
+        worker.clip_box.xMin = -32768;
+        worker.clip_box.yMin = -32768;
+        worker.clip_box.xMax =  32767;
+        worker.clip_box.yMax =  32767;
+    }
+
+    gray_init_cells(worker, raster);
+
+    worker.outline        = outline;
+    worker.num_cells      = 0;
+    worker.invalid        = 1;
+    worker.band_size      = raster.band_size;
+    worker.num_gray_spans = 0;
+
+    if (0 != (params.flags & FT_Common.FT_RASTER_FLAG_DIRECT))
+    {
+        worker.render_span      = params.gray_spans;
+        worker.render_span_data = params.user;
+    }
+    else
+    {
+        worker.target           = target_map;
+        worker.render_span      = gray_render_span;
+        worker.render_span_data = worker;
+    }
+
+    if (worker.raster_memory != null)
+        worker.raster_memory.CheckSize(target_map.width, target_map.rows);
+
+    return __gray_convert_glyph(worker);
+}
+function __gray_convert_glyph(ras)
+{
+    var bands = m_bands;
+    var band = 0;
+    var n = 0;
+    var num_bands = 0;
+    var min = 0;
+    var max = 0;
+    var max_y = 0;
+    var clip = null;
+
+    gray_compute_cbox(ras);
+
+    /* clip to target bitmap, exit if nothing to do */
+    clip = ras.clip_box;
+
+    if (ras.max_ex <= clip.xMin || ras.min_ex >= clip.xMax ||
+        ras.max_ey <= clip.yMin || ras.min_ey >= clip.yMax )
+        return 0;
+
+    if (ras.min_ex < clip.xMin) ras.min_ex = clip.xMin;
+    if (ras.min_ey < clip.yMin) ras.min_ey = clip.yMin;
+
+    if (ras.max_ex > clip.xMax ) ras.max_ex = clip.xMax;
+    if (ras.max_ey > clip.yMax ) ras.max_ey = clip.yMax;
+
+    ras.count_ex = ras.max_ex - ras.min_ex;
+    ras.count_ey = ras.max_ey - ras.min_ey;
+
+    /* set up vertical bands */
+    num_bands = parseInt((ras.max_ey - ras.min_ey) / ras.band_size);
+    if (num_bands == 0)
+        num_bands = 1;
+    if (num_bands >= 39)
+        num_bands = 39;
+
+    ras.band_shoot = 0;
+
+    min   = ras.min_ey;
+    max_y = ras.max_ey;
+
+    for (n = 0; n < num_bands; n++, min = max)
+    {
+        max = min + ras.band_size;
+        if ((n == num_bands - 1) || (max > max_y))
+            max = max_y;
+
+        bands[0].min = min;
+        bands[0].max = max;
+        band = 0;
+
+        while (band >= 0)
+        {
+            var isReduceBands = 0;
+
+            var bottom, top, middle;
+            var error = 0;
+            var _band = bands[band];
+
+            var cells_max;
+
+            ras.ycount = _band.max - _band.min;
+            if (ras.ycount >= ras.buffer_size)
+                isReduceBands = 1;
+
+            if (0 == isReduceBands)
+            {
+                ras.max_cells = ras.buffer_size;
+                if (ras.max_cells < 2)
+                {
+                    // такого быть не может из-за лишнего килобайтика)
+                    isReduceBands = 1;
+                }
+
+                if (0 == isReduceBands)
+                {
+                    for (var yindex = 0; yindex < ras.ycount; yindex++)
+                        ras.ycells[yindex] = -1;
+
+                    ras.num_cells = 0;
+                    ras.invalid   = 1;
+                    ras.min_ey    = _band.min;
+                    ras.max_ey    = _band.max;
+                    ras.count_ey  = _band.max - _band.min;
+
+                    error = __gray_convert_glyph_inner(ras);
+
+                    if (0 == error)
+                    {
+                        gray_sweep(ras, ras.target);
+                        band--;
+                        continue;
+                    }
+                    else if (error != FT_Common.FT_Err_Raster_Overflow)
+                        return 1;
+                }
+            }
+
+            /* render pool overflow; we will reduce the render band by half */
+            bottom = _band.min;
+            top    = _band.max;
+            middle = bottom + ((top - bottom) >> 1);
+
+            /* This is too complex for a single scanline; there must */
+            /* be some problems.                                     */
+            if (middle == bottom)
+                return 1;
+
+            if (bottom-top >= ras.band_size)
+                ras.band_shoot++;
+
+
+            bands[band+1].min = bottom;
+            bands[band+1].max = middle;
+            bands[band].min = middle;
+            bands[band].max = top;
+
+            band++;
+        }
+    }
+
+    if (ras.band_shoot > 8 && ras.band_size > 16)
+        ras.band_size = parseInt(ras.band_size / 2);
+
+    return 0;
+}
+
+function __gray_convert_glyph_inner(ras)
+{
+    var error1 = FT_Outline_Decompose(ras.outline, ft_outline_funcs_gray, ras);
+
+    if (FT_Common.ErrorLongJump == error1)
+        return FT_Common.FT_Err_Raster_Overflow;
+
+    var error2 = gray_record_cell(ras);
+    if (FT_Common.ErrorLongJump == error2)
+        return FT_Common.FT_Err_Raster_Overflow;
+
+    return error1;
+}
+
+var m_bands = new Array(40);
+for (var i = 0; i < 40; i++)
+    m_bands[i] = new TBand();
+
+function FT_Grays_Raster()
+{
+    // --------
+    this.glyph_format = FT_Common.FT_GLYPH_FORMAT_OUTLINE;
+
+    this.raster_new = function(memory, raster)
+    {
+        raster.memory = memory;
+        return 0;
+    }
+    this.raster_reset = function(raster, pool_base, pool_size)
+    {
+        raster.buffer_size    = 1024;
+        raster.band_size      = 117; // сделал как в си-шной либе, чтобы было удобно дебажиться.
+        // а вообще - нужно так: (мы памяти выделяем больше на 1kb (под указатели ycells))
+        //raster.band_size = 128;
+    }
+    this.raster_set_mode = null;
+    this.raster_render = __grays_raster_render;
+    this.raster_done = function()
+    {
+    }
+}
+// --------------------------------------------------------------------
+
+function FT_Smooth_Renderer_Class()
+{
+    this.flags = FT_Common.FT_MODULE_RENDERER;
+    this.name = "smooth";
+    this.version = 0x10000;
+    this.requires = 0x20000;
+
+    this.module_interface = null;
+
+    this.init = ft_smooth_init;
+    this.done = null;
+    this.get_interface = null;
+
+    this.glyph_format = FT_Common.FT_GLYPH_FORMAT_OUTLINE;
+
+    this.render_glyph = ft_smooth_render;
+    this.transform_glyph = ft_smooth_transform;
+    this.get_glyph_cbox = ft_smooth_get_cbox;
+    this.set_mode = ft_smooth_set_mode;
+
+    this.raster_class = new FT_Grays_Raster();
+}
+function FT_Smooth_Renderer()
+{
+    this.clazz = new FT_Smooth_Renderer_Class();
+    this.library = null;
+    this.memory = null;
+    this.generic = null;
+
+    this.glyph_format = 0;
+    this.glyph_class = new FT_Glyph_Class();
+    this.raster = null;
+
+    this.raster_render = null;
+    this.render = null;
+}
+
+function create_renderer_smooth_module(library)
+{
+    var ren1_mod = new FT_Smooth_Renderer();
+    ren1_mod.clazz = new FT_Smooth_Renderer_Class();
+    ren1_mod.clazz.render_glyph = ft_smooth_render;
+
+    ren1_mod.library = library;
+    ren1_mod.memory = library.Memory;
+    ren1_mod.generic = null;
+
+    return ren1_mod;
+}
+function create_renderer_smooth_lcd_module(library)
+{
+    var ren1_mod = new FT_Smooth_Renderer();
+    ren1_mod.clazz = new FT_Smooth_Renderer_Class();
+    ren1_mod.clazz.render_glyph = ft_smooth_render_lcd;
+
+    ren1_mod.library = library;
+    ren1_mod.memory = library.Memory;
+    ren1_mod.generic = null;
+
+    return ren1_mod;
+}
+function create_renderer_smooth_lcd_v_module(library)
+{
+    var ren1_mod = new FT_Smooth_Renderer();
+    ren1_mod.clazz = new FT_Smooth_Renderer_Class();
+    ren1_mod.clazz.render_glyph = ft_smooth_render_lcd_v;
+
+    ren1_mod.library = library;
+    ren1_mod.memory = library.Memory;
+    ren1_mod.generic = null;
+
+    return ren1_mod;
+}
+
+function ft_smooth_init(render)
+{
+    render.clazz.raster_class.raster_reset(render.raster, render.library.raster_pool, render.library.raster_pool_size);
+    return 0;
+}
+
+function ft_smooth_set_mode(render, mode_tag, data)
+{
+    return render.clazz.raster_class.raster_set_mode(render.raster, mode_tag, data);
+}
+
+function ft_smooth_transform(render, slot, matrix, delta)
+{
+    if (slot.format != render.glyph_format)
+        return FT_Common.FT_Err_Invalid_Argument;
+
+    if (matrix)
+        FT_Outline_Transform(slot.outline, matrix);
+
+    if (delta)
+        FT_Outline_Translate(slot.outline, delta.x, delta.y);
+
+    return 0;
+}
+
+function ft_smooth_get_cbox(render, slot, cbox)
+{
+    cbox.xMin = 0;
+    cbox.yMin = 0;
+    cbox.xMax = 0;
+    cbox.yMax = 0;
+
+    if (slot.format == render.glyph_format)
+        FT_Outline_Get_CBox(slot.outline, cbox);
+}
+
+function ft_smooth_render(render, slot, mode, origin)
+{
+    if (mode == FT_Common.FT_RENDER_MODE_LIGHT)
+        mode = FT_Common.FT_RENDER_MODE_NORMAL;
+
+    return ft_smooth_render_generic(render, slot, mode, origin, FT_Common.FT_RENDER_MODE_NORMAL);
+}
+
+function ft_smooth_render_lcd(render, slot, mode, origin)
+{
+    var error = ft_smooth_render_generic(render, slot, mode, origin, FT_Common.FT_RENDER_MODE_LCD);
+    if (error == 0)
+        slot.bitmap.pixel_mode = FT_Common.FT_PIXEL_MODE_LCD;
+
+    return error;
+}
+
+function ft_smooth_render_lcd_v(render, slot, mode, origin)
+{
+    var error = ft_smooth_render_generic(render, slot, mode, origin, FT_Common.FT_RENDER_MODE_LCD_V);
+    if (error == 0)
+        slot.bitmap.pixel_mode = FT_Common.FT_PIXEL_MODE_LCD_V;
+
+    return error;
+}
+
+function ft_smooth_render_generic(render, slot, mode, origin, required_mode)
+{
+    var error = 0;
+    var outline = null;
+    var cbox = new FT_BBox();
+    var width, height, pitch;
+
+    //#ifndef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
+    var height_org, width_org;
+    //#endif
+
+    var hmul = (mode == FT_Common.FT_RENDER_MODE_LCD) ? 1 : 0;
+    var vmul = (mode == FT_Common.FT_RENDER_MODE_LCD_V) ? 1 : 0;
+    var x_shift, y_shift, x_left, y_top;
+
+    var params = new FT_Raster_Params();
+
+    /* check glyph image format */
+    if (slot.format != render.glyph_format)
+        return FT_Common.FT_Err_Invalid_Argument;
+
+    /* check mode */
+    if (mode != required_mode)
+        return FT_Common.FT_Err_Cannot_Render_Glyph;
+
+    outline = slot.outline;
+
+    /* translate the outline to the new origin if needed */
+    if (origin != null)
+        FT_Outline_Translate(outline, origin.x, origin.y);
+
+    /* compute the control box, and grid fit it */
+    FT_Outline_Get_CBox(outline, cbox);
+
+    cbox.xMin = (cbox.xMin & ~63);
+    cbox.yMin = (cbox.yMin & ~63);
+    cbox.xMax = ((cbox.xMax+63) & ~63);
+    cbox.yMax = ((cbox.yMax+63) & ~63);
+
+    if (cbox.xMin < 0 && cbox.xMax > 2147483647 + cbox.xMin)
+    {
+        if (outline && origin)
+            FT_Outline_Translate(outline, -origin.x, -origin.y);
+        return FT_Common.FT_Err_Raster_Overflow;
+    }
+    else
+        width  = ((cbox.xMax - cbox.xMin) >>> 6);
+
+    if ( cbox.yMin < 0 && cbox.yMax > 2147483647 + cbox.yMin )
+    {
+        if ( outline && origin )
+            FT_Outline_Translate( outline, -origin.x, -origin.y );
+        return FT_Common.FT_Err_Raster_Overflow;
+    }
+    else
+        height = ((cbox.yMax - cbox.yMin) >>> 6);
+
+    var bitmap = slot.bitmap;
+    var memory = render.memory;
+
+    //#ifndef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
+    width_org  = width;
+    height_org = height;
+    //#endif
+
+    /* release old bitmap buffer */
+    if (slot.internal.flags & FT_Common.FT_GLYPH_OWN_BITMAP)
+    {
+        delete bitmap.buffer;
+        slot.internal.flags &= ~FT_Common.FT_GLYPH_OWN_BITMAP;
+    }
+
+    /* allocate new one */
+    pitch = width;
+    if (hmul == 1)
+    {
+        width = width * 3;
+        pitch = (width + 3) & ~3;
+    }
+
+    if (vmul == 1)
+        height *= 3;
+
+    x_shift = cbox.xMin;
+    y_shift = cbox.yMin;
+    x_left  = cbox.xMin >> 6;
+    y_top   = cbox.yMax >> 6;
+
+    //#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
+    /*
+    if (slot.library.lcd_filter_func)
+    {
+        var extra = slot.library.lcd_extra;
+        if (hmul == 1)
+        {
+            x_shift -= 64 * (extra >>> 1);
+            width   += 3 * extra;
+            pitch    = (width + 3) & ~3;
+            x_left  -= (extra >>> 1);
+        }
+        if (vmul == 1)
+        {
+            y_shift -= 64 * (extra >>> 1);
+            height  += 3 * extra;
+            y_top   += (extra >>> 1);
+        }
+    }
+    */
+    //#endif
+
+    if (width > 0x7FFF || height > 0x7FFF)
+    {
+        if (outline && origin)
+            FT_Outline_Translate(outline, -origin.x, -origin.y);
+        return FT_Common.FT_Err_Raster_Overflow;
+    }
+
+    bitmap.pixel_mode = FT_Common.FT_PIXEL_MODE_GRAY;
+    bitmap.num_grays  = 256;
+    bitmap.width      = width;
+    bitmap.rows       = height;
+    bitmap.pitch      = pitch;
+
+    if (bitmap.width > 1000 || bitmap.height > 1000)
+        return 130;
+
+    /* translate outline to render it into the bitmap */
+    FT_Outline_Translate(outline, -x_shift, -y_shift);
+    var memory = slot.library.Memory;
+
+    //bitmap.buffer = memory.Alloc(pitch * height);
+
+    slot.internal.flags |= FT_Common.FT_GLYPH_OWN_BITMAP;
+
+    /* set up parameters */
+    params.target = bitmap;
+    params.source = outline;
+    params.flags  = FT_Common.FT_RASTER_FLAG_AA;
+
+    //#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
+    /*
+    var points = outline.points;
+    var count = outline.n_points;
+
+    if (hmul == 1)
+        for (var i = 0; i < count; i++)
+            points[i].x = points[i].x * 3;
+
+    if (vmul == 1)
+        for (var i = 0; i < count; i++)
+            points[i].y = points[i].y * 3;
+    error = render.raster_render(render.raster, params);
+    if (hmul == 1)
+        for (var i = 0; i < count; i++)
+            points[i].x = parseInt(points[i].x / 3);
+
+    if (vmul == 1)
+        for (var i = 0; i < count; i++)
+            points[i].y = parseInt(points[i].y / 3);
+
+    if (slot.library.lcd_filter_func)
+        slot.library.lcd_filter_func(bitmap, mode, slot.library);
+    */
+
+    //#else /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
+    error = render.raster_render(render.raster, params);
+    if (hmul == 1)
+    {
+        var pixels = bitmap.buffer.data;
+        var line = 0;
+        for (var hh = height_org; hh > 0; hh--, line += pitch)
+        {
+            var end = line + width;
+            for (var xx = width_org; xx > 0; xx--)
+            {
+                var pixel = pixels[line+xx-1];
+
+                pixels[end-3] = pixel;
+                pixels[end-2] = pixel;
+                pixels[end-1] = pixel;
+                end -= 3;
+            }
+        }
+    }
+    if (vmul == 1)
+    {
+        var pixels = bitmap.buffer.data;
+        var read = (height - height_org) * pitch;
+        var write = 0;
+        var ii = 0;
+        for (var hh = height_org; hh > 0; hh--)
+        {
+            for (ii=0;ii<pitch;ii++)
+                pixels[write+ii] = pixels[read+ii];
+
+            write += pitch;
+
+            for (ii=0;ii<pitch;ii++)
+                pixels[write+ii] = pixels[read+ii];
+
+            write += pitch;
+
+            for (ii=0;ii<pitch;ii++)
+                pixels[write+ii] = pixels[read+ii];
+
+            write += pitch;
+            read  += pitch;
+        }
+    }
+    //#endif /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
+
+    FT_Outline_Translate(outline, x_shift, y_shift);
+
+    if (x_left > 0x7FFFFFFF || y_top > 0x7FFFFFFF)
+        return FT_Common.FT_Err_Invalid_Pixel_Size;
+
+    if (error == 0)
+    {
+        slot.format      = FT_Common.FT_GLYPH_FORMAT_BITMAP;
+        slot.bitmap_left = x_left;
+        slot.bitmap_top  = y_top;
+    }
+
+    if ( outline && origin )
+        FT_Outline_Translate(outline, -origin.x, -origin.y);
+
+    return error;
+}
\ No newline at end of file
diff --git a/Common/FontsFreeType/Private/FreeType/modules/sfnt.js b/Common/FontsFreeType/Private/FreeType/modules/sfnt.js
new file mode 100644
index 0000000000000000000000000000000000000000..d1a63c58bcdb63f48b75cea040e01f42ada37d3a
--- /dev/null
+++ b/Common/FontsFreeType/Private/FreeType/modules/sfnt.js
@@ -0,0 +1,5530 @@
+/******************************************************************************/
+// bdf
+/******************************************************************************/
+function BDF_PropertyRec()
+{
+    this.type;
+    this.u;
+}
+
+function tt_face_free_bdf_props(face)
+{
+    var bdf = face.bdf;
+    if (bdf.loaded == 1)
+    {
+        bdf.table = null;
+        bdf.table_end = 0;
+        bdf.strings = null;
+        bdf.strings_size = 0;
+    }
+}
+
+function tt_face_load_bdf_props(face, stream)
+{
+    var bdf = face.bdf;
+    var error = 0;
+
+    bdf.table = null;
+    bdf.table_end = 0;
+    bdf.strings = null;
+    bdf.strings_size = 0;
+    bdf.num_strikes = 0;
+    bdf.loaded = 0;
+
+    var length = tt_face_goto_table(face, FT_Common.TTAG_BDF, stream);
+    error = FT_Error;
+    if (error != 0 || length < 8)
+        return FT_Common.FT_Err_Invalid_Table;
+
+    bdf.table = new CPointer();
+    error = stream.ExtractFrame(length, bdf.table);
+
+    if (error != 0)
+        return FT_Common.FT_Err_Invalid_Table;
+
+    bdf.table_end = length;
+
+    var p = dublicate_pointer(bdf.table);
+    var version = FT_NEXT_USHORT(p);
+    var num_strikes = FT_NEXT_USHORT(p);
+    var strings = FT_NEXT_ULONG (p);
+
+    if (version != 0x0001 || strings < 8  || (strings - 8) / 4 < num_strikes || strings + 1 > length)
+    {
+        bdf.table = null;
+        return FT_Common.FT_Err_Invalid_Table;
+    }
+
+    bdf.num_strikes = num_strikes;
+    bdf.strings = new CPointer();
+    bdf.strings.data = bdf.table.data;
+    bdf.strings.pos = bdf.table.pos + strings;
+    bdf.strings_size = length - strings;
+
+    var count = bdf.num_strikes;
+    p.pos = bdf.table.pos + 8;
+    var strike = p.pos + count * 4;
+
+    for ( ; count > 0; count--)
+    {
+        p.pos+=2;
+        var num_items = FT_PEEK_USHORT(p);
+
+        strike += 10 * num_items;
+        p.pos+=2;
+    }
+
+    if (strike > bdf.strings)
+    {
+        bdf.table = null;
+        bdf.table_end = 0;
+        bdf.strings = null;
+        bdf.strings_size = 0;
+        bdf.num_strikes = 0;
+        bdf.loaded = 0;
+        return FT_Common.FT_Err_Invalid_Table;
+    }
+
+    bdf.loaded = 1;
+    return error;
+}
+
+function tt_face_find_bdf_prop(face,property_name,aprop)
+{
+    var bdf = face.bdf;
+    var size = face.size;
+    var error = 0;
+
+    aprop.type = FT_Common.BDF_PROPERTY_TYPE_NONE;
+
+    if (bdf.loaded == 0)
+    {
+        error = tt_face_load_bdf_props(face, face.stream);
+        if (error != 0)
+            return error;
+    }
+
+    var count = bdf.num_strikes;
+    var p = dublicate_pointer(bdf.table);
+    p.pos += 8;
+
+    var strike = dublicate_pointer(p);
+    strike.pos += 4 * count;
+
+    error = FT_Common.FT_Err_Invalid_Argument;
+
+    var property_len = property_name.length;
+    if (size == null || property_len == 0)
+        return error;
+
+    var is_strike = 0;
+    for ( ; count > 0; count-- )
+    {
+        var _ppem  = FT_NEXT_USHORT(p);
+        var _count = FT_NEXT_USHORT(p);
+
+        if (_ppem == size.metrics.y_ppem)
+        {
+            count = _count;
+            is_strike = 1;
+            break;
+        }
+
+        strike.pos += 10 * _count;
+    }
+    if (0 == is_strike)
+        return error;
+
+    p.pos = strike.pos;
+    var point = dublicate_pointer(bdf.strings);
+    for (; count > 0; count--)
+    {
+        p.pos+=4;
+        var type = FT_PEEK_USHORT(p);
+        p.pos-=4;
+
+        if ((type & 0x10) != 0)
+        {
+            var name_offset = FT_PEEK_ULONG(p);
+            p.pos+=6;
+            var value = FT_PEEK_ULONG(p);
+            p.pos-=6;
+
+            point.pos = bdf.strings.pos + name_offset;
+            if (name_offset < bdf.strings_size && property_len < bdf.strings_size - name_offset &&
+                        property_name == FT_PEEK_String1(point,bdf.strings_size-name_offset))
+            {
+                switch ( type & 0x0F )
+                {
+                    case 0x00:
+                    case 0x01:
+                        point.pos = bdf.strings.pos + value;
+                        if (value < bdf.strings_size && -1 != ft_memchr(point, 0, bdf.strings_size))
+                        {
+                            aprop.type = FT_Common.BDF_PROPERTY_TYPE_ATOM;
+                            aprop.u = FT_PEEK_String1(point,bdf.strings_size);
+                            return 0;
+                        }
+                        break;
+
+                    case 0x02:
+                        aprop.type = FT_Common.BDF_PROPERTY_TYPE_INTEGER;
+                        aprop.u = ((value > FT_Common.m_i) ? value-FT_Common.a_i : value);
+                        return 0;
+                    case 0x03:
+                        aprop.type = FT_Common.BDF_PROPERTY_TYPE_CARDINAL;
+                        aprop.u = ((value >= 0) ? value : value + FT_Common.m_i);
+                        return 0;
+                    default:
+                        break;
+                }
+            }
+        }
+        p.pos += 10;
+    }
+
+    return error;
+}
+
+function sfnt_get_charset_id(face,acharset_encoding,acharset_registry)
+{
+    var encoding = new BDF_PropertyRec();
+    var registry = new BDF_PropertyRec();
+
+    FT_Error = tt_face_find_bdf_prop(face, "CHARSET_REGISTRY", registry);
+    if (FT_Error == 0)
+    {
+        FT_Error = tt_face_find_bdf_prop(face, "CHARSET_ENCODING", encoding);
+        if (FT_Error == 0)
+        {
+            if (registry.type == BDF_PROPERTY_TYPE_ATOM && encoding.type == BDF_PROPERTY_TYPE_ATOM)
+            {
+                return {enc:encoding.u,reg:registry.u};
+            }
+            else
+                FT_Error = FT_Common.FT_Err_Invalid_Argument;
+        }
+    }
+
+    return {enc:"",reg:""};
+}
+/******************************************************************************/
+// ttkern
+/******************************************************************************/
+function tt_face_load_kern(face, stream)
+{
+    var error = 0;
+    var table_size = face.goto_table(face, FT_Common.TTAG_kern, stream);
+    error = FT_Error;
+
+    if (error != 0)
+        return error;
+
+    if (table_size < 4)
+        return FT_Common.FT_Err_Table_Missing;
+
+    face.kern_table = new CPointer();
+    error = stream.ExtractFrame(table_size, face.kern_table);
+    if (error != 0)
+        return error;
+
+    face.kern_table_size = table_size;
+    stream.cur = face.kern_table.pos;
+    var p_limit = stream.cur + table_size;
+
+    stream.cur += 2; // skip version
+    var num_tables = stream.GetUShort();
+
+    if (num_tables > 32)
+        num_tables = 32;
+
+    var avail = 0;
+    var ordered = 0;
+
+    var nn = 0;
+    for (; nn < num_tables; nn++)
+    {
+        var mask = 1 << nn;
+
+        var p_next = stream.cur;
+
+        if (stream.cur + 6 < p_limit)
+            break;
+
+        stream.cur += 2; // skip version
+        var length = stream.GetUShort();
+        var coverage = stream.GetUShort();
+
+        if (length <= 6)
+            break;
+
+        p_next += length;
+
+        if (p_next > p_limit)
+            p_next = p_limit;
+
+        if ((coverage & ~8) != 0x0001 || (stream.cur + 8) > p_limit)
+        {
+            stream.cur = p_next;
+            continue;
+        }
+
+        var num_pairs = stream.GetUShort();
+        stream.cur += 6;
+
+        if ((p_next - stream.cur) < (6 * num_pairs))
+            num_pairs = parseInt((p_next - stream.cur) / 6);
+
+        avail |= mask;
+
+        if (num_pairs > 0)
+        {
+            var count = 0;
+            var old_pair = stream.GetULong();
+
+            stream.cur += 2;
+
+            for (count = num_pairs - 1; count > 0; count--)
+            {
+                var cur_pair = stream.GetULong();
+                if (cur_pair <= old_pair)
+                    break;
+
+                stream.cur += 2;
+                old_pair = cur_pair;
+            }
+
+            if (count == 0)
+                ordered |= mask;
+        }
+
+        stream.cur = p_next;
+    }
+
+    face.num_kern_tables = nn;
+    face.kern_avail_bits = avail;
+    face.kern_order_bits = ordered;
+
+    return error;
+}
+function tt_face_done_kern(face)
+{
+    face.kern_table = null;
+    face.kern_table_size = 0;
+    face.num_kern_tables = 0;
+    face.kern_avail_bits = 0;
+    face.kern_order_bits = 0;
+}
+function tt_face_get_kerning(face,left_glyph,right_glyph)
+{
+    var result = 0;
+    var count, mask = 1;
+    var p = dublicate_pointer(face.kern_table);
+    if (null == p)
+        return result;
+
+    var p_limit = p.pos + face.kern_table_size;
+
+    p.pos += 4;
+    mask = 0x0001;
+
+    for (count = face.num_kern_tables; count > 0 && p.pos + 6 <= p_limit; count--, mask <<= 1)
+    {
+        if (mask < 0)
+            mask+=FT_Common.a_i;
+        var version  = FT_NEXT_USHORT( p );
+        var length   = FT_NEXT_USHORT( p );
+        var coverage = FT_NEXT_USHORT( p );
+        var value = 0;
+
+        var base = p.pos;
+        var next = base + length;
+
+        if (next > p_limit)
+            next = p_limit;
+
+        if ((face.kern_avail_bits & mask) == 0)
+        {
+            p.pos = next;
+            continue;
+        }
+
+        if (p.pos + 8 > next)
+        {
+            p.pos = next;
+            continue;
+        }
+
+        var num_pairs = FT_NEXT_USHORT( p );
+        p.pos += 6;
+
+        if (( next - p.pos) < 6 * num_pairs)
+            num_pairs = parseInt((next - p.pos)/6);
+
+        switch (coverage >>> 8)
+        {
+            case 0:
+            {
+                var key0 = (left_glyph<<16 | right_glyph)&0xFFFFFFFF;
+                if (key0 < 0)
+                    key0 += FT_Common.a_i;
+
+                if ((face.kern_order_bits & mask) != 0)
+                {
+                    var min = 0;
+                    var max = num_pairs;
+
+                    var q = dublicate_pointer(p);
+                    var is_found = 0;
+                    while ( min < max )
+                    {
+                        var mid = (min + max) >>> 1;
+                        q.pos = p.pos + 6 * mid;
+                        var key = FT_NEXT_ULONG(q);
+
+                        if (key == key0)
+                        {
+                            value = FT_PEEK_SHORT( q );
+                            if ((coverage & 8) != 0)
+                                result = value;
+                            else
+                                result += value;
+                            p.pos = next;
+                            is_found = 1;
+                            break;
+                        }
+                        if (key < key0)
+                            min = mid + 1;
+                        else
+                            max = mid;
+                    }
+                    if (1 == is_found)
+                        continue;
+                }
+                else
+                {
+                    var is_found = 0;
+                    for (var count2 = num_pairs; count2 > 0; count2--)
+                    {
+                        var key = FT_NEXT_ULONG(p);
+
+                        if (key == key0)
+                        {
+                            value = FT_PEEK_SHORT(p);
+                            if ((coverage & 8) != 0)
+                                result = value;
+                            else
+                                result += value;
+                            p.pos = next;
+                            is_found = 1;
+                            break;
+                        }
+                        p.pos += 2;
+                    }
+                    if (is_found == 1)
+                        continue;
+                }
+            }
+            break;
+        default:
+            break;
+        }
+        p.pos = next;
+    }
+
+    return result;
+}
+/******************************************************************************/
+// ttload
+/******************************************************************************/
+function tt_face_lookup_table(face, tag)
+{
+    var count = face.num_tables;
+    for (var i=0; i<count; i++)
+    {
+        var entry = face.dir_tables[i];
+        if (entry.Tag == tag && entry.Length != 0)
+            return entry;
+    }
+    return null;
+}
+function tt_face_goto_table(face, tag, stream)
+{
+    var length = 0;
+    var table = tt_face_lookup_table(face, tag);
+    if (table != null)
+    {
+        length = table.Length;
+        FT_Error = stream.Seek(table.Offset);
+        return table.Length;
+    }
+    FT_Error = FT_Common.FT_Err_Table_Missing;
+    return 0;
+}
+function check_table_dir(sfnt, stream)
+{
+    var error = 0;
+    var nn = 0;
+    var valid_entries = 0;
+    var has_head = 0;
+    var has_sing = 0;
+    var has_meta = 0;
+    var offset = sfnt.offset + 12;
+
+    error = stream.Seek(offset);
+    if (FT_Common.FT_Err_Ok != error)
+        return error;
+
+    var num_t = sfnt.num_tables;
+    for (nn = 0; nn < num_t; nn++)
+    {
+        error = stream.EnterFrame(16);
+        if (error != 0)
+        {
+            nn--;
+            sfnt.num_tables = nn;
+            break;
+        }
+
+        var Tag = stream.GetULong();
+        var CheckSum = stream.GetULong();
+        var Offset = stream.GetULong();
+        var Length = stream.GetULong();
+
+        stream.ExitFrame();
+
+        if (Offset + Length > stream.size)
+            continue;
+        else
+            valid_entries++;
+
+        if (Tag == FT_Common.TTAG_head || Tag == FT_Common.TTAG_bhed)
+        {
+            has_head = 1;
+            if (Length < 0x36)
+                return FT_Common.FT_Err_Table_Missing;
+
+            error = stream.Seek(Offset + 12);
+            if (error != FT_Common.FT_Err_Ok)
+                return error;
+
+            var magic = stream.ReadULong();
+            if (magic != 0x5F0F3CF5)
+                return FT_Common.FT_Err_Table_Missing;
+
+            error = stream.Seek(offset + (nn+1)*16);
+            if (error != FT_Common.FT_Err_Ok)
+                return error;
+        }
+        else if (Tag == FT_Common.TTAG_SING)
+            has_sing = 1;
+        else if (Tag == FT_Common.TTAG_META)
+            has_meta = 1;
+    }
+
+    sfnt.num_tables = valid_entries;
+
+    if (sfnt.num_tables == 0)
+        return FT_Common.FT_Err_Unknown_File_Format;
+
+    if ((has_head == 1) || ((has_sing == 1) && (has_meta == 1)))
+        return FT_Common.FT_Err_Ok;
+    else
+        return FT_Common.FT_Err_Table_Missing;
+
+    return error;
+}
+function tt_face_load_font_dir(face, stream)
+{
+    var sfnt = new SFNT_HeaderRec();
+    var error = 0;
+
+    sfnt.offset = stream.pos;
+    sfnt.format_tag = stream.ReadULong();
+
+    error = FT_Error;
+    if (error != 0)
+        return error;
+
+    error = stream.EnterFrame(8);
+    if (error != 0)
+        return error;
+
+    sfnt.num_tables = stream.GetUShort();
+    sfnt.search_range = stream.GetUShort();
+    sfnt.entry_selector = stream.GetUShort();
+    sfnt.range_shift = stream.GetUShort();
+
+    stream.ExitFrame();
+
+    error = check_table_dir(sfnt, stream);
+    if (0 != error)
+        return error;
+
+    face.num_tables = sfnt.num_tables;
+    face.format_tag = sfnt.format_tag;
+
+    face.dir_tables = new Array(face.num_tables);
+
+    error = stream.Seek(sfnt.offset + 12);
+    if (0 == error)
+    {
+        error = stream.EnterFrame(face.num_tables * 16);
+    }
+    if (0 != error)
+        return error;
+
+    var cur = 0;
+    for (var nn = 0; nn < sfnt.num_tables; nn++ )
+    {
+        face.dir_tables[cur] = new TT_Table();
+        var entry = face.dir_tables[cur];
+        entry.Tag      = stream.GetULong();
+        entry.CheckSum = stream.GetULong();
+        entry.Offset   = stream.GetLong();
+        entry.Length   = stream.GetLong();
+
+        /* ignore invalid tables */
+        if (entry.Offset + entry.Length > stream.size)
+            continue;
+        cur++;
+    }
+
+    stream.ExitFrame();
+    return error;
+}
+function tt_face_load_any(face,tag,offset,buffer,length)
+{
+    var error = 0;
+    var table;
+    var size;
+
+    if (tag != 0)
+    {
+        table = tt_face_lookup_table(face, tag);
+        if (null == table)
+            return FT_Common.FT_Err_Table_Missing;
+
+        offset += table.Offset;
+        size = table.Length;
+    }
+    else
+    {
+        size = face.stream.size;
+    }
+
+    if (length == 0)
+    {
+        FT_Error = 0;
+        return size;
+    }
+
+    if (null != length)
+        size = length;
+
+    error = face.stream.ReadAt(offset,buffer,size);
+    FT_Error = error;
+    return size;
+}
+function tt_face_load_generic_header(face, stream, tag)
+{
+    var error = 0;
+    face.goto_table(face, tag, stream);
+    error = FT_Error;
+    if (error != FT_Common.FT_Err_Ok)
+        return error;
+
+    error = stream.EnterFrame(54);
+    if (error != 0)
+        return error;
+
+    var header = face.header;
+
+    header.Table_Version = stream.GetULong();
+    header.Font_Revision = stream.GetULong();
+    header.CheckSum_Adjust = stream.GetLong();
+    header.Magic_Number = stream.GetLong();
+    header.Flags = stream.GetUShort();
+    header.Units_Per_EM = stream.GetUShort();
+    header.Created1 = stream.GetLong();
+    header.Created2 = stream.GetLong();
+    header.Modified1 = stream.GetLong();
+    header.Modified2 = stream.GetLong();
+    header.xMin = stream.GetShort();
+    header.yMin = stream.GetShort();
+    header.xMax = stream.GetShort();
+    header.yMax = stream.GetShort();
+    header.Mac_Style = stream.GetUShort();
+    header.Lowest_Rec_PPEM = stream.GetUShort();
+    header.Font_Direction = stream.GetShort();
+    header.Index_To_Loc_Format = stream.GetShort();
+    header.Glyph_Data_Format = stream.GetShort();
+
+    stream.ExitFrame();
+
+    return error;
+}
+function tt_face_load_head(face, stream)
+{
+    return tt_face_load_generic_header(face, stream, FT_Common.TTAG_head);
+}
+function tt_face_load_bhed(face, stream)
+{
+    return tt_face_load_generic_header(face, stream, FT_Common.TTAG_bhed);
+}
+function tt_face_load_maxp(face, stream)
+{
+    var error = 0;
+    face.goto_table(face, FT_Common.TTAG_maxp, stream);
+    error = FT_Error;
+    if (error != 0)
+        return error;
+
+    error = stream.EnterFrame(6);
+    if (error != 0)
+        return error;
+
+    var maxProfile = face.max_profile;
+    maxProfile.version = stream.GetLong();
+    maxProfile.numGlyphs = stream.GetUShort();
+    stream.ExitFrame();
+
+    maxProfile.maxPoints             = 0;
+    maxProfile.maxContours           = 0;
+    maxProfile.maxCompositePoints    = 0;
+    maxProfile.maxCompositeContours  = 0;
+    maxProfile.maxZones              = 0;
+    maxProfile.maxTwilightPoints     = 0;
+    maxProfile.maxStorage            = 0;
+    maxProfile.maxFunctionDefs       = 0;
+    maxProfile.maxInstructionDefs    = 0;
+    maxProfile.maxStackElements      = 0;
+    maxProfile.maxSizeOfInstructions = 0;
+    maxProfile.maxComponentElements  = 0;
+    maxProfile.maxComponentDepth     = 0;
+
+    if (maxProfile.version >= 0x10000)
+    {
+        error = stream.EnterFrame(26);
+        if (error != 0)
+            return error;
+
+        maxProfile.maxPoints             = stream.GetUShort();
+        maxProfile.maxContours           = stream.GetUShort();
+        maxProfile.maxCompositePoints    = stream.GetUShort();
+        maxProfile.maxCompositeContours  = stream.GetUShort();
+        maxProfile.maxZones              = stream.GetUShort();
+        maxProfile.maxTwilightPoints     = stream.GetUShort();
+        maxProfile.maxStorage            = stream.GetUShort();
+        maxProfile.maxFunctionDefs       = stream.GetUShort();
+        maxProfile.maxInstructionDefs    = stream.GetUShort();
+        maxProfile.maxStackElements      = stream.GetUShort();
+        maxProfile.maxSizeOfInstructions = stream.GetUShort();
+        maxProfile.maxComponentElements  = stream.GetUShort();
+        maxProfile.maxComponentDepth     = stream.GetUShort();
+
+        if (maxProfile.maxFunctionDefs < 64)
+            maxProfile.maxFunctionDefs = 64;
+
+        /* we add 4 phantom points later */
+        if (maxProfile.maxTwilightPoints > (0xFFFF - 4))
+            maxProfile.maxTwilightPoints = 0xFFFF - 4;
+
+        /* we arbitrarily limit recursion to avoid stack exhaustion */
+        if (maxProfile.maxComponentDepth > 100)
+            maxProfile.maxComponentDepth = 100;
+
+        stream.ExitFrame();
+    }
+    return error;
+}
+function tt_face_load_name(face, stream)
+{
+    var error = 0;
+    var table_pos = 0;
+    var table_len = 0;
+    var storage_start = 0;
+    var storage_limit = 0;
+    var count = 0;
+
+    table_len = face.goto_table(face, FT_Common.TTAG_name, stream);
+    error = FT_Error;
+    if (error != 0)
+        return error;
+
+    var table = face.name_table;
+    table.stream = stream;
+
+    table_pos = stream.pos;
+
+    error = stream.EnterFrame(6);
+    if (error != 0)
+        return error;
+
+    table.format = stream.GetUShort();
+    table.numNameRecords = stream.GetUShort();
+    table.storageOffset = stream.GetUShort();
+
+    stream.ExitFrame();
+
+    storage_start = table_pos + 6 + 12*table.numNameRecords;
+    storage_limit = table_pos + table_len;
+
+    if (storage_start > storage_limit)
+        return FT_Common.FT_Err_Name_Table_Missing;
+
+    /* Allocate the array of name records. */
+    count = table.numNameRecords;
+    table.numNameRecords = 0;
+
+    table.names = new Array(count);
+
+    error = stream.EnterFrame(count * 12);
+    for (; count > 0; count--)
+    {
+        var entry = new TT_NameEntryRec();
+        entry.platformID = stream.GetUShort();
+        entry.encodingID = stream.GetUShort();
+        entry.languageID = stream.GetUShort();
+        entry.nameID = stream.GetUShort();
+        entry.stringLength = stream.GetUShort();
+        entry.stringOffset = stream.GetUShort();
+
+        if (entry.stringLength == 0)
+            continue;
+
+        entry.stringOffset += (table_pos + table.storageOffset);
+        if (entry.stringOffset < storage_start || (entry.stringOffset + entry.stringLength) > storage_limit)
+            continue;
+
+        table.names[table.numNameRecords] = entry;
+        table.numNameRecords++;
+    }
+
+    stream.ExitFrame();
+
+    /* everything went well, update face->num_names */
+    face.num_names = table.numNameRecords;
+    return error;
+}
+function tt_face_free_name(face)
+{
+    face.name_table.names = null;
+    var table = face.num_table;
+    table.names = null;
+    table.numNameRecords = 0;
+    table.format         = 0;
+    table.storageOffset  = 0;
+}
+function tt_face_load_cmap(face, stream)
+{
+    face.cmap_size = face.goto_table(face, FT_Common.TTAG_cmap, stream);
+    if (FT_Error != 0)
+        return FT_Error;
+
+    face.cmap_table = new CPointer();
+    var error = stream.ExtractFrame(face.cmap_size, face.cmap_table);
+    if (error != 0)
+    {
+        face.cmap_size = 0;
+        face.cmap_table = null;
+    }
+    return error;
+}
+function tt_face_load_os2(face, stream)
+{
+    var error = 0;
+
+    var os2 = face.os2;
+
+    face.goto_table(face, FT_Common.TTAG_OS2, stream);
+    if (error != 0)
+        return error;
+
+    error = stream.EnterFrame(78);
+    if (error != 0)
+        return error;
+
+    os2.version = stream.GetUShort();
+    os2.xAvgCharWidth = stream.GetShort();
+    os2.usWeightClass = stream.GetUShort();
+    os2.usWidthClass = stream.GetUShort();
+    os2.fsType = stream.GetShort();
+    os2.ySubscriptXSize = stream.GetShort();
+    os2.ySubscriptYSize = stream.GetShort();
+    os2.ySubscriptXOffset = stream.GetShort();
+    os2.ySubscriptYOffset = stream.GetShort();
+    os2.ySuperscriptXSize = stream.GetShort();
+    os2.ySuperscriptYSize = stream.GetShort();
+    os2.ySuperscriptXOffset = stream.GetShort();
+    os2.ySuperscriptYOffset = stream.GetShort();
+    os2.yStrikeoutSize = stream.GetShort();
+    os2.yStrikeoutPosition = stream.GetShort();
+    os2.sFamilyClass = stream.GetShort();
+
+    os2.panose = new Array(10);
+    os2.panose[0] = stream.GetUChar();
+    os2.panose[1] = stream.GetUChar();
+    os2.panose[2] = stream.GetUChar();
+    os2.panose[3] = stream.GetUChar();
+    os2.panose[4] = stream.GetUChar();
+    os2.panose[5] = stream.GetUChar();
+    os2.panose[6] = stream.GetUChar();
+    os2.panose[7] = stream.GetUChar();
+    os2.panose[8] = stream.GetUChar();
+    os2.panose[9] = stream.GetUChar();
+
+    os2.ulUnicodeRange1 = stream.GetULong();
+    os2.ulUnicodeRange2 = stream.GetULong();
+    os2.ulUnicodeRange3 = stream.GetULong();
+    os2.ulUnicodeRange4 = stream.GetULong();
+
+    os2.achVendID = new Array(4);
+    os2.achVendID[0] = stream.GetUChar();
+    os2.achVendID[1] = stream.GetUChar();
+    os2.achVendID[2] = stream.GetUChar();
+    os2.achVendID[3] = stream.GetUChar();
+
+    os2.fsSelection = stream.GetUShort();
+    os2.usFirstCharIndex = stream.GetUShort();
+    os2.usLastCharIndex = stream.GetUShort();
+    os2.sTypoAscender = stream.GetShort();
+    os2.sTypoDescender = stream.GetShort();
+    os2.sTypoLineGap = stream.GetShort();
+    os2.usWinAscent = stream.GetUShort();
+    os2.usWinDescent = stream.GetUShort();
+
+    os2.ulCodePageRange1 = 0;
+    os2.ulCodePageRange2 = 0;
+    os2.sxHeight         = 0;
+    os2.sCapHeight       = 0;
+    os2.usDefaultChar    = 0;
+    os2.usBreakChar      = 0;
+    os2.usMaxContext     = 0;
+
+    stream.ExitFrame();
+
+    if (os2.version >= 0x0001)
+    {
+        error = stream.EnterFrame(8);
+        if (error != 0)
+            return error;
+
+        os2.ulCodePageRange1 = stream.GetULong();
+        os2.ulCodePageRange2 = stream.GetULong();
+
+        if (os2.version >= 0x0002)
+        {
+            error = stream.EnterFrame(10);
+            if (error != 0)
+                return error;
+
+            os2.sxHeight         = stream.GetShort();
+            os2.sCapHeight       = stream.GetShort();
+            os2.usDefaultChar    = stream.GetUShort();
+            os2.usBreakChar      = stream.GetUShort();
+            os2.usMaxContext     = stream.GetUShort();
+        }
+    }
+
+    return error;
+}
+function tt_face_load_post(face, stream)
+{
+    var error = 0;
+
+    face.goto_table(face, FT_Common.TTAG_post, stream);
+    error = FT_Error;
+    if (error != 0)
+        return error;
+
+    error = stream.EnterFrame(32);
+    if (error != 0)
+        return error;
+
+    var post = face.postscript;
+    post.FormatType = stream.GetLong();
+    post.italicAngle = stream.GetLong();
+    post.underlinePosition = stream.GetShort();
+    post.underlineThickness = stream.GetShort();
+    post.isFixedPitch = stream.GetULong();
+    post.minMemType42 = stream.GetULong();
+    post.maxMemType42 = stream.GetULong();
+    post.minMemType1 = stream.GetULong();
+    post.maxMemType1 = stream.GetULong();
+
+    stream.ExitFrame();
+
+    return error;
+}
+function tt_face_load_pclt(face, stream)
+{
+    var error = 0;
+    var pclt = face.pclt;
+
+    /* optional table */
+    face.goto_table(face, FT_Common.TTAG_PCLT, stream);
+	error = FT_Error;
+    if (error != 0)
+        return error;
+
+    error = stream.EnterFrame(54);
+    if (error != 0)
+        return error;
+
+    pclt.Version = stream.GetULong();
+    pclt.FontNumber = stream.GetULong();
+    pclt.Pitch = stream.GetUShort();
+    pclt.xHeight = stream.GetUShort();
+    pclt.Style = stream.GetUShort();
+    pclt.TypeFamily = stream.GetUShort();
+    pclt.CapHeight = stream.GetUShort();
+    pclt.SymbolSet = stream.GetUShort();
+    pclt.TypeFace = stream.GetString1(16);
+    pclt.CharacterComplement = stream.GetString1(8);
+    pclt.FileName = stream.GetString1(6);
+    pclt.StrokeWeight = stream.GetChar();
+    pclt.WidthType = stream.GetChar();
+    pclt.SerifStyle = stream.GetUChar();
+    pclt.Reserved = stream.GetUChar();
+
+    stream.ExitFrame();
+    return error;
+}
+function tt_face_load_gasp(face, stream)
+{
+    var error = 0;
+    face.goto_table(face, FT_Common.TTAG_gasp, stream);
+    error = FT_Error;
+    if (error != 0)
+        return error;
+
+    error = stream.EnterFrame(4);
+    if (error != 0)
+        return error;
+
+    face.gasp.version   = stream.GetUShort();
+    face.gasp.numRanges = stream.GetUShort();
+
+    stream.ExitFrame();
+
+    if (face.gasp.version >= 2)
+    {
+        face.gasp.numRanges = 0;
+        return FT_Common.FT_Err_Invalid_Table;
+    }
+
+    var num_ranges = face.gasp.numRanges;
+    face.gasp.gaspRanges = new Array(num_ranges);
+    var ranges = face.gasp.gaspRanges;
+
+    error = stream.EnterFrame(num_ranges * 4);
+    if (error != 0)
+        return error;
+
+    for (var i = 0; i < num_ranges; i++)
+    {
+        ranges[i] = new TT_GaspRange();
+        ranges[i].maxPPEM = stream.GetUShort();
+        ranges[i].gaspFlag = stream.GetUShort();
+    }
+
+    stream.ExitFrame();
+    return error;
+}
+/******************************************************************************/
+// ttmtx
+/******************************************************************************/
+function tt_face_load_hmtx(face, stream, isvertical)
+{
+    var error = 0;
+
+    var table_len = 0;
+    var num_shorts = 0;
+    var num_longs = 0;
+    var num_shorts_checked = 0;
+
+    var lm = null;
+
+    if (isvertical == 1)
+    {
+        table_len = face.goto_table(face, FT_Common.TTAG_vmtx, stream);
+        error = FT_Error;
+        if (error != 0)
+            return error;
+
+        num_longs = face.vertical.number_Of_VMetrics;
+        if (num_longs > (table_len / 4))
+            num_longs = parseInt(table_len / 4);
+
+        face.vertical.number_Of_VMetrics = 0;
+
+        lm = face.vertical;
+    }
+    else
+    {
+        table_len = face.goto_table(face, FT_Common.TTAG_hmtx, stream);
+        error = FT_Error;
+        if (error != 0)
+            return error;
+
+        num_longs = face.horizontal.number_Of_HMetrics;
+        if (num_longs > (table_len / 4))
+            num_longs = parseInt(table_len / 4);
+
+        face.horizontal.number_Of_HMetrics = 0;
+
+        lm = face.horizontal;
+    }
+
+    /* never trust derived values */
+    num_shorts         = face.max_profile.numGlyphs - num_longs;
+    num_shorts_checked = parseInt((table_len - num_longs * 4) / 2);
+
+    if (num_longs > 0)
+        lm.long_metrics = new Array(num_longs);
+    if (num_shorts > 0)
+        lm.short_metrics = new Array(num_shorts);
+
+    var longs  = lm.long_metrics;
+    var shorts = lm.short_metrics;
+
+    if (num_shorts < 0)
+        num_shorts = 0;
+
+    error = stream.EnterFrame(table_len);
+
+    for (var i = 0; i < num_longs; i++)
+    {
+        longs[i] = new TT_LongMetricsRec();
+        longs[i].advance = stream.GetUShort();
+        longs[i].bearing = stream.GetShort();
+    }
+
+    var count_s = Math.min(num_shorts, num_shorts_checked);
+    for (var i = 0; i < count_s; i++)
+    {
+        shorts[i] = stream.GetShort();
+    }
+
+    if (num_shorts > num_shorts_checked && num_shorts_checked > 0)
+    {
+        var ind = shorts.length;
+        var val = shorts[num_shorts_checked - 1];
+        for (var i = ind; i < num_shorts; i++)
+            shorts[i] = val;
+    }
+
+    stream.ExitFrame();
+
+    if (isvertical)
+        face.vertical.number_Of_VMetrics = num_longs;
+    else
+        face.horizontal.number_Of_HMetrics = num_longs;
+
+    return error;
+}
+function tt_face_load_hhea(face, stream, isvertical)
+{
+    var error = 0;
+    var header = null;
+    if (1 == isvertical)
+    {
+        face.goto_table(face, FT_Common.TTAG_vhea, stream);
+        error = FT_Error;
+        if (error != 0)
+            return error;
+
+        header = face.vertical;
+    }
+    else
+    {
+        face.goto_table(face, FT_Common.TTAG_hhea, stream);
+        error = FT_Error;
+        if (error != 0)
+            return error;
+
+        header = face.horizontal;
+    }
+
+    error = stream.EnterFrame(36);
+    if (error != 0)
+        return error;
+
+    if (0 == isvertical)
+    {
+        header.Version = stream.GetULong();
+        header.Ascender = stream.GetShort();
+        header.Descender = stream.GetShort();
+        header.Line_Gap = stream.GetShort();
+
+        header.advance_Width_Max = stream.GetUShort();
+
+        header.min_Left_Side_Bearing = stream.GetShort();
+        header.min_Right_Side_Bearing = stream.GetShort();
+        header.xMax_Extent = stream.GetShort();
+        header.caret_Slope_Rise = stream.GetShort();
+        header.caret_Slope_Run = stream.GetShort();
+        header.caret_Offset = stream.GetShort();
+
+        header.Reserved1 = stream.GetShort();
+        header.Reserved2 = stream.GetShort();
+        header.Reserved3 = stream.GetShort();
+        header.Reserved4 = stream.GetShort();
+
+        header.metric_Data_Format = stream.GetShort();
+        header.number_Of_HMetrics = stream.GetUShort();
+    }
+    else
+    {
+        header.Version = stream.GetULong();
+        header.Ascender = stream.GetShort();
+        header.Descender = stream.GetShort();
+        header.Line_Gap = stream.GetShort();
+
+        header.advance_Height_Max = stream.GetUShort();
+
+        header.min_Top_Side_Bearing = stream.GetShort();
+        header.min_Bottom_Side_Bearing = stream.GetShort();
+        header.yMax_Extent = stream.GetShort();
+        header.caret_Slope_Rise = stream.GetShort();
+        header.caret_Slope_Run = stream.GetShort();
+        header.caret_Offset = stream.GetShort();
+
+        header.Reserved1 = stream.GetShort();
+        header.Reserved2 = stream.GetShort();
+        header.Reserved3 = stream.GetShort();
+        header.Reserved4 = stream.GetShort();
+
+        header.metric_Data_Format = stream.GetShort();
+        header.number_Of_VMetrics = stream.GetUShort();
+    }
+
+    stream.ExitFrame();
+
+    header.long_metrics  = null;
+    header.short_metrics = null;
+
+    return error;
+}
+function tt_face_get_metrics(face, vertical, gindex)
+{
+    var header = (vertical == 1) ? face.vertical : face.horizontal;
+
+    var longs_m = null;
+    var k = header.number_Of_HMetrics;
+
+    var v1 = 0;
+    var v2 = 0;
+    if (k == 0 || null == header.long_metrics || gindex >= face.max_profile.numGlyphs)
+        return { bearing:0,advance:0 };
+
+    if (gindex < k)
+    {
+        longs_m = header.long_metrics[gindex];
+        v1 = longs_m.bearing;
+        v2 = longs_m.advance;
+    }
+    else
+    {
+        v1 = header.short_metrics[gindex - k];
+        v2 = header.long_metrics[k - 1].advance;
+    }
+    return { bearing:v1,advance:v2 };
+}
+/******************************************************************************/
+// ttpost
+/******************************************************************************/
+function load_format_20(face, stream, post_limit)
+{
+    var error = 0;
+
+    var num_glyphs = stream.ReadUShort();
+    error = FT_Error;
+    if (error != 0)
+        return error;
+
+    if (num_glyphs > face.max_profile.numGlyphs)
+        return FT_Common.FT_Err_Invalid_File_Format;
+
+    error = stream.EnterFrame(num_glyphs*2);
+    if (error != 0)
+        return error;
+
+    var glyph_indices = new Array(num_glyphs);
+    for (var n=0;n<num_glyphs;n++)
+        glyph_indices[n] = stream.GetUShort();
+    stream.ExitFrame();
+
+    var num_names = 0;
+    for ( n = 0; n < num_glyphs; n++ )
+    {
+        var idx = glyph_indices[n];
+        if (idx >= 258)
+        {
+            idx -= 257;
+            if (idx > num_names)
+                num_names = idx;
+        }
+    }
+
+    var name_strings = new Array(num_names);
+    var n=0;
+    for (n = 0; n < num_names; n++)
+    {
+        var len = 0;
+        if (stream.pos >= post_limit)
+            break;
+        else
+        {
+            len = stream.ReadUChar();
+            error = FT_Error;
+            if (error != 0)
+                return error;
+        }
+
+        if (len > post_limit || stream.pos > post_limit - len)
+        {
+            len = Math.max(0, post_limit - stream.pos);
+        }
+
+        name_strings[n] = stream.ReadString1(len);
+    }
+
+    if (n < num_names)
+    {
+        for (; n < num_names; n++)
+            name_strings[n] = "";
+    }
+
+    var table = face.postscript_names.names.format_20;
+    table.num_glyphs    = num_glyphs;
+    table.num_names     = num_names;
+    table.glyph_indices = glyph_indices;
+    table.glyph_names   = name_strings;
+
+    return 0;
+}
+function load_format_25(face, stream, post_limit)
+{
+    var num_glyphs = stream.ReadUShort();
+    var error = FT_Error;
+    if (error != 0)
+        return error;
+
+    if (num_glyphs > face.max_profile.numGlyphs || num_glyphs > 258)
+        return FT_Common.FT_Err_Invalid_File_Format;
+
+    var offset_table = g_memory.Alloc(num_glyphs);
+    error = stream.Read(offset_table,num_glyphs);
+
+    if (error != 0)
+        return error;
+
+    for (var n = 0; n < num_glyphs; n++ )
+    {
+        var idx = n + offset_table[n];
+        if ( idx < 0 || idx > num_glyphs )
+            return FT_Common.FT_Err_Invalid_File_Format;
+    }
+
+    var table = face.postscript_names.names.format_25;
+    table.num_glyphs = num_glyphs;
+    table.offsets = offset_table;
+    return 0;
+}
+function load_post_names(face)
+{
+    var stream = face.stream;
+    var post_len = face.goto_table(face, FT_Common.TTAG_post, stream);
+    var error = FT_Error;
+    if (error != 0)
+        return error;
+
+    var post_limit = stream.pos + post_len;
+    var format = face.postscript.FormatType;
+
+    error = stream.Skip(32);
+    if (error != 0)
+        return error;
+
+    if (format == 0x00020000)
+        error = load_format_20(face, stream, post_limit);
+    else if (format == 0x00028000)
+        error = load_format_25(face, stream, post_limit);
+    else
+        error = FT_Common.FT_Err_Invalid_File_Format;
+
+    face.postscript_names.loaded = 1;
+    return error;
+}
+function tt_face_free_ps_names(face)
+{
+    var names = face.postscript_names;
+
+    if (names.loaded == 1)
+    {
+        var format = face.postscript.FormatType;
+        if (format == 0x00020000)
+        {
+            var table = names.names.format_20;
+
+            table.glyph_indices = null;
+            table.num_glyphs = 0;
+
+            table.glyph_names = null;
+            table.num_names = 0;
+        }
+        else if (format == 0x00028000)
+        {
+            var table = names.names.format_25;
+            table.offsets = null;
+            table.num_glyphs = 0;
+        }
+    }
+    names.loaded = 0;
+}
+function tt_face_get_ps_name(face, idx)
+{
+    if (null == face)
+    {
+        FT_Error = FT_Common.FT_Err_Invalid_Face_Handle;
+        return "";
+    }
+    if (idx >= face.max_profile.numGlyphs)
+    {
+        FT_Error = FT_Common.FT_Err_Invalid_Glyph_Index;
+        return "";
+    }
+    var psnames = face.psnames;
+    if (null == psnames)
+    {
+        FT_Error = FT_Common.FT_Err_Unimplemented_Feature;
+        return "";
+    }
+
+    FT_Error = 0;
+    var names = face.postscript_names;
+    var format = face.postscript.FormatType;
+
+    var res = psnames.macintosh_name(0);
+    if (format == 0x00010000)
+    {
+        if (idx < 258)
+            res = psnames.macintosh_name(idx);
+    }
+    else if (format == 0x00020000)
+    {
+        var table = names.names.format_20;
+        if (0 == names.loaded)
+        {
+            FT_Error = load_post_names(face);
+            if (FT_Error != 0)
+                return res;
+        }
+
+        if (idx < table.num_glyphs)
+        {
+            var name_index = table.glyph_indices[idx];
+
+            if (name_index < 258)
+                res = psnames.macintosh_name(name_index);
+            else
+                res = table.glyph_names[name_index - 258];
+        }
+    }
+    else if (format == 0x00028000)
+    {
+        var table = names.names.format_25;
+        if (0 == names.loaded)
+        {
+            FT_Error = load_post_names( face );
+            if (FT_Error != 0)
+                return res;
+        }
+
+        if (idx < table.num_glyphs)
+        {
+            idx += table.offsets[idx];
+            res = psnames.macintosh_name(idx);
+        }
+    }
+    return res;
+}
+/******************************************************************************/
+// ttsbit
+/******************************************************************************/
+function blit_sbit(target, _source, line_bits, byte_padded, x_offset, y_offset, source_height)
+{
+    var line_incr = target.pitch;
+    var line_buff = target.buffer;
+
+    var source = dublicate_pointer(_source);
+
+    if (line_incr < 0)
+        line_buff -= line_incr * (target.rows - 1);
+
+    line_buff.pos += (x_offset >> 3) + y_offset * line_incr;
+
+    var acc    = 0;
+    var loaded = 0;
+
+    for (var height = source_height; height > 0; height--)
+    {
+        var cur = dublicate_pointer(line_buff);
+        var count = line_bits;
+        var shift = (x_offset & 7);
+        var space = (8 - shift);
+
+        if ( count >= 8 )
+        {
+            count -= 8;
+            do
+            {
+                if (loaded < 8)
+                {
+                    acc |= (source.data[source.pos++] << ( 8 - loaded));
+                    loaded += 8;
+                }
+
+                val = (0xFF & (acc >>> 8));
+                if (shift != 0)
+                {
+                    cur.data[cur.pos] |= (0xFF & (val >>> shift));
+                    cur.data[cur.pos+1] |= (0xFF & (val << space));
+                }
+                else
+                    cur.data[cur.pos] |= val;
+
+                cur.pos++;
+                acc <<= 8;
+                loaded -= 8;
+                count  -= 8;
+            } while (count >= 0);
+            count += 8;
+        }
+
+        if (count > 0)
+        {
+            if (loaded < count)
+            {
+                acc |= ((source.data[source.pos++]) << (8 - loaded));
+                loaded += 8;
+            }
+
+            var val = ((0xFF&(acc >>> 8)) & ~(0xFF >>> count));
+            cur.data[cur.pos] |= (0xFF & (val >>> shift));
+
+            if (count > space)
+                cur.data[cur.pos+1] |= (0xFF & (val << space));
+
+            acc <<= count;
+            loaded -= count;
+        }
+
+        if ( byte_padded )
+        {
+            acc    = 0;
+            loaded = 0;
+        }
+        line_buff.pos += line_incr;
+    }
+}
+function Load_SBit_Const_Metrics(range, stream)
+{
+    range.image_size = stream.ReadULong();
+    if (FT_Error != 0)
+        return FT_Error;
+
+    var error = stream.EnterFrame(8);
+    if (0 == error)
+    {
+        var metrics = range.metrics;
+
+        metrics.height = stream.GetUChar();
+        metrics.width = stream.GetUChar();
+
+        metrics.horiBearingX = stream.GetChar();
+        metrics.horiBearingY = stream.GetChar();
+        metrics.horiAdvance = stream.GetUChar();
+
+        metrics.vertBearingX = stream.GetChar();
+        metrics.vertBearingY = stream.GetChar();
+        metrics.vertAdvance = stream.GetUChar();
+    }
+    stream.ExitFrame();
+    return error;
+}
+function Load_SBit_Range_Codes(range, stream, load_offsets)
+{
+    var count = stream.ReadULong();
+    if (FT_Error != 0)
+        return FT_Error;
+
+    range.num_glyphs = count;
+
+    var size = 2 * count;
+    if (load_offsets != 0)
+    {
+        range.glyph_offsets = new Array(count);
+        size *= 2;
+    }
+
+    var error = stream.EnterFrame(size);
+    if (0 != error)
+        return error;
+
+    range.glyph_codes = new Array(count);
+
+    for (var n = 0; n < count; n++)
+    {
+        range.glyph_codes[n] = stream.GetUShort();
+
+        if (load_offsets != 0)
+            range.glyph_offsets[n] = range.image_offset + stream.GetUShort();
+    }
+
+    stream.ExitFrame();
+    return error;
+}
+function Load_SBit_Range(range, stream)
+{
+    var error = 0;
+
+    switch(range.index_format)
+    {
+    case 1:
+    case 3:
+        if (range.last_glyph < range.first_glyph)
+            return FT_Common.FT_Err_Invalid_File_Format;
+
+        var num_glyphs = range.last_glyph - range.first_glyph + 1;
+        range.num_glyphs = num_glyphs;
+        num_glyphs++;
+
+        var large = (range.index_format == 1) ? 1 : 0;
+        var size_elem = large ? 4 : 2;
+
+        error = stream.EnterFrame(num_glyphs*size_elem);
+        if (error != 0)
+            return error;
+        range.glyph_offsets = new Array(num_glyphs);
+
+        for (var n = 0; n < num_glyphs; n++)
+            range.glyph_offsets[n] = (range.image_offset + ((large == 1) ? stream.GetULong() : stream.GetUShort()));
+        stream.ExitFrame();
+        break;
+
+    case 2:
+        error = Load_SBit_Const_Metrics(range, stream);
+        break;
+    case 4:
+        error = Load_SBit_Range_Codes(range, stream, 1);
+        break;
+    case 5:
+        error = Load_SBit_Const_Metrics(range, stream);
+        if (error != 0)
+            error = Load_SBit_Range_Codes(range, stream, 0);
+        break;
+    default:
+        error = FT_Common.FT_Err_Invalid_File_Format;
+    }
+    return error;
+}
+
+function tt_face_load_eblc(face, stream)
+{
+    var error = 0;
+
+    face.num_sbit_strikes = 0;
+    face.goto_table(face, FT_Common.TTAG_EBLC, stream);
+    if (FT_Error != 0)
+        face.goto_table(face, FT_Common.TTAG_bloc, stream);
+    error = FT_Error;
+    if (error != 0)
+        return error;
+
+    var table_base = stream.pos;
+    error = stream.EnterFrame(8);
+    if (error != 0)
+        return error;
+
+    var version = stream.GetLong();
+    var num_strikes = stream.GetULong();
+
+    stream.ExitFrame();
+
+    if (version != 0x00020000 || num_strikes >= 0x10000)
+        return FT_Common.FT_Err_Invalid_File_Format;
+
+    face.sbit_strikes = new Array(num_strikes);
+    face.num_sbit_strikes = num_strikes;
+    
+    for (var i = 0; i < num_strikes; i++)
+        face.sbit_strikes[i] = new TT_SBit_StrikeRec();
+
+    var strike_ind = 0;
+    var count  = num_strikes;
+
+    error = stream.EnterFrame(48*num_strikes);
+    if (error != 0)
+        return error;
+
+    while ( count > 0 )
+    {
+        var strike = face.sbit_strikes[strike_ind];
+
+        strike.ranges_offset = stream.GetULong();
+        stream.cur += 4;
+        strike.num_ranges = stream.GetULong();
+        strike.color_ref = stream.GetULong();
+
+        var h = strike.hori;
+        var v = strike.vert;
+
+        h.ascender = stream.GetChar();
+        h.descender = stream.GetChar();
+        h.max_width = stream.GetUChar();
+        h.caret_slope_numerator = stream.GetChar();
+        h.caret_slope_denominator = stream.GetChar();
+        h.caret_offset = stream.GetChar();
+        h.min_origin_SB = stream.GetChar();
+        h.min_advance_SB = stream.GetChar();
+        h.max_before_BL = stream.GetChar();
+        h.min_after_BL = stream.GetChar();
+        h.pads1 = stream.GetChar();
+        h.pads2 = stream.GetChar();
+
+        v.ascender = stream.GetChar();
+        v.descender = stream.GetChar();
+        v.max_width = stream.GetUChar();
+        v.caret_slope_numerator = stream.GetChar();
+        v.caret_slope_denominator = stream.GetChar();
+        v.caret_offset = stream.GetChar();
+        v.min_origin_SB = stream.GetChar();
+        v.min_advance_SB = stream.GetChar();
+        v.max_before_BL = stream.GetChar();
+        v.min_after_BL = stream.GetChar();
+        v.pads1 = stream.GetChar();
+        v.pads2 = stream.GetChar();
+
+        strike.start_glyph = stream.GetUShort();
+        strike.end_glyph = stream.GetUShort();
+        strike.x_ppem = stream.GetUChar();
+        strike.y_ppem = stream.GetUChar();
+        strike.bit_depth = stream.GetUChar();
+        strike.flags = stream.GetChar();
+
+        count--;
+        strike_ind++;
+    }
+    
+    stream.ExitFrame();
+    strike_ind = 0;
+    count  = num_strikes;
+
+    while ( count > 0 )
+    {
+        var strike = face.sbit_strikes[strike_ind];
+        var range;
+        var count2 = strike.num_ranges;
+
+        error = stream.Seek(table_base + strike.ranges_offset);
+        if (0 != error)
+            return error;
+
+        error = stream.EnterFrame(strike.num_ranges * 8);
+        if (0 != error)
+            return error;
+
+        strike.sbit_ranges = new Array(strike.num_ranges);
+        var __count = strike.num_ranges;
+        for (var i = 0; i < __count; i++)
+            strike.sbit_ranges[i] = new TT_SBit_RangeRec();
+
+        var range_ind = 0;
+        while ( count2 > 0 )
+        {
+            range = strike.sbit_ranges[range_ind];
+            range.first_glyph  = stream.GetUShort();
+            range.last_glyph   = stream.GetUShort();
+            range.table_offset = table_base + strike.ranges_offset + stream.GetULong();
+            count2--;
+            range_ind++;
+        }
+
+        stream.ExitFrame();
+
+        count2 = strike.num_ranges;
+        range_ind = 0;
+        while (count2 > 0)
+        {
+            range = strike.sbit_ranges[range_ind];
+            error = stream.Seek(range.table_offset);
+            if (error != 0)
+                return error;
+            error = stream.EnterFrame(8);
+            if (error != 0)
+                return error;
+
+            range.index_format = stream.GetUShort();
+            range.image_format = stream.GetUShort();
+            range.image_offset = stream.GetULong();
+
+            stream.ExitFrame();
+
+            error = Load_SBit_Range(range, stream);
+            if (error != 0)
+                return error;
+
+            count2--;
+            range_ind++;
+        }
+
+        count--;
+        strike_ind++;
+    }
+
+    return error;
+}
+function tt_face_free_eblc(face)
+{
+    face.sbit_strikes = null;
+    face.num_sbit_strikes = 0;
+}
+function tt_face_set_sbit_strike(face, req)
+{
+    return FT_Match_Size(face, req, 0);
+}
+function tt_face_load_strike_metrics(face, strike_index, metrics)
+{
+    if (strike_index >= face.num_sbit_strikes)
+      return FT_Common.FT_Err_Invalid_Argument;
+
+    var strike = face.sbit_strikes[strike_index];
+
+    metrics.x_ppem = strike.x_ppem;
+    metrics.y_ppem = strike.y_ppem;
+
+    metrics.ascender  = strike.hori.ascender << 6;
+    metrics.descender = strike.hori.descender << 6;
+
+    metrics.max_advance = (strike.hori.min_origin_SB + strike.hori.max_width + strike.hori.min_advance_SB) << 6;
+
+    metrics.height = metrics.ascender - metrics.descender;
+
+    return 0;
+}
+function find_sbit_range(glyph_index, strike)
+{
+    FT_Error = 0;
+    var range = null;
+    var glyph_offset = 0;
+
+    if (glyph_index < strike.start_glyph || glyph_index > strike.end_glyph)
+    {
+        FT_Error = FT_Common.FT_Err_Invalid_Argument;
+    }
+
+    var range_ind = 0;
+    var range_limit = strike.num_ranges;
+
+    for ( ; range_ind < range_limit; range_ind++)
+    {
+        range = strike.sbit_ranges[range_ind];
+        if (glyph_index >= range.first_glyph && glyph_index <= range.last_glyph)
+        {
+            var delta = (glyph_index - range.first_glyph);
+
+            switch (range.index_format)
+            {
+            case 1:
+            case 3:
+                glyph_offset = range.glyph_offsets[delta];
+                break;
+            case 2:
+                glyph_offset = range.image_offset + range.image_size * delta;
+                break;
+            case 4:
+            case 5:
+                for (var n = 0; n < range.num_glyphs; n++)
+                {
+                    if (range.glyph_codes[n] == glyph_index)
+                    {
+                        if (range.index_format == 4)
+                            glyph_offset = range.glyph_offsets[n];
+                        else
+                            glyph_offset = range.image_offset + n * range.image_size;
+                        return {range:range,glyph_offset:glyph_offset};
+                    }
+                }
+                break;
+            default:
+                break;
+            }
+
+            return {range:range,glyph_offset:glyph_offset};
+        }
+    }
+
+    FT_Error = FT_Common.FT_Err_Invalid_Argument;
+    return {range:range,glyph_offset:glyph_offset};
+}
+function tt_find_sbit_image(face, glyph_index, strike_index)
+{
+    FT_Error = 0;
+    if (null == face.sbit_strikes || (face.num_sbit_strikes <= strike_index))
+    {
+        FT_Error = FT_Common.FT_Err_Invalid_Argument;
+        return {strike:null,range:null,glyph_offset:0};
+    }
+
+    var strike = face.sbit_strikes[strike_index];
+    var ret = find_sbit_range(glyph_index, strike);
+    if (FT_Error != 0)
+    {
+        FT_Error = FT_Common.FT_Err_Invalid_Argument;
+        return {strike:null,range:null,glyph_offset:0};
+    }
+
+    return {strike:strike,range:ret.range,glyph_offset:ret.glyph_offset};
+}
+function tt_load_sbit_metrics(stream, range, metrics)
+{
+    var error = 0;
+    switch (range.image_format)
+    {
+    case 1:
+    case 2:
+    case 8:
+        error = stream.EnterFrame(5);
+        if (error != 0)
+            return error;
+
+        metrics.height       = stream.GetUChar();
+        metrics.width        = stream.GetUChar();
+        metrics.horiBearingX = stream.GetChar();
+        metrics.horiBearingY = stream.GetChar();
+        metrics.horiAdvance  = stream.GetUChar();
+
+        metrics.vertBearingX = 0;
+        metrics.vertBearingY = 0;
+        metrics.vertAdvance  = 0;
+
+        stream.ExitFrame();
+        break;
+
+    case 6:
+    case 7:
+    case 9:
+        error = stream.EnterFrame(8);
+        if (error != 0)
+            return error;
+
+        metrics.height       = stream.GetUChar();
+        metrics.width        = stream.GetUChar();
+        metrics.horiBearingX = stream.GetChar();
+        metrics.horiBearingY = stream.GetChar();
+        metrics.horiAdvance  = stream.GetUChar();
+
+        metrics.vertBearingX = stream.GetChar();
+        metrics.vertBearingY = stream.GetChar();
+        metrics.vertAdvance  = stream.GetUChar();
+
+        stream.ExitFrame();
+        break;
+    case 5:
+    default:
+        if (range.index_format == 2 || range.index_format == 5)
+        {
+            var s = range.metrics;
+            metrics.height       = s.height;
+            metrics.width        = s.width;
+            metrics.horiBearingX = s.horiBearingX;
+            metrics.horiBearingY = s.horiBearingY;
+            metrics.horiAdvance  = s.horiAdvance;
+
+            metrics.vertBearingX = s.vertBearingX;
+            metrics.vertBearingY = s.vertBearingY;
+            metrics.vertAdvance  = s.vertAdvance;
+        }
+        else
+            return FT_Common.FT_Err_Invalid_File_Format;
+    }
+
+    return error;
+}
+function crop_bitmap(map, metrics)
+{
+    var rows, count;
+    var line_len;
+    var line = new CPointer();
+    line.data = map.buffer.data;
+    var d = line.data;
+
+    // 1
+    line.pos = map.buffer.pos;
+    rows = map.rows;
+    line_len = map.pitch;
+
+    var is_go_to = 0;
+    for (count = 0; count < rows; count++)
+    {
+        for (var cur=0; cur < line_len; cur++)
+        {
+            if (d[line.pos+cur] != 0)
+            {
+                is_go_to = 1;
+                break;
+            }
+        }
+        if (1 == is_go_to)
+            break;
+        line.pos += line_len;
+    }
+
+    if (count >= rows)
+    {
+        map.width      = 0;
+        map.rows       = 0;
+        map.pitch      = 0;
+        map.pixel_mode = FT_Common.FT_PIXEL_MODE_MONO;
+    }
+
+    if ( count > 0 )
+    {
+        line.pos = map.buffer.pos;
+        var pos1 = line.pos;
+        var pos2 = line.pos + count * line_len;
+
+        var c = (rows - count)*line_len;
+
+        for (var i=0;i<c;i++)
+            d[pos1+i] = d[pos2+i];
+
+        metrics.height       = (metrics.height - count)&0xFF;
+        metrics.horiBearingY = (metrics.horiBearingY - count);
+        metrics.vertBearingY = (metrics.vertBearingY - count);
+
+        map.rows -= count;
+        rows -= count;
+    }
+
+    //2
+    is_go_to = 0;
+    line.pos = (rows - 1) * line_len;
+
+    for (count = 0; count < rows; count++)
+    {
+        for (var cur=0; cur < line_len; cur++)
+        {
+            if (d[line.pos+cur] != 0)
+            {
+                is_go_to = 1;
+                break;
+            }
+        }
+        if (is_go_to == 1)
+            break;
+
+        line.pos -= line_len;
+    }
+
+    if (count > 0)
+    {
+        metrics.height = (metrics.height - count);
+        rows -= count;
+        map.rows -= count;
+    }
+
+    // 3
+    is_go_to = 0;
+    do
+    {
+        line.pos = map.buffer.pos;
+        var limit = line.pos + rows * line_len;
+
+        for (; line.pos < limit; line.pos += line_len)
+        {
+            if ((d[line.pos] & 0x80) != 0)
+            {
+                is_go_to = 1;
+                break;
+            }
+        }
+        if (1 == is_go_to)
+            break;
+
+        line.pos = map.buffer.pos;
+        limit = line.pos + rows * line_len;
+
+        for (; line.pos < limit; line.pos += line_len)
+        {
+            var width = map.width;
+            var cur = line.pos;
+            var old = 0xFF & (d[cur] << 1);
+            for (var n = 8; n < width; n += 8)
+            {
+                var val = d[cur+1];
+                d[cur] = 0xFF & (old | (val >>> 7));
+                old = 0xFF & (val << 1);
+                cur++;
+            }
+            d[cur] = old;
+        }
+
+        map.width--;
+        metrics.horiBearingX++;
+        metrics.vertBearingX++;
+        metrics.width--;
+
+    } while (map.width > 0);
+
+    // 4
+    do
+    {
+        var right = map.width - 1;
+        line.pos = (right >>> 3);
+        var limit = line.pos + rows * line_len;
+        var mask = 0xFF & (0x80 >>> (right & 7));
+
+        for ( ; line.pos < limit; line.pos += line_len)
+            if ((d[line.pos] & mask)!=0)
+                return;
+
+        map.width--;
+        metrics.width--;
+
+    } while ( map.width > 0 );
+}
+function Load_SBit_Single(map, x_offset, y_offset, pix_bits, image_format, metrics, stream)
+{
+    var error = 0;
+    if (x_offset < 0 || x_offset + metrics.width > map.width || y_offset < 0 || y_offset + metrics.height > map.rows)
+        return FT_Common.FT_Err_Invalid_Argument;
+
+    var glyph_width = metrics.width;
+    var glyph_height = metrics.height;
+    var glyph_size;
+    var line_bits = pix_bits * glyph_width;
+    var pad_bytes = 0;
+
+    switch ( image_format )
+    {
+        case 1:  /* byte-padded formats */
+        case 6:
+            var line_length;
+            switch ( pix_bits )
+            {
+                case 1:
+                    line_length = (glyph_width + 7) >>> 3;
+                    break;
+                case 2:
+                    line_length = (glyph_width + 3) >>> 2;
+                    break;
+                case 4:
+                    line_length = (glyph_width + 1) >>> 1;
+                    break;
+                default:
+                    line_length = glyph_width;
+            }
+
+            glyph_size = glyph_height * line_length;
+            pad_bytes  = 1;
+            break;
+      case 2:
+      case 5:
+      case 7:
+            line_bits  = glyph_width * pix_bits;
+            glyph_size = (glyph_height * line_bits + 7) >>> 3;
+            break;
+      default:
+            return FT_Common.FT_Err_Invalid_File_Format;
+    }
+
+    error = stream.EnterFrame(glyph_size);
+    if (0 != error)
+        return error;
+
+    var s = new CPointer();
+    s.data = stream.data;
+    s.pos = stream.cur;
+    blit_sbit(map, s, line_bits, pad_bytes, x_offset * pix_bits, y_offset, metrics.height);
+
+    stream.ExitFrame();
+    return error;
+}
+function Load_SBit_Image(strike, range, ebdt_pos, glyph_offset, slot, x_offset, y_offset, stream, metrics, depth)
+{
+    var map = slot.bitmap;
+    var error = stream.Seek(ebdt_pos + glyph_offset);
+    if (0 != error)
+        return error;
+
+    error = tt_load_sbit_metrics(stream, range, metrics);
+    if (error != 0)
+        return 0;
+
+    if (depth == 0)
+    {
+        map.width = metrics.width;
+        map.rows  = metrics.height;
+
+        switch (strike.bit_depth)
+        {
+        case 1:
+            map.pixel_mode = FT_Common.FT_PIXEL_MODE_MONO;
+            map.pitch = (map.width + 7) >>> 3;
+            break;
+        case 2:
+            map.pixel_mode = FT_Common.FT_PIXEL_MODE_GRAY2;
+            map.pitch = (map.width + 3) >>> 2;
+            break;
+        case 4:
+            map.pixel_mode = FT_Common.FT_PIXEL_MODE_GRAY4;
+            map.pitch = (map.width + 1) >>> 1;
+            break;
+        case 8:
+            map.pixel_mode = FT_Common.FT_PIXEL_MODE_GRAY;
+            map.pitch = map.width;
+            break;
+        default:
+            return FT_Common.FT_Err_Invalid_File_Format;
+        }
+
+        var size = map.rows * map.pitch;
+        if (size == 0)
+            return error;
+
+        error = ft_glyphslot_alloc_bitmap(slot, size);
+        if (error != 0)
+            return error;
+    }
+
+    switch (range.image_format)
+    {
+        case 1:
+        case 2:
+        case 5:
+        case 6:
+        case 7:
+            return Load_SBit_Single(map, x_offset, y_offset, strike.bit_depth, range.image_format, metrics, stream);
+
+        case 8:
+            error = stream.Skip(1);
+            if (error != 0)
+                return FT_Common.FT_Err_Invalid_Stream_Skip;
+        case 9:
+            break;
+
+        default:
+            return FT_Common.FT_Err_Invalid_File_Format;
+    }
+
+    var num_components = stream.ReadUShort();
+    FT_Error = error;
+    if (error != 0)
+        return error;
+
+    error = stream.EnterFrame(4*num_components);
+    if (error != 0)
+        return error;
+
+    var components = new Array(num_components);
+    var count = num_components;
+    var comp = 0;
+
+    for (; count > 0; count--, comp++)
+    {
+        var _comp = components[comp];
+        _comp.glyph_code = stream.GetUShort();
+        _comp.x_offset   = stream.GetChar();
+        _comp.y_offset   = stream.GetChar();
+    }
+
+    stream.ExitFrame();
+    count = num_components;
+    comp = 0;
+    for ( ; count > 0; count--, comp++ )
+    {
+        var elem_metrics = new TT_SBit_MetricsRec();
+
+        var _comp = components[comp];
+        var elem = find_sbit_range(_comp.glyph_code, strike);
+        error = FT_Error;
+        if (error != 0)
+        {
+            components = null;
+            return error;
+        }
+
+        error = Load_SBit_Image(strike, elem.range, ebdt_pos, elem.glyph_offset, slot, x_offset + _comp.x_offset,
+                                 y_offset + _comp.y_offset, stream, elem_metrics, depth + 1);
+        if (error != 0)
+        {
+            components = null;
+            return error;
+        }
+    }
+
+    return error;
+}
+function tt_face_load_sbit_image(face, strike_index, glyph_index, load_flags, stream, map, metrics)
+{
+    var elem = tt_find_sbit_image(face, glyph_index, strike_index);
+    var error = FT_Error;
+    if (error != 0)
+        return error;
+
+    face.goto_table(face, FT_Common.TTAG_EBDT, stream);
+    error = FT_Error;
+    if (error != 0)
+    {
+        face.goto_table(face, FT_Common.TTAG_bdat, stream);
+        error = FT_Error;
+    }
+    if (error != 0)
+        return error;
+
+    var ebdt_pos = stream.pos;
+    var strike = elem.strike;
+
+    error = Load_SBit_Image(strike, elem.range, ebdt_pos, elem.glyph_offset,
+                             face.glyph, 0, 0, stream, metrics, 0);
+    if (error != 0)
+        return error;
+
+    if (strike.flags & 1)
+    {
+        var advance = strike.hori.ascender - strike.hori.descender;
+
+        metrics.vertBearingX = parseInt((-metrics.width / 2));
+        metrics.vertBearingY = parseInt((advance - metrics.height)/2);
+        metrics.vertAdvance  = parseInt(advance*12/10);
+    }
+
+    if (load_flags & FT_Common.FT_LOAD_CROP_BITMAP)
+        crop_bitmap(map, metrics);
+    return error;
+}
+/******************************************************************************/
+// ttcmap
+/******************************************************************************/
+function TT_CMapRec()
+{
+    this.cmap = new FT_CMapRec();
+    this.data = null;
+    this.flags = 0;
+
+    this.type = FT_Common.FT_CMAP_1;
+}
+function TT_CMap_ClassRec()
+{
+    this.clazz = new FT_CMap_ClassRec();
+    this.format = 0;
+    this.validate = null;
+    this.get_cmap_info = null;
+}
+function TT_Validator()
+{
+    this.validator = new FT_ValidatorRec();
+    this.num_glyphs = 0;
+}
+function tt_cmap_init(cmap, table)
+{
+    cmap.data = dublicate_pointer(table);
+    return 0;
+}
+// cmap0 ----------------------------------------------------------------------------------
+function tt_cmap0_char_index(cmap, char_code)
+{
+    var table = cmap.data;
+    return char_code < 256 ? table.data[table.pos + 6 + char_code] : 0;
+}
+function tt_cmap0_char_next(cmap, char_code)
+{
+    var table = cmap.data;
+    var pos_base = table.pos + 6;
+    var charcode = char_code;
+    var result = 0;
+    var gindex = 0;
+
+    var d = table.data;
+    while (++charcode < 256)
+    {
+        gindex = d[pos_base + charcode];
+        if (gindex != 0)
+        {
+            result = charcode;
+            break;
+        }
+    }
+
+    return {gindex:gindex,char_code:result};
+}
+function tt_cmap0_class_rec()
+{
+    this.clazz = create_cmap_class_rec(0,tt_cmap_init,null,tt_cmap0_char_index,tt_cmap0_char_next,null,null,null,null,null);
+    this.format = 0;
+    this.validate = function(table, valid)
+    {
+        var p = dublicate_pointer(table);
+        p.pos += 2;
+        var length = FT_NEXT_USHORT(p);
+
+        if (length > valid.limit || length < 262)
+            return FT_Common.FT_Err_Invalid_Table;
+
+        if (valid.level >= 1)
+        {
+            var idx;
+            var d = p.data;
+            var c = table.pos + 6;
+            for (var n = 0; n < 256; n++)
+            {
+                idx = d[c++];
+                if (idx >= valid.num_glyphs)
+                    return FT_Common.FT_Err_Invalid_Glyph_Index;
+            }
+        }
+        return 0;
+    }
+    this.get_cmap_info = function(cmap, cmap_info)
+    {
+        var data = cmap.data;
+        data.pos += 4;
+        cmap_info.format   = 0;
+        cmap_info.language = FT_PEEK_USHORT(data);
+        data.pos -= 4;
+        return 0;
+    }
+}
+// cmap2 ----------------------------------------------------------------------------------
+function tt_cmap2_get_subheader(table, char_code)
+{
+    if (char_code < 0x10000)
+    {
+        var char_lo = (char_code & 0xFF);
+        var char_hi = (char_code >>> 8);
+        var p = dublicate_pointer(table);
+        p.pos += 6;
+
+        var subs = table.pos + 518;
+        var sub = subs;
+
+        if (char_hi == 0)
+        {
+            sub = subs;
+            p.pos += char_lo * 2;
+            if (FT_PEEK_USHORT(p) != 0)
+                return null;
+        }
+        else
+        {
+            p.pos += char_hi * 2;
+            sub = subs + (FT_PEEK_USHORT(p) & ~7);
+            if (sub == subs)
+                return null;
+        }
+        var result = new CPointer();
+        result.data = table.data;
+        result.pos = sub;
+        return result;
+    }
+    return null;
+}
+function tt_cmap2_char_index(cmap, char_code)
+{
+    var table = dublicate_pointer(cmap.data);
+    var result = 0;
+    var subheader = tt_cmap2_get_subheader(table, char_code);
+    if (subheader != null)
+    {
+        var p = subheader;
+        var idx = (char_code & 0xFF);
+
+        var start  = FT_NEXT_USHORT(p);
+        var count  = FT_NEXT_USHORT(p);
+        var delta  = FT_NEXT_SHORT (p);
+        var offset = FT_PEEK_USHORT(p);
+
+        idx -= start;
+        if ( idx < count && offset != 0 )
+        {
+            p.pos += offset + 2 * idx;
+            idx = FT_PEEK_USHORT(p);
+            if (idx != 0)
+                result = (idx + delta) & 0xFFFF;
+        }
+    }
+    return result;
+}
+function tt_cmap2_char_next(cmap, charcode_)
+{
+    var table = dublicate_pointer(cmap.data);
+    var gindex = 0;
+    var result = 0;
+    var charcode = charcode_ + 1;
+    var subheader = null;
+
+    while (charcode < 0x10000)
+    {
+        subheader = tt_cmap2_get_subheader(table, charcode);
+        if (subheader != null)
+        {
+            var p = subheader;
+            var start   = FT_NEXT_USHORT(p);
+            var count   = FT_NEXT_USHORT(p);
+            var delta   = FT_NEXT_SHORT(p);
+            var offset  = FT_PEEK_USHORT(p);
+            var char_lo = (charcode & 0xFF);
+            var pos, idx;
+
+            if (offset == 0)
+            {
+                charcode = charcode & ~255 + 256;
+                continue;
+            }
+
+            if (char_lo < start)
+            {
+                char_lo = start;
+                pos = 0;
+            }
+            else
+                pos = (char_lo - start);
+
+            p.pos += offset + pos * 2;
+            charcode = charcode & ~255 + char_lo;
+
+            for ( ; pos < count; pos++, charcode++ )
+            {
+                idx = FT_NEXT_USHORT(p);
+
+                if ( idx != 0 )
+                {
+                    gindex = (idx + delta) & 0xFFFF;
+                    if ( gindex != 0 )
+                    {
+                        result = charcode;
+                        return {gindex:gindex,char_code:result};
+                    }
+                }
+            }
+        }
+        charcode = charcode & ~255 + 256;
+    }
+    return {gindex:gindex,char_code:result};
+}
+function tt_cmap2_class_rec()
+{
+    this.clazz = create_cmap_class_rec(0,tt_cmap_init,null,tt_cmap2_char_index,tt_cmap2_char_next,null,null,null,null,null);
+    this.format = 2;
+    this.validate = function(table, valid)
+    {
+        var p = dublicate_pointer(table);
+        p.pos += 2;
+        var length = FT_PEEK_USHORT(p);
+        var n = 0;
+
+        if (length > valid.limit || length < 6 + 512)
+            return FT_Common.FT_Err_Invalid_Table;
+
+        p.pos = table.pos + 6;
+        var max_subs = 0;
+        for ( n = 0; n < 256; n++ )
+        {
+            var idx = FT_NEXT_USHORT(p);
+            if (valid.level >= 2 && (idx & 7) != 0)
+                return FT_Common.FT_Err_Invalid_Table;
+
+            idx >>>= 3;
+
+            if (idx > max_subs)
+                max_subs = idx;
+        }
+
+        var glyph_ids = p.pos + (max_subs + 1) * 8;
+        if (glyph_ids > valid.limit)
+            return FT_Common.FT_Err_Invalid_Table;
+
+        for (n = 0; n <= max_subs; n++)
+        {
+            var first_code = FT_NEXT_USHORT(p);
+            var code_count = FT_NEXT_USHORT(p);
+            var delta = FT_NEXT_SHORT(p);
+            var offset = FT_NEXT_USHORT(p);
+
+            if (code_count == 0)
+                continue;
+
+            if (valid.level >= 2)
+            {
+                if (first_code >= 256 || first_code + code_count > 256)
+                    return FT_Common.FT_Err_Invalid_Table;
+            }
+
+            if (offset != 0)
+            {
+                var ids = p.pos - 2 + offset;
+                if (ids < glyph_ids || ids + code_count*2 > (table.pos+length))
+                    return FT_Common.FT_Err_Invalid_Offset;
+
+                if (valid.level >= 1)
+                {
+                    var limit = p.pos + code_count * 2;
+                    var idx;
+                    for (; p.pos < limit;)
+                    {
+                        idx = FT_NEXT_USHORT(p);
+                        if ( idx != 0 )
+                        {
+                            idx = (idx + delta) & 0xFFFF;
+                            if (idx >= valid.num_glyphs)
+                                return FT_Common.FT_Err_Invalid_Glyph_Index;
+                        }
+                    }
+                }
+            }
+        }
+        return 0;
+    }
+    this.get_cmap_info = function(cmap, cmap_info)
+    {
+        cmap.data.pos += 4;
+        cmap_info.format   = 2;
+        cmap_info.language = FT_PEEK_USHORT(cmap.data);
+        cmap.data.pos -= 4;
+        return 0;
+    }
+}
+// cmap4 ----------------------------------------------------------------------------------
+function TT_CMap4Rec()
+{
+    this.cmap = new TT_CMapRec();
+    this.cur_charcode;
+    this.cur_gindex;
+
+    this.num_ranges;
+    this.cur_range;
+    this.cur_start;
+    this.cur_end;
+    this.cur_delta;
+    this.cur_values;
+
+    this.type = FT_Common.FT_CMAP_4;
+}
+function tt_cmap4_init(cmap,table)
+{
+    var p = dublicate_pointer(table);
+    p.pos += 6;
+    cmap.cmap.data = dublicate_pointer(table);
+    cmap.num_ranges = FT_PEEK_USHORT(p) >>> 1;
+    cmap.cur_charcode = 0xFFFFFFFF;
+    cmap.cur_gindex = 0;
+    return 0;
+}
+function tt_cmap4_set_range(cmap, range_index)
+{
+    var table = cmap.cmap.data.pos;
+    var p = dublicate_pointer(cmap.cmap.data);
+    var num_ranges = cmap.num_ranges;
+
+    while (range_index < num_ranges)
+    {
+        p.pos = table + 14 + range_index * 2;
+        cmap.cur_end = FT_PEEK_USHORT(p);
+
+        p.pos += 2 + num_ranges * 2;
+        cmap.cur_start = FT_PEEK_USHORT(p);
+
+        p.pos += num_ranges * 2;
+        cmap.cur_delta = FT_PEEK_SHORT(p);
+
+        p.pos += num_ranges * 2;
+        var offset = FT_PEEK_USHORT(p);
+
+        if (range_index >= num_ranges - 1 && cmap.cur_start == 0xFFFF && cmap.cur_end == 0xFFFF)
+        {
+            var face = cmap.cmap.cmap.charmap.face;
+            var limit = face.cmap_table.pos + face.cmap_size;
+            if (offset && p.pos + offset + 2 > limit)
+            {
+                cmap.cur_delta = 1;
+                offset = 0;
+            }
+        }
+        if (offset != 0xFFFF)
+        {
+            cmap.cur_values = null;
+            if (offset != 0)
+            {
+                cmap.cur_values = dublicate_pointer(p);
+                cmap.cur_values.pos += offset;
+            }
+            cmap.cur_range = range_index;
+            return 0;
+        }
+        range_index++;
+    }
+    return -1;
+}
+function tt_cmap4_next(cmap)
+{
+    if (cmap.cur_charcode >= 0xFFFF)
+    {
+        cmap.cur_charcode = 0xFFFFFFFF;
+        cmap.cur_gindex = 0;
+        return;
+    }
+
+    var charcode = cmap.cur_charcode + 1;
+
+    if (charcode < cmap.cur_start)
+        charcode = cmap.cur_start;
+
+    while(true)
+    {
+        var p = new CPointer();
+        var values = cmap.cur_values;
+        var end = cmap.cur_end;
+        var delta = cmap.cur_delta;
+
+        if ( charcode <= end )
+        {
+            if (values != null)
+            {
+                p.data = values.data;
+                p.pos = values.pos;
+                p.pos += 2*(charcode - cmap.cur_start);
+                do
+                {
+                    var gindex = FT_NEXT_USHORT(p);
+                    if (gindex != 0)
+                    {
+                        gindex = ((gindex + delta) & 0xFFFF);
+                        if (gindex != 0)
+                        {
+                            cmap.cur_charcode = charcode;
+                            cmap.cur_gindex   = gindex;
+                            return;
+                        }
+                    }
+                } while ( ++charcode <= end );
+            }
+            else
+            {
+                do
+                {
+                    var gindex = ((charcode + delta)&0xFFFF);
+                    if (gindex != 0)
+                    {
+                        cmap.cur_charcode = charcode;
+                        cmap.cur_gindex = gindex;
+                        return;
+                    }
+                } while ( ++charcode <= end );
+            }
+        }
+
+        if (tt_cmap4_set_range(cmap, cmap.cur_range + 1) < 0)
+            break;
+
+        if (charcode < cmap.cur_start)
+            charcode = cmap.cur_start;
+    }
+    cmap.cur_charcode = 0xFFFFFFFF;
+    cmap.cur_gindex = 0;
+}
+function tt_cmap4_char_map_linear(cmap, _charcode, next)
+{
+    var num_segs2, start, end, offset;
+    var delta;
+    var i, num_segs;
+    var charcode = _charcode;
+    var gindex = 0;
+    var base = cmap.cmap.data.pos;
+    var p = dublicate_pointer(cmap.cmap.data);
+    p.pos += 6;
+
+    num_segs2 = FT_PEEK_USHORT(p) & ~1;
+    num_segs = num_segs2 >>> 1;
+
+    if (num_segs == 0)
+        return {gindex:0,char_code:_charcode};
+
+    if (next != 0)
+        charcode++;
+
+    for (; charcode <= 0xFFFF; charcode++)
+    {
+        p.pos = base + 14;
+        var q = dublicate_pointer(p);
+        q.pos = base + 16 + num_segs2;
+
+        for ( i = 0; i < num_segs; i++ )
+        {
+            end   = FT_NEXT_USHORT(p);
+            start = FT_NEXT_USHORT(q);
+
+            if ( charcode >= start && charcode <= end )
+            {
+                p.pos = q.pos - 2 + num_segs2;
+                delta = FT_PEEK_SHORT(p);
+                p.pos += num_segs2;
+                offset = FT_PEEK_USHORT(p);
+
+                if (i >= num_segs - 1 && start == 0xFFFF && end == 0xFFFF)
+                {
+                    var face = cmap.cmap.cmap.charmap.face;
+                    var limit = face.cmap_table.pos + face.cmap_size;
+                    if (offset != 0 && p.pos + offset + 2 > limit)
+                    {
+                        delta  = 1;
+                        offset = 0;
+                    }
+                }
+
+                if (offset == 0xFFFF)
+                    continue;
+
+                if (offset != 0)
+                {
+                    p.pos += offset + (charcode - start) * 2;
+                    gindex = FT_PEEK_USHORT(p);
+                    if (gindex != 0)
+                        gindex = (gindex + delta) & 0xFFFF;
+                }
+                else
+                    gindex = (charcode + delta) & 0xFFFF;
+
+                break;
+            }
+        }
+
+        if (next == 0 || gindex != 0)
+            break;
+    }
+
+    if (next != 0 && gindex != 0)
+        return {gindex:gindex,char_code:charcode};
+
+    return {gindex:gindex,char_code:_char_code};
+}
+function tt_cmap4_char_map_binary(cmap, _charcode, next)
+{
+    var num_segs2, start, end, offset;
+    var delta;
+    var max, min, mid, num_segs;
+    var __charcode = _charcode;
+    var charcode = _charcode;
+    var gindex = 0;
+    var p = dublicate_pointer(cmap.cmap.data);
+    var base = p.pos;
+
+    p.pos += 6;
+    num_segs2 = FT_PEEK_USHORT(p) & ~1;
+
+    if (num_segs2 == 0)
+        return {gindex:gindex,char_code:__charcode};
+
+    num_segs = num_segs2 >>> 1;
+
+    mid = num_segs;
+    end = 0xFFFF;
+
+    if (next != 0)
+        charcode++;
+
+    min = 0;
+    max = num_segs;
+
+    while (min < max)
+    {
+        mid = (min + max) >>> 1;
+        p.pos = base + 14 + mid * 2;
+        end = FT_PEEK_USHORT(p);
+        p.pos += 2 + num_segs2;
+        start = FT_PEEK_USHORT(p);
+
+        if (charcode < start)
+            max = mid;
+        else if (charcode > end)
+            min = mid + 1;
+        else
+        {
+            p.pos += num_segs2;
+            delta = FT_PEEK_SHORT(p);
+            p.pos += num_segs2;
+            offset = FT_PEEK_USHORT(p);
+
+            if (mid >= num_segs - 1 && start == 0xFFFF && end == 0xFFFF)
+            {
+                var face = cmap.cmap.cmap.charmap.face;
+                var limit = face.cmap_table.pos + face.cmap_size;
+                if (offset && p.pos + offset + 2 > limit)
+                {
+                    delta  = 1;
+                    offset = 0;
+                }
+            }
+
+            if ((cmap.flags & 2) != 0)
+            {
+                var i;
+                max = mid;
+                if (offset == 0xFFFF)
+                    mid = max + 1;
+
+                for (i = max ; i > 0; i--)
+                {
+                    var old_p = p.pos;
+                    p.pos = base + 14 + (i - 1) * 2;
+                    var prev_end = FT_PEEK_USHORT(p);
+
+                    if ( charcode > prev_end )
+                    {
+                        p.pos = old_p.pos;
+                        break;
+                    }
+
+                    end = prev_end;
+                    p.pos += 2 + num_segs2;
+                    start = FT_PEEK_USHORT(p);
+                    p.pos += num_segs2;
+                    delta = FT_PEEK_SHORT(p);
+                    p.pos += num_segs2;
+                    offset = FT_PEEK_USHORT(p);
+
+                    if (offset != 0xFFFF)
+                        mid = i - 1;
+                }
+
+                if (mid == max + 1)
+                {
+                    if (i != max)
+                    {
+                        p.pos = base + 14 + max * 2;
+                        end = FT_PEEK_USHORT(p);
+                        p.pos += 2 + num_segs2;
+                        start = FT_PEEK_USHORT(p);
+                        p.pos += num_segs2;
+                        delta = FT_PEEK_SHORT(p);
+                        p.pos += num_segs2;
+                        offset = FT_PEEK_USHORT(p);
+                    }
+                    mid = max;
+                    for (i = max + 1; i < num_segs; i++)
+                    {
+                        p.pos = base + 14 + i * 2;
+                        var next_end = FT_PEEK_USHORT(p);
+                        p.pos += 2 + num_segs2;
+                        var next_start = FT_PEEK_USHORT(p);
+
+                        if (charcode < next_start)
+                            break;
+
+                        end = next_end;
+                        start = next_start;
+                        p.pos += num_segs2;
+                        delta = FT_PEEK_SHORT(p);
+                        p.pos += num_segs2;
+                        offset = FT_PEEK_USHORT(p);
+
+                        if (offset != 0xFFFF)
+                            mid = i;
+                    }
+                    i--;
+
+                    if (mid == max)
+                    {
+                        mid = i;
+                        break;
+                    }
+                }
+
+                if (mid != i)
+                {
+                    p.pos = base + 14 + mid * 2;
+                    end = FT_PEEK_USHORT(p);
+                    p.pos += 2 + num_segs2;
+                    start = FT_PEEK_USHORT(p);
+                    p.pos += num_segs2;
+                    delta = FT_PEEK_SHORT(p);
+                    p.pos += num_segs2;
+                    offset = FT_PEEK_USHORT(p);
+                }
+            }
+            else
+            {
+                if (offset == 0xFFFF)
+                    break;
+            }
+
+            if (offset != 0)
+            {
+                p.pos += offset + (charcode - start) * 2;
+                gindex = FT_PEEK_USHORT(p);
+                if (gindex != 0)
+                    gindex = (gindex + delta) & 0xFFFF;
+            }
+            else
+                gindex = (charcode + delta) & 0xFFFF;
+
+            break;
+        }
+    }
+
+    if (next != 0)
+    {
+        if ( charcode > end )
+        {
+            mid++;
+            if ( mid == num_segs )
+                return {gindex:0,char_code:__charcode};
+        }
+
+        if (tt_cmap4_set_range(cmap, mid) != 0)
+        {
+            if (gindex != 0)
+                __charcode = charcode;
+        }
+        else
+        {
+            cmap.cur_charcode = charcode;
+            if (gindex != 0)
+                cmap.cur_gindex = gindex;
+            else
+            {
+                cmap.cur_charcode = charcode;
+                tt_cmap4_next(cmap);
+                gindex = cmap.cur_gindex;
+            }
+
+            if (gindex != 0)
+                __charcode = cmap.cur_charcode;
+        }
+    }
+
+    return {gindex:gindex,char_code:__charcode};
+}
+function tt_cmap4_char_index(cmap,char_code)
+{
+    if (char_code >= 0x10000)
+        return 0;
+
+    if ((cmap.cmap.flags & 1) != 0)
+        return tt_cmap4_char_map_linear(cmap, char_code, 0).gindex;
+    else
+        return tt_cmap4_char_map_binary(cmap, char_code, 0).gindex;
+}
+function tt_cmap4_char_next(cmap,char_code)
+{
+    var gindex = 0;
+    var _char_code = char_code;
+    if (_char_code >= 0xFFFF)
+        return {gindex:gindex,char_code:_char_code};
+
+    if ((cmap.flags & 1) != 0)
+    {
+        var r = tt_cmap4_char_map_linear(cmap, char_code, 1);
+        gindex = r.gindex;
+        _char_code = r.char_code;
+    }
+    else
+    {
+        if (_char_code == cmap.cur_charcode)
+        {
+            tt_cmap4_next(cmap);
+            gindex = cmap.cur_gindex;
+            if (gindex)
+                _char_code = cmap.cur_charcode;
+        }
+        else
+        {
+            var r = tt_cmap4_char_map_binary(cmap, char_code, 1);
+            gindex = r.gindex;
+            _char_code = r.char_code;
+        }
+    }
+    return {gindex:gindex,char_code:_char_code};
+}
+function tt_cmap4_class_rec()
+{
+    this.clazz = create_cmap_class_rec(0,tt_cmap4_init,null,tt_cmap4_char_index,tt_cmap4_char_next,null,null,null,null,null);
+    this.format = 4;
+    this.validate = function(table, valid)
+    {
+        var p = dublicate_pointer(table);
+        p.pos += 2;
+        var length = FT_NEXT_USHORT(p);
+        var error = 0;
+
+        if (length < 16)
+            return FT_Common.FT_Err_Invalid_Table;
+
+        if (table.pos + length > valid.limit)
+        {
+            if (valid.level >= 1)
+                return FT_Common.FT_Err_Invalid_Table;
+
+            length = (valid.limit - table.pos);
+        }
+
+        p.pos = table.pos + 6;
+        var num_segs = FT_NEXT_USHORT(p);
+
+        if (valid.level >= 2)
+        {
+            if ((num_segs & 1) != 0)
+                return FT_Common.FT_Err_Invalid_Table;
+        }
+
+        num_segs >>>= 1;
+
+        if (length < 16 + num_segs * 2 * 4)
+            return FT_Common.FT_Err_Invalid_Table;
+
+        if (valid.level >= 2)
+        {
+            var search_range   = FT_NEXT_USHORT(p);
+            var entry_selector = FT_NEXT_USHORT(p);
+            var range_shift    = FT_NEXT_USHORT(p);
+
+            if (((search_range | range_shift) & 1) != 0)
+                return FT_Common.FT_Err_Invalid_Table;
+
+            search_range >>>= 1;
+            range_shift >>>= 1;
+
+            if (search_range > num_segs || search_range * 2 < num_segs || search_range + range_shift != num_segs                 ||
+                                search_range != (1 << entry_selector))
+                return FT_Common.FT_Err_Invalid_Table;
+        }
+
+        var ends      = table.pos + 14;
+        var starts    = table.pos + 16 + num_segs * 2;
+        var deltas    = starts  + num_segs * 2;
+        var offsets   = deltas  + num_segs * 2;
+        var glyph_ids = offsets + num_segs * 2;
+
+        if (valid.level >= 2)
+        {
+            p.pos = ends + (num_segs - 1) * 2;
+            if (FT_PEEK_USHORT(p) != 0xFFFF)
+                return FT_Common.FT_Err_Invalid_Table;
+        }
+
+        var start, end, offset, n;
+        var last_start = 0, last_end = 0;
+        var delta;
+        var p_start = new CPointer(); p_start.data = p.data; p_start.pos = starts;
+        var p_end = new CPointer(); p_end.data = p.data; p_end.pos = ends;
+        var p_delta = new CPointer(); p_delta.data = p.data; p_delta.pos = deltas;
+        var p_offset = new CPointer(); p_offset.data = p.data; p_offset.pos = offsets;
+
+        for ( n = 0; n < num_segs; n++ )
+        {
+            p.pos = p_offset.pos;
+            start  = FT_NEXT_USHORT(p_start);
+            end    = FT_NEXT_USHORT(p_end);
+            delta  = FT_NEXT_SHORT(p_delta);
+            offset = FT_NEXT_USHORT(p_offset);
+
+            if (start > end)
+                return FT_Common.FT_Err_Invalid_Table;;
+
+            if (start <= last_end && n > 0)
+            {
+                if (valid.level >= 1)
+                    return FT_Common.FT_Err_Invalid_Table;
+                else
+                {
+                    if (last_start > start || last_end > end)
+                        error |= 1;
+                    else
+                        error |= 2;
+                }
+            }
+
+            if (offset && offset != 0xFFFF)
+            {
+                p.pos += offset;
+                if (valid.level >= 1)
+                {
+                    if (p.pos < glyph_ids || p.pos + (end - start + 1) * 2 > table.pos + length)
+                        return FT_Common.FT_Err_Invalid_Table;
+                }
+                else if (n != num_segs - 1 || !(start == 0xFFFF && end == 0xFFFF))
+                {
+                    if (p.pos < glyph_ids || p.pos + (end - start + 1) * 2 > valid.limit)
+                        return FT_Common.FT_Err_Invalid_Table;
+                }
+
+                if (valid.level >= 1)
+                {
+                    var idx;
+                    for (var i = start; i < end; i++ )
+                    {
+                        idx = FT_NEXT_USHORT(p);
+                        if (idx != 0)
+                        {
+                            idx = (idx + delta) & 0xFFFF;
+                            if (idx >= valid.num_glyphs)
+                                return FT_Common.FT_Err_Invalid_Glyph_Index;
+                        }
+                    }
+                }
+            }
+            else if (offset == 0xFFFF)
+            {
+              if (valid.level >= 2 || n != num_segs - 1 || !( start == 0xFFFF && end == 0xFFFF))
+                return FT_Common.FT_Err_Invalid_Table;
+            }
+
+            last_start = start;
+            last_end   = end;
+        }
+
+        return error;
+    }
+    this.get_cmap_info = function(cmap, cmap_info)
+    {
+        var data = cmap.cmap.data;
+        data.pos += 4;
+        cmap_info.format = 4;
+        cmap_info.language = FT_PEEK_USHORT(data);
+        data.pos -= 4;
+        return 0;
+    }
+}
+// cmap6 ----------------------------------------------------------------------------------
+function tt_cmap6_char_index(cmap, char_code)
+{
+    var p = dublicate_pointer(cmap.data);
+    p.pos += 6;
+    var result = 0;
+    var start = FT_NEXT_USHORT(p);
+    var count = FT_NEXT_USHORT(p);
+    var idx =  char_code - start;
+
+    if ( idx < count )
+    {
+        p.pos += 2 * idx;
+        result = FT_PEEK_USHORT(p);
+    }
+    return result;
+}
+function tt_cmap6_char_next(cmap, _char_code)
+{
+    var p = dublicate_pointer(cmap.data);
+    p.pos += 6;
+    var result    = 0;
+    var char_code = _char_code + 1;
+    var gindex = 0;
+
+    var start = FT_NEXT_USHORT(p);
+    var count = FT_NEXT_USHORT(p);
+
+    if (char_code >= 0x10000)
+        return {gindex:gindex,char_code:_char_code};
+
+    if (char_code < start)
+        char_code = start;
+
+    var idx = char_code - start;
+    p.pos += 2 * idx;
+    for (; idx < count; idx++)
+    {
+        gindex = FT_NEXT_USHORT(p);
+        if (gindex != 0)
+        {
+            result = char_code;
+            break;
+        }
+        char_code++;
+    }
+    return {gindex:gindex,char_code:result};
+}
+function tt_cmap6_class_rec()
+{
+    this.clazz = create_cmap_class_rec(0,tt_cmap_init,null,tt_cmap6_char_index,tt_cmap6_char_next,null,null,null,null,null);
+    this.format = 6;
+    this.validate = function(table, valid)
+    {
+        var base = table.pos;
+        var p = new CPointer();
+        p.data = table.data;
+
+        if (base + 10 > valid.limit)
+            return FT_Common.FT_Err_Invalid_Table;
+
+        p.pos = base + 2;
+        var length = FT_NEXT_USHORT(p);
+        p.pos = base + 8;
+        var count = FT_NEXT_USHORT(p);
+
+        if (base + length > valid.limit || length < 10 + count * 2)
+            return FT_Common.FT_Err_Invalid_Table;
+
+        if (valid.level >= 1)
+        {
+            var gindex;
+            for (; count > 0; count--)
+            {
+                gindex = FT_NEXT_USHORT(p);
+                if (gindex >= valid.num_glyphs)
+                    return FT_Common.FT_Err_Invalid_Glyph_Index;
+            }
+        }
+        return 0;
+    }
+    this.get_cmap_info = function(cmap, cmap_info)
+    {
+        var data = cmap.data;
+        data.pos += 4;
+        cmap_info.format = 6;
+        cmap_info.language = FT_PEEK_USHORT(data);
+        data.pos -= 4;
+        return 0;
+    }
+}
+// cmap8 ----------------------------------------------------------------------------------
+function tt_cmap8_char_index(cmap, char_code)
+{
+    var result = 0;
+    var p = dublicate_pointer(cmap.cmap.data);
+    p.pos += 8204;
+    var num_groups = FT_NEXT_ULONG(p);
+    var start, end, start_id;
+    for (; num_groups > 0; num_groups--)
+    {
+        start    = FT_NEXT_ULONG(p);
+        end      = FT_NEXT_ULONG(p);
+        start_id = FT_NEXT_ULONG(p);
+
+        if (char_code < start)
+            break;
+
+        if (char_code <= end)
+        {
+            result = (start_id + char_code - start);
+            break;
+        }
+    }
+    return result;
+}
+function tt_cmap8_char_next(cmap, _char_code)
+{
+    var result = 0;
+    var char_code = _char_code + 1;
+    var gindex = 0;
+    var p = dublicate_pointer(cmap.cmap.data);
+    p.pos += 8204;
+    var num_groups = FT_NEXT_ULONG(p);
+    var start, end, start_id;
+
+    for ( ; num_groups > 0; num_groups-- )
+    {
+        start    = FT_NEXT_ULONG(p);
+        end      = FT_NEXT_ULONG(p);
+        start_id = FT_NEXT_ULONG(p);
+
+        if (char_code < start)
+            char_code = start;
+
+        if (char_code <= end)
+        {
+            gindex = (char_code - start + start_id);
+            if ( gindex != 0 )
+            {
+                result = char_code;
+                break;
+            }
+        }
+    }
+    return {gindex:gindex,char_code:result};
+}
+function tt_cmap8_class_rec()
+{
+    this.clazz = create_cmap_class_rec(0,tt_cmap_init,null,tt_cmap8_char_index,tt_cmap8_char_next,null,null,null,null,null);
+    this.format = 8;
+    this.validate = function(table, valid)
+    {
+        var base = table.pos;
+        var p = dublicate_pointer(table);
+        p.pos += 4;
+
+        if (base + 16 + 8192 > valid.limit)
+            return FT_Common.FT_Err_Invalid_Table;
+
+        var length = FT_NEXT_ULONG(p);
+        if (length > (valid.limit - base) || length < 8192 + 16)
+            return FT_Common.FT_Err_Invalid_Table;
+
+        var is32 = base + 12;
+        p.pos = is32 + 8192;
+        var num_groups = FT_NEXT_ULONG(p);
+
+        if (p.pos + num_groups * 12 > valid.limit)
+            return FT_Common.FT_Err_Invalid_Table;
+
+        var n, start, end, start_id, count, last = 0;
+        for ( n = 0; n < num_groups; n++ )
+        {
+            var hi, lo;
+            start    = FT_NEXT_ULONG(p);
+            end      = FT_NEXT_ULONG(p );
+            start_id = FT_NEXT_ULONG(p);
+
+            if (start > end)
+                return FT_Common.FT_Err_Invalid_Table;
+
+            if (n > 0 && start <= last)
+                return FT_Common.FT_Err_Invalid_Table;
+
+            if (valid.level >= 1)
+            {
+                if (start_id + end - start >= valid.num_glyphs)
+                    return FT_Common.FT_Err_Invalid_Glyph_Index;
+
+                count = (end - start + 1);
+                if ((start & ~0xFFFF) != 0)
+                {
+                    for (; count > 0; count--, start++)
+                    {
+                        hi = (start >>> 16);
+                        lo = (start & 0xFFFF);
+
+                        if ((p.data[is32 + hi >>> 3] & (0x80 >>> (hi & 7))) == 0)
+                            return FT_Common.FT_Err_Invalid_Table;
+
+                        if ((p.data[is32 + lo >>> 3] & (0x80 >>> (lo & 7))) == 0)
+                            return FT_Common.FT_Err_Invalid_Table;
+                    }
+                }
+                else
+                {
+                    if ((end & ~0xFFFF) != 0)
+                        return FT_Common.FT_Err_Invalid_Table;
+
+                    for ( ; count > 0; count--, start++ )
+                    {
+                        lo = (start & 0xFFFF);
+                        if ((p.data[is32 + lo >>> 3] & (0x80 >>> (lo & 7))) != 0)
+                            return FT_Common.FT_Err_Invalid_Table;
+                    }
+                }
+            }
+            last = end;
+        }
+
+        return 0;
+    }
+    this.get_cmap_info = function(cmap, cmap_info)
+    {
+        var data = cmap.cmap.data;
+        data.pos += 8;
+        cmap_info.format = 8;
+        cmap_info.language = FT_PEEK_ULONG(data);
+        data.pos -= 8;
+        return 0;
+    }
+}
+// cmap10 ---------------------------------------------------------------------------------
+function tt_cmap10_char_index(cmap, char_code)
+{
+    var p = dublicate_pointer(cmap.cmap.data);
+    p.pos += 12;
+    var result = 0;
+    var start = FT_NEXT_ULONG(p);
+    var count = FT_NEXT_ULONG(p);
+    var idx = (char_code - start);
+
+    if (idx < count)
+    {
+        p.pos += 2 * idx;
+        result = FT_PEEK_USHORT(p);
+    }
+    return result;
+}
+function tt_cmap10_char_next(cmap, _char_code)
+{
+    var p = dublicate_pointer(cmap.cmap.data);
+    p.pos += 12;
+    var char_code = _char_code + 1;
+    var gindex = 0;
+    var start = FT_NEXT_ULONG(p);
+    var count = FT_NEXT_ULONG(p);
+
+    if (char_code < start)
+        char_code = start;
+
+    var idx = char_code - start;
+    p.pos += 2 * idx;
+
+    for (; idx < count; idx++)
+    {
+        gindex = FT_NEXT_USHORT(p);
+        if (gindex != 0)
+            break;
+        char_code++;
+    }
+    return {gindex:gindex,char_code:char_code};
+}
+function tt_cmap10_class_rec()
+{
+    this.clazz = create_cmap_class_rec(0,tt_cmap_init,null,tt_cmap10_char_index,tt_cmap10_char_next,null,null,null,null,null);
+    this.format = 10;
+    this.validate = function(table, valid)
+    {
+        var p = dublicate_pointer(table);
+        var base = table.pos;
+        p.pos += 4;
+
+        if (base + 20 > valid.limit)
+            return FT_Common.FT_Err_Invalid_Table;
+
+        var length = FT_NEXT_ULONG(p);
+        p.pos = base + 16;
+        var count = FT_NEXT_ULONG(p);
+
+        if (length > (valid.limit - base) || length < 20 + count * 2)
+            return FT_Common.FT_Err_Invalid_Table;
+
+        if (valid.level >= 1)
+        {
+            var gindex;
+            for (; count > 0; count--)
+            {
+                gindex = FT_NEXT_USHORT(p);
+                if (gindex >= valid.num_glyphs)
+                    return FT_Common.FT_Err_Invalid_Glyph_Index;
+            }
+        }
+        return 0;
+    }
+    this.get_cmap_info = function(cmap, cmap_info)
+    {
+        var data = cmap.cmap.data;
+        data.pos += 8;
+        cmap_info.format = 10;
+        cmap_info.language = FT_PEEK_ULONG(data);
+        data.pos -= 8;
+        return 0;
+    }
+}
+// cmap12 ---------------------------------------------------------------------------------
+function TT_CMap12Rec()
+{
+    this.cmap = new TT_CMapRec();
+    this.valid;
+    this.cur_charcode;
+    this.cur_gindex;
+    this.cur_group;
+    this.num_groups;
+
+    this.type = FT_Common.FT_CMAP_12;
+}
+function tt_cmap12_init(cmap, table)
+{
+    cmap.cmap.data = dublicate_pointer(table);
+    table.pos += 12;
+    cmap.num_groups = FT_PEEK_ULONG(table);
+    table.pos -= 12;
+    cmap.valid = 0;
+    return 0;
+}
+function tt_cmap12_next(cmap)
+{
+    if (cmap.cur_charcode >= 0xFFFFFFFF)
+    {
+        cmap.valid = 0;
+        return;
+    }
+
+    var p = dublicate_pointer(cmap.cmap.data);
+    var base = p.pos;
+    var start, end, start_id;
+    var gindex;
+
+    var char_code = cmap.cur_charcode + 1;
+    for (var n = cmap.cur_group; n < cmap.num_groups; n++)
+    {
+        p.pos = base + 16 + 12 * n;
+        start    = FT_NEXT_ULONG(p);
+        end      = FT_NEXT_ULONG(p);
+        start_id = FT_PEEK_ULONG(p);
+
+        if (char_code < start)
+            char_code = start;
+
+        for ( ; char_code <= end; char_code++ )
+        {
+            gindex = (start_id + char_code - start);
+            if (gindex != 0)
+            {
+                cmap.cur_charcode = char_code;
+                cmap.cur_gindex   = gindex;
+                cmap.cur_group    = n;
+                return;
+            }
+        }
+    }
+    cmap.valid = 0;
+}
+function tt_cmap12_char_map_binary(cmap, _char_code, next)
+{
+    var gindex = 0;
+    var p = dublicate_pointer(cmap.cmap.data);
+    var base = p.pos;
+    p.pos += 12;
+    var num_groups = FT_PEEK_ULONG(p);
+    var char_code = _char_code;
+    var __char_code = _char_code;
+    var start, end, start_id;
+    var max, min, mid;
+
+    if (num_groups == 0)
+        return {gindex:gindex,char_code:__char_code};
+
+    mid = num_groups;
+    end = 0xFFFFFFFF;
+
+    if (next != 0)
+        char_code++;
+
+    min = 0;
+    max = num_groups;
+
+    while (min < max)
+    {
+        mid = (min + max) >>> 1;
+        p.pos = base + 16 + 12 * mid;
+
+        start = FT_NEXT_ULONG(p);
+        end = FT_NEXT_ULONG(p);
+
+        if (char_code < start)
+            max = mid;
+        else if (char_code > end)
+            min = mid + 1;
+        else
+        {
+            start_id = FT_PEEK_ULONG(p);
+            gindex = (start_id + char_code - start);
+            break;
+        }
+    }
+
+    if (next != 0)
+    {
+        if (char_code > end)
+        {
+            mid++;
+            if (mid == num_groups)
+                return 0;
+        }
+
+        cmap.valid = 1;
+        cmap.cur_charcode = char_code;
+        cmap12.cur_group = mid;
+
+        if (gindex == 0)
+        {
+            tt_cmap12_next(cmap);
+
+            if (cmap.valid == 1)
+                gindex = cmap.cur_gindex;
+        }
+        else
+            cmap.cur_gindex = gindex;
+
+        if (gindex != 0)
+            __char_code = cmap.cur_charcode;
+    }
+
+    return {gindex:gindex,char_code:__char_code};
+}
+function tt_cmap12_char_index(cmap, char_code)
+{
+    return tt_cmap12_char_map_binary(cmap, char_code, 0).gindex;
+}
+function tt_cmap12_char_next(cmap, _char_code)
+{
+    var gindex = 0;
+    var __char_code = _char_code;
+
+    if (cmap.cur_charcode >= 0xFFFFFFFF)
+        return {gindex:gindex,char_code:__char_code};
+
+    if (cmap12.valid == 1 && cmap.cur_charcode == _char_code)
+    {
+        tt_cmap12_next(cmap);
+        if (1 == cmap.valid)
+        {
+            gindex = cmap.cur_gindex;
+            if (gindex != 0)
+                __char_code = cmap.cur_charcode;
+        }
+        else
+            gindex = 0;
+    }
+    else
+        return tt_cmap12_char_map_binary(cmap, _char_code, 1);
+
+    return {gindex:gindex,char_code:__char_code};
+}
+function tt_cmap12_class_rec()
+{
+    this.clazz = create_cmap_class_rec(0,tt_cmap12_init,null,tt_cmap12_char_index,tt_cmap12_char_next,null,null,null,null,null);
+    this.format = 12;
+    this.validate = function(table, valid)
+    {
+        var base = table.pos;
+        var p = dublicate_pointer(table);
+        if (p.pos + 16 > valid.limit)
+            return FT_Common.FT_Err_Invalid_Table;
+        p.pos = base + 4;
+        var length = FT_NEXT_ULONG(p);
+        p.pos = base + 12;
+        var num_groups = FT_NEXT_ULONG(p);
+        if (length > (valid.limit - base) || length < 16 + 12 * num_groups)
+            return FT_Common.FT_Err_Invalid_Table;
+        var n, start, end, start_id, last = 0;
+        for (n = 0; n < num_groups; n++)
+        {
+            start    = FT_NEXT_ULONG(p);
+            end      = FT_NEXT_ULONG(p);
+            start_id = FT_NEXT_ULONG(p);
+
+            if (start > end)
+                return FT_Common.FT_Err_Invalid_Table;
+            if (n > 0 && start <= last)
+                return FT_Common.FT_Err_Invalid_Table;
+            if (valid.level >= 1)
+            {
+                if (start_id + end - start >= valid.num_glyphs)
+                    return FT_Common.FT_Err_Invalid_Glyph_Index;
+            }
+            last = end;
+        }
+        return 0;
+    }
+    this.get_cmap_info = function(cmap, cmap_info)
+    {
+        var data = cmap.cmap.data;
+        data.pos += 8;
+        cmap_info.format = 12;
+        cmap_info.language = FT_PEEK_ULONG(data);
+        data.pos -= 8;
+        return 0;
+    }
+}
+// cmap13 ---------------------------------------------------------------------------------
+function TT_CMap13Rec()
+{
+    this.cmap = new TT_CMapRec();
+    this.valid;
+    this.cur_charcode;
+    this.cur_gindex;
+    this.cur_group;
+    this.num_groups;
+
+    this.type = FT_Common.FT_CMAP_13;
+}
+function tt_cmap13_init(cmap, table)
+{
+    cmap.cmap.data = dublicate_pointer(table);
+    table.pos += 12;
+    cmap.num_groups = FT_PEEK_ULONG(table);
+    table.pos -= 12;
+    cmap.valid = 0;
+    return 0;
+}
+function tt_cmap13_next(cmap)
+{
+    if (cmap.cur_charcode >= 0xFFFFFFFF)
+    {
+        cmap.valid = 0;
+        return;
+    }
+
+    var p = dublicate_pointer(cmap.cmap.data);
+    var base = p.pos;
+    var start, end, glyph_id, char_code;
+    var gindex;
+
+    char_code = cmap.cur_charcode + 1;
+    for (var n = cmap.cur_group; n < cmap.num_groups; n++ )
+    {
+        p.pos = base + 16 + 12 * n;
+        start = FT_NEXT_ULONG(p);
+        end = FT_NEXT_ULONG(p);
+        glyph_id = FT_PEEK_ULONG(p);
+
+        if (char_code < start)
+            char_code = start;
+
+        if ( char_code <= end )
+        {
+            gindex = glyph_id;
+            if (gindex != 0)
+            {
+                cmap.cur_charcode = char_code;
+                cmap.cur_gindex = gindex;
+                cmap.cur_group = n;
+                return;
+            }
+        }
+    }
+    cmap.valid = 0;
+}
+function tt_cmap13_char_map_binary(cmap, _char_code, next)
+{
+    var gindex = 0;
+    var p = dublicate_pointer(cmap.cmap.data);
+    var base = p.pos;
+    p.pos += 12;
+    var num_groups = FT_PEEK_ULONG(p);
+    var char_code = _char_code;
+    var __char_code = _char_code;
+    var start, end;
+    var max, min, mid;
+
+    if (num_groups == 0)
+        return {gindex:gindex,char_code:__char_code};
+
+    mid = num_groups;
+    end = 0xFFFFFFFF;
+
+    if (next != 0)
+        char_code++;
+
+        min = 0;
+        max = num_groups;
+
+    while (min < max)
+    {
+        mid = (min + max) >>> 1;
+        p.pos = base + 16 + 12 * mid;
+
+        start = FT_NEXT_ULONG(p);
+        end   = FT_NEXT_ULONG(p);
+
+        if (char_code < start)
+            max = mid;
+        else if (char_code > end)
+            min = mid + 1;
+        else
+        {
+            gindex = FT_PEEK_ULONG(p);
+            break;
+        }
+    }
+
+    if (next != 0)
+    {
+        if (char_code > end)
+        {
+            mid++;
+            if (mid == num_groups)
+                return 0;
+        }
+
+        cmap.valid        = 1;
+        cmap.cur_charcode = char_code;
+        cmap.cur_group    = mid;
+
+        if (gindex == 0)
+        {
+            tt_cmap13_next( cmap13 );
+            if (cmap.valid == 1)
+                gindex = cmap.cur_gindex;
+        }
+        else
+            cmap.cur_gindex = gindex;
+
+        if (gindex != 0)
+            __char_code = cmap.cur_charcode;
+    }
+
+    return {gindex:gindex,char_code:__char_code};
+}
+function tt_cmap13_char_index(cmap, char_code)
+{
+    return tt_cmap13_char_map_binary(cmap, char_code, 0).gindex;
+}
+function tt_cmap13_char_next(cmap, _char_code)
+{
+    if (cmap.cur_charcode >= 0xFFFFFFFF)
+        return {gindex:0,char_code:_char_code};
+
+    var gindex;
+    var __char_code = _char_code;
+    if (cmap.valid == 1 && cmap.cur_charcode == _char_code)
+    {
+        tt_cmap13_next(cmap);
+        if (cmap.valid == 1)
+        {
+            gindex = cmap.cur_gindex;
+            if (gindex != 0)
+                __char_code = cmap.cur_charcode;
+        }
+        else
+            gindex = 0;
+    }
+    else
+        return tt_cmap13_char_map_binary( cmap, pchar_code, 1 );
+
+    return {gindex:gindex,char_code:__char_code};
+}
+function tt_cmap13_class_rec()
+{
+    this.clazz = create_cmap_class_rec(0,tt_cmap13_init,null,tt_cmap13_char_index,tt_cmap13_char_next,null,null,null,null,null);
+    this.format = 13;
+    this.validate = function(table, valid)
+    {
+        var p = dublicate_pointer(table);
+        var base = p.pos;
+
+        if (bae + 16 > valid.limit)
+            return FT_Common.FT_Err_Invalid_Table;
+
+        p.pos = base + 4;
+        var length = FT_NEXT_ULONG(p);
+        p.pos = base + 12;
+        var num_groups = FT_NEXT_ULONG(p);
+
+        if (length > (valid.limit - base) || length < 16 + 12 * num_groups)
+            return FT_Common.FT_Err_Invalid_Table;
+
+        var start, end, glyph_id, last = 0;
+        for (var n = 0; n < num_groups; n++)
+        {
+            start    = FT_NEXT_ULONG(p);
+            end      = FT_NEXT_ULONG(p);
+            glyph_id = FT_NEXT_ULONG(p);
+
+            if (start > end)
+                return FT_Common.FT_Err_Invalid_Table;
+
+            if (n > 0 && start <= last)
+                return FT_Common.FT_Err_Invalid_Table;
+
+            if (valid.level >= 1)
+            {
+                if (glyph_id >= valid.num_glyphs)
+                    return FT_Common.FT_Err_Invalid_Glyph_Index;
+            }
+
+            last = end;
+        }
+        return 0;
+    }
+    this.get_cmap_info = function(cmap, cmap_info)
+    {
+        var data = cmap.data;
+        data.pos += 8;
+        cmap_info.format = 13;
+        cmap_info.language = FT_PEEK_ULONG(data);
+        data.pos -= 8;
+        return 0;
+    }
+}
+// cmap14 ---------------------------------------------------------------------------------
+function TT_CMap14Rec()
+{
+    this.cmap = new TT_CMapRec();
+    this.num_selectors;
+    this.max_results;
+    this.results = null;
+
+    this.type = FT_Common.FT_CMAP_14;
+}
+function tt_cmap14_done(cmap)
+{
+    cmap.results = null;
+}
+function tt_cmap14_ensure(cmap, num_results, memory)
+{
+    var old_max = cmap.max_results;
+    if (num_results > cmap.max_results)
+    {
+        var c = num_results - old_max;
+        for (;c>0;c--)
+            cmap.results[old_max+c-1] = 0;
+        cmap.max_results = num_results;
+    }
+    return 0;
+}
+function tt_cmap14_init(cmap, table)
+{
+    cmap.cmap.data = dublicate_pointer(table);
+    table.pos += 6;
+    cmap.num_selectors = FT_PEEK_ULONG(table);
+    table.pos -= 6;
+    cmap.max_results   = 0;
+    cmap.results = null;
+    return 0;
+}
+function tt_cmap14_char_index(cmap,char_code)
+{
+    return 0;
+}
+function tt_cmap14_char_next(cmap, _char_code)
+{
+    return {gindex:0,char_code:0};
+}
+function tt_cmap14_char_map_def_binary(base, char_code)
+{
+    var p = dublicate_pointer(base);
+    var numRanges = FT_PEEK_ULONG(p);
+    var min = 0;
+    var max = numRanges;
+
+    while (min < max)
+    {
+        var mid = (min + max) >>> 1;
+        p.pos = base.pos + 4 + 4 * mid;
+        var start = FT_NEXT_UOFF3(p);
+        var cnt = FT_NEXT_BYTE(p);
+
+        if (char_code < start)
+            max = mid;
+        else if (char_code > start+cnt)
+            min = mid + 1;
+        else
+            return 1;
+    }
+    return 0;
+}
+function tt_cmap14_char_map_nondef_binary(base, char_code)
+{
+    var p = dublicate_pointer(base);
+    var numMappings = FT_PEEK_ULONG(p);
+    var min = 0;
+    var max = numMappings;
+
+    while (min < max)
+    {
+        var mid = (min + max) >>> 1;
+        p.pos = base.pos + 4 + 5 * mid;
+        var uni = FT_NEXT_UOFF3(p);
+
+        if (char_code < uni)
+            max = mid;
+        else if (char_code > uni)
+            min = mid + 1;
+        else
+            return FT_PEEK_USHORT(p);
+    }
+    return 0;
+}
+function tt_cmap14_find_variant(base, variantCode)
+{
+    var p = dublicate_pointer(base);
+    var numVar = FT_PEEK_ULONG(p);
+    var min = 0;
+    var max = numVar;
+
+    while (min < max)
+    {
+        var mid = (min + max) >>> 1;
+        p.pos = base.pos + 4 + 11 * mid;
+        var varSel = FT_NEXT_UOFF3(p);
+
+        if (variantCode < varSel)
+            max = mid;
+        else if (variantCode > varSel)
+            min = mid + 1;
+        else
+            return p;
+    }
+    return null;
+}
+function tt_cmap14_char_var_index(cmap, ucmap, charcode, variantSelector)
+{
+    var base = dublicate_pointer(cmap.cmap.data);
+    base.pos += 6;
+    var p = tt_cmap14_find_variant(base, variantSelector);
+    if (null == p)
+        return 0;
+
+    var defOff = FT_NEXT_ULONG(p);
+    var nondefOff = FT_PEEK_ULONG(p);
+
+    base.pos = cmap.cmap.data.pos + defOff;
+    if (defOff != 0 && 0 != tt_cmap14_char_map_def_binary(base, charcode))
+    {
+        return ucmap.cmap.clazz.char_index(ucmap.cmap, charcode);
+    }
+
+    base.pos = cmap.cmap.data.pos + nondefOff;
+    if (nondefOff != 0)
+        return tt_cmap14_char_map_nondef_binary(base, charcode);
+
+    return 0;
+}
+function tt_cmap14_char_var_isdefault(cmap, charcode, variantSelector)
+{
+    var base = dublicate_pointer(cmap.cmap.data);
+    var base_pos = base.pos;
+    base += 6;
+    var p = tt_cmap14_find_variant(base, variantSelector);
+    if (null == p)
+        return -1;
+
+    var defOff    = FT_NEXT_ULONG(p);
+    var nondefOff = FT_NEXT_ULONG(p);
+
+    base.pos = base_pos + defOff;
+    if (defOff != 0 && 0 != tt_cmap14_char_map_def_binary(base, charcode))
+        return 1;
+
+    base.pos = base_pos + nondefOff;
+    if (nondefOff != 0 && tt_cmap14_char_map_nondef_binary(base, charcode) != 0)
+        return 0;
+
+    return -1;
+}
+function tt_cmap14_variants(cmap, memory)
+{
+    var count = cmap.num_selectors;
+    var p = dublicate_pointer(cmap.cmap.data);
+    p.pos += 10;
+
+    if (0 != tt_cmap14_ensure(cmap, (count + 1), memory))
+        return null;
+
+    var result = cmap.results;
+    var i = 0;
+    for (; i < count; i++)
+    {
+        result[i] = FT_NEXT_UOFF3(p);
+        p.pos += 8;
+    }
+    result[i] = 0;
+
+    p.data = result;
+    p.pos = 0;
+    return p;
+}
+function tt_cmap14_char_variants(cmap, memory, charCode)
+{
+    var count = cmap.num_selectors;
+    var p = dublicate_pointer(cmap.cmap.data);
+    var base_pos = p.pos;
+    p.pos += 10;
+    
+    if (0 != tt_cmap14_ensure(cmap, (count + 1), memory))
+        return null;
+
+    var p1 = dublicate_pointer(p);
+    var p2 = dublicate_pointer(p);
+
+    var results = cmap.results;
+    var q = 0;
+    for (; count > 0; --count)
+    {
+        var varSel    = FT_NEXT_UOFF3(p);
+        var defOff    = FT_NEXT_ULONG(p);
+        var nondefOff = FT_NEXT_ULONG(p);
+
+        p1.pos = base_pos + defOff;
+        p2.pos = base_pos + nondefOff;
+        if ((defOff != 0 && 0 != tt_cmap14_char_map_def_binary(p1, charCode)) ||
+           (nondefOff != 0 && 0 != tt_cmap14_char_map_nondef_binary(p2, charCode)))
+        {
+            results[q] = varSel;
+            q++;
+        }
+    }
+    results[q] = 0;
+    p.data = results;
+    p.pos = 0;
+    return p;
+}
+function tt_cmap14_def_char_count(_p)
+{
+    var p = dublicate_pointer(_p);
+    var numRanges = FT_NEXT_ULONG(p);
+    var tot = 0;
+    p.pos += 3;
+    for (; numRanges > 0; numRanges--)
+    {
+        tot += 1 + p.data[p.pos];
+        p.pos += 4;
+    }
+    return tot;
+}
+function tt_cmap14_get_def_chars(cmap, _p, memory)
+{
+    var p = dublicate_pointer(_p);
+    var cnt = tt_cmap14_def_char_count(p);
+    var numRanges = FT_NEXT_ULONG(p);
+
+    if (0 != tt_cmap14_ensure(cmap, (cnt + 1), memory))
+        return null;
+
+    var results = cmap.results;
+    var q = 0;
+    for (; numRanges > 0; --numRanges)
+    {
+        var uni = FT_NEXT_UOFF3(p);
+        cnt = FT_NEXT_BYTE(p) + 1;
+        do
+        {
+            results[q] = uni;
+            uni  += 1;
+            q    += 1;
+        } while (--cnt != 0);
+    }
+    results[q] = 0;
+    p.data = results;
+    p.pos = 0;
+    return p;
+}
+function tt_cmap14_get_nondef_chars(cmap, _p, memory)
+{
+    var p = dublicate_pointer(_p);
+    var numMappings = FT_NEXT_ULONG(p);
+
+    if (0 != tt_cmap14_ensure(cmap, (numMappings + 1), memory))
+        return null;
+
+    var ret = cmap.results;
+    var i = 0;
+    for (; i < numMappings; i++)
+    {
+        ret[i] = FT_NEXT_UOFF3(p);
+        p.pos += 2;
+    }
+    ret[i] = 0;
+    p.data = ret;
+    p.pos = 0;
+    return p;
+}
+function tt_cmap14_variant_chars(cmap, memory, variantSelector)
+{
+    var base = dublicate_pointer(cmap.cmap.data);
+    var base_pos = base.pos;
+    base.pos += 6;
+    var p = tt_cmap14_find_variant(base, variantSelector);
+    if (null == p)
+        return null;
+
+    var defOff = FT_NEXT_ULONG(p);
+    var nondefOff = FT_NEXT_ULONG(p);
+
+    if (defOff == 0 && nondefOff == 0)
+        return null;
+
+    base.pos = base_pos + nondefOff;
+    if (defOff == 0)
+        return tt_cmap14_get_nondef_chars(cmap, base, memory);
+    base.pos = base_pos + defOff;
+    if (nondefOff == 0)
+        return tt_cmap14_get_def_chars(cmap, base, memory);
+
+    var numRanges;
+    var numMappings;
+    var duni;
+    var dcnt;
+    var nuni;
+    var dp;
+    var di, ni, k;
+
+    var _cmap_data = cmap.cmap.data;
+    p = dublicate_pointer(_cmap_data);
+    p.pos += nondefOff;
+    dp = dublicate_pointer(_cmap_data);
+    dp.pos += defOff;
+
+    numMappings = FT_NEXT_ULONG(p);
+    dcnt        = tt_cmap14_def_char_count(dp);
+    numRanges   = FT_NEXT_ULONG(dp);
+
+    if (numMappings == 0)
+    {
+        var __pp = dublicate_pointer(_cmap_data);
+        __pp += defOff;
+        return tt_cmap14_get_def_chars(cmap, _p, memory);
+    }
+    if (dcnt == 0)
+    {
+        var __pp = dublicate_pointer(_cmap_data);
+        __pp += nondefOff;
+        return tt_cmap14_get_nondef_chars(cmap, __p, memory);
+    }
+
+    if (0 != tt_cmap14_ensure(cmap, (dcnt + numMappings + 1), memory))
+        return null;
+
+    var ret = cmap.results;
+    duni = FT_NEXT_UOFF3(dp);
+    dcnt = FT_NEXT_BYTE(dp);
+    di = 1;
+    nuni = FT_NEXT_UOFF3(p);
+    p.pos += 2;
+    ni = 1;
+    i = 0;
+
+    for ( ;; )
+    {
+        if (nuni > duni + dcnt)
+        {
+            for (k = 0; k <= dcnt; k++)
+                ret[i++] = duni + k;
+
+            ++di;
+
+            if (di > numRanges)
+                break;
+
+            duni = FT_NEXT_UOFF3(dp);
+            dcnt = FT_NEXT_BYTE(dp);
+        }
+        else
+        {
+            if (nuni < duni)
+                ret[i++] = nuni;
+            ++ni;
+            if (ni > numMappings)
+                break;
+
+            nuni = FT_NEXT_UOFF3(p);
+            p.pos += 2;
+        }
+    }
+
+    if (ni <= numMappings)
+    {
+        ret[i++] = nuni;
+        while (ni < numMappings)
+        {
+            ret[i++] = FT_NEXT_UOFF3(p);
+            p.pos += 2;
+            ++ni;
+        }
+    }
+    else if (di <= numRanges)
+    {
+        for (k = 0; k <= dcnt; k++)
+            ret[i++] = duni + k;
+
+        while (di < numRanges)
+        {
+            duni = FT_NEXT_UOFF3(dp);
+            dcnt = FT_NEXT_BYTE(dp);
+
+            for (k = 0; k <= dcnt; k++)
+                ret[i++] = duni + k;
+            ++di;
+        }
+    }
+    ret[i] = 0;
+    p.data = ret;
+    p.pos = 0;
+    return p;
+}
+function tt_cmap14_class_rec()
+{
+    this.clazz = create_cmap_class_rec(0,tt_cmap14_init,tt_cmap14_done,tt_cmap14_char_index,tt_cmap14_char_next,
+        tt_cmap14_char_var_index,tt_cmap14_char_var_isdefault,tt_cmap14_variants,
+        tt_cmap14_char_variants,tt_cmap14_variant_chars);
+    this.format = 14;
+    this.validate = function(table, valid)
+    {
+        var p = dublicate_pointer(table);
+        var defp = dublicate_pointer(table);
+        var base = p.pos;
+        p.pos += 2;
+        var length        = FT_NEXT_ULONG(p);
+        var num_selectors = FT_NEXT_ULONG(p);
+
+        if (length > (valid.limit - base) || length < 10 + 11 * num_selectors)
+            return FT_Common.FT_Err_Invalid_Table;
+
+        var n, lastVarSel = 1;
+        for ( n = 0; n < num_selectors; n++ )
+        {
+            var varSel = FT_NEXT_UOFF3(p);
+            var defOff = FT_NEXT_ULONG(p);
+            var nondefOff = FT_NEXT_ULONG(p);
+
+            if (defOff >= length || nondefOff >= length)
+                return FT_Common.FT_Err_Invalid_Table;
+
+            if (varSel < lastVarSel)
+                return FT_Common.FT_Err_Invalid_Table;
+
+            lastVarSel = varSel + 1;
+            if (defOff != 0)
+            {
+                defp.pos = base + defOff;
+                var numRanges = FT_NEXT_ULONG(defp);
+                var lastBase  = 0;
+
+                if (defp.pos + numRanges * 4 > valid.limit)
+                    return FT_Common.FT_Err_Invalid_Table;
+
+                for (var i = 0; i < numRanges; ++i)
+                {
+                    var _base = FT_NEXT_UOFF3(defp);
+                    var cnt  = FT_NEXT_BYTE(defp);
+
+                    if (_base + cnt >= 0x110000)
+                        return FT_Common.FT_Err_Invalid_Table;
+
+                    if (_base < lastBase)
+                        return FT_Common.FT_Err_Invalid_Table;
+
+                    lastBase = _base + cnt + 1;
+                }
+            }
+
+            if (nondefOff != 0)
+            {
+                defp.pos = base + nondefOff;
+                var numMappings = FT_NEXT_ULONG(defp);
+                var lastUni = 0;
+
+                if (numMappings * 4 > (valid.limit - defp.pos))
+                    return FT_Common.FT_Err_Invalid_Table;
+
+                for (var i = 0; i < numMappings; ++i)
+                {
+                    var uni = FT_NEXT_UOFF3(defp);
+                    var gid = FT_NEXT_USHORT(defp);
+
+                    if ( uni >= 0x110000)
+                        return FT_Common.FT_Err_Invalid_Table;
+                    if (uni < lastUni)
+                        return FT_Common.FT_Err_Invalid_Table;
+                    lastUni = uni + 1;
+                    if (valid.level >= 1 && gid >= valid.num_glyphs)
+                        return FT_Common.FT_Err_Invalid_Glyph_Index;
+                }
+            }
+        }
+
+        return 0;
+    }
+    this.get_cmap_info = function(cmap, cmap_info)
+    {
+        cmap_info.format = 14;
+        cmap_info.language = 0xFFFFFFFF;
+        return 0;
+    }
+}
+// finally
+function tt_face_build_cmaps(face)
+{
+    var table = dublicate_pointer(face.cmap_table);
+
+    if (null == table)
+        return FT_Common.FT_Err_Invalid_Table;
+
+    var limit = table.pos + face.cmap_size;
+    var p = dublicate_pointer(table);
+
+    if (p.data == null || p.pos + 4 > limit)
+        return FT_Common.FT_Err_Invalid_Table;
+
+    if (FT_NEXT_USHORT(p) != 0)
+        return FT_Common.FT_Err_Invalid_Table;
+
+    var num_cmaps = FT_NEXT_USHORT(p);
+    //#ifdef FT_MAX_CHARMAP_CACHEABLE
+    if (num_cmaps > FT_Common.FT_MAX_CHARMAP_CACHEABLE)
+    {
+    }
+    //#endif
+
+    var pclazz = FT_TT_CMAP_CLASSES_GET;
+    var pclazz_len = pclazz.length;
+    var clazz;
+    for (; num_cmaps > 0 && p.pos + 8 <= limit; num_cmaps--)
+    {
+        var charmap = new FT_CharMapRec();
+        charmap.platform_id = FT_NEXT_USHORT(p);
+        charmap.encoding_id = FT_NEXT_USHORT(p);
+        charmap.face        = face;
+        charmap.encoding    = FT_Common.FT_ENCODING_NONE;
+        var offset          = FT_NEXT_ULONG(p);
+
+        if (offset && offset <= face.cmap_size - 2)
+        {
+            var cmap = dublicate_pointer(table);
+            cmap.pos += offset;
+            var format = FT_PEEK_USHORT(cmap);
+            for (var i = 0; i < pclazz_len; i++)
+            {
+                clazz = pclazz[i];
+                if (clazz.format == format)
+                {
+                    var valid = new TT_Validator();
+                    valid.base = cmap;
+                    valid.limit = limit;
+                    valid.level = 0;
+                    valid.error = 0;
+                    valid.num_glyphs = face.max_profile.numGlyphs;
+
+                    var error = clazz.validate(cmap, valid);
+                    if (error == 0)
+                    {
+                        var ttcmap = FT_CMap_New(clazz, cmap, charmap);
+                        if (null != ttcmap)
+                        {
+                            ttcmap.flags = 0;
+                        }
+                    }
+                    break;
+                }
+            }
+        }
+    }
+    return 0;
+}
+function tt_get_cmap_info(cmap, cmap_info)
+{
+    var clazz = __FT_CMapRec(cmap).clazz;
+    return clazz.get_cmap_info(cmap, cmap_info);
+}
+/******************************************************************************/
+// driver
+/******************************************************************************/
+function tt_face_load_sfnt_header_stub(face,stream,face_index,header)
+{
+    return FT_Common.FT_Err_Unimplemented_Feature;
+}
+function tt_face_load_directory_stub(face,stream,header)
+{
+    return FT_Common.FT_Err_Unimplemented_Feature;
+}
+function tt_face_load_hdmx_stub(face,stream)
+{
+    return FT_Common.FT_Err_Unimplemented_Feature;
+}
+function tt_face_free_hdmx_stub(face)
+{
+}
+function tt_face_set_sbit_strike_stub(face,x_ppem,y_ppem)
+{
+    var req = new FT_Size_RequestRec();
+    req.type = FT_Common.FT_SIZE_REQUEST_TYPE_NOMINAL;
+    req.width = x_ppem;
+    req.height = y_ppem;
+    req.horiResolution = 0;
+    req.vertResolution = 0;
+
+    var strikeindex = 0x7FFFFFFF;
+    return tt_face_set_sbit_strike(face, req, strikeindex);
+}
+
+function tt_face_load_sbit_stub(face,stream)
+{
+    return FT_Common.FT_Err_Unimplemented_Feature;
+}
+function tt_face_free_sbit_stub(face)
+{
+}
+
+function tt_face_load_charmap_stub(face,cmap,input)
+{
+    return FT_Common.FT_Err_Unimplemented_Feature;
+}
+function tt_face_free_charmap_stub(face,cmap)
+{
+    return 0;
+}
+
+function get_sfnt_table(face, tag)
+{
+    var table = null;
+    switch ( tag )
+    {
+    case 0:
+        table = face.header;
+        break;
+    case 3:
+        table = face.horizontal;
+        break;
+    case 4:
+        table = (face.vertical_info == 1) ? face.vertical : null;
+        break;
+    case 2:
+        table = (face.os2.version == 0xFFFF) ? null : face.os2;
+        break;
+    case 5:
+        table = face.postscript;
+        break;
+    case 1:
+        table = face.max_profile;
+        break;
+    case 6:
+        table = (face.pclt.Version != 0) ? face.pclt : null;
+        break;
+    default:
+        break;
+    }
+    return table;
+}
+function sfnt_table_info(face, idx, tag)
+{
+    if (tag != null)
+        return {tag:0,offset:0,length:face.num_tables};
+
+    if (idx >= face.num_tables)
+        return null;
+    var t = face.dir_tables[idx];
+    return {tag:t.Tag,offset:t.Offset,length:t.Length};
+}
+function ft_mem_strcpyn(dst, src, size)
+{
+    var len = src.length;
+    var ret = 1;
+    if (len > size)
+    {
+        len = size;
+        ret = 0;
+    }
+    var i=0;
+    while (len > 1)
+    {
+        dst[dst.pos + i] = src.charCodeAt(i);
+        i++;
+        size--;
+    }
+    dst[dst.pos + i] = 0;
+    return ret;
+}
+function sfnt_get_glyph_name(face, glyph_index, buffer, buffer_max)
+{
+    var gname = tt_face_get_ps_name(face, glyph_index);
+    var error = FT_Error;
+    if (error == 0)
+        ft_mem_strcpyn(buffer, gname, buffer_max);
+    return error;
+}
+function sfnt_get_name_index(face, glyph_name)
+{
+    var max_gid = 0xFFFFFFFF;
+    if (face.num_glyphs < 0)
+        return 0;
+    else if (face.num_glyphs < 0xFFFFFFFF)
+        max_gid = face.num_glyphs;
+    for (var i = 0; i < max_gid; i++)
+    {
+        var gname = tt_face_get_ps_name(face, i);
+        var error = FT_Error;
+        if (error != 0)
+            continue;
+
+        if (glyph_name == gname)
+            return i;
+    }
+    return 0;
+}
+function sfnt_get_ps_name(face)
+{
+    var n, found_win, found_apple;
+    var result = "";
+
+    if (face.postscript_name != "")
+        return face.postscript_name;
+
+    found_win   = -1;
+    found_apple = -1;
+
+    var num_faces = face.num_faces;
+    for (n = 0; n < num_faces; n++)
+    {
+        var name = face.name_table.names[n];
+        if (name.nameID == 6 && name.stringLength > 0)
+        {
+            if (name.platformID == 3 && name.encodingID == 1 && name.languageID == 0x409)
+                found_win = n;
+
+            if (name.platformID == 1 && name.encodingID == 0 && name.languageID == 0)
+                found_apple = n;
+        }
+    }
+
+    if (found_win != -1)
+    {
+        var stream = face.name_table.stream;
+        var name = face.name_table.names[found_win];
+        var len = parseInt(name.stringLength / 2);
+
+        var error = stream.Seek(name.stringOffset);
+        if (error == 0)
+            error = stream.EnterFrame(name.stringLength);
+        if (error != 0)
+        {
+            name.stringOffset = 0;
+            name.stringLength = 0;
+            face.postscript_name = "";
+            return "";
+        }
+        var d = stream.data;
+        var cur = stream.cur;
+        for (; len > 0; len--, cur += 2)
+        {
+            if (d[cur] == 0 && d[cur+1] >= 32 && d[cur+1] < 128)
+                result += String.fromCharCode(d[cur+1]);
+        }
+        stream.ExitFrame();
+        face.postscript_name = result;
+        return result;
+    }
+
+    if (found_apple != -1)
+    {
+        var stream = face.name_table.stream;
+        var name = face.name_table.names[found_apple];
+        var len = name.stringLength;
+
+        var error = stream.Seek(name.stringOffset);
+        if (error == 0)
+        {
+            result = stream.ReadString1(name.stringLength);
+            error = FT_Error;
+        }
+        if (error != 0)
+        {
+            name.stringOffset = 0;
+            name.stringLength = 0;
+            face.postscript_name = "";
+            return "";
+        }
+
+        face.postscript_name = result;
+        return result;
+    }
+
+    face.postscript_name = result;
+    return result;
+}
+
+var sfnt_service_glyph_dict = new FT_Service_GlyphDictRec(sfnt_get_glyph_name,sfnt_get_name_index);
+var sfnt_service_ps_name = new FT_Service_PsFontNameRec(sfnt_get_ps_name);
+var tt_service_get_cmap_info = new FT_Service_TTCMapsRec(tt_get_cmap_info);
+
+var tt_cmap_classes = new Array(9);
+tt_cmap_classes[0] = new tt_cmap0_class_rec();
+tt_cmap_classes[1] = new tt_cmap2_class_rec();
+tt_cmap_classes[2] = new tt_cmap4_class_rec();
+tt_cmap_classes[3] = new tt_cmap6_class_rec();
+tt_cmap_classes[4] = new tt_cmap8_class_rec();
+tt_cmap_classes[5] = new tt_cmap10_class_rec();
+tt_cmap_classes[6] = new tt_cmap12_class_rec();
+tt_cmap_classes[7] = new tt_cmap13_class_rec();
+tt_cmap_classes[8] = new tt_cmap14_class_rec();
+
+var sfnt_service_sfnt_table = new FT_Service_SFNT_TableRec(tt_face_load_any,get_sfnt_table,sfnt_table_info);
+var sfnt_service_bdf = new FT_Service_BDFRec(sfnt_get_charset_id,tt_face_find_bdf_prop);
+
+var sfnt_services = new Array(5);
+sfnt_services[0] = new FT_ServiceDescRec(FT_SERVICE_ID_SFNT_TABLE,sfnt_service_sfnt_table);
+sfnt_services[1] = new FT_ServiceDescRec(FT_SERVICE_ID_POSTSCRIPT_FONT_NAME,sfnt_service_ps_name);
+sfnt_services[2] = new FT_ServiceDescRec(FT_SERVICE_ID_GLYPH_DICT,sfnt_service_glyph_dict);
+sfnt_services[3] = new FT_ServiceDescRec(FT_SERVICE_ID_BDF,sfnt_service_bdf);
+sfnt_services[4] = new FT_ServiceDescRec(FT_SERVICE_ID_TT_CMAP,tt_service_get_cmap_info);
+
+function tt_face_get_name(face, nameid)
+{
+    FT_Error = 0;
+    var found_apple         = -1;
+    var found_apple_roman   = -1;
+    var found_apple_english = -1;
+    var found_win           = -1;
+    var found_unicode       = -1;
+
+    var is_english = false;
+    var convert = null;
+    var rec = null;
+    var num_names = face.num_names;
+    var n = 0;
+    for (; n < face.num_names; n++)
+    {
+        rec = face.name_table.names[n];
+        if (rec.nameID == nameid && rec.stringLength > 0)
+        {
+            switch (rec.platformID)
+            {
+            case FT_Common.TT_PLATFORM_APPLE_UNICODE:
+            case FT_Common.TT_PLATFORM_ISO:
+                found_unicode = n;
+                break;
+
+            case FT_Common.TT_PLATFORM_MACINTOSH:
+                if ( rec.languageID == 0)
+                    found_apple_english = n;
+                else if (rec.encodingID == 0)
+                    found_apple_roman = n;
+                break;
+
+            case FT_Common.TT_PLATFORM_MICROSOFT:
+                if (found_win == -1 || (rec.languageID & 0x3FF) == 0x009)
+                {
+                    switch ( rec.encodingID )
+                    {
+                    case FT_Common.TT_MS_ID_SYMBOL_CS:
+                    case FT_Common.TT_MS_ID_UNICODE_CS:
+                    case FT_Common.TT_MS_ID_UCS_4:
+                        is_english = ((rec.languageID & 0x3FF) == 0x009) ? true : false;
+                        found_win  = n;
+                        break;
+
+                    default:
+                        break;
+                    }
+                }
+                break;
+            default:
+                break;
+            }
+        }
+    }
+
+    found_apple = found_apple_roman;
+    if (found_apple_english >= 0)
+        found_apple = found_apple_english;
+
+    if (found_win >= 0 && !(found_apple >= 0 && false === is_english))
+    {
+        rec = face.name_table.names[found_win];
+        switch (rec.encodingID)
+        {
+        case FT_Common.TT_MS_ID_UNICODE_CS:
+        case FT_Common.TT_MS_ID_SYMBOL_CS:
+            convert = tt_name_entry_ascii_from_utf16;
+            break;
+
+        case FT_Common.TT_MS_ID_UCS_4:
+            convert = tt_name_entry_ascii_from_utf16;
+            break;
+
+        default:
+            break;
+        }
+    }
+    else if (found_apple >= 0)
+    {
+        rec     = face.name_table.names[found_apple];
+        convert = tt_name_entry_ascii_from_other;
+    }
+    else if (found_unicode >= 0)
+    {
+        rec     = face.name_table.names[found_unicode];
+        convert = tt_name_entry_ascii_from_utf16;
+    }
+
+    if (rec && convert)
+    {
+        if (rec.string == null)
+        {
+            var stream = face.name_table.stream;
+            FT_Error = stream.Seek(rec.stringOffset);
+            if (FT_Error == 0)
+            {
+                rec.string = stream.ReadArray(rec.stringLength);
+            }
+            if (FT_Error != 0 || null == rec.string)
+                return "";
+        }
+        return convert(rec);
+    }
+    return "";
+}
+/* convert an Apple Roman or symbol name entry to ASCII */
+function tt_name_entry_ascii_from_utf16(entry)
+{
+    var string = "";
+    var p = entry.string;
+    var len = parseInt(entry.stringLength / 2);
+    if (len > p.length)
+        len = p.length;
+
+    var code = 0;
+    for (var n = 0; n < len; n++)
+    {
+        code = p[2*n] << 8 | p[2*n+1];
+        if (code < 32 || code > 127)
+            code = FT_Common.SYMBOL_CONST_VOPROS;
+
+        string += String.fromCharCode(code);
+    }
+    return string;
+}
+
+/* convert an Apple Roman or symbol name entry to ASCII */
+function tt_name_entry_ascii_from_other(entry)
+{
+    var string = "";
+    var p = entry.string;
+    var len = entry.stringLength;
+    if (len > p.length)
+        len = p.length;
+
+    var code = 0;
+    for (var n = 0; n < len; n++)
+    {
+        code = p[n];
+        if ( code < 32 || code > 127 )
+            code = FT_Common.SYMBOL_CONST_VOPROS;
+
+        string += String.fromCharCode(code);
+    }
+    return string;
+}
+
+function sfnt_init_face(stream, face, face_index)
+{
+    var error = 0;
+    var library = face.driver.library;
+
+    var sfnt = face.sfnt;
+    if (null == sfnt)
+    {
+        sfnt = library.FT_Get_Module_Interface("sfnt");
+        if (null == sfnt)
+            return FT_Common.FT_Err_Invalid_File_Format;
+
+        face.sfnt = sfnt;
+        face.goto_table = sfnt.goto_table;
+    }
+
+    face.psnames = FT_FACE_FIND_GLOBAL_SERVICE(face, "postscript-cmaps");
+
+    error = sfnt_open_font(stream, face);
+    if (error != FT_Common.FT_Err_Ok)
+        return error;
+
+    if (face_index < 0)
+        face_index = 0;
+
+    if (face_index >= face.ttc_header.count)
+        return FT_Common.FT_Err_Invalid_Argument;
+
+    error = stream.Seek(face.ttc_header.offsets[face_index])
+    if (error != FT_Common.FT_Err_Ok)
+        return error;
+
+    /* check that we have a valid TrueType file */
+    error = sfnt.load_font_dir(face, stream);
+    if (error != FT_Common.FT_Err_Ok)
+        return error;
+
+    face.num_faces = face.ttc_header.count;
+    face.face_index = face_index;
+
+    return error;
+}
+function sfnt_load_face(stream, face, face_index)
+{
+    var error = FT_Common.FT_Err_Ok;
+    var psnames_error = FT_Common.FT_Err_Ok;
+
+    var has_outline = false;
+    var is_apple_sbit = false;
+    var ignore_preferred_family = false;
+    var ignore_preferred_subfamily = false;
+
+    var sfnt = face.sfnt;
+
+    if (face.internal.incremental_interface != null)
+        has_outline = true;
+    else if (null != tt_face_lookup_table(face, FT_Common.TTAG_glyf))
+        has_outline = true;
+    else if (null != tt_face_lookup_table(face, FT_Common.TTAG_CFF))
+        has_outline = true;
+
+    if (false === has_outline && sfnt.load_bhed != null)
+    {
+        error = sfnt.load_bhed(face, stream);
+        is_apple_sbit = (error == 0) ? false : true;
+    }
+
+    if (false === is_apple_sbit)
+    {
+        error = sfnt.load_head(face, stream);
+        if (error != 0)
+            return error;
+    }
+
+    if (0 == face.header.Units_Per_EM)
+        return FT_Common.FT_Err_Invalid_Table;
+
+    error = sfnt.load_maxp(face, stream);
+    error = sfnt.load_cmap(face, stream);
+
+    error = sfnt.load_name(face, stream);
+    error = sfnt.load_post(face, stream);
+
+    psnames_error = error;
+
+    if (false === is_apple_sbit)
+    {
+        error = sfnt.load_hhea(face, stream, 0);
+        if (error == 0)
+        {
+            error = sfnt.load_hmtx(face, stream, 0);
+            if (error == FT_Common.FT_Err_Table_Missing)
+            {
+                error = FT_Common.FT_Err_Hmtx_Table_Missing;
+
+                //#ifdef FT_CONFIG_OPTION_INCREMENTAL
+                if (face.internal.incremental_interface &&
+                    face.internal.incremental_interface.funcs.get_glyph_metrics)
+                {
+                    face.horizontal.number_Of_HMetrics = 0;
+                    error = FT_Common.FT_Err_Ok;
+                }
+                //#endif
+            }
+        }
+        else if (error == FT_Common.FT_Err_Table_Missing)
+        {
+            if (face.format_tag == FT_Common.TTAG_true)
+            {
+                has_outline = false;
+                error       = FT_Common.FT_Err_Ok;
+            }
+            else
+            {
+                error = FT_Common.FT_Err_Horiz_Header_Missing;
+
+                //#ifdef FT_CONFIG_OPTION_INCREMENTAL
+                if (face.internal.incremental_interface &&
+                    face.internal.incremental_interface.funcs.get_glyph_metrics)
+                {
+                    face.horizontal.number_Of_HMetrics = 0;
+                    error = FT_Common.FT_Err_Ok;
+                }
+                //#endif
+            }
+        }
+
+        if (error != 0)
+            return error;
+
+        error = sfnt.load_hhea(face, stream, 1);
+        if (error == 0)
+        {
+            error = sfnt.load_hmtx(face, stream, 1);
+            if (error == 0)
+                face.vertical_info = 1;
+        }
+
+        if (error != 0 && error != FT_Common.FT_Err_Table_Missing)
+            return error;
+
+        error = sfnt.load_os2(face, stream);
+        if (error != 0)
+        {
+            /* we treat the table as missing if there are any errors */
+            face.os2.version = 0xFFFF;
+        }
+    }
+
+    if (sfnt.load_eblc)
+    {
+        error = sfnt.load_eblc(face, stream);
+        if (error != 0)
+        {
+            if (error == FT_Common.FT_Err_Table_Missing)
+                error = FT_Common.FT_Err_Ok;
+            else
+                return error;
+        }
+    }
+
+    error = sfnt.load_pclt(face, stream);
+    if (error != 0)
+    {
+        if (error != FT_Common.FT_Err_Table_Missing)
+            return error;
+
+        face.pclt.Version = 0;
+    }
+
+    error = sfnt.load_gasp(face, stream);
+    error = sfnt.load_kern(face, stream);
+
+    face.num_glyphs = face.max_profile.numGlyphs;
+
+    face.family_name = "";
+    face.style_name = "";
+
+    if (face.os2.version != 0xFFFF && (face.os2.fsSelection & 256) != 0)
+    {
+        /*
+        if (false ==  ignore_preferred_family)
+        {
+            face.family_name = tt_face_get_name(face, FT_Common.TT_NAME_ID_PREFERRED_FAMILY);
+            error = FT_Error;
+            if (error != 0)
+                return error;
+        }
+        */
+        if ("" == face.family_name)
+        {
+            face.family_name = tt_face_get_name(face, FT_Common.TT_NAME_ID_FONT_FAMILY);
+            error = FT_Error;
+            if (error != 0)
+                return error;
+        }
+
+        /*
+        if (false == ignore_preferred_subfamily)
+        {
+            face.style_name = tt_face_get_name(face, FT_Common.TT_NAME_ID_PREFERRED_SUBFAMILY);
+            error = FT_Error;
+            if (error != 0)
+                return error;
+        }
+        */
+        if ("" == face.style_name)
+        {
+            face.style_name = tt_face_get_name(face, FT_Common.TT_NAME_ID_FONT_SUBFAMILY);
+            error = FT_Error;
+            if (error != 0)
+                return error;
+        }
+    }
+    else
+    {
+        face.family_name = tt_face_get_name(face, FT_Common.TT_NAME_ID_WWS_FAMILY);
+        error = FT_Error;
+        if (error != 0)
+            return error;
+
+        /*
+        if (face.family_name == "" && false == ignore_preferred_family)
+        {
+            face.family_name = tt_face_get_name(face, FT_Common.TT_NAME_ID_PREFERRED_FAMILY);
+            error = FT_Error;
+            if (error != 0)
+                return error;
+        }
+        */
+        if (face.family_name == "")
+        {
+            face.family_name = tt_face_get_name(face, FT_Common.TT_NAME_ID_FONT_FAMILY);
+            error = FT_Error;
+            if (error != 0)
+                return error;
+        }
+
+        face.style_name = tt_face_get_name(face, FT_Common.TT_NAME_ID_WWS_SUBFAMILY);
+        error = FT_Error;
+        if (error != 0)
+            return error;
+
+        /*
+        if (face.style_name == "" && false == ignore_preferred_subfamily)
+        {
+            face.style_name = tt_face_get_name(face, FT_Common.TT_NAME_ID_PREFERRED_SUBFAMILY);
+            error = FT_Error;
+            if (error != 0)
+                return error;
+        }
+        */
+        if (face.style_name == "")
+        {
+            face.style_name = tt_face_get_name(face, FT_Common.TT_NAME_ID_FONT_SUBFAMILY);
+            error = FT_Error;
+            if (error != 0)
+                return error;
+        }
+    }
+
+    // face_flags
+    var flags = face.face_flags;
+    if (has_outline === true)
+        flags |= FT_Common.FT_FACE_FLAG_SCALABLE;
+
+    flags |= (FT_Common.FT_FACE_FLAG_SFNT | FT_Common.FT_FACE_FLAG_HORIZONTAL);
+
+    //#ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES
+    if (psnames_error == 0 && face.postscript.FormatType != 0x00030000)
+        flags |= FT_Common.FT_FACE_FLAG_GLYPH_NAMES;
+    //#endif
+
+    /* fixed width font? */
+    if (face.postscript.isFixedPitch)
+        flags |= FT_Common.FT_FACE_FLAG_FIXED_WIDTH;
+
+    /* vertical information? */
+    if (face.vertical_info)
+        flags |= FT_Common.FT_FACE_FLAG_VERTICAL;
+
+    /* kerning available ? */
+    if (face.kern_avail_bits != 0)
+        flags |= FT_Common.FT_FACE_FLAG_KERNING;
+
+    //#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
+    /* Don't bother to load the tables unless somebody asks for them. */
+    /* No need to do work which will (probably) not be used.          */
+    if (null != tt_face_lookup_table(face, FT_Common.TTAG_glyf) &&
+        null != tt_face_lookup_table(face, FT_Common.TTAG_fvar) &&
+        null != tt_face_lookup_table(face, FT_Common.TTAG_gvar))
+        flags |= FT_Common.FT_FACE_FLAG_MULTIPLE_MASTERS;
+    //#endif
+
+    face.face_flags = flags;
+
+    // Compute style flags.
+    flags = 0;
+    if (has_outline === true && face.os2.version != 0xFFFF)
+    {
+        if ((face.os2.fsSelection & 512) != 0)
+            flags |= FT_Common.FT_STYLE_FLAG_ITALIC;
+        else if ((face.os2.fsSelection & 1) != 0)
+            flags |= FT_Common.FT_STYLE_FLAG_ITALIC;
+
+        if ((face.os2.fsSelection & 32) != 0)
+            flags |= FT_Common.FT_STYLE_FLAG_BOLD;
+    }
+    else
+    {
+        if ((face.header.Mac_Style & 1) != 0)
+            flags |= FT_Common.FT_STYLE_FLAG_BOLD;
+
+        if ((face.header.Mac_Style & 2) != 0)
+            flags |= FT_Common.FT_STYLE_FLAG_ITALIC;
+    }
+
+    face.style_flags = flags;
+
+    // TODO: ---
+    tt_face_build_cmaps(face);
+
+    for (var m = 0; m < face.num_charmaps; m++)
+    {
+        var charmap = __FT_CharmapRec(face.charmaps[m]);
+        charmap.encoding = 0;
+        charmap.encoding = sfnt_find_encoding(charmap.platform_id, charmap.encoding_id);
+    }
+
+    //#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
+    var count = face.num_sbit_strikes;
+
+    if (count > 0)
+    {
+        var em_size = face.header.Units_Per_EM;
+        var avgwidth = face.os2.xAvgCharWidth;
+        var metrics = new FT_Size_Metrics();
+
+        if (em_size == 0 || face.os2.version == 0xFFFF)
+        {
+            avgwidth = 0;
+            em_size = 1;
+        }
+
+        face.available_sizes = new Array(count);
+
+        for (var i = 0; i < count; i++)
+        {
+            face.available_sizes[i] = new FT_Bitmap_Size();
+            var bsize = face.available_sizes[i];
+
+            error = sfnt.load_strike_metrics(face, i, metrics);
+            if (error != 0)
+                return error;
+
+            bsize.height = (metrics.height >>> 6) & 0xFFFF;
+            bsize.width = parseInt((avgwidth * metrics.x_ppem + parseInt(em_size / 2)) / em_size) & 0xFFFF;
+
+            bsize.x_ppem = metrics.x_ppem << 6;
+            bsize.y_ppem = metrics.y_ppem << 6;
+
+            /* assume 72dpi */
+            bsize.size   = metrics.y_ppem << 6;
+        }
+
+        face.face_flags |= FT_Common.FT_FACE_FLAG_FIXED_SIZES;
+        face.num_fixed_sizes = count;
+    }
+
+    //#endif TT_CONFIG_OPTION_EMBEDDED_BITMAPS
+
+    /* a font with no bitmaps and no outlines is scalable; */
+    /* it has only empty glyphs then                       */
+    if (((face.face_flags & FT_Common.FT_FACE_FLAG_FIXED_SIZES) == 0) &&
+        ((face.face_flags & FT_Common.FT_FACE_FLAG_SCALABLE) == 0))
+        face.face_flags |= FT_Common.FT_FACE_FLAG_SCALABLE;
+
+    // Set up metrics
+    if ((face.face_flags & FT_Common.FT_FACE_FLAG_SCALABLE) != 0)
+    {
+        face.bbox.xMin    = face.header.xMin;
+        face.bbox.yMin    = face.header.yMin;
+        face.bbox.xMax    = face.header.xMax;
+        face.bbox.yMax    = face.header.yMax;
+        face.units_per_EM = face.header.Units_Per_EM;
+
+        face.ascender  = face.horizontal.Ascender;
+        face.descender = face.horizontal.Descender;
+
+        face.height = (face.ascender - face.descender + face.horizontal.Line_Gap);
+
+        if (face.ascender == 0 && face.descender == 0)
+        {
+            if (face.os2.version != 0xFFFF)
+            {
+                if (face.os2.sTypoAscender || face.os2.sTypoDescender)
+                {
+                    face.ascender  = face.os2.sTypoAscender;
+                    face.descender = face.os2.sTypoDescender;
+
+                    face.height = (face.ascender - face.descender + face.os2.sTypoLineGap);
+                }
+                else
+                {
+                    face.ascender  = face.os2.usWinAscent;
+                    face.descender = -face.os2.usWinDescent;
+
+                    face.height = (face.ascender - face.descender);
+                }
+            }
+        }
+
+        face.max_advance_width  = face.horizontal.advance_Width_Max;
+        face.max_advance_height = ((face.vertical_info != 0) ? face.vertical.advance_Height_Max : face.height);
+
+        face.underline_position  = face.postscript.underlinePosition - parseInt(face.postscript.underlineThickness / 2);
+        face.underline_thickness = face.postscript.underlineThickness;
+    }
+    return error;
+}
+function sfnt_done_face()
+{
+}
+
+function sfnt_find_encoding(platform_id, encoding_id)
+{
+    switch (platform_id)
+    {
+        case FT_Common.TT_PLATFORM_ISO:
+        {
+            return FT_Common.FT_ENCODING_UNICODE;
+        }
+        case FT_Common.TT_PLATFORM_APPLE_UNICODE:
+        {
+            return FT_Common.FT_ENCODING_UNICODE;
+        }
+        case FT_Common.TT_PLATFORM_MACINTOSH:
+        {
+            if (FT_Common.TT_MAC_ID_ROMAN == encoding_id)
+                return FT_Common.FT_ENCODING_APPLE_ROMAN;
+            break;
+        }
+        case FT_Common.TT_PLATFORM_MICROSOFT:
+        {
+            if (FT_Common.TT_MS_ID_SYMBOL_CS == encoding_id)
+                return FT_Common.FT_ENCODING_MS_SYMBOL;
+            if (FT_Common.TT_MS_ID_UCS_4 == encoding_id)
+                return FT_Common.FT_ENCODING_UNICODE;
+            if (FT_Common.TT_MS_ID_UNICODE_CS == encoding_id)
+                return FT_Common.FT_ENCODING_UNICODE;
+            if (FT_Common.TT_MS_ID_SJIS == encoding_id)
+                return FT_Common.FT_ENCODING_SJIS;
+            if (FT_Common.TT_MS_ID_GB2312 == encoding_id)
+                return FT_Common.FT_ENCODING_GB2312;
+            if (FT_Common.TT_MS_ID_BIG_5 == encoding_id)
+                return FT_Common.FT_ENCODING_BIG5;
+            if (FT_Common.TT_MS_ID_WANSUNG == encoding_id)
+                return FT_Common.FT_ENCODING_WANSUNG;
+            if (FT_Common.TT_MS_ID_JOHAB == encoding_id)
+                return FT_Common.FT_ENCODING_JOHAB;
+            break;
+        }
+        default:
+            break;
+    }
+    return FT_Common.FT_ENCODING_NONE;
+}
+
+function sfnt_open_font(stream, face)
+{
+    var error = 0;
+
+    face.ttc_header.tag     = 0;
+    face.ttc_header.version = 0;
+    face.ttc_header.count   = 0;
+
+    var offset = stream.pos;
+    var tag = stream.ReadULong();
+    error = FT_Error;
+    FT_Error = 0;
+
+    if (error != FT_Common.FT_Err_Ok)
+      return error;
+
+    if (tag != 0x00010000 && tag != FT_Common.TTAG_ttcf && tag != FT_Common.TTAG_OTTO &&
+         tag != FT_Common.TTAG_true && tag != FT_Common.TTAG_typ1 && tag != 0x00020000)
+        return FT_Common.FT_Err_Unknown_File_Format;
+
+    face.ttc_header.tag = FT_Common.TTAG_ttcf;
+
+    if (tag == FT_Common.TTAG_ttcf)
+    {
+        error = stream.EnterFrame(8);
+        if (error != 0)
+            return error;
+
+        face.ttc_header.version = stream.GetLong();
+        face.ttc_header.count = stream.GetLong();
+
+        stream.ExitFrame();
+
+        if (face.ttc_header.count == 0)
+            return FT_Common.FT_Err_Invalid_Table;
+
+        var ul = FT_Common.IntToUInt(face.ttc_header.count);
+        if (ul > (stream.size / (28 + 4)))
+            return FT_Common.FT_Err_Array_Too_Large;
+
+        face.ttc_header.offsets = new Array(ul);
+        error = stream.EnterFrame(4*ul);
+
+        if (error != FT_Common.FT_Err_Ok)
+            return error;
+
+        for (var n = 0; n < ul; n++)
+            face.ttc_header.offsets[n] = stream.GetULong();
+
+        stream.ExitFrame();
+    }
+    else
+    {
+        face.ttc_header.version = 1 << 16;
+        face.ttc_header.count = 1;
+
+        face.ttc_header.offsets = new Array(1);
+        face.ttc_header.offsets[0] = offset;
+    }
+
+    return error;
+}
+
+function _sfnt_interface()
+{
+    this.goto_table = tt_face_goto_table;
+
+    this.init_face = sfnt_init_face;
+    this.load_face = sfnt_load_face;
+    this.done_face = sfnt_done_face;
+    this.get_interface = sfnt_get_interface;
+    
+    this.load_any = tt_face_load_any;
+
+    //#ifdef FT_CONFIG_OPTION_OLD_INTERNALS
+    this.load_sfnt_header = tt_face_load_sfnt_header_stub;
+    this.load_directory = tt_face_load_directory_stub;
+    //#endif
+
+    this.load_head = tt_face_load_head;
+    this.load_hhea = tt_face_load_hhea;
+    this.load_cmap = tt_face_load_cmap;
+    this.load_maxp = tt_face_load_maxp;
+    this.load_os2 = tt_face_load_os2;
+    this.load_post = tt_face_load_post;
+
+    this.load_name = tt_face_load_name;
+    this.free_name = tt_face_free_name;
+
+    //#ifdef FT_CONFIG_OPTION_OLD_INTERNALS
+    this.load_hdmx_stub = tt_face_load_hdmx_stub;
+    this.free_hdmx_stub = tt_face_free_hdmx_stub;
+    //#endif
+
+    this.load_kern = tt_face_load_kern;
+
+    this.load_gasp = tt_face_load_gasp;
+    this.load_pclt = tt_face_load_pclt;
+
+    this.load_bhed = tt_face_load_bhed;
+
+    //#ifdef FT_CONFIG_OPTION_OLD_INTERNALS
+    this.set_sbit_strike_stub = tt_face_set_sbit_strike_stub;
+    this.load_sbits_stub = tt_face_load_sbit_stub;
+
+    this.find_sbit_image = tt_find_sbit_image;
+    this.load_sbit_metrics = tt_load_sbit_metrics;
+    //#endif
+
+    this.load_sbit_image = tt_face_load_sbit_image;
+
+    //#ifdef FT_CONFIG_OPTION_OLD_INTERNALS
+    this.free_sbits_stub = tt_face_free_sbit_stub;
+    //#endif
+
+    this.get_psname = tt_face_get_ps_name;
+    this.free_psnames = tt_face_free_ps_names;
+
+    //#ifdef FT_CONFIG_OPTION_OLD_INTERNALS
+    this.load_charmap_stub = tt_face_load_charmap_stub;
+    this.free_charmap_stub = tt_face_free_charmap_stub;
+    //#endif
+
+    this.get_kerning = tt_face_get_kerning;
+
+    this.load_font_dir = tt_face_load_font_dir;
+    this.load_hmtx = tt_face_load_hmtx;
+
+    this.load_eblc = tt_face_load_eblc;
+    this.free_eblc = tt_face_free_eblc;
+
+    this.set_sbit_strike = tt_face_set_sbit_strike;
+    this.load_strike_metrics = tt_face_load_strike_metrics;
+
+    this.get_metrics = tt_face_get_metrics;
+}
+var sfnt_interface = new _sfnt_interface();
+
+/******************************************************************************/
+// pic
+/******************************************************************************/
+var FT_SFNT_SERVICES_GET            = sfnt_services;
+var FT_SFNT_SERVICE_GLYPH_DICT_GET  = sfnt_service_glyph_dict;
+var FT_SFNT_SERVICE_PS_NAME_GET     = sfnt_service_ps_name;
+var FT_TT_SERVICE_GET_CMAP_INFO_GET = tt_service_get_cmap_info;
+var FT_TT_CMAP_CLASSES_GET          = tt_cmap_classes;
+var FT_SFNT_SERVICE_SFNT_TABLE_GET  = sfnt_service_sfnt_table;
+var FT_SFNT_SERVICE_BDF_GET         = sfnt_service_bdf;
+var FT_SFNT_INTERFACE_GET           = sfnt_interface;
+
+function sfnt_get_interface(module,name)
+{
+    return ft_service_list_lookup(FT_SFNT_SERVICES_GET, name);
+}
+
+function create_sfnt_module(library)
+{
+    var sfnt_mod = new FT_Module();
+    sfnt_mod.clazz = new FT_Module_Class();
+
+    var clazz = sfnt_mod.clazz;
+    clazz.flags = 0;
+    clazz.name = "sfnt";
+    clazz.version = 0x10000;
+    clazz.requires = 0x20000;
+
+    clazz.module_interface = FT_SFNT_INTERFACE_GET;
+    clazz.init = null;
+    clazz.done = null;
+
+    clazz.get_interface = sfnt_get_interface;
+
+    sfnt_mod.library = library;
+    sfnt_mod.memory = library.Memory;
+    sfnt_mod.generic = null;
+
+    return sfnt_mod;
+}
+
diff --git a/Common/FontsFreeType/Private/FreeType/services.js b/Common/FontsFreeType/Private/FreeType/services.js
new file mode 100644
index 0000000000000000000000000000000000000000..2fa84548aa7f8c9ae16057bbf8d0d9b4bc49c57a
--- /dev/null
+++ b/Common/FontsFreeType/Private/FreeType/services.js
@@ -0,0 +1,258 @@
+/******************************************************************************/
+//                                  SERVICES
+/******************************************************************************/
+
+/******************************************************************************/
+// bdf
+/******************************************************************************/
+var FT_SERVICE_ID_BDF = "bdf";
+function FT_Service_BDFRec(get_charset_id_,get_property_)
+{
+    this.get_charset_id = get_charset_id_;
+    this.get_property = get_property_;
+}
+/******************************************************************************/
+// cid
+/******************************************************************************/
+var FT_SERVICE_ID_CID = "CID";
+function FT_Service_CIDRec(get_ros_, get_is_cid_, get_cid_from_glyph_index_)
+{
+    this.get_ros = get_ros_;
+    this.get_is_cid = get_is_cid_;
+    this.get_cid_from_glyph_index = get_cid_from_glyph_index_;
+}
+/******************************************************************************/
+// glyph-dict
+/******************************************************************************/
+var FT_SERVICE_ID_GLYPH_DICT = "glyph-dict";
+function FT_Service_GlyphDictRec(get_name_, name_index_)
+{
+    this.get_name = get_name_;
+    this.name_index = name_index_;
+}
+/******************************************************************************/
+// gxval
+/******************************************************************************/
+var FT_SERVICE_ID_GX_VALIDATE = "truetypegx-validate";
+var FT_SERVICE_ID_CLASSICKERN_VALIDATE = "classickern-validate";
+
+function FT_Service_GXvalidateRec(validate_)
+{
+    this.validate = validate_;
+}
+function FT_Service_CKERNvalidateRec(validate_)
+{
+    this.validate = validate_;
+}
+/******************************************************************************/
+// kerning
+/******************************************************************************/
+var FT_SERVICE_ID_KERNING = "kerning";
+function FT_Service_KerningRec(get_track_)
+{
+    this.get_track = get_track_;
+}
+/******************************************************************************/
+// multi-masters
+/******************************************************************************/
+var FT_SERVICE_ID_MULTI_MASTERS = "multi-masters";
+function FT_Service_MultiMastersRec(get_mm_, set_mm_design_, set_mm_blend_, get_mm_var_, set_var_design_)
+{
+    this.get_mm = get_mm_;
+    this.set_mm_design = set_mm_design_;
+    this.set_mm_blend = set_mm_blend_;
+    this.get_mm_var = get_mm_var_;
+    this.set_var_design = set_var_design_;
+}
+/******************************************************************************/
+// opentype-validate
+/******************************************************************************/
+var FT_SERVICE_ID_OPENTYPE_VALIDATE = "opentype-validate";
+function FT_Service_OTvalidateRec(validate_)
+{
+    this.validate = validate_;
+}
+/******************************************************************************/
+// pfr-metrics
+/******************************************************************************/
+var FT_SERVICE_ID_PFR_METRICS = "pfr-metrics";
+function FT_Service_PfrMetricsRec(get_metrics_,get_kerning_,get_advance_)
+{
+    this.get_metrics = get_metrics_;
+    this.get_kerning = get_kerning_;
+    this.get_advance = get_advance_;
+}
+/******************************************************************************/
+// postscript-font-name
+/******************************************************************************/
+var FT_SERVICE_ID_POSTSCRIPT_FONT_NAME = "postscript-font-name";
+function FT_Service_PsFontNameRec(get_ps_font_name_)
+{
+    this.get_ps_font_name = get_ps_font_name_;
+}
+/******************************************************************************/
+// postscript-cmaps
+/******************************************************************************/
+var FT_SERVICE_ID_POSTSCRIPT_CMAPS = "postscript-cmaps";
+
+function PS_UniMap()
+{
+    this.unicode;
+    this.glyph_index;
+}
+function PS_UnicodesRec()
+{
+    this.cmap;
+    this.num_maps;
+    this.maps;
+}
+function FT_Service_PsCMapsRec(unicode_value_, unicodes_init_,unicodes_char_index_, unicodes_char_next_, macintosh_name_,
+                                    adobe_std_strings_, adobe_std_encoding_, adobe_expert_encoding_)
+{
+    this.unicode_value = unicode_value_;
+
+    this.unicodes_init = unicodes_init_;
+    this.unicodes_char_index = unicodes_char_index_;
+    this.unicodes_char_next = unicodes_char_next_;
+
+    this.macintosh_name = macintosh_name_;
+    this.adobe_std_strings = adobe_std_strings_;
+    this.adobe_std_encoding = adobe_std_strings_;
+    this.adobe_expert_encoding = adobe_expert_encoding_;
+}
+/******************************************************************************/
+// postscript-info
+/******************************************************************************/
+var FT_SERVICE_ID_POSTSCRIPT_INFO = "postscript-info";
+function FT_Service_PsInfoRec(get_font_info_, ps_get_font_extra_, has_glyph_names_,get_font_private_, get_font_value_)
+{
+    this.ps_get_font_info = get_font_info_;
+    this.ps_get_font_extra = ps_get_font_extra_;
+    this.ps_has_glyph_names = has_glyph_names_;
+    this.ps_get_font_private = get_font_private_;
+    this.ps_get_font_value = get_font_value_;
+}
+/******************************************************************************/
+// sfnt-table
+/******************************************************************************/
+var FT_SERVICE_ID_SFNT_TABLE = "sfnt-table";
+function FT_Service_SFNT_TableRec(load_, get_, info_)
+{
+    this.load_table = load_;
+    this.get_table = get_;
+    this.table_info = info_;
+}
+/******************************************************************************/
+// tt-cmaps
+/******************************************************************************/
+var FT_SERVICE_ID_TT_CMAP = "tt-cmaps";
+function TT_CMapInfo()
+{
+    this.language;
+    this.format;
+}
+function FT_Service_TTCMapsRec(get_cmap_info_)
+{
+    this.get_cmap_info = get_cmap_info_;
+}
+/******************************************************************************/
+// truetype-engine
+/******************************************************************************/
+var FT_SERVICE_ID_TRUETYPE_ENGINE = "truetype-engine";
+function FT_Service_TrueTypeEngineRec(engine_type_)
+{
+    this.engine_type = engine_type_;
+}
+/******************************************************************************/
+// tt-glyf
+/******************************************************************************/
+var FT_SERVICE_ID_TT_GLYF = "tt-glyf";
+function FT_Service_TTGlyfRec(get_location_)
+{
+    this.get_location = get_location_;
+}
+/******************************************************************************/
+// winfonts
+/******************************************************************************/
+var FT_SERVICE_ID_WINFNT = "winfonts";
+function FT_Service_WinFntRec(get_header_)
+{
+    this.get_header = get_header_;
+}
+/******************************************************************************/
+// xf86
+/******************************************************************************/
+var FT_SERVICE_ID_XF86_NAME  = "xf86-driver-name";
+var FT_XF86_FORMAT_TRUETYPE  = "TrueType";
+var FT_XF86_FORMAT_TYPE_1    = "Type 1";
+var FT_XF86_FORMAT_BDF       = "BDF";
+var FT_XF86_FORMAT_PCF       = "PCF";
+var FT_XF86_FORMAT_TYPE_42   = "Type 42";
+var FT_XF86_FORMAT_CID       = "CID Type 1";
+var FT_XF86_FORMAT_CFF       = "CFF";
+var FT_XF86_FORMAT_PFR       = "PFR";
+var FT_XF86_FORMAT_WINFNT    = "Windows FNT";
+
+/******************************************************************************/
+function FT_ServiceDescRec(id,data)
+{
+    this.serv_id = id;
+    this.serv_data = data;
+}
+function ft_service_list_lookup(service_descriptors,service_id)
+{
+    var c = service_descriptors.length;
+    for (var i=0;i<c;i++)
+    {
+        if (service_descriptors[i].serv_id == service_id)
+            return service_descriptors[i].serv_data;
+    }
+    return null;
+}
+
+function FT_FACE_FIND_SERVICE(face, id)
+{
+    var module = face.driver;
+    if (module.clazz.get_interface)
+        return module.clazz.get_interface(module, id);
+    return null;
+}
+function FT_FACE_FIND_GLOBAL_SERVICE(face, name)
+{
+    return ft_module_get_service(face.driver, name);
+}
+function ft_module_get_service(module, name)
+{
+    var result = null;
+
+    if (module != null)
+    {
+        if (null != module.clazz.get_interface)
+            result = module.clazz.get_interface(module, name);
+        if (null == result)
+        {
+            var modules = module.library.modules;
+            var count = modules.length;
+            for (var i = 0;i<count;i++)
+            {
+                if (modules[i].clazz.get_interface)
+                {
+                    result = modules[i].clazz.get_interface(modules[i], name);
+                    if (null != result)
+                        break;
+                }
+            }
+        }
+    }
+
+    return result;
+}
+
+function FT_ServiceCache()
+{
+    this.service_POSTSCRIPT_FONT_NAME = null;
+    this.service_MULTI_MASTERS = null;
+    this.service_GLYPH_DICT = null;
+    this.service_PFR_METRICS = null;
+    this.service_WINFNT = null;
+}
\ No newline at end of file
diff --git a/Common/FontsFreeType/Private/generator/Readme.txt b/Common/FontsFreeType/Private/generator/Readme.txt
new file mode 100644
index 0000000000000000000000000000000000000000..dca4551dfd71ea43d767765acc9c4ef01bbd6a52
--- /dev/null
+++ b/Common/FontsFreeType/Private/generator/Readme.txt
@@ -0,0 +1,5 @@
+Как пользоваться:
+1) открыть index.html
+2) скопировать все из странички
+3) вставить в функцию GetConfigMap (main.cpp)
+4) запустить generator (из папки Debug/Release, чтобы файл font_engine.js положился туда, куда надо)
\ No newline at end of file
diff --git a/Common/FontsFreeType/Private/generator/generator.pro b/Common/FontsFreeType/Private/generator/generator.pro
new file mode 100644
index 0000000000000000000000000000000000000000..3a133d751bd0308ecdf81bdfdea594bb67631ecc
--- /dev/null
+++ b/Common/FontsFreeType/Private/generator/generator.pro
@@ -0,0 +1,30 @@
+TEMPLATE = app
+CONFIG += console c++11
+CONFIG -= app_bundle
+CONFIG -= qt
+
+CONFIG -= debug_and_release debug_and_release_target
+
+SOURCES += main.cpp
+
+linux-g++ | linux-g++-64 | linux-g++-32 {
+    DEFINES += \
+        LINUX \
+        _LINUX \
+        _LINUX_QT
+}
+mac {
+    DEFINES += \
+    LINUX \
+    _LINUX \
+    _LINUX_QT \
+    _MAC \
+    MAC \
+    QT_MAC \
+    _MAC_ \
+    __MAC__
+}
+win32 {
+    DEFINES += \
+    WIN32
+}
diff --git a/Common/FontsFreeType/Private/generator/index.html b/Common/FontsFreeType/Private/generator/index.html
new file mode 100644
index 0000000000000000000000000000000000000000..74721ec994befc597673bd9d6aaad271c4a774ee
--- /dev/null
+++ b/Common/FontsFreeType/Private/generator/index.html
@@ -0,0 +1,132 @@
+<!doctype html>
+<html>
+<head>
+
+    <title>FontEngine</title>
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=IE8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no">
+    
+	<script type="text/javascript" src="../Freetype/config.js"></script>
+	<script type="text/javascript" src="../Freetype/base.js"></script>
+	<script type="text/javascript" src="../Freetype/services.js"></script>
+	
+	<script type="text/javascript" src="../Freetype/modules/psaux.js"></script>
+	<script type="text/javascript" src="../Freetype/modules/psnames.js"></script>
+	<script type="text/javascript" src="../Freetype/modules/render.js"></script>
+	<script type="text/javascript" src="../Freetype/modules/sfnt.js"></script>	
+	
+	<script type="text/javascript" src="../Freetype/drivers/truetype.js"></script>
+	<script type="text/javascript" src="../Freetype/drivers/cff.js"></script>
+	<script type="text/javascript" src="../Freetype/drivers/cid.js"></script>
+	<script type="text/javascript" src="../Freetype/drivers/t1.js"></script>
+	<script type="text/javascript" src="../Freetype/drivers/ttinterp.js"></script>
+	
+	<script type="text/javascript" src="../Freetype/freetype.js"></script>
+	
+</head>
+<body>
+	
+	<div id="log" style="font-family:Courier New"/>
+
+	<script>
+	
+	function _correct(_src)
+	{
+		var res = _src;
+		res = res.replace(/&/g,'&amp;');
+		res = res.replace(/</g,'&lt;');
+		res = res.replace(/>/g,'&gt;');
+		res = res.replace(/'/g,'&apos;');
+		res = res.replace(/"/g,'&quot;');
+		return res;
+	}
+
+	var _log = "";
+	var _br = "<br/>";
+	
+	var __obj = {};
+	var __arr = [];
+	
+	for (var i in FT_Common)
+    {
+		if (true === FT_Common[i])
+		{
+			__arr.push("" + i);
+			__obj["" + i] = "true";
+		}
+		else if (false === FT_Common[i])
+		{
+			__arr.push("" + i);
+			__obj["" + i] = "false";
+		}
+		else
+		{	
+			var tof = typeof FT_Common[i];
+
+			if (tof == "number")
+			{
+				__arr.push("" + i);
+				__obj["" + i] = "" + FT_Common[i];
+			}
+		}
+    }
+	
+	function compareStrings(a, b) 
+	{
+		if (a == b)
+			return 0;
+		
+		if (a.indexOf(b) != -1)
+			return -1;
+		
+		if (b.indexOf(a) != -1)
+			return 1;
+			
+		return (a < b) ? -1 : (a > b) ? 1 : 0;
+	}
+	
+	__arr.sort(compareStrings);
+	
+	for (var i = 0; i < __arr.length; i++)
+    {
+		_log += _correct("_vec1.push_back(L\"FT_Common." + __arr[i] + "\"); ");
+		_log += _correct("_vec2.push_back(L\"" + __obj[__arr[i]] + "\");");
+		_log += _br;
+    }
+	
+	/*
+    for (var i in FT_Common)
+    {
+		if (true === FT_Common[i])
+		{
+			_log += _correct("_vec1.push_back(L\"FT_Common." + i + "\"); ");
+			_log += _correct("_vec2.push_back(L\"true\");");
+			_log += _br;
+		}
+		else if (false === FT_Common[i])
+		{
+			_log += _correct("_vec1.push_back(L\"FT_Common." + i + "\"); ");
+			_log += _correct("_vec2.push_back(L\"false\");");
+			_log += _br;
+		}
+		else
+		{	
+			var tof = typeof FT_Common[i];
+
+			if (tof == "number")
+			{
+				_log += _correct("_vec1.push_back(L\"FT_Common." + i + "\"); ");
+				_log += _correct("_vec2.push_back(L\"" + FT_Common[i] + "\");");
+				_log += _br;
+			}
+		}
+    }
+	*/
+	
+	document.getElementById("log").innerHTML = _log;
+
+	</script>
+    	
+</body>
+</html>
\ No newline at end of file
diff --git a/Common/FontsFreeType/Private/generator/main.cpp b/Common/FontsFreeType/Private/generator/main.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..2a4fa850134f64c88293d846125888ab1f9e9930
--- /dev/null
+++ b/Common/FontsFreeType/Private/generator/main.cpp
@@ -0,0 +1,897 @@
+#include <iostream>
+#include <vector>
+#include <map>
+
+#include "../../../../../ServerComponents/DesktopEditor/common/File.h"
+
+using namespace std;
+
+void GetConfigMap(std::vector<std::wstring>& _vec1, std::vector<std::wstring>& _vec2)
+{
+    _vec1.push_back(L"FT_Common.AFM_MAX_ARGUMENTS"); _vec2.push_back(L"5");
+    _vec1.push_back(L"FT_Common.AFM_STREAM_STATUS_EOC"); _vec2.push_back(L"1");
+    _vec1.push_back(L"FT_Common.AFM_STREAM_STATUS_EOF"); _vec2.push_back(L"3");
+    _vec1.push_back(L"FT_Common.AFM_STREAM_STATUS_EOL"); _vec2.push_back(L"2");
+    _vec1.push_back(L"FT_Common.AFM_STREAM_STATUS_NORMAL"); _vec2.push_back(L"0");
+    _vec1.push_back(L"FT_Common.AFM_TOKEN_ASCENDER"); _vec2.push_back(L"0");
+    _vec1.push_back(L"FT_Common.AFM_TOKEN_AXISLABEL"); _vec2.push_back(L"1");
+    _vec1.push_back(L"FT_Common.AFM_TOKEN_AXISTYPE"); _vec2.push_back(L"2");
+    _vec1.push_back(L"FT_Common.AFM_TOKEN_BLENDAXISTYPES"); _vec2.push_back(L"4");
+    _vec1.push_back(L"FT_Common.AFM_TOKEN_BLENDDESIGNMAP"); _vec2.push_back(L"5");
+    _vec1.push_back(L"FT_Common.AFM_TOKEN_BLENDDESIGNPOSITIONS"); _vec2.push_back(L"6");
+    _vec1.push_back(L"FT_Common.AFM_TOKEN_B"); _vec2.push_back(L"3");
+    _vec1.push_back(L"FT_Common.AFM_TOKEN_CAPHEIGHT"); _vec2.push_back(L"10");
+    _vec1.push_back(L"FT_Common.AFM_TOKEN_CC"); _vec2.push_back(L"8");
+    _vec1.push_back(L"FT_Common.AFM_TOKEN_CHARACTERSET"); _vec2.push_back(L"12");
+    _vec1.push_back(L"FT_Common.AFM_TOKEN_CHARACTERS"); _vec2.push_back(L"13");
+    _vec1.push_back(L"FT_Common.AFM_TOKEN_CHARWIDTH"); _vec2.push_back(L"11");
+    _vec1.push_back(L"FT_Common.AFM_TOKEN_CH"); _vec2.push_back(L"9");
+    _vec1.push_back(L"FT_Common.AFM_TOKEN_C"); _vec2.push_back(L"7");
+    _vec1.push_back(L"FT_Common.AFM_TOKEN_DESCENDER"); _vec2.push_back(L"14");
+    _vec1.push_back(L"FT_Common.AFM_TOKEN_ENCODINGSCHEME"); _vec2.push_back(L"15");
+    _vec1.push_back(L"FT_Common.AFM_TOKEN_ENDAXIS"); _vec2.push_back(L"16");
+    _vec1.push_back(L"FT_Common.AFM_TOKEN_ENDCHARMETRICS"); _vec2.push_back(L"17");
+    _vec1.push_back(L"FT_Common.AFM_TOKEN_ENDCOMPOSITES"); _vec2.push_back(L"18");
+    _vec1.push_back(L"FT_Common.AFM_TOKEN_ENDDIRECTION"); _vec2.push_back(L"19");
+    _vec1.push_back(L"FT_Common.AFM_TOKEN_ENDFONTMETRICS"); _vec2.push_back(L"20");
+    _vec1.push_back(L"FT_Common.AFM_TOKEN_ENDKERNDATA"); _vec2.push_back(L"21");
+    _vec1.push_back(L"FT_Common.AFM_TOKEN_ENDKERNPAIRS"); _vec2.push_back(L"22");
+    _vec1.push_back(L"FT_Common.AFM_TOKEN_ENDTRACKKERN"); _vec2.push_back(L"23");
+    _vec1.push_back(L"FT_Common.AFM_TOKEN_ESCCHAR"); _vec2.push_back(L"24");
+    _vec1.push_back(L"FT_Common.AFM_TOKEN_FAMILYNAME"); _vec2.push_back(L"25");
+    _vec1.push_back(L"FT_Common.AFM_TOKEN_FONTBBOX"); _vec2.push_back(L"26");
+    _vec1.push_back(L"FT_Common.AFM_TOKEN_FONTNAME"); _vec2.push_back(L"27");
+    _vec1.push_back(L"FT_Common.AFM_TOKEN_FULLNAME"); _vec2.push_back(L"28");
+    _vec1.push_back(L"FT_Common.AFM_TOKEN_ISBASEFONT"); _vec2.push_back(L"29");
+    _vec1.push_back(L"FT_Common.AFM_TOKEN_ISCIDFONT"); _vec2.push_back(L"30");
+    _vec1.push_back(L"FT_Common.AFM_TOKEN_ISFIXEDPITCH"); _vec2.push_back(L"31");
+    _vec1.push_back(L"FT_Common.AFM_TOKEN_ISFIXEDV"); _vec2.push_back(L"32");
+    _vec1.push_back(L"FT_Common.AFM_TOKEN_ITALICANGLE"); _vec2.push_back(L"33");
+    _vec1.push_back(L"FT_Common.AFM_TOKEN_KPH"); _vec2.push_back(L"35");
+    _vec1.push_back(L"FT_Common.AFM_TOKEN_KPX"); _vec2.push_back(L"36");
+    _vec1.push_back(L"FT_Common.AFM_TOKEN_KPY"); _vec2.push_back(L"37");
+    _vec1.push_back(L"FT_Common.AFM_TOKEN_KP"); _vec2.push_back(L"34");
+    _vec1.push_back(L"FT_Common.AFM_TOKEN_L"); _vec2.push_back(L"38");
+    _vec1.push_back(L"FT_Common.AFM_TOKEN_MAPPINGSCHEME"); _vec2.push_back(L"39");
+    _vec1.push_back(L"FT_Common.AFM_TOKEN_METRICSSETS"); _vec2.push_back(L"40");
+    _vec1.push_back(L"FT_Common.AFM_TOKEN_NOTICE"); _vec2.push_back(L"42");
+    _vec1.push_back(L"FT_Common.AFM_TOKEN_N"); _vec2.push_back(L"41");
+    _vec1.push_back(L"FT_Common.AFM_TOKEN_PCC"); _vec2.push_back(L"43");
+    _vec1.push_back(L"FT_Common.AFM_TOKEN_STARTAXIS"); _vec2.push_back(L"44");
+    _vec1.push_back(L"FT_Common.AFM_TOKEN_STARTCHARMETRICS"); _vec2.push_back(L"45");
+    _vec1.push_back(L"FT_Common.AFM_TOKEN_STARTCOMPOSITES"); _vec2.push_back(L"46");
+    _vec1.push_back(L"FT_Common.AFM_TOKEN_STARTDIRECTION"); _vec2.push_back(L"47");
+    _vec1.push_back(L"FT_Common.AFM_TOKEN_STARTFONTMETRICS"); _vec2.push_back(L"48");
+    _vec1.push_back(L"FT_Common.AFM_TOKEN_STARTKERNDATA"); _vec2.push_back(L"49");
+    _vec1.push_back(L"FT_Common.AFM_TOKEN_STARTKERNPAIRS0"); _vec2.push_back(L"51");
+    _vec1.push_back(L"FT_Common.AFM_TOKEN_STARTKERNPAIRS1"); _vec2.push_back(L"52");
+    _vec1.push_back(L"FT_Common.AFM_TOKEN_STARTKERNPAIRS"); _vec2.push_back(L"50");
+    _vec1.push_back(L"FT_Common.AFM_TOKEN_STARTTRACKKERN"); _vec2.push_back(L"53");
+    _vec1.push_back(L"FT_Common.AFM_TOKEN_STDHW"); _vec2.push_back(L"54");
+    _vec1.push_back(L"FT_Common.AFM_TOKEN_STDVW"); _vec2.push_back(L"55");
+    _vec1.push_back(L"FT_Common.AFM_TOKEN_TRACKKERN"); _vec2.push_back(L"56");
+    _vec1.push_back(L"FT_Common.AFM_TOKEN_UNDERLINEPOSITION"); _vec2.push_back(L"57");
+    _vec1.push_back(L"FT_Common.AFM_TOKEN_UNDERLINETHICKNESS"); _vec2.push_back(L"58");
+    _vec1.push_back(L"FT_Common.AFM_TOKEN_UNKNOWN"); _vec2.push_back(L"75");
+    _vec1.push_back(L"FT_Common.AFM_TOKEN_VERSION"); _vec2.push_back(L"61");
+    _vec1.push_back(L"FT_Common.AFM_TOKEN_VVECTOR"); _vec2.push_back(L"60");
+    _vec1.push_back(L"FT_Common.AFM_TOKEN_VV"); _vec2.push_back(L"59");
+    _vec1.push_back(L"FT_Common.AFM_TOKEN_W0X"); _vec2.push_back(L"64");
+    _vec1.push_back(L"FT_Common.AFM_TOKEN_W0Y"); _vec2.push_back(L"65");
+    _vec1.push_back(L"FT_Common.AFM_TOKEN_W0"); _vec2.push_back(L"63");
+    _vec1.push_back(L"FT_Common.AFM_TOKEN_W1X"); _vec2.push_back(L"67");
+    _vec1.push_back(L"FT_Common.AFM_TOKEN_W1Y"); _vec2.push_back(L"68");
+    _vec1.push_back(L"FT_Common.AFM_TOKEN_W1"); _vec2.push_back(L"66");
+    _vec1.push_back(L"FT_Common.AFM_TOKEN_WEIGHTVECTOR"); _vec2.push_back(L"72");
+    _vec1.push_back(L"FT_Common.AFM_TOKEN_WEIGHT"); _vec2.push_back(L"71");
+    _vec1.push_back(L"FT_Common.AFM_TOKEN_WX"); _vec2.push_back(L"69");
+    _vec1.push_back(L"FT_Common.AFM_TOKEN_WY"); _vec2.push_back(L"70");
+    _vec1.push_back(L"FT_Common.AFM_TOKEN_W"); _vec2.push_back(L"62");
+    _vec1.push_back(L"FT_Common.AFM_TOKEN_XHEIGHT"); _vec2.push_back(L"73");
+    _vec1.push_back(L"FT_Common.AFM_VALUE_TYPE_BOOL"); _vec2.push_back(L"4");
+    _vec1.push_back(L"FT_Common.AFM_VALUE_TYPE_FIXED"); _vec2.push_back(L"2");
+    _vec1.push_back(L"FT_Common.AFM_VALUE_TYPE_INDEX"); _vec2.push_back(L"5");
+    _vec1.push_back(L"FT_Common.AFM_VALUE_TYPE_INTEGER"); _vec2.push_back(L"3");
+    _vec1.push_back(L"FT_Common.AFM_VALUE_TYPE_NAME"); _vec2.push_back(L"1");
+    _vec1.push_back(L"FT_Common.AFM_VALUE_TYPE_STRING"); _vec2.push_back(L"0");
+    _vec1.push_back(L"FT_Common.ARGS_ARE_WORDS"); _vec2.push_back(L"1");
+    _vec1.push_back(L"FT_Common.ARGS_ARE_XY_VALUES"); _vec2.push_back(L"2");
+    _vec1.push_back(L"FT_Common.BDF_PROPERTY_TYPE_ATOM"); _vec2.push_back(L"1");
+    _vec1.push_back(L"FT_Common.BDF_PROPERTY_TYPE_CARDINAL"); _vec2.push_back(L"3");
+    _vec1.push_back(L"FT_Common.BDF_PROPERTY_TYPE_INTEGER"); _vec2.push_back(L"2");
+    _vec1.push_back(L"FT_Common.BDF_PROPERTY_TYPE_NONE"); _vec2.push_back(L"0");
+    _vec1.push_back(L"FT_Common.CFFCODE_PRIVATE"); _vec2.push_back(L"8192");
+    _vec1.push_back(L"FT_Common.CFFCODE_TOPDICT"); _vec2.push_back(L"4096");
+    _vec1.push_back(L"FT_Common.CFF_CODE_PRIVATE"); _vec2.push_back(L"8192");
+    _vec1.push_back(L"FT_Common.CFF_CODE_TOPDICT"); _vec2.push_back(L"4096");
+    _vec1.push_back(L"FT_Common.CFF_COUNT_CHECK_WIDTH"); _vec2.push_back(L"128");
+    _vec1.push_back(L"FT_Common.CFF_COUNT_CLEAR_STACK"); _vec2.push_back(L"32");
+    _vec1.push_back(L"FT_Common.CFF_COUNT_EXACT"); _vec2.push_back(L"64");
+    _vec1.push_back(L"FT_Common.CFF_MAX_CID_FONTS"); _vec2.push_back(L"256");
+    _vec1.push_back(L"FT_Common.CFF_MAX_OPERANDS"); _vec2.push_back(L"48");
+    _vec1.push_back(L"FT_Common.CFF_MAX_STACK_DEPTH"); _vec2.push_back(L"96");
+    _vec1.push_back(L"FT_Common.CFF_MAX_SUBRS_CALLS"); _vec2.push_back(L"32");
+    _vec1.push_back(L"FT_Common.CFF_MAX_TRANS_ELEMENTS"); _vec2.push_back(L"32");
+    _vec1.push_back(L"FT_Common.ErrorLongJump"); _vec2.push_back(L"-100");
+    _vec1.push_back(L"FT_Common.FT_ANGLE_PI2"); _vec2.push_back(L"5898240");
+    _vec1.push_back(L"FT_Common.FT_ANGLE_PI"); _vec2.push_back(L"11796480");
+    _vec1.push_back(L"FT_Common.FT_CMAP_0"); _vec2.push_back(L"0");
+    _vec1.push_back(L"FT_Common.FT_CMAP_12"); _vec2.push_back(L"3");
+    _vec1.push_back(L"FT_Common.FT_CMAP_13"); _vec2.push_back(L"4");
+    _vec1.push_back(L"FT_Common.FT_CMAP_14"); _vec2.push_back(L"5");
+    _vec1.push_back(L"FT_Common.FT_CMAP_1"); _vec2.push_back(L"1");
+    _vec1.push_back(L"FT_Common.FT_CMAP_4"); _vec2.push_back(L"2");
+    _vec1.push_back(L"FT_Common.FT_CURVE_TAG_CONIC"); _vec2.push_back(L"0");
+    _vec1.push_back(L"FT_Common.FT_CURVE_TAG_CUBIC"); _vec2.push_back(L"2");
+    _vec1.push_back(L"FT_Common.FT_CURVE_TAG_HAS_SCANMODE"); _vec2.push_back(L"4");
+    _vec1.push_back(L"FT_Common.FT_CURVE_TAG_ON"); _vec2.push_back(L"1");
+    _vec1.push_back(L"FT_Common.FT_CURVE_TAG_TOUCH_BOTH"); _vec2.push_back(L"24");
+    _vec1.push_back(L"FT_Common.FT_CURVE_TAG_TOUCH_X"); _vec2.push_back(L"8");
+    _vec1.push_back(L"FT_Common.FT_CURVE_TAG_TOUCH_Y"); _vec2.push_back(L"16");
+    _vec1.push_back(L"FT_Common.FT_ENCODING_ADOBE_CUSTOM"); _vec2.push_back(L"1094992451");
+    _vec1.push_back(L"FT_Common.FT_ENCODING_ADOBE_EXPERT"); _vec2.push_back(L"1094992453");
+    _vec1.push_back(L"FT_Common.FT_ENCODING_ADOBE_LATIN_1"); _vec2.push_back(L"1818326065");
+    _vec1.push_back(L"FT_Common.FT_ENCODING_ADOBE_STANDARD"); _vec2.push_back(L"1094995778");
+    _vec1.push_back(L"FT_Common.FT_ENCODING_APPLE_ROMAN"); _vec2.push_back(L"1634889070");
+    _vec1.push_back(L"FT_Common.FT_ENCODING_BIG5"); _vec2.push_back(L"1651074869");
+    _vec1.push_back(L"FT_Common.FT_ENCODING_GB2312"); _vec2.push_back(L"1734484000");
+    _vec1.push_back(L"FT_Common.FT_ENCODING_JOHAB"); _vec2.push_back(L"1785686113");
+    _vec1.push_back(L"FT_Common.FT_ENCODING_MS_BIG5"); _vec2.push_back(L"1651074869");
+    _vec1.push_back(L"FT_Common.FT_ENCODING_MS_GB2312"); _vec2.push_back(L"1734484000");
+    _vec1.push_back(L"FT_Common.FT_ENCODING_MS_JOHAB"); _vec2.push_back(L"1785686113");
+    _vec1.push_back(L"FT_Common.FT_ENCODING_MS_SJIS"); _vec2.push_back(L"1936353651");
+    _vec1.push_back(L"FT_Common.FT_ENCODING_MS_SYMBOL"); _vec2.push_back(L"1937337698");
+    _vec1.push_back(L"FT_Common.FT_ENCODING_MS_WANSUNG"); _vec2.push_back(L"2002873971");
+    _vec1.push_back(L"FT_Common.FT_ENCODING_NONE"); _vec2.push_back(L"0");
+    _vec1.push_back(L"FT_Common.FT_ENCODING_OLD_LATIN_2"); _vec2.push_back(L"1818326066");
+    _vec1.push_back(L"FT_Common.FT_ENCODING_SJIS"); _vec2.push_back(L"1936353651");
+    _vec1.push_back(L"FT_Common.FT_ENCODING_UNICODE"); _vec2.push_back(L"1970170211");
+    _vec1.push_back(L"FT_Common.FT_ENCODING_WANSUNG"); _vec2.push_back(L"2002873971");
+    _vec1.push_back(L"FT_Common.FT_Err_Array_Too_Large"); _vec2.push_back(L"10");
+    _vec1.push_back(L"FT_Common.FT_Err_Bad_Argument"); _vec2.push_back(L"132");
+    _vec1.push_back(L"FT_Common.FT_Err_Bbx_Too_Big"); _vec2.push_back(L"184");
+    _vec1.push_back(L"FT_Common.FT_Err_CMap_Table_Missing"); _vec2.push_back(L"146");
+    _vec1.push_back(L"FT_Common.FT_Err_Cannot_Open_Resource"); _vec2.push_back(L"1");
+    _vec1.push_back(L"FT_Common.FT_Err_Cannot_Open_Stream"); _vec2.push_back(L"81");
+    _vec1.push_back(L"FT_Common.FT_Err_Cannot_Render_Glyph"); _vec2.push_back(L"19");
+    _vec1.push_back(L"FT_Common.FT_Err_Code_Overflow"); _vec2.push_back(L"131");
+    _vec1.push_back(L"FT_Common.FT_Err_Corrupted_Font_Glyphs"); _vec2.push_back(L"186");
+    _vec1.push_back(L"FT_Common.FT_Err_Corrupted_Font_Header"); _vec2.push_back(L"185");
+    _vec1.push_back(L"FT_Common.FT_Err_Could_Not_Find_Context"); _vec2.push_back(L"153");
+    _vec1.push_back(L"FT_Common.FT_Err_Debug_OpCode"); _vec2.push_back(L"135");
+    _vec1.push_back(L"FT_Common.FT_Err_Divide_By_Zero"); _vec2.push_back(L"133");
+    _vec1.push_back(L"FT_Common.FT_Err_ENDF_In_Exec_Stream"); _vec2.push_back(L"136");
+    _vec1.push_back(L"FT_Common.FT_Err_Execution_Too_Long"); _vec2.push_back(L"139");
+    _vec1.push_back(L"FT_Common.FT_Err_Hmtx_Table_Missing"); _vec2.push_back(L"147");
+    _vec1.push_back(L"FT_Common.FT_Err_Horiz_Header_Missing"); _vec2.push_back(L"143");
+    _vec1.push_back(L"FT_Common.FT_Err_Ignore"); _vec2.push_back(L"162");
+    _vec1.push_back(L"FT_Common.FT_Err_Invalid_Argument"); _vec2.push_back(L"6");
+    _vec1.push_back(L"FT_Common.FT_Err_Invalid_Cache_Handle"); _vec2.push_back(L"39");
+    _vec1.push_back(L"FT_Common.FT_Err_Invalid_CharMap_Format"); _vec2.push_back(L"150");
+    _vec1.push_back(L"FT_Common.FT_Err_Invalid_CharMap_Handle"); _vec2.push_back(L"38");
+    _vec1.push_back(L"FT_Common.FT_Err_Invalid_Character_Code"); _vec2.push_back(L"17");
+    _vec1.push_back(L"FT_Common.FT_Err_Invalid_CodeRange"); _vec2.push_back(L"138");
+    _vec1.push_back(L"FT_Common.FT_Err_Invalid_Composite"); _vec2.push_back(L"21");
+    _vec1.push_back(L"FT_Common.FT_Err_Invalid_Driver_Handle"); _vec2.push_back(L"34");
+    _vec1.push_back(L"FT_Common.FT_Err_Invalid_Face_Handle"); _vec2.push_back(L"35");
+    _vec1.push_back(L"FT_Common.FT_Err_Invalid_File_Format"); _vec2.push_back(L"3");
+    _vec1.push_back(L"FT_Common.FT_Err_Invalid_Frame_Operation"); _vec2.push_back(L"86");
+    _vec1.push_back(L"FT_Common.FT_Err_Invalid_Frame_Read"); _vec2.push_back(L"88");
+    _vec1.push_back(L"FT_Common.FT_Err_Invalid_Glyph_Format"); _vec2.push_back(L"18");
+    _vec1.push_back(L"FT_Common.FT_Err_Invalid_Glyph_Index"); _vec2.push_back(L"16");
+    _vec1.push_back(L"FT_Common.FT_Err_Invalid_Handle"); _vec2.push_back(L"32");
+    _vec1.push_back(L"FT_Common.FT_Err_Invalid_Horiz_Metrics"); _vec2.push_back(L"149");
+    _vec1.push_back(L"FT_Common.FT_Err_Invalid_Library_Handle"); _vec2.push_back(L"33");
+    _vec1.push_back(L"FT_Common.FT_Err_Invalid_Offset"); _vec2.push_back(L"9");
+    _vec1.push_back(L"FT_Common.FT_Err_Invalid_Opcode"); _vec2.push_back(L"128");
+    _vec1.push_back(L"FT_Common.FT_Err_Invalid_Outline"); _vec2.push_back(L"20");
+    _vec1.push_back(L"FT_Common.FT_Err_Invalid_PPem"); _vec2.push_back(L"151");
+    _vec1.push_back(L"FT_Common.FT_Err_Invalid_Pixel_Size"); _vec2.push_back(L"23");
+    _vec1.push_back(L"FT_Common.FT_Err_Invalid_Post_Table_Format"); _vec2.push_back(L"154");
+    _vec1.push_back(L"FT_Common.FT_Err_Invalid_Post_Table"); _vec2.push_back(L"155");
+    _vec1.push_back(L"FT_Common.FT_Err_Invalid_Reference"); _vec2.push_back(L"134");
+    _vec1.push_back(L"FT_Common.FT_Err_Invalid_Size_Handle"); _vec2.push_back(L"36");
+    _vec1.push_back(L"FT_Common.FT_Err_Invalid_Slot_Handle"); _vec2.push_back(L"37");
+    _vec1.push_back(L"FT_Common.FT_Err_Invalid_Stream_Handle"); _vec2.push_back(L"40");
+    _vec1.push_back(L"FT_Common.FT_Err_Invalid_Stream_Operation"); _vec2.push_back(L"85");
+    _vec1.push_back(L"FT_Common.FT_Err_Invalid_Stream_Read"); _vec2.push_back(L"84");
+    _vec1.push_back(L"FT_Common.FT_Err_Invalid_Stream_Seek"); _vec2.push_back(L"82");
+    _vec1.push_back(L"FT_Common.FT_Err_Invalid_Stream_Skip"); _vec2.push_back(L"83");
+    _vec1.push_back(L"FT_Common.FT_Err_Invalid_Table"); _vec2.push_back(L"8");
+    _vec1.push_back(L"FT_Common.FT_Err_Invalid_Version"); _vec2.push_back(L"4");
+    _vec1.push_back(L"FT_Common.FT_Err_Invalid_Vert_Metrics"); _vec2.push_back(L"152");
+    _vec1.push_back(L"FT_Common.FT_Err_Locations_Missing"); _vec2.push_back(L"144");
+    _vec1.push_back(L"FT_Common.FT_Err_Lower_Module_Version"); _vec2.push_back(L"5");
+    _vec1.push_back(L"FT_Common.FT_Err_Missing_Bbx_Field"); _vec2.push_back(L"183");
+    _vec1.push_back(L"FT_Common.FT_Err_Missing_Chars_Field"); _vec2.push_back(L"180");
+    _vec1.push_back(L"FT_Common.FT_Err_Missing_Encoding_Field"); _vec2.push_back(L"182");
+    _vec1.push_back(L"FT_Common.FT_Err_Missing_Font_Field"); _vec2.push_back(L"177");
+    _vec1.push_back(L"FT_Common.FT_Err_Missing_Fontboundingbox_Field"); _vec2.push_back(L"179");
+    _vec1.push_back(L"FT_Common.FT_Err_Missing_Size_Field"); _vec2.push_back(L"178");
+    _vec1.push_back(L"FT_Common.FT_Err_Missing_Startchar_Field"); _vec2.push_back(L"181");
+    _vec1.push_back(L"FT_Common.FT_Err_Missing_Startfont_Field"); _vec2.push_back(L"176");
+    _vec1.push_back(L"FT_Common.FT_Err_Name_Table_Missing"); _vec2.push_back(L"145");
+    _vec1.push_back(L"FT_Common.FT_Err_Nested_DEFS"); _vec2.push_back(L"137");
+    _vec1.push_back(L"FT_Common.FT_Err_Nested_Frame_Access"); _vec2.push_back(L"87");
+    _vec1.push_back(L"FT_Common.FT_Err_No_Unicode_Glyph_Name"); _vec2.push_back(L"163");
+    _vec1.push_back(L"FT_Common.FT_Err_Ok"); _vec2.push_back(L"0");
+    _vec1.push_back(L"FT_Common.FT_Err_Out_Of_Memory"); _vec2.push_back(L"64");
+    _vec1.push_back(L"FT_Common.FT_Err_Post_Table_Missing"); _vec2.push_back(L"148");
+    _vec1.push_back(L"FT_Common.FT_Err_Raster_Corrupted"); _vec2.push_back(L"97");
+    _vec1.push_back(L"FT_Common.FT_Err_Raster_Negative_Height"); _vec2.push_back(L"99");
+    _vec1.push_back(L"FT_Common.FT_Err_Raster_Overflow"); _vec2.push_back(L"98");
+    _vec1.push_back(L"FT_Common.FT_Err_Raster_Uninitialized"); _vec2.push_back(L"96");
+    _vec1.push_back(L"FT_Common.FT_Err_Stack_Overflow"); _vec2.push_back(L"130");
+    _vec1.push_back(L"FT_Common.FT_Err_Stack_Underflow"); _vec2.push_back(L"161");
+    _vec1.push_back(L"FT_Common.FT_Err_Syntax_Error"); _vec2.push_back(L"160");
+    _vec1.push_back(L"FT_Common.FT_Err_Table_Missing"); _vec2.push_back(L"142");
+    _vec1.push_back(L"FT_Common.FT_Err_Too_Few_Arguments"); _vec2.push_back(L"129");
+    _vec1.push_back(L"FT_Common.FT_Err_Too_Many_Caches"); _vec2.push_back(L"112");
+    _vec1.push_back(L"FT_Common.FT_Err_Too_Many_Drivers"); _vec2.push_back(L"48");
+    _vec1.push_back(L"FT_Common.FT_Err_Too_Many_Extensions"); _vec2.push_back(L"49");
+    _vec1.push_back(L"FT_Common.FT_Err_Too_Many_Function_Defs"); _vec2.push_back(L"140");
+    _vec1.push_back(L"FT_Common.FT_Err_Too_Many_Hints"); _vec2.push_back(L"22");
+    _vec1.push_back(L"FT_Common.FT_Err_Too_Many_Instruction_Defs"); _vec2.push_back(L"141");
+    _vec1.push_back(L"FT_Common.FT_Err_Unimplemented_Feature"); _vec2.push_back(L"7");
+    _vec1.push_back(L"FT_Common.FT_Err_Unknown_File_Format"); _vec2.push_back(L"2");
+    _vec1.push_back(L"FT_Common.FT_Err_Unlisted_Object"); _vec2.push_back(L"65");
+    _vec1.push_back(L"FT_Common.FT_FACE_FLAG_CID_KEYED"); _vec2.push_back(L"4096");
+    _vec1.push_back(L"FT_Common.FT_FACE_FLAG_EXTERNAL_STREAM"); _vec2.push_back(L"1024");
+    _vec1.push_back(L"FT_Common.FT_FACE_FLAG_FAST_GLYPHS"); _vec2.push_back(L"128");
+    _vec1.push_back(L"FT_Common.FT_FACE_FLAG_FIXED_SIZES"); _vec2.push_back(L"2");
+    _vec1.push_back(L"FT_Common.FT_FACE_FLAG_FIXED_WIDTH"); _vec2.push_back(L"4");
+    _vec1.push_back(L"FT_Common.FT_FACE_FLAG_GLYPH_NAMES"); _vec2.push_back(L"512");
+    _vec1.push_back(L"FT_Common.FT_FACE_FLAG_HINTER"); _vec2.push_back(L"2048");
+    _vec1.push_back(L"FT_Common.FT_FACE_FLAG_HORIZONTAL"); _vec2.push_back(L"16");
+    _vec1.push_back(L"FT_Common.FT_FACE_FLAG_KERNING"); _vec2.push_back(L"64");
+    _vec1.push_back(L"FT_Common.FT_FACE_FLAG_MULTIPLE_MASTERS"); _vec2.push_back(L"256");
+    _vec1.push_back(L"FT_Common.FT_FACE_FLAG_SCALABLE"); _vec2.push_back(L"1");
+    _vec1.push_back(L"FT_Common.FT_FACE_FLAG_SFNT"); _vec2.push_back(L"8");
+    _vec1.push_back(L"FT_Common.FT_FACE_FLAG_TRICKY"); _vec2.push_back(L"8192");
+    _vec1.push_back(L"FT_Common.FT_FACE_FLAG_VERTICAL"); _vec2.push_back(L"32");
+    _vec1.push_back(L"FT_Common.FT_GLYPH_BBOX_GRIDFIT"); _vec2.push_back(L"1");
+    _vec1.push_back(L"FT_Common.FT_GLYPH_BBOX_PIXELS"); _vec2.push_back(L"3");
+    _vec1.push_back(L"FT_Common.FT_GLYPH_BBOX_SUBPIXELS"); _vec2.push_back(L"0");
+    _vec1.push_back(L"FT_Common.FT_GLYPH_BBOX_TRUNCATE"); _vec2.push_back(L"2");
+    _vec1.push_back(L"FT_Common.FT_GLYPH_BBOX_UNSCALED"); _vec2.push_back(L"0");
+    _vec1.push_back(L"FT_Common.FT_GLYPH_FORMAT_BITMAP"); _vec2.push_back(L"1651078259");
+    _vec1.push_back(L"FT_Common.FT_GLYPH_FORMAT_COMPOSITE"); _vec2.push_back(L"1668246896");
+    _vec1.push_back(L"FT_Common.FT_GLYPH_FORMAT_NONE"); _vec2.push_back(L"0");
+    _vec1.push_back(L"FT_Common.FT_GLYPH_FORMAT_OUTLINE"); _vec2.push_back(L"1869968492");
+    _vec1.push_back(L"FT_Common.FT_GLYPH_FORMAT_PLOTTER"); _vec2.push_back(L"1886154612");
+    _vec1.push_back(L"FT_Common.FT_GLYPH_OWN_BITMAP"); _vec2.push_back(L"1");
+    _vec1.push_back(L"FT_Common.FT_KERNING_DEFAULT"); _vec2.push_back(L"0");
+    _vec1.push_back(L"FT_Common.FT_KERNING_UNFITTED"); _vec2.push_back(L"1");
+    _vec1.push_back(L"FT_Common.FT_KERNING_UNSCALED"); _vec2.push_back(L"2");
+    _vec1.push_back(L"FT_Common.FT_LOAD_ADVANCE_ONLY"); _vec2.push_back(L"256");
+    _vec1.push_back(L"FT_Common.FT_LOAD_CROP_BITMAP"); _vec2.push_back(L"64");
+    _vec1.push_back(L"FT_Common.FT_LOAD_DEFAULT"); _vec2.push_back(L"0");
+    _vec1.push_back(L"FT_Common.FT_LOAD_FORCE_AUTOHINT"); _vec2.push_back(L"32");
+    _vec1.push_back(L"FT_Common.FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH"); _vec2.push_back(L"512");
+    _vec1.push_back(L"FT_Common.FT_LOAD_IGNORE_TRANSFORM"); _vec2.push_back(L"2048");
+    _vec1.push_back(L"FT_Common.FT_LOAD_LINEAR_DESIGN"); _vec2.push_back(L"8192");
+    _vec1.push_back(L"FT_Common.FT_LOAD_MONOCHROME"); _vec2.push_back(L"4096");
+    _vec1.push_back(L"FT_Common.FT_LOAD_NO_AUTOHINT"); _vec2.push_back(L"32768");
+    _vec1.push_back(L"FT_Common.FT_LOAD_NO_BITMAP"); _vec2.push_back(L"8");
+    _vec1.push_back(L"FT_Common.FT_LOAD_NO_HINTING"); _vec2.push_back(L"2");
+    _vec1.push_back(L"FT_Common.FT_LOAD_NO_RECURSE"); _vec2.push_back(L"1024");
+    _vec1.push_back(L"FT_Common.FT_LOAD_NO_SCALE"); _vec2.push_back(L"1");
+    _vec1.push_back(L"FT_Common.FT_LOAD_PEDANTIC"); _vec2.push_back(L"128");
+    _vec1.push_back(L"FT_Common.FT_LOAD_RENDER"); _vec2.push_back(L"4");
+    _vec1.push_back(L"FT_Common.FT_LOAD_SBITS_ONLY"); _vec2.push_back(L"16384");
+    _vec1.push_back(L"FT_Common.FT_LOAD_VERTICAL_LAYOUT"); _vec2.push_back(L"16");
+    _vec1.push_back(L"FT_Common.FT_MAX_CHARMAP_CACHEABLE"); _vec2.push_back(L"15");
+    _vec1.push_back(L"FT_Common.FT_MODULE_DRIVER_HAS_HINTER"); _vec2.push_back(L"1024");
+    _vec1.push_back(L"FT_Common.FT_MODULE_DRIVER_NO_OUTLINES"); _vec2.push_back(L"512");
+    _vec1.push_back(L"FT_Common.FT_MODULE_DRIVER_SCALABLE"); _vec2.push_back(L"256");
+    _vec1.push_back(L"FT_Common.FT_MODULE_FONT_DRIVER"); _vec2.push_back(L"1");
+    _vec1.push_back(L"FT_Common.FT_MODULE_HINTER"); _vec2.push_back(L"4");
+    _vec1.push_back(L"FT_Common.FT_MODULE_RENDERER"); _vec2.push_back(L"2");
+    _vec1.push_back(L"FT_Common.FT_MODULE_STYLER"); _vec2.push_back(L"8");
+    _vec1.push_back(L"FT_Common.FT_Mod_Err"); _vec2.push_back(L"256");
+    _vec1.push_back(L"FT_Common.FT_ORIENTATION_FILL_LEFT"); _vec2.push_back(L"1");
+    _vec1.push_back(L"FT_Common.FT_ORIENTATION_FILL_RIGHT"); _vec2.push_back(L"0");
+    _vec1.push_back(L"FT_Common.FT_ORIENTATION_NONE"); _vec2.push_back(L"2");
+    _vec1.push_back(L"FT_Common.FT_ORIENTATION_POSTSCRIPT"); _vec2.push_back(L"1");
+    _vec1.push_back(L"FT_Common.FT_ORIENTATION_TRUETYPE"); _vec2.push_back(L"0");
+    _vec1.push_back(L"FT_Common.FT_OUTLINE_EVEN_ODD_FILL"); _vec2.push_back(L"2");
+    _vec1.push_back(L"FT_Common.FT_OUTLINE_HIGH_PRECISION"); _vec2.push_back(L"256");
+    _vec1.push_back(L"FT_Common.FT_OUTLINE_IGNORE_DROPOUTS"); _vec2.push_back(L"8");
+    _vec1.push_back(L"FT_Common.FT_OUTLINE_INCLUDE_STUBS"); _vec2.push_back(L"32");
+    _vec1.push_back(L"FT_Common.FT_OUTLINE_NONE"); _vec2.push_back(L"0");
+    _vec1.push_back(L"FT_Common.FT_OUTLINE_OWNER"); _vec2.push_back(L"1");
+    _vec1.push_back(L"FT_Common.FT_OUTLINE_REVERSE_FILL"); _vec2.push_back(L"4");
+    _vec1.push_back(L"FT_Common.FT_OUTLINE_SINGLE_PASS"); _vec2.push_back(L"512");
+    _vec1.push_back(L"FT_Common.FT_OUTLINE_SMART_DROPOUTS"); _vec2.push_back(L"16");
+    _vec1.push_back(L"FT_Common.FT_PARAM_TAG_UNPATENTED_HINTING"); _vec2.push_back(L"1970172001");
+    _vec1.push_back(L"FT_Common.FT_PIXEL_MODE_GRAY2"); _vec2.push_back(L"3");
+    _vec1.push_back(L"FT_Common.FT_PIXEL_MODE_GRAY4"); _vec2.push_back(L"4");
+    _vec1.push_back(L"FT_Common.FT_PIXEL_MODE_GRAY"); _vec2.push_back(L"2");
+    _vec1.push_back(L"FT_Common.FT_PIXEL_MODE_LCD_V"); _vec2.push_back(L"6");
+    _vec1.push_back(L"FT_Common.FT_PIXEL_MODE_LCD"); _vec2.push_back(L"5");
+    _vec1.push_back(L"FT_Common.FT_PIXEL_MODE_MAX"); _vec2.push_back(L"7");
+    _vec1.push_back(L"FT_Common.FT_PIXEL_MODE_MONO"); _vec2.push_back(L"1");
+    _vec1.push_back(L"FT_Common.FT_PIXEL_MODE_NONE"); _vec2.push_back(L"0");
+    _vec1.push_back(L"FT_Common.FT_RASTER_FLAG_AA"); _vec2.push_back(L"1");
+    _vec1.push_back(L"FT_Common.FT_RASTER_FLAG_CLIP"); _vec2.push_back(L"4");
+    _vec1.push_back(L"FT_Common.FT_RASTER_FLAG_DEFAULT"); _vec2.push_back(L"0");
+    _vec1.push_back(L"FT_Common.FT_RASTER_FLAG_DIRECT"); _vec2.push_back(L"2");
+    _vec1.push_back(L"FT_Common.FT_RENDER_MODE_LCD_V"); _vec2.push_back(L"4");
+    _vec1.push_back(L"FT_Common.FT_RENDER_MODE_LCD"); _vec2.push_back(L"3");
+    _vec1.push_back(L"FT_Common.FT_RENDER_MODE_LIGHT"); _vec2.push_back(L"1");
+    _vec1.push_back(L"FT_Common.FT_RENDER_MODE_MAX"); _vec2.push_back(L"5");
+    _vec1.push_back(L"FT_Common.FT_RENDER_MODE_MONO"); _vec2.push_back(L"2");
+    _vec1.push_back(L"FT_Common.FT_RENDER_MODE_NORMAL"); _vec2.push_back(L"0");
+    _vec1.push_back(L"FT_Common.FT_SIZE_REQUEST_TYPE_BBOX"); _vec2.push_back(L"2");
+    _vec1.push_back(L"FT_Common.FT_SIZE_REQUEST_TYPE_CELL"); _vec2.push_back(L"3");
+    _vec1.push_back(L"FT_Common.FT_SIZE_REQUEST_TYPE_MAX"); _vec2.push_back(L"5");
+    _vec1.push_back(L"FT_Common.FT_SIZE_REQUEST_TYPE_NOMINAL"); _vec2.push_back(L"0");
+    _vec1.push_back(L"FT_Common.FT_SIZE_REQUEST_TYPE_REAL_DIM"); _vec2.push_back(L"1");
+    _vec1.push_back(L"FT_Common.FT_SIZE_REQUEST_TYPE_SCALES"); _vec2.push_back(L"4");
+    _vec1.push_back(L"FT_Common.FT_STYLE_FLAG_BOLD"); _vec2.push_back(L"2");
+    _vec1.push_back(L"FT_Common.FT_STYLE_FLAG_ITALIC"); _vec2.push_back(L"1");
+    _vec1.push_back(L"FT_Common.FT_SUBGLYPH_FLAG_2X2"); _vec2.push_back(L"128");
+    _vec1.push_back(L"FT_Common.FT_SUBGLYPH_FLAG_ARGS_ARE_WORDS"); _vec2.push_back(L"1");
+    _vec1.push_back(L"FT_Common.FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES"); _vec2.push_back(L"2");
+    _vec1.push_back(L"FT_Common.FT_SUBGLYPH_FLAG_ROUND_XY_TO_GRID"); _vec2.push_back(L"4");
+    _vec1.push_back(L"FT_Common.FT_SUBGLYPH_FLAG_SCALE"); _vec2.push_back(L"8");
+    _vec1.push_back(L"FT_Common.FT_SUBGLYPH_FLAG_USE_MY_METRICS"); _vec2.push_back(L"512");
+    _vec1.push_back(L"FT_Common.FT_SUBGLYPH_FLAG_XY_SCALE"); _vec2.push_back(L"64");
+    _vec1.push_back(L"FT_Common.FT_TRIG_MAX_ITERS"); _vec2.push_back(L"23");
+    _vec1.push_back(L"FT_Common.FT_TRIG_SCALE"); _vec2.push_back(L"2608131496");
+    _vec1.push_back(L"FT_Common.GX_TC_RESERVED_TUPLE_FLAGS"); _vec2.push_back(L"28672");
+    _vec1.push_back(L"FT_Common.GX_TC_TUPLES_SHARE_POINT_NUMBERS"); _vec2.push_back(L"32768");
+    _vec1.push_back(L"FT_Common.GX_TC_TUPLE_COUNT_MASK"); _vec2.push_back(L"4095");
+    _vec1.push_back(L"FT_Common.GX_TI_EMBEDDED_TUPLE_COORD"); _vec2.push_back(L"32768");
+    _vec1.push_back(L"FT_Common.GX_TI_INTERMEDIATE_TUPLE"); _vec2.push_back(L"16384");
+    _vec1.push_back(L"FT_Common.GX_TI_PRIVATE_POINT_NUMBERS"); _vec2.push_back(L"8192");
+    _vec1.push_back(L"FT_Common.GX_TI_RESERVED_TUPLE_FLAG"); _vec2.push_back(L"4096");
+    _vec1.push_back(L"FT_Common.GX_TI_TUPLE_INDEX_MASK"); _vec2.push_back(L"4095");
+    _vec1.push_back(L"FT_Common.MAX_RUNNABLE_OPCODES"); _vec2.push_back(L"1000000");
+    _vec1.push_back(L"FT_Common.MORE_COMPONENTS"); _vec2.push_back(L"32");
+    _vec1.push_back(L"FT_Common.N_AFM_TOKENS"); _vec2.push_back(L"74");
+    _vec1.push_back(L"FT_Common.OVERLAP_COMPOUND"); _vec2.push_back(L"1024");
+    _vec1.push_back(L"FT_Common.PS_DICT_BLUE_FUZZ"); _vec2.push_back(L"17");
+    _vec1.push_back(L"FT_Common.PS_DICT_BLUE_SCALE"); _vec2.push_back(L"24");
+    _vec1.push_back(L"FT_Common.PS_DICT_BLUE_SHIFT"); _vec2.push_back(L"25");
+    _vec1.push_back(L"FT_Common.PS_DICT_BLUE_VALUE"); _vec2.push_back(L"16");
+    _vec1.push_back(L"FT_Common.PS_DICT_CHAR_STRING_KEY"); _vec2.push_back(L"7");
+    _vec1.push_back(L"FT_Common.PS_DICT_CHAR_STRING"); _vec2.push_back(L"8");
+    _vec1.push_back(L"FT_Common.PS_DICT_ENCODING_ENTRY"); _vec2.push_back(L"10");
+    _vec1.push_back(L"FT_Common.PS_DICT_ENCODING_TYPE"); _vec2.push_back(L"9");
+    _vec1.push_back(L"FT_Common.PS_DICT_FAMILY_BLUE"); _vec2.push_back(L"21");
+    _vec1.push_back(L"FT_Common.PS_DICT_FAMILY_NAME"); _vec2.push_back(L"39");
+    _vec1.push_back(L"FT_Common.PS_DICT_FAMILY_OTHER_BLUE"); _vec2.push_back(L"23");
+    _vec1.push_back(L"FT_Common.PS_DICT_FONT_BBOX"); _vec2.push_back(L"2");
+    _vec1.push_back(L"FT_Common.PS_DICT_FONT_MATRIX"); _vec2.push_back(L"1");
+    _vec1.push_back(L"FT_Common.PS_DICT_FONT_NAME"); _vec2.push_back(L"4");
+    _vec1.push_back(L"FT_Common.PS_DICT_FONT_TYPE"); _vec2.push_back(L"0");
+    _vec1.push_back(L"FT_Common.PS_DICT_FORCE_BOLD"); _vec2.push_back(L"30");
+    _vec1.push_back(L"FT_Common.PS_DICT_FS_TYPE"); _vec2.push_back(L"44");
+    _vec1.push_back(L"FT_Common.PS_DICT_FULL_NAME"); _vec2.push_back(L"38");
+    _vec1.push_back(L"FT_Common.PS_DICT_IS_FIXED_PITCH"); _vec2.push_back(L"41");
+    _vec1.push_back(L"FT_Common.PS_DICT_ITALIC_ANGLE"); _vec2.push_back(L"45");
+    _vec1.push_back(L"FT_Common.PS_DICT_LANGUAGE_GROUP"); _vec2.push_back(L"35");
+    _vec1.push_back(L"FT_Common.PS_DICT_LEN_IV"); _vec2.push_back(L"33");
+    _vec1.push_back(L"FT_Common.PS_DICT_MAX"); _vec2.push_back(L"45");
+    _vec1.push_back(L"FT_Common.PS_DICT_MIN_FEATURE"); _vec2.push_back(L"32");
+    _vec1.push_back(L"FT_Common.PS_DICT_NOTICE"); _vec2.push_back(L"37");
+    _vec1.push_back(L"FT_Common.PS_DICT_NUM_BLUE_VALUES"); _vec2.push_back(L"15");
+    _vec1.push_back(L"FT_Common.PS_DICT_NUM_CHAR_STRINGS"); _vec2.push_back(L"6");
+    _vec1.push_back(L"FT_Common.PS_DICT_NUM_FAMILY_BLUES"); _vec2.push_back(L"20");
+    _vec1.push_back(L"FT_Common.PS_DICT_NUM_FAMILY_OTHER_BLUES"); _vec2.push_back(L"22");
+    _vec1.push_back(L"FT_Common.PS_DICT_NUM_OTHER_BLUES"); _vec2.push_back(L"18");
+    _vec1.push_back(L"FT_Common.PS_DICT_NUM_STEM_SNAP_H"); _vec2.push_back(L"26");
+    _vec1.push_back(L"FT_Common.PS_DICT_NUM_STEM_SNAP_V"); _vec2.push_back(L"28");
+    _vec1.push_back(L"FT_Common.PS_DICT_NUM_SUBRS"); _vec2.push_back(L"11");
+    _vec1.push_back(L"FT_Common.PS_DICT_OTHER_BLUE"); _vec2.push_back(L"19");
+    _vec1.push_back(L"FT_Common.PS_DICT_PAINT_TYPE"); _vec2.push_back(L"3");
+    _vec1.push_back(L"FT_Common.PS_DICT_PASSWORD"); _vec2.push_back(L"34");
+    _vec1.push_back(L"FT_Common.PS_DICT_RND_STEM_UP"); _vec2.push_back(L"31");
+    _vec1.push_back(L"FT_Common.PS_DICT_STD_HW"); _vec2.push_back(L"13");
+    _vec1.push_back(L"FT_Common.PS_DICT_STD_VW"); _vec2.push_back(L"14");
+    _vec1.push_back(L"FT_Common.PS_DICT_STEM_SNAP_H"); _vec2.push_back(L"27");
+    _vec1.push_back(L"FT_Common.PS_DICT_STEM_SNAP_V"); _vec2.push_back(L"29");
+    _vec1.push_back(L"FT_Common.PS_DICT_SUBR"); _vec2.push_back(L"12");
+    _vec1.push_back(L"FT_Common.PS_DICT_UNDERLINE_POSITION"); _vec2.push_back(L"42");
+    _vec1.push_back(L"FT_Common.PS_DICT_UNDERLINE_THICKNESS"); _vec2.push_back(L"43");
+    _vec1.push_back(L"FT_Common.PS_DICT_UNIQUE_ID"); _vec2.push_back(L"5");
+    _vec1.push_back(L"FT_Common.PS_DICT_VERSION"); _vec2.push_back(L"36");
+    _vec1.push_back(L"FT_Common.PS_DICT_WEIGHT"); _vec2.push_back(L"40");
+    _vec1.push_back(L"FT_Common.ROUND_XY_TO_GRID"); _vec2.push_back(L"4");
+    _vec1.push_back(L"FT_Common.SCALED_COMPONENT_OFFSET"); _vec2.push_back(L"2048");
+    _vec1.push_back(L"FT_Common.SPH_OPTION_BITMAP_WIDTHS"); _vec2.push_back(L"false");
+    _vec1.push_back(L"FT_Common.SPH_OPTION_SET_COMPATIBLE_WIDTHS"); _vec2.push_back(L"false");
+    _vec1.push_back(L"FT_Common.SPH_OPTION_SET_GRAYSCALE"); _vec2.push_back(L"false");
+    _vec1.push_back(L"FT_Common.SPH_OPTION_SET_RASTERIZER_VERSION"); _vec2.push_back(L"38");
+    _vec1.push_back(L"FT_Common.SPH_OPTION_SET_SUBPIXEL"); _vec2.push_back(L"true");
+    _vec1.push_back(L"FT_Common.SPH_TWEAK_ALLOW_X_DMOVEX"); _vec2.push_back(L"2");
+    _vec1.push_back(L"FT_Common.SPH_TWEAK_ALLOW_X_DMOVE"); _vec2.push_back(L"1");
+    _vec1.push_back(L"FT_Common.SPH_TWEAK_ALLOW_X_MOVE_ZP2"); _vec2.push_back(L"4");
+    _vec1.push_back(L"FT_Common.SPH_TWEAK_ALWAYS_DO_DELTAP"); _vec2.push_back(L"8");
+    _vec1.push_back(L"FT_Common.SPH_TWEAK_ALWAYS_SKIP_DELTAP"); _vec2.push_back(L"16");
+    _vec1.push_back(L"FT_Common.SPH_TWEAK_COURIER_NEW_2_HACK"); _vec2.push_back(L"32");
+    _vec1.push_back(L"FT_Common.SPH_TWEAK_DEEMBOLDEN"); _vec2.push_back(L"64");
+    _vec1.push_back(L"FT_Common.SPH_TWEAK_DELTAP_SKIP_EXAGGERATED_VALUES"); _vec2.push_back(L"128");
+    _vec1.push_back(L"FT_Common.SPH_TWEAK_DO_SHPIX"); _vec2.push_back(L"256");
+    _vec1.push_back(L"FT_Common.SPH_TWEAK_EMBOLDEN"); _vec2.push_back(L"512");
+    _vec1.push_back(L"FT_Common.SPH_TWEAK_MIAP_HACK"); _vec2.push_back(L"1024");
+    _vec1.push_back(L"FT_Common.SPH_TWEAK_MIRP_CVT_ZERO"); _vec2.push_back(L"8388608");
+    _vec1.push_back(L"FT_Common.SPH_TWEAK_NORMAL_ROUND"); _vec2.push_back(L"2048");
+    _vec1.push_back(L"FT_Common.SPH_TWEAK_NO_ALIGNRP_AFTER_IUP"); _vec2.push_back(L"4096");
+    _vec1.push_back(L"FT_Common.SPH_TWEAK_NO_CALL_AFTER_IUP"); _vec2.push_back(L"8192");
+    _vec1.push_back(L"FT_Common.SPH_TWEAK_NO_DELTAP_AFTER_IUP"); _vec2.push_back(L"16384");
+    _vec1.push_back(L"FT_Common.SPH_TWEAK_PIXEL_HINTING"); _vec2.push_back(L"32768");
+    _vec1.push_back(L"FT_Common.SPH_TWEAK_RASTERIZER_35"); _vec2.push_back(L"65536");
+    _vec1.push_back(L"FT_Common.SPH_TWEAK_ROUND_NONPIXEL_Y_MOVES"); _vec2.push_back(L"131072");
+    _vec1.push_back(L"FT_Common.SPH_TWEAK_SKIP_INLINE_DELTAS"); _vec2.push_back(L"262144");
+    _vec1.push_back(L"FT_Common.SPH_TWEAK_SKIP_IUP"); _vec2.push_back(L"524288");
+    _vec1.push_back(L"FT_Common.SPH_TWEAK_SKIP_NONPIXEL_Y_MOVES"); _vec2.push_back(L"1048576");
+    _vec1.push_back(L"FT_Common.SPH_TWEAK_SKIP_OFFPIXEL_Y_MOVES"); _vec2.push_back(L"2097152");
+    _vec1.push_back(L"FT_Common.SPH_TWEAK_TIMES_NEW_ROMAN_HACK"); _vec2.push_back(L"4194304");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_0"); _vec2.push_back(L"48");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_7"); _vec2.push_back(L"55");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_9"); _vec2.push_back(L"57");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_A"); _vec2.push_back(L"65");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_BS"); _vec2.push_back(L"47");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_B"); _vec2.push_back(L"66");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_C"); _vec2.push_back(L"67");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_D"); _vec2.push_back(L"68");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_E"); _vec2.push_back(L"69");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_F"); _vec2.push_back(L"70");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_G"); _vec2.push_back(L"71");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_H"); _vec2.push_back(L"72");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_I"); _vec2.push_back(L"73");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_J"); _vec2.push_back(L"74");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_K"); _vec2.push_back(L"75");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_LOGOR"); _vec2.push_back(L"124");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_LS1"); _vec2.push_back(L"40");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_LS2"); _vec2.push_back(L"91");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_LS3"); _vec2.push_back(L"123");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_L"); _vec2.push_back(L"76");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_MATH_1"); _vec2.push_back(L"60");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_MATH_2"); _vec2.push_back(L"62");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_MATH_3"); _vec2.push_back(L"37");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_MATH_MINUS"); _vec2.push_back(L"45");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_MATH_PLUS"); _vec2.push_back(L"43");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_M"); _vec2.push_back(L"77");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_N"); _vec2.push_back(L"78");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_O"); _vec2.push_back(L"79");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_POINT"); _vec2.push_back(L"46");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_P"); _vec2.push_back(L"80");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_Q"); _vec2.push_back(L"81");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_RS1"); _vec2.push_back(L"41");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_RS2"); _vec2.push_back(L"93");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_RS3"); _vec2.push_back(L"125");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_R"); _vec2.push_back(L"82");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_S0"); _vec2.push_back(L"0");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_SERP"); _vec2.push_back(L"59");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_SF"); _vec2.push_back(L"12");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_SHARP"); _vec2.push_back(L"35");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_SN"); _vec2.push_back(L"10");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_SPACE"); _vec2.push_back(L"32");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_SR"); _vec2.push_back(L"13");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_SS"); _vec2.push_back(L"92");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_ST"); _vec2.push_back(L"9");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_S"); _vec2.push_back(L"83");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_T"); _vec2.push_back(L"84");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_U"); _vec2.push_back(L"85");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_VOPROS"); _vec2.push_back(L"63");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_VOSCL"); _vec2.push_back(L"33");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_V"); _vec2.push_back(L"86");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_W"); _vec2.push_back(L"87");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_X"); _vec2.push_back(L"88");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_Y"); _vec2.push_back(L"89");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_Z"); _vec2.push_back(L"90");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST__"); _vec2.push_back(L"95");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_a"); _vec2.push_back(L"97");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_b"); _vec2.push_back(L"98");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_c"); _vec2.push_back(L"99");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_d"); _vec2.push_back(L"100");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_e"); _vec2.push_back(L"101");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_f"); _vec2.push_back(L"102");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_g"); _vec2.push_back(L"103");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_h"); _vec2.push_back(L"104");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_i"); _vec2.push_back(L"105");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_j"); _vec2.push_back(L"106");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_k"); _vec2.push_back(L"107");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_l"); _vec2.push_back(L"108");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_m"); _vec2.push_back(L"109");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_n"); _vec2.push_back(L"110");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_o"); _vec2.push_back(L"111");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_p"); _vec2.push_back(L"112");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_q"); _vec2.push_back(L"113");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_r"); _vec2.push_back(L"114");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_s"); _vec2.push_back(L"115");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_t"); _vec2.push_back(L"116");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_u"); _vec2.push_back(L"117");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_v"); _vec2.push_back(L"118");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_w"); _vec2.push_back(L"119");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_x"); _vec2.push_back(L"120");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_y"); _vec2.push_back(L"121");
+    _vec1.push_back(L"FT_Common.SYMBOL_CONST_z"); _vec2.push_back(L"122");
+    _vec1.push_back(L"FT_Common.T1_BLEND_BLUE_SCALE"); _vec2.push_back(L"9");
+    _vec1.push_back(L"FT_Common.T1_BLEND_BLUE_SHIFT"); _vec2.push_back(L"10");
+    _vec1.push_back(L"FT_Common.T1_BLEND_BLUE_VALUES"); _vec2.push_back(L"3");
+    _vec1.push_back(L"FT_Common.T1_BLEND_FAMILY_BLUES"); _vec2.push_back(L"11");
+    _vec1.push_back(L"FT_Common.T1_BLEND_FAMILY_OTHER_BLUES"); _vec2.push_back(L"12");
+    _vec1.push_back(L"FT_Common.T1_BLEND_FORCE_BOLD"); _vec2.push_back(L"13");
+    _vec1.push_back(L"FT_Common.T1_BLEND_ITALIC_ANGLE"); _vec2.push_back(L"2");
+    _vec1.push_back(L"FT_Common.T1_BLEND_MAX"); _vec2.push_back(L"14");
+    _vec1.push_back(L"FT_Common.T1_BLEND_OTHER_BLUES"); _vec2.push_back(L"4");
+    _vec1.push_back(L"FT_Common.T1_BLEND_STANDARD_HEIGHT"); _vec2.push_back(L"6");
+    _vec1.push_back(L"FT_Common.T1_BLEND_STANDARD_WIDTH"); _vec2.push_back(L"5");
+    _vec1.push_back(L"FT_Common.T1_BLEND_STEM_SNAP_HEIGHTS"); _vec2.push_back(L"8");
+    _vec1.push_back(L"FT_Common.T1_BLEND_STEM_SNAP_WIDTHS"); _vec2.push_back(L"7");
+    _vec1.push_back(L"FT_Common.T1_BLEND_UNDERLINE_POSITION"); _vec2.push_back(L"0");
+    _vec1.push_back(L"FT_Common.T1_BLEND_UNDERLINE_THICKNESS"); _vec2.push_back(L"1");
+    _vec1.push_back(L"FT_Common.T1_ENCODING_TYPE_ARRAY"); _vec2.push_back(L"1");
+    _vec1.push_back(L"FT_Common.T1_ENCODING_TYPE_EXPERT"); _vec2.push_back(L"4");
+    _vec1.push_back(L"FT_Common.T1_ENCODING_TYPE_ISOLATIN1"); _vec2.push_back(L"3");
+    _vec1.push_back(L"FT_Common.T1_ENCODING_TYPE_NONE"); _vec2.push_back(L"0");
+    _vec1.push_back(L"FT_Common.T1_ENCODING_TYPE_STANDARD"); _vec2.push_back(L"2");
+    _vec1.push_back(L"FT_Common.T1_FIELD_DICT_FONTDICT"); _vec2.push_back(L"1");
+    _vec1.push_back(L"FT_Common.T1_FIELD_DICT_PRIVATE"); _vec2.push_back(L"2");
+    _vec1.push_back(L"FT_Common.T1_FIELD_LOCATION_BBOX"); _vec2.push_back(L"5");
+    _vec1.push_back(L"FT_Common.T1_FIELD_LOCATION_BLEND"); _vec2.push_back(L"8");
+    _vec1.push_back(L"FT_Common.T1_FIELD_LOCATION_CID_INFO"); _vec2.push_back(L"0");
+    _vec1.push_back(L"FT_Common.T1_FIELD_LOCATION_FACE"); _vec2.push_back(L"7");
+    _vec1.push_back(L"FT_Common.T1_FIELD_LOCATION_FONT_DICT"); _vec2.push_back(L"1");
+    _vec1.push_back(L"FT_Common.T1_FIELD_LOCATION_FONT_EXTRA"); _vec2.push_back(L"2");
+    _vec1.push_back(L"FT_Common.T1_FIELD_LOCATION_FONT_INFO"); _vec2.push_back(L"3");
+    _vec1.push_back(L"FT_Common.T1_FIELD_LOCATION_LOADER"); _vec2.push_back(L"6");
+    _vec1.push_back(L"FT_Common.T1_FIELD_LOCATION_MAX"); _vec2.push_back(L"9");
+    _vec1.push_back(L"FT_Common.T1_FIELD_LOCATION_PRIVATE"); _vec2.push_back(L"4");
+    _vec1.push_back(L"FT_Common.T1_FIELD_TYPE_BBOX"); _vec2.push_back(L"7");
+    _vec1.push_back(L"FT_Common.T1_FIELD_TYPE_BOOL"); _vec2.push_back(L"1");
+    _vec1.push_back(L"FT_Common.T1_FIELD_TYPE_CALLBACK"); _vec2.push_back(L"10");
+    _vec1.push_back(L"FT_Common.T1_FIELD_TYPE_FIXED_1000"); _vec2.push_back(L"4");
+    _vec1.push_back(L"FT_Common.T1_FIELD_TYPE_FIXED_ARRAY"); _vec2.push_back(L"9");
+    _vec1.push_back(L"FT_Common.T1_FIELD_TYPE_FIXED"); _vec2.push_back(L"3");
+    _vec1.push_back(L"FT_Common.T1_FIELD_TYPE_INTEGER_ARRAY"); _vec2.push_back(L"8");
+    _vec1.push_back(L"FT_Common.T1_FIELD_TYPE_INTEGER"); _vec2.push_back(L"2");
+    _vec1.push_back(L"FT_Common.T1_FIELD_TYPE_KEY"); _vec2.push_back(L"6");
+    _vec1.push_back(L"FT_Common.T1_FIELD_TYPE_MAX"); _vec2.push_back(L"11");
+    _vec1.push_back(L"FT_Common.T1_FIELD_TYPE_NONE"); _vec2.push_back(L"0");
+    _vec1.push_back(L"FT_Common.T1_FIELD_TYPE_STRING"); _vec2.push_back(L"5");
+    _vec1.push_back(L"FT_Common.T1_FONTDIR_AFTER_PRIVATE"); _vec2.push_back(L"2");
+    _vec1.push_back(L"FT_Common.T1_MAX_CHARSTRINGS_OPERANDS"); _vec2.push_back(L"256");
+    _vec1.push_back(L"FT_Common.T1_MAX_MM_AXIS"); _vec2.push_back(L"4");
+    _vec1.push_back(L"FT_Common.T1_MAX_MM_DESIGNS"); _vec2.push_back(L"16");
+    _vec1.push_back(L"FT_Common.T1_MAX_MM_MAP_POINTS"); _vec2.push_back(L"20");
+    _vec1.push_back(L"FT_Common.T1_MAX_SUBRS_CALLS"); _vec2.push_back(L"16");
+    _vec1.push_back(L"FT_Common.T1_MAX_TABLE_ELEMENTS"); _vec2.push_back(L"32");
+    _vec1.push_back(L"FT_Common.T1_PRIVATE"); _vec2.push_back(L"1");
+    _vec1.push_back(L"FT_Common.T1_Parse_Have_Moveto"); _vec2.push_back(L"2");
+    _vec1.push_back(L"FT_Common.T1_Parse_Have_Path"); _vec2.push_back(L"3");
+    _vec1.push_back(L"FT_Common.T1_Parse_Have_Width"); _vec2.push_back(L"1");
+    _vec1.push_back(L"FT_Common.T1_Parse_Start"); _vec2.push_back(L"0");
+    _vec1.push_back(L"FT_Common.T1_TOKEN_TYPE_ANY"); _vec2.push_back(L"1");
+    _vec1.push_back(L"FT_Common.T1_TOKEN_TYPE_ARRAY"); _vec2.push_back(L"3");
+    _vec1.push_back(L"FT_Common.T1_TOKEN_TYPE_KEY"); _vec2.push_back(L"4");
+    _vec1.push_back(L"FT_Common.T1_TOKEN_TYPE_MAX"); _vec2.push_back(L"5");
+    _vec1.push_back(L"FT_Common.T1_TOKEN_TYPE_NONE"); _vec2.push_back(L"0");
+    _vec1.push_back(L"FT_Common.T1_TOKEN_TYPE_STRING"); _vec2.push_back(L"2");
+    _vec1.push_back(L"FT_Common.TABLE_EXTEND"); _vec2.push_back(L"5");
+    _vec1.push_back(L"FT_Common.TTAG_BASE"); _vec2.push_back(L"1111577413");
+    _vec1.push_back(L"FT_Common.TTAG_BDF"); _vec2.push_back(L"1111770656");
+    _vec1.push_back(L"FT_Common.TTAG_CFF"); _vec2.push_back(L"1128678944");
+    _vec1.push_back(L"FT_Common.TTAG_CID"); _vec2.push_back(L"1128875040");
+    _vec1.push_back(L"FT_Common.TTAG_DSIG"); _vec2.push_back(L"1146308935");
+    _vec1.push_back(L"FT_Common.TTAG_EBDT"); _vec2.push_back(L"1161970772");
+    _vec1.push_back(L"FT_Common.TTAG_EBLC"); _vec2.push_back(L"1161972803");
+    _vec1.push_back(L"FT_Common.TTAG_EBSC"); _vec2.push_back(L"1161974595");
+    _vec1.push_back(L"FT_Common.TTAG_FOND"); _vec2.push_back(L"1179602500");
+    _vec1.push_back(L"FT_Common.TTAG_GDEF"); _vec2.push_back(L"1195656518");
+    _vec1.push_back(L"FT_Common.TTAG_GPOS"); _vec2.push_back(L"1196445523");
+    _vec1.push_back(L"FT_Common.TTAG_GSUB"); _vec2.push_back(L"1196643650");
+    _vec1.push_back(L"FT_Common.TTAG_JSTF"); _vec2.push_back(L"1246975046");
+    _vec1.push_back(L"FT_Common.TTAG_LTSH"); _vec2.push_back(L"1280594760");
+    _vec1.push_back(L"FT_Common.TTAG_LWFN"); _vec2.push_back(L"1280788046");
+    _vec1.push_back(L"FT_Common.TTAG_MATH"); _vec2.push_back(L"1296127048");
+    _vec1.push_back(L"FT_Common.TTAG_META"); _vec2.push_back(L"1296389185");
+    _vec1.push_back(L"FT_Common.TTAG_MMFX"); _vec2.push_back(L"1296909912");
+    _vec1.push_back(L"FT_Common.TTAG_MMSD"); _vec2.push_back(L"1296913220");
+    _vec1.push_back(L"FT_Common.TTAG_OS2"); _vec2.push_back(L"1330851634");
+    _vec1.push_back(L"FT_Common.TTAG_OTTO"); _vec2.push_back(L"1330926671");
+    _vec1.push_back(L"FT_Common.TTAG_PCLT"); _vec2.push_back(L"1346587732");
+    _vec1.push_back(L"FT_Common.TTAG_POST"); _vec2.push_back(L"1347375956");
+    _vec1.push_back(L"FT_Common.TTAG_SING"); _vec2.push_back(L"1397313095");
+    _vec1.push_back(L"FT_Common.TTAG_TYP1"); _vec2.push_back(L"1415139377");
+    _vec1.push_back(L"FT_Common.TTAG_VDMX"); _vec2.push_back(L"1447316824");
+    _vec1.push_back(L"FT_Common.TTAG_avar"); _vec2.push_back(L"1635148146");
+    _vec1.push_back(L"FT_Common.TTAG_bdat"); _vec2.push_back(L"1650745716");
+    _vec1.push_back(L"FT_Common.TTAG_bhed"); _vec2.push_back(L"1651008868");
+    _vec1.push_back(L"FT_Common.TTAG_bloc"); _vec2.push_back(L"1651273571");
+    _vec1.push_back(L"FT_Common.TTAG_bsln"); _vec2.push_back(L"1651731566");
+    _vec1.push_back(L"FT_Common.TTAG_cmap"); _vec2.push_back(L"1668112752");
+    _vec1.push_back(L"FT_Common.TTAG_cvar"); _vec2.push_back(L"1668702578");
+    _vec1.push_back(L"FT_Common.TTAG_cvt"); _vec2.push_back(L"1668707360");
+    _vec1.push_back(L"FT_Common.TTAG_feat"); _vec2.push_back(L"1717920116");
+    _vec1.push_back(L"FT_Common.TTAG_fpgm"); _vec2.push_back(L"1718642541");
+    _vec1.push_back(L"FT_Common.TTAG_fvar"); _vec2.push_back(L"1719034226");
+    _vec1.push_back(L"FT_Common.TTAG_gasp"); _vec2.push_back(L"1734439792");
+    _vec1.push_back(L"FT_Common.TTAG_glyf"); _vec2.push_back(L"1735162214");
+    _vec1.push_back(L"FT_Common.TTAG_gvar"); _vec2.push_back(L"1735811442");
+    _vec1.push_back(L"FT_Common.TTAG_hdmx"); _vec2.push_back(L"1751412088");
+    _vec1.push_back(L"FT_Common.TTAG_head"); _vec2.push_back(L"1751474532");
+    _vec1.push_back(L"FT_Common.TTAG_hhea"); _vec2.push_back(L"1751672161");
+    _vec1.push_back(L"FT_Common.TTAG_hmtx"); _vec2.push_back(L"1752003704");
+    _vec1.push_back(L"FT_Common.TTAG_just"); _vec2.push_back(L"1786082164");
+    _vec1.push_back(L"FT_Common.TTAG_kern"); _vec2.push_back(L"1801810542");
+    _vec1.push_back(L"FT_Common.TTAG_lcar"); _vec2.push_back(L"1818452338");
+    _vec1.push_back(L"FT_Common.TTAG_loca"); _vec2.push_back(L"1819239265");
+    _vec1.push_back(L"FT_Common.TTAG_maxp"); _vec2.push_back(L"1835104368");
+    _vec1.push_back(L"FT_Common.TTAG_mort"); _vec2.push_back(L"1836020340");
+    _vec1.push_back(L"FT_Common.TTAG_morx"); _vec2.push_back(L"1836020344");
+    _vec1.push_back(L"FT_Common.TTAG_name"); _vec2.push_back(L"1851878757");
+    _vec1.push_back(L"FT_Common.TTAG_opbd"); _vec2.push_back(L"1869636196");
+    _vec1.push_back(L"FT_Common.TTAG_opsz"); _vec2.push_back(L"1869640570");
+    _vec1.push_back(L"FT_Common.TTAG_post"); _vec2.push_back(L"1886352244");
+    _vec1.push_back(L"FT_Common.TTAG_prep"); _vec2.push_back(L"1886545264");
+    _vec1.push_back(L"FT_Common.TTAG_prop"); _vec2.push_back(L"1886547824");
+    _vec1.push_back(L"FT_Common.TTAG_sfnt"); _vec2.push_back(L"1936092788");
+    _vec1.push_back(L"FT_Common.TTAG_slnt"); _vec2.push_back(L"1936486004");
+    _vec1.push_back(L"FT_Common.TTAG_trak"); _vec2.push_back(L"1953653099");
+    _vec1.push_back(L"FT_Common.TTAG_true"); _vec2.push_back(L"1953658213");
+    _vec1.push_back(L"FT_Common.TTAG_ttcf"); _vec2.push_back(L"1953784678");
+    _vec1.push_back(L"FT_Common.TTAG_ttc"); _vec2.push_back(L"1953784608");
+    _vec1.push_back(L"FT_Common.TTAG_typ1"); _vec2.push_back(L"1954115633");
+    _vec1.push_back(L"FT_Common.TTAG_vhea"); _vec2.push_back(L"1986553185");
+    _vec1.push_back(L"FT_Common.TTAG_vmtx"); _vec2.push_back(L"1986884728");
+    _vec1.push_back(L"FT_Common.TTAG_wdth"); _vec2.push_back(L"2003072104");
+    _vec1.push_back(L"FT_Common.TTAG_wght"); _vec2.push_back(L"2003265652");
+    _vec1.push_back(L"FT_Common.TT_ADOBE_ID_CUSTOM"); _vec2.push_back(L"2");
+    _vec1.push_back(L"FT_Common.TT_ADOBE_ID_EXPERT"); _vec2.push_back(L"1");
+    _vec1.push_back(L"FT_Common.TT_ADOBE_ID_LATIN_1"); _vec2.push_back(L"3");
+    _vec1.push_back(L"FT_Common.TT_ADOBE_ID_STANDARD"); _vec2.push_back(L"0");
+    _vec1.push_back(L"FT_Common.TT_APPLE_ID_DEFAULT"); _vec2.push_back(L"0");
+    _vec1.push_back(L"FT_Common.TT_APPLE_ID_ISO_10646"); _vec2.push_back(L"2");
+    _vec1.push_back(L"FT_Common.TT_APPLE_ID_UNICODE_1_1"); _vec2.push_back(L"1");
+    _vec1.push_back(L"FT_Common.TT_APPLE_ID_UNICODE_2_0"); _vec2.push_back(L"3");
+    _vec1.push_back(L"FT_Common.TT_APPLE_ID_UNICODE_32"); _vec2.push_back(L"4");
+    _vec1.push_back(L"FT_Common.TT_APPLE_ID_VARIANT_SELECTOR"); _vec2.push_back(L"5");
+    _vec1.push_back(L"FT_Common.TT_CMAP_FLAG_OVERLAPPING"); _vec2.push_back(L"2");
+    _vec1.push_back(L"FT_Common.TT_CMAP_FLAG_UNSORTED"); _vec2.push_back(L"1");
+    _vec1.push_back(L"FT_Common.TT_MAC_ID_ROMAN"); _vec2.push_back(L"0");
+    _vec1.push_back(L"FT_Common.TT_MAX_CODE_RANGES"); _vec2.push_back(L"3");
+    _vec1.push_back(L"FT_Common.TT_MS_ID_BIG_5"); _vec2.push_back(L"4");
+    _vec1.push_back(L"FT_Common.TT_MS_ID_GB2312"); _vec2.push_back(L"3");
+    _vec1.push_back(L"FT_Common.TT_MS_ID_JOHAB"); _vec2.push_back(L"6");
+    _vec1.push_back(L"FT_Common.TT_MS_ID_SJIS"); _vec2.push_back(L"2");
+    _vec1.push_back(L"FT_Common.TT_MS_ID_SYMBOL_CS"); _vec2.push_back(L"0");
+    _vec1.push_back(L"FT_Common.TT_MS_ID_UCS_4"); _vec2.push_back(L"10");
+    _vec1.push_back(L"FT_Common.TT_MS_ID_UNICODE_CS"); _vec2.push_back(L"1");
+    _vec1.push_back(L"FT_Common.TT_MS_ID_WANSUNG"); _vec2.push_back(L"5");
+    _vec1.push_back(L"FT_Common.TT_NAME_ID_CID_FINDFONT_NAME"); _vec2.push_back(L"20");
+    _vec1.push_back(L"FT_Common.TT_NAME_ID_COPYRIGHT"); _vec2.push_back(L"0");
+    _vec1.push_back(L"FT_Common.TT_NAME_ID_DESCRIPTION"); _vec2.push_back(L"10");
+    _vec1.push_back(L"FT_Common.TT_NAME_ID_DESIGNER_URL"); _vec2.push_back(L"12");
+    _vec1.push_back(L"FT_Common.TT_NAME_ID_DESIGNER"); _vec2.push_back(L"9");
+    _vec1.push_back(L"FT_Common.TT_NAME_ID_FONT_FAMILY"); _vec2.push_back(L"1");
+    _vec1.push_back(L"FT_Common.TT_NAME_ID_FONT_SUBFAMILY"); _vec2.push_back(L"2");
+    _vec1.push_back(L"FT_Common.TT_NAME_ID_FULL_NAME"); _vec2.push_back(L"4");
+    _vec1.push_back(L"FT_Common.TT_NAME_ID_LICENSE_URL"); _vec2.push_back(L"14");
+    _vec1.push_back(L"FT_Common.TT_NAME_ID_LICENSE"); _vec2.push_back(L"13");
+    _vec1.push_back(L"FT_Common.TT_NAME_ID_MAC_FULL_NAME"); _vec2.push_back(L"18");
+    _vec1.push_back(L"FT_Common.TT_NAME_ID_MANUFACTURER"); _vec2.push_back(L"8");
+    _vec1.push_back(L"FT_Common.TT_NAME_ID_PREFERRED_FAMILY"); _vec2.push_back(L"16");
+    _vec1.push_back(L"FT_Common.TT_NAME_ID_PREFERRED_SUBFAMILY"); _vec2.push_back(L"17");
+    _vec1.push_back(L"FT_Common.TT_NAME_ID_PS_NAME"); _vec2.push_back(L"6");
+    _vec1.push_back(L"FT_Common.TT_NAME_ID_SAMPLE_TEXT"); _vec2.push_back(L"19");
+    _vec1.push_back(L"FT_Common.TT_NAME_ID_TRADEMARK"); _vec2.push_back(L"7");
+    _vec1.push_back(L"FT_Common.TT_NAME_ID_UNIQUE_ID"); _vec2.push_back(L"3");
+    _vec1.push_back(L"FT_Common.TT_NAME_ID_VENDOR_URL"); _vec2.push_back(L"11");
+    _vec1.push_back(L"FT_Common.TT_NAME_ID_VERSION_STRING"); _vec2.push_back(L"5");
+    _vec1.push_back(L"FT_Common.TT_NAME_ID_WWS_FAMILY"); _vec2.push_back(L"21");
+    _vec1.push_back(L"FT_Common.TT_NAME_ID_WWS_SUBFAMILY"); _vec2.push_back(L"22");
+    _vec1.push_back(L"FT_Common.TT_PLATFORM_ADOBE"); _vec2.push_back(L"7");
+    _vec1.push_back(L"FT_Common.TT_PLATFORM_APPLE_UNICODE"); _vec2.push_back(L"0");
+    _vec1.push_back(L"FT_Common.TT_PLATFORM_CUSTOM"); _vec2.push_back(L"4");
+    _vec1.push_back(L"FT_Common.TT_PLATFORM_ISO"); _vec2.push_back(L"2");
+    _vec1.push_back(L"FT_Common.TT_PLATFORM_MACINTOSH"); _vec2.push_back(L"1");
+    _vec1.push_back(L"FT_Common.TT_PLATFORM_MICROSOFT"); _vec2.push_back(L"3");
+    _vec1.push_back(L"FT_Common.UNSCALED_COMPONENT_OFFSET"); _vec2.push_back(L"4096");
+    _vec1.push_back(L"FT_Common.USE_MY_METRICS"); _vec2.push_back(L"512");
+    _vec1.push_back(L"FT_Common.WE_HAVE_AN_XY_SCALE"); _vec2.push_back(L"64");
+    _vec1.push_back(L"FT_Common.WE_HAVE_A_2X2"); _vec2.push_back(L"128");
+    _vec1.push_back(L"FT_Common.WE_HAVE_A_SCALE"); _vec2.push_back(L"8");
+    _vec1.push_back(L"FT_Common.WE_HAVE_INSTR"); _vec2.push_back(L"256");
+    _vec1.push_back(L"FT_Common.a_c"); _vec2.push_back(L"256");
+    _vec1.push_back(L"FT_Common.a_i"); _vec2.push_back(L"4294967296");
+    _vec1.push_back(L"FT_Common.a_s"); _vec2.push_back(L"65536");
+    _vec1.push_back(L"FT_Common.cff_kind_bool"); _vec2.push_back(L"5");
+    _vec1.push_back(L"FT_Common.cff_kind_callback"); _vec2.push_back(L"7");
+    _vec1.push_back(L"FT_Common.cff_kind_delta"); _vec2.push_back(L"6");
+    _vec1.push_back(L"FT_Common.cff_kind_fixed_thousand"); _vec2.push_back(L"3");
+    _vec1.push_back(L"FT_Common.cff_kind_fixed"); _vec2.push_back(L"2");
+    _vec1.push_back(L"FT_Common.cff_kind_max"); _vec2.push_back(L"8");
+    _vec1.push_back(L"FT_Common.cff_kind_none"); _vec2.push_back(L"0");
+    _vec1.push_back(L"FT_Common.cff_kind_num"); _vec2.push_back(L"1");
+    _vec1.push_back(L"FT_Common.cff_kind_string"); _vec2.push_back(L"4");
+    _vec1.push_back(L"FT_Common.cff_op_abs"); _vec2.push_back(L"26");
+    _vec1.push_back(L"FT_Common.cff_op_add"); _vec2.push_back(L"27");
+    _vec1.push_back(L"FT_Common.cff_op_and"); _vec2.push_back(L"44");
+    _vec1.push_back(L"FT_Common.cff_op_blend"); _vec2.push_back(L"34");
+    _vec1.push_back(L"FT_Common.cff_op_callgsubr"); _vec2.push_back(L"50");
+    _vec1.push_back(L"FT_Common.cff_op_callothersubr"); _vec2.push_back(L"54");
+    _vec1.push_back(L"FT_Common.cff_op_callsubr"); _vec2.push_back(L"49");
+    _vec1.push_back(L"FT_Common.cff_op_closepath"); _vec2.push_back(L"53");
+    _vec1.push_back(L"FT_Common.cff_op_cntrmask"); _vec2.push_back(L"24");
+    _vec1.push_back(L"FT_Common.cff_op_div"); _vec2.push_back(L"29");
+    _vec1.push_back(L"FT_Common.cff_op_dotsection"); _vec2.push_back(L"25");
+    _vec1.push_back(L"FT_Common.cff_op_drop"); _vec2.push_back(L"35");
+    _vec1.push_back(L"FT_Common.cff_op_dup"); _vec2.push_back(L"39");
+    _vec1.push_back(L"FT_Common.cff_op_endchar"); _vec2.push_back(L"18");
+    _vec1.push_back(L"FT_Common.cff_op_eq"); _vec2.push_back(L"47");
+    _vec1.push_back(L"FT_Common.cff_op_exch"); _vec2.push_back(L"36");
+    _vec1.push_back(L"FT_Common.cff_op_flex1"); _vec2.push_back(L"17");
+    _vec1.push_back(L"FT_Common.cff_op_flex"); _vec2.push_back(L"14");
+    _vec1.push_back(L"FT_Common.cff_op_get"); _vec2.push_back(L"41");
+    _vec1.push_back(L"FT_Common.cff_op_hflex1"); _vec2.push_back(L"16");
+    _vec1.push_back(L"FT_Common.cff_op_hflex"); _vec2.push_back(L"15");
+    _vec1.push_back(L"FT_Common.cff_op_hhcurveto"); _vec2.push_back(L"8");
+    _vec1.push_back(L"FT_Common.cff_op_hintmask"); _vec2.push_back(L"23");
+    _vec1.push_back(L"FT_Common.cff_op_hlineto"); _vec2.push_back(L"5");
+    _vec1.push_back(L"FT_Common.cff_op_hmoveto"); _vec2.push_back(L"2");
+    _vec1.push_back(L"FT_Common.cff_op_hsbw"); _vec2.push_back(L"52");
+    _vec1.push_back(L"FT_Common.cff_op_hstemhm"); _vec2.push_back(L"21");
+    _vec1.push_back(L"FT_Common.cff_op_hstem"); _vec2.push_back(L"19");
+    _vec1.push_back(L"FT_Common.cff_op_hvcurveto"); _vec2.push_back(L"9");
+    _vec1.push_back(L"FT_Common.cff_op_ifelse"); _vec2.push_back(L"48");
+    _vec1.push_back(L"FT_Common.cff_op_index"); _vec2.push_back(L"37");
+    _vec1.push_back(L"FT_Common.cff_op_load"); _vec2.push_back(L"43");
+    _vec1.push_back(L"FT_Common.cff_op_max"); _vec2.push_back(L"59");
+    _vec1.push_back(L"FT_Common.cff_op_mul"); _vec2.push_back(L"32");
+    _vec1.push_back(L"FT_Common.cff_op_neg"); _vec2.push_back(L"30");
+    _vec1.push_back(L"FT_Common.cff_op_not"); _vec2.push_back(L"46");
+    _vec1.push_back(L"FT_Common.cff_op_or"); _vec2.push_back(L"45");
+    _vec1.push_back(L"FT_Common.cff_op_pop"); _vec2.push_back(L"55");
+    _vec1.push_back(L"FT_Common.cff_op_put"); _vec2.push_back(L"40");
+    _vec1.push_back(L"FT_Common.cff_op_random"); _vec2.push_back(L"31");
+    _vec1.push_back(L"FT_Common.cff_op_rcurveline"); _vec2.push_back(L"10");
+    _vec1.push_back(L"FT_Common.cff_op_return"); _vec2.push_back(L"51");
+    _vec1.push_back(L"FT_Common.cff_op_rlinecurve"); _vec2.push_back(L"11");
+    _vec1.push_back(L"FT_Common.cff_op_rlineto"); _vec2.push_back(L"4");
+    _vec1.push_back(L"FT_Common.cff_op_rmoveto"); _vec2.push_back(L"1");
+    _vec1.push_back(L"FT_Common.cff_op_roll"); _vec2.push_back(L"38");
+    _vec1.push_back(L"FT_Common.cff_op_rrcurveto"); _vec2.push_back(L"7");
+    _vec1.push_back(L"FT_Common.cff_op_sbw"); _vec2.push_back(L"57");
+    _vec1.push_back(L"FT_Common.cff_op_seac"); _vec2.push_back(L"56");
+    _vec1.push_back(L"FT_Common.cff_op_setcurrentpoint"); _vec2.push_back(L"58");
+    _vec1.push_back(L"FT_Common.cff_op_sqrt"); _vec2.push_back(L"33");
+    _vec1.push_back(L"FT_Common.cff_op_store"); _vec2.push_back(L"42");
+    _vec1.push_back(L"FT_Common.cff_op_sub"); _vec2.push_back(L"28");
+    _vec1.push_back(L"FT_Common.cff_op_unknown"); _vec2.push_back(L"0");
+    _vec1.push_back(L"FT_Common.cff_op_vhcurveto"); _vec2.push_back(L"12");
+    _vec1.push_back(L"FT_Common.cff_op_vlineto"); _vec2.push_back(L"6");
+    _vec1.push_back(L"FT_Common.cff_op_vmoveto"); _vec2.push_back(L"3");
+    _vec1.push_back(L"FT_Common.cff_op_vstemhm"); _vec2.push_back(L"22");
+    _vec1.push_back(L"FT_Common.cff_op_vstem"); _vec2.push_back(L"20");
+    _vec1.push_back(L"FT_Common.cff_op_vvcurveto"); _vec2.push_back(L"13");
+    _vec1.push_back(L"FT_Common.m_c"); _vec2.push_back(L"127");
+    _vec1.push_back(L"FT_Common.m_i"); _vec2.push_back(L"2147483647");
+    _vec1.push_back(L"FT_Common.m_s"); _vec2.push_back(L"32767");
+    _vec1.push_back(L"FT_Common.op_callothersubr"); _vec2.push_back(L"21");
+    _vec1.push_back(L"FT_Common.op_callsubr"); _vec2.push_back(L"22");
+    _vec1.push_back(L"FT_Common.op_closepath"); _vec2.push_back(L"5");
+    _vec1.push_back(L"FT_Common.op_div"); _vec2.push_back(L"20");
+    _vec1.push_back(L"FT_Common.op_dotsection"); _vec2.push_back(L"15");
+    _vec1.push_back(L"FT_Common.op_endchar"); _vec2.push_back(L"1");
+    _vec1.push_back(L"FT_Common.op_hlineto"); _vec2.push_back(L"6");
+    _vec1.push_back(L"FT_Common.op_hmoveto"); _vec2.push_back(L"7");
+    _vec1.push_back(L"FT_Common.op_hsbw"); _vec2.push_back(L"2");
+    _vec1.push_back(L"FT_Common.op_hstem3"); _vec2.push_back(L"17");
+    _vec1.push_back(L"FT_Common.op_hstem"); _vec2.push_back(L"16");
+    _vec1.push_back(L"FT_Common.op_hvcurveto"); _vec2.push_back(L"8");
+    _vec1.push_back(L"FT_Common.op_max"); _vec2.push_back(L"27");
+    _vec1.push_back(L"FT_Common.op_none"); _vec2.push_back(L"0");
+    _vec1.push_back(L"FT_Common.op_pop"); _vec2.push_back(L"23");
+    _vec1.push_back(L"FT_Common.op_return"); _vec2.push_back(L"24");
+    _vec1.push_back(L"FT_Common.op_rlineto"); _vec2.push_back(L"9");
+    _vec1.push_back(L"FT_Common.op_rmoveto"); _vec2.push_back(L"10");
+    _vec1.push_back(L"FT_Common.op_rrcurveto"); _vec2.push_back(L"11");
+    _vec1.push_back(L"FT_Common.op_sbw"); _vec2.push_back(L"4");
+    _vec1.push_back(L"FT_Common.op_seac"); _vec2.push_back(L"3");
+    _vec1.push_back(L"FT_Common.op_setcurrentpoint"); _vec2.push_back(L"25");
+    _vec1.push_back(L"FT_Common.op_unknown15"); _vec2.push_back(L"26");
+    _vec1.push_back(L"FT_Common.op_vhcurveto"); _vec2.push_back(L"12");
+    _vec1.push_back(L"FT_Common.op_vlineto"); _vec2.push_back(L"13");
+    _vec1.push_back(L"FT_Common.op_vmoveto"); _vec2.push_back(L"14");
+    _vec1.push_back(L"FT_Common.op_vstem3"); _vec2.push_back(L"19");
+    _vec1.push_back(L"FT_Common.op_vstem"); _vec2.push_back(L"18");
+    _vec1.push_back(L"FT_Common.tt_coderange_cvt"); _vec2.push_back(L"2");
+    _vec1.push_back(L"FT_Common.tt_coderange_font"); _vec2.push_back(L"1");
+    _vec1.push_back(L"FT_Common.tt_coderange_glyph"); _vec2.push_back(L"3");
+    _vec1.push_back(L"FT_Common.tt_coderange_none"); _vec2.push_back(L"0");
+}
+
+void string_replace(std::wstring& text, const std::wstring& replaceFrom, const std::wstring& replaceTo)
+{
+    size_t posn = 0;
+    while (std::wstring::npos != (posn = text.find(replaceFrom, posn)))
+    {
+        text.replace(posn, replaceFrom.length(), replaceTo);
+        posn += replaceTo.length();
+    }
+}
+
+void CorrectScript(std::wstring& sData, std::vector<std::wstring>& _vec1, std::vector<std::wstring>& _vec2)
+{
+    std::vector<std::wstring>::iterator i = _vec1.begin();
+    std::vector<std::wstring>::iterator j = _vec2.begin();
+    for (; i != _vec1.end(); i++, j++)
+    {
+        string_replace(sData, *i, *j);
+    }
+}
+
+int main()
+{
+    std::wstring sBasePath = NSFile::GetProcessDirectory() + L"/../../Freetype/";
+
+    // FILES
+    std::vector<std::wstring> arFiles;
+    arFiles.push_back(sBasePath + L"config.js");
+    arFiles.push_back(sBasePath + L"services.js");
+    arFiles.push_back(sBasePath + L"base.js");
+
+    arFiles.push_back(sBasePath + L"modules/psnames.js");
+    arFiles.push_back(sBasePath + L"modules/psaux.js");
+    arFiles.push_back(sBasePath + L"modules/sfnt.js");
+    arFiles.push_back(sBasePath + L"modules/render.js");
+
+    arFiles.push_back(sBasePath + L"drivers/ttinterp.js");
+    arFiles.push_back(sBasePath + L"drivers/truetype.js");
+    arFiles.push_back(sBasePath + L"drivers/cff.js");
+    arFiles.push_back(sBasePath + L"drivers/t1.js");
+
+    arFiles.push_back(sBasePath + L"freetype.js");
+
+    // CONFIG MAP
+    std::vector<std::wstring> _vec1;
+    std::vector<std::wstring> _vec2;
+    GetConfigMap(_vec1, _vec2);
+
+    // READ
+    std::wstring sOutput = L"\"use strict\";\r\n\r\n";
+    for (std::vector<std::wstring>::iterator i = arFiles.begin(); i != arFiles.end(); i++)
+    {
+        std::wstring sFileInput = *i;
+
+        std::wstring sData = L"";
+        NSFile::CFileBinary::ReadAllTextUtf8(sFileInput, sData);
+
+        if (sFileInput.find(L"config.js") != std::wstring::npos)
+        {
+            std::wstring s0 = L"function _FT_Common()";
+            std::wstring::size_type nPos0 = sData.find(s0);
+            if (nPos0 != std::wstring::npos)
+            {
+                sData = sData.substr(nPos0);
+            }
+
+            std::wstring s1 = L"// GENERATOR_START_CONSTANTS";
+            std::wstring s2 = L"// GENERATOR_END_CONSTANTS";
+
+            std::wstring::size_type nPos1 = sData.find(s1);
+            std::wstring::size_type nPos2 = sData.find(s2);
+
+            if (nPos1 != std::wstring::npos && nPos2 != std::wstring::npos)
+            {
+                std::wstring sRes = sData.substr(0, nPos1) + sData.substr(nPos2 + s2.length());
+                sData = sRes;
+            }
+        }
+
+        CorrectScript(sData, _vec1, _vec2);
+
+        sOutput += sData;
+        sOutput += L"\n";
+    }
+
+    NSFile::CFileBinary::SaveToFile(sBasePath + L"../../font_engine.js", sOutput);
+
+    return 0;
+}
+
diff --git a/Common/FontsFreeType/font_engine.js b/Common/FontsFreeType/font_engine.js
index 77990a7df297cd9d263563680f9d3234cd326625..b6f206f0b7a34f44770f0858898f6258a3c82df0 100644
--- a/Common/FontsFreeType/font_engine.js
+++ b/Common/FontsFreeType/font_engine.js
@@ -1,8 +1,10 @@
 "use strict";
 
 function _FT_Common()
-{    
-    this.UintToInt = function(v){
+{
+
+
+	this.UintToInt = function(v){
         return (v>2147483647)?v-4294967296:v;
     }
     this.UShort_To_Short = function(v){
@@ -100,7 +102,8 @@ function _FT_Common()
         return ret;
     }
 }
-var FT_Common = new _FT_Common();/******************************************************************************/
+var FT_Common = new _FT_Common();
+/******************************************************************************/
 //                                  SERVICES
 /******************************************************************************/
 
@@ -357,7 +360,8 @@ function FT_ServiceCache()
     this.service_GLYPH_DICT = null;
     this.service_PFR_METRICS = null;
     this.service_WINFNT = null;
-}/******************************************************************************/
+}
+/******************************************************************************/
 // stream
 /******************************************************************************/
 function FT_Frame_Field(v,s,o)
@@ -3909,7 +3913,8 @@ function ft_synthesize_vertical_metrics(metrics, advance)
     metrics.vertBearingX = parseInt(metrics.horiBearingX - metrics.horiAdvance / 2);
     metrics.vertBearingY = parseInt((advance - height) / 2);
     metrics.vertAdvance  = advance;
-}var ft_standard_glyph_names = [".null","nonmarkingreturn","notequal","infinity","lessequal","greaterequal","partialdiff","summation","product","pi","integral",
+}
+var ft_standard_glyph_names = [".null","nonmarkingreturn","notequal","infinity","lessequal","greaterequal","partialdiff","summation","product","pi","integral",
 "Omega","radical","approxequal","Delta","nonbreakingspace","lozenge","apple","franc","Gbreve","gbreve","Idotaccent","Scedilla",
 "scedilla","Cacute","cacute","Ccaron","ccaron","dcroat",".notdef","space","exclam","quotedbl","numbersign","dollar","percent",
 "ampersand","quoteright","parenleft","parenright","asterisk","plus","comma","hyphen","period","slash","zero","one","two","three",
@@ -7997,7 +8002,8 @@ function create_psnames_module(library)
     psnames_mod.generic = null;
 
     return psnames_mod;
-}/******************************************************************************/
+}
+/******************************************************************************/
 // t1tables
 /******************************************************************************/
 function _isdigit(x)
@@ -12150,7 +12156,7 @@ function T1_FieldRec()
     this.location = 0;
     this.type = 0;
     this.reader = null;
-    this.offset = 0; // � ��� ��� ������ ������ ����� ������. � �� ����� � ������
+    this.offset = 0; // у нас это просто индекс члена класса. А не сдвиг в памяти
     this.size = 0;
     this.array_max = 0;
 
@@ -12169,8 +12175,8 @@ function create_dublicate_t1_field(_field)
     ret.location = _field.location;
     ret.type = _field.type;
     ret.reader = _field.reader;
-    ret.offset = _field.offset; // � ��� ��� ������ ������ � ������� (�.�. ��� �� ������� ��� ���� �� �����)
-    ret.size = _field.size;     // �� �������� (�� ������� �������)
+    ret.offset = _field.offset; // у нас это просто индекс в МАССИВЕ (т.е. для не массива это поле не нужно)
+    ret.size = _field.size;     // не пользуем (на будущее оставим)
     ret.array_max = _field.array_max;
 
     ret.count_offset = _field.count_offset;
@@ -12599,6 +12605,7 @@ function create_psaux_module(library)
 
     return psaux_mod;
 }
+
 /******************************************************************************/
 // bdf
 /******************************************************************************/
@@ -18129,6 +18136,7 @@ function create_sfnt_module(library)
     return sfnt_mod;
 }
 
+
 function CRasterMemory()
 {
     this.width = 0;
@@ -20554,7 +20562,8 @@ function ft_smooth_render_generic(render, slot, mode, origin, required_mode)
         FT_Outline_Translate(outline, -origin.x, -origin.y);
 
     return error;
-}var TT_Round_Off             = 5;
+}
+var TT_Round_Off             = 5;
 var TT_Round_To_Half_Grid    = 0;
 var TT_Round_To_Grid         = 1;
 var TT_Round_To_Double_Grid  = 2;
@@ -26997,7 +27006,8 @@ function CSubpixHintingHacks()
     // -----------------------------------------------------------------------
 }
 
-var global_SubpixHintingHacks = new CSubpixHintingHacks();/******************************************************************************/
+var global_SubpixHintingHacks = new CSubpixHintingHacks();
+/******************************************************************************/
 // classes
 /******************************************************************************/
 function TT_Size_Metrics()
@@ -28166,19 +28176,6 @@ function tt_done_blend(memory, blend)
 /******************************************************************************/
 // glyphloader
 /******************************************************************************/
-FT_Common.ARGS_ARE_WORDS         = 0x0001;
-FT_Common.ARGS_ARE_XY_VALUES     = 0x0002;
-FT_Common.ROUND_XY_TO_GRID       = 0x0004;
-FT_Common.WE_HAVE_A_SCALE        = 0x0008;
-FT_Common.MORE_COMPONENTS        = 0x0020;
-FT_Common.WE_HAVE_AN_XY_SCALE    = 0x0040;
-FT_Common.WE_HAVE_A_2X2          = 0x0080;
-FT_Common.WE_HAVE_INSTR          = 0x0100;
-FT_Common.USE_MY_METRICS         = 0x0200;
-FT_Common.OVERLAP_COMPOUND       = 0x0400;
-FT_Common.SCALED_COMPONENT_OFFSET   = 0x0800;
-FT_Common.UNSCALED_COMPONENT_OFFSET = 0x1000;
-
 function load_sbit_image(size, glyph, glyph_index, load_flags)
 {
     var metrics = new TT_SBit_MetricsRec();
@@ -28585,19 +28582,19 @@ function TT_Load_Composite_Glyph(loader)
         count_read += 4;
 
         count = 2;
-        if (subglyph.flags & FT_Common.ARGS_ARE_WORDS)
+        if (subglyph.flags & 1)
             count += 2;
-        if (subglyph.flags & FT_Common.WE_HAVE_A_SCALE)
+        if (subglyph.flags & 8)
             count += 2;
-        else if (subglyph.flags & FT_Common.WE_HAVE_AN_XY_SCALE)
+        else if (subglyph.flags & 64)
             count += 4;
-        else if (subglyph.flags & FT_Common.WE_HAVE_A_2X2)
+        else if (subglyph.flags & 128)
             count += 8;
 
         if (count_read + count > size_read)
             return 21;
 
-        if (subglyph.flags & FT_Common.ARGS_ARE_WORDS)
+        if (subglyph.flags & 1)
         {
             subglyph.arg1 = s.GetShort();
             subglyph.arg2 = s.GetShort();
@@ -28611,17 +28608,17 @@ function TT_Load_Composite_Glyph(loader)
         xx = yy = 0x10000;
         xy = yx = 0;
 
-        if (subglyph.flags & FT_Common.WE_HAVE_A_SCALE)
+        if (subglyph.flags & 8)
         {
             xx = s.GetShort() << 2;
             yy = xx;
         }
-        else if (subglyph.flags & FT_Common.WE_HAVE_AN_XY_SCALE)
+        else if (subglyph.flags & 64)
         {
             xx = s.GetShort() << 2;
             yy = s.GetShort() << 2;
         }
-        else if (subglyph.flags & FT_Common.WE_HAVE_A_2X2)
+        else if (subglyph.flags & 128)
         {
             xx = s.GetShort() << 2;
             yx = s.GetShort() << 2;
@@ -28638,7 +28635,7 @@ function TT_Load_Composite_Glyph(loader)
 
         count_read += count;
 
-    } while (subglyph.flags & FT_Common.MORE_COMPONENTS);
+    } while (subglyph.flags & 32);
 
     gloader.current.num_subglyphs = num_subglyphs;
 
@@ -28795,7 +28792,7 @@ function TT_Process_Composite_Component(loader, subglyph, start_point, num_base_
     var num_points = gloader.base.outline.n_points;
     var x, y;
 
-    var have_scale = (0 == (subglyph.flags & (FT_Common.WE_HAVE_A_SCALE | FT_Common.WE_HAVE_AN_XY_SCALE | FT_Common.WE_HAVE_A_2X2))) ? 0 : 1;
+    var have_scale = (0 == (subglyph.flags & (8 | 64 | 128))) ? 0 : 1;
 
     if (have_scale != 0)
     {
@@ -28803,7 +28800,7 @@ function TT_Process_Composite_Component(loader, subglyph, start_point, num_base_
             FT_Vector_Transform(base_vecs[i], subglyph.transform);
     }
 
-    if (0 == (subglyph.flags & FT_Common.ARGS_ARE_XY_VALUES))
+    if (0 == (subglyph.flags & 2))
     {
         var k = subglyph.arg1;
         var l = subglyph.arg2;
@@ -28826,7 +28823,7 @@ function TT_Process_Composite_Component(loader, subglyph, start_point, num_base_
         if (x == 0 && y == 0)
             return 0;
 
-        if (have_scale != 0 && 0 != (subglyph.flags & FT_Common.SCALED_COMPONENT_OFFSET))
+        if (have_scale != 0 && 0 != (subglyph.flags & 2048))
         {
             var mac_xscale = FT_SqrtFixed(FT_MulFix(subglyph.transform.xx, subglyph.transform.xx) +
                                             FT_MulFix(subglyph.transform.xy, subglyph.transform.xy));
@@ -28846,7 +28843,7 @@ function TT_Process_Composite_Component(loader, subglyph, start_point, num_base_
             x = FT_MulFix(x, x_scale);
             y = FT_MulFix(y, y_scale);
 
-            if (subglyph.flags & FT_Common.ROUND_XY_TO_GRID)
+            if (subglyph.flags & 4)
             {
                 x = FT_PIX_ROUND(x);
                 y = FT_PIX_ROUND(y);
@@ -29705,7 +29702,7 @@ function load_truetype_glyph(loader, glyph_index, recurse_count, header_only)
             var i = 0;
             for (; i < limit; ++i, ++subglyph )
             {
-                if (subglyph.flags & FT_Common.ARGS_ARE_XY_VALUES)
+                if (subglyph.flags & 2)
                 {
                     subglyph.arg1 += (deltas[i].x & 0xFFFF);
                     subglyph.arg2 += (deltas[i].y & 0xFFFF);
@@ -29788,7 +29785,7 @@ function load_truetype_glyph(loader, glyph_index, recurse_count, header_only)
 
         var bIsSubFlags = true;
         if (bIsSubFlags && face.driver.library.tt_hint_props.TT_USE_BYTECODE_INTERPRETER)
-            bIsSubFlags = ((subglyph.flags & FT_Common.WE_HAVE_INSTR) != 0);
+            bIsSubFlags = ((subglyph.flags & 256) != 0);
 
         if (((loader.load_flags & 2) == 0) && bIsSubFlags && num_points > start_point)
             TT_Process_Composite_Glyph(loader, start_point, start_contour);
@@ -30796,7 +30793,8 @@ function create_tt_driver(library)
 
     driver.clazz = new TT_Driver_Class();
     return driver;
-}/******************************************************************************/
+}
+/******************************************************************************/
 // cfftypes
 /******************************************************************************/
 function CFF_IndexRec()
@@ -36762,7 +36760,8 @@ function create_cff_driver(library)
     driver.memory = library.Memory;
 
     return driver;
-}/******************************************************************************/
+}
+/******************************************************************************/
 // afm
 /******************************************************************************/
 function T1_Done_Metrics(memory, fi)
@@ -40399,7 +40398,8 @@ function create_t1_driver(library)
 
     driver.clazz = new T1_Driver_Class();
     return driver;
-}var FT_Error = 0;
+}
+var FT_Error = 0;
 function FT_Library()
 {
     this.Memory = null;
@@ -40469,6 +40469,7 @@ function FT_Library()
             error = this.ft_add_renderer(module);
             if (0 != error)
             {
+                //delete module;
                 return error;
             }
         }
@@ -40617,7 +40618,7 @@ function FT_Library()
                 slot = null;
                 if (FT_Error != 0)
                 {
-					face = null;
+                    face = null;
                     return null;
                 }
 
@@ -40626,7 +40627,7 @@ function FT_Library()
                     var size = FT_New_Size(face);
                     if (FT_Error != 0)
                     {
-						face = null;
+                        face = null;
                         return null;
                     }
 
@@ -41705,3 +41706,4 @@ function FT_CMap_New(clazz, init_data, charmap)
 
     return cmap;
 }
+