michael@0: /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ michael@0: /* Copyright 2012 Mozilla Foundation michael@0: * michael@0: * Licensed under the Apache License, Version 2.0 (the "License"); michael@0: * you may not use this file except in compliance with the License. michael@0: * You may obtain a copy of the License at michael@0: * michael@0: * http://www.apache.org/licenses/LICENSE-2.0 michael@0: * michael@0: * Unless required by applicable law or agreed to in writing, software michael@0: * distributed under the License is distributed on an "AS IS" BASIS, michael@0: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. michael@0: * See the License for the specific language governing permissions and michael@0: * limitations under the License. michael@0: */ michael@0: /*jshint globalstrict: false */ michael@0: michael@0: // Initializing PDFJS global object (if still undefined) michael@0: if (typeof PDFJS === 'undefined') { michael@0: (typeof window !== 'undefined' ? window : this).PDFJS = {}; michael@0: } michael@0: michael@0: PDFJS.version = '1.0.68'; michael@0: PDFJS.build = 'ead4cbf'; michael@0: michael@0: (function pdfjsWrapper() { michael@0: // Use strict in our context only - users might not want it michael@0: 'use strict'; michael@0: michael@0: /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ michael@0: /* Copyright 2012 Mozilla Foundation michael@0: * michael@0: * Licensed under the Apache License, Version 2.0 (the "License"); michael@0: * you may not use this file except in compliance with the License. michael@0: * You may obtain a copy of the License at michael@0: * michael@0: * http://www.apache.org/licenses/LICENSE-2.0 michael@0: * michael@0: * Unless required by applicable law or agreed to in writing, software michael@0: * distributed under the License is distributed on an "AS IS" BASIS, michael@0: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. michael@0: * See the License for the specific language governing permissions and michael@0: * limitations under the License. michael@0: */ michael@0: /* globals Cmd, ColorSpace, Dict, MozBlobBuilder, Name, PDFJS, Ref, URL, michael@0: Promise */ michael@0: michael@0: 'use strict'; michael@0: michael@0: var globalScope = (typeof window === 'undefined') ? this : window; michael@0: michael@0: var isWorker = (typeof window == 'undefined'); michael@0: michael@0: var FONT_IDENTITY_MATRIX = [0.001, 0, 0, 0.001, 0, 0]; michael@0: michael@0: var TextRenderingMode = { michael@0: FILL: 0, michael@0: STROKE: 1, michael@0: FILL_STROKE: 2, michael@0: INVISIBLE: 3, michael@0: FILL_ADD_TO_PATH: 4, michael@0: STROKE_ADD_TO_PATH: 5, michael@0: FILL_STROKE_ADD_TO_PATH: 6, michael@0: ADD_TO_PATH: 7, michael@0: FILL_STROKE_MASK: 3, michael@0: ADD_TO_PATH_FLAG: 4 michael@0: }; michael@0: michael@0: var ImageKind = { michael@0: GRAYSCALE_1BPP: 1, michael@0: RGB_24BPP: 2, michael@0: RGBA_32BPP: 3 michael@0: }; michael@0: michael@0: // The global PDFJS object exposes the API michael@0: // In production, it will be declared outside a global wrapper michael@0: // In development, it will be declared here michael@0: if (!globalScope.PDFJS) { michael@0: globalScope.PDFJS = {}; michael@0: } michael@0: michael@0: globalScope.PDFJS.pdfBug = false; michael@0: michael@0: PDFJS.VERBOSITY_LEVELS = { michael@0: errors: 0, michael@0: warnings: 1, michael@0: infos: 5 michael@0: }; michael@0: michael@0: // All the possible operations for an operator list. michael@0: var OPS = PDFJS.OPS = { michael@0: // Intentionally start from 1 so it is easy to spot bad operators that will be michael@0: // 0's. michael@0: dependency: 1, michael@0: setLineWidth: 2, michael@0: setLineCap: 3, michael@0: setLineJoin: 4, michael@0: setMiterLimit: 5, michael@0: setDash: 6, michael@0: setRenderingIntent: 7, michael@0: setFlatness: 8, michael@0: setGState: 9, michael@0: save: 10, michael@0: restore: 11, michael@0: transform: 12, michael@0: moveTo: 13, michael@0: lineTo: 14, michael@0: curveTo: 15, michael@0: curveTo2: 16, michael@0: curveTo3: 17, michael@0: closePath: 18, michael@0: rectangle: 19, michael@0: stroke: 20, michael@0: closeStroke: 21, michael@0: fill: 22, michael@0: eoFill: 23, michael@0: fillStroke: 24, michael@0: eoFillStroke: 25, michael@0: closeFillStroke: 26, michael@0: closeEOFillStroke: 27, michael@0: endPath: 28, michael@0: clip: 29, michael@0: eoClip: 30, michael@0: beginText: 31, michael@0: endText: 32, michael@0: setCharSpacing: 33, michael@0: setWordSpacing: 34, michael@0: setHScale: 35, michael@0: setLeading: 36, michael@0: setFont: 37, michael@0: setTextRenderingMode: 38, michael@0: setTextRise: 39, michael@0: moveText: 40, michael@0: setLeadingMoveText: 41, michael@0: setTextMatrix: 42, michael@0: nextLine: 43, michael@0: showText: 44, michael@0: showSpacedText: 45, michael@0: nextLineShowText: 46, michael@0: nextLineSetSpacingShowText: 47, michael@0: setCharWidth: 48, michael@0: setCharWidthAndBounds: 49, michael@0: setStrokeColorSpace: 50, michael@0: setFillColorSpace: 51, michael@0: setStrokeColor: 52, michael@0: setStrokeColorN: 53, michael@0: setFillColor: 54, michael@0: setFillColorN: 55, michael@0: setStrokeGray: 56, michael@0: setFillGray: 57, michael@0: setStrokeRGBColor: 58, michael@0: setFillRGBColor: 59, michael@0: setStrokeCMYKColor: 60, michael@0: setFillCMYKColor: 61, michael@0: shadingFill: 62, michael@0: beginInlineImage: 63, michael@0: beginImageData: 64, michael@0: endInlineImage: 65, michael@0: paintXObject: 66, michael@0: markPoint: 67, michael@0: markPointProps: 68, michael@0: beginMarkedContent: 69, michael@0: beginMarkedContentProps: 70, michael@0: endMarkedContent: 71, michael@0: beginCompat: 72, michael@0: endCompat: 73, michael@0: paintFormXObjectBegin: 74, michael@0: paintFormXObjectEnd: 75, michael@0: beginGroup: 76, michael@0: endGroup: 77, michael@0: beginAnnotations: 78, michael@0: endAnnotations: 79, michael@0: beginAnnotation: 80, michael@0: endAnnotation: 81, michael@0: paintJpegXObject: 82, michael@0: paintImageMaskXObject: 83, michael@0: paintImageMaskXObjectGroup: 84, michael@0: paintImageXObject: 85, michael@0: paintInlineImageXObject: 86, michael@0: paintInlineImageXObjectGroup: 87, michael@0: paintImageXObjectRepeat: 88, michael@0: paintImageMaskXObjectRepeat: 89, michael@0: paintSolidColorImageMask: 90 michael@0: }; michael@0: michael@0: // A notice for devs. These are good for things that are helpful to devs, such michael@0: // as warning that Workers were disabled, which is important to devs but not michael@0: // end users. michael@0: function info(msg) { michael@0: if (PDFJS.verbosity >= PDFJS.VERBOSITY_LEVELS.infos) { michael@0: console.log('Info: ' + msg); michael@0: } michael@0: } michael@0: michael@0: // Non-fatal warnings. michael@0: function warn(msg) { michael@0: if (PDFJS.verbosity >= PDFJS.VERBOSITY_LEVELS.warnings) { michael@0: console.log('Warning: ' + msg); michael@0: } michael@0: } michael@0: michael@0: // Fatal errors that should trigger the fallback UI and halt execution by michael@0: // throwing an exception. michael@0: function error(msg) { michael@0: // If multiple arguments were passed, pass them all to the log function. michael@0: if (arguments.length > 1) { michael@0: var logArguments = ['Error:']; michael@0: logArguments.push.apply(logArguments, arguments); michael@0: console.log.apply(console, logArguments); michael@0: // Join the arguments into a single string for the lines below. michael@0: msg = [].join.call(arguments, ' '); michael@0: } else { michael@0: console.log('Error: ' + msg); michael@0: } michael@0: console.log(backtrace()); michael@0: UnsupportedManager.notify(UNSUPPORTED_FEATURES.unknown); michael@0: throw new Error(msg); michael@0: } michael@0: michael@0: function backtrace() { michael@0: try { michael@0: throw new Error(); michael@0: } catch (e) { michael@0: return e.stack ? e.stack.split('\n').slice(2).join('\n') : ''; michael@0: } michael@0: } michael@0: michael@0: function assert(cond, msg) { michael@0: if (!cond) { michael@0: error(msg); michael@0: } michael@0: } michael@0: michael@0: var UNSUPPORTED_FEATURES = PDFJS.UNSUPPORTED_FEATURES = { michael@0: unknown: 'unknown', michael@0: forms: 'forms', michael@0: javaScript: 'javaScript', michael@0: smask: 'smask', michael@0: shadingPattern: 'shadingPattern', michael@0: font: 'font' michael@0: }; michael@0: michael@0: var UnsupportedManager = PDFJS.UnsupportedManager = michael@0: (function UnsupportedManagerClosure() { michael@0: var listeners = []; michael@0: return { michael@0: listen: function (cb) { michael@0: listeners.push(cb); michael@0: }, michael@0: notify: function (featureId) { michael@0: warn('Unsupported feature "' + featureId + '"'); michael@0: for (var i = 0, ii = listeners.length; i < ii; i++) { michael@0: listeners[i](featureId); michael@0: } michael@0: } michael@0: }; michael@0: })(); michael@0: michael@0: // Combines two URLs. The baseUrl shall be absolute URL. If the url is an michael@0: // absolute URL, it will be returned as is. michael@0: function combineUrl(baseUrl, url) { michael@0: if (!url) { michael@0: return baseUrl; michael@0: } michael@0: if (/^[a-z][a-z0-9+\-.]*:/i.test(url)) { michael@0: return url; michael@0: } michael@0: var i; michael@0: if (url.charAt(0) == '/') { michael@0: // absolute path michael@0: i = baseUrl.indexOf('://'); michael@0: if (url.charAt(1) === '/') { michael@0: ++i; michael@0: } else { michael@0: i = baseUrl.indexOf('/', i + 3); michael@0: } michael@0: return baseUrl.substring(0, i) + url; michael@0: } else { michael@0: // relative path michael@0: var pathLength = baseUrl.length; michael@0: i = baseUrl.lastIndexOf('#'); michael@0: pathLength = i >= 0 ? i : pathLength; michael@0: i = baseUrl.lastIndexOf('?', pathLength); michael@0: pathLength = i >= 0 ? i : pathLength; michael@0: var prefixLength = baseUrl.lastIndexOf('/', pathLength); michael@0: return baseUrl.substring(0, prefixLength + 1) + url; michael@0: } michael@0: } michael@0: michael@0: // Validates if URL is safe and allowed, e.g. to avoid XSS. michael@0: function isValidUrl(url, allowRelative) { michael@0: if (!url) { michael@0: return false; michael@0: } michael@0: // RFC 3986 (http://tools.ietf.org/html/rfc3986#section-3.1) michael@0: // scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) michael@0: var protocol = /^[a-z][a-z0-9+\-.]*(?=:)/i.exec(url); michael@0: if (!protocol) { michael@0: return allowRelative; michael@0: } michael@0: protocol = protocol[0].toLowerCase(); michael@0: switch (protocol) { michael@0: case 'http': michael@0: case 'https': michael@0: case 'ftp': michael@0: case 'mailto': michael@0: return true; michael@0: default: michael@0: return false; michael@0: } michael@0: } michael@0: PDFJS.isValidUrl = isValidUrl; michael@0: michael@0: function shadow(obj, prop, value) { michael@0: Object.defineProperty(obj, prop, { value: value, michael@0: enumerable: true, michael@0: configurable: true, michael@0: writable: false }); michael@0: return value; michael@0: } michael@0: michael@0: var PasswordResponses = PDFJS.PasswordResponses = { michael@0: NEED_PASSWORD: 1, michael@0: INCORRECT_PASSWORD: 2 michael@0: }; michael@0: michael@0: var PasswordException = (function PasswordExceptionClosure() { michael@0: function PasswordException(msg, code) { michael@0: this.name = 'PasswordException'; michael@0: this.message = msg; michael@0: this.code = code; michael@0: } michael@0: michael@0: PasswordException.prototype = new Error(); michael@0: PasswordException.constructor = PasswordException; michael@0: michael@0: return PasswordException; michael@0: })(); michael@0: michael@0: var UnknownErrorException = (function UnknownErrorExceptionClosure() { michael@0: function UnknownErrorException(msg, details) { michael@0: this.name = 'UnknownErrorException'; michael@0: this.message = msg; michael@0: this.details = details; michael@0: } michael@0: michael@0: UnknownErrorException.prototype = new Error(); michael@0: UnknownErrorException.constructor = UnknownErrorException; michael@0: michael@0: return UnknownErrorException; michael@0: })(); michael@0: michael@0: var InvalidPDFException = (function InvalidPDFExceptionClosure() { michael@0: function InvalidPDFException(msg) { michael@0: this.name = 'InvalidPDFException'; michael@0: this.message = msg; michael@0: } michael@0: michael@0: InvalidPDFException.prototype = new Error(); michael@0: InvalidPDFException.constructor = InvalidPDFException; michael@0: michael@0: return InvalidPDFException; michael@0: })(); michael@0: michael@0: var MissingPDFException = (function MissingPDFExceptionClosure() { michael@0: function MissingPDFException(msg) { michael@0: this.name = 'MissingPDFException'; michael@0: this.message = msg; michael@0: } michael@0: michael@0: MissingPDFException.prototype = new Error(); michael@0: MissingPDFException.constructor = MissingPDFException; michael@0: michael@0: return MissingPDFException; michael@0: })(); michael@0: michael@0: var NotImplementedException = (function NotImplementedExceptionClosure() { michael@0: function NotImplementedException(msg) { michael@0: this.message = msg; michael@0: } michael@0: michael@0: NotImplementedException.prototype = new Error(); michael@0: NotImplementedException.prototype.name = 'NotImplementedException'; michael@0: NotImplementedException.constructor = NotImplementedException; michael@0: michael@0: return NotImplementedException; michael@0: })(); michael@0: michael@0: var MissingDataException = (function MissingDataExceptionClosure() { michael@0: function MissingDataException(begin, end) { michael@0: this.begin = begin; michael@0: this.end = end; michael@0: this.message = 'Missing data [' + begin + ', ' + end + ')'; michael@0: } michael@0: michael@0: MissingDataException.prototype = new Error(); michael@0: MissingDataException.prototype.name = 'MissingDataException'; michael@0: MissingDataException.constructor = MissingDataException; michael@0: michael@0: return MissingDataException; michael@0: })(); michael@0: michael@0: var XRefParseException = (function XRefParseExceptionClosure() { michael@0: function XRefParseException(msg) { michael@0: this.message = msg; michael@0: } michael@0: michael@0: XRefParseException.prototype = new Error(); michael@0: XRefParseException.prototype.name = 'XRefParseException'; michael@0: XRefParseException.constructor = XRefParseException; michael@0: michael@0: return XRefParseException; michael@0: })(); michael@0: michael@0: michael@0: function bytesToString(bytes) { michael@0: var length = bytes.length; michael@0: var MAX_ARGUMENT_COUNT = 8192; michael@0: if (length < MAX_ARGUMENT_COUNT) { michael@0: return String.fromCharCode.apply(null, bytes); michael@0: } michael@0: var strBuf = []; michael@0: for (var i = 0; i < length; i += MAX_ARGUMENT_COUNT) { michael@0: var chunkEnd = Math.min(i + MAX_ARGUMENT_COUNT, length); michael@0: var chunk = bytes.subarray(i, chunkEnd); michael@0: strBuf.push(String.fromCharCode.apply(null, chunk)); michael@0: } michael@0: return strBuf.join(''); michael@0: } michael@0: michael@0: function stringToArray(str) { michael@0: var length = str.length; michael@0: var array = []; michael@0: for (var i = 0; i < length; ++i) { michael@0: array[i] = str.charCodeAt(i); michael@0: } michael@0: return array; michael@0: } michael@0: michael@0: function stringToBytes(str) { michael@0: var length = str.length; michael@0: var bytes = new Uint8Array(length); michael@0: for (var i = 0; i < length; ++i) { michael@0: bytes[i] = str.charCodeAt(i) & 0xFF; michael@0: } michael@0: return bytes; michael@0: } michael@0: michael@0: function string32(value) { michael@0: return String.fromCharCode((value >> 24) & 0xff, (value >> 16) & 0xff, michael@0: (value >> 8) & 0xff, value & 0xff); michael@0: } michael@0: michael@0: function log2(x) { michael@0: var n = 1, i = 0; michael@0: while (x > n) { michael@0: n <<= 1; michael@0: i++; michael@0: } michael@0: return i; michael@0: } michael@0: michael@0: function readInt8(data, start) { michael@0: return (data[start] << 24) >> 24; michael@0: } michael@0: michael@0: function readUint16(data, offset) { michael@0: return (data[offset] << 8) | data[offset + 1]; michael@0: } michael@0: michael@0: function readUint32(data, offset) { michael@0: return ((data[offset] << 24) | (data[offset + 1] << 16) | michael@0: (data[offset + 2] << 8) | data[offset + 3]) >>> 0; michael@0: } michael@0: michael@0: // Lazy test the endianness of the platform michael@0: // NOTE: This will be 'true' for simulated TypedArrays michael@0: function isLittleEndian() { michael@0: var buffer8 = new Uint8Array(2); michael@0: buffer8[0] = 1; michael@0: var buffer16 = new Uint16Array(buffer8.buffer); michael@0: return (buffer16[0] === 1); michael@0: } michael@0: michael@0: Object.defineProperty(PDFJS, 'isLittleEndian', { michael@0: configurable: true, michael@0: get: function PDFJS_isLittleEndian() { michael@0: return shadow(PDFJS, 'isLittleEndian', isLittleEndian()); michael@0: } michael@0: }); michael@0: michael@0: PDFJS.hasCanvasTypedArrays = true; michael@0: michael@0: var IDENTITY_MATRIX = [1, 0, 0, 1, 0, 0]; michael@0: michael@0: var Util = PDFJS.Util = (function UtilClosure() { michael@0: function Util() {} michael@0: michael@0: Util.makeCssRgb = function Util_makeCssRgb(rgb) { michael@0: return 'rgb(' + rgb[0] + ',' + rgb[1] + ',' + rgb[2] + ')'; michael@0: }; michael@0: michael@0: Util.makeCssCmyk = function Util_makeCssCmyk(cmyk) { michael@0: var rgb = ColorSpace.singletons.cmyk.getRgb(cmyk, 0); michael@0: return Util.makeCssRgb(rgb); michael@0: }; michael@0: michael@0: // Concatenates two transformation matrices together and returns the result. michael@0: Util.transform = function Util_transform(m1, m2) { michael@0: return [ michael@0: m1[0] * m2[0] + m1[2] * m2[1], michael@0: m1[1] * m2[0] + m1[3] * m2[1], michael@0: m1[0] * m2[2] + m1[2] * m2[3], michael@0: m1[1] * m2[2] + m1[3] * m2[3], michael@0: m1[0] * m2[4] + m1[2] * m2[5] + m1[4], michael@0: m1[1] * m2[4] + m1[3] * m2[5] + m1[5] michael@0: ]; michael@0: }; michael@0: michael@0: // For 2d affine transforms michael@0: Util.applyTransform = function Util_applyTransform(p, m) { michael@0: var xt = p[0] * m[0] + p[1] * m[2] + m[4]; michael@0: var yt = p[0] * m[1] + p[1] * m[3] + m[5]; michael@0: return [xt, yt]; michael@0: }; michael@0: michael@0: Util.applyInverseTransform = function Util_applyInverseTransform(p, m) { michael@0: var d = m[0] * m[3] - m[1] * m[2]; michael@0: var xt = (p[0] * m[3] - p[1] * m[2] + m[2] * m[5] - m[4] * m[3]) / d; michael@0: var yt = (-p[0] * m[1] + p[1] * m[0] + m[4] * m[1] - m[5] * m[0]) / d; michael@0: return [xt, yt]; michael@0: }; michael@0: michael@0: // Applies the transform to the rectangle and finds the minimum axially michael@0: // aligned bounding box. michael@0: Util.getAxialAlignedBoundingBox = michael@0: function Util_getAxialAlignedBoundingBox(r, m) { michael@0: michael@0: var p1 = Util.applyTransform(r, m); michael@0: var p2 = Util.applyTransform(r.slice(2, 4), m); michael@0: var p3 = Util.applyTransform([r[0], r[3]], m); michael@0: var p4 = Util.applyTransform([r[2], r[1]], m); michael@0: return [ michael@0: Math.min(p1[0], p2[0], p3[0], p4[0]), michael@0: Math.min(p1[1], p2[1], p3[1], p4[1]), michael@0: Math.max(p1[0], p2[0], p3[0], p4[0]), michael@0: Math.max(p1[1], p2[1], p3[1], p4[1]) michael@0: ]; michael@0: }; michael@0: michael@0: Util.inverseTransform = function Util_inverseTransform(m) { michael@0: var d = m[0] * m[3] - m[1] * m[2]; michael@0: return [m[3] / d, -m[1] / d, -m[2] / d, m[0] / d, michael@0: (m[2] * m[5] - m[4] * m[3]) / d, (m[4] * m[1] - m[5] * m[0]) / d]; michael@0: }; michael@0: michael@0: // Apply a generic 3d matrix M on a 3-vector v: michael@0: // | a b c | | X | michael@0: // | d e f | x | Y | michael@0: // | g h i | | Z | michael@0: // M is assumed to be serialized as [a,b,c,d,e,f,g,h,i], michael@0: // with v as [X,Y,Z] michael@0: Util.apply3dTransform = function Util_apply3dTransform(m, v) { michael@0: return [ michael@0: m[0] * v[0] + m[1] * v[1] + m[2] * v[2], michael@0: m[3] * v[0] + m[4] * v[1] + m[5] * v[2], michael@0: m[6] * v[0] + m[7] * v[1] + m[8] * v[2] michael@0: ]; michael@0: }; michael@0: michael@0: // This calculation uses Singular Value Decomposition. michael@0: // The SVD can be represented with formula A = USV. We are interested in the michael@0: // matrix S here because it represents the scale values. michael@0: Util.singularValueDecompose2dScale = michael@0: function Util_singularValueDecompose2dScale(m) { michael@0: michael@0: var transpose = [m[0], m[2], m[1], m[3]]; michael@0: michael@0: // Multiply matrix m with its transpose. michael@0: var a = m[0] * transpose[0] + m[1] * transpose[2]; michael@0: var b = m[0] * transpose[1] + m[1] * transpose[3]; michael@0: var c = m[2] * transpose[0] + m[3] * transpose[2]; michael@0: var d = m[2] * transpose[1] + m[3] * transpose[3]; michael@0: michael@0: // Solve the second degree polynomial to get roots. michael@0: var first = (a + d) / 2; michael@0: var second = Math.sqrt((a + d) * (a + d) - 4 * (a * d - c * b)) / 2; michael@0: var sx = first + second || 1; michael@0: var sy = first - second || 1; michael@0: michael@0: // Scale values are the square roots of the eigenvalues. michael@0: return [Math.sqrt(sx), Math.sqrt(sy)]; michael@0: }; michael@0: michael@0: // Normalize rectangle rect=[x1, y1, x2, y2] so that (x1,y1) < (x2,y2) michael@0: // For coordinate systems whose origin lies in the bottom-left, this michael@0: // means normalization to (BL,TR) ordering. For systems with origin in the michael@0: // top-left, this means (TL,BR) ordering. michael@0: Util.normalizeRect = function Util_normalizeRect(rect) { michael@0: var r = rect.slice(0); // clone rect michael@0: if (rect[0] > rect[2]) { michael@0: r[0] = rect[2]; michael@0: r[2] = rect[0]; michael@0: } michael@0: if (rect[1] > rect[3]) { michael@0: r[1] = rect[3]; michael@0: r[3] = rect[1]; michael@0: } michael@0: return r; michael@0: }; michael@0: michael@0: // Returns a rectangle [x1, y1, x2, y2] corresponding to the michael@0: // intersection of rect1 and rect2. If no intersection, returns 'false' michael@0: // The rectangle coordinates of rect1, rect2 should be [x1, y1, x2, y2] michael@0: Util.intersect = function Util_intersect(rect1, rect2) { michael@0: function compare(a, b) { michael@0: return a - b; michael@0: } michael@0: michael@0: // Order points along the axes michael@0: var orderedX = [rect1[0], rect1[2], rect2[0], rect2[2]].sort(compare), michael@0: orderedY = [rect1[1], rect1[3], rect2[1], rect2[3]].sort(compare), michael@0: result = []; michael@0: michael@0: rect1 = Util.normalizeRect(rect1); michael@0: rect2 = Util.normalizeRect(rect2); michael@0: michael@0: // X: first and second points belong to different rectangles? michael@0: if ((orderedX[0] === rect1[0] && orderedX[1] === rect2[0]) || michael@0: (orderedX[0] === rect2[0] && orderedX[1] === rect1[0])) { michael@0: // Intersection must be between second and third points michael@0: result[0] = orderedX[1]; michael@0: result[2] = orderedX[2]; michael@0: } else { michael@0: return false; michael@0: } michael@0: michael@0: // Y: first and second points belong to different rectangles? michael@0: if ((orderedY[0] === rect1[1] && orderedY[1] === rect2[1]) || michael@0: (orderedY[0] === rect2[1] && orderedY[1] === rect1[1])) { michael@0: // Intersection must be between second and third points michael@0: result[1] = orderedY[1]; michael@0: result[3] = orderedY[2]; michael@0: } else { michael@0: return false; michael@0: } michael@0: michael@0: return result; michael@0: }; michael@0: michael@0: Util.sign = function Util_sign(num) { michael@0: return num < 0 ? -1 : 1; michael@0: }; michael@0: michael@0: // TODO(mack): Rename appendToArray michael@0: Util.concatenateToArray = function concatenateToArray(arr1, arr2) { michael@0: Array.prototype.push.apply(arr1, arr2); michael@0: }; michael@0: michael@0: Util.prependToArray = function concatenateToArray(arr1, arr2) { michael@0: Array.prototype.unshift.apply(arr1, arr2); michael@0: }; michael@0: michael@0: Util.extendObj = function extendObj(obj1, obj2) { michael@0: for (var key in obj2) { michael@0: obj1[key] = obj2[key]; michael@0: } michael@0: }; michael@0: michael@0: Util.getInheritableProperty = function Util_getInheritableProperty(dict, michael@0: name) { michael@0: while (dict && !dict.has(name)) { michael@0: dict = dict.get('Parent'); michael@0: } michael@0: if (!dict) { michael@0: return null; michael@0: } michael@0: return dict.get(name); michael@0: }; michael@0: michael@0: Util.inherit = function Util_inherit(sub, base, prototype) { michael@0: sub.prototype = Object.create(base.prototype); michael@0: sub.prototype.constructor = sub; michael@0: for (var prop in prototype) { michael@0: sub.prototype[prop] = prototype[prop]; michael@0: } michael@0: }; michael@0: michael@0: Util.loadScript = function Util_loadScript(src, callback) { michael@0: var script = document.createElement('script'); michael@0: var loaded = false; michael@0: script.setAttribute('src', src); michael@0: if (callback) { michael@0: script.onload = function() { michael@0: if (!loaded) { michael@0: callback(); michael@0: } michael@0: loaded = true; michael@0: }; michael@0: } michael@0: document.getElementsByTagName('head')[0].appendChild(script); michael@0: }; michael@0: michael@0: return Util; michael@0: })(); michael@0: michael@0: var PageViewport = PDFJS.PageViewport = (function PageViewportClosure() { michael@0: function PageViewport(viewBox, scale, rotation, offsetX, offsetY, dontFlip) { michael@0: this.viewBox = viewBox; michael@0: this.scale = scale; michael@0: this.rotation = rotation; michael@0: this.offsetX = offsetX; michael@0: this.offsetY = offsetY; michael@0: michael@0: // creating transform to convert pdf coordinate system to the normal michael@0: // canvas like coordinates taking in account scale and rotation michael@0: var centerX = (viewBox[2] + viewBox[0]) / 2; michael@0: var centerY = (viewBox[3] + viewBox[1]) / 2; michael@0: var rotateA, rotateB, rotateC, rotateD; michael@0: rotation = rotation % 360; michael@0: rotation = rotation < 0 ? rotation + 360 : rotation; michael@0: switch (rotation) { michael@0: case 180: michael@0: rotateA = -1; rotateB = 0; rotateC = 0; rotateD = 1; michael@0: break; michael@0: case 90: michael@0: rotateA = 0; rotateB = 1; rotateC = 1; rotateD = 0; michael@0: break; michael@0: case 270: michael@0: rotateA = 0; rotateB = -1; rotateC = -1; rotateD = 0; michael@0: break; michael@0: //case 0: michael@0: default: michael@0: rotateA = 1; rotateB = 0; rotateC = 0; rotateD = -1; michael@0: break; michael@0: } michael@0: michael@0: if (dontFlip) { michael@0: rotateC = -rotateC; rotateD = -rotateD; michael@0: } michael@0: michael@0: var offsetCanvasX, offsetCanvasY; michael@0: var width, height; michael@0: if (rotateA === 0) { michael@0: offsetCanvasX = Math.abs(centerY - viewBox[1]) * scale + offsetX; michael@0: offsetCanvasY = Math.abs(centerX - viewBox[0]) * scale + offsetY; michael@0: width = Math.abs(viewBox[3] - viewBox[1]) * scale; michael@0: height = Math.abs(viewBox[2] - viewBox[0]) * scale; michael@0: } else { michael@0: offsetCanvasX = Math.abs(centerX - viewBox[0]) * scale + offsetX; michael@0: offsetCanvasY = Math.abs(centerY - viewBox[1]) * scale + offsetY; michael@0: width = Math.abs(viewBox[2] - viewBox[0]) * scale; michael@0: height = Math.abs(viewBox[3] - viewBox[1]) * scale; michael@0: } michael@0: // creating transform for the following operations: michael@0: // translate(-centerX, -centerY), rotate and flip vertically, michael@0: // scale, and translate(offsetCanvasX, offsetCanvasY) michael@0: this.transform = [ michael@0: rotateA * scale, michael@0: rotateB * scale, michael@0: rotateC * scale, michael@0: rotateD * scale, michael@0: offsetCanvasX - rotateA * scale * centerX - rotateC * scale * centerY, michael@0: offsetCanvasY - rotateB * scale * centerX - rotateD * scale * centerY michael@0: ]; michael@0: michael@0: this.width = width; michael@0: this.height = height; michael@0: this.fontScale = scale; michael@0: } michael@0: PageViewport.prototype = { michael@0: clone: function PageViewPort_clone(args) { michael@0: args = args || {}; michael@0: var scale = 'scale' in args ? args.scale : this.scale; michael@0: var rotation = 'rotation' in args ? args.rotation : this.rotation; michael@0: return new PageViewport(this.viewBox.slice(), scale, rotation, michael@0: this.offsetX, this.offsetY, args.dontFlip); michael@0: }, michael@0: convertToViewportPoint: function PageViewport_convertToViewportPoint(x, y) { michael@0: return Util.applyTransform([x, y], this.transform); michael@0: }, michael@0: convertToViewportRectangle: michael@0: function PageViewport_convertToViewportRectangle(rect) { michael@0: var tl = Util.applyTransform([rect[0], rect[1]], this.transform); michael@0: var br = Util.applyTransform([rect[2], rect[3]], this.transform); michael@0: return [tl[0], tl[1], br[0], br[1]]; michael@0: }, michael@0: convertToPdfPoint: function PageViewport_convertToPdfPoint(x, y) { michael@0: return Util.applyInverseTransform([x, y], this.transform); michael@0: } michael@0: }; michael@0: return PageViewport; michael@0: })(); michael@0: michael@0: var PDFStringTranslateTable = [ michael@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, michael@0: 0x2D8, 0x2C7, 0x2C6, 0x2D9, 0x2DD, 0x2DB, 0x2DA, 0x2DC, 0, 0, 0, 0, 0, 0, 0, michael@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, michael@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, michael@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, michael@0: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2022, 0x2020, 0x2021, 0x2026, 0x2014, michael@0: 0x2013, 0x192, 0x2044, 0x2039, 0x203A, 0x2212, 0x2030, 0x201E, 0x201C, michael@0: 0x201D, 0x2018, 0x2019, 0x201A, 0x2122, 0xFB01, 0xFB02, 0x141, 0x152, 0x160, michael@0: 0x178, 0x17D, 0x131, 0x142, 0x153, 0x161, 0x17E, 0, 0x20AC michael@0: ]; michael@0: michael@0: function stringToPDFString(str) { michael@0: var i, n = str.length, strBuf = []; michael@0: if (str[0] === '\xFE' && str[1] === '\xFF') { michael@0: // UTF16BE BOM michael@0: for (i = 2; i < n; i += 2) { michael@0: strBuf.push(String.fromCharCode( michael@0: (str.charCodeAt(i) << 8) | str.charCodeAt(i + 1))); michael@0: } michael@0: } else { michael@0: for (i = 0; i < n; ++i) { michael@0: var code = PDFStringTranslateTable[str.charCodeAt(i)]; michael@0: strBuf.push(code ? String.fromCharCode(code) : str.charAt(i)); michael@0: } michael@0: } michael@0: return strBuf.join(''); michael@0: } michael@0: michael@0: function stringToUTF8String(str) { michael@0: return decodeURIComponent(escape(str)); michael@0: } michael@0: michael@0: function isEmptyObj(obj) { michael@0: for (var key in obj) { michael@0: return false; michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: function isBool(v) { michael@0: return typeof v == 'boolean'; michael@0: } michael@0: michael@0: function isInt(v) { michael@0: return typeof v == 'number' && ((v | 0) == v); michael@0: } michael@0: michael@0: function isNum(v) { michael@0: return typeof v == 'number'; michael@0: } michael@0: michael@0: function isString(v) { michael@0: return typeof v == 'string'; michael@0: } michael@0: michael@0: function isNull(v) { michael@0: return v === null; michael@0: } michael@0: michael@0: function isName(v) { michael@0: return v instanceof Name; michael@0: } michael@0: michael@0: function isCmd(v, cmd) { michael@0: return v instanceof Cmd && (!cmd || v.cmd == cmd); michael@0: } michael@0: michael@0: function isDict(v, type) { michael@0: if (!(v instanceof Dict)) { michael@0: return false; michael@0: } michael@0: if (!type) { michael@0: return true; michael@0: } michael@0: var dictType = v.get('Type'); michael@0: return isName(dictType) && dictType.name == type; michael@0: } michael@0: michael@0: function isArray(v) { michael@0: return v instanceof Array; michael@0: } michael@0: michael@0: function isStream(v) { michael@0: return typeof v == 'object' && v !== null && v !== undefined && michael@0: ('getBytes' in v); michael@0: } michael@0: michael@0: function isArrayBuffer(v) { michael@0: return typeof v == 'object' && v !== null && v !== undefined && michael@0: ('byteLength' in v); michael@0: } michael@0: michael@0: function isRef(v) { michael@0: return v instanceof Ref; michael@0: } michael@0: michael@0: function isPDFFunction(v) { michael@0: var fnDict; michael@0: if (typeof v != 'object') { michael@0: return false; michael@0: } else if (isDict(v)) { michael@0: fnDict = v; michael@0: } else if (isStream(v)) { michael@0: fnDict = v.dict; michael@0: } else { michael@0: return false; michael@0: } michael@0: return fnDict.has('FunctionType'); michael@0: } michael@0: michael@0: /** michael@0: * Legacy support for PDFJS Promise implementation. michael@0: * TODO remove eventually michael@0: * @ignore michael@0: */ michael@0: var LegacyPromise = PDFJS.LegacyPromise = (function LegacyPromiseClosure() { michael@0: return function LegacyPromise() { michael@0: var resolve, reject; michael@0: var promise = new Promise(function (resolve_, reject_) { michael@0: resolve = resolve_; michael@0: reject = reject_; michael@0: }); michael@0: promise.resolve = resolve; michael@0: promise.reject = reject; michael@0: return promise; michael@0: }; michael@0: })(); michael@0: michael@0: /** michael@0: * Polyfill for Promises: michael@0: * The following promise implementation tries to generally implment the michael@0: * Promise/A+ spec. Some notable differences from other promise libaries are: michael@0: * - There currently isn't a seperate deferred and promise object. michael@0: * - Unhandled rejections eventually show an error if they aren't handled. michael@0: * michael@0: * Based off of the work in: michael@0: * https://bugzilla.mozilla.org/show_bug.cgi?id=810490 michael@0: */ michael@0: (function PromiseClosure() { michael@0: if (globalScope.Promise) { michael@0: // Promises existing in the DOM/Worker, checking presence of all/resolve michael@0: if (typeof globalScope.Promise.all !== 'function') { michael@0: globalScope.Promise.all = function (iterable) { michael@0: var count = 0, results = [], resolve, reject; michael@0: var promise = new globalScope.Promise(function (resolve_, reject_) { michael@0: resolve = resolve_; michael@0: reject = reject_; michael@0: }); michael@0: iterable.forEach(function (p, i) { michael@0: count++; michael@0: p.then(function (result) { michael@0: results[i] = result; michael@0: count--; michael@0: if (count === 0) { michael@0: resolve(results); michael@0: } michael@0: }, reject); michael@0: }); michael@0: if (count === 0) { michael@0: resolve(results); michael@0: } michael@0: return promise; michael@0: }; michael@0: } michael@0: if (typeof globalScope.Promise.resolve !== 'function') { michael@0: globalScope.Promise.resolve = function (x) { michael@0: return new globalScope.Promise(function (resolve) { resolve(x); }); michael@0: }; michael@0: } michael@0: return; michael@0: } michael@0: throw new Error('DOM Promise is not present'); michael@0: })(); michael@0: michael@0: var StatTimer = (function StatTimerClosure() { michael@0: function rpad(str, pad, length) { michael@0: while (str.length < length) { michael@0: str += pad; michael@0: } michael@0: return str; michael@0: } michael@0: function StatTimer() { michael@0: this.started = {}; michael@0: this.times = []; michael@0: this.enabled = true; michael@0: } michael@0: StatTimer.prototype = { michael@0: time: function StatTimer_time(name) { michael@0: if (!this.enabled) { michael@0: return; michael@0: } michael@0: if (name in this.started) { michael@0: warn('Timer is already running for ' + name); michael@0: } michael@0: this.started[name] = Date.now(); michael@0: }, michael@0: timeEnd: function StatTimer_timeEnd(name) { michael@0: if (!this.enabled) { michael@0: return; michael@0: } michael@0: if (!(name in this.started)) { michael@0: warn('Timer has not been started for ' + name); michael@0: } michael@0: this.times.push({ michael@0: 'name': name, michael@0: 'start': this.started[name], michael@0: 'end': Date.now() michael@0: }); michael@0: // Remove timer from started so it can be called again. michael@0: delete this.started[name]; michael@0: }, michael@0: toString: function StatTimer_toString() { michael@0: var i, ii; michael@0: var times = this.times; michael@0: var out = ''; michael@0: // Find the longest name for padding purposes. michael@0: var longest = 0; michael@0: for (i = 0, ii = times.length; i < ii; ++i) { michael@0: var name = times[i]['name']; michael@0: if (name.length > longest) { michael@0: longest = name.length; michael@0: } michael@0: } michael@0: for (i = 0, ii = times.length; i < ii; ++i) { michael@0: var span = times[i]; michael@0: var duration = span.end - span.start; michael@0: out += rpad(span['name'], ' ', longest) + ' ' + duration + 'ms\n'; michael@0: } michael@0: return out; michael@0: } michael@0: }; michael@0: return StatTimer; michael@0: })(); michael@0: michael@0: PDFJS.createBlob = function createBlob(data, contentType) { michael@0: if (typeof Blob !== 'undefined') { michael@0: return new Blob([data], { type: contentType }); michael@0: } michael@0: // Blob builder is deprecated in FF14 and removed in FF18. michael@0: var bb = new MozBlobBuilder(); michael@0: bb.append(data); michael@0: return bb.getBlob(contentType); michael@0: }; michael@0: michael@0: PDFJS.createObjectURL = (function createObjectURLClosure() { michael@0: // Blob/createObjectURL is not available, falling back to data schema. michael@0: var digits = michael@0: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; michael@0: michael@0: return function createObjectURL(data, contentType) { michael@0: if (!PDFJS.disableCreateObjectURL && michael@0: typeof URL !== 'undefined' && URL.createObjectURL) { michael@0: var blob = PDFJS.createBlob(data, contentType); michael@0: return URL.createObjectURL(blob); michael@0: } michael@0: michael@0: var buffer = 'data:' + contentType + ';base64,'; michael@0: for (var i = 0, ii = data.length; i < ii; i += 3) { michael@0: var b1 = data[i] & 0xFF; michael@0: var b2 = data[i + 1] & 0xFF; michael@0: var b3 = data[i + 2] & 0xFF; michael@0: var d1 = b1 >> 2, d2 = ((b1 & 3) << 4) | (b2 >> 4); michael@0: var d3 = i + 1 < ii ? ((b2 & 0xF) << 2) | (b3 >> 6) : 64; michael@0: var d4 = i + 2 < ii ? (b3 & 0x3F) : 64; michael@0: buffer += digits[d1] + digits[d2] + digits[d3] + digits[d4]; michael@0: } michael@0: return buffer; michael@0: }; michael@0: })(); michael@0: michael@0: function MessageHandler(name, comObj) { michael@0: this.name = name; michael@0: this.comObj = comObj; michael@0: this.callbackIndex = 1; michael@0: this.postMessageTransfers = true; michael@0: var callbacks = this.callbacks = {}; michael@0: var ah = this.actionHandler = {}; michael@0: michael@0: ah['console_log'] = [function ahConsoleLog(data) { michael@0: console.log.apply(console, data); michael@0: }]; michael@0: ah['console_error'] = [function ahConsoleError(data) { michael@0: console.error.apply(console, data); michael@0: }]; michael@0: ah['_unsupported_feature'] = [function ah_unsupportedFeature(data) { michael@0: UnsupportedManager.notify(data); michael@0: }]; michael@0: michael@0: comObj.onmessage = function messageHandlerComObjOnMessage(event) { michael@0: var data = event.data; michael@0: if (data.isReply) { michael@0: var callbackId = data.callbackId; michael@0: if (data.callbackId in callbacks) { michael@0: var callback = callbacks[callbackId]; michael@0: delete callbacks[callbackId]; michael@0: callback(data.data); michael@0: } else { michael@0: error('Cannot resolve callback ' + callbackId); michael@0: } michael@0: } else if (data.action in ah) { michael@0: var action = ah[data.action]; michael@0: if (data.callbackId) { michael@0: var deferred = {}; michael@0: var promise = new Promise(function (resolve, reject) { michael@0: deferred.resolve = resolve; michael@0: deferred.reject = reject; michael@0: }); michael@0: deferred.promise = promise; michael@0: promise.then(function(resolvedData) { michael@0: comObj.postMessage({ michael@0: isReply: true, michael@0: callbackId: data.callbackId, michael@0: data: resolvedData michael@0: }); michael@0: }); michael@0: action[0].call(action[1], data.data, deferred); michael@0: } else { michael@0: action[0].call(action[1], data.data); michael@0: } michael@0: } else { michael@0: error('Unkown action from worker: ' + data.action); michael@0: } michael@0: }; michael@0: } michael@0: michael@0: MessageHandler.prototype = { michael@0: on: function messageHandlerOn(actionName, handler, scope) { michael@0: var ah = this.actionHandler; michael@0: if (ah[actionName]) { michael@0: error('There is already an actionName called "' + actionName + '"'); michael@0: } michael@0: ah[actionName] = [handler, scope]; michael@0: }, michael@0: /** michael@0: * Sends a message to the comObj to invoke the action with the supplied data. michael@0: * @param {String} actionName Action to call. michael@0: * @param {JSON} data JSON data to send. michael@0: * @param {function} [callback] Optional callback that will handle a reply. michael@0: * @param {Array} [transfers] Optional list of transfers/ArrayBuffers michael@0: */ michael@0: send: function messageHandlerSend(actionName, data, callback, transfers) { michael@0: var message = { michael@0: action: actionName, michael@0: data: data michael@0: }; michael@0: if (callback) { michael@0: var callbackId = this.callbackIndex++; michael@0: this.callbacks[callbackId] = callback; michael@0: message.callbackId = callbackId; michael@0: } michael@0: if (transfers && this.postMessageTransfers) { michael@0: this.comObj.postMessage(message, transfers); michael@0: } else { michael@0: this.comObj.postMessage(message); michael@0: } michael@0: } michael@0: }; michael@0: michael@0: function loadJpegStream(id, imageUrl, objs) { michael@0: var img = new Image(); michael@0: img.onload = (function loadJpegStream_onloadClosure() { michael@0: objs.resolve(id, img); michael@0: }); michael@0: img.src = imageUrl; michael@0: } michael@0: michael@0: michael@0: var ColorSpace = (function ColorSpaceClosure() { michael@0: // Constructor should define this.numComps, this.defaultColor, this.name michael@0: function ColorSpace() { michael@0: error('should not call ColorSpace constructor'); michael@0: } michael@0: michael@0: ColorSpace.prototype = { michael@0: /** michael@0: * Converts the color value to the RGB color. The color components are michael@0: * located in the src array starting from the srcOffset. Returns the array michael@0: * of the rgb components, each value ranging from [0,255]. michael@0: */ michael@0: getRgb: function ColorSpace_getRgb(src, srcOffset) { michael@0: var rgb = new Uint8Array(3); michael@0: this.getRgbItem(src, srcOffset, rgb, 0); michael@0: return rgb; michael@0: }, michael@0: /** michael@0: * Converts the color value to the RGB color, similar to the getRgb method. michael@0: * The result placed into the dest array starting from the destOffset. michael@0: */ michael@0: getRgbItem: function ColorSpace_getRgbItem(src, srcOffset, michael@0: dest, destOffset) { michael@0: error('Should not call ColorSpace.getRgbItem'); michael@0: }, michael@0: /** michael@0: * Converts the specified number of the color values to the RGB colors. michael@0: * The colors are located in the src array starting from the srcOffset. michael@0: * The result is placed into the dest array starting from the destOffset. michael@0: * The src array items shall be in [0,2^bits) range, the dest array items michael@0: * will be in [0,255] range. alpha01 indicates how many alpha components michael@0: * there are in the dest array; it will be either 0 (RGB array) or 1 (RGBA michael@0: * array). michael@0: */ michael@0: getRgbBuffer: function ColorSpace_getRgbBuffer(src, srcOffset, count, michael@0: dest, destOffset, bits, michael@0: alpha01) { michael@0: error('Should not call ColorSpace.getRgbBuffer'); michael@0: }, michael@0: /** michael@0: * Determines the number of bytes required to store the result of the michael@0: * conversion done by the getRgbBuffer method. As in getRgbBuffer, michael@0: * |alpha01| is either 0 (RGB output) or 1 (RGBA output). michael@0: */ michael@0: getOutputLength: function ColorSpace_getOutputLength(inputLength, michael@0: alpha01) { michael@0: error('Should not call ColorSpace.getOutputLength'); michael@0: }, michael@0: /** michael@0: * Returns true if source data will be equal the result/output data. michael@0: */ michael@0: isPassthrough: function ColorSpace_isPassthrough(bits) { michael@0: return false; michael@0: }, michael@0: /** michael@0: * Fills in the RGB colors in the destination buffer. alpha01 indicates michael@0: * how many alpha components there are in the dest array; it will be either michael@0: * 0 (RGB array) or 1 (RGBA array). michael@0: */ michael@0: fillRgb: function ColorSpace_fillRgb(dest, originalWidth, michael@0: originalHeight, width, height, michael@0: actualHeight, bpc, comps, alpha01) { michael@0: var count = originalWidth * originalHeight; michael@0: var rgbBuf = null; michael@0: var numComponentColors = 1 << bpc; michael@0: var needsResizing = originalHeight != height || originalWidth != width; michael@0: var i, ii; michael@0: michael@0: if (this.isPassthrough(bpc)) { michael@0: rgbBuf = comps; michael@0: } else if (this.numComps === 1 && count > numComponentColors && michael@0: this.name !== 'DeviceGray' && this.name !== 'DeviceRGB') { michael@0: // Optimization: create a color map when there is just one component and michael@0: // we are converting more colors than the size of the color map. We michael@0: // don't build the map if the colorspace is gray or rgb since those michael@0: // methods are faster than building a map. This mainly offers big speed michael@0: // ups for indexed and alternate colorspaces. michael@0: // michael@0: // TODO it may be worth while to cache the color map. While running michael@0: // testing I never hit a cache so I will leave that out for now (perhaps michael@0: // we are reparsing colorspaces too much?). michael@0: var allColors = bpc <= 8 ? new Uint8Array(numComponentColors) : michael@0: new Uint16Array(numComponentColors); michael@0: var key; michael@0: for (i = 0; i < numComponentColors; i++) { michael@0: allColors[i] = i; michael@0: } michael@0: var colorMap = new Uint8Array(numComponentColors * 3); michael@0: this.getRgbBuffer(allColors, 0, numComponentColors, colorMap, 0, bpc, michael@0: /* alpha01 = */ 0); michael@0: michael@0: var destPos, rgbPos; michael@0: if (!needsResizing) { michael@0: // Fill in the RGB values directly into |dest|. michael@0: destPos = 0; michael@0: for (i = 0; i < count; ++i) { michael@0: key = comps[i] * 3; michael@0: dest[destPos++] = colorMap[key]; michael@0: dest[destPos++] = colorMap[key + 1]; michael@0: dest[destPos++] = colorMap[key + 2]; michael@0: destPos += alpha01; michael@0: } michael@0: } else { michael@0: rgbBuf = new Uint8Array(count * 3); michael@0: rgbPos = 0; michael@0: for (i = 0; i < count; ++i) { michael@0: key = comps[i] * 3; michael@0: rgbBuf[rgbPos++] = colorMap[key]; michael@0: rgbBuf[rgbPos++] = colorMap[key + 1]; michael@0: rgbBuf[rgbPos++] = colorMap[key + 2]; michael@0: } michael@0: } michael@0: } else { michael@0: if (!needsResizing) { michael@0: // Fill in the RGB values directly into |dest|. michael@0: this.getRgbBuffer(comps, 0, width * actualHeight, dest, 0, bpc, michael@0: alpha01); michael@0: } else { michael@0: rgbBuf = new Uint8Array(count * 3); michael@0: this.getRgbBuffer(comps, 0, count, rgbBuf, 0, bpc, michael@0: /* alpha01 = */ 0); michael@0: } michael@0: } michael@0: michael@0: if (rgbBuf) { michael@0: if (needsResizing) { michael@0: rgbBuf = PDFImage.resize(rgbBuf, bpc, 3, originalWidth, michael@0: originalHeight, width, height); michael@0: } michael@0: rgbPos = 0; michael@0: destPos = 0; michael@0: for (i = 0, ii = width * actualHeight; i < ii; i++) { michael@0: dest[destPos++] = rgbBuf[rgbPos++]; michael@0: dest[destPos++] = rgbBuf[rgbPos++]; michael@0: dest[destPos++] = rgbBuf[rgbPos++]; michael@0: destPos += alpha01; michael@0: } michael@0: } michael@0: }, michael@0: /** michael@0: * True if the colorspace has components in the default range of [0, 1]. michael@0: * This should be true for all colorspaces except for lab color spaces michael@0: * which are [0,100], [-128, 127], [-128, 127]. michael@0: */ michael@0: usesZeroToOneRange: true michael@0: }; michael@0: michael@0: ColorSpace.parse = function ColorSpace_parse(cs, xref, res) { michael@0: var IR = ColorSpace.parseToIR(cs, xref, res); michael@0: if (IR instanceof AlternateCS) { michael@0: return IR; michael@0: } michael@0: return ColorSpace.fromIR(IR); michael@0: }; michael@0: michael@0: ColorSpace.fromIR = function ColorSpace_fromIR(IR) { michael@0: var name = isArray(IR) ? IR[0] : IR; michael@0: var whitePoint, blackPoint; michael@0: michael@0: switch (name) { michael@0: case 'DeviceGrayCS': michael@0: return this.singletons.gray; michael@0: case 'DeviceRgbCS': michael@0: return this.singletons.rgb; michael@0: case 'DeviceCmykCS': michael@0: return this.singletons.cmyk; michael@0: case 'CalGrayCS': michael@0: whitePoint = IR[1].WhitePoint; michael@0: blackPoint = IR[1].BlackPoint; michael@0: var gamma = IR[1].Gamma; michael@0: return new CalGrayCS(whitePoint, blackPoint, gamma); michael@0: case 'PatternCS': michael@0: var basePatternCS = IR[1]; michael@0: if (basePatternCS) { michael@0: basePatternCS = ColorSpace.fromIR(basePatternCS); michael@0: } michael@0: return new PatternCS(basePatternCS); michael@0: case 'IndexedCS': michael@0: var baseIndexedCS = IR[1]; michael@0: var hiVal = IR[2]; michael@0: var lookup = IR[3]; michael@0: return new IndexedCS(ColorSpace.fromIR(baseIndexedCS), hiVal, lookup); michael@0: case 'AlternateCS': michael@0: var numComps = IR[1]; michael@0: var alt = IR[2]; michael@0: var tintFnIR = IR[3]; michael@0: michael@0: return new AlternateCS(numComps, ColorSpace.fromIR(alt), michael@0: PDFFunction.fromIR(tintFnIR)); michael@0: case 'LabCS': michael@0: whitePoint = IR[1].WhitePoint; michael@0: blackPoint = IR[1].BlackPoint; michael@0: var range = IR[1].Range; michael@0: return new LabCS(whitePoint, blackPoint, range); michael@0: default: michael@0: error('Unkown name ' + name); michael@0: } michael@0: return null; michael@0: }; michael@0: michael@0: ColorSpace.parseToIR = function ColorSpace_parseToIR(cs, xref, res) { michael@0: if (isName(cs)) { michael@0: var colorSpaces = res.get('ColorSpace'); michael@0: if (isDict(colorSpaces)) { michael@0: var refcs = colorSpaces.get(cs.name); michael@0: if (refcs) { michael@0: cs = refcs; michael@0: } michael@0: } michael@0: } michael@0: michael@0: cs = xref.fetchIfRef(cs); michael@0: var mode; michael@0: michael@0: if (isName(cs)) { michael@0: mode = cs.name; michael@0: this.mode = mode; michael@0: michael@0: switch (mode) { michael@0: case 'DeviceGray': michael@0: case 'G': michael@0: return 'DeviceGrayCS'; michael@0: case 'DeviceRGB': michael@0: case 'RGB': michael@0: return 'DeviceRgbCS'; michael@0: case 'DeviceCMYK': michael@0: case 'CMYK': michael@0: return 'DeviceCmykCS'; michael@0: case 'Pattern': michael@0: return ['PatternCS', null]; michael@0: default: michael@0: error('unrecognized colorspace ' + mode); michael@0: } michael@0: } else if (isArray(cs)) { michael@0: mode = cs[0].name; michael@0: this.mode = mode; michael@0: var numComps, params; michael@0: michael@0: switch (mode) { michael@0: case 'DeviceGray': michael@0: case 'G': michael@0: return 'DeviceGrayCS'; michael@0: case 'DeviceRGB': michael@0: case 'RGB': michael@0: return 'DeviceRgbCS'; michael@0: case 'DeviceCMYK': michael@0: case 'CMYK': michael@0: return 'DeviceCmykCS'; michael@0: case 'CalGray': michael@0: params = cs[1].getAll(); michael@0: return ['CalGrayCS', params]; michael@0: case 'CalRGB': michael@0: return 'DeviceRgbCS'; michael@0: case 'ICCBased': michael@0: var stream = xref.fetchIfRef(cs[1]); michael@0: var dict = stream.dict; michael@0: numComps = dict.get('N'); michael@0: if (numComps == 1) { michael@0: return 'DeviceGrayCS'; michael@0: } else if (numComps == 3) { michael@0: return 'DeviceRgbCS'; michael@0: } else if (numComps == 4) { michael@0: return 'DeviceCmykCS'; michael@0: } michael@0: break; michael@0: case 'Pattern': michael@0: var basePatternCS = cs[1]; michael@0: if (basePatternCS) { michael@0: basePatternCS = ColorSpace.parseToIR(basePatternCS, xref, res); michael@0: } michael@0: return ['PatternCS', basePatternCS]; michael@0: case 'Indexed': michael@0: case 'I': michael@0: var baseIndexedCS = ColorSpace.parseToIR(cs[1], xref, res); michael@0: var hiVal = cs[2] + 1; michael@0: var lookup = xref.fetchIfRef(cs[3]); michael@0: if (isStream(lookup)) { michael@0: lookup = lookup.getBytes(); michael@0: } michael@0: return ['IndexedCS', baseIndexedCS, hiVal, lookup]; michael@0: case 'Separation': michael@0: case 'DeviceN': michael@0: var name = cs[1]; michael@0: numComps = 1; michael@0: if (isName(name)) { michael@0: numComps = 1; michael@0: } else if (isArray(name)) { michael@0: numComps = name.length; michael@0: } michael@0: var alt = ColorSpace.parseToIR(cs[2], xref, res); michael@0: var tintFnIR = PDFFunction.getIR(xref, xref.fetchIfRef(cs[3])); michael@0: return ['AlternateCS', numComps, alt, tintFnIR]; michael@0: case 'Lab': michael@0: params = cs[1].getAll(); michael@0: return ['LabCS', params]; michael@0: default: michael@0: error('unimplemented color space object "' + mode + '"'); michael@0: } michael@0: } else { michael@0: error('unrecognized color space object: "' + cs + '"'); michael@0: } michael@0: return null; michael@0: }; michael@0: /** michael@0: * Checks if a decode map matches the default decode map for a color space. michael@0: * This handles the general decode maps where there are two values per michael@0: * component. e.g. [0, 1, 0, 1, 0, 1] for a RGB color. michael@0: * This does not handle Lab, Indexed, or Pattern decode maps since they are michael@0: * slightly different. michael@0: * @param {Array} decode Decode map (usually from an image). michael@0: * @param {Number} n Number of components the color space has. michael@0: */ michael@0: ColorSpace.isDefaultDecode = function ColorSpace_isDefaultDecode(decode, n) { michael@0: if (!decode) { michael@0: return true; michael@0: } michael@0: michael@0: if (n * 2 !== decode.length) { michael@0: warn('The decode map is not the correct length'); michael@0: return true; michael@0: } michael@0: for (var i = 0, ii = decode.length; i < ii; i += 2) { michael@0: if (decode[i] !== 0 || decode[i + 1] != 1) { michael@0: return false; michael@0: } michael@0: } michael@0: return true; michael@0: }; michael@0: michael@0: ColorSpace.singletons = { michael@0: get gray() { michael@0: return shadow(this, 'gray', new DeviceGrayCS()); michael@0: }, michael@0: get rgb() { michael@0: return shadow(this, 'rgb', new DeviceRgbCS()); michael@0: }, michael@0: get cmyk() { michael@0: return shadow(this, 'cmyk', new DeviceCmykCS()); michael@0: } michael@0: }; michael@0: michael@0: return ColorSpace; michael@0: })(); michael@0: michael@0: /** michael@0: * Alternate color space handles both Separation and DeviceN color spaces. A michael@0: * Separation color space is actually just a DeviceN with one color component. michael@0: * Both color spaces use a tinting function to convert colors to a base color michael@0: * space. michael@0: */ michael@0: var AlternateCS = (function AlternateCSClosure() { michael@0: function AlternateCS(numComps, base, tintFn) { michael@0: this.name = 'Alternate'; michael@0: this.numComps = numComps; michael@0: this.defaultColor = new Float32Array(numComps); michael@0: for (var i = 0; i < numComps; ++i) { michael@0: this.defaultColor[i] = 1; michael@0: } michael@0: this.base = base; michael@0: this.tintFn = tintFn; michael@0: } michael@0: michael@0: AlternateCS.prototype = { michael@0: getRgb: ColorSpace.prototype.getRgb, michael@0: getRgbItem: function AlternateCS_getRgbItem(src, srcOffset, michael@0: dest, destOffset) { michael@0: var baseNumComps = this.base.numComps; michael@0: var input = 'subarray' in src ? michael@0: src.subarray(srcOffset, srcOffset + this.numComps) : michael@0: Array.prototype.slice.call(src, srcOffset, srcOffset + this.numComps); michael@0: var tinted = this.tintFn(input); michael@0: this.base.getRgbItem(tinted, 0, dest, destOffset); michael@0: }, michael@0: getRgbBuffer: function AlternateCS_getRgbBuffer(src, srcOffset, count, michael@0: dest, destOffset, bits, michael@0: alpha01) { michael@0: var tintFn = this.tintFn; michael@0: var base = this.base; michael@0: var scale = 1 / ((1 << bits) - 1); michael@0: var baseNumComps = base.numComps; michael@0: var usesZeroToOneRange = base.usesZeroToOneRange; michael@0: var isPassthrough = (base.isPassthrough(8) || !usesZeroToOneRange) && michael@0: alpha01 === 0; michael@0: var pos = isPassthrough ? destOffset : 0; michael@0: var baseBuf = isPassthrough ? dest : new Uint8Array(baseNumComps * count); michael@0: var numComps = this.numComps; michael@0: michael@0: var scaled = new Float32Array(numComps); michael@0: var i, j; michael@0: for (i = 0; i < count; i++) { michael@0: for (j = 0; j < numComps; j++) { michael@0: scaled[j] = src[srcOffset++] * scale; michael@0: } michael@0: var tinted = tintFn(scaled); michael@0: if (usesZeroToOneRange) { michael@0: for (j = 0; j < baseNumComps; j++) { michael@0: baseBuf[pos++] = tinted[j] * 255; michael@0: } michael@0: } else { michael@0: base.getRgbItem(tinted, 0, baseBuf, pos); michael@0: pos += baseNumComps; michael@0: } michael@0: } michael@0: if (!isPassthrough) { michael@0: base.getRgbBuffer(baseBuf, 0, count, dest, destOffset, 8, alpha01); michael@0: } michael@0: }, michael@0: getOutputLength: function AlternateCS_getOutputLength(inputLength, michael@0: alpha01) { michael@0: return this.base.getOutputLength(inputLength * michael@0: this.base.numComps / this.numComps, michael@0: alpha01); michael@0: }, michael@0: isPassthrough: ColorSpace.prototype.isPassthrough, michael@0: fillRgb: ColorSpace.prototype.fillRgb, michael@0: isDefaultDecode: function AlternateCS_isDefaultDecode(decodeMap) { michael@0: return ColorSpace.isDefaultDecode(decodeMap, this.numComps); michael@0: }, michael@0: usesZeroToOneRange: true michael@0: }; michael@0: michael@0: return AlternateCS; michael@0: })(); michael@0: michael@0: var PatternCS = (function PatternCSClosure() { michael@0: function PatternCS(baseCS) { michael@0: this.name = 'Pattern'; michael@0: this.base = baseCS; michael@0: } michael@0: PatternCS.prototype = {}; michael@0: michael@0: return PatternCS; michael@0: })(); michael@0: michael@0: var IndexedCS = (function IndexedCSClosure() { michael@0: function IndexedCS(base, highVal, lookup) { michael@0: this.name = 'Indexed'; michael@0: this.numComps = 1; michael@0: this.defaultColor = new Uint8Array([0]); michael@0: this.base = base; michael@0: this.highVal = highVal; michael@0: michael@0: var baseNumComps = base.numComps; michael@0: var length = baseNumComps * highVal; michael@0: var lookupArray; michael@0: michael@0: if (isStream(lookup)) { michael@0: lookupArray = new Uint8Array(length); michael@0: var bytes = lookup.getBytes(length); michael@0: lookupArray.set(bytes); michael@0: } else if (isString(lookup)) { michael@0: lookupArray = new Uint8Array(length); michael@0: for (var i = 0; i < length; ++i) { michael@0: lookupArray[i] = lookup.charCodeAt(i); michael@0: } michael@0: } else if (lookup instanceof Uint8Array || lookup instanceof Array) { michael@0: lookupArray = lookup; michael@0: } else { michael@0: error('Unrecognized lookup table: ' + lookup); michael@0: } michael@0: this.lookup = lookupArray; michael@0: } michael@0: michael@0: IndexedCS.prototype = { michael@0: getRgb: ColorSpace.prototype.getRgb, michael@0: getRgbItem: function IndexedCS_getRgbItem(src, srcOffset, michael@0: dest, destOffset) { michael@0: var numComps = this.base.numComps; michael@0: var start = src[srcOffset] * numComps; michael@0: this.base.getRgbItem(this.lookup, start, dest, destOffset); michael@0: }, michael@0: getRgbBuffer: function IndexedCS_getRgbBuffer(src, srcOffset, count, michael@0: dest, destOffset, bits, michael@0: alpha01) { michael@0: var base = this.base; michael@0: var numComps = base.numComps; michael@0: var outputDelta = base.getOutputLength(numComps, alpha01); michael@0: var lookup = this.lookup; michael@0: michael@0: for (var i = 0; i < count; ++i) { michael@0: var lookupPos = src[srcOffset++] * numComps; michael@0: base.getRgbBuffer(lookup, lookupPos, 1, dest, destOffset, 8, alpha01); michael@0: destOffset += outputDelta; michael@0: } michael@0: }, michael@0: getOutputLength: function IndexedCS_getOutputLength(inputLength, alpha01) { michael@0: return this.base.getOutputLength(inputLength * this.base.numComps, michael@0: alpha01); michael@0: }, michael@0: isPassthrough: ColorSpace.prototype.isPassthrough, michael@0: fillRgb: ColorSpace.prototype.fillRgb, michael@0: isDefaultDecode: function IndexedCS_isDefaultDecode(decodeMap) { michael@0: // indexed color maps shouldn't be changed michael@0: return true; michael@0: }, michael@0: usesZeroToOneRange: true michael@0: }; michael@0: return IndexedCS; michael@0: })(); michael@0: michael@0: var DeviceGrayCS = (function DeviceGrayCSClosure() { michael@0: function DeviceGrayCS() { michael@0: this.name = 'DeviceGray'; michael@0: this.numComps = 1; michael@0: this.defaultColor = new Float32Array([0]); michael@0: } michael@0: michael@0: DeviceGrayCS.prototype = { michael@0: getRgb: ColorSpace.prototype.getRgb, michael@0: getRgbItem: function DeviceGrayCS_getRgbItem(src, srcOffset, michael@0: dest, destOffset) { michael@0: var c = (src[srcOffset] * 255) | 0; michael@0: c = c < 0 ? 0 : c > 255 ? 255 : c; michael@0: dest[destOffset] = dest[destOffset + 1] = dest[destOffset + 2] = c; michael@0: }, michael@0: getRgbBuffer: function DeviceGrayCS_getRgbBuffer(src, srcOffset, count, michael@0: dest, destOffset, bits, michael@0: alpha01) { michael@0: var scale = 255 / ((1 << bits) - 1); michael@0: var j = srcOffset, q = destOffset; michael@0: for (var i = 0; i < count; ++i) { michael@0: var c = (scale * src[j++]) | 0; michael@0: dest[q++] = c; michael@0: dest[q++] = c; michael@0: dest[q++] = c; michael@0: q += alpha01; michael@0: } michael@0: }, michael@0: getOutputLength: function DeviceGrayCS_getOutputLength(inputLength, michael@0: alpha01) { michael@0: return inputLength * (3 + alpha01); michael@0: }, michael@0: isPassthrough: ColorSpace.prototype.isPassthrough, michael@0: fillRgb: ColorSpace.prototype.fillRgb, michael@0: isDefaultDecode: function DeviceGrayCS_isDefaultDecode(decodeMap) { michael@0: return ColorSpace.isDefaultDecode(decodeMap, this.numComps); michael@0: }, michael@0: usesZeroToOneRange: true michael@0: }; michael@0: return DeviceGrayCS; michael@0: })(); michael@0: michael@0: var DeviceRgbCS = (function DeviceRgbCSClosure() { michael@0: function DeviceRgbCS() { michael@0: this.name = 'DeviceRGB'; michael@0: this.numComps = 3; michael@0: this.defaultColor = new Float32Array([0, 0, 0]); michael@0: } michael@0: DeviceRgbCS.prototype = { michael@0: getRgb: ColorSpace.prototype.getRgb, michael@0: getRgbItem: function DeviceRgbCS_getRgbItem(src, srcOffset, michael@0: dest, destOffset) { michael@0: var r = (src[srcOffset] * 255) | 0; michael@0: var g = (src[srcOffset + 1] * 255) | 0; michael@0: var b = (src[srcOffset + 2] * 255) | 0; michael@0: dest[destOffset] = r < 0 ? 0 : r > 255 ? 255 : r; michael@0: dest[destOffset + 1] = g < 0 ? 0 : g > 255 ? 255 : g; michael@0: dest[destOffset + 2] = b < 0 ? 0 : b > 255 ? 255 : b; michael@0: }, michael@0: getRgbBuffer: function DeviceRgbCS_getRgbBuffer(src, srcOffset, count, michael@0: dest, destOffset, bits, michael@0: alpha01) { michael@0: if (bits === 8 && alpha01 === 0) { michael@0: dest.set(src.subarray(srcOffset, srcOffset + count * 3), destOffset); michael@0: return; michael@0: } michael@0: var scale = 255 / ((1 << bits) - 1); michael@0: var j = srcOffset, q = destOffset; michael@0: for (var i = 0; i < count; ++i) { michael@0: dest[q++] = (scale * src[j++]) | 0; michael@0: dest[q++] = (scale * src[j++]) | 0; michael@0: dest[q++] = (scale * src[j++]) | 0; michael@0: q += alpha01; michael@0: } michael@0: }, michael@0: getOutputLength: function DeviceRgbCS_getOutputLength(inputLength, michael@0: alpha01) { michael@0: return (inputLength * (3 + alpha01) / 3) | 0; michael@0: }, michael@0: isPassthrough: function DeviceRgbCS_isPassthrough(bits) { michael@0: return bits == 8; michael@0: }, michael@0: fillRgb: ColorSpace.prototype.fillRgb, michael@0: isDefaultDecode: function DeviceRgbCS_isDefaultDecode(decodeMap) { michael@0: return ColorSpace.isDefaultDecode(decodeMap, this.numComps); michael@0: }, michael@0: usesZeroToOneRange: true michael@0: }; michael@0: return DeviceRgbCS; michael@0: })(); michael@0: michael@0: var DeviceCmykCS = (function DeviceCmykCSClosure() { michael@0: // The coefficients below was found using numerical analysis: the method of michael@0: // steepest descent for the sum((f_i - color_value_i)^2) for r/g/b colors, michael@0: // where color_value is the tabular value from the table of sampled RGB colors michael@0: // from CMYK US Web Coated (SWOP) colorspace, and f_i is the corresponding michael@0: // CMYK color conversion using the estimation below: michael@0: // f(A, B,.. N) = Acc+Bcm+Ccy+Dck+c+Fmm+Gmy+Hmk+Im+Jyy+Kyk+Ly+Mkk+Nk+255 michael@0: function convertToRgb(src, srcOffset, srcScale, dest, destOffset) { michael@0: var c = src[srcOffset + 0] * srcScale; michael@0: var m = src[srcOffset + 1] * srcScale; michael@0: var y = src[srcOffset + 2] * srcScale; michael@0: var k = src[srcOffset + 3] * srcScale; michael@0: michael@0: var r = michael@0: (c * (-4.387332384609988 * c + 54.48615194189176 * m + michael@0: 18.82290502165302 * y + 212.25662451639585 * k + michael@0: -285.2331026137004) + michael@0: m * (1.7149763477362134 * m - 5.6096736904047315 * y + michael@0: -17.873870861415444 * k - 5.497006427196366) + michael@0: y * (-2.5217340131683033 * y - 21.248923337353073 * k + michael@0: 17.5119270841813) + michael@0: k * (-21.86122147463605 * k - 189.48180835922747) + 255) | 0; michael@0: var g = michael@0: (c * (8.841041422036149 * c + 60.118027045597366 * m + michael@0: 6.871425592049007 * y + 31.159100130055922 * k + michael@0: -79.2970844816548) + michael@0: m * (-15.310361306967817 * m + 17.575251261109482 * y + michael@0: 131.35250912493976 * k - 190.9453302588951) + michael@0: y * (4.444339102852739 * y + 9.8632861493405 * k - 24.86741582555878) + michael@0: k * (-20.737325471181034 * k - 187.80453709719578) + 255) | 0; michael@0: var b = michael@0: (c * (0.8842522430003296 * c + 8.078677503112928 * m + michael@0: 30.89978309703729 * y - 0.23883238689178934 * k + michael@0: -14.183576799673286) + michael@0: m * (10.49593273432072 * m + 63.02378494754052 * y + michael@0: 50.606957656360734 * k - 112.23884253719248) + michael@0: y * (0.03296041114873217 * y + 115.60384449646641 * k + michael@0: -193.58209356861505) + michael@0: k * (-22.33816807309886 * k - 180.12613974708367) + 255) | 0; michael@0: michael@0: dest[destOffset] = r > 255 ? 255 : r < 0 ? 0 : r; michael@0: dest[destOffset + 1] = g > 255 ? 255 : g < 0 ? 0 : g; michael@0: dest[destOffset + 2] = b > 255 ? 255 : b < 0 ? 0 : b; michael@0: } michael@0: michael@0: function DeviceCmykCS() { michael@0: this.name = 'DeviceCMYK'; michael@0: this.numComps = 4; michael@0: this.defaultColor = new Float32Array([0, 0, 0, 1]); michael@0: } michael@0: DeviceCmykCS.prototype = { michael@0: getRgb: ColorSpace.prototype.getRgb, michael@0: getRgbItem: function DeviceCmykCS_getRgbItem(src, srcOffset, michael@0: dest, destOffset) { michael@0: convertToRgb(src, srcOffset, 1, dest, destOffset); michael@0: }, michael@0: getRgbBuffer: function DeviceCmykCS_getRgbBuffer(src, srcOffset, count, michael@0: dest, destOffset, bits, michael@0: alpha01) { michael@0: var scale = 1 / ((1 << bits) - 1); michael@0: for (var i = 0; i < count; i++) { michael@0: convertToRgb(src, srcOffset, scale, dest, destOffset); michael@0: srcOffset += 4; michael@0: destOffset += 3 + alpha01; michael@0: } michael@0: }, michael@0: getOutputLength: function DeviceCmykCS_getOutputLength(inputLength, michael@0: alpha01) { michael@0: return (inputLength / 4 * (3 + alpha01)) | 0; michael@0: }, michael@0: isPassthrough: ColorSpace.prototype.isPassthrough, michael@0: fillRgb: ColorSpace.prototype.fillRgb, michael@0: isDefaultDecode: function DeviceCmykCS_isDefaultDecode(decodeMap) { michael@0: return ColorSpace.isDefaultDecode(decodeMap, this.numComps); michael@0: }, michael@0: usesZeroToOneRange: true michael@0: }; michael@0: michael@0: return DeviceCmykCS; michael@0: })(); michael@0: michael@0: // michael@0: // CalGrayCS: Based on "PDF Reference, Sixth Ed", p.245 michael@0: // michael@0: var CalGrayCS = (function CalGrayCSClosure() { michael@0: function CalGrayCS(whitePoint, blackPoint, gamma) { michael@0: this.name = 'CalGray'; michael@0: this.numComps = 1; michael@0: this.defaultColor = new Float32Array([0]); michael@0: michael@0: if (!whitePoint) { michael@0: error('WhitePoint missing - required for color space CalGray'); michael@0: } michael@0: blackPoint = blackPoint || [0, 0, 0]; michael@0: gamma = gamma || 1; michael@0: michael@0: // Translate arguments to spec variables. michael@0: this.XW = whitePoint[0]; michael@0: this.YW = whitePoint[1]; michael@0: this.ZW = whitePoint[2]; michael@0: michael@0: this.XB = blackPoint[0]; michael@0: this.YB = blackPoint[1]; michael@0: this.ZB = blackPoint[2]; michael@0: michael@0: this.G = gamma; michael@0: michael@0: // Validate variables as per spec. michael@0: if (this.XW < 0 || this.ZW < 0 || this.YW !== 1) { michael@0: error('Invalid WhitePoint components for ' + this.name + michael@0: ', no fallback available'); michael@0: } michael@0: michael@0: if (this.XB < 0 || this.YB < 0 || this.ZB < 0) { michael@0: info('Invalid BlackPoint for ' + this.name + ', falling back to default'); michael@0: this.XB = this.YB = this.ZB = 0; michael@0: } michael@0: michael@0: if (this.XB !== 0 || this.YB !== 0 || this.ZB !== 0) { michael@0: warn(this.name + ', BlackPoint: XB: ' + this.XB + ', YB: ' + this.YB + michael@0: ', ZB: ' + this.ZB + ', only default values are supported.'); michael@0: } michael@0: michael@0: if (this.G < 1) { michael@0: info('Invalid Gamma: ' + this.G + ' for ' + this.name + michael@0: ', falling back to default'); michael@0: this.G = 1; michael@0: } michael@0: } michael@0: michael@0: function convertToRgb(cs, src, srcOffset, dest, destOffset, scale) { michael@0: // A represents a gray component of a calibrated gray space. michael@0: // A <---> AG in the spec michael@0: var A = src[srcOffset] * scale; michael@0: var AG = Math.pow(A, cs.G); michael@0: michael@0: // Computes intermediate variables M, L, N as per spec. michael@0: // Except if other than default BlackPoint values are used. michael@0: var M = cs.XW * AG; michael@0: var L = cs.YW * AG; michael@0: var N = cs.ZW * AG; michael@0: michael@0: // Decode XYZ, as per spec. michael@0: var X = M; michael@0: var Y = L; michael@0: var Z = N; michael@0: michael@0: // http://www.poynton.com/notes/colour_and_gamma/ColorFAQ.html, Ch 4. michael@0: // This yields values in range [0, 100]. michael@0: var Lstar = Math.max(116 * Math.pow(Y, 1 / 3) - 16, 0); michael@0: michael@0: // Convert values to rgb range [0, 255]. michael@0: dest[destOffset] = Lstar * 255 / 100; michael@0: dest[destOffset + 1] = Lstar * 255 / 100; michael@0: dest[destOffset + 2] = Lstar * 255 / 100; michael@0: } michael@0: michael@0: CalGrayCS.prototype = { michael@0: getRgb: ColorSpace.prototype.getRgb, michael@0: getRgbItem: function CalGrayCS_getRgbItem(src, srcOffset, michael@0: dest, destOffset) { michael@0: convertToRgb(this, src, srcOffset, dest, destOffset, 1); michael@0: }, michael@0: getRgbBuffer: function CalGrayCS_getRgbBuffer(src, srcOffset, count, michael@0: dest, destOffset, bits, michael@0: alpha01) { michael@0: var scale = 1 / ((1 << bits) - 1); michael@0: michael@0: for (var i = 0; i < count; ++i) { michael@0: convertToRgb(this, src, srcOffset, dest, destOffset, scale); michael@0: srcOffset += 1; michael@0: destOffset += 3 + alpha01; michael@0: } michael@0: }, michael@0: getOutputLength: function CalGrayCS_getOutputLength(inputLength, alpha01) { michael@0: return inputLength * (3 + alpha01); michael@0: }, michael@0: isPassthrough: ColorSpace.prototype.isPassthrough, michael@0: fillRgb: ColorSpace.prototype.fillRgb, michael@0: isDefaultDecode: function CalGrayCS_isDefaultDecode(decodeMap) { michael@0: return ColorSpace.isDefaultDecode(decodeMap, this.numComps); michael@0: }, michael@0: usesZeroToOneRange: true michael@0: }; michael@0: return CalGrayCS; michael@0: })(); michael@0: michael@0: // michael@0: // LabCS: Based on "PDF Reference, Sixth Ed", p.250 michael@0: // michael@0: var LabCS = (function LabCSClosure() { michael@0: function LabCS(whitePoint, blackPoint, range) { michael@0: this.name = 'Lab'; michael@0: this.numComps = 3; michael@0: this.defaultColor = new Float32Array([0, 0, 0]); michael@0: michael@0: if (!whitePoint) { michael@0: error('WhitePoint missing - required for color space Lab'); michael@0: } michael@0: blackPoint = blackPoint || [0, 0, 0]; michael@0: range = range || [-100, 100, -100, 100]; michael@0: michael@0: // Translate args to spec variables michael@0: this.XW = whitePoint[0]; michael@0: this.YW = whitePoint[1]; michael@0: this.ZW = whitePoint[2]; michael@0: this.amin = range[0]; michael@0: this.amax = range[1]; michael@0: this.bmin = range[2]; michael@0: this.bmax = range[3]; michael@0: michael@0: // These are here just for completeness - the spec doesn't offer any michael@0: // formulas that use BlackPoint in Lab michael@0: this.XB = blackPoint[0]; michael@0: this.YB = blackPoint[1]; michael@0: this.ZB = blackPoint[2]; michael@0: michael@0: // Validate vars as per spec michael@0: if (this.XW < 0 || this.ZW < 0 || this.YW !== 1) { michael@0: error('Invalid WhitePoint components, no fallback available'); michael@0: } michael@0: michael@0: if (this.XB < 0 || this.YB < 0 || this.ZB < 0) { michael@0: info('Invalid BlackPoint, falling back to default'); michael@0: this.XB = this.YB = this.ZB = 0; michael@0: } michael@0: michael@0: if (this.amin > this.amax || this.bmin > this.bmax) { michael@0: info('Invalid Range, falling back to defaults'); michael@0: this.amin = -100; michael@0: this.amax = 100; michael@0: this.bmin = -100; michael@0: this.bmax = 100; michael@0: } michael@0: } michael@0: michael@0: // Function g(x) from spec michael@0: function fn_g(x) { michael@0: if (x >= 6 / 29) { michael@0: return x * x * x; michael@0: } else { michael@0: return (108 / 841) * (x - 4 / 29); michael@0: } michael@0: } michael@0: michael@0: function decode(value, high1, low2, high2) { michael@0: return low2 + (value) * (high2 - low2) / (high1); michael@0: } michael@0: michael@0: // If decoding is needed maxVal should be 2^bits per component - 1. michael@0: function convertToRgb(cs, src, srcOffset, maxVal, dest, destOffset) { michael@0: // XXX: Lab input is in the range of [0, 100], [amin, amax], [bmin, bmax] michael@0: // not the usual [0, 1]. If a command like setFillColor is used the src michael@0: // values will already be within the correct range. However, if we are michael@0: // converting an image we have to map the values to the correct range given michael@0: // above. michael@0: // Ls,as,bs <---> L*,a*,b* in the spec michael@0: var Ls = src[srcOffset]; michael@0: var as = src[srcOffset + 1]; michael@0: var bs = src[srcOffset + 2]; michael@0: if (maxVal !== false) { michael@0: Ls = decode(Ls, maxVal, 0, 100); michael@0: as = decode(as, maxVal, cs.amin, cs.amax); michael@0: bs = decode(bs, maxVal, cs.bmin, cs.bmax); michael@0: } michael@0: michael@0: // Adjust limits of 'as' and 'bs' michael@0: as = as > cs.amax ? cs.amax : as < cs.amin ? cs.amin : as; michael@0: bs = bs > cs.bmax ? cs.bmax : bs < cs.bmin ? cs.bmin : bs; michael@0: michael@0: // Computes intermediate variables X,Y,Z as per spec michael@0: var M = (Ls + 16) / 116; michael@0: var L = M + (as / 500); michael@0: var N = M - (bs / 200); michael@0: michael@0: var X = cs.XW * fn_g(L); michael@0: var Y = cs.YW * fn_g(M); michael@0: var Z = cs.ZW * fn_g(N); michael@0: michael@0: var r, g, b; michael@0: // Using different conversions for D50 and D65 white points, michael@0: // per http://www.color.org/srgb.pdf michael@0: if (cs.ZW < 1) { michael@0: // Assuming D50 (X=0.9642, Y=1.00, Z=0.8249) michael@0: r = X * 3.1339 + Y * -1.6170 + Z * -0.4906; michael@0: g = X * -0.9785 + Y * 1.9160 + Z * 0.0333; michael@0: b = X * 0.0720 + Y * -0.2290 + Z * 1.4057; michael@0: } else { michael@0: // Assuming D65 (X=0.9505, Y=1.00, Z=1.0888) michael@0: r = X * 3.2406 + Y * -1.5372 + Z * -0.4986; michael@0: g = X * -0.9689 + Y * 1.8758 + Z * 0.0415; michael@0: b = X * 0.0557 + Y * -0.2040 + Z * 1.0570; michael@0: } michael@0: // clamp color values to [0,1] range then convert to [0,255] range. michael@0: dest[destOffset] = r <= 0 ? 0 : r >= 1 ? 255 : Math.sqrt(r) * 255 | 0; michael@0: dest[destOffset + 1] = g <= 0 ? 0 : g >= 1 ? 255 : Math.sqrt(g) * 255 | 0; michael@0: dest[destOffset + 2] = b <= 0 ? 0 : b >= 1 ? 255 : Math.sqrt(b) * 255 | 0; michael@0: } michael@0: michael@0: LabCS.prototype = { michael@0: getRgb: ColorSpace.prototype.getRgb, michael@0: getRgbItem: function LabCS_getRgbItem(src, srcOffset, dest, destOffset) { michael@0: convertToRgb(this, src, srcOffset, false, dest, destOffset); michael@0: }, michael@0: getRgbBuffer: function LabCS_getRgbBuffer(src, srcOffset, count, michael@0: dest, destOffset, bits, michael@0: alpha01) { michael@0: var maxVal = (1 << bits) - 1; michael@0: for (var i = 0; i < count; i++) { michael@0: convertToRgb(this, src, srcOffset, maxVal, dest, destOffset); michael@0: srcOffset += 3; michael@0: destOffset += 3 + alpha01; michael@0: } michael@0: }, michael@0: getOutputLength: function LabCS_getOutputLength(inputLength, alpha01) { michael@0: return (inputLength * (3 + alpha01) / 3) | 0; michael@0: }, michael@0: isPassthrough: ColorSpace.prototype.isPassthrough, michael@0: isDefaultDecode: function LabCS_isDefaultDecode(decodeMap) { michael@0: // XXX: Decoding is handled with the lab conversion because of the strange michael@0: // ranges that are used. michael@0: return true; michael@0: }, michael@0: usesZeroToOneRange: false michael@0: }; michael@0: return LabCS; michael@0: })(); michael@0: michael@0: michael@0: michael@0: var PDFFunction = (function PDFFunctionClosure() { michael@0: var CONSTRUCT_SAMPLED = 0; michael@0: var CONSTRUCT_INTERPOLATED = 2; michael@0: var CONSTRUCT_STICHED = 3; michael@0: var CONSTRUCT_POSTSCRIPT = 4; michael@0: michael@0: return { michael@0: getSampleArray: function PDFFunction_getSampleArray(size, outputSize, bps, michael@0: str) { michael@0: var i, ii; michael@0: var length = 1; michael@0: for (i = 0, ii = size.length; i < ii; i++) { michael@0: length *= size[i]; michael@0: } michael@0: length *= outputSize; michael@0: michael@0: var array = []; michael@0: var codeSize = 0; michael@0: var codeBuf = 0; michael@0: // 32 is a valid bps so shifting won't work michael@0: var sampleMul = 1.0 / (Math.pow(2.0, bps) - 1); michael@0: michael@0: var strBytes = str.getBytes((length * bps + 7) / 8); michael@0: var strIdx = 0; michael@0: for (i = 0; i < length; i++) { michael@0: while (codeSize < bps) { michael@0: codeBuf <<= 8; michael@0: codeBuf |= strBytes[strIdx++]; michael@0: codeSize += 8; michael@0: } michael@0: codeSize -= bps; michael@0: array.push((codeBuf >> codeSize) * sampleMul); michael@0: codeBuf &= (1 << codeSize) - 1; michael@0: } michael@0: return array; michael@0: }, michael@0: michael@0: getIR: function PDFFunction_getIR(xref, fn) { michael@0: var dict = fn.dict; michael@0: if (!dict) { michael@0: dict = fn; michael@0: } michael@0: michael@0: var types = [this.constructSampled, michael@0: null, michael@0: this.constructInterpolated, michael@0: this.constructStiched, michael@0: this.constructPostScript]; michael@0: michael@0: var typeNum = dict.get('FunctionType'); michael@0: var typeFn = types[typeNum]; michael@0: if (!typeFn) { michael@0: error('Unknown type of function'); michael@0: } michael@0: michael@0: return typeFn.call(this, fn, dict, xref); michael@0: }, michael@0: michael@0: fromIR: function PDFFunction_fromIR(IR) { michael@0: var type = IR[0]; michael@0: switch (type) { michael@0: case CONSTRUCT_SAMPLED: michael@0: return this.constructSampledFromIR(IR); michael@0: case CONSTRUCT_INTERPOLATED: michael@0: return this.constructInterpolatedFromIR(IR); michael@0: case CONSTRUCT_STICHED: michael@0: return this.constructStichedFromIR(IR); michael@0: //case CONSTRUCT_POSTSCRIPT: michael@0: default: michael@0: return this.constructPostScriptFromIR(IR); michael@0: } michael@0: }, michael@0: michael@0: parse: function PDFFunction_parse(xref, fn) { michael@0: var IR = this.getIR(xref, fn); michael@0: return this.fromIR(IR); michael@0: }, michael@0: michael@0: constructSampled: function PDFFunction_constructSampled(str, dict) { michael@0: function toMultiArray(arr) { michael@0: var inputLength = arr.length; michael@0: var out = []; michael@0: var index = 0; michael@0: for (var i = 0; i < inputLength; i += 2) { michael@0: out[index] = [arr[i], arr[i + 1]]; michael@0: ++index; michael@0: } michael@0: return out; michael@0: } michael@0: var domain = dict.get('Domain'); michael@0: var range = dict.get('Range'); michael@0: michael@0: if (!domain || !range) { michael@0: error('No domain or range'); michael@0: } michael@0: michael@0: var inputSize = domain.length / 2; michael@0: var outputSize = range.length / 2; michael@0: michael@0: domain = toMultiArray(domain); michael@0: range = toMultiArray(range); michael@0: michael@0: var size = dict.get('Size'); michael@0: var bps = dict.get('BitsPerSample'); michael@0: var order = dict.get('Order') || 1; michael@0: if (order !== 1) { michael@0: // No description how cubic spline interpolation works in PDF32000:2008 michael@0: // As in poppler, ignoring order, linear interpolation may work as good michael@0: info('No support for cubic spline interpolation: ' + order); michael@0: } michael@0: michael@0: var encode = dict.get('Encode'); michael@0: if (!encode) { michael@0: encode = []; michael@0: for (var i = 0; i < inputSize; ++i) { michael@0: encode.push(0); michael@0: encode.push(size[i] - 1); michael@0: } michael@0: } michael@0: encode = toMultiArray(encode); michael@0: michael@0: var decode = dict.get('Decode'); michael@0: if (!decode) { michael@0: decode = range; michael@0: } else { michael@0: decode = toMultiArray(decode); michael@0: } michael@0: michael@0: var samples = this.getSampleArray(size, outputSize, bps, str); michael@0: michael@0: return [ michael@0: CONSTRUCT_SAMPLED, inputSize, domain, encode, decode, samples, size, michael@0: outputSize, Math.pow(2, bps) - 1, range michael@0: ]; michael@0: }, michael@0: michael@0: constructSampledFromIR: function PDFFunction_constructSampledFromIR(IR) { michael@0: // See chapter 3, page 109 of the PDF reference michael@0: function interpolate(x, xmin, xmax, ymin, ymax) { michael@0: return ymin + ((x - xmin) * ((ymax - ymin) / (xmax - xmin))); michael@0: } michael@0: michael@0: return function constructSampledFromIRResult(args) { michael@0: // See chapter 3, page 110 of the PDF reference. michael@0: var m = IR[1]; michael@0: var domain = IR[2]; michael@0: var encode = IR[3]; michael@0: var decode = IR[4]; michael@0: var samples = IR[5]; michael@0: var size = IR[6]; michael@0: var n = IR[7]; michael@0: //var mask = IR[8]; michael@0: var range = IR[9]; michael@0: michael@0: if (m != args.length) { michael@0: error('Incorrect number of arguments: ' + m + ' != ' + michael@0: args.length); michael@0: } michael@0: michael@0: var x = args; michael@0: michael@0: // Building the cube vertices: its part and sample index michael@0: // http://rjwagner49.com/Mathematics/Interpolation.pdf michael@0: var cubeVertices = 1 << m; michael@0: var cubeN = new Float64Array(cubeVertices); michael@0: var cubeVertex = new Uint32Array(cubeVertices); michael@0: var i, j; michael@0: for (j = 0; j < cubeVertices; j++) { michael@0: cubeN[j] = 1; michael@0: } michael@0: michael@0: var k = n, pos = 1; michael@0: // Map x_i to y_j for 0 <= i < m using the sampled function. michael@0: for (i = 0; i < m; ++i) { michael@0: // x_i' = min(max(x_i, Domain_2i), Domain_2i+1) michael@0: var domain_2i = domain[i][0]; michael@0: var domain_2i_1 = domain[i][1]; michael@0: var xi = Math.min(Math.max(x[i], domain_2i), domain_2i_1); michael@0: michael@0: // e_i = Interpolate(x_i', Domain_2i, Domain_2i+1, michael@0: // Encode_2i, Encode_2i+1) michael@0: var e = interpolate(xi, domain_2i, domain_2i_1, michael@0: encode[i][0], encode[i][1]); michael@0: michael@0: // e_i' = min(max(e_i, 0), Size_i - 1) michael@0: var size_i = size[i]; michael@0: e = Math.min(Math.max(e, 0), size_i - 1); michael@0: michael@0: // Adjusting the cube: N and vertex sample index michael@0: var e0 = e < size_i - 1 ? Math.floor(e) : e - 1; // e1 = e0 + 1; michael@0: var n0 = e0 + 1 - e; // (e1 - e) / (e1 - e0); michael@0: var n1 = e - e0; // (e - e0) / (e1 - e0); michael@0: var offset0 = e0 * k; michael@0: var offset1 = offset0 + k; // e1 * k michael@0: for (j = 0; j < cubeVertices; j++) { michael@0: if (j & pos) { michael@0: cubeN[j] *= n1; michael@0: cubeVertex[j] += offset1; michael@0: } else { michael@0: cubeN[j] *= n0; michael@0: cubeVertex[j] += offset0; michael@0: } michael@0: } michael@0: michael@0: k *= size_i; michael@0: pos <<= 1; michael@0: } michael@0: michael@0: var y = new Float64Array(n); michael@0: for (j = 0; j < n; ++j) { michael@0: // Sum all cube vertices' samples portions michael@0: var rj = 0; michael@0: for (i = 0; i < cubeVertices; i++) { michael@0: rj += samples[cubeVertex[i] + j] * cubeN[i]; michael@0: } michael@0: michael@0: // r_j' = Interpolate(r_j, 0, 2^BitsPerSample - 1, michael@0: // Decode_2j, Decode_2j+1) michael@0: rj = interpolate(rj, 0, 1, decode[j][0], decode[j][1]); michael@0: michael@0: // y_j = min(max(r_j, range_2j), range_2j+1) michael@0: y[j] = Math.min(Math.max(rj, range[j][0]), range[j][1]); michael@0: } michael@0: michael@0: return y; michael@0: }; michael@0: }, michael@0: michael@0: constructInterpolated: function PDFFunction_constructInterpolated(str, michael@0: dict) { michael@0: var c0 = dict.get('C0') || [0]; michael@0: var c1 = dict.get('C1') || [1]; michael@0: var n = dict.get('N'); michael@0: michael@0: if (!isArray(c0) || !isArray(c1)) { michael@0: error('Illegal dictionary for interpolated function'); michael@0: } michael@0: michael@0: var length = c0.length; michael@0: var diff = []; michael@0: for (var i = 0; i < length; ++i) { michael@0: diff.push(c1[i] - c0[i]); michael@0: } michael@0: michael@0: return [CONSTRUCT_INTERPOLATED, c0, diff, n]; michael@0: }, michael@0: michael@0: constructInterpolatedFromIR: michael@0: function PDFFunction_constructInterpolatedFromIR(IR) { michael@0: var c0 = IR[1]; michael@0: var diff = IR[2]; michael@0: var n = IR[3]; michael@0: michael@0: var length = diff.length; michael@0: michael@0: return function constructInterpolatedFromIRResult(args) { michael@0: var x = n == 1 ? args[0] : Math.pow(args[0], n); michael@0: michael@0: var out = []; michael@0: for (var j = 0; j < length; ++j) { michael@0: out.push(c0[j] + (x * diff[j])); michael@0: } michael@0: michael@0: return out; michael@0: michael@0: }; michael@0: }, michael@0: michael@0: constructStiched: function PDFFunction_constructStiched(fn, dict, xref) { michael@0: var domain = dict.get('Domain'); michael@0: michael@0: if (!domain) { michael@0: error('No domain'); michael@0: } michael@0: michael@0: var inputSize = domain.length / 2; michael@0: if (inputSize != 1) { michael@0: error('Bad domain for stiched function'); michael@0: } michael@0: michael@0: var fnRefs = dict.get('Functions'); michael@0: var fns = []; michael@0: for (var i = 0, ii = fnRefs.length; i < ii; ++i) { michael@0: fns.push(PDFFunction.getIR(xref, xref.fetchIfRef(fnRefs[i]))); michael@0: } michael@0: michael@0: var bounds = dict.get('Bounds'); michael@0: var encode = dict.get('Encode'); michael@0: michael@0: return [CONSTRUCT_STICHED, domain, bounds, encode, fns]; michael@0: }, michael@0: michael@0: constructStichedFromIR: function PDFFunction_constructStichedFromIR(IR) { michael@0: var domain = IR[1]; michael@0: var bounds = IR[2]; michael@0: var encode = IR[3]; michael@0: var fnsIR = IR[4]; michael@0: var fns = []; michael@0: michael@0: for (var i = 0, ii = fnsIR.length; i < ii; i++) { michael@0: fns.push(PDFFunction.fromIR(fnsIR[i])); michael@0: } michael@0: michael@0: return function constructStichedFromIRResult(args) { michael@0: var clip = function constructStichedFromIRClip(v, min, max) { michael@0: if (v > max) { michael@0: v = max; michael@0: } else if (v < min) { michael@0: v = min; michael@0: } michael@0: return v; michael@0: }; michael@0: michael@0: // clip to domain michael@0: var v = clip(args[0], domain[0], domain[1]); michael@0: // calulate which bound the value is in michael@0: for (var i = 0, ii = bounds.length; i < ii; ++i) { michael@0: if (v < bounds[i]) { michael@0: break; michael@0: } michael@0: } michael@0: michael@0: // encode value into domain of function michael@0: var dmin = domain[0]; michael@0: if (i > 0) { michael@0: dmin = bounds[i - 1]; michael@0: } michael@0: var dmax = domain[1]; michael@0: if (i < bounds.length) { michael@0: dmax = bounds[i]; michael@0: } michael@0: michael@0: var rmin = encode[2 * i]; michael@0: var rmax = encode[2 * i + 1]; michael@0: michael@0: var v2 = rmin + (v - dmin) * (rmax - rmin) / (dmax - dmin); michael@0: michael@0: // call the appropriate function michael@0: return fns[i]([v2]); michael@0: }; michael@0: }, michael@0: michael@0: constructPostScript: function PDFFunction_constructPostScript(fn, dict, michael@0: xref) { michael@0: var domain = dict.get('Domain'); michael@0: var range = dict.get('Range'); michael@0: michael@0: if (!domain) { michael@0: error('No domain.'); michael@0: } michael@0: michael@0: if (!range) { michael@0: error('No range.'); michael@0: } michael@0: michael@0: var lexer = new PostScriptLexer(fn); michael@0: var parser = new PostScriptParser(lexer); michael@0: var code = parser.parse(); michael@0: michael@0: return [CONSTRUCT_POSTSCRIPT, domain, range, code]; michael@0: }, michael@0: michael@0: constructPostScriptFromIR: function PDFFunction_constructPostScriptFromIR( michael@0: IR) { michael@0: var domain = IR[1]; michael@0: var range = IR[2]; michael@0: var code = IR[3]; michael@0: var numOutputs = range.length / 2; michael@0: var evaluator = new PostScriptEvaluator(code); michael@0: // Cache the values for a big speed up, the cache size is limited though michael@0: // since the number of possible values can be huge from a PS function. michael@0: var cache = new FunctionCache(); michael@0: return function constructPostScriptFromIRResult(args) { michael@0: var initialStack = []; michael@0: for (var i = 0, ii = (domain.length / 2); i < ii; ++i) { michael@0: initialStack.push(args[i]); michael@0: } michael@0: michael@0: var key = initialStack.join('_'); michael@0: if (cache.has(key)) { michael@0: return cache.get(key); michael@0: } michael@0: michael@0: var stack = evaluator.execute(initialStack); michael@0: var transformed = []; michael@0: for (i = numOutputs - 1; i >= 0; --i) { michael@0: var out = stack.pop(); michael@0: var rangeIndex = 2 * i; michael@0: if (out < range[rangeIndex]) { michael@0: out = range[rangeIndex]; michael@0: } else if (out > range[rangeIndex + 1]) { michael@0: out = range[rangeIndex + 1]; michael@0: } michael@0: transformed[i] = out; michael@0: } michael@0: cache.set(key, transformed); michael@0: return transformed; michael@0: }; michael@0: } michael@0: }; michael@0: })(); michael@0: michael@0: var FunctionCache = (function FunctionCacheClosure() { michael@0: // Of 10 PDF's with type4 functions the maxium number of distinct values seen michael@0: // was 256. This still may need some tweaking in the future though. michael@0: var MAX_CACHE_SIZE = 1024; michael@0: function FunctionCache() { michael@0: this.cache = {}; michael@0: this.total = 0; michael@0: } michael@0: FunctionCache.prototype = { michael@0: has: function FunctionCache_has(key) { michael@0: return key in this.cache; michael@0: }, michael@0: get: function FunctionCache_get(key) { michael@0: return this.cache[key]; michael@0: }, michael@0: set: function FunctionCache_set(key, value) { michael@0: if (this.total < MAX_CACHE_SIZE) { michael@0: this.cache[key] = value; michael@0: this.total++; michael@0: } michael@0: } michael@0: }; michael@0: return FunctionCache; michael@0: })(); michael@0: michael@0: var PostScriptStack = (function PostScriptStackClosure() { michael@0: var MAX_STACK_SIZE = 100; michael@0: function PostScriptStack(initialStack) { michael@0: this.stack = initialStack || []; michael@0: } michael@0: michael@0: PostScriptStack.prototype = { michael@0: push: function PostScriptStack_push(value) { michael@0: if (this.stack.length >= MAX_STACK_SIZE) { michael@0: error('PostScript function stack overflow.'); michael@0: } michael@0: this.stack.push(value); michael@0: }, michael@0: pop: function PostScriptStack_pop() { michael@0: if (this.stack.length <= 0) { michael@0: error('PostScript function stack underflow.'); michael@0: } michael@0: return this.stack.pop(); michael@0: }, michael@0: copy: function PostScriptStack_copy(n) { michael@0: if (this.stack.length + n >= MAX_STACK_SIZE) { michael@0: error('PostScript function stack overflow.'); michael@0: } michael@0: var stack = this.stack; michael@0: for (var i = stack.length - n, j = n - 1; j >= 0; j--, i++) { michael@0: stack.push(stack[i]); michael@0: } michael@0: }, michael@0: index: function PostScriptStack_index(n) { michael@0: this.push(this.stack[this.stack.length - n - 1]); michael@0: }, michael@0: // rotate the last n stack elements p times michael@0: roll: function PostScriptStack_roll(n, p) { michael@0: var stack = this.stack; michael@0: var l = stack.length - n; michael@0: var r = stack.length - 1, c = l + (p - Math.floor(p / n) * n), i, j, t; michael@0: for (i = l, j = r; i < j; i++, j--) { michael@0: t = stack[i]; stack[i] = stack[j]; stack[j] = t; michael@0: } michael@0: for (i = l, j = c - 1; i < j; i++, j--) { michael@0: t = stack[i]; stack[i] = stack[j]; stack[j] = t; michael@0: } michael@0: for (i = c, j = r; i < j; i++, j--) { michael@0: t = stack[i]; stack[i] = stack[j]; stack[j] = t; michael@0: } michael@0: } michael@0: }; michael@0: return PostScriptStack; michael@0: })(); michael@0: var PostScriptEvaluator = (function PostScriptEvaluatorClosure() { michael@0: function PostScriptEvaluator(operators) { michael@0: this.operators = operators; michael@0: } michael@0: PostScriptEvaluator.prototype = { michael@0: execute: function PostScriptEvaluator_execute(initialStack) { michael@0: var stack = new PostScriptStack(initialStack); michael@0: var counter = 0; michael@0: var operators = this.operators; michael@0: var length = operators.length; michael@0: var operator, a, b; michael@0: while (counter < length) { michael@0: operator = operators[counter++]; michael@0: if (typeof operator == 'number') { michael@0: // Operator is really an operand and should be pushed to the stack. michael@0: stack.push(operator); michael@0: continue; michael@0: } michael@0: switch (operator) { michael@0: // non standard ps operators michael@0: case 'jz': // jump if false michael@0: b = stack.pop(); michael@0: a = stack.pop(); michael@0: if (!a) { michael@0: counter = b; michael@0: } michael@0: break; michael@0: case 'j': // jump michael@0: a = stack.pop(); michael@0: counter = a; michael@0: break; michael@0: michael@0: // all ps operators in alphabetical order (excluding if/ifelse) michael@0: case 'abs': michael@0: a = stack.pop(); michael@0: stack.push(Math.abs(a)); michael@0: break; michael@0: case 'add': michael@0: b = stack.pop(); michael@0: a = stack.pop(); michael@0: stack.push(a + b); michael@0: break; michael@0: case 'and': michael@0: b = stack.pop(); michael@0: a = stack.pop(); michael@0: if (isBool(a) && isBool(b)) { michael@0: stack.push(a && b); michael@0: } else { michael@0: stack.push(a & b); michael@0: } michael@0: break; michael@0: case 'atan': michael@0: a = stack.pop(); michael@0: stack.push(Math.atan(a)); michael@0: break; michael@0: case 'bitshift': michael@0: b = stack.pop(); michael@0: a = stack.pop(); michael@0: if (a > 0) { michael@0: stack.push(a << b); michael@0: } else { michael@0: stack.push(a >> b); michael@0: } michael@0: break; michael@0: case 'ceiling': michael@0: a = stack.pop(); michael@0: stack.push(Math.ceil(a)); michael@0: break; michael@0: case 'copy': michael@0: a = stack.pop(); michael@0: stack.copy(a); michael@0: break; michael@0: case 'cos': michael@0: a = stack.pop(); michael@0: stack.push(Math.cos(a)); michael@0: break; michael@0: case 'cvi': michael@0: a = stack.pop() | 0; michael@0: stack.push(a); michael@0: break; michael@0: case 'cvr': michael@0: // noop michael@0: break; michael@0: case 'div': michael@0: b = stack.pop(); michael@0: a = stack.pop(); michael@0: stack.push(a / b); michael@0: break; michael@0: case 'dup': michael@0: stack.copy(1); michael@0: break; michael@0: case 'eq': michael@0: b = stack.pop(); michael@0: a = stack.pop(); michael@0: stack.push(a == b); michael@0: break; michael@0: case 'exch': michael@0: stack.roll(2, 1); michael@0: break; michael@0: case 'exp': michael@0: b = stack.pop(); michael@0: a = stack.pop(); michael@0: stack.push(Math.pow(a, b)); michael@0: break; michael@0: case 'false': michael@0: stack.push(false); michael@0: break; michael@0: case 'floor': michael@0: a = stack.pop(); michael@0: stack.push(Math.floor(a)); michael@0: break; michael@0: case 'ge': michael@0: b = stack.pop(); michael@0: a = stack.pop(); michael@0: stack.push(a >= b); michael@0: break; michael@0: case 'gt': michael@0: b = stack.pop(); michael@0: a = stack.pop(); michael@0: stack.push(a > b); michael@0: break; michael@0: case 'idiv': michael@0: b = stack.pop(); michael@0: a = stack.pop(); michael@0: stack.push((a / b) | 0); michael@0: break; michael@0: case 'index': michael@0: a = stack.pop(); michael@0: stack.index(a); michael@0: break; michael@0: case 'le': michael@0: b = stack.pop(); michael@0: a = stack.pop(); michael@0: stack.push(a <= b); michael@0: break; michael@0: case 'ln': michael@0: a = stack.pop(); michael@0: stack.push(Math.log(a)); michael@0: break; michael@0: case 'log': michael@0: a = stack.pop(); michael@0: stack.push(Math.log(a) / Math.LN10); michael@0: break; michael@0: case 'lt': michael@0: b = stack.pop(); michael@0: a = stack.pop(); michael@0: stack.push(a < b); michael@0: break; michael@0: case 'mod': michael@0: b = stack.pop(); michael@0: a = stack.pop(); michael@0: stack.push(a % b); michael@0: break; michael@0: case 'mul': michael@0: b = stack.pop(); michael@0: a = stack.pop(); michael@0: stack.push(a * b); michael@0: break; michael@0: case 'ne': michael@0: b = stack.pop(); michael@0: a = stack.pop(); michael@0: stack.push(a != b); michael@0: break; michael@0: case 'neg': michael@0: a = stack.pop(); michael@0: stack.push(-b); michael@0: break; michael@0: case 'not': michael@0: a = stack.pop(); michael@0: if (isBool(a) && isBool(b)) { michael@0: stack.push(a && b); michael@0: } else { michael@0: stack.push(a & b); michael@0: } michael@0: break; michael@0: case 'or': michael@0: b = stack.pop(); michael@0: a = stack.pop(); michael@0: if (isBool(a) && isBool(b)) { michael@0: stack.push(a || b); michael@0: } else { michael@0: stack.push(a | b); michael@0: } michael@0: break; michael@0: case 'pop': michael@0: stack.pop(); michael@0: break; michael@0: case 'roll': michael@0: b = stack.pop(); michael@0: a = stack.pop(); michael@0: stack.roll(a, b); michael@0: break; michael@0: case 'round': michael@0: a = stack.pop(); michael@0: stack.push(Math.round(a)); michael@0: break; michael@0: case 'sin': michael@0: a = stack.pop(); michael@0: stack.push(Math.sin(a)); michael@0: break; michael@0: case 'sqrt': michael@0: a = stack.pop(); michael@0: stack.push(Math.sqrt(a)); michael@0: break; michael@0: case 'sub': michael@0: b = stack.pop(); michael@0: a = stack.pop(); michael@0: stack.push(a - b); michael@0: break; michael@0: case 'true': michael@0: stack.push(true); michael@0: break; michael@0: case 'truncate': michael@0: a = stack.pop(); michael@0: a = a < 0 ? Math.ceil(a) : Math.floor(a); michael@0: stack.push(a); michael@0: break; michael@0: case 'xor': michael@0: b = stack.pop(); michael@0: a = stack.pop(); michael@0: if (isBool(a) && isBool(b)) { michael@0: stack.push(a != b); michael@0: } else { michael@0: stack.push(a ^ b); michael@0: } michael@0: break; michael@0: default: michael@0: error('Unknown operator ' + operator); michael@0: break; michael@0: } michael@0: } michael@0: return stack.stack; michael@0: } michael@0: }; michael@0: return PostScriptEvaluator; michael@0: })(); michael@0: michael@0: michael@0: var HIGHLIGHT_OFFSET = 4; // px michael@0: var SUPPORTED_TYPES = ['Link', 'Text', 'Widget']; michael@0: michael@0: var Annotation = (function AnnotationClosure() { michael@0: // 12.5.5: Algorithm: Appearance streams michael@0: function getTransformMatrix(rect, bbox, matrix) { michael@0: var bounds = Util.getAxialAlignedBoundingBox(bbox, matrix); michael@0: var minX = bounds[0]; michael@0: var minY = bounds[1]; michael@0: var maxX = bounds[2]; michael@0: var maxY = bounds[3]; michael@0: michael@0: if (minX === maxX || minY === maxY) { michael@0: // From real-life file, bbox was [0, 0, 0, 0]. In this case, michael@0: // just apply the transform for rect michael@0: return [1, 0, 0, 1, rect[0], rect[1]]; michael@0: } michael@0: michael@0: var xRatio = (rect[2] - rect[0]) / (maxX - minX); michael@0: var yRatio = (rect[3] - rect[1]) / (maxY - minY); michael@0: return [ michael@0: xRatio, michael@0: 0, michael@0: 0, michael@0: yRatio, michael@0: rect[0] - minX * xRatio, michael@0: rect[1] - minY * yRatio michael@0: ]; michael@0: } michael@0: michael@0: function getDefaultAppearance(dict) { michael@0: var appearanceState = dict.get('AP'); michael@0: if (!isDict(appearanceState)) { michael@0: return; michael@0: } michael@0: michael@0: var appearance; michael@0: var appearances = appearanceState.get('N'); michael@0: if (isDict(appearances)) { michael@0: var as = dict.get('AS'); michael@0: if (as && appearances.has(as.name)) { michael@0: appearance = appearances.get(as.name); michael@0: } michael@0: } else { michael@0: appearance = appearances; michael@0: } michael@0: return appearance; michael@0: } michael@0: michael@0: function Annotation(params) { michael@0: if (params.data) { michael@0: this.data = params.data; michael@0: return; michael@0: } michael@0: michael@0: var dict = params.dict; michael@0: var data = this.data = {}; michael@0: michael@0: data.subtype = dict.get('Subtype').name; michael@0: var rect = dict.get('Rect') || [0, 0, 0, 0]; michael@0: data.rect = Util.normalizeRect(rect); michael@0: data.annotationFlags = dict.get('F'); michael@0: michael@0: var color = dict.get('C'); michael@0: if (isArray(color) && color.length === 3) { michael@0: // TODO(mack): currently only supporting rgb; need support different michael@0: // colorspaces michael@0: data.color = color; michael@0: } else { michael@0: data.color = [0, 0, 0]; michael@0: } michael@0: michael@0: // Some types of annotations have border style dict which has more michael@0: // info than the border array michael@0: if (dict.has('BS')) { michael@0: var borderStyle = dict.get('BS'); michael@0: data.borderWidth = borderStyle.has('W') ? borderStyle.get('W') : 1; michael@0: } else { michael@0: var borderArray = dict.get('Border') || [0, 0, 1]; michael@0: data.borderWidth = borderArray[2] || 0; michael@0: michael@0: // TODO: implement proper support for annotations with line dash patterns. michael@0: var dashArray = borderArray[3]; michael@0: if (data.borderWidth > 0 && dashArray && isArray(dashArray)) { michael@0: var dashArrayLength = dashArray.length; michael@0: if (dashArrayLength > 0) { michael@0: // According to the PDF specification: the elements in a dashArray michael@0: // shall be numbers that are nonnegative and not all equal to zero. michael@0: var isInvalid = false; michael@0: var numPositive = 0; michael@0: for (var i = 0; i < dashArrayLength; i++) { michael@0: var validNumber = (+dashArray[i] >= 0); michael@0: if (!validNumber) { michael@0: isInvalid = true; michael@0: break; michael@0: } else if (dashArray[i] > 0) { michael@0: numPositive++; michael@0: } michael@0: } michael@0: if (isInvalid || numPositive === 0) { michael@0: data.borderWidth = 0; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: this.appearance = getDefaultAppearance(dict); michael@0: data.hasAppearance = !!this.appearance; michael@0: data.id = params.ref.num; michael@0: } michael@0: michael@0: Annotation.prototype = { michael@0: michael@0: getData: function Annotation_getData() { michael@0: return this.data; michael@0: }, michael@0: michael@0: hasHtml: function Annotation_hasHtml() { michael@0: return false; michael@0: }, michael@0: michael@0: getHtmlElement: function Annotation_getHtmlElement(commonObjs) { michael@0: throw new NotImplementedException( michael@0: 'getHtmlElement() should be implemented in subclass'); michael@0: }, michael@0: michael@0: // TODO(mack): Remove this, it's not really that helpful. michael@0: getEmptyContainer: function Annotation_getEmptyContainer(tagName, rect, michael@0: borderWidth) { michael@0: assert(!isWorker, michael@0: 'getEmptyContainer() should be called from main thread'); michael@0: michael@0: var bWidth = borderWidth || 0; michael@0: michael@0: rect = rect || this.data.rect; michael@0: var element = document.createElement(tagName); michael@0: element.style.borderWidth = bWidth + 'px'; michael@0: var width = rect[2] - rect[0] - 2 * bWidth; michael@0: var height = rect[3] - rect[1] - 2 * bWidth; michael@0: element.style.width = width + 'px'; michael@0: element.style.height = height + 'px'; michael@0: return element; michael@0: }, michael@0: michael@0: isInvisible: function Annotation_isInvisible() { michael@0: var data = this.data; michael@0: if (data && SUPPORTED_TYPES.indexOf(data.subtype) !== -1) { michael@0: return false; michael@0: } else { michael@0: return !!(data && michael@0: data.annotationFlags && // Default: not invisible michael@0: data.annotationFlags & 0x1); // Invisible michael@0: } michael@0: }, michael@0: michael@0: isViewable: function Annotation_isViewable() { michael@0: var data = this.data; michael@0: return !!(!this.isInvisible() && michael@0: data && michael@0: (!data.annotationFlags || michael@0: !(data.annotationFlags & 0x22)) && // Hidden or NoView michael@0: data.rect); // rectangle is nessessary michael@0: }, michael@0: michael@0: isPrintable: function Annotation_isPrintable() { michael@0: var data = this.data; michael@0: return !!(!this.isInvisible() && michael@0: data && michael@0: data.annotationFlags && // Default: not printable michael@0: data.annotationFlags & 0x4 && // Print michael@0: data.rect); // rectangle is nessessary michael@0: }, michael@0: michael@0: loadResources: function(keys) { michael@0: var promise = new LegacyPromise(); michael@0: this.appearance.dict.getAsync('Resources').then(function(resources) { michael@0: if (!resources) { michael@0: promise.resolve(); michael@0: return; michael@0: } michael@0: var objectLoader = new ObjectLoader(resources.map, michael@0: keys, michael@0: resources.xref); michael@0: objectLoader.load().then(function() { michael@0: promise.resolve(resources); michael@0: }); michael@0: }.bind(this)); michael@0: michael@0: return promise; michael@0: }, michael@0: michael@0: getOperatorList: function Annotation_getOperatorList(evaluator) { michael@0: michael@0: var promise = new LegacyPromise(); michael@0: michael@0: if (!this.appearance) { michael@0: promise.resolve(new OperatorList()); michael@0: return promise; michael@0: } michael@0: michael@0: var data = this.data; michael@0: michael@0: var appearanceDict = this.appearance.dict; michael@0: var resourcesPromise = this.loadResources([ michael@0: 'ExtGState', michael@0: 'ColorSpace', michael@0: 'Pattern', michael@0: 'Shading', michael@0: 'XObject', michael@0: 'Font' michael@0: // ProcSet michael@0: // Properties michael@0: ]); michael@0: var bbox = appearanceDict.get('BBox') || [0, 0, 1, 1]; michael@0: var matrix = appearanceDict.get('Matrix') || [1, 0, 0, 1, 0 ,0]; michael@0: var transform = getTransformMatrix(data.rect, bbox, matrix); michael@0: michael@0: resourcesPromise.then(function(resources) { michael@0: var opList = new OperatorList(); michael@0: opList.addOp(OPS.beginAnnotation, [data.rect, transform, matrix]); michael@0: evaluator.getOperatorList(this.appearance, resources, opList); michael@0: opList.addOp(OPS.endAnnotation, []); michael@0: promise.resolve(opList); michael@0: michael@0: this.appearance.reset(); michael@0: }.bind(this)); michael@0: michael@0: return promise; michael@0: } michael@0: }; michael@0: michael@0: Annotation.getConstructor = michael@0: function Annotation_getConstructor(subtype, fieldType) { michael@0: michael@0: if (!subtype) { michael@0: return; michael@0: } michael@0: michael@0: // TODO(mack): Implement FreeText annotations michael@0: if (subtype === 'Link') { michael@0: return LinkAnnotation; michael@0: } else if (subtype === 'Text') { michael@0: return TextAnnotation; michael@0: } else if (subtype === 'Widget') { michael@0: if (!fieldType) { michael@0: return; michael@0: } michael@0: michael@0: if (fieldType === 'Tx') { michael@0: return TextWidgetAnnotation; michael@0: } else { michael@0: return WidgetAnnotation; michael@0: } michael@0: } else { michael@0: return Annotation; michael@0: } michael@0: }; michael@0: michael@0: // TODO(mack): Support loading annotation from data michael@0: Annotation.fromData = function Annotation_fromData(data) { michael@0: var subtype = data.subtype; michael@0: var fieldType = data.fieldType; michael@0: var Constructor = Annotation.getConstructor(subtype, fieldType); michael@0: if (Constructor) { michael@0: return new Constructor({ data: data }); michael@0: } michael@0: }; michael@0: michael@0: Annotation.fromRef = function Annotation_fromRef(xref, ref) { michael@0: michael@0: var dict = xref.fetchIfRef(ref); michael@0: if (!isDict(dict)) { michael@0: return; michael@0: } michael@0: michael@0: var subtype = dict.get('Subtype'); michael@0: subtype = isName(subtype) ? subtype.name : ''; michael@0: if (!subtype) { michael@0: return; michael@0: } michael@0: michael@0: var fieldType = Util.getInheritableProperty(dict, 'FT'); michael@0: fieldType = isName(fieldType) ? fieldType.name : ''; michael@0: michael@0: var Constructor = Annotation.getConstructor(subtype, fieldType); michael@0: if (!Constructor) { michael@0: return; michael@0: } michael@0: michael@0: var params = { michael@0: dict: dict, michael@0: ref: ref, michael@0: }; michael@0: michael@0: var annotation = new Constructor(params); michael@0: michael@0: if (annotation.isViewable() || annotation.isPrintable()) { michael@0: return annotation; michael@0: } else { michael@0: warn('unimplemented annotation type: ' + subtype); michael@0: } michael@0: }; michael@0: michael@0: Annotation.appendToOperatorList = function Annotation_appendToOperatorList( michael@0: annotations, opList, pdfManager, partialEvaluator, intent) { michael@0: michael@0: function reject(e) { michael@0: annotationsReadyPromise.reject(e); michael@0: } michael@0: michael@0: var annotationsReadyPromise = new LegacyPromise(); michael@0: michael@0: var annotationPromises = []; michael@0: for (var i = 0, n = annotations.length; i < n; ++i) { michael@0: if (intent === 'display' && annotations[i].isViewable() || michael@0: intent === 'print' && annotations[i].isPrintable()) { michael@0: annotationPromises.push( michael@0: annotations[i].getOperatorList(partialEvaluator)); michael@0: } michael@0: } michael@0: Promise.all(annotationPromises).then(function(datas) { michael@0: opList.addOp(OPS.beginAnnotations, []); michael@0: for (var i = 0, n = datas.length; i < n; ++i) { michael@0: var annotOpList = datas[i]; michael@0: opList.addOpList(annotOpList); michael@0: } michael@0: opList.addOp(OPS.endAnnotations, []); michael@0: annotationsReadyPromise.resolve(); michael@0: }, reject); michael@0: michael@0: return annotationsReadyPromise; michael@0: }; michael@0: michael@0: return Annotation; michael@0: })(); michael@0: PDFJS.Annotation = Annotation; michael@0: michael@0: michael@0: var WidgetAnnotation = (function WidgetAnnotationClosure() { michael@0: michael@0: function WidgetAnnotation(params) { michael@0: Annotation.call(this, params); michael@0: michael@0: if (params.data) { michael@0: return; michael@0: } michael@0: michael@0: var dict = params.dict; michael@0: var data = this.data; michael@0: michael@0: data.fieldValue = stringToPDFString( michael@0: Util.getInheritableProperty(dict, 'V') || ''); michael@0: data.alternativeText = stringToPDFString(dict.get('TU') || ''); michael@0: data.defaultAppearance = Util.getInheritableProperty(dict, 'DA') || ''; michael@0: var fieldType = Util.getInheritableProperty(dict, 'FT'); michael@0: data.fieldType = isName(fieldType) ? fieldType.name : ''; michael@0: data.fieldFlags = Util.getInheritableProperty(dict, 'Ff') || 0; michael@0: this.fieldResources = Util.getInheritableProperty(dict, 'DR') || Dict.empty; michael@0: michael@0: // Building the full field name by collecting the field and michael@0: // its ancestors 'T' data and joining them using '.'. michael@0: var fieldName = []; michael@0: var namedItem = dict; michael@0: var ref = params.ref; michael@0: while (namedItem) { michael@0: var parent = namedItem.get('Parent'); michael@0: var parentRef = namedItem.getRaw('Parent'); michael@0: var name = namedItem.get('T'); michael@0: if (name) { michael@0: fieldName.unshift(stringToPDFString(name)); michael@0: } else { michael@0: // The field name is absent, that means more than one field michael@0: // with the same name may exist. Replacing the empty name michael@0: // with the '`' plus index in the parent's 'Kids' array. michael@0: // This is not in the PDF spec but necessary to id the michael@0: // the input controls. michael@0: var kids = parent.get('Kids'); michael@0: var j, jj; michael@0: for (j = 0, jj = kids.length; j < jj; j++) { michael@0: var kidRef = kids[j]; michael@0: if (kidRef.num == ref.num && kidRef.gen == ref.gen) { michael@0: break; michael@0: } michael@0: } michael@0: fieldName.unshift('`' + j); michael@0: } michael@0: namedItem = parent; michael@0: ref = parentRef; michael@0: } michael@0: data.fullName = fieldName.join('.'); michael@0: } michael@0: michael@0: var parent = Annotation.prototype; michael@0: Util.inherit(WidgetAnnotation, Annotation, { michael@0: isViewable: function WidgetAnnotation_isViewable() { michael@0: if (this.data.fieldType === 'Sig') { michael@0: warn('unimplemented annotation type: Widget signature'); michael@0: return false; michael@0: } michael@0: michael@0: return parent.isViewable.call(this); michael@0: } michael@0: }); michael@0: michael@0: return WidgetAnnotation; michael@0: })(); michael@0: michael@0: var TextWidgetAnnotation = (function TextWidgetAnnotationClosure() { michael@0: function TextWidgetAnnotation(params) { michael@0: WidgetAnnotation.call(this, params); michael@0: michael@0: if (params.data) { michael@0: return; michael@0: } michael@0: michael@0: this.data.textAlignment = Util.getInheritableProperty(params.dict, 'Q'); michael@0: } michael@0: michael@0: // TODO(mack): This dupes some of the logic in CanvasGraphics.setFont() michael@0: function setTextStyles(element, item, fontObj) { michael@0: michael@0: var style = element.style; michael@0: style.fontSize = item.fontSize + 'px'; michael@0: style.direction = item.fontDirection < 0 ? 'rtl': 'ltr'; michael@0: michael@0: if (!fontObj) { michael@0: return; michael@0: } michael@0: michael@0: style.fontWeight = fontObj.black ? michael@0: (fontObj.bold ? 'bolder' : 'bold') : michael@0: (fontObj.bold ? 'bold' : 'normal'); michael@0: style.fontStyle = fontObj.italic ? 'italic' : 'normal'; michael@0: michael@0: var fontName = fontObj.loadedName; michael@0: var fontFamily = fontName ? '"' + fontName + '", ' : ''; michael@0: // Use a reasonable default font if the font doesn't specify a fallback michael@0: var fallbackName = fontObj.fallbackName || 'Helvetica, sans-serif'; michael@0: style.fontFamily = fontFamily + fallbackName; michael@0: } michael@0: michael@0: michael@0: Util.inherit(TextWidgetAnnotation, WidgetAnnotation, { michael@0: hasHtml: function TextWidgetAnnotation_hasHtml() { michael@0: return !this.data.hasAppearance && !!this.data.fieldValue; michael@0: }, michael@0: michael@0: getHtmlElement: function TextWidgetAnnotation_getHtmlElement(commonObjs) { michael@0: assert(!isWorker, 'getHtmlElement() shall be called from main thread'); michael@0: michael@0: var item = this.data; michael@0: michael@0: var element = this.getEmptyContainer('div'); michael@0: element.style.display = 'table'; michael@0: michael@0: var content = document.createElement('div'); michael@0: content.textContent = item.fieldValue; michael@0: var textAlignment = item.textAlignment; michael@0: content.style.textAlign = ['left', 'center', 'right'][textAlignment]; michael@0: content.style.verticalAlign = 'middle'; michael@0: content.style.display = 'table-cell'; michael@0: michael@0: var fontObj = item.fontRefName ? michael@0: commonObjs.getData(item.fontRefName) : null; michael@0: setTextStyles(content, item, fontObj); michael@0: michael@0: element.appendChild(content); michael@0: michael@0: return element; michael@0: }, michael@0: michael@0: getOperatorList: function TextWidgetAnnotation_getOperatorList(evaluator) { michael@0: if (this.appearance) { michael@0: return Annotation.prototype.getOperatorList.call(this, evaluator); michael@0: } michael@0: michael@0: var promise = new LegacyPromise(); michael@0: var opList = new OperatorList(); michael@0: var data = this.data; michael@0: michael@0: // Even if there is an appearance stream, ignore it. This is the michael@0: // behaviour used by Adobe Reader. michael@0: michael@0: var defaultAppearance = data.defaultAppearance; michael@0: if (!defaultAppearance) { michael@0: promise.resolve(opList); michael@0: return promise; michael@0: } michael@0: michael@0: // Include any font resources found in the default appearance michael@0: michael@0: var stream = new Stream(stringToBytes(defaultAppearance)); michael@0: evaluator.getOperatorList(stream, this.fieldResources, opList); michael@0: var appearanceFnArray = opList.fnArray; michael@0: var appearanceArgsArray = opList.argsArray; michael@0: var fnArray = []; michael@0: michael@0: // TODO(mack): Add support for stroke color michael@0: data.rgb = [0, 0, 0]; michael@0: // TODO THIS DOESN'T MAKE ANY SENSE SINCE THE fnArray IS EMPTY! michael@0: for (var i = 0, n = fnArray.length; i < n; ++i) { michael@0: var fnId = appearanceFnArray[i]; michael@0: var args = appearanceArgsArray[i]; michael@0: michael@0: if (fnId === OPS.setFont) { michael@0: data.fontRefName = args[0]; michael@0: var size = args[1]; michael@0: if (size < 0) { michael@0: data.fontDirection = -1; michael@0: data.fontSize = -size; michael@0: } else { michael@0: data.fontDirection = 1; michael@0: data.fontSize = size; michael@0: } michael@0: } else if (fnId === OPS.setFillRGBColor) { michael@0: data.rgb = args; michael@0: } else if (fnId === OPS.setFillGray) { michael@0: var rgbValue = args[0] * 255; michael@0: data.rgb = [rgbValue, rgbValue, rgbValue]; michael@0: } michael@0: } michael@0: promise.resolve(opList); michael@0: return promise; michael@0: } michael@0: }); michael@0: michael@0: return TextWidgetAnnotation; michael@0: })(); michael@0: michael@0: var InteractiveAnnotation = (function InteractiveAnnotationClosure() { michael@0: function InteractiveAnnotation(params) { michael@0: Annotation.call(this, params); michael@0: } michael@0: michael@0: Util.inherit(InteractiveAnnotation, Annotation, { michael@0: hasHtml: function InteractiveAnnotation_hasHtml() { michael@0: return true; michael@0: }, michael@0: michael@0: highlight: function InteractiveAnnotation_highlight() { michael@0: if (this.highlightElement && michael@0: this.highlightElement.hasAttribute('hidden')) { michael@0: this.highlightElement.removeAttribute('hidden'); michael@0: } michael@0: }, michael@0: michael@0: unhighlight: function InteractiveAnnotation_unhighlight() { michael@0: if (this.highlightElement && michael@0: !this.highlightElement.hasAttribute('hidden')) { michael@0: this.highlightElement.setAttribute('hidden', true); michael@0: } michael@0: }, michael@0: michael@0: initContainer: function InteractiveAnnotation_initContainer() { michael@0: michael@0: var item = this.data; michael@0: var rect = item.rect; michael@0: michael@0: var container = this.getEmptyContainer('section', rect, item.borderWidth); michael@0: container.style.backgroundColor = item.color; michael@0: michael@0: var color = item.color; michael@0: var rgb = []; michael@0: for (var i = 0; i < 3; ++i) { michael@0: rgb[i] = Math.round(color[i] * 255); michael@0: } michael@0: item.colorCssRgb = Util.makeCssRgb(rgb); michael@0: michael@0: var highlight = document.createElement('div'); michael@0: highlight.className = 'annotationHighlight'; michael@0: highlight.style.left = highlight.style.top = -HIGHLIGHT_OFFSET + 'px'; michael@0: highlight.style.right = highlight.style.bottom = -HIGHLIGHT_OFFSET + 'px'; michael@0: highlight.setAttribute('hidden', true); michael@0: michael@0: this.highlightElement = highlight; michael@0: container.appendChild(this.highlightElement); michael@0: michael@0: return container; michael@0: } michael@0: }); michael@0: michael@0: return InteractiveAnnotation; michael@0: })(); michael@0: michael@0: var TextAnnotation = (function TextAnnotationClosure() { michael@0: function TextAnnotation(params) { michael@0: InteractiveAnnotation.call(this, params); michael@0: michael@0: if (params.data) { michael@0: return; michael@0: } michael@0: michael@0: var dict = params.dict; michael@0: var data = this.data; michael@0: michael@0: var content = dict.get('Contents'); michael@0: var title = dict.get('T'); michael@0: data.content = stringToPDFString(content || ''); michael@0: data.title = stringToPDFString(title || ''); michael@0: michael@0: if (data.hasAppearance) { michael@0: data.name = 'NoIcon'; michael@0: } else { michael@0: data.name = dict.has('Name') ? dict.get('Name').name : 'Note'; michael@0: } michael@0: michael@0: if (dict.has('C')) { michael@0: data.hasBgColor = true; michael@0: } michael@0: } michael@0: michael@0: var ANNOT_MIN_SIZE = 10; michael@0: michael@0: Util.inherit(TextAnnotation, InteractiveAnnotation, { michael@0: michael@0: getHtmlElement: function TextAnnotation_getHtmlElement(commonObjs) { michael@0: assert(!isWorker, 'getHtmlElement() shall be called from main thread'); michael@0: michael@0: var item = this.data; michael@0: var rect = item.rect; michael@0: michael@0: // sanity check because of OOo-generated PDFs michael@0: if ((rect[3] - rect[1]) < ANNOT_MIN_SIZE) { michael@0: rect[3] = rect[1] + ANNOT_MIN_SIZE; michael@0: } michael@0: if ((rect[2] - rect[0]) < ANNOT_MIN_SIZE) { michael@0: rect[2] = rect[0] + (rect[3] - rect[1]); // make it square michael@0: } michael@0: michael@0: var container = this.initContainer(); michael@0: container.className = 'annotText'; michael@0: michael@0: var image = document.createElement('img'); michael@0: image.style.height = container.style.height; michael@0: image.style.width = container.style.width; michael@0: var iconName = item.name; michael@0: image.src = PDFJS.imageResourcesPath + 'annotation-' + michael@0: iconName.toLowerCase() + '.svg'; michael@0: image.alt = '[{{type}} Annotation]'; michael@0: image.dataset.l10nId = 'text_annotation_type'; michael@0: image.dataset.l10nArgs = JSON.stringify({type: iconName}); michael@0: michael@0: var contentWrapper = document.createElement('div'); michael@0: contentWrapper.className = 'annotTextContentWrapper'; michael@0: contentWrapper.style.left = Math.floor(rect[2] - rect[0] + 5) + 'px'; michael@0: contentWrapper.style.top = '-10px'; michael@0: michael@0: var content = document.createElement('div'); michael@0: content.className = 'annotTextContent'; michael@0: content.setAttribute('hidden', true); michael@0: michael@0: var i, ii; michael@0: if (item.hasBgColor) { michael@0: var color = item.color; michael@0: var rgb = []; michael@0: for (i = 0; i < 3; ++i) { michael@0: // Enlighten the color (70%) michael@0: var c = Math.round(color[i] * 255); michael@0: rgb[i] = Math.round((255 - c) * 0.7) + c; michael@0: } michael@0: content.style.backgroundColor = Util.makeCssRgb(rgb); michael@0: } michael@0: michael@0: var title = document.createElement('h1'); michael@0: var text = document.createElement('p'); michael@0: title.textContent = item.title; michael@0: michael@0: if (!item.content && !item.title) { michael@0: content.setAttribute('hidden', true); michael@0: } else { michael@0: var e = document.createElement('span'); michael@0: var lines = item.content.split(/(?:\r\n?|\n)/); michael@0: for (i = 0, ii = lines.length; i < ii; ++i) { michael@0: var line = lines[i]; michael@0: e.appendChild(document.createTextNode(line)); michael@0: if (i < (ii - 1)) { michael@0: e.appendChild(document.createElement('br')); michael@0: } michael@0: } michael@0: text.appendChild(e); michael@0: michael@0: var pinned = false; michael@0: michael@0: var showAnnotation = function showAnnotation(pin) { michael@0: if (pin) { michael@0: pinned = true; michael@0: } michael@0: if (content.hasAttribute('hidden')) { michael@0: container.style.zIndex += 1; michael@0: content.removeAttribute('hidden'); michael@0: } michael@0: }; michael@0: michael@0: var hideAnnotation = function hideAnnotation(unpin) { michael@0: if (unpin) { michael@0: pinned = false; michael@0: } michael@0: if (!content.hasAttribute('hidden') && !pinned) { michael@0: container.style.zIndex -= 1; michael@0: content.setAttribute('hidden', true); michael@0: } michael@0: }; michael@0: michael@0: var toggleAnnotation = function toggleAnnotation() { michael@0: if (pinned) { michael@0: hideAnnotation(true); michael@0: } else { michael@0: showAnnotation(true); michael@0: } michael@0: }; michael@0: michael@0: image.addEventListener('click', function image_clickHandler() { michael@0: toggleAnnotation(); michael@0: }, false); michael@0: image.addEventListener('mouseover', function image_mouseOverHandler() { michael@0: showAnnotation(); michael@0: }, false); michael@0: image.addEventListener('mouseout', function image_mouseOutHandler() { michael@0: hideAnnotation(); michael@0: }, false); michael@0: michael@0: content.addEventListener('click', function content_clickHandler() { michael@0: hideAnnotation(true); michael@0: }, false); michael@0: } michael@0: michael@0: content.appendChild(title); michael@0: content.appendChild(text); michael@0: contentWrapper.appendChild(content); michael@0: container.appendChild(image); michael@0: container.appendChild(contentWrapper); michael@0: michael@0: return container; michael@0: } michael@0: }); michael@0: michael@0: return TextAnnotation; michael@0: })(); michael@0: michael@0: var LinkAnnotation = (function LinkAnnotationClosure() { michael@0: function LinkAnnotation(params) { michael@0: InteractiveAnnotation.call(this, params); michael@0: michael@0: if (params.data) { michael@0: return; michael@0: } michael@0: michael@0: var dict = params.dict; michael@0: var data = this.data; michael@0: michael@0: var action = dict.get('A'); michael@0: if (action) { michael@0: var linkType = action.get('S').name; michael@0: if (linkType === 'URI') { michael@0: var url = action.get('URI'); michael@0: if (isName(url)) { michael@0: // Some bad PDFs do not put parentheses around relative URLs. michael@0: url = '/' + url.name; michael@0: } else if (url) { michael@0: url = addDefaultProtocolToUrl(url); michael@0: } michael@0: // TODO: pdf spec mentions urls can be relative to a Base michael@0: // entry in the dictionary. michael@0: if (!isValidUrl(url, false)) { michael@0: url = ''; michael@0: } michael@0: data.url = url; michael@0: } else if (linkType === 'GoTo') { michael@0: data.dest = action.get('D'); michael@0: } else if (linkType === 'GoToR') { michael@0: var urlDict = action.get('F'); michael@0: if (isDict(urlDict)) { michael@0: // We assume that the 'url' is a Filspec dictionary michael@0: // and fetch the url without checking any further michael@0: url = urlDict.get('F') || ''; michael@0: } michael@0: michael@0: // TODO: pdf reference says that GoToR michael@0: // can also have 'NewWindow' attribute michael@0: if (!isValidUrl(url, false)) { michael@0: url = ''; michael@0: } michael@0: data.url = url; michael@0: data.dest = action.get('D'); michael@0: } else if (linkType === 'Named') { michael@0: data.action = action.get('N').name; michael@0: } else { michael@0: warn('unrecognized link type: ' + linkType); michael@0: } michael@0: } else if (dict.has('Dest')) { michael@0: // simple destination link michael@0: var dest = dict.get('Dest'); michael@0: data.dest = isName(dest) ? dest.name : dest; michael@0: } michael@0: } michael@0: michael@0: // Lets URLs beginning with 'www.' default to using the 'http://' protocol. michael@0: function addDefaultProtocolToUrl(url) { michael@0: if (url && url.indexOf('www.') === 0) { michael@0: return ('http://' + url); michael@0: } michael@0: return url; michael@0: } michael@0: michael@0: Util.inherit(LinkAnnotation, InteractiveAnnotation, { michael@0: hasOperatorList: function LinkAnnotation_hasOperatorList() { michael@0: return false; michael@0: }, michael@0: michael@0: getHtmlElement: function LinkAnnotation_getHtmlElement(commonObjs) { michael@0: michael@0: var container = this.initContainer(); michael@0: container.className = 'annotLink'; michael@0: michael@0: var item = this.data; michael@0: michael@0: container.style.borderColor = item.colorCssRgb; michael@0: container.style.borderStyle = 'solid'; michael@0: michael@0: var link = document.createElement('a'); michael@0: link.href = link.title = this.data.url || ''; michael@0: michael@0: container.appendChild(link); michael@0: michael@0: return container; michael@0: } michael@0: }); michael@0: michael@0: return LinkAnnotation; michael@0: })(); michael@0: michael@0: michael@0: var ChunkedStream = (function ChunkedStreamClosure() { michael@0: function ChunkedStream(length, chunkSize, manager) { michael@0: this.bytes = new Uint8Array(length); michael@0: this.start = 0; michael@0: this.pos = 0; michael@0: this.end = length; michael@0: this.chunkSize = chunkSize; michael@0: this.loadedChunks = []; michael@0: this.numChunksLoaded = 0; michael@0: this.numChunks = Math.ceil(length / chunkSize); michael@0: this.manager = manager; michael@0: this.initialDataLength = 0; michael@0: } michael@0: michael@0: // required methods for a stream. if a particular stream does not michael@0: // implement these, an error should be thrown michael@0: ChunkedStream.prototype = { michael@0: michael@0: getMissingChunks: function ChunkedStream_getMissingChunks() { michael@0: var chunks = []; michael@0: for (var chunk = 0, n = this.numChunks; chunk < n; ++chunk) { michael@0: if (!(chunk in this.loadedChunks)) { michael@0: chunks.push(chunk); michael@0: } michael@0: } michael@0: return chunks; michael@0: }, michael@0: michael@0: getBaseStreams: function ChunkedStream_getBaseStreams() { michael@0: return [this]; michael@0: }, michael@0: michael@0: allChunksLoaded: function ChunkedStream_allChunksLoaded() { michael@0: return this.numChunksLoaded === this.numChunks; michael@0: }, michael@0: michael@0: onReceiveData: function ChunkedStream_onReceiveData(begin, chunk) { michael@0: var end = begin + chunk.byteLength; michael@0: michael@0: assert(begin % this.chunkSize === 0, 'Bad begin offset: ' + begin); michael@0: // Using this.length is inaccurate here since this.start can be moved michael@0: // See ChunkedStream.moveStart() michael@0: var length = this.bytes.length; michael@0: assert(end % this.chunkSize === 0 || end === length, michael@0: 'Bad end offset: ' + end); michael@0: michael@0: this.bytes.set(new Uint8Array(chunk), begin); michael@0: var chunkSize = this.chunkSize; michael@0: var beginChunk = Math.floor(begin / chunkSize); michael@0: var endChunk = Math.floor((end - 1) / chunkSize) + 1; michael@0: var curChunk; michael@0: michael@0: for (curChunk = beginChunk; curChunk < endChunk; ++curChunk) { michael@0: if (!(curChunk in this.loadedChunks)) { michael@0: this.loadedChunks[curChunk] = true; michael@0: ++this.numChunksLoaded; michael@0: } michael@0: } michael@0: }, michael@0: michael@0: onReceiveInitialData: function ChunkedStream_onReceiveInitialData(data) { michael@0: this.bytes.set(data); michael@0: this.initialDataLength = data.length; michael@0: var endChunk = (this.end === data.length ? michael@0: this.numChunks : Math.floor(data.length / this.chunkSize)); michael@0: for (var i = 0; i < endChunk; i++) { michael@0: this.loadedChunks[i] = true; michael@0: ++this.numChunksLoaded; michael@0: } michael@0: }, michael@0: michael@0: ensureRange: function ChunkedStream_ensureRange(begin, end) { michael@0: if (begin >= end) { michael@0: return; michael@0: } michael@0: michael@0: if (end <= this.initialDataLength) { michael@0: return; michael@0: } michael@0: michael@0: var chunkSize = this.chunkSize; michael@0: var beginChunk = Math.floor(begin / chunkSize); michael@0: var endChunk = Math.floor((end - 1) / chunkSize) + 1; michael@0: for (var chunk = beginChunk; chunk < endChunk; ++chunk) { michael@0: if (!(chunk in this.loadedChunks)) { michael@0: throw new MissingDataException(begin, end); michael@0: } michael@0: } michael@0: }, michael@0: michael@0: nextEmptyChunk: function ChunkedStream_nextEmptyChunk(beginChunk) { michael@0: var chunk, n; michael@0: for (chunk = beginChunk, n = this.numChunks; chunk < n; ++chunk) { michael@0: if (!(chunk in this.loadedChunks)) { michael@0: return chunk; michael@0: } michael@0: } michael@0: // Wrap around to beginning michael@0: for (chunk = 0; chunk < beginChunk; ++chunk) { michael@0: if (!(chunk in this.loadedChunks)) { michael@0: return chunk; michael@0: } michael@0: } michael@0: return null; michael@0: }, michael@0: michael@0: hasChunk: function ChunkedStream_hasChunk(chunk) { michael@0: return chunk in this.loadedChunks; michael@0: }, michael@0: michael@0: get length() { michael@0: return this.end - this.start; michael@0: }, michael@0: michael@0: getByte: function ChunkedStream_getByte() { michael@0: var pos = this.pos; michael@0: if (pos >= this.end) { michael@0: return -1; michael@0: } michael@0: this.ensureRange(pos, pos + 1); michael@0: return this.bytes[this.pos++]; michael@0: }, michael@0: michael@0: getUint16: function ChunkedStream_getUint16() { michael@0: var b0 = this.getByte(); michael@0: var b1 = this.getByte(); michael@0: return (b0 << 8) + b1; michael@0: }, michael@0: michael@0: getInt32: function ChunkedStream_getInt32() { michael@0: var b0 = this.getByte(); michael@0: var b1 = this.getByte(); michael@0: var b2 = this.getByte(); michael@0: var b3 = this.getByte(); michael@0: return (b0 << 24) + (b1 << 16) + (b2 << 8) + b3; michael@0: }, michael@0: michael@0: // returns subarray of original buffer michael@0: // should only be read michael@0: getBytes: function ChunkedStream_getBytes(length) { michael@0: var bytes = this.bytes; michael@0: var pos = this.pos; michael@0: var strEnd = this.end; michael@0: michael@0: if (!length) { michael@0: this.ensureRange(pos, strEnd); michael@0: return bytes.subarray(pos, strEnd); michael@0: } michael@0: michael@0: var end = pos + length; michael@0: if (end > strEnd) { michael@0: end = strEnd; michael@0: } michael@0: this.ensureRange(pos, end); michael@0: michael@0: this.pos = end; michael@0: return bytes.subarray(pos, end); michael@0: }, michael@0: michael@0: peekBytes: function ChunkedStream_peekBytes(length) { michael@0: var bytes = this.getBytes(length); michael@0: this.pos -= bytes.length; michael@0: return bytes; michael@0: }, michael@0: michael@0: getByteRange: function ChunkedStream_getBytes(begin, end) { michael@0: this.ensureRange(begin, end); michael@0: return this.bytes.subarray(begin, end); michael@0: }, michael@0: michael@0: skip: function ChunkedStream_skip(n) { michael@0: if (!n) { michael@0: n = 1; michael@0: } michael@0: this.pos += n; michael@0: }, michael@0: michael@0: reset: function ChunkedStream_reset() { michael@0: this.pos = this.start; michael@0: }, michael@0: michael@0: moveStart: function ChunkedStream_moveStart() { michael@0: this.start = this.pos; michael@0: }, michael@0: michael@0: makeSubStream: function ChunkedStream_makeSubStream(start, length, dict) { michael@0: this.ensureRange(start, start + length); michael@0: michael@0: function ChunkedStreamSubstream() {} michael@0: ChunkedStreamSubstream.prototype = Object.create(this); michael@0: ChunkedStreamSubstream.prototype.getMissingChunks = function() { michael@0: var chunkSize = this.chunkSize; michael@0: var beginChunk = Math.floor(this.start / chunkSize); michael@0: var endChunk = Math.floor((this.end - 1) / chunkSize) + 1; michael@0: var missingChunks = []; michael@0: for (var chunk = beginChunk; chunk < endChunk; ++chunk) { michael@0: if (!(chunk in this.loadedChunks)) { michael@0: missingChunks.push(chunk); michael@0: } michael@0: } michael@0: return missingChunks; michael@0: }; michael@0: var subStream = new ChunkedStreamSubstream(); michael@0: subStream.pos = subStream.start = start; michael@0: subStream.end = start + length || this.end; michael@0: subStream.dict = dict; michael@0: return subStream; michael@0: }, michael@0: michael@0: isStream: true michael@0: }; michael@0: michael@0: return ChunkedStream; michael@0: })(); michael@0: michael@0: var ChunkedStreamManager = (function ChunkedStreamManagerClosure() { michael@0: michael@0: function ChunkedStreamManager(length, chunkSize, url, args) { michael@0: this.stream = new ChunkedStream(length, chunkSize, this); michael@0: this.length = length; michael@0: this.chunkSize = chunkSize; michael@0: this.url = url; michael@0: this.disableAutoFetch = args.disableAutoFetch; michael@0: var msgHandler = this.msgHandler = args.msgHandler; michael@0: michael@0: if (args.chunkedViewerLoading) { michael@0: msgHandler.on('OnDataRange', this.onReceiveData.bind(this)); michael@0: msgHandler.on('OnDataProgress', this.onProgress.bind(this)); michael@0: this.sendRequest = function ChunkedStreamManager_sendRequest(begin, end) { michael@0: msgHandler.send('RequestDataRange', { begin: begin, end: end }); michael@0: }; michael@0: } else { michael@0: michael@0: var getXhr = function getXhr() { michael@0: return new XMLHttpRequest(); michael@0: }; michael@0: this.networkManager = new NetworkManager(this.url, { michael@0: getXhr: getXhr, michael@0: httpHeaders: args.httpHeaders, michael@0: withCredentials: args.withCredentials michael@0: }); michael@0: this.sendRequest = function ChunkedStreamManager_sendRequest(begin, end) { michael@0: this.networkManager.requestRange(begin, end, { michael@0: onDone: this.onReceiveData.bind(this), michael@0: onProgress: this.onProgress.bind(this) michael@0: }); michael@0: }; michael@0: } michael@0: michael@0: this.currRequestId = 0; michael@0: michael@0: this.chunksNeededByRequest = {}; michael@0: this.requestsByChunk = {}; michael@0: this.callbacksByRequest = {}; michael@0: michael@0: this.loadedStream = new LegacyPromise(); michael@0: if (args.initialData) { michael@0: this.setInitialData(args.initialData); michael@0: } michael@0: } michael@0: michael@0: ChunkedStreamManager.prototype = { michael@0: michael@0: setInitialData: function ChunkedStreamManager_setInitialData(data) { michael@0: this.stream.onReceiveInitialData(data); michael@0: if (this.stream.allChunksLoaded()) { michael@0: this.loadedStream.resolve(this.stream); michael@0: } else if (this.msgHandler) { michael@0: this.msgHandler.send('DocProgress', { michael@0: loaded: data.length, michael@0: total: this.length michael@0: }); michael@0: } michael@0: }, michael@0: michael@0: onLoadedStream: function ChunkedStreamManager_getLoadedStream() { michael@0: return this.loadedStream; michael@0: }, michael@0: michael@0: // Get all the chunks that are not yet loaded and groups them into michael@0: // contiguous ranges to load in as few requests as possible michael@0: requestAllChunks: function ChunkedStreamManager_requestAllChunks() { michael@0: var missingChunks = this.stream.getMissingChunks(); michael@0: this.requestChunks(missingChunks); michael@0: return this.loadedStream; michael@0: }, michael@0: michael@0: requestChunks: function ChunkedStreamManager_requestChunks(chunks, michael@0: callback) { michael@0: var requestId = this.currRequestId++; michael@0: michael@0: var chunksNeeded; michael@0: var i, ii; michael@0: this.chunksNeededByRequest[requestId] = chunksNeeded = {}; michael@0: for (i = 0, ii = chunks.length; i < ii; i++) { michael@0: if (!this.stream.hasChunk(chunks[i])) { michael@0: chunksNeeded[chunks[i]] = true; michael@0: } michael@0: } michael@0: michael@0: if (isEmptyObj(chunksNeeded)) { michael@0: if (callback) { michael@0: callback(); michael@0: } michael@0: return; michael@0: } michael@0: michael@0: this.callbacksByRequest[requestId] = callback; michael@0: michael@0: var chunksToRequest = []; michael@0: for (var chunk in chunksNeeded) { michael@0: chunk = chunk | 0; michael@0: if (!(chunk in this.requestsByChunk)) { michael@0: this.requestsByChunk[chunk] = []; michael@0: chunksToRequest.push(chunk); michael@0: } michael@0: this.requestsByChunk[chunk].push(requestId); michael@0: } michael@0: michael@0: if (!chunksToRequest.length) { michael@0: return; michael@0: } michael@0: michael@0: var groupedChunksToRequest = this.groupChunks(chunksToRequest); michael@0: michael@0: for (i = 0; i < groupedChunksToRequest.length; ++i) { michael@0: var groupedChunk = groupedChunksToRequest[i]; michael@0: var begin = groupedChunk.beginChunk * this.chunkSize; michael@0: var end = Math.min(groupedChunk.endChunk * this.chunkSize, this.length); michael@0: this.sendRequest(begin, end); michael@0: } michael@0: }, michael@0: michael@0: getStream: function ChunkedStreamManager_getStream() { michael@0: return this.stream; michael@0: }, michael@0: michael@0: // Loads any chunks in the requested range that are not yet loaded michael@0: requestRange: function ChunkedStreamManager_requestRange( michael@0: begin, end, callback) { michael@0: michael@0: end = Math.min(end, this.length); michael@0: michael@0: var beginChunk = this.getBeginChunk(begin); michael@0: var endChunk = this.getEndChunk(end); michael@0: michael@0: var chunks = []; michael@0: for (var chunk = beginChunk; chunk < endChunk; ++chunk) { michael@0: chunks.push(chunk); michael@0: } michael@0: michael@0: this.requestChunks(chunks, callback); michael@0: }, michael@0: michael@0: requestRanges: function ChunkedStreamManager_requestRanges(ranges, michael@0: callback) { michael@0: ranges = ranges || []; michael@0: var chunksToRequest = []; michael@0: michael@0: for (var i = 0; i < ranges.length; i++) { michael@0: var beginChunk = this.getBeginChunk(ranges[i].begin); michael@0: var endChunk = this.getEndChunk(ranges[i].end); michael@0: for (var chunk = beginChunk; chunk < endChunk; ++chunk) { michael@0: if (chunksToRequest.indexOf(chunk) < 0) { michael@0: chunksToRequest.push(chunk); michael@0: } michael@0: } michael@0: } michael@0: michael@0: chunksToRequest.sort(function(a, b) { return a - b; }); michael@0: this.requestChunks(chunksToRequest, callback); michael@0: }, michael@0: michael@0: // Groups a sorted array of chunks into as few continguous larger michael@0: // chunks as possible michael@0: groupChunks: function ChunkedStreamManager_groupChunks(chunks) { michael@0: var groupedChunks = []; michael@0: var beginChunk = -1; michael@0: var prevChunk = -1; michael@0: for (var i = 0; i < chunks.length; ++i) { michael@0: var chunk = chunks[i]; michael@0: michael@0: if (beginChunk < 0) { michael@0: beginChunk = chunk; michael@0: } michael@0: michael@0: if (prevChunk >= 0 && prevChunk + 1 !== chunk) { michael@0: groupedChunks.push({ beginChunk: beginChunk, michael@0: endChunk: prevChunk + 1 }); michael@0: beginChunk = chunk; michael@0: } michael@0: if (i + 1 === chunks.length) { michael@0: groupedChunks.push({ beginChunk: beginChunk, michael@0: endChunk: chunk + 1 }); michael@0: } michael@0: michael@0: prevChunk = chunk; michael@0: } michael@0: return groupedChunks; michael@0: }, michael@0: michael@0: onProgress: function ChunkedStreamManager_onProgress(args) { michael@0: var bytesLoaded = (this.stream.numChunksLoaded * this.chunkSize + michael@0: args.loaded); michael@0: this.msgHandler.send('DocProgress', { michael@0: loaded: bytesLoaded, michael@0: total: this.length michael@0: }); michael@0: }, michael@0: michael@0: onReceiveData: function ChunkedStreamManager_onReceiveData(args) { michael@0: var chunk = args.chunk; michael@0: var begin = args.begin; michael@0: var end = begin + chunk.byteLength; michael@0: michael@0: var beginChunk = this.getBeginChunk(begin); michael@0: var endChunk = this.getEndChunk(end); michael@0: michael@0: this.stream.onReceiveData(begin, chunk); michael@0: if (this.stream.allChunksLoaded()) { michael@0: this.loadedStream.resolve(this.stream); michael@0: } michael@0: michael@0: var loadedRequests = []; michael@0: var i, requestId; michael@0: for (chunk = beginChunk; chunk < endChunk; ++chunk) { michael@0: // The server might return more chunks than requested michael@0: var requestIds = this.requestsByChunk[chunk] || []; michael@0: delete this.requestsByChunk[chunk]; michael@0: michael@0: for (i = 0; i < requestIds.length; ++i) { michael@0: requestId = requestIds[i]; michael@0: var chunksNeeded = this.chunksNeededByRequest[requestId]; michael@0: if (chunk in chunksNeeded) { michael@0: delete chunksNeeded[chunk]; michael@0: } michael@0: michael@0: if (!isEmptyObj(chunksNeeded)) { michael@0: continue; michael@0: } michael@0: michael@0: loadedRequests.push(requestId); michael@0: } michael@0: } michael@0: michael@0: // If there are no pending requests, automatically fetch the next michael@0: // unfetched chunk of the PDF michael@0: if (!this.disableAutoFetch && isEmptyObj(this.requestsByChunk)) { michael@0: var nextEmptyChunk; michael@0: if (this.stream.numChunksLoaded === 1) { michael@0: // This is a special optimization so that after fetching the first michael@0: // chunk, rather than fetching the second chunk, we fetch the last michael@0: // chunk. michael@0: var lastChunk = this.stream.numChunks - 1; michael@0: if (!this.stream.hasChunk(lastChunk)) { michael@0: nextEmptyChunk = lastChunk; michael@0: } michael@0: } else { michael@0: nextEmptyChunk = this.stream.nextEmptyChunk(endChunk); michael@0: } michael@0: if (isInt(nextEmptyChunk)) { michael@0: this.requestChunks([nextEmptyChunk]); michael@0: } michael@0: } michael@0: michael@0: for (i = 0; i < loadedRequests.length; ++i) { michael@0: requestId = loadedRequests[i]; michael@0: var callback = this.callbacksByRequest[requestId]; michael@0: delete this.callbacksByRequest[requestId]; michael@0: if (callback) { michael@0: callback(); michael@0: } michael@0: } michael@0: michael@0: this.msgHandler.send('DocProgress', { michael@0: loaded: this.stream.numChunksLoaded * this.chunkSize, michael@0: total: this.length michael@0: }); michael@0: }, michael@0: michael@0: getBeginChunk: function ChunkedStreamManager_getBeginChunk(begin) { michael@0: var chunk = Math.floor(begin / this.chunkSize); michael@0: return chunk; michael@0: }, michael@0: michael@0: getEndChunk: function ChunkedStreamManager_getEndChunk(end) { michael@0: if (end % this.chunkSize === 0) { michael@0: return end / this.chunkSize; michael@0: } michael@0: michael@0: // 0 -> 0 michael@0: // 1 -> 1 michael@0: // 99 -> 1 michael@0: // 100 -> 1 michael@0: // 101 -> 2 michael@0: var chunk = Math.floor((end - 1) / this.chunkSize) + 1; michael@0: return chunk; michael@0: } michael@0: }; michael@0: michael@0: return ChunkedStreamManager; michael@0: })(); michael@0: michael@0: michael@0: michael@0: // The maximum number of bytes fetched per range request michael@0: var RANGE_CHUNK_SIZE = 65536; michael@0: michael@0: // TODO(mack): Make use of PDFJS.Util.inherit() when it becomes available michael@0: var BasePdfManager = (function BasePdfManagerClosure() { michael@0: function BasePdfManager() { michael@0: throw new Error('Cannot initialize BaseManagerManager'); michael@0: } michael@0: michael@0: BasePdfManager.prototype = { michael@0: onLoadedStream: function BasePdfManager_onLoadedStream() { michael@0: throw new NotImplementedException(); michael@0: }, michael@0: michael@0: ensureDoc: function BasePdfManager_ensureDoc(prop, args) { michael@0: return this.ensure(this.pdfDocument, prop, args); michael@0: }, michael@0: michael@0: ensureXRef: function BasePdfManager_ensureXRef(prop, args) { michael@0: return this.ensure(this.pdfDocument.xref, prop, args); michael@0: }, michael@0: michael@0: ensureCatalog: function BasePdfManager_ensureCatalog(prop, args) { michael@0: return this.ensure(this.pdfDocument.catalog, prop, args); michael@0: }, michael@0: michael@0: getPage: function BasePdfManager_pagePage(pageIndex) { michael@0: return this.pdfDocument.getPage(pageIndex); michael@0: }, michael@0: michael@0: cleanup: function BasePdfManager_cleanup() { michael@0: return this.pdfDocument.cleanup(); michael@0: }, michael@0: michael@0: ensure: function BasePdfManager_ensure(obj, prop, args) { michael@0: return new NotImplementedException(); michael@0: }, michael@0: michael@0: requestRange: function BasePdfManager_ensure(begin, end) { michael@0: return new NotImplementedException(); michael@0: }, michael@0: michael@0: requestLoadedStream: function BasePdfManager_requestLoadedStream() { michael@0: return new NotImplementedException(); michael@0: }, michael@0: michael@0: updatePassword: function BasePdfManager_updatePassword(password) { michael@0: this.pdfDocument.xref.password = this.password = password; michael@0: if (this.passwordChangedPromise) { michael@0: this.passwordChangedPromise.resolve(); michael@0: } michael@0: }, michael@0: michael@0: terminate: function BasePdfManager_terminate() { michael@0: return new NotImplementedException(); michael@0: } michael@0: }; michael@0: michael@0: return BasePdfManager; michael@0: })(); michael@0: michael@0: var LocalPdfManager = (function LocalPdfManagerClosure() { michael@0: function LocalPdfManager(data, password) { michael@0: var stream = new Stream(data); michael@0: this.pdfDocument = new PDFDocument(this, stream, password); michael@0: this.loadedStream = new LegacyPromise(); michael@0: this.loadedStream.resolve(stream); michael@0: } michael@0: michael@0: LocalPdfManager.prototype = Object.create(BasePdfManager.prototype); michael@0: LocalPdfManager.prototype.constructor = LocalPdfManager; michael@0: michael@0: LocalPdfManager.prototype.ensure = michael@0: function LocalPdfManager_ensure(obj, prop, args) { michael@0: var promise = new LegacyPromise(); michael@0: try { michael@0: var value = obj[prop]; michael@0: var result; michael@0: if (typeof(value) === 'function') { michael@0: result = value.apply(obj, args); michael@0: } else { michael@0: result = value; michael@0: } michael@0: promise.resolve(result); michael@0: } catch (e) { michael@0: console.log(e.stack); michael@0: promise.reject(e); michael@0: } michael@0: return promise; michael@0: }; michael@0: michael@0: LocalPdfManager.prototype.requestRange = michael@0: function LocalPdfManager_requestRange(begin, end) { michael@0: var promise = new LegacyPromise(); michael@0: promise.resolve(); michael@0: return promise; michael@0: }; michael@0: michael@0: LocalPdfManager.prototype.requestLoadedStream = michael@0: function LocalPdfManager_requestLoadedStream() { michael@0: }; michael@0: michael@0: LocalPdfManager.prototype.onLoadedStream = michael@0: function LocalPdfManager_getLoadedStream() { michael@0: return this.loadedStream; michael@0: }; michael@0: michael@0: LocalPdfManager.prototype.terminate = michael@0: function LocalPdfManager_terminate() { michael@0: return; michael@0: }; michael@0: michael@0: return LocalPdfManager; michael@0: })(); michael@0: michael@0: var NetworkPdfManager = (function NetworkPdfManagerClosure() { michael@0: function NetworkPdfManager(args, msgHandler) { michael@0: michael@0: this.msgHandler = msgHandler; michael@0: michael@0: var params = { michael@0: msgHandler: msgHandler, michael@0: httpHeaders: args.httpHeaders, michael@0: withCredentials: args.withCredentials, michael@0: chunkedViewerLoading: args.chunkedViewerLoading, michael@0: disableAutoFetch: args.disableAutoFetch, michael@0: initialData: args.initialData michael@0: }; michael@0: this.streamManager = new ChunkedStreamManager(args.length, RANGE_CHUNK_SIZE, michael@0: args.url, params); michael@0: michael@0: this.pdfDocument = new PDFDocument(this, this.streamManager.getStream(), michael@0: args.password); michael@0: } michael@0: michael@0: NetworkPdfManager.prototype = Object.create(BasePdfManager.prototype); michael@0: NetworkPdfManager.prototype.constructor = NetworkPdfManager; michael@0: michael@0: NetworkPdfManager.prototype.ensure = michael@0: function NetworkPdfManager_ensure(obj, prop, args) { michael@0: var promise = new LegacyPromise(); michael@0: this.ensureHelper(promise, obj, prop, args); michael@0: return promise; michael@0: }; michael@0: michael@0: NetworkPdfManager.prototype.ensureHelper = michael@0: function NetworkPdfManager_ensureHelper(promise, obj, prop, args) { michael@0: try { michael@0: var result; michael@0: var value = obj[prop]; michael@0: if (typeof(value) === 'function') { michael@0: result = value.apply(obj, args); michael@0: } else { michael@0: result = value; michael@0: } michael@0: promise.resolve(result); michael@0: } catch(e) { michael@0: if (!(e instanceof MissingDataException)) { michael@0: console.log(e.stack); michael@0: promise.reject(e); michael@0: return; michael@0: } michael@0: michael@0: this.streamManager.requestRange(e.begin, e.end, function() { michael@0: this.ensureHelper(promise, obj, prop, args); michael@0: }.bind(this)); michael@0: } michael@0: }; michael@0: michael@0: NetworkPdfManager.prototype.requestRange = michael@0: function NetworkPdfManager_requestRange(begin, end) { michael@0: var promise = new LegacyPromise(); michael@0: this.streamManager.requestRange(begin, end, function() { michael@0: promise.resolve(); michael@0: }); michael@0: return promise; michael@0: }; michael@0: michael@0: NetworkPdfManager.prototype.requestLoadedStream = michael@0: function NetworkPdfManager_requestLoadedStream() { michael@0: this.streamManager.requestAllChunks(); michael@0: }; michael@0: michael@0: NetworkPdfManager.prototype.onLoadedStream = michael@0: function NetworkPdfManager_getLoadedStream() { michael@0: return this.streamManager.onLoadedStream(); michael@0: }; michael@0: michael@0: NetworkPdfManager.prototype.terminate = michael@0: function NetworkPdfManager_terminate() { michael@0: this.streamManager.networkManager.abortAllRequests(); michael@0: }; michael@0: michael@0: return NetworkPdfManager; michael@0: })(); michael@0: michael@0: michael@0: michael@0: var Page = (function PageClosure() { michael@0: michael@0: var LETTER_SIZE_MEDIABOX = [0, 0, 612, 792]; michael@0: michael@0: function Page(pdfManager, xref, pageIndex, pageDict, ref, fontCache) { michael@0: this.pdfManager = pdfManager; michael@0: this.pageIndex = pageIndex; michael@0: this.pageDict = pageDict; michael@0: this.xref = xref; michael@0: this.ref = ref; michael@0: this.fontCache = fontCache; michael@0: this.idCounters = { michael@0: obj: 0 michael@0: }; michael@0: this.resourcesPromise = null; michael@0: } michael@0: michael@0: Page.prototype = { michael@0: getPageProp: function Page_getPageProp(key) { michael@0: return this.pageDict.get(key); michael@0: }, michael@0: michael@0: getInheritedPageProp: function Page_inheritPageProp(key) { michael@0: var dict = this.pageDict; michael@0: var value = dict.get(key); michael@0: while (value === undefined) { michael@0: dict = dict.get('Parent'); michael@0: if (!dict) { michael@0: break; michael@0: } michael@0: value = dict.get(key); michael@0: } michael@0: return value; michael@0: }, michael@0: michael@0: get content() { michael@0: return this.getPageProp('Contents'); michael@0: }, michael@0: michael@0: get resources() { michael@0: var value = this.getInheritedPageProp('Resources'); michael@0: // For robustness: The spec states that a \Resources entry has to be michael@0: // present, but can be empty. Some document omit it still. In this case michael@0: // return an empty dictionary: michael@0: if (value === undefined) { michael@0: value = Dict.empty; michael@0: } michael@0: return shadow(this, 'resources', value); michael@0: }, michael@0: michael@0: get mediaBox() { michael@0: var obj = this.getInheritedPageProp('MediaBox'); michael@0: // Reset invalid media box to letter size. michael@0: if (!isArray(obj) || obj.length !== 4) { michael@0: obj = LETTER_SIZE_MEDIABOX; michael@0: } michael@0: return shadow(this, 'mediaBox', obj); michael@0: }, michael@0: michael@0: get view() { michael@0: var mediaBox = this.mediaBox; michael@0: var cropBox = this.getInheritedPageProp('CropBox'); michael@0: if (!isArray(cropBox) || cropBox.length !== 4) { michael@0: return shadow(this, 'view', mediaBox); michael@0: } michael@0: michael@0: // From the spec, 6th ed., p.963: michael@0: // "The crop, bleed, trim, and art boxes should not ordinarily michael@0: // extend beyond the boundaries of the media box. If they do, they are michael@0: // effectively reduced to their intersection with the media box." michael@0: cropBox = Util.intersect(cropBox, mediaBox); michael@0: if (!cropBox) { michael@0: return shadow(this, 'view', mediaBox); michael@0: } michael@0: return shadow(this, 'view', cropBox); michael@0: }, michael@0: michael@0: get annotationRefs() { michael@0: return shadow(this, 'annotationRefs', michael@0: this.getInheritedPageProp('Annots')); michael@0: }, michael@0: michael@0: get rotate() { michael@0: var rotate = this.getInheritedPageProp('Rotate') || 0; michael@0: // Normalize rotation so it's a multiple of 90 and between 0 and 270 michael@0: if (rotate % 90 !== 0) { michael@0: rotate = 0; michael@0: } else if (rotate >= 360) { michael@0: rotate = rotate % 360; michael@0: } else if (rotate < 0) { michael@0: // The spec doesn't cover negatives, assume its counterclockwise michael@0: // rotation. The following is the other implementation of modulo. michael@0: rotate = ((rotate % 360) + 360) % 360; michael@0: } michael@0: return shadow(this, 'rotate', rotate); michael@0: }, michael@0: michael@0: getContentStream: function Page_getContentStream() { michael@0: var content = this.content; michael@0: var stream; michael@0: if (isArray(content)) { michael@0: // fetching items michael@0: var xref = this.xref; michael@0: var i, n = content.length; michael@0: var streams = []; michael@0: for (i = 0; i < n; ++i) { michael@0: streams.push(xref.fetchIfRef(content[i])); michael@0: } michael@0: stream = new StreamsSequenceStream(streams); michael@0: } else if (isStream(content)) { michael@0: stream = content; michael@0: } else { michael@0: // replacing non-existent page content with empty one michael@0: stream = new NullStream(); michael@0: } michael@0: return stream; michael@0: }, michael@0: michael@0: loadResources: function(keys) { michael@0: if (!this.resourcesPromise) { michael@0: // TODO: add async getInheritedPageProp and remove this. michael@0: this.resourcesPromise = this.pdfManager.ensure(this, 'resources'); michael@0: } michael@0: var promise = new LegacyPromise(); michael@0: this.resourcesPromise.then(function resourceSuccess() { michael@0: var objectLoader = new ObjectLoader(this.resources.map, michael@0: keys, michael@0: this.xref); michael@0: objectLoader.load().then(function objectLoaderSuccess() { michael@0: promise.resolve(); michael@0: }); michael@0: }.bind(this)); michael@0: return promise; michael@0: }, michael@0: michael@0: getOperatorList: function Page_getOperatorList(handler, intent) { michael@0: var self = this; michael@0: var promise = new LegacyPromise(); michael@0: michael@0: function reject(e) { michael@0: promise.reject(e); michael@0: } michael@0: michael@0: var pageListPromise = new LegacyPromise(); michael@0: michael@0: var pdfManager = this.pdfManager; michael@0: var contentStreamPromise = pdfManager.ensure(this, 'getContentStream', michael@0: []); michael@0: var resourcesPromise = this.loadResources([ michael@0: 'ExtGState', michael@0: 'ColorSpace', michael@0: 'Pattern', michael@0: 'Shading', michael@0: 'XObject', michael@0: 'Font' michael@0: // ProcSet michael@0: // Properties michael@0: ]); michael@0: michael@0: var partialEvaluator = new PartialEvaluator(pdfManager, this.xref, michael@0: handler, this.pageIndex, michael@0: 'p' + this.pageIndex + '_', michael@0: this.idCounters, michael@0: this.fontCache); michael@0: michael@0: var dataPromises = Promise.all([contentStreamPromise, resourcesPromise], michael@0: reject); michael@0: dataPromises.then(function(data) { michael@0: var contentStream = data[0]; michael@0: var opList = new OperatorList(intent, handler, self.pageIndex); michael@0: michael@0: handler.send('StartRenderPage', { michael@0: transparency: partialEvaluator.hasBlendModes(self.resources), michael@0: pageIndex: self.pageIndex, michael@0: intent: intent michael@0: }); michael@0: partialEvaluator.getOperatorList(contentStream, self.resources, opList); michael@0: pageListPromise.resolve(opList); michael@0: }); michael@0: michael@0: var annotationsPromise = pdfManager.ensure(this, 'annotations'); michael@0: Promise.all([pageListPromise, annotationsPromise]).then(function(datas) { michael@0: var pageOpList = datas[0]; michael@0: var annotations = datas[1]; michael@0: michael@0: if (annotations.length === 0) { michael@0: pageOpList.flush(true); michael@0: promise.resolve(pageOpList); michael@0: return; michael@0: } michael@0: michael@0: var annotationsReadyPromise = Annotation.appendToOperatorList( michael@0: annotations, pageOpList, pdfManager, partialEvaluator, intent); michael@0: annotationsReadyPromise.then(function () { michael@0: pageOpList.flush(true); michael@0: promise.resolve(pageOpList); michael@0: }, reject); michael@0: }, reject); michael@0: michael@0: return promise; michael@0: }, michael@0: michael@0: extractTextContent: function Page_extractTextContent() { michael@0: var handler = { michael@0: on: function nullHandlerOn() {}, michael@0: send: function nullHandlerSend() {} michael@0: }; michael@0: michael@0: var self = this; michael@0: michael@0: var pdfManager = this.pdfManager; michael@0: var contentStreamPromise = pdfManager.ensure(this, 'getContentStream', michael@0: []); michael@0: michael@0: var resourcesPromise = this.loadResources([ michael@0: 'ExtGState', michael@0: 'XObject', michael@0: 'Font' michael@0: ]); michael@0: michael@0: var dataPromises = Promise.all([contentStreamPromise, michael@0: resourcesPromise]); michael@0: return dataPromises.then(function(data) { michael@0: var contentStream = data[0]; michael@0: var partialEvaluator = new PartialEvaluator(pdfManager, self.xref, michael@0: handler, self.pageIndex, michael@0: 'p' + self.pageIndex + '_', michael@0: self.idCounters, michael@0: self.fontCache); michael@0: michael@0: return partialEvaluator.getTextContent(contentStream, michael@0: self.resources); michael@0: }); michael@0: }, michael@0: michael@0: getAnnotationsData: function Page_getAnnotationsData() { michael@0: var annotations = this.annotations; michael@0: var annotationsData = []; michael@0: for (var i = 0, n = annotations.length; i < n; ++i) { michael@0: annotationsData.push(annotations[i].getData()); michael@0: } michael@0: return annotationsData; michael@0: }, michael@0: michael@0: get annotations() { michael@0: var annotations = []; michael@0: var annotationRefs = (this.annotationRefs || []); michael@0: for (var i = 0, n = annotationRefs.length; i < n; ++i) { michael@0: var annotationRef = annotationRefs[i]; michael@0: var annotation = Annotation.fromRef(this.xref, annotationRef); michael@0: if (annotation) { michael@0: annotations.push(annotation); michael@0: } michael@0: } michael@0: return shadow(this, 'annotations', annotations); michael@0: } michael@0: }; michael@0: michael@0: return Page; michael@0: })(); michael@0: michael@0: /** michael@0: * The `PDFDocument` holds all the data of the PDF file. Compared to the michael@0: * `PDFDoc`, this one doesn't have any job management code. michael@0: * Right now there exists one PDFDocument on the main thread + one object michael@0: * for each worker. If there is no worker support enabled, there are two michael@0: * `PDFDocument` objects on the main thread created. michael@0: */ michael@0: var PDFDocument = (function PDFDocumentClosure() { michael@0: function PDFDocument(pdfManager, arg, password) { michael@0: if (isStream(arg)) { michael@0: init.call(this, pdfManager, arg, password); michael@0: } else if (isArrayBuffer(arg)) { michael@0: init.call(this, pdfManager, new Stream(arg), password); michael@0: } else { michael@0: error('PDFDocument: Unknown argument type'); michael@0: } michael@0: } michael@0: michael@0: function init(pdfManager, stream, password) { michael@0: assert(stream.length > 0, 'stream must have data'); michael@0: this.pdfManager = pdfManager; michael@0: this.stream = stream; michael@0: var xref = new XRef(this.stream, password, pdfManager); michael@0: this.xref = xref; michael@0: } michael@0: michael@0: function find(stream, needle, limit, backwards) { michael@0: var pos = stream.pos; michael@0: var end = stream.end; michael@0: var strBuf = []; michael@0: if (pos + limit > end) { michael@0: limit = end - pos; michael@0: } michael@0: for (var n = 0; n < limit; ++n) { michael@0: strBuf.push(String.fromCharCode(stream.getByte())); michael@0: } michael@0: var str = strBuf.join(''); michael@0: stream.pos = pos; michael@0: var index = backwards ? str.lastIndexOf(needle) : str.indexOf(needle); michael@0: if (index == -1) { michael@0: return false; /* not found */ michael@0: } michael@0: stream.pos += index; michael@0: return true; /* found */ michael@0: } michael@0: michael@0: var DocumentInfoValidators = { michael@0: get entries() { michael@0: // Lazily build this since all the validation functions below are not michael@0: // defined until after this file loads. michael@0: return shadow(this, 'entries', { michael@0: Title: isString, michael@0: Author: isString, michael@0: Subject: isString, michael@0: Keywords: isString, michael@0: Creator: isString, michael@0: Producer: isString, michael@0: CreationDate: isString, michael@0: ModDate: isString, michael@0: Trapped: isName michael@0: }); michael@0: } michael@0: }; michael@0: michael@0: PDFDocument.prototype = { michael@0: parse: function PDFDocument_parse(recoveryMode) { michael@0: this.setup(recoveryMode); michael@0: try { michael@0: // checking if AcroForm is present michael@0: this.acroForm = this.catalog.catDict.get('AcroForm'); michael@0: if (this.acroForm) { michael@0: this.xfa = this.acroForm.get('XFA'); michael@0: var fields = this.acroForm.get('Fields'); michael@0: if ((!fields || !isArray(fields) || fields.length === 0) && michael@0: !this.xfa) { michael@0: // no fields and no XFA -- not a form (?) michael@0: this.acroForm = null; michael@0: } michael@0: } michael@0: } catch (ex) { michael@0: info('Something wrong with AcroForm entry'); michael@0: this.acroForm = null; michael@0: } michael@0: }, michael@0: michael@0: get linearization() { michael@0: var length = this.stream.length; michael@0: var linearization = false; michael@0: if (length) { michael@0: try { michael@0: linearization = new Linearization(this.stream); michael@0: if (linearization.length != length) { michael@0: linearization = false; michael@0: } michael@0: } catch (err) { michael@0: if (err instanceof MissingDataException) { michael@0: throw err; michael@0: } michael@0: michael@0: info('The linearization data is not available ' + michael@0: 'or unreadable PDF data is found'); michael@0: linearization = false; michael@0: } michael@0: } michael@0: // shadow the prototype getter with a data property michael@0: return shadow(this, 'linearization', linearization); michael@0: }, michael@0: get startXRef() { michael@0: var stream = this.stream; michael@0: var startXRef = 0; michael@0: var linearization = this.linearization; michael@0: if (linearization) { michael@0: // Find end of first obj. michael@0: stream.reset(); michael@0: if (find(stream, 'endobj', 1024)) { michael@0: startXRef = stream.pos + 6; michael@0: } michael@0: } else { michael@0: // Find startxref by jumping backward from the end of the file. michael@0: var step = 1024; michael@0: var found = false, pos = stream.end; michael@0: while (!found && pos > 0) { michael@0: pos -= step - 'startxref'.length; michael@0: if (pos < 0) { michael@0: pos = 0; michael@0: } michael@0: stream.pos = pos; michael@0: found = find(stream, 'startxref', step, true); michael@0: } michael@0: if (found) { michael@0: stream.skip(9); michael@0: var ch; michael@0: do { michael@0: ch = stream.getByte(); michael@0: } while (Lexer.isSpace(ch)); michael@0: var str = ''; michael@0: while (ch >= 0x20 && ch <= 0x39) { // < '9' michael@0: str += String.fromCharCode(ch); michael@0: ch = stream.getByte(); michael@0: } michael@0: startXRef = parseInt(str, 10); michael@0: if (isNaN(startXRef)) { michael@0: startXRef = 0; michael@0: } michael@0: } michael@0: } michael@0: // shadow the prototype getter with a data property michael@0: return shadow(this, 'startXRef', startXRef); michael@0: }, michael@0: get mainXRefEntriesOffset() { michael@0: var mainXRefEntriesOffset = 0; michael@0: var linearization = this.linearization; michael@0: if (linearization) { michael@0: mainXRefEntriesOffset = linearization.mainXRefEntriesOffset; michael@0: } michael@0: // shadow the prototype getter with a data property michael@0: return shadow(this, 'mainXRefEntriesOffset', mainXRefEntriesOffset); michael@0: }, michael@0: // Find the header, remove leading garbage and setup the stream michael@0: // starting from the header. michael@0: checkHeader: function PDFDocument_checkHeader() { michael@0: var stream = this.stream; michael@0: stream.reset(); michael@0: if (find(stream, '%PDF-', 1024)) { michael@0: // Found the header, trim off any garbage before it. michael@0: stream.moveStart(); michael@0: // Reading file format version michael@0: var MAX_VERSION_LENGTH = 12; michael@0: var version = '', ch; michael@0: while ((ch = stream.getByte()) > 0x20) { // SPACE michael@0: if (version.length >= MAX_VERSION_LENGTH) { michael@0: break; michael@0: } michael@0: version += String.fromCharCode(ch); michael@0: } michael@0: // removing "%PDF-"-prefix michael@0: this.pdfFormatVersion = version.substring(5); michael@0: return; michael@0: } michael@0: // May not be a PDF file, continue anyway. michael@0: }, michael@0: parseStartXRef: function PDFDocument_parseStartXRef() { michael@0: var startXRef = this.startXRef; michael@0: this.xref.setStartXRef(startXRef); michael@0: }, michael@0: setup: function PDFDocument_setup(recoveryMode) { michael@0: this.xref.parse(recoveryMode); michael@0: this.catalog = new Catalog(this.pdfManager, this.xref); michael@0: }, michael@0: get numPages() { michael@0: var linearization = this.linearization; michael@0: var num = linearization ? linearization.numPages : this.catalog.numPages; michael@0: // shadow the prototype getter michael@0: return shadow(this, 'numPages', num); michael@0: }, michael@0: get documentInfo() { michael@0: var docInfo = { michael@0: PDFFormatVersion: this.pdfFormatVersion, michael@0: IsAcroFormPresent: !!this.acroForm, michael@0: IsXFAPresent: !!this.xfa michael@0: }; michael@0: var infoDict; michael@0: try { michael@0: infoDict = this.xref.trailer.get('Info'); michael@0: } catch (err) { michael@0: info('The document information dictionary is invalid.'); michael@0: } michael@0: if (infoDict) { michael@0: var validEntries = DocumentInfoValidators.entries; michael@0: // Only fill the document info with valid entries from the spec. michael@0: for (var key in validEntries) { michael@0: if (infoDict.has(key)) { michael@0: var value = infoDict.get(key); michael@0: // Make sure the value conforms to the spec. michael@0: if (validEntries[key](value)) { michael@0: docInfo[key] = (typeof value !== 'string' ? michael@0: value : stringToPDFString(value)); michael@0: } else { michael@0: info('Bad value in document info for "' + key + '"'); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: return shadow(this, 'documentInfo', docInfo); michael@0: }, michael@0: get fingerprint() { michael@0: var xref = this.xref, hash, fileID = ''; michael@0: michael@0: if (xref.trailer.has('ID')) { michael@0: hash = stringToBytes(xref.trailer.get('ID')[0]); michael@0: } else { michael@0: hash = calculateMD5(this.stream.bytes.subarray(0, 100), 0, 100); michael@0: } michael@0: michael@0: for (var i = 0, n = hash.length; i < n; i++) { michael@0: fileID += hash[i].toString(16); michael@0: } michael@0: michael@0: return shadow(this, 'fingerprint', fileID); michael@0: }, michael@0: michael@0: getPage: function PDFDocument_getPage(pageIndex) { michael@0: return this.catalog.getPage(pageIndex); michael@0: }, michael@0: michael@0: cleanup: function PDFDocument_cleanup() { michael@0: return this.catalog.cleanup(); michael@0: } michael@0: }; michael@0: michael@0: return PDFDocument; michael@0: })(); michael@0: michael@0: michael@0: michael@0: var Name = (function NameClosure() { michael@0: function Name(name) { michael@0: this.name = name; michael@0: } michael@0: michael@0: Name.prototype = {}; michael@0: michael@0: var nameCache = {}; michael@0: michael@0: Name.get = function Name_get(name) { michael@0: var nameValue = nameCache[name]; michael@0: return (nameValue ? nameValue : (nameCache[name] = new Name(name))); michael@0: }; michael@0: michael@0: return Name; michael@0: })(); michael@0: michael@0: var Cmd = (function CmdClosure() { michael@0: function Cmd(cmd) { michael@0: this.cmd = cmd; michael@0: } michael@0: michael@0: Cmd.prototype = {}; michael@0: michael@0: var cmdCache = {}; michael@0: michael@0: Cmd.get = function Cmd_get(cmd) { michael@0: var cmdValue = cmdCache[cmd]; michael@0: return (cmdValue ? cmdValue : (cmdCache[cmd] = new Cmd(cmd))); michael@0: }; michael@0: michael@0: return Cmd; michael@0: })(); michael@0: michael@0: var Dict = (function DictClosure() { michael@0: var nonSerializable = function nonSerializableClosure() { michael@0: return nonSerializable; // creating closure on some variable michael@0: }; michael@0: michael@0: var GETALL_DICTIONARY_TYPES_WHITELIST = { michael@0: 'Background': true, michael@0: 'ExtGState': true, michael@0: 'Halftone': true, michael@0: 'Layout': true, michael@0: 'Mask': true, michael@0: 'Pagination': true, michael@0: 'Printing': true michael@0: }; michael@0: michael@0: function isRecursionAllowedFor(dict) { michael@0: if (!isName(dict.Type)) { michael@0: return true; michael@0: } michael@0: var dictType = dict.Type.name; michael@0: return GETALL_DICTIONARY_TYPES_WHITELIST[dictType] === true; michael@0: } michael@0: michael@0: // xref is optional michael@0: function Dict(xref) { michael@0: // Map should only be used internally, use functions below to access. michael@0: this.map = Object.create(null); michael@0: this.xref = xref; michael@0: this.objId = null; michael@0: this.__nonSerializable__ = nonSerializable; // disable cloning of the Dict michael@0: } michael@0: michael@0: Dict.prototype = { michael@0: assignXref: function Dict_assignXref(newXref) { michael@0: this.xref = newXref; michael@0: }, michael@0: michael@0: // automatically dereferences Ref objects michael@0: get: function Dict_get(key1, key2, key3) { michael@0: var value; michael@0: var xref = this.xref; michael@0: if (typeof (value = this.map[key1]) != 'undefined' || key1 in this.map || michael@0: typeof key2 == 'undefined') { michael@0: return xref ? xref.fetchIfRef(value) : value; michael@0: } michael@0: if (typeof (value = this.map[key2]) != 'undefined' || key2 in this.map || michael@0: typeof key3 == 'undefined') { michael@0: return xref ? xref.fetchIfRef(value) : value; michael@0: } michael@0: value = this.map[key3] || null; michael@0: return xref ? xref.fetchIfRef(value) : value; michael@0: }, michael@0: michael@0: // Same as get(), but returns a promise and uses fetchIfRefAsync(). michael@0: getAsync: function Dict_getAsync(key1, key2, key3) { michael@0: var value; michael@0: var promise; michael@0: var xref = this.xref; michael@0: if (typeof (value = this.map[key1]) !== undefined || key1 in this.map || michael@0: typeof key2 === undefined) { michael@0: if (xref) { michael@0: return xref.fetchIfRefAsync(value); michael@0: } michael@0: promise = new LegacyPromise(); michael@0: promise.resolve(value); michael@0: return promise; michael@0: } michael@0: if (typeof (value = this.map[key2]) !== undefined || key2 in this.map || michael@0: typeof key3 === undefined) { michael@0: if (xref) { michael@0: return xref.fetchIfRefAsync(value); michael@0: } michael@0: promise = new LegacyPromise(); michael@0: promise.resolve(value); michael@0: return promise; michael@0: } michael@0: value = this.map[key3] || null; michael@0: if (xref) { michael@0: return xref.fetchIfRefAsync(value); michael@0: } michael@0: promise = new LegacyPromise(); michael@0: promise.resolve(value); michael@0: return promise; michael@0: }, michael@0: michael@0: // no dereferencing michael@0: getRaw: function Dict_getRaw(key) { michael@0: return this.map[key]; michael@0: }, michael@0: michael@0: // creates new map and dereferences all Refs michael@0: getAll: function Dict_getAll() { michael@0: var all = Object.create(null); michael@0: var queue = null; michael@0: var key, obj; michael@0: for (key in this.map) { michael@0: obj = this.get(key); michael@0: if (obj instanceof Dict) { michael@0: if (isRecursionAllowedFor(obj)) { michael@0: (queue || (queue = [])).push({target: all, key: key, obj: obj}); michael@0: } else { michael@0: all[key] = this.getRaw(key); michael@0: } michael@0: } else { michael@0: all[key] = obj; michael@0: } michael@0: } michael@0: if (!queue) { michael@0: return all; michael@0: } michael@0: michael@0: // trying to take cyclic references into the account michael@0: var processed = Object.create(null); michael@0: while (queue.length > 0) { michael@0: var item = queue.shift(); michael@0: var itemObj = item.obj; michael@0: var objId = itemObj.objId; michael@0: if (objId && objId in processed) { michael@0: item.target[item.key] = processed[objId]; michael@0: continue; michael@0: } michael@0: var dereferenced = Object.create(null); michael@0: for (key in itemObj.map) { michael@0: obj = itemObj.get(key); michael@0: if (obj instanceof Dict) { michael@0: if (isRecursionAllowedFor(obj)) { michael@0: queue.push({target: dereferenced, key: key, obj: obj}); michael@0: } else { michael@0: dereferenced[key] = itemObj.getRaw(key); michael@0: } michael@0: } else { michael@0: dereferenced[key] = obj; michael@0: } michael@0: } michael@0: if (objId) { michael@0: processed[objId] = dereferenced; michael@0: } michael@0: item.target[item.key] = dereferenced; michael@0: } michael@0: return all; michael@0: }, michael@0: michael@0: set: function Dict_set(key, value) { michael@0: this.map[key] = value; michael@0: }, michael@0: michael@0: has: function Dict_has(key) { michael@0: return key in this.map; michael@0: }, michael@0: michael@0: forEach: function Dict_forEach(callback) { michael@0: for (var key in this.map) { michael@0: callback(key, this.get(key)); michael@0: } michael@0: } michael@0: }; michael@0: michael@0: Dict.empty = new Dict(null); michael@0: michael@0: return Dict; michael@0: })(); michael@0: michael@0: var Ref = (function RefClosure() { michael@0: function Ref(num, gen) { michael@0: this.num = num; michael@0: this.gen = gen; michael@0: } michael@0: michael@0: Ref.prototype = {}; michael@0: michael@0: return Ref; michael@0: })(); michael@0: michael@0: // The reference is identified by number and generation. michael@0: // This structure stores only one instance of the reference. michael@0: var RefSet = (function RefSetClosure() { michael@0: function RefSet() { michael@0: this.dict = {}; michael@0: } michael@0: michael@0: RefSet.prototype = { michael@0: has: function RefSet_has(ref) { michael@0: return ('R' + ref.num + '.' + ref.gen) in this.dict; michael@0: }, michael@0: michael@0: put: function RefSet_put(ref) { michael@0: this.dict['R' + ref.num + '.' + ref.gen] = true; michael@0: }, michael@0: michael@0: remove: function RefSet_remove(ref) { michael@0: delete this.dict['R' + ref.num + '.' + ref.gen]; michael@0: } michael@0: }; michael@0: michael@0: return RefSet; michael@0: })(); michael@0: michael@0: var RefSetCache = (function RefSetCacheClosure() { michael@0: function RefSetCache() { michael@0: this.dict = Object.create(null); michael@0: } michael@0: michael@0: RefSetCache.prototype = { michael@0: get: function RefSetCache_get(ref) { michael@0: return this.dict['R' + ref.num + '.' + ref.gen]; michael@0: }, michael@0: michael@0: has: function RefSetCache_has(ref) { michael@0: return ('R' + ref.num + '.' + ref.gen) in this.dict; michael@0: }, michael@0: michael@0: put: function RefSetCache_put(ref, obj) { michael@0: this.dict['R' + ref.num + '.' + ref.gen] = obj; michael@0: }, michael@0: michael@0: putAlias: function RefSetCache_putAlias(ref, aliasRef) { michael@0: this.dict['R' + ref.num + '.' + ref.gen] = this.get(aliasRef); michael@0: }, michael@0: michael@0: forEach: function RefSetCache_forEach(fn, thisArg) { michael@0: for (var i in this.dict) { michael@0: fn.call(thisArg, this.dict[i]); michael@0: } michael@0: }, michael@0: michael@0: clear: function RefSetCache_clear() { michael@0: this.dict = Object.create(null); michael@0: } michael@0: }; michael@0: michael@0: return RefSetCache; michael@0: })(); michael@0: michael@0: var Catalog = (function CatalogClosure() { michael@0: function Catalog(pdfManager, xref) { michael@0: this.pdfManager = pdfManager; michael@0: this.xref = xref; michael@0: this.catDict = xref.getCatalogObj(); michael@0: this.fontCache = new RefSetCache(); michael@0: assert(isDict(this.catDict), michael@0: 'catalog object is not a dictionary'); michael@0: michael@0: this.pagePromises = []; michael@0: } michael@0: michael@0: Catalog.prototype = { michael@0: get metadata() { michael@0: var streamRef = this.catDict.getRaw('Metadata'); michael@0: if (!isRef(streamRef)) { michael@0: return shadow(this, 'metadata', null); michael@0: } michael@0: michael@0: var encryptMetadata = (!this.xref.encrypt ? false : michael@0: this.xref.encrypt.encryptMetadata); michael@0: michael@0: var stream = this.xref.fetch(streamRef, !encryptMetadata); michael@0: var metadata; michael@0: if (stream && isDict(stream.dict)) { michael@0: var type = stream.dict.get('Type'); michael@0: var subtype = stream.dict.get('Subtype'); michael@0: michael@0: if (isName(type) && isName(subtype) && michael@0: type.name === 'Metadata' && subtype.name === 'XML') { michael@0: // XXX: This should examine the charset the XML document defines, michael@0: // however since there are currently no real means to decode michael@0: // arbitrary charsets, let's just hope that the author of the PDF michael@0: // was reasonable enough to stick with the XML default charset, michael@0: // which is UTF-8. michael@0: try { michael@0: metadata = stringToUTF8String(bytesToString(stream.getBytes())); michael@0: } catch (e) { michael@0: info('Skipping invalid metadata.'); michael@0: } michael@0: } michael@0: } michael@0: michael@0: return shadow(this, 'metadata', metadata); michael@0: }, michael@0: get toplevelPagesDict() { michael@0: var pagesObj = this.catDict.get('Pages'); michael@0: assert(isDict(pagesObj), 'invalid top-level pages dictionary'); michael@0: // shadow the prototype getter michael@0: return shadow(this, 'toplevelPagesDict', pagesObj); michael@0: }, michael@0: get documentOutline() { michael@0: var obj = null; michael@0: try { michael@0: obj = this.readDocumentOutline(); michael@0: } catch (ex) { michael@0: if (ex instanceof MissingDataException) { michael@0: throw ex; michael@0: } michael@0: warn('Unable to read document outline'); michael@0: } michael@0: return shadow(this, 'documentOutline', obj); michael@0: }, michael@0: readDocumentOutline: function Catalog_readDocumentOutline() { michael@0: var xref = this.xref; michael@0: var obj = this.catDict.get('Outlines'); michael@0: var root = { items: [] }; michael@0: if (isDict(obj)) { michael@0: obj = obj.getRaw('First'); michael@0: var processed = new RefSet(); michael@0: if (isRef(obj)) { michael@0: var queue = [{obj: obj, parent: root}]; michael@0: // to avoid recursion keeping track of the items michael@0: // in the processed dictionary michael@0: processed.put(obj); michael@0: while (queue.length > 0) { michael@0: var i = queue.shift(); michael@0: var outlineDict = xref.fetchIfRef(i.obj); michael@0: if (outlineDict === null) { michael@0: continue; michael@0: } michael@0: if (!outlineDict.has('Title')) { michael@0: error('Invalid outline item'); michael@0: } michael@0: var dest = outlineDict.get('A'); michael@0: if (dest) { michael@0: dest = dest.get('D'); michael@0: } else if (outlineDict.has('Dest')) { michael@0: dest = outlineDict.getRaw('Dest'); michael@0: if (isName(dest)) { michael@0: dest = dest.name; michael@0: } michael@0: } michael@0: var title = outlineDict.get('Title'); michael@0: var outlineItem = { michael@0: dest: dest, michael@0: title: stringToPDFString(title), michael@0: color: outlineDict.get('C') || [0, 0, 0], michael@0: count: outlineDict.get('Count'), michael@0: bold: !!(outlineDict.get('F') & 2), michael@0: italic: !!(outlineDict.get('F') & 1), michael@0: items: [] michael@0: }; michael@0: i.parent.items.push(outlineItem); michael@0: obj = outlineDict.getRaw('First'); michael@0: if (isRef(obj) && !processed.has(obj)) { michael@0: queue.push({obj: obj, parent: outlineItem}); michael@0: processed.put(obj); michael@0: } michael@0: obj = outlineDict.getRaw('Next'); michael@0: if (isRef(obj) && !processed.has(obj)) { michael@0: queue.push({obj: obj, parent: i.parent}); michael@0: processed.put(obj); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: return (root.items.length > 0 ? root.items : null); michael@0: }, michael@0: get numPages() { michael@0: var obj = this.toplevelPagesDict.get('Count'); michael@0: assert( michael@0: isInt(obj), michael@0: 'page count in top level pages object is not an integer' michael@0: ); michael@0: // shadow the prototype getter michael@0: return shadow(this, 'num', obj); michael@0: }, michael@0: get destinations() { michael@0: function fetchDestination(dest) { michael@0: return isDict(dest) ? dest.get('D') : dest; michael@0: } michael@0: michael@0: var xref = this.xref; michael@0: var dests = {}, nameTreeRef, nameDictionaryRef; michael@0: var obj = this.catDict.get('Names'); michael@0: if (obj) { michael@0: nameTreeRef = obj.getRaw('Dests'); michael@0: } else if (this.catDict.has('Dests')) { michael@0: nameDictionaryRef = this.catDict.get('Dests'); michael@0: } michael@0: michael@0: if (nameDictionaryRef) { michael@0: // reading simple destination dictionary michael@0: obj = nameDictionaryRef; michael@0: obj.forEach(function catalogForEach(key, value) { michael@0: if (!value) { michael@0: return; michael@0: } michael@0: dests[key] = fetchDestination(value); michael@0: }); michael@0: } michael@0: if (nameTreeRef) { michael@0: var nameTree = new NameTree(nameTreeRef, xref); michael@0: var names = nameTree.getAll(); michael@0: for (var name in names) { michael@0: if (!names.hasOwnProperty(name)) { michael@0: continue; michael@0: } michael@0: dests[name] = fetchDestination(names[name]); michael@0: } michael@0: } michael@0: return shadow(this, 'destinations', dests); michael@0: }, michael@0: get attachments() { michael@0: var xref = this.xref; michael@0: var attachments, nameTreeRef; michael@0: var obj = this.catDict.get('Names'); michael@0: if (obj) { michael@0: nameTreeRef = obj.getRaw('EmbeddedFiles'); michael@0: } michael@0: michael@0: if (nameTreeRef) { michael@0: var nameTree = new NameTree(nameTreeRef, xref); michael@0: var names = nameTree.getAll(); michael@0: for (var name in names) { michael@0: if (!names.hasOwnProperty(name)) { michael@0: continue; michael@0: } michael@0: var fs = new FileSpec(names[name], xref); michael@0: if (!attachments) { michael@0: attachments = {}; michael@0: } michael@0: attachments[stringToPDFString(name)] = fs.serializable; michael@0: } michael@0: } michael@0: return shadow(this, 'attachments', attachments); michael@0: }, michael@0: get javaScript() { michael@0: var xref = this.xref; michael@0: var obj = this.catDict.get('Names'); michael@0: michael@0: var javaScript = []; michael@0: if (obj && obj.has('JavaScript')) { michael@0: var nameTree = new NameTree(obj.getRaw('JavaScript'), xref); michael@0: var names = nameTree.getAll(); michael@0: for (var name in names) { michael@0: if (!names.hasOwnProperty(name)) { michael@0: continue; michael@0: } michael@0: // We don't really use the JavaScript right now. This code is michael@0: // defensive so we don't cause errors on document load. michael@0: var jsDict = names[name]; michael@0: if (!isDict(jsDict)) { michael@0: continue; michael@0: } michael@0: var type = jsDict.get('S'); michael@0: if (!isName(type) || type.name !== 'JavaScript') { michael@0: continue; michael@0: } michael@0: var js = jsDict.get('JS'); michael@0: if (!isString(js) && !isStream(js)) { michael@0: continue; michael@0: } michael@0: if (isStream(js)) { michael@0: js = bytesToString(js.getBytes()); michael@0: } michael@0: javaScript.push(stringToPDFString(js)); michael@0: } michael@0: } michael@0: return shadow(this, 'javaScript', javaScript); michael@0: }, michael@0: michael@0: cleanup: function Catalog_cleanup() { michael@0: this.fontCache.forEach(function (font) { michael@0: delete font.sent; michael@0: delete font.translated; michael@0: }); michael@0: this.fontCache.clear(); michael@0: }, michael@0: michael@0: getPage: function Catalog_getPage(pageIndex) { michael@0: if (!(pageIndex in this.pagePromises)) { michael@0: this.pagePromises[pageIndex] = this.getPageDict(pageIndex).then( michael@0: function (a) { michael@0: var dict = a[0]; michael@0: var ref = a[1]; michael@0: return new Page(this.pdfManager, this.xref, pageIndex, dict, ref, michael@0: this.fontCache); michael@0: }.bind(this) michael@0: ); michael@0: } michael@0: return this.pagePromises[pageIndex]; michael@0: }, michael@0: michael@0: getPageDict: function Catalog_getPageDict(pageIndex) { michael@0: var promise = new LegacyPromise(); michael@0: var nodesToVisit = [this.catDict.getRaw('Pages')]; michael@0: var currentPageIndex = 0; michael@0: var xref = this.xref; michael@0: michael@0: function next() { michael@0: while (nodesToVisit.length) { michael@0: var currentNode = nodesToVisit.pop(); michael@0: michael@0: if (isRef(currentNode)) { michael@0: xref.fetchAsync(currentNode).then(function (obj) { michael@0: if ((isDict(obj, 'Page') || (isDict(obj) && !obj.has('Kids')))) { michael@0: if (pageIndex === currentPageIndex) { michael@0: promise.resolve([obj, currentNode]); michael@0: } else { michael@0: currentPageIndex++; michael@0: next(); michael@0: } michael@0: return; michael@0: } michael@0: nodesToVisit.push(obj); michael@0: next(); michael@0: }.bind(this), promise.reject.bind(promise)); michael@0: return; michael@0: } michael@0: michael@0: // must be a child page dictionary michael@0: assert( michael@0: isDict(currentNode), michael@0: 'page dictionary kid reference points to wrong type of object' michael@0: ); michael@0: var count = currentNode.get('Count'); michael@0: // Skip nodes where the page can't be. michael@0: if (currentPageIndex + count <= pageIndex) { michael@0: currentPageIndex += count; michael@0: continue; michael@0: } michael@0: michael@0: var kids = currentNode.get('Kids'); michael@0: assert(isArray(kids), 'page dictionary kids object is not an array'); michael@0: if (count === kids.length) { michael@0: // Nodes that don't have the page have been skipped and this is the michael@0: // bottom of the tree which means the page requested must be a michael@0: // descendant of this pages node. Ideally we would just resolve the michael@0: // promise with the page ref here, but there is the case where more michael@0: // pages nodes could link to single a page (see issue 3666 pdf). To michael@0: // handle this push it back on the queue so if it is a pages node it michael@0: // will be descended into. michael@0: nodesToVisit = [kids[pageIndex - currentPageIndex]]; michael@0: currentPageIndex = pageIndex; michael@0: continue; michael@0: } else { michael@0: for (var last = kids.length - 1; last >= 0; last--) { michael@0: nodesToVisit.push(kids[last]); michael@0: } michael@0: } michael@0: } michael@0: promise.reject('Page index ' + pageIndex + ' not found.'); michael@0: } michael@0: next(); michael@0: return promise; michael@0: }, michael@0: michael@0: getPageIndex: function Catalog_getPageIndex(ref) { michael@0: // The page tree nodes have the count of all the leaves below them. To get michael@0: // how many pages are before we just have to walk up the tree and keep michael@0: // adding the count of siblings to the left of the node. michael@0: var xref = this.xref; michael@0: function pagesBeforeRef(kidRef) { michael@0: var total = 0; michael@0: var parentRef; michael@0: return xref.fetchAsync(kidRef).then(function (node) { michael@0: if (!node) { michael@0: return null; michael@0: } michael@0: parentRef = node.getRaw('Parent'); michael@0: return node.getAsync('Parent'); michael@0: }).then(function (parent) { michael@0: if (!parent) { michael@0: return null; michael@0: } michael@0: return parent.getAsync('Kids'); michael@0: }).then(function (kids) { michael@0: if (!kids) { michael@0: return null; michael@0: } michael@0: var kidPromises = []; michael@0: var found = false; michael@0: for (var i = 0; i < kids.length; i++) { michael@0: var kid = kids[i]; michael@0: assert(isRef(kid), 'kids must be a ref'); michael@0: if (kid.num == kidRef.num) { michael@0: found = true; michael@0: break; michael@0: } michael@0: kidPromises.push(xref.fetchAsync(kid).then(function (kid) { michael@0: if (kid.has('Count')) { michael@0: var count = kid.get('Count'); michael@0: total += count; michael@0: } else { // page leaf node michael@0: total++; michael@0: } michael@0: })); michael@0: } michael@0: if (!found) { michael@0: error('kid ref not found in parents kids'); michael@0: } michael@0: return Promise.all(kidPromises).then(function () { michael@0: return [total, parentRef]; michael@0: }); michael@0: }); michael@0: } michael@0: michael@0: var total = 0; michael@0: function next(ref) { michael@0: return pagesBeforeRef(ref).then(function (args) { michael@0: if (!args) { michael@0: return total; michael@0: } michael@0: var count = args[0]; michael@0: var parentRef = args[1]; michael@0: total += count; michael@0: return next(parentRef); michael@0: }); michael@0: } michael@0: michael@0: return next(ref); michael@0: } michael@0: }; michael@0: michael@0: return Catalog; michael@0: })(); michael@0: michael@0: var XRef = (function XRefClosure() { michael@0: function XRef(stream, password) { michael@0: this.stream = stream; michael@0: this.entries = []; michael@0: this.xrefstms = {}; michael@0: // prepare the XRef cache michael@0: this.cache = []; michael@0: this.password = password; michael@0: } michael@0: michael@0: XRef.prototype = { michael@0: setStartXRef: function XRef_setStartXRef(startXRef) { michael@0: // Store the starting positions of xref tables as we process them michael@0: // so we can recover from missing data errors michael@0: this.startXRefQueue = [startXRef]; michael@0: }, michael@0: michael@0: parse: function XRef_parse(recoveryMode) { michael@0: var trailerDict; michael@0: if (!recoveryMode) { michael@0: trailerDict = this.readXRef(); michael@0: } else { michael@0: warn('Indexing all PDF objects'); michael@0: trailerDict = this.indexObjects(); michael@0: } michael@0: trailerDict.assignXref(this); michael@0: this.trailer = trailerDict; michael@0: var encrypt = trailerDict.get('Encrypt'); michael@0: if (encrypt) { michael@0: var ids = trailerDict.get('ID'); michael@0: var fileId = (ids && ids.length) ? ids[0] : ''; michael@0: this.encrypt = new CipherTransformFactory(encrypt, fileId, michael@0: this.password); michael@0: } michael@0: michael@0: // get the root dictionary (catalog) object michael@0: if (!(this.root = trailerDict.get('Root'))) { michael@0: error('Invalid root reference'); michael@0: } michael@0: }, michael@0: michael@0: processXRefTable: function XRef_processXRefTable(parser) { michael@0: if (!('tableState' in this)) { michael@0: // Stores state of the table as we process it so we can resume michael@0: // from middle of table in case of missing data error michael@0: this.tableState = { michael@0: entryNum: 0, michael@0: streamPos: parser.lexer.stream.pos, michael@0: parserBuf1: parser.buf1, michael@0: parserBuf2: parser.buf2 michael@0: }; michael@0: } michael@0: michael@0: var obj = this.readXRefTable(parser); michael@0: michael@0: // Sanity check michael@0: if (!isCmd(obj, 'trailer')) { michael@0: error('Invalid XRef table: could not find trailer dictionary'); michael@0: } michael@0: // Read trailer dictionary, e.g. michael@0: // trailer michael@0: // << /Size 22 michael@0: // /Root 20R michael@0: // /Info 10R michael@0: // /ID [ <81b14aafa313db63dbd6f981e49f94f4> ] michael@0: // >> michael@0: // The parser goes through the entire stream << ... >> and provides michael@0: // a getter interface for the key-value table michael@0: var dict = parser.getObj(); michael@0: if (!isDict(dict)) { michael@0: error('Invalid XRef table: could not parse trailer dictionary'); michael@0: } michael@0: delete this.tableState; michael@0: michael@0: return dict; michael@0: }, michael@0: michael@0: readXRefTable: function XRef_readXRefTable(parser) { michael@0: // Example of cross-reference table: michael@0: // xref michael@0: // 0 1 <-- subsection header (first obj #, obj count) michael@0: // 0000000000 65535 f <-- actual object (offset, generation #, f/n) michael@0: // 23 2 <-- subsection header ... and so on ... michael@0: // 0000025518 00002 n michael@0: // 0000025635 00000 n michael@0: // trailer michael@0: // ... michael@0: michael@0: var stream = parser.lexer.stream; michael@0: var tableState = this.tableState; michael@0: stream.pos = tableState.streamPos; michael@0: parser.buf1 = tableState.parserBuf1; michael@0: parser.buf2 = tableState.parserBuf2; michael@0: michael@0: // Outer loop is over subsection headers michael@0: var obj; michael@0: michael@0: while (true) { michael@0: if (!('firstEntryNum' in tableState) || !('entryCount' in tableState)) { michael@0: if (isCmd(obj = parser.getObj(), 'trailer')) { michael@0: break; michael@0: } michael@0: tableState.firstEntryNum = obj; michael@0: tableState.entryCount = parser.getObj(); michael@0: } michael@0: michael@0: var first = tableState.firstEntryNum; michael@0: var count = tableState.entryCount; michael@0: if (!isInt(first) || !isInt(count)) { michael@0: error('Invalid XRef table: wrong types in subsection header'); michael@0: } michael@0: // Inner loop is over objects themselves michael@0: for (var i = tableState.entryNum; i < count; i++) { michael@0: tableState.streamPos = stream.pos; michael@0: tableState.entryNum = i; michael@0: tableState.parserBuf1 = parser.buf1; michael@0: tableState.parserBuf2 = parser.buf2; michael@0: michael@0: var entry = {}; michael@0: entry.offset = parser.getObj(); michael@0: entry.gen = parser.getObj(); michael@0: var type = parser.getObj(); michael@0: michael@0: if (isCmd(type, 'f')) { michael@0: entry.free = true; michael@0: } else if (isCmd(type, 'n')) { michael@0: entry.uncompressed = true; michael@0: } michael@0: michael@0: // Validate entry obj michael@0: if (!isInt(entry.offset) || !isInt(entry.gen) || michael@0: !(entry.free || entry.uncompressed)) { michael@0: console.log(entry.offset, entry.gen, entry.free, michael@0: entry.uncompressed); michael@0: error('Invalid entry in XRef subsection: ' + first + ', ' + count); michael@0: } michael@0: michael@0: if (!this.entries[i + first]) { michael@0: this.entries[i + first] = entry; michael@0: } michael@0: } michael@0: michael@0: tableState.entryNum = 0; michael@0: tableState.streamPos = stream.pos; michael@0: tableState.parserBuf1 = parser.buf1; michael@0: tableState.parserBuf2 = parser.buf2; michael@0: delete tableState.firstEntryNum; michael@0: delete tableState.entryCount; michael@0: } michael@0: michael@0: // Per issue 3248: hp scanners generate bad XRef michael@0: if (first === 1 && this.entries[1] && this.entries[1].free) { michael@0: // shifting the entries michael@0: this.entries.shift(); michael@0: } michael@0: michael@0: // Sanity check: as per spec, first object must be free michael@0: if (this.entries[0] && !this.entries[0].free) { michael@0: error('Invalid XRef table: unexpected first object'); michael@0: } michael@0: return obj; michael@0: }, michael@0: michael@0: processXRefStream: function XRef_processXRefStream(stream) { michael@0: if (!('streamState' in this)) { michael@0: // Stores state of the stream as we process it so we can resume michael@0: // from middle of stream in case of missing data error michael@0: var streamParameters = stream.dict; michael@0: var byteWidths = streamParameters.get('W'); michael@0: var range = streamParameters.get('Index'); michael@0: if (!range) { michael@0: range = [0, streamParameters.get('Size')]; michael@0: } michael@0: michael@0: this.streamState = { michael@0: entryRanges: range, michael@0: byteWidths: byteWidths, michael@0: entryNum: 0, michael@0: streamPos: stream.pos michael@0: }; michael@0: } michael@0: this.readXRefStream(stream); michael@0: delete this.streamState; michael@0: michael@0: return stream.dict; michael@0: }, michael@0: michael@0: readXRefStream: function XRef_readXRefStream(stream) { michael@0: var i, j; michael@0: var streamState = this.streamState; michael@0: stream.pos = streamState.streamPos; michael@0: michael@0: var byteWidths = streamState.byteWidths; michael@0: var typeFieldWidth = byteWidths[0]; michael@0: var offsetFieldWidth = byteWidths[1]; michael@0: var generationFieldWidth = byteWidths[2]; michael@0: michael@0: var entryRanges = streamState.entryRanges; michael@0: while (entryRanges.length > 0) { michael@0: var first = entryRanges[0]; michael@0: var n = entryRanges[1]; michael@0: michael@0: if (!isInt(first) || !isInt(n)) { michael@0: error('Invalid XRef range fields: ' + first + ', ' + n); michael@0: } michael@0: if (!isInt(typeFieldWidth) || !isInt(offsetFieldWidth) || michael@0: !isInt(generationFieldWidth)) { michael@0: error('Invalid XRef entry fields length: ' + first + ', ' + n); michael@0: } michael@0: for (i = streamState.entryNum; i < n; ++i) { michael@0: streamState.entryNum = i; michael@0: streamState.streamPos = stream.pos; michael@0: michael@0: var type = 0, offset = 0, generation = 0; michael@0: for (j = 0; j < typeFieldWidth; ++j) { michael@0: type = (type << 8) | stream.getByte(); michael@0: } michael@0: // if type field is absent, its default value is 1 michael@0: if (typeFieldWidth === 0) { michael@0: type = 1; michael@0: } michael@0: for (j = 0; j < offsetFieldWidth; ++j) { michael@0: offset = (offset << 8) | stream.getByte(); michael@0: } michael@0: for (j = 0; j < generationFieldWidth; ++j) { michael@0: generation = (generation << 8) | stream.getByte(); michael@0: } michael@0: var entry = {}; michael@0: entry.offset = offset; michael@0: entry.gen = generation; michael@0: switch (type) { michael@0: case 0: michael@0: entry.free = true; michael@0: break; michael@0: case 1: michael@0: entry.uncompressed = true; michael@0: break; michael@0: case 2: michael@0: break; michael@0: default: michael@0: error('Invalid XRef entry type: ' + type); michael@0: } michael@0: if (!this.entries[first + i]) { michael@0: this.entries[first + i] = entry; michael@0: } michael@0: } michael@0: michael@0: streamState.entryNum = 0; michael@0: streamState.streamPos = stream.pos; michael@0: entryRanges.splice(0, 2); michael@0: } michael@0: }, michael@0: michael@0: indexObjects: function XRef_indexObjects() { michael@0: // Simple scan through the PDF content to find objects, michael@0: // trailers and XRef streams. michael@0: function readToken(data, offset) { michael@0: var token = '', ch = data[offset]; michael@0: while (ch !== 13 && ch !== 10) { michael@0: if (++offset >= data.length) { michael@0: break; michael@0: } michael@0: token += String.fromCharCode(ch); michael@0: ch = data[offset]; michael@0: } michael@0: return token; michael@0: } michael@0: function skipUntil(data, offset, what) { michael@0: var length = what.length, dataLength = data.length; michael@0: var skipped = 0; michael@0: // finding byte sequence michael@0: while (offset < dataLength) { michael@0: var i = 0; michael@0: while (i < length && data[offset + i] == what[i]) { michael@0: ++i; michael@0: } michael@0: if (i >= length) { michael@0: break; // sequence found michael@0: } michael@0: offset++; michael@0: skipped++; michael@0: } michael@0: return skipped; michael@0: } michael@0: var trailerBytes = new Uint8Array([116, 114, 97, 105, 108, 101, 114]); michael@0: var startxrefBytes = new Uint8Array([115, 116, 97, 114, 116, 120, 114, michael@0: 101, 102]); michael@0: var endobjBytes = new Uint8Array([101, 110, 100, 111, 98, 106]); michael@0: var xrefBytes = new Uint8Array([47, 88, 82, 101, 102]); michael@0: michael@0: var stream = this.stream; michael@0: stream.pos = 0; michael@0: var buffer = stream.getBytes(); michael@0: var position = stream.start, length = buffer.length; michael@0: var trailers = [], xrefStms = []; michael@0: while (position < length) { michael@0: var ch = buffer[position]; michael@0: if (ch === 32 || ch === 9 || ch === 13 || ch === 10) { michael@0: ++position; michael@0: continue; michael@0: } michael@0: if (ch === 37) { // %-comment michael@0: do { michael@0: ++position; michael@0: if (position >= length) { michael@0: break; michael@0: } michael@0: ch = buffer[position]; michael@0: } while (ch !== 13 && ch !== 10); michael@0: continue; michael@0: } michael@0: var token = readToken(buffer, position); michael@0: var m; michael@0: if (token === 'xref') { michael@0: position += skipUntil(buffer, position, trailerBytes); michael@0: trailers.push(position); michael@0: position += skipUntil(buffer, position, startxrefBytes); michael@0: } else if ((m = /^(\d+)\s+(\d+)\s+obj\b/.exec(token))) { michael@0: this.entries[m[1]] = { michael@0: offset: position, michael@0: gen: m[2] | 0, michael@0: uncompressed: true michael@0: }; michael@0: michael@0: var contentLength = skipUntil(buffer, position, endobjBytes) + 7; michael@0: var content = buffer.subarray(position, position + contentLength); michael@0: michael@0: // checking XRef stream suspect michael@0: // (it shall have '/XRef' and next char is not a letter) michael@0: var xrefTagOffset = skipUntil(content, 0, xrefBytes); michael@0: if (xrefTagOffset < contentLength && michael@0: content[xrefTagOffset + 5] < 64) { michael@0: xrefStms.push(position); michael@0: this.xrefstms[position] = 1; // don't read it recursively michael@0: } michael@0: michael@0: position += contentLength; michael@0: } else { michael@0: position += token.length + 1; michael@0: } michael@0: } michael@0: // reading XRef streams michael@0: var i, ii; michael@0: for (i = 0, ii = xrefStms.length; i < ii; ++i) { michael@0: this.startXRefQueue.push(xrefStms[i]); michael@0: this.readXRef(/* recoveryMode */ true); michael@0: } michael@0: // finding main trailer michael@0: var dict; michael@0: for (i = 0, ii = trailers.length; i < ii; ++i) { michael@0: stream.pos = trailers[i]; michael@0: var parser = new Parser(new Lexer(stream), true, null); michael@0: var obj = parser.getObj(); michael@0: if (!isCmd(obj, 'trailer')) { michael@0: continue; michael@0: } michael@0: // read the trailer dictionary michael@0: if (!isDict(dict = parser.getObj())) { michael@0: continue; michael@0: } michael@0: // taking the first one with 'ID' michael@0: if (dict.has('ID')) { michael@0: return dict; michael@0: } michael@0: } michael@0: // no tailer with 'ID', taking last one (if exists) michael@0: if (dict) { michael@0: return dict; michael@0: } michael@0: // nothing helps michael@0: // calling error() would reject worker with an UnknownErrorException. michael@0: throw new InvalidPDFException('Invalid PDF structure'); michael@0: }, michael@0: michael@0: readXRef: function XRef_readXRef(recoveryMode) { michael@0: var stream = this.stream; michael@0: michael@0: try { michael@0: while (this.startXRefQueue.length) { michael@0: var startXRef = this.startXRefQueue[0]; michael@0: michael@0: stream.pos = startXRef + stream.start; michael@0: michael@0: var parser = new Parser(new Lexer(stream), true, null); michael@0: var obj = parser.getObj(); michael@0: var dict; michael@0: michael@0: // Get dictionary michael@0: if (isCmd(obj, 'xref')) { michael@0: // Parse end-of-file XRef michael@0: dict = this.processXRefTable(parser); michael@0: if (!this.topDict) { michael@0: this.topDict = dict; michael@0: } michael@0: michael@0: // Recursively get other XRefs 'XRefStm', if any michael@0: obj = dict.get('XRefStm'); michael@0: if (isInt(obj)) { michael@0: var pos = obj; michael@0: // ignore previously loaded xref streams michael@0: // (possible infinite recursion) michael@0: if (!(pos in this.xrefstms)) { michael@0: this.xrefstms[pos] = 1; michael@0: this.startXRefQueue.push(pos); michael@0: } michael@0: } michael@0: } else if (isInt(obj)) { michael@0: // Parse in-stream XRef michael@0: if (!isInt(parser.getObj()) || michael@0: !isCmd(parser.getObj(), 'obj') || michael@0: !isStream(obj = parser.getObj())) { michael@0: error('Invalid XRef stream'); michael@0: } michael@0: dict = this.processXRefStream(obj); michael@0: if (!this.topDict) { michael@0: this.topDict = dict; michael@0: } michael@0: if (!dict) { michael@0: error('Failed to read XRef stream'); michael@0: } michael@0: } else { michael@0: error('Invalid XRef stream header'); michael@0: } michael@0: michael@0: // Recursively get previous dictionary, if any michael@0: obj = dict.get('Prev'); michael@0: if (isInt(obj)) { michael@0: this.startXRefQueue.push(obj); michael@0: } else if (isRef(obj)) { michael@0: // The spec says Prev must not be a reference, i.e. "/Prev NNN" michael@0: // This is a fallback for non-compliant PDFs, i.e. "/Prev NNN 0 R" michael@0: this.startXRefQueue.push(obj.num); michael@0: } michael@0: michael@0: this.startXRefQueue.shift(); michael@0: } michael@0: michael@0: return this.topDict; michael@0: } catch (e) { michael@0: if (e instanceof MissingDataException) { michael@0: throw e; michael@0: } michael@0: info('(while reading XRef): ' + e); michael@0: } michael@0: michael@0: if (recoveryMode) { michael@0: return; michael@0: } michael@0: throw new XRefParseException(); michael@0: }, michael@0: michael@0: getEntry: function XRef_getEntry(i) { michael@0: var xrefEntry = this.entries[i]; michael@0: if (xrefEntry && !xrefEntry.free && xrefEntry.offset) { michael@0: return xrefEntry; michael@0: } michael@0: return null; michael@0: }, michael@0: michael@0: fetchIfRef: function XRef_fetchIfRef(obj) { michael@0: if (!isRef(obj)) { michael@0: return obj; michael@0: } michael@0: return this.fetch(obj); michael@0: }, michael@0: michael@0: fetch: function XRef_fetch(ref, suppressEncryption) { michael@0: assert(isRef(ref), 'ref object is not a reference'); michael@0: var num = ref.num; michael@0: if (num in this.cache) { michael@0: var cacheEntry = this.cache[num]; michael@0: return cacheEntry; michael@0: } michael@0: michael@0: var xrefEntry = this.getEntry(num); michael@0: michael@0: // the referenced entry can be free michael@0: if (xrefEntry === null) { michael@0: return (this.cache[num] = null); michael@0: } michael@0: michael@0: if (xrefEntry.uncompressed) { michael@0: xrefEntry = this.fetchUncompressed(ref, xrefEntry, suppressEncryption); michael@0: } else { michael@0: xrefEntry = this.fetchCompressed(xrefEntry, suppressEncryption); michael@0: } michael@0: michael@0: if (isDict(xrefEntry)) { michael@0: xrefEntry.objId = 'R' + ref.num + '.' + ref.gen; michael@0: } michael@0: return xrefEntry; michael@0: }, michael@0: michael@0: fetchUncompressed: function XRef_fetchUncompressed(ref, xrefEntry, michael@0: suppressEncryption) { michael@0: var gen = ref.gen; michael@0: var num = ref.num; michael@0: if (xrefEntry.gen !== gen) { michael@0: error('inconsistent generation in XRef'); michael@0: } michael@0: var stream = this.stream.makeSubStream(xrefEntry.offset + michael@0: this.stream.start); michael@0: var parser = new Parser(new Lexer(stream), true, this); michael@0: var obj1 = parser.getObj(); michael@0: var obj2 = parser.getObj(); michael@0: var obj3 = parser.getObj(); michael@0: if (!isInt(obj1) || parseInt(obj1, 10) !== num || michael@0: !isInt(obj2) || parseInt(obj2, 10) !== gen || michael@0: !isCmd(obj3)) { michael@0: error('bad XRef entry'); michael@0: } michael@0: if (!isCmd(obj3, 'obj')) { michael@0: // some bad PDFs use "obj1234" and really mean 1234 michael@0: if (obj3.cmd.indexOf('obj') === 0) { michael@0: num = parseInt(obj3.cmd.substring(3), 10); michael@0: if (!isNaN(num)) { michael@0: return num; michael@0: } michael@0: } michael@0: error('bad XRef entry'); michael@0: } michael@0: if (this.encrypt && !suppressEncryption) { michael@0: try { michael@0: xrefEntry = parser.getObj(this.encrypt.createCipherTransform(num, michael@0: gen)); michael@0: } catch (ex) { michael@0: // Almost all streams must be encrypted, but sometimes michael@0: // they are not, probably due to some broken generators. michael@0: // Retrying without encryption... michael@0: return this.fetch(ref, true); michael@0: } michael@0: } else { michael@0: xrefEntry = parser.getObj(); michael@0: } michael@0: if (!isStream(xrefEntry)) { michael@0: this.cache[num] = xrefEntry; michael@0: } michael@0: return xrefEntry; michael@0: }, michael@0: michael@0: fetchCompressed: function XRef_fetchCompressed(xrefEntry, michael@0: suppressEncryption) { michael@0: var tableOffset = xrefEntry.offset; michael@0: var stream = this.fetch(new Ref(tableOffset, 0)); michael@0: if (!isStream(stream)) { michael@0: error('bad ObjStm stream'); michael@0: } michael@0: var first = stream.dict.get('First'); michael@0: var n = stream.dict.get('N'); michael@0: if (!isInt(first) || !isInt(n)) { michael@0: error('invalid first and n parameters for ObjStm stream'); michael@0: } michael@0: var parser = new Parser(new Lexer(stream), false, this); michael@0: parser.allowStreams = true; michael@0: var i, entries = [], num, nums = []; michael@0: // read the object numbers to populate cache michael@0: for (i = 0; i < n; ++i) { michael@0: num = parser.getObj(); michael@0: if (!isInt(num)) { michael@0: error('invalid object number in the ObjStm stream: ' + num); michael@0: } michael@0: nums.push(num); michael@0: var offset = parser.getObj(); michael@0: if (!isInt(offset)) { michael@0: error('invalid object offset in the ObjStm stream: ' + offset); michael@0: } michael@0: } michael@0: // read stream objects for cache michael@0: for (i = 0; i < n; ++i) { michael@0: entries.push(parser.getObj()); michael@0: num = nums[i]; michael@0: var entry = this.entries[num]; michael@0: if (entry && entry.offset === tableOffset && entry.gen === i) { michael@0: this.cache[num] = entries[i]; michael@0: } michael@0: } michael@0: xrefEntry = entries[xrefEntry.gen]; michael@0: if (xrefEntry === undefined) { michael@0: error('bad XRef entry for compressed object'); michael@0: } michael@0: return xrefEntry; michael@0: }, michael@0: michael@0: fetchIfRefAsync: function XRef_fetchIfRefAsync(obj) { michael@0: if (!isRef(obj)) { michael@0: var promise = new LegacyPromise(); michael@0: promise.resolve(obj); michael@0: return promise; michael@0: } michael@0: return this.fetchAsync(obj); michael@0: }, michael@0: michael@0: fetchAsync: function XRef_fetchAsync(ref, suppressEncryption) { michael@0: var promise = new LegacyPromise(); michael@0: var tryFetch = function (promise) { michael@0: try { michael@0: promise.resolve(this.fetch(ref, suppressEncryption)); michael@0: } catch (e) { michael@0: if (e instanceof MissingDataException) { michael@0: this.stream.manager.requestRange(e.begin, e.end, tryFetch); michael@0: return; michael@0: } michael@0: promise.reject(e); michael@0: } michael@0: }.bind(this, promise); michael@0: tryFetch(); michael@0: return promise; michael@0: }, michael@0: michael@0: getCatalogObj: function XRef_getCatalogObj() { michael@0: return this.root; michael@0: } michael@0: }; michael@0: michael@0: return XRef; michael@0: })(); michael@0: michael@0: /** michael@0: * A NameTree is like a Dict but has some advantageous properties, see the michael@0: * spec (7.9.6) for more details. michael@0: * TODO: implement all the Dict functions and make this more efficent. michael@0: */ michael@0: var NameTree = (function NameTreeClosure() { michael@0: function NameTree(root, xref) { michael@0: this.root = root; michael@0: this.xref = xref; michael@0: } michael@0: michael@0: NameTree.prototype = { michael@0: getAll: function NameTree_getAll() { michael@0: var dict = {}; michael@0: if (!this.root) { michael@0: return dict; michael@0: } michael@0: var xref = this.xref; michael@0: // reading name tree michael@0: var processed = new RefSet(); michael@0: processed.put(this.root); michael@0: var queue = [this.root]; michael@0: while (queue.length > 0) { michael@0: var i, n; michael@0: var obj = xref.fetchIfRef(queue.shift()); michael@0: if (!isDict(obj)) { michael@0: continue; michael@0: } michael@0: if (obj.has('Kids')) { michael@0: var kids = obj.get('Kids'); michael@0: for (i = 0, n = kids.length; i < n; i++) { michael@0: var kid = kids[i]; michael@0: if (processed.has(kid)) { michael@0: error('invalid destinations'); michael@0: } michael@0: queue.push(kid); michael@0: processed.put(kid); michael@0: } michael@0: continue; michael@0: } michael@0: var names = obj.get('Names'); michael@0: if (names) { michael@0: for (i = 0, n = names.length; i < n; i += 2) { michael@0: dict[names[i]] = xref.fetchIfRef(names[i + 1]); michael@0: } michael@0: } michael@0: } michael@0: return dict; michael@0: } michael@0: }; michael@0: return NameTree; michael@0: })(); michael@0: michael@0: /** michael@0: * "A PDF file can refer to the contents of another file by using a File michael@0: * Specification (PDF 1.1)", see the spec (7.11) for more details. michael@0: * NOTE: Only embedded files are supported (as part of the attachments support) michael@0: * TODO: support the 'URL' file system (with caching if !/V), portable michael@0: * collections attributes and related files (/RF) michael@0: */ michael@0: var FileSpec = (function FileSpecClosure() { michael@0: function FileSpec(root, xref) { michael@0: if (!root || !isDict(root)) { michael@0: return; michael@0: } michael@0: this.xref = xref; michael@0: this.root = root; michael@0: if (root.has('FS')) { michael@0: this.fs = root.get('FS'); michael@0: } michael@0: this.description = root.has('Desc') ? michael@0: stringToPDFString(root.get('Desc')) : michael@0: ''; michael@0: if (root.has('RF')) { michael@0: warn('Related file specifications are not supported'); michael@0: } michael@0: this.contentAvailable = true; michael@0: if (!root.has('EF')) { michael@0: this.contentAvailable = false; michael@0: warn('Non-embedded file specifications are not supported'); michael@0: } michael@0: } michael@0: michael@0: function pickPlatformItem(dict) { michael@0: // Look for the filename in this order: michael@0: // UF, F, Unix, Mac, DOS michael@0: if (dict.has('UF')) { michael@0: return dict.get('UF'); michael@0: } else if (dict.has('F')) { michael@0: return dict.get('F'); michael@0: } else if (dict.has('Unix')) { michael@0: return dict.get('Unix'); michael@0: } else if (dict.has('Mac')) { michael@0: return dict.get('Mac'); michael@0: } else if (dict.has('DOS')) { michael@0: return dict.get('DOS'); michael@0: } else { michael@0: return null; michael@0: } michael@0: } michael@0: michael@0: FileSpec.prototype = { michael@0: get filename() { michael@0: if (!this._filename && this.root) { michael@0: var filename = pickPlatformItem(this.root) || 'unnamed'; michael@0: this._filename = stringToPDFString(filename). michael@0: replace(/\\\\/g, '\\'). michael@0: replace(/\\\//g, '/'). michael@0: replace(/\\/g, '/'); michael@0: } michael@0: return this._filename; michael@0: }, michael@0: get content() { michael@0: if (!this.contentAvailable) { michael@0: return null; michael@0: } michael@0: if (!this.contentRef && this.root) { michael@0: this.contentRef = pickPlatformItem(this.root.get('EF')); michael@0: } michael@0: var content = null; michael@0: if (this.contentRef) { michael@0: var xref = this.xref; michael@0: var fileObj = xref.fetchIfRef(this.contentRef); michael@0: if (fileObj && isStream(fileObj)) { michael@0: content = fileObj.getBytes(); michael@0: } else { michael@0: warn('Embedded file specification points to non-existing/invalid ' + michael@0: 'content'); michael@0: } michael@0: } else { michael@0: warn('Embedded file specification does not have a content'); michael@0: } michael@0: return content; michael@0: }, michael@0: get serializable() { michael@0: return { michael@0: filename: this.filename, michael@0: content: this.content michael@0: }; michael@0: } michael@0: }; michael@0: return FileSpec; michael@0: })(); michael@0: michael@0: /** michael@0: * A helper for loading missing data in object graphs. It traverses the graph michael@0: * depth first and queues up any objects that have missing data. Once it has michael@0: * has traversed as many objects that are available it attempts to bundle the michael@0: * missing data requests and then resume from the nodes that weren't ready. michael@0: * michael@0: * NOTE: It provides protection from circular references by keeping track of michael@0: * of loaded references. However, you must be careful not to load any graphs michael@0: * that have references to the catalog or other pages since that will cause the michael@0: * entire PDF document object graph to be traversed. michael@0: */ michael@0: var ObjectLoader = (function() { michael@0: function mayHaveChildren(value) { michael@0: return isRef(value) || isDict(value) || isArray(value) || isStream(value); michael@0: } michael@0: michael@0: function addChildren(node, nodesToVisit) { michael@0: var value; michael@0: if (isDict(node) || isStream(node)) { michael@0: var map; michael@0: if (isDict(node)) { michael@0: map = node.map; michael@0: } else { michael@0: map = node.dict.map; michael@0: } michael@0: for (var key in map) { michael@0: value = map[key]; michael@0: if (mayHaveChildren(value)) { michael@0: nodesToVisit.push(value); michael@0: } michael@0: } michael@0: } else if (isArray(node)) { michael@0: for (var i = 0, ii = node.length; i < ii; i++) { michael@0: value = node[i]; michael@0: if (mayHaveChildren(value)) { michael@0: nodesToVisit.push(value); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: function ObjectLoader(obj, keys, xref) { michael@0: this.obj = obj; michael@0: this.keys = keys; michael@0: this.xref = xref; michael@0: this.refSet = null; michael@0: } michael@0: michael@0: ObjectLoader.prototype = { michael@0: load: function ObjectLoader_load() { michael@0: var keys = this.keys; michael@0: this.promise = new LegacyPromise(); michael@0: // Don't walk the graph if all the data is already loaded. michael@0: if (!(this.xref.stream instanceof ChunkedStream) || michael@0: this.xref.stream.getMissingChunks().length === 0) { michael@0: this.promise.resolve(); michael@0: return this.promise; michael@0: } michael@0: michael@0: this.refSet = new RefSet(); michael@0: // Setup the initial nodes to visit. michael@0: var nodesToVisit = []; michael@0: for (var i = 0; i < keys.length; i++) { michael@0: nodesToVisit.push(this.obj[keys[i]]); michael@0: } michael@0: michael@0: this.walk(nodesToVisit); michael@0: return this.promise; michael@0: }, michael@0: michael@0: walk: function ObjectLoader_walk(nodesToVisit) { michael@0: var nodesToRevisit = []; michael@0: var pendingRequests = []; michael@0: // DFS walk of the object graph. michael@0: while (nodesToVisit.length) { michael@0: var currentNode = nodesToVisit.pop(); michael@0: michael@0: // Only references or chunked streams can cause missing data exceptions. michael@0: if (isRef(currentNode)) { michael@0: // Skip nodes that have already been visited. michael@0: if (this.refSet.has(currentNode)) { michael@0: continue; michael@0: } michael@0: try { michael@0: var ref = currentNode; michael@0: this.refSet.put(ref); michael@0: currentNode = this.xref.fetch(currentNode); michael@0: } catch (e) { michael@0: if (!(e instanceof MissingDataException)) { michael@0: throw e; michael@0: } michael@0: nodesToRevisit.push(currentNode); michael@0: pendingRequests.push({ begin: e.begin, end: e.end }); michael@0: } michael@0: } michael@0: if (currentNode && currentNode.getBaseStreams) { michael@0: var baseStreams = currentNode.getBaseStreams(); michael@0: var foundMissingData = false; michael@0: for (var i = 0; i < baseStreams.length; i++) { michael@0: var stream = baseStreams[i]; michael@0: if (stream.getMissingChunks && stream.getMissingChunks().length) { michael@0: foundMissingData = true; michael@0: pendingRequests.push({ michael@0: begin: stream.start, michael@0: end: stream.end michael@0: }); michael@0: } michael@0: } michael@0: if (foundMissingData) { michael@0: nodesToRevisit.push(currentNode); michael@0: } michael@0: } michael@0: michael@0: addChildren(currentNode, nodesToVisit); michael@0: } michael@0: michael@0: if (pendingRequests.length) { michael@0: this.xref.stream.manager.requestRanges(pendingRequests, michael@0: function pendingRequestCallback() { michael@0: nodesToVisit = nodesToRevisit; michael@0: for (var i = 0; i < nodesToRevisit.length; i++) { michael@0: var node = nodesToRevisit[i]; michael@0: // Remove any reference nodes from the currrent refset so they michael@0: // aren't skipped when we revist them. michael@0: if (isRef(node)) { michael@0: this.refSet.remove(node); michael@0: } michael@0: } michael@0: this.walk(nodesToVisit); michael@0: }.bind(this)); michael@0: return; michael@0: } michael@0: // Everything is loaded. michael@0: this.refSet = null; michael@0: this.promise.resolve(); michael@0: } michael@0: }; michael@0: michael@0: return ObjectLoader; michael@0: })(); michael@0: michael@0: michael@0: var ISOAdobeCharset = [ michael@0: '.notdef', 'space', 'exclam', 'quotedbl', 'numbersign', 'dollar', michael@0: 'percent', 'ampersand', 'quoteright', 'parenleft', 'parenright', michael@0: 'asterisk', 'plus', 'comma', 'hyphen', 'period', 'slash', 'zero', michael@0: 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', michael@0: 'nine', 'colon', 'semicolon', 'less', 'equal', 'greater', 'question', michael@0: 'at', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', michael@0: 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', michael@0: 'bracketleft', 'backslash', 'bracketright', 'asciicircum', 'underscore', michael@0: 'quoteleft', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', michael@0: 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', michael@0: 'braceleft', 'bar', 'braceright', 'asciitilde', 'exclamdown', 'cent', michael@0: 'sterling', 'fraction', 'yen', 'florin', 'section', 'currency', michael@0: 'quotesingle', 'quotedblleft', 'guillemotleft', 'guilsinglleft', michael@0: 'guilsinglright', 'fi', 'fl', 'endash', 'dagger', 'daggerdbl', michael@0: 'periodcentered', 'paragraph', 'bullet', 'quotesinglbase', michael@0: 'quotedblbase', 'quotedblright', 'guillemotright', 'ellipsis', michael@0: 'perthousand', 'questiondown', 'grave', 'acute', 'circumflex', 'tilde', michael@0: 'macron', 'breve', 'dotaccent', 'dieresis', 'ring', 'cedilla', michael@0: 'hungarumlaut', 'ogonek', 'caron', 'emdash', 'AE', 'ordfeminine', michael@0: 'Lslash', 'Oslash', 'OE', 'ordmasculine', 'ae', 'dotlessi', 'lslash', michael@0: 'oslash', 'oe', 'germandbls', 'onesuperior', 'logicalnot', 'mu', michael@0: 'trademark', 'Eth', 'onehalf', 'plusminus', 'Thorn', 'onequarter', michael@0: 'divide', 'brokenbar', 'degree', 'thorn', 'threequarters', 'twosuperior', michael@0: 'registered', 'minus', 'eth', 'multiply', 'threesuperior', 'copyright', michael@0: 'Aacute', 'Acircumflex', 'Adieresis', 'Agrave', 'Aring', 'Atilde', michael@0: 'Ccedilla', 'Eacute', 'Ecircumflex', 'Edieresis', 'Egrave', 'Iacute', michael@0: 'Icircumflex', 'Idieresis', 'Igrave', 'Ntilde', 'Oacute', 'Ocircumflex', michael@0: 'Odieresis', 'Ograve', 'Otilde', 'Scaron', 'Uacute', 'Ucircumflex', michael@0: 'Udieresis', 'Ugrave', 'Yacute', 'Ydieresis', 'Zcaron', 'aacute', michael@0: 'acircumflex', 'adieresis', 'agrave', 'aring', 'atilde', 'ccedilla', michael@0: 'eacute', 'ecircumflex', 'edieresis', 'egrave', 'iacute', 'icircumflex', michael@0: 'idieresis', 'igrave', 'ntilde', 'oacute', 'ocircumflex', 'odieresis', michael@0: 'ograve', 'otilde', 'scaron', 'uacute', 'ucircumflex', 'udieresis', michael@0: 'ugrave', 'yacute', 'ydieresis', 'zcaron' michael@0: ]; michael@0: michael@0: var ExpertCharset = [ michael@0: '.notdef', 'space', 'exclamsmall', 'Hungarumlautsmall', 'dollaroldstyle', michael@0: 'dollarsuperior', 'ampersandsmall', 'Acutesmall', 'parenleftsuperior', michael@0: 'parenrightsuperior', 'twodotenleader', 'onedotenleader', 'comma', michael@0: 'hyphen', 'period', 'fraction', 'zerooldstyle', 'oneoldstyle', michael@0: 'twooldstyle', 'threeoldstyle', 'fouroldstyle', 'fiveoldstyle', michael@0: 'sixoldstyle', 'sevenoldstyle', 'eightoldstyle', 'nineoldstyle', michael@0: 'colon', 'semicolon', 'commasuperior', 'threequartersemdash', michael@0: 'periodsuperior', 'questionsmall', 'asuperior', 'bsuperior', michael@0: 'centsuperior', 'dsuperior', 'esuperior', 'isuperior', 'lsuperior', michael@0: 'msuperior', 'nsuperior', 'osuperior', 'rsuperior', 'ssuperior', michael@0: 'tsuperior', 'ff', 'fi', 'fl', 'ffi', 'ffl', 'parenleftinferior', michael@0: 'parenrightinferior', 'Circumflexsmall', 'hyphensuperior', 'Gravesmall', michael@0: 'Asmall', 'Bsmall', 'Csmall', 'Dsmall', 'Esmall', 'Fsmall', 'Gsmall', michael@0: 'Hsmall', 'Ismall', 'Jsmall', 'Ksmall', 'Lsmall', 'Msmall', 'Nsmall', michael@0: 'Osmall', 'Psmall', 'Qsmall', 'Rsmall', 'Ssmall', 'Tsmall', 'Usmall', michael@0: 'Vsmall', 'Wsmall', 'Xsmall', 'Ysmall', 'Zsmall', 'colonmonetary', michael@0: 'onefitted', 'rupiah', 'Tildesmall', 'exclamdownsmall', 'centoldstyle', michael@0: 'Lslashsmall', 'Scaronsmall', 'Zcaronsmall', 'Dieresissmall', michael@0: 'Brevesmall', 'Caronsmall', 'Dotaccentsmall', 'Macronsmall', michael@0: 'figuredash', 'hypheninferior', 'Ogoneksmall', 'Ringsmall', michael@0: 'Cedillasmall', 'onequarter', 'onehalf', 'threequarters', michael@0: 'questiondownsmall', 'oneeighth', 'threeeighths', 'fiveeighths', michael@0: 'seveneighths', 'onethird', 'twothirds', 'zerosuperior', 'onesuperior', michael@0: 'twosuperior', 'threesuperior', 'foursuperior', 'fivesuperior', michael@0: 'sixsuperior', 'sevensuperior', 'eightsuperior', 'ninesuperior', michael@0: 'zeroinferior', 'oneinferior', 'twoinferior', 'threeinferior', michael@0: 'fourinferior', 'fiveinferior', 'sixinferior', 'seveninferior', michael@0: 'eightinferior', 'nineinferior', 'centinferior', 'dollarinferior', michael@0: 'periodinferior', 'commainferior', 'Agravesmall', 'Aacutesmall', michael@0: 'Acircumflexsmall', 'Atildesmall', 'Adieresissmall', 'Aringsmall', michael@0: 'AEsmall', 'Ccedillasmall', 'Egravesmall', 'Eacutesmall', michael@0: 'Ecircumflexsmall', 'Edieresissmall', 'Igravesmall', 'Iacutesmall', michael@0: 'Icircumflexsmall', 'Idieresissmall', 'Ethsmall', 'Ntildesmall', michael@0: 'Ogravesmall', 'Oacutesmall', 'Ocircumflexsmall', 'Otildesmall', michael@0: 'Odieresissmall', 'OEsmall', 'Oslashsmall', 'Ugravesmall', 'Uacutesmall', michael@0: 'Ucircumflexsmall', 'Udieresissmall', 'Yacutesmall', 'Thornsmall', michael@0: 'Ydieresissmall' michael@0: ]; michael@0: michael@0: var ExpertSubsetCharset = [ michael@0: '.notdef', 'space', 'dollaroldstyle', 'dollarsuperior', michael@0: 'parenleftsuperior', 'parenrightsuperior', 'twodotenleader', michael@0: 'onedotenleader', 'comma', 'hyphen', 'period', 'fraction', michael@0: 'zerooldstyle', 'oneoldstyle', 'twooldstyle', 'threeoldstyle', michael@0: 'fouroldstyle', 'fiveoldstyle', 'sixoldstyle', 'sevenoldstyle', michael@0: 'eightoldstyle', 'nineoldstyle', 'colon', 'semicolon', 'commasuperior', michael@0: 'threequartersemdash', 'periodsuperior', 'asuperior', 'bsuperior', michael@0: 'centsuperior', 'dsuperior', 'esuperior', 'isuperior', 'lsuperior', michael@0: 'msuperior', 'nsuperior', 'osuperior', 'rsuperior', 'ssuperior', michael@0: 'tsuperior', 'ff', 'fi', 'fl', 'ffi', 'ffl', 'parenleftinferior', michael@0: 'parenrightinferior', 'hyphensuperior', 'colonmonetary', 'onefitted', michael@0: 'rupiah', 'centoldstyle', 'figuredash', 'hypheninferior', 'onequarter', michael@0: 'onehalf', 'threequarters', 'oneeighth', 'threeeighths', 'fiveeighths', michael@0: 'seveneighths', 'onethird', 'twothirds', 'zerosuperior', 'onesuperior', michael@0: 'twosuperior', 'threesuperior', 'foursuperior', 'fivesuperior', michael@0: 'sixsuperior', 'sevensuperior', 'eightsuperior', 'ninesuperior', michael@0: 'zeroinferior', 'oneinferior', 'twoinferior', 'threeinferior', michael@0: 'fourinferior', 'fiveinferior', 'sixinferior', 'seveninferior', michael@0: 'eightinferior', 'nineinferior', 'centinferior', 'dollarinferior', michael@0: 'periodinferior', 'commainferior' michael@0: ]; michael@0: michael@0: michael@0: michael@0: var CIDToUnicodeMaps = { michael@0: 'Adobe-Japan1': [[32, 160], {f: 12, c: 33}, [45, 8209], {f: 46, c: 46}, 165, michael@0: {f: 2, c: 93}, [95, 818], [96, 768], {f: 27, c: 97}, 166, 125, [732, 771], michael@0: [700, 8217], 92, [699, 8216], 124, [126, 8764], {f: 3, c: 161}, 8260, 402, michael@0: 0, 164, 8220, 171, {f: 2, c: 8249}, {f: 2, c: 64257}, [8210, 8211], 0, 0, michael@0: [183, 8729], 0, 8226, 8218, 8222, 8221, 187, 0, 0, 191, {f: 2, c: 769}, michael@0: [175, 772], {f: 3, c: 774}, 778, [184, 807], 779, 808, 780, [822, 8212], michael@0: 198, 170, 321, 216, 338, 186, 230, 305, 322, 248, 339, 223, 173, 169, 172, michael@0: 174, 0, 0, {f: 2, c: 178}, 181, 185, {f: 3, c: 188}, {f: 6, c: 192}, michael@0: {f: 16, c: 199}, 0, {f: 6, c: 217}, {f: 6, c: 224}, {f: 16, c: 231}, 0, michael@0: {f: 7, c: 249}, 352, 376, 381, [773, 8254], 353, 8482, 382, 0, 8194, michael@0: {f: 59, c: 33}, 165, {f: 31, c: 93}, 65512, {f: 2, c: 125}, 0, michael@0: {f: 63, c: 65377}, {s: 243}, [8195, 12288], michael@0: {f: 2, c: 12289}, 65292, 65294, 12539, {f: 2, c: 65306}, 65311, 65281, michael@0: {f: 2, c: 12443}, 180, 65344, 168, 65342, 65507, 65343, {f: 2, c: 12541}, michael@0: {f: 2, c: 12445}, 12291, 20189, {f: 3, c: 12293}, 12540, 8213, 8208, 65295, michael@0: 65340, [12316, 65374], 8214, 65372, 8230, 8229, {s: 4}, {f: 2, c: 65288}, michael@0: {f: 2, c: 12308}, 65339, 65341, 65371, 65373, {f: 10, c: 12296}, 65291, michael@0: [8722, 65293], 177, 215, 247, 65309, 8800, 65308, 65310, {f: 2, c: 8806}, michael@0: 8734, 8756, 9794, 9792, 176, {f: 2, c: 8242}, 8451, 65509, 65284, michael@0: {f: 2, c: 65504}, 65285, 65283, 65286, 65290, 65312, 167, 9734, 9733, 9675, michael@0: 9679, 9678, 9671, 9670, 9633, 9632, 9651, 9650, 9661, 9660, 8251, 12306, michael@0: 8594, {f: 2, c: 8592}, 8595, 12307, 8712, 8715, {f: 2, c: 8838}, michael@0: {f: 2, c: 8834}, 8746, 8745, {f: 2, c: 8743}, 65506, 8658, 8660, 8704, michael@0: 8707, 8736, 8869, 8978, 8706, 8711, 8801, 8786, {f: 2, c: 8810}, 8730, michael@0: 8765, 8733, 8757, {f: 2, c: 8747}, 8491, 8240, 9839, 9837, 9834, michael@0: {f: 2, c: 8224}, 182, 9711, {f: 10, c: 65296}, {f: 26, c: 65313}, michael@0: {f: 26, c: 65345}, {f: 83, c: 12353}, {f: 86, c: 12449}, {f: 17, c: 913}, michael@0: {f: 7, c: 931}, {f: 17, c: 945}, {f: 7, c: 963}, {f: 6, c: 1040}, 1025, michael@0: {f: 32, c: 1046}, 1105, {f: 26, c: 1078}, 20124, 21782, 23043, 38463, michael@0: 21696, 24859, 25384, 23030, 36898, 33909, 33564, 31312, 24746, 25569, michael@0: 28197, 26093, 33894, 33446, 39925, 26771, 22311, 26017, 25201, 23451, michael@0: 22992, 34427, 39156, 32098, 32190, 39822, 25110, 31903, 34999, 23433, michael@0: 24245, 25353, 26263, 26696, 38343, 38797, 26447, 20197, 20234, 20301, michael@0: 20381, 20553, 22258, 22839, 22996, 23041, 23561, 24799, 24847, 24944, michael@0: 26131, 26885, 28858, 30031, 30064, 31227, 32173, 32239, 32963, 33806, michael@0: [12176, 34915], 35586, 36949, 36986, 21307, 20117, 20133, 22495, 32946, michael@0: 37057, 30959, [12032, 19968], 22769, 28322, 36920, 31282, 33576, 33419, michael@0: 39983, 20801, 21360, 21693, 21729, 22240, 23035, 24341, 39154, 28139, michael@0: 32996, 34093, 38498, 38512, 38560, 38907, 21515, 21491, 23431, 28879, michael@0: [12155, 32701], 36802, [12204, 38632], 21359, 40284, 31418, 19985, 30867, michael@0: [12165, 33276], 28198, 22040, 21764, 27421, 34074, 39995, 23013, 21417, michael@0: 28006, [12128, 29916], 38287, 22082, 20113, 36939, 38642, 33615, 39180, michael@0: 21473, 21942, 23344, 24433, 26144, 26355, 26628, 27704, 27891, 27945, michael@0: 29787, 30408, 31310, 38964, 33521, 34907, 35424, 37613, 28082, 30123, michael@0: 30410, 39365, 24742, 35585, 36234, 38322, 27022, 21421, 20870, 22290, michael@0: 22576, 22852, 23476, 24310, 24616, 25513, 25588, 27839, 28436, 28814, michael@0: 28948, 29017, 29141, 29503, 32257, 33398, 33489, 34199, 36960, 37467, michael@0: 40219, 22633, 26044, 27738, 29989, 20985, 22830, 22885, 24448, 24540, michael@0: 25276, 26106, 27178, 27431, 27572, 29579, 32705, 35158, 40236, 40206, michael@0: [12009, 40644], 23713, 27798, 33659, 20740, 23627, 25014, 33222, 26742, michael@0: 29281, [12036, 20057], 20474, 21368, 24681, 28201, 31311, [12211, 38899], michael@0: 19979, 21270, 20206, 20309, 20285, 20385, 20339, 21152, 21487, 22025, michael@0: 22799, 23233, 23478, 23521, 31185, 26247, 26524, 26550, 27468, 27827, michael@0: [12117, 28779], 29634, 31117, [12146, 31166], 31292, 31623, 33457, 33499, michael@0: 33540, 33655, 33775, 33747, 34662, 35506, 22057, 36008, 36838, 36942, michael@0: 38686, 34442, 20420, 23784, 25105, [12123, 29273], 30011, 33253, 33469, michael@0: 34558, 36032, 38597, 39187, 39381, 20171, 20250, 35299, 22238, 22602, michael@0: 22730, 24315, 24555, 24618, 24724, 24674, 25040, 25106, 25296, 25913, michael@0: 39745, 26214, 26800, 28023, 28784, 30028, 30342, 32117, 33445, 34809, michael@0: 38283, 38542, [12185, 35997], 20977, 21182, 22806, 21683, 23475, 23830, michael@0: 24936, 27010, 28079, 30861, 33995, 34903, 35442, 37799, 39608, 28012, michael@0: 39336, 34521, 22435, 26623, 34510, 37390, 21123, 22151, 21508, 24275, michael@0: 25313, 25785, 26684, 26680, 27579, 29554, 30906, 31339, 35226, michael@0: [12179, 35282], 36203, 36611, 37101, 38307, 38548, [12208, 38761], 23398, michael@0: 23731, 27005, {f: 2, c: 38989}, 25499, 31520, 27179, 27263, 26806, 39949, michael@0: 28511, 21106, 21917, 24688, 25324, 27963, 28167, 28369, 33883, 35088, michael@0: 36676, 19988, 39993, 21494, 26907, 27194, 38788, 26666, 20828, 31427, michael@0: 33970, 37340, 37772, 22107, 40232, 26658, 33541, 33841, 31909, 21000, michael@0: 33477, [12129, 29926], 20094, 20355, 20896, 23506, 21002, 21208, 21223, michael@0: 24059, 21914, 22570, 23014, 23436, 23448, 23515, [12082, 24178], 24185, michael@0: 24739, 24863, 24931, 25022, 25563, 25954, 26577, 26707, 26874, 27454, michael@0: 27475, 27735, 28450, 28567, 28485, 29872, [12130, 29976], 30435, 30475, michael@0: 31487, 31649, 31777, 32233, [12152, 32566], 32752, 32925, 33382, 33694, michael@0: 35251, 35532, 36011, 36996, 37969, 38291, 38289, 38306, 38501, 38867, michael@0: 39208, 33304, 20024, 21547, 23736, 24012, 29609, 30284, 30524, 23721, michael@0: 32747, 36107, 38593, 38929, 38996, 39000, 20225, 20238, 21361, 21916, michael@0: 22120, 22522, 22855, 23305, 23492, 23696, 24076, 24190, 24524, 25582, michael@0: 26426, 26071, 26082, 26399, 26827, 26820, 27231, 24112, 27589, 27671, michael@0: 27773, 30079, 31048, 23395, 31232, 32000, 24509, 35215, 35352, 36020, michael@0: 36215, 36556, 36637, 39138, 39438, [12004, 12225, 39740], [12018, 20096], michael@0: 20605, 20736, 22931, 23452, 25135, 25216, 25836, 27450, 29344, 30097, michael@0: 31047, 32681, 34811, 35516, 35696, 25516, 33738, 38816, 21513, 21507, michael@0: 21931, 26708, 27224, 35440, 30759, 26485, [12233, 40653], 21364, 23458, michael@0: 33050, 34384, 36870, 19992, 20037, 20167, 20241, 21450, 21560, 23470, michael@0: [12088, 24339], 24613, 25937, 26429, 27714, 27762, 27875, 28792, 29699, michael@0: 31350, 31406, 31496, 32026, 31998, 32102, 26087, [12124, 29275], 21435, michael@0: 23621, 24040, 25298, 25312, 25369, 28192, 34394, 35377, 36317, 37624, michael@0: 28417, 31142, [12226, 39770], 20136, {f: 2, c: 20139}, 20379, 20384, 20689, michael@0: 20807, 31478, 20849, 20982, 21332, 21281, 21375, 21483, 21932, 22659, michael@0: 23777, 24375, 24394, 24623, 24656, 24685, 25375, 25945, 27211, 27841, michael@0: 29378, 29421, 30703, 33016, 33029, 33288, 34126, 37111, 37857, 38911, michael@0: 39255, 39514, 20208, 20957, 23597, 26241, 26989, 23616, 26354, 26997, michael@0: [12127, 29577], 26704, 31873, 20677, 21220, 22343, [12081, 24062], 37670, michael@0: [12100, 26020], 27427, 27453, 29748, 31105, 31165, 31563, 32202, 33465, michael@0: 33740, 34943, 35167, 35641, 36817, [12198, 37329], 21535, 37504, 20061, michael@0: 20534, 21477, 21306, 29399, 29590, 30697, 33510, 36527, 39366, 39368, michael@0: 39378, 20855, 24858, 34398, 21936, 31354, 20598, 23507, 36935, 38533, michael@0: 20018, 27355, 37351, 23633, 23624, 25496, 31391, 27795, 38772, 36705, michael@0: 31402, 29066, 38536, 31874, 26647, 32368, 26705, 37740, 21234, 21531, michael@0: 34219, 35347, 32676, 36557, 37089, 21350, 34952, 31041, 20418, 20670, michael@0: 21009, 20804, 21843, 22317, 29674, 22411, 22865, 24418, 24452, 24693, michael@0: 24950, 24935, 25001, 25522, 25658, 25964, 26223, 26690, 28179, 30054, michael@0: 31293, 31995, 32076, 32153, 32331, 32619, 33550, 33610, 34509, 35336, michael@0: 35427, 35686, 36605, 38938, 40335, 33464, 36814, 39912, 21127, 25119, michael@0: 25731, 28608, 38553, 26689, 20625, [12107, 27424], 27770, 28500, michael@0: [12147, 31348], 32080, [12174, 34880], 35363, [12105, 26376], 20214, 20537, michael@0: 20518, 20581, 20860, 21048, 21091, 21927, 22287, 22533, 23244, 24314, michael@0: 25010, 25080, 25331, 25458, 26908, 27177, 29309, [12125, 29356], 29486, michael@0: 30740, 30831, 32121, 30476, 32937, [12178, 35211], 35609, 36066, 36562, michael@0: 36963, 37749, 38522, 38997, 39443, 40568, 20803, 21407, 21427, 24187, michael@0: 24358, 28187, 28304, [12126, 29572], 29694, 32067, 33335, [12180, 35328], michael@0: 35578, 38480, 20046, 20491, 21476, 21628, 22266, 22993, 23396, michael@0: [12080, 24049], 24235, 24359, [12094, 25144], 25925, 26543, 28246, 29392, michael@0: 31946, 34996, 32929, 32993, 33776, [11969, 34382], 35463, 36328, 37431, michael@0: 38599, 39015, [12238, 40723], 20116, 20114, 20237, 21320, 21577, 21566, michael@0: 23087, 24460, 24481, 24735, 26791, 27278, 29786, 30849, 35486, 35492, michael@0: 35703, 37264, 20062, 39881, 20132, 20348, 20399, 20505, 20502, 20809, michael@0: 20844, 21151, 21177, 21246, 21402, [12061, 21475], 21521, 21518, 21897, michael@0: 22353, 22434, 22909, 23380, 23389, 23439, [12079, 24037], 24039, 24055, michael@0: 24184, 24195, 24218, 24247, 24344, 24658, 24908, 25239, 25304, 25511, michael@0: 25915, 26114, 26179, 26356, 26477, 26657, 26775, 27083, 27743, 27946, michael@0: 28009, 28207, 28317, 30002, 30343, 30828, 31295, 31968, 32005, 32024, michael@0: 32094, 32177, 32789, 32771, 32943, 32945, 33108, 33167, 33322, 33618, michael@0: [12175, 34892], 34913, 35611, 36002, 36092, 37066, 37237, 37489, 30783, michael@0: 37628, 38308, 38477, 38917, [12217, 39321], [12220, 39640], 40251, 21083, michael@0: 21163, 21495, 21512, 22741, 25335, 28640, 35946, 36703, 40633, 20811, michael@0: 21051, 21578, 22269, 31296, 37239, 40288, [12234, 40658], 29508, 28425, michael@0: 33136, 29969, 24573, 24794, [12219, 39592], 29403, 36796, 27492, 38915, michael@0: 20170, 22256, 22372, 22718, 23130, 24680, 25031, 26127, 26118, 26681, michael@0: 26801, 28151, 30165, 32058, [12169, 33390], 39746, 20123, 20304, 21449, michael@0: 21766, 23919, 24038, 24046, 26619, 27801, 29811, 30722, 35408, 37782, michael@0: 35039, 22352, 24231, 25387, 20661, 20652, 20877, 26368, 21705, 22622, michael@0: 22971, 23472, 24425, 25165, 25505, 26685, 27507, 28168, 28797, 37319, michael@0: 29312, 30741, 30758, 31085, 25998, 32048, 33756, 35009, 36617, 38555, michael@0: 21092, 22312, 26448, 32618, 36001, 20916, 22338, 38442, 22586, 27018, michael@0: 32948, 21682, 23822, 22524, 30869, 40442, 20316, 21066, 21643, 25662, michael@0: 26152, 26388, 26613, 31364, 31574, 32034, 37679, 26716, 39853, 31545, michael@0: 21273, 20874, 21047, 23519, 25334, 25774, 25830, 26413, 27578, 34217, michael@0: 38609, 30352, 39894, 25420, 37638, 39851, [12139, 30399], 26194, 19977, michael@0: 20632, 21442, [12077, 23665], 24808, 25746, 25955, 26719, 29158, 29642, michael@0: 29987, 31639, 32386, 34453, 35715, 36059, 37240, 39184, 26028, 26283, michael@0: 27531, 20181, 20180, 20282, 20351, 21050, 21496, 21490, 21987, 22235, michael@0: [12064, 22763], 22987, 22985, 23039, [12070, 23376], 23629, 24066, 24107, michael@0: 24535, 24605, 25351, [12096, 25903], 23388, 26031, 26045, 26088, 26525, michael@0: [12108, 27490], 27515, [12114, 27663], 29509, 31049, 31169, [12151, 31992], michael@0: 32025, 32043, 32930, 33026, [12164, 33267], 35222, 35422, 35433, 35430, michael@0: 35468, 35566, 36039, 36060, 38604, 39164, [12013, 27503], 20107, 20284, michael@0: 20365, 20816, 23383, 23546, 24904, 25345, 26178, 27425, 28363, 27835, michael@0: 29246, 29885, 30164, 30913, [12144, 31034], [12157, 32780], [12159, 32819], michael@0: [12163, 33258], 33940, 36766, 27728, [12229, 40575], 24335, 35672, 40235, michael@0: 31482, 36600, 23437, 38635, 19971, 21489, 22519, 22833, 23241, 23460, michael@0: 24713, 28287, 28422, 30142, 36074, 23455, 34048, 31712, 20594, 26612, michael@0: 33437, 23649, 34122, 32286, 33294, 20889, 23556, 25448, 36198, 26012, michael@0: 29038, 31038, 32023, 32773, 35613, [12190, 36554], 36974, 34503, 37034, michael@0: 20511, 21242, 23610, 26451, 28796, 29237, 37196, 37320, 37675, 33509, michael@0: 23490, 24369, 24825, 20027, 21462, 23432, [12095, 25163], 26417, 27530, michael@0: 29417, 29664, 31278, 33131, 36259, 37202, [12216, 39318], 20754, 21463, michael@0: 21610, 23551, 25480, 27193, 32172, 38656, 22234, 21454, 21608, 23447, michael@0: 23601, 24030, 20462, 24833, 25342, 27954, 31168, 31179, 32066, 32333, michael@0: 32722, 33261, [12168, 33311], 33936, 34886, 35186, 35728, 36468, 36655, michael@0: 36913, 37195, 37228, 38598, 37276, 20160, 20303, 20805, [12055, 21313], michael@0: 24467, 25102, 26580, 27713, 28171, 29539, 32294, 37325, 37507, 21460, michael@0: 22809, 23487, 28113, 31069, 32302, 31899, 22654, 29087, 20986, 34899, michael@0: 36848, 20426, 23803, 26149, 30636, 31459, 33308, 39423, 20934, 24490, michael@0: 26092, 26991, 27529, 28147, 28310, 28516, 30462, 32020, 24033, 36981, michael@0: 37255, 38918, 20966, 21021, 25152, 26257, 26329, 28186, 24246, 32210, michael@0: 32626, 26360, 34223, 34295, 35576, 21161, 21465, [12069, 22899], 24207, michael@0: 24464, 24661, 37604, 38500, 20663, 20767, 21213, 21280, 21319, 21484, michael@0: 21736, 21830, 21809, 22039, 22888, 22974, 23100, 23477, 23558, michael@0: [12073, 23567], 23569, 23578, 24196, 24202, 24288, 24432, 25215, 25220, michael@0: 25307, 25484, 25463, 26119, 26124, 26157, 26230, 26494, 26786, 27167, michael@0: 27189, 27836, 28040, 28169, 28248, 28988, 28966, 29031, 30151, 30465, michael@0: 30813, 30977, 31077, 31216, 31456, 31505, 31911, 32057, 32918, 33750, michael@0: 33931, 34121, 34909, 35059, 35359, 35388, 35412, 35443, 35937, 36062, michael@0: 37284, 37478, 37758, 37912, 38556, 38808, 19978, 19976, 19998, 20055, michael@0: 20887, 21104, 22478, 22580, 22732, 23330, 24120, 24773, 25854, 26465, michael@0: 26454, 27972, 29366, 30067, 31331, 33976, 35698, 37304, 37664, 22065, michael@0: 22516, 39166, 25325, 26893, 27542, 29165, 32340, 32887, [12170, 33394], michael@0: 35302, [12215, 39135], 34645, 36785, 23611, 20280, 20449, 20405, 21767, michael@0: 23072, 23517, 23529, [12092, 24515], 24910, 25391, 26032, 26187, 26862, michael@0: 27035, 28024, 28145, 30003, 30137, 30495, 31070, 31206, 32051, michael@0: [12162, 33251], 33455, 34218, 35242, 35386, [12189, 36523], [12191, 36763], michael@0: 36914, 37341, 38663, [12040, 20154], 20161, 20995, 22645, 22764, 23563, michael@0: 29978, 23613, 33102, 35338, 36805, 38499, 38765, 31525, 35535, 38920, michael@0: 37218, 22259, 21416, 36887, 21561, 22402, 24101, 25512, [12116, 27700], michael@0: 28810, 30561, 31883, 32736, 34928, 36930, 37204, 37648, 37656, 38543, michael@0: 29790, 39620, 23815, 23913, 25968, 26530, 36264, 38619, 25454, 26441, michael@0: 26905, 33733, 38935, 38592, 35070, 28548, 25722, [12072, 23544], 19990, michael@0: 28716, 30045, 26159, 20932, 21046, 21218, 22995, 24449, 24615, 25104, michael@0: 25919, 25972, 26143, 26228, 26866, 26646, 27491, 28165, 29298, michael@0: [12131, 29983], 30427, 31934, 32854, 22768, 35069, [11972, 35199], 35488, michael@0: 35475, 35531, 36893, 37266, [11992, 38738], 38745, [12011, 25993], 31246, michael@0: 33030, 38587, 24109, 24796, 25114, 26021, 26132, 26512, [12143, 30707], michael@0: 31309, 31821, 32318, 33034, 36012, [12186, 36196], 36321, 36447, 30889, michael@0: 20999, 25305, 25509, 25666, 25240, 35373, 31363, 31680, 35500, 38634, michael@0: 32118, [12166, 33292], 34633, 20185, 20808, 21315, 21344, 23459, 23554, michael@0: 23574, 24029, 25126, 25159, 25776, 26643, 26676, 27849, 27973, 27927, michael@0: 26579, 28508, 29006, 29053, 26059, 31359, 31661, 32218, 32330, 32680, michael@0: 33146, [12167, 33307], 33337, 34214, 35438, 36046, 36341, 36984, 36983, michael@0: 37549, 37521, 38275, 39854, 21069, 21892, 28472, 28982, 20840, 31109, michael@0: 32341, 33203, 31950, 22092, 22609, 23720, 25514, 26366, 26365, 26970, michael@0: 29401, 30095, 30094, 30990, 31062, 31199, 31895, 32032, 32068, 34311, michael@0: 35380, 38459, 36961, [12239, 40736], 20711, 21109, 21452, 21474, 20489, michael@0: 21930, 22766, 22863, 29245, 23435, 23652, 21277, 24803, 24819, 25436, michael@0: 25475, 25407, 25531, 25805, 26089, 26361, 24035, 27085, 27133, 28437, michael@0: 29157, 20105, 30185, 30456, 31379, 31967, 32207, 32156, 32865, 33609, michael@0: 33624, 33900, 33980, 34299, 35013, [12187, 36208], 36865, 36973, 37783, michael@0: 38684, 39442, 20687, 22679, 24974, 33235, 34101, 36104, 36896, 20419, michael@0: 20596, 21063, 21363, 24687, 25417, 26463, 28204, [12188, 36275], 36895, michael@0: 20439, 23646, 36042, 26063, 32154, 21330, 34966, 20854, 25539, 23384, michael@0: 23403, 23562, 25613, 26449, 36956, 20182, 22810, 22826, 27760, 35409, michael@0: 21822, 22549, 22949, 24816, 25171, 26561, 33333, 26965, 38464, 39364, michael@0: 39464, 20307, 22534, 23550, 32784, 23729, 24111, 24453, 24608, 24907, michael@0: 25140, 26367, 27888, 28382, 32974, 33151, 33492, 34955, 36024, 36864, michael@0: 36910, 38538, 40667, 39899, 20195, 21488, [12068, 22823], 31532, 37261, michael@0: 38988, 40441, 28381, 28711, 21331, 21828, 23429, 25176, 25246, 25299, michael@0: 27810, 28655, 29730, 35351, 37944, 28609, 35582, 33592, 20967, 34552, michael@0: 21482, 21481, 20294, 36948, [12192, 36784], 22890, 33073, 24061, 31466, michael@0: 36799, 26842, [12181, 35895], 29432, 40008, 27197, 35504, 20025, 21336, michael@0: 22022, 22374, 25285, 25506, 26086, 27470, 28129, 28251, 28845, 30701, michael@0: 31471, 31658, 32187, 32829, 32966, 34507, 35477, 37723, 22243, 22727, michael@0: 24382, 26029, 26262, 27264, 27573, 30007, 35527, 20516, 30693, 22320, michael@0: 24347, 24677, 26234, 27744, 30196, 31258, 32622, 33268, 34584, 36933, michael@0: 39347, 31689, 30044, [12149, 31481], 31569, 33988, 36880, 31209, 31378, michael@0: 33590, 23265, 30528, 20013, 20210, 23449, 24544, 25277, 26172, 26609, michael@0: 27880, [12173, 34411], 34935, 35387, 37198, 37619, 39376, 27159, 28710, michael@0: 29482, 33511, 33879, 36015, 19969, 20806, 20939, 21899, 23541, 24086, michael@0: 24115, 24193, 24340, 24373, 24427, 24500, 25074, 25361, 26274, 26397, michael@0: 28526, 29266, 30010, 30522, 32884, 33081, 33144, 34678, 35519, 35548, michael@0: 36229, 36339, 37530, [11985, 12199, 38263], 38914, [12227, 40165], 21189, michael@0: 25431, 30452, 26389, 27784, 29645, 36035, 37806, 38515, 27941, 22684, michael@0: 26894, 27084, 36861, 37786, 30171, 36890, 22618, 26626, 25524, 27131, michael@0: 20291, 28460, 26584, 36795, 34086, 32180, 37716, 26943, 28528, 22378, michael@0: 22775, 23340, 32044, [12118, 29226], 21514, 37347, 40372, 20141, 20302, michael@0: 20572, 20597, 21059, 35998, 21576, 22564, 23450, 24093, 24213, 24237, michael@0: 24311, 24351, 24716, 25269, 25402, 25552, 26799, 27712, 30855, 31118, michael@0: 31243, 32224, 33351, 35330, 35558, 36420, 36883, 37048, 37165, 37336, michael@0: [12237, 40718], 27877, 25688, 25826, 25973, 28404, 30340, 31515, 36969, michael@0: 37841, 28346, 21746, 24505, 25764, 36685, 36845, 37444, 20856, 22635, michael@0: 22825, 23637, 24215, 28155, 32399, 29980, 36028, 36578, 39003, 28857, michael@0: 20253, 27583, 28593, [12133, 30000], 38651, 20814, 21520, 22581, 22615, michael@0: 22956, 23648, 24466, [12099, 26007], 26460, 28193, 30331, 33759, 36077, michael@0: 36884, 37117, 37709, 30757, 30778, 21162, 24230, [12063, 22303], 22900, michael@0: 24594, 20498, 20826, 20908, 20941, [12049, 20992], 21776, 22612, 22616, michael@0: 22871, 23445, 23798, 23947, 24764, 25237, 25645, 26481, 26691, 26812, michael@0: 26847, 30423, 28120, 28271, 28059, 28783, 29128, 24403, 30168, 31095, michael@0: 31561, 31572, 31570, 31958, 32113, 21040, 33891, 34153, 34276, 35342, michael@0: 35588, [12182, 35910], 36367, 36867, 36879, 37913, 38518, 38957, 39472, michael@0: 38360, 20685, 21205, 21516, 22530, 23566, 24999, 25758, 27934, 30643, michael@0: 31461, 33012, 33796, 36947, 37509, 23776, 40199, 21311, 24471, 24499, michael@0: 28060, 29305, 30563, 31167, 31716, 27602, 29420, 35501, 26627, 27233, michael@0: 20984, 31361, 26932, 23626, 40182, 33515, 23493, [12195, 37193], 28702, michael@0: 22136, 23663, 24775, 25958, 27788, 35930, 36929, 38931, 21585, 26311, michael@0: 37389, 22856, 37027, 20869, 20045, 20970, 34201, 35598, 28760, 25466, michael@0: 37707, 26978, 39348, 32260, 30071, 21335, 26976, 36575, 38627, 27741, michael@0: [12038, 20108], 23612, 24336, 36841, 21250, 36049, [12161, 32905], 34425, michael@0: 24319, [12103, 26085], 20083, [12042, 20837], 22914, 23615, 38894, 20219, michael@0: 22922, 24525, 35469, 28641, 31152, 31074, 23527, 33905, 29483, 29105, michael@0: 24180, 24565, 25467, 25754, 29123, 31896, 20035, 24316, 20043, 22492, michael@0: 22178, 24745, 28611, 32013, 33021, 33075, 33215, 36786, 35223, 34468, michael@0: 24052, 25226, 25773, 35207, 26487, 27874, 27966, 29750, 30772, 23110, michael@0: 32629, 33453, [12218, 39340], 20467, 24259, 25309, 25490, 25943, 26479, michael@0: 30403, 29260, 32972, 32954, 36649, 37197, 20493, 22521, 23186, 26757, michael@0: 26995, 29028, 29437, 36023, 22770, 36064, 38506, 36889, 34687, 31204, michael@0: 30695, 33833, 20271, 21093, 21338, 25293, 26575, 27850, [12137, 30333], michael@0: 31636, 31893, 33334, 34180, 36843, 26333, 28448, 29190, 32283, 33707, michael@0: 39361, [12008, 40614], 20989, 31665, 30834, 31672, 32903, 31560, 27368, michael@0: 24161, 32908, 30033, 30048, [12043, 20843], 37474, 28300, 30330, 37271, michael@0: 39658, 20240, 32624, 25244, 31567, 38309, 40169, 22138, 22617, 34532, michael@0: 38588, 20276, 21028, 21322, 21453, 21467, 24070, 25644, 26001, 26495, michael@0: 27710, 27726, 29256, 29359, 29677, 30036, 32321, 33324, 34281, 36009, michael@0: 31684, [12196, 37318], 29033, 38930, 39151, 25405, 26217, 30058, 30436, michael@0: 30928, 34115, 34542, 21290, 21329, 21542, 22915, 24199, 24444, 24754, michael@0: 25161, 25209, 25259, 26000, [12112, 27604], 27852, 30130, [12138, 30382], michael@0: 30865, 31192, 32203, 32631, 32933, 34987, 35513, 36027, 36991, michael@0: [12206, 38750], [12214, 39131], 27147, 31800, 20633, 23614, 24494, 26503, michael@0: 27608, 29749, 30473, 32654, [12240, 40763], 26570, 31255, 21305, michael@0: [12134, 30091], 39661, 24422, 33181, 33777, 32920, 24380, 24517, 30050, michael@0: 31558, 36924, 26727, 23019, 23195, 32016, 30334, 35628, 20469, 24426, michael@0: 27161, 27703, 28418, 29922, 31080, 34920, 35413, 35961, 24287, 25551, michael@0: 30149, 31186, 33495, 37672, 37618, 33948, 34541, 39981, 21697, 24428, michael@0: 25996, 27996, 28693, 36007, 36051, 38971, 25935, 29942, 19981, 20184, michael@0: 22496, 22827, 23142, 23500, 20904, 24067, 24220, 24598, 25206, 25975, michael@0: 26023, 26222, 28014, [12119, 29238], 31526, 33104, 33178, 33433, 35676, michael@0: 36000, 36070, 36212, [12201, 38428], 38468, 20398, 25771, 27494, 33310, michael@0: 33889, 34154, 37096, 23553, 26963, [12213, 39080], 33914, 34135, 20239, michael@0: 21103, 24489, 24133, 26381, 31119, 33145, 35079, 35206, 28149, 24343, michael@0: 25173, 27832, 20175, 29289, 39826, 20998, 21563, 22132, 22707, 24996, michael@0: 25198, 28954, 22894, 31881, 31966, 32027, 38640, [12098, 25991], 32862, michael@0: 19993, 20341, 20853, 22592, 24163, 24179, 24330, 26564, 20006, 34109, michael@0: 38281, 38491, [12150, 31859], [12212, 38913], 20731, 22721, 30294, 30887, michael@0: 21029, 30629, 34065, 31622, 20559, 22793, [12122, 29255], 31687, 32232, michael@0: 36794, 36820, 36941, 20415, 21193, 23081, 24321, 38829, 20445, 33303, michael@0: 37610, 22275, 25429, 27497, 29995, 35036, 36628, 31298, 21215, 22675, michael@0: 24917, 25098, 26286, [11935, 27597], 31807, 33769, 20515, 20472, 21253, michael@0: 21574, 22577, 22857, 23453, 23792, 23791, 23849, 24214, 25265, 25447, michael@0: 25918, [12101, 26041], 26379, 27861, 27873, 28921, 30770, 32299, 32990, michael@0: 33459, 33804, 34028, 34562, 35090, 35370, 35914, 37030, 37586, 39165, michael@0: 40179, 40300, 20047, 20129, 20621, 21078, 22346, 22952, 24125, michael@0: {f: 2, c: 24536}, 25151, 26292, 26395, 26576, 26834, 20882, 32033, 32938, michael@0: 33192, 35584, 35980, 36031, 37502, 38450, 21536, 38956, 21271, 20693, michael@0: [12056, 21340], 22696, 25778, 26420, 29287, 30566, 31302, 37350, 21187, michael@0: 27809, 27526, 22528, 24140, 22868, 26412, 32763, 20961, 30406, 25705, michael@0: 30952, 39764, [12231, 40635], 22475, 22969, 26151, 26522, 27598, 21737, michael@0: 27097, 24149, 33180, 26517, 39850, 26622, 40018, 26717, 20134, 20451, michael@0: [12060, 21448], 25273, 26411, 27819, 36804, 20397, 32365, 40639, 19975, michael@0: 24930, 28288, 28459, 34067, 21619, 26410, 39749, [11922, 24051], 31637, michael@0: 23724, 23494, 34588, 28234, 34001, 31252, 33032, 22937, 31885, michael@0: [11936, 27665], 30496, 21209, 22818, 28961, 29279, [12141, 30683], 38695, michael@0: 40289, 26891, 23167, 23064, 20901, 21517, 21629, 26126, 30431, 36855, michael@0: 37528, 40180, 23018, 29277, 28357, 20813, 26825, 32191, 32236, michael@0: [12207, 38754], 40634, 25720, 27169, 33538, 22916, 23391, [12113, 27611], michael@0: 29467, 30450, 32178, 32791, 33945, 20786, [12106, 26408], 40665, michael@0: [12140, 30446], 26466, 21247, 39173, 23588, 25147, 31870, 36016, 21839, michael@0: 24758, 32011, [12200, 38272], 21249, 20063, 20918, 22812, 29242, 32822, michael@0: 37326, 24357, [12142, 30690], 21380, 24441, 32004, 34220, 35379, 36493, michael@0: 38742, 26611, 34222, 37971, 24841, 24840, 27833, 30290, 35565, 36664, michael@0: 21807, 20305, 20778, 21191, 21451, 23461, 24189, 24736, 24962, 25558, michael@0: 26377, 26586, 28263, 28044, {f: 2, c: 29494}, 30001, 31056, 35029, 35480, michael@0: 36938, [12194, 37009], 37109, 38596, 34701, [12067, 22805], 20104, 20313, michael@0: 19982, 35465, 36671, 38928, 20653, 24188, 22934, 23481, 24248, 25562, michael@0: 25594, 25793, 26332, 26954, 27096, 27915, 28342, 29076, [12132, 29992], michael@0: 31407, [12154, 32650], 32768, 33865, 33993, 35201, 35617, 36362, 36965, michael@0: 38525, 39178, 24958, 25233, 27442, 27779, 28020, 32716, 32764, 28096, michael@0: 32645, 34746, 35064, 26469, 33713, 38972, 38647, 27931, 32097, 33853, michael@0: 37226, 20081, 21365, 23888, 27396, 28651, 34253, 34349, 35239, 21033, michael@0: 21519, 23653, 26446, 26792, 29702, 29827, 30178, 35023, 35041, michael@0: [12197, 37324], 38626, 38520, 24459, 29575, [12148, 31435], 33870, 25504, michael@0: 30053, 21129, 27969, 28316, 29705, 30041, 30827, 31890, 38534, michael@0: [12015, 31452], [12243, 40845], 20406, 24942, 26053, 34396, 20102, 20142, michael@0: 20698, 20001, 20940, 23534, 26009, 26753, 28092, 29471, 30274, 30637, michael@0: 31260, 31975, 33391, 35538, 36988, 37327, 38517, 38936, [12050, 21147], michael@0: 32209, 20523, 21400, 26519, 28107, 29136, 29747, 33256, 36650, 38563, michael@0: 40023, 40607, 29792, 22593, 28057, 32047, 39006, 20196, 20278, 20363, michael@0: 20919, 21169, 23994, 24604, 29618, 31036, 33491, 37428, 38583, 38646, michael@0: 38666, 40599, 40802, 26278, 27508, 21015, 21155, 28872, 35010, 24265, michael@0: 24651, 24976, 28451, 29001, 31806, 32244, 32879, 34030, 36899, 37676, michael@0: 21570, 39791, 27347, 28809, 36034, 36335, 38706, 21172, 23105, 24266, michael@0: 24324, 26391, 27004, 27028, 28010, 28431, 29282, 29436, 31725, michael@0: [12156, 32769], 32894, 34635, 37070, 20845, 40595, 31108, 32907, 37682, michael@0: 35542, 20525, 21644, 35441, 27498, 36036, 33031, 24785, 26528, 40434, michael@0: 20121, 20120, 39952, 35435, 34241, 34152, 26880, 28286, 30871, 33109, michael@0: 24332, 19984, 19989, 20010, 20017, [12034, 20022], 20028, [12035, 20031], michael@0: 20034, 20054, 20056, 20098, [12037, 20101], 35947, 20106, 33298, 24333, michael@0: 20110, {f: 2, c: 20126}, [12039, 20128], 20130, 20144, 20147, 20150, 20174, michael@0: 20173, 20164, 20166, 20162, 20183, 20190, 20205, 20191, 20215, 20233, michael@0: 20314, 20272, 20315, 20317, 20311, 20295, 20342, 20360, 20367, 20376, michael@0: 20347, 20329, 20336, 20369, 20335, 20358, 20374, 20760, 20436, 20447, michael@0: 20430, 20440, 20443, 20433, 20442, 20432, {f: 2, c: 20452}, 20506, 20520, michael@0: 20500, 20522, 20517, 20485, 20252, 20470, 20513, 20521, 20524, 20478, michael@0: 20463, 20497, 20486, 20547, 20551, 26371, 20565, 20560, 20552, 20570, michael@0: 20566, 20588, 20600, 20608, 20634, 20613, 20660, 20658, {f: 2, c: 20681}, michael@0: 20659, 20674, 20694, 20702, 20709, 20717, 20707, 20718, 20729, 20725, michael@0: 20745, {f: 2, c: 20737}, 20758, 20757, 20756, 20762, 20769, 20794, 20791, michael@0: 20796, 20795, [12041, 20799], [11918, 20800], 20818, 20812, 20820, 20834, michael@0: 31480, {f: 2, c: 20841}, 20846, 20864, [12044, 20866], 22232, 20876, 20873, michael@0: 20879, 20881, 20883, 20885, [12045, 20886], 20900, 20902, 20898, michael@0: {f: 2, c: 20905}, [12046, 20907], 20915, {f: 2, c: 20913}, 20912, 20917, michael@0: 20925, 20933, 20937, 20955, [12047, 20960], 34389, 20969, 20973, 20976, michael@0: [12048, 20981], 20990, 20996, 21003, 21012, 21006, 21031, 21034, 21038, michael@0: 21043, 21049, 21071, 21060, {f: 2, c: 21067}, 21086, 21076, 21098, 21108, michael@0: 21097, 21107, 21119, 21117, 21133, 21140, 21138, 21105, 21128, 21137, michael@0: 36776, 36775, {f: 2, c: 21164}, 21180, 21173, 21185, 21197, 21207, 21214, michael@0: 21219, 21222, 39149, 21216, 21235, 21237, 21240, [12051, 21241], 21254, michael@0: 21256, 30008, 21261, 21264, 21263, [12052, 21269], [12053, 21274], 21283, michael@0: 21295, 21297, 21299, [12054, 21304], 21312, 21318, 21317, 19991, 21321, michael@0: 21325, 20950, 21342, [12057, 21353], 21358, 22808, 21371, 21367, michael@0: [12058, 21378], 21398, 21408, 21414, 21413, 21422, 21424, [12059, 21430], michael@0: 21443, 31762, 38617, 21471, 26364, 29166, 21486, 21480, 21485, 21498, michael@0: 21505, 21565, 21568, {f: 2, c: 21548}, 21564, 21550, 21558, 21545, 21533, michael@0: 21582, 21647, 21621, 21646, 21599, 21617, 21623, 21616, 21650, 21627, michael@0: 21632, 21622, 21636, 21648, 21638, 21703, 21666, 21688, 21669, 21676, michael@0: 21700, 21704, 21672, 21675, 21698, 21668, 21694, 21692, 21720, michael@0: {f: 2, c: 21733}, 21775, 21780, 21757, 21742, 21741, 21754, 21730, 21817, michael@0: 21824, 21859, 21836, 21806, 21852, 21829, {f: 2, c: 21846}, 21816, 21811, michael@0: 21853, 21913, 21888, 21679, 21898, 21919, 21883, 21886, 21912, 21918, michael@0: 21934, 21884, 21891, 21929, 21895, 21928, 21978, 21957, 21983, 21956, michael@0: 21980, 21988, 21972, 22036, 22007, 22038, 22014, 22013, 22043, 22009, michael@0: 22094, 22096, 29151, 22068, 22070, 22066, 22072, 22123, 22116, 22063, michael@0: 22124, 22122, 22150, 22144, 22154, 22176, 22164, 22159, 22181, 22190, michael@0: 22198, 22196, 22210, 22204, 22209, 22211, 22208, 22216, 22222, 22225, michael@0: 22227, [12062, 22231], 22254, 22265, 22272, 22271, 22276, 22281, 22280, michael@0: 22283, 22285, 22291, 22296, 22294, 21959, 22300, 22310, {f: 2, c: 22327}, michael@0: 22350, 22331, 22336, 22351, 22377, 22464, 22408, 22369, 22399, 22409, michael@0: 22419, 22432, 22451, 22436, 22442, 22448, 22467, 22470, 22484, michael@0: {f: 2, c: 22482}, 22538, 22486, 22499, 22539, 22553, 22557, 22642, 22561, michael@0: 22626, 22603, 22640, 27584, 22610, 22589, 22649, 22661, 22713, 22687, michael@0: 22699, 22714, 22750, 22715, 22712, 22702, 22725, 22739, 22737, 22743, michael@0: 22745, 22744, 22757, 22748, 22756, 22751, 22767, 22778, 22777, michael@0: {f: 3, c: 22779}, [12065, 22786], [12066, 22794], 22800, 22811, 26790, michael@0: 22821, {f: 2, c: 22828}, 22834, 22840, 22846, 31442, 22869, 22864, 22862, michael@0: 22874, 22872, 22882, 22880, 22887, 22892, 22889, 22904, 22913, 22941, michael@0: 20318, 20395, 22947, 22962, 22982, 23016, 23004, 22925, {f: 2, c: 23001}, michael@0: 23077, 23071, 23057, 23068, 23049, 23066, 23104, 23148, 23113, michael@0: {f: 2, c: 23093}, 23138, 23146, 23194, 23228, 23230, 23243, 23234, 23229, michael@0: 23267, 23255, 23270, 23273, 23254, {f: 2, c: 23290}, 23308, 23307, 23318, michael@0: 23346, 23248, 23338, 23350, 23358, 23363, 23365, 23360, 23377, 23381, michael@0: {f: 2, c: 23386}, 23397, 23401, 23408, 23411, 23413, 23416, 25992, 23418, michael@0: [12071, 23424], 23427, 23462, 23480, 23491, 23495, 23497, 23508, 23504, michael@0: 23524, 23526, 23522, 23518, 23525, 23531, 23536, 23542, 23539, 23557, michael@0: {f: 2, c: 23559}, 23565, 23571, 23584, [11920, 12074, 23586], 23592, michael@0: [12075, 23608], 23609, 23617, 23622, 23630, 23635, 23632, 23631, 23409, michael@0: 23660, [12076, 23662], 20066, 23670, 23673, 23692, 23697, 23700, 22939, michael@0: 23723, 23739, 23734, 23740, 23735, 23749, 23742, 23751, 23769, 23785, michael@0: 23805, 23802, 23789, 23948, 23786, 23819, 23829, 23831, 23900, 23839, michael@0: 23835, 23825, 23828, 23842, 23834, 23833, 23832, 23884, 23890, 23886, michael@0: 23883, 23916, 23923, 23926, 23943, 23940, 23938, 23970, 23965, 23980, michael@0: 23982, 23997, 23952, 23991, 23996, 24009, 24013, 24019, 24018, 24022, michael@0: [12078, 24027], 24043, 24050, 24053, 24075, 24090, 24089, 24081, 24091, michael@0: {f: 2, c: 24118}, 24132, 24131, 24128, 24142, 24151, 24148, 24159, 24162, michael@0: 24164, 24135, {f: 2, c: 24181}, [11923, 12083, 24186], 40636, michael@0: [12084, 24191], 24224, {f: 2, c: 24257}, 24264, 24272, 24271, 24278, 24291, michael@0: 24285, {f: 2, c: 24282}, 24290, 24289, {f: 2, c: 24296}, 24300, 24305, michael@0: 24307, 24304, [12085, 24308], 24312, [12086, 24318], 24323, 24329, 24413, michael@0: 24412, [12087, 24331], 24337, 24342, 24361, 24365, 24376, 24385, 24392, michael@0: 24396, 24398, 24367, [11924, 24401], {f: 2, c: 24406}, 24409, michael@0: [12090, 24417], 24429, [12091, 24435], 24439, 24451, 24450, 24447, 24458, michael@0: 24456, 24465, 24455, 24478, 24473, 24472, 24480, 24488, 24493, 24508, michael@0: 24534, 24571, 24548, 24568, 24561, 24541, 24755, 24575, 24609, 24672, michael@0: 24601, 24592, 24617, 24590, 24625, 24603, 24597, 24619, 24614, 24591, michael@0: 24634, 24666, 24641, 24682, 24695, 24671, 24650, 24646, 24653, 24675, michael@0: 24643, 24676, 24642, 24684, 24683, 24665, 24705, 24717, 24807, 24707, michael@0: 24730, 24708, 24731, {f: 2, c: 24726}, 24722, 24743, 24715, 24801, 24760, michael@0: 24800, 24787, 24756, 24560, 24765, 24774, 24757, 24792, 24909, 24853, michael@0: 24838, {f: 2, c: 24822}, 24832, 24820, 24826, 24835, 24865, 24827, 24817, michael@0: {f: 2, c: 24845}, 24903, 24894, 24872, 24871, 24906, 24895, 24892, 24876, michael@0: 24884, 24893, 24898, 24900, 24947, 24951, {f: 3, c: 24920}, 24939, 24948, michael@0: 24943, 24933, 24945, 24927, 24925, 24915, 24949, 24985, 24982, 24967, michael@0: 25004, 24980, 24986, 24970, 24977, 25003, 25006, 25036, 25034, 25033, michael@0: 25079, 25032, 25027, 25030, 25018, 25035, 32633, 25037, 25062, 25059, michael@0: 25078, 25082, 25076, 25087, 25085, 25084, 25086, 25088, [12093, 25096], michael@0: 25097, 25101, 25100, 25108, 25115, 25118, 25121, 25130, 25134, 25136, michael@0: {f: 2, c: 25138}, 25153, 25166, 25182, 25187, 25179, 25184, 25192, 25212, michael@0: 25218, 25225, 25214, {f: 2, c: 25234}, 25238, 25300, 25219, 25236, 25303, michael@0: 25297, 25275, 25295, 25343, 25286, 25812, 25288, 25308, 25292, 25290, michael@0: 25282, 25287, 25243, 25289, 25356, 25326, 25329, 25383, 25346, 25352, michael@0: 25327, 25333, 25424, 25406, 25421, 25628, 25423, 25494, 25486, 25472, michael@0: 25515, 25462, 25507, 25487, 25481, 25503, 25525, 25451, 25449, 25534, michael@0: 25577, 25536, 25542, 25571, 25545, 25554, 25590, 25540, 25622, 25652, michael@0: 25606, 25619, 25638, 25654, 25885, 25623, 25640, 25615, 25703, 25711, michael@0: 25718, 25678, 25898, 25749, 25747, 25765, 25769, 25736, 25788, 25818, michael@0: 25810, 25797, 25799, 25787, 25816, 25794, 25841, 25831, 33289, michael@0: {f: 2, c: 25824}, 25260, 25827, 25839, 25900, 25846, 25844, 25842, 25850, michael@0: 25856, 25853, 25880, 25884, 25861, 25892, 25891, 25899, [12097, 25908], michael@0: [11929, 25909], 25911, 25910, 25912, 30027, 25928, 25942, 25941, 25933, michael@0: 25944, 25950, 25949, 25970, 25976, {f: 2, c: 25986}, 35722, 26011, 26015, michael@0: 26027, 26039, 26051, 26054, 26049, 26052, 26060, 26066, 26075, 26073, michael@0: [12102, 26080], [11931, 26081], 26097, 26482, 26122, 26115, 26107, 26483, michael@0: {f: 2, c: 26165}, 26164, 26140, 26191, 26180, 26185, 26177, 26206, 26205, michael@0: 26212, {f: 2, c: 26215}, 26207, 26210, 26224, 26243, 26248, 26254, 26249, michael@0: 26244, 26264, 26269, 26305, 26297, 26313, 26302, 26300, 26308, 26296, michael@0: 26326, 26330, 26336, 26175, 26342, 26345, [12104, 26352], 26357, 26359, michael@0: 26383, 26390, 26398, {f: 2, c: 26406}, 38712, 26414, 26431, 26422, 26433, michael@0: 26424, 26423, 26438, 26462, 26464, 26457, {f: 2, c: 26467}, 26505, 26480, michael@0: 26537, 26492, 26474, 26508, 26507, 26534, 26529, 26501, 26551, 26607, michael@0: 26548, 26604, 26547, 26601, 26552, 26596, 26590, 26589, 26594, 26606, michael@0: 26553, 26574, 26566, 26599, 27292, 26654, 26694, 26665, 26688, 26701, michael@0: 26674, 26702, 26803, 26667, 26713, 26723, 26743, 26751, 26783, 26767, michael@0: 26797, 26772, 26781, 26779, 26755, 27310, 26809, 26740, 26805, 26784, michael@0: 26810, 26895, 26765, 26750, 26881, 26826, 26888, 26840, 26914, 26918, michael@0: 26849, 26892, 26829, 26836, 26855, 26837, 26934, 26898, 26884, 26839, michael@0: 26851, 26917, 26873, 26848, 26863, 26920, 26922, 26906, 26915, 26913, michael@0: 26822, 27001, 26999, 26972, 27000, 26987, 26964, 27006, 26990, 26937, michael@0: 26996, 26941, 26969, 26928, 26977, 26974, 26973, 27009, 26986, 27058, michael@0: 27054, 27088, 27071, 27073, 27091, 27070, 27086, 23528, 27082, 27101, michael@0: 27067, 27075, 27047, 27182, 27025, 27040, 27036, 27029, 27060, 27102, michael@0: 27112, 27138, 27163, 27135, 27402, 27129, 27122, 27111, 27141, 27057, michael@0: 27166, 27117, 27156, 27115, 27146, 27154, 27329, 27171, 27155, 27204, michael@0: 27148, 27250, 27190, 27256, 27207, 27234, 27225, 27238, 27208, 27192, michael@0: 27170, 27280, 27277, 27296, 27268, {f: 2, c: 27298}, 27287, 34327, 27323, michael@0: 27331, 27330, 27320, 27315, 27308, 27358, 27345, 27359, 27306, 27354, michael@0: 27370, 27387, 27397, 34326, 27386, 27410, 27414, 39729, 27423, 27448, michael@0: 27447, 30428, 27449, 39150, 27463, 27459, 27465, 27472, 27481, 27476, michael@0: 27483, 27487, 27489, 27512, [12109, 27513], {f: 2, c: 27519}, 27524, 27523, michael@0: 27533, 27544, 27541, 27550, 27556, {f: 2, c: 27562}, 27567, 27570, 27569, michael@0: [12110, 27571], 27575, 27580, 27590, [12111, 27595], 27603, 27615, 27628, michael@0: 27627, 27635, 27631, 40638, 27656, 27667, [12115, 27668], 27675, 27684, michael@0: 27683, 27742, 27733, 27746, 27754, 27778, 27789, 27802, 27777, 27803, michael@0: 27774, 27752, 27763, 27794, 27792, 27844, 27889, 27859, 27837, 27863, michael@0: 27845, 27869, 27822, 27825, 27838, 27834, 27867, 27887, 27865, 27882, michael@0: 27935, 34893, 27958, 27947, 27965, 27960, 27929, 27957, 27955, 27922, michael@0: 27916, 28003, 28051, 28004, 27994, 28025, 27993, 28046, 28053, 28644, michael@0: 28037, 28153, 28181, 28170, 28085, 28103, 28134, 28088, 28102, 28140, michael@0: 28126, 28108, 28136, 28114, 28101, 28154, 28121, 28132, 28117, 28138, michael@0: 28142, 28205, 28270, 28206, 28185, 28274, 28255, 28222, 28195, 28267, michael@0: 28203, 28278, 28237, 28191, 28227, 28218, 28238, 28196, 28415, 28189, michael@0: 28216, 28290, 28330, 28312, 28361, 28343, 28371, 28349, 28335, 28356, michael@0: 28338, {f: 2, c: 28372}, 28303, 28325, 28354, 28319, 28481, 28433, 28748, michael@0: 28396, 28408, 28414, 28479, 28402, 28465, 28399, 28466, 28364, 28478, michael@0: 28435, 28407, 28550, 28538, 28536, 28545, 28544, 28527, 28507, 28659, michael@0: 28525, 28546, 28540, 28504, 28558, 28561, 28610, 28518, 28595, 28579, michael@0: 28577, 28580, 28601, 28614, 28586, 28639, 28629, 28652, 28628, 28632, michael@0: 28657, 28654, 28635, 28681, 28683, 28666, 28689, 28673, 28687, 28670, michael@0: 28699, 28698, 28532, 28701, 28696, 28703, 28720, 28734, 28722, 28753, michael@0: 28771, 28825, 28818, 28847, 28913, 28844, 28856, 28851, 28846, 28895, michael@0: 28875, 28893, 28889, 28937, 28925, 28956, 28953, 29029, 29013, 29064, michael@0: 29030, 29026, 29004, 29014, 29036, 29071, 29179, 29060, 29077, 29096, michael@0: 29100, 29143, 29113, 29118, 29138, 29129, 29140, 29134, 29152, 29164, michael@0: 29159, 29173, 29180, 29177, 29183, 29197, 29200, 29211, 29224, 29229, michael@0: 29228, 29232, 29234, [12120, 29243], 29244, [12121, 29247], 29248, 29254, michael@0: 29259, 29272, 29300, 29310, 29314, 29313, 29319, 29330, 29334, 29346, michael@0: 29351, 29369, 29362, 29379, 29382, 29380, 29390, 29394, 29410, michael@0: {f: 2, c: 29408}, 29433, 29431, 20495, 29463, 29450, 29468, 29462, 29469, michael@0: 29492, 29487, 29481, 29477, 29502, {f: 2, c: 29518}, 40664, 29527, 29546, michael@0: 29544, 29552, 29560, 29557, 29563, 29562, 29640, 29619, 29646, 29627, michael@0: 29632, 29669, 29678, 29662, 29858, 29701, 29807, 29733, 29688, 29746, michael@0: 29754, 29781, 29759, 29791, 29785, 29761, 29788, 29801, 29808, 29795, michael@0: 29802, 29814, 29822, 29835, 29854, 29863, 29898, 29903, 29908, 29681, michael@0: 29920, 29923, 29927, 29929, 29934, 29938, {f: 2, c: 29936}, 29944, 29943, michael@0: 29956, 29955, 29957, 29964, 29966, 29965, 29973, 29971, 29982, 29990, michael@0: 29996, 30012, 30020, 30029, 30026, 30025, 30043, 30022, 30042, 30057, michael@0: 30052, 30055, 30059, 30061, 30072, 30070, {f: 2, c: 30086}, 30068, 30090, michael@0: 30089, 30082, 30100, 30106, 30109, 30117, 30115, 30146, 30131, 30147, michael@0: 30133, 30141, 30136, 30140, 30129, 30157, 30154, 30162, 30169, 30179, michael@0: 30174, {f: 2, c: 30206}, 30204, 30209, 30192, 30202, {f: 2, c: 30194}, michael@0: 30219, 30221, 30217, 30239, 30247, {f: 3, c: 30240}, 30244, 30260, 30256, michael@0: 30267, {f: 2, c: 30279}, 30278, 30300, 30296, {f: 2, c: 30305}, michael@0: {f: 3, c: 30312}, 30311, 30316, 30320, 30322, [12136, 30326], 30328, 30332, michael@0: 30336, 30339, 30344, 30347, 30350, 30358, 30355, {f: 2, c: 30361}, 30384, michael@0: 30388, {f: 3, c: 30392}, 30402, 30413, 30422, 30418, 30430, 30433, 30437, michael@0: 30439, 30442, 34351, 30459, 30472, 30471, 30468, 30505, 30500, 30494, michael@0: {f: 2, c: 30501}, 30491, {f: 2, c: 30519}, 30535, 30554, 30568, 30571, michael@0: 30555, 30565, 30591, 30590, 30585, 30606, 30603, 30609, 30624, 30622, michael@0: 30640, 30646, 30649, 30655, {f: 2, c: 30652}, 30651, 30663, 30669, 30679, michael@0: 30682, 30684, 30691, 30702, 30716, 30732, 30738, 31014, 30752, 31018, michael@0: 30789, 30862, 30836, 30854, 30844, 30874, 30860, 30883, 30901, 30890, michael@0: 30895, 30929, 30918, 30923, 30932, 30910, 30908, 30917, 30922, 30956, michael@0: 30951, 30938, 30973, 30964, 30983, 30994, 30993, 31001, 31020, 31019, michael@0: 31040, 31072, 31063, 31071, 31066, 31061, 31059, 31098, 31103, 31114, michael@0: 31133, 31143, 40779, 31146, 31150, 31155, {f: 2, c: 31161}, 31177, 31189, michael@0: 31207, 31212, 31201, 31203, 31240, 31245, {f: 2, c: 31256}, 31264, 31263, michael@0: 31104, 31281, 31291, 31294, 31287, 31299, 31319, 31305, {f: 2, c: 31329}, michael@0: 31337, 40861, 31344, 31353, 31357, 31368, 31383, 31381, 31384, 31382, michael@0: 31401, 31432, 31408, 31414, 31429, 31428, 31423, 36995, 31431, 31434, michael@0: 31437, 31439, 31445, 31443, {f: 2, c: 31449}, 31453, {f: 2, c: 31457}, michael@0: 31462, 31469, 31472, 31490, 31503, 31498, 31494, 31539, {f: 2, c: 31512}, michael@0: 31518, 31541, 31528, 31542, 31568, 31610, 31492, 31565, 31499, 31564, michael@0: 31557, 31605, 31589, 31604, 31591, {f: 2, c: 31600}, 31596, 31598, 31645, michael@0: 31640, 31647, 31629, 31644, 31642, 31627, 31634, 31631, 31581, 31641, michael@0: 31691, 31681, 31692, 31695, 31668, 31686, 31709, 31721, 31761, 31764, michael@0: 31718, 31717, 31840, 31744, 31751, 31763, 31731, 31735, 31767, 31757, michael@0: 31734, 31779, 31783, 31786, 31775, 31799, 31787, 31805, 31820, 31811, michael@0: 31828, 31823, 31808, 31824, 31832, 31839, 31844, 31830, 31845, 31852, michael@0: 31861, 31875, 31888, 31908, 31917, 31906, 31915, 31905, 31912, 31923, michael@0: 31922, 31921, 31918, 31929, 31933, 31936, 31941, 31938, 31960, 31954, michael@0: 31964, 31970, 39739, 31983, 31986, 31988, 31990, 31994, 32006, 32002, michael@0: 32028, 32021, 32010, 32069, 32075, 32046, 32050, 32063, 32053, 32070, michael@0: 32115, 32086, 32078, 32114, 32104, 32110, 32079, 32099, 32147, 32137, michael@0: 32091, 32143, 32125, 32155, 32186, 32174, 32163, 32181, 32199, 32189, michael@0: 32171, 32317, 32162, 32175, 32220, 32184, 32159, 32176, 32216, 32221, michael@0: 32228, 32222, 32251, 32242, 32225, 32261, 32266, 32291, 32289, 32274, michael@0: 32305, 32287, 32265, 32267, 32290, 32326, 32358, 32315, 32309, 32313, michael@0: 32323, 32311, 32306, 32314, 32359, 32349, 32342, 32350, {f: 2, c: 32345}, michael@0: 32377, 32362, 32361, 32380, 32379, 32387, 32213, 32381, 36782, 32383, michael@0: {f: 2, c: 32392}, 32396, 32402, 32400, {f: 2, c: 32403}, 32406, 32398, michael@0: {f: 2, c: 32411}, 32568, 32570, 32581, {f: 3, c: 32588}, 32592, michael@0: [12153, 32593], 32597, 32596, 32600, {f: 2, c: 32607}, {f: 2, c: 32616}, michael@0: 32615, 32632, 32642, 32646, 32643, 32648, 32647, 32652, 32660, 32670, michael@0: 32669, 32666, 32675, 32687, 32690, 32697, 32686, 32694, 32696, 35697, michael@0: {f: 2, c: 32709}, 32714, 32725, 32724, 32737, 32742, 32745, 32755, 32761, michael@0: 39132, 32774, 32772, 32779, [12158, 32786], {f: 2, c: 32792}, 32796, 32801, michael@0: 32808, 32831, 32827, 32842, 32838, 32850, 32856, 32858, 32863, 32866, michael@0: 32872, 32883, 32882, 32880, 32886, 32889, 32893, [12160, 32895], 32900, michael@0: 32902, 32901, 32923, 32915, 32922, 32941, 20880, 32940, 32987, 32997, michael@0: 32985, 32989, 32964, 32986, 32982, 33033, 33007, 33009, 33051, 33065, michael@0: 33059, 33071, 33099, 38539, 33094, 33086, 33107, 33105, 33020, 33137, michael@0: 33134, {f: 2, c: 33125}, 33140, 33155, 33160, 33162, 33152, 33154, 33184, michael@0: 33173, 33188, 33187, 33119, 33171, 33193, 33200, 33205, 33214, 33208, michael@0: 33213, 33216, 33218, 33210, 33225, 33229, 33233, 33241, 33240, 33224, michael@0: 33242, {f: 2, c: 33247}, 33255, {f: 2, c: 33274}, 33278, {f: 2, c: 33281}, michael@0: 33285, 33287, 33290, 33293, 33296, 33302, 33321, 33323, 33336, 33331, michael@0: 33344, 33369, 33368, 33373, 33370, 33375, 33380, 33378, 33384, michael@0: {f: 2, c: 33386}, 33326, 33393, 33399, [12171, 33400], 33406, 33421, 33426, michael@0: 33451, 33439, 33467, 33452, 33505, 33507, 33503, 33490, 33524, 33523, michael@0: 33530, 33683, 33539, 33531, 33529, 33502, 33542, 33500, 33545, 33497, michael@0: 33589, 33588, 33558, 33586, 33585, 33600, 33593, 33616, 33605, 33583, michael@0: 33579, {f: 2, c: 33559}, 33669, 33690, 33706, 33695, 33698, 33686, 33571, michael@0: 33678, 33671, 33674, 33660, 33717, 33651, 33653, 33696, 33673, 33704, michael@0: 33780, 33811, 33771, 33742, 33789, 33795, 33752, 33803, 33729, 33783, michael@0: 33799, 33760, 33778, 33805, 33826, 33824, 33725, 33848, 34054, 33787, michael@0: 33901, 33834, 33852, 34138, 33924, 33911, 33899, 33965, 33902, 33922, michael@0: 33897, 33862, 33836, 33903, 33913, 33845, 33994, 33890, 33977, 33983, michael@0: 33951, 34009, 33997, 33979, 34010, 34000, 33985, 33990, 34006, 33953, michael@0: 34081, 34047, 34036, {f: 2, c: 34071}, 34092, 34079, 34069, 34068, 34044, michael@0: 34112, 34147, 34136, 34120, 34113, 34306, 34123, 34133, 34176, 34212, michael@0: 34184, 34193, 34186, 34216, 34157, 34196, 34203, 34282, 34183, 34204, michael@0: 34167, 34174, 34192, 34249, 34234, 34255, 34233, 34256, 34261, 34269, michael@0: 34277, 34268, 34297, 34314, 34323, 34315, 34302, 34298, 34310, 34338, michael@0: 34330, 34352, 34367, [12172, 34381], 20053, 34388, 34399, 34407, 34417, michael@0: 34451, 34467, {f: 2, c: 34473}, {f: 2, c: 34443}, 34486, 34479, 34500, michael@0: 34502, 34480, 34505, 34851, 34475, 34516, 34526, 34537, 34540, 34527, michael@0: 34523, 34543, 34578, 34566, 34568, 34560, 34563, 34555, 34577, 34569, michael@0: 34573, 34553, 34570, 34612, 34623, 34615, 34619, 34597, 34601, 34586, michael@0: 34656, 34655, 34680, 34636, 34638, 34676, 34647, 34664, 34670, 34649, michael@0: 34643, 34659, 34666, 34821, 34722, 34719, 34690, 34735, 34763, 34749, michael@0: 34752, 34768, 38614, 34731, 34756, 34739, 34759, 34758, 34747, 34799, michael@0: 34802, 34784, 34831, 34829, 34814, {f: 2, c: 34806}, 34830, 34770, 34833, michael@0: 34838, 34837, 34850, 34849, 34865, 34870, 34873, 34855, 34875, 34884, michael@0: 34882, 34898, 34905, 34910, 34914, 34923, 34945, 34942, 34974, 34933, michael@0: 34941, 34997, 34930, 34946, 34967, 34962, 34990, 34969, 34978, 34957, michael@0: 34980, 34992, 35007, 34993, {f: 2, c: 35011}, 35028, {f: 2, c: 35032}, michael@0: 35037, 35065, 35074, 35068, 35060, 35048, 35058, 35076, 35084, 35082, michael@0: 35091, 35139, 35102, 35109, {f: 2, c: 35114}, 35137, 35140, 35131, 35126, michael@0: 35128, 35148, 35101, 35168, 35166, 35174, 35172, 35181, 35178, 35183, michael@0: 35188, 35191, [12177, 35198], 35203, 35208, 35210, 35219, 35224, 35233, michael@0: 35241, 35238, 35244, 35247, 35250, 35258, 35261, {f: 2, c: 35263}, 35290, michael@0: {f: 2, c: 35292}, 35303, 35316, 35320, 35331, 35350, 35344, 35340, 35355, michael@0: 35357, 35365, 35382, 35393, 35419, 35410, 35398, 35400, 35452, 35437, michael@0: 35436, 35426, 35461, 35458, 35460, 35496, 35489, 35473, {f: 2, c: 35493}, michael@0: 35482, 35491, 35524, 35533, 35522, 35546, 35563, 35571, 35559, 35556, michael@0: 35569, 35604, 35552, 35554, 35575, 35550, 35547, 35596, 35591, 35610, michael@0: 35553, 35606, 35600, 35607, 35616, 35635, 38827, 35622, 35627, 35646, michael@0: 35624, 35649, 35660, 35663, 35662, 35657, 35670, 35675, 35674, 35691, michael@0: 35679, 35692, 35695, 35700, 35709, 35712, 35724, 35726, {f: 2, c: 35730}, michael@0: 35734, {f: 2, c: 35737}, 35898, 35905, 35903, 35912, 35916, 35918, 35920, michael@0: [12183, 35925], 35938, 35948, [12184, 35960], 35962, 35970, 35977, 35973, michael@0: 35978, {f: 2, c: 35981}, 35988, 35964, 35992, 25117, 36013, 36010, 36029, michael@0: {f: 2, c: 36018}, 36014, 36022, 36040, 36033, 36068, 36067, 36058, 36093, michael@0: {f: 2, c: 36090}, {f: 2, c: 36100}, 36106, 36103, 36111, 36109, 36112, michael@0: 40782, 36115, 36045, 36116, 36118, 36199, 36205, 36209, 36211, 36225, michael@0: 36249, 36290, 36286, 36282, 36303, 36314, 36310, 36300, 36315, 36299, michael@0: {f: 2, c: 36330}, 36319, 36323, 36348, {f: 2, c: 36360}, 36351, michael@0: {f: 2, c: 36381}, 36368, 36383, 36418, 36405, 36400, 36404, 36426, 36423, michael@0: 36425, 36428, 36432, 36424, 36441, 36452, 36448, 36394, 36451, 36437, michael@0: 36470, 36466, 36476, 36481, 36487, 36485, 36484, 36491, 36490, 36499, michael@0: 36497, 36500, 36505, 36522, 36513, 36524, 36528, 36550, 36529, 36542, michael@0: 36549, 36552, 36555, 36571, 36579, 36604, 36603, 36587, 36606, 36618, michael@0: 36613, 36629, 36626, 36633, 36627, 36636, 36639, 36635, 36620, 36646, michael@0: 36659, 36667, 36665, 36677, 36674, 36670, 36684, 36681, 36678, 36686, michael@0: 36695, 36700, {f: 3, c: 36706}, 36764, 36767, 36771, 36781, 36783, 36791, michael@0: 36826, 36837, 36834, 36842, 36847, 36999, 36852, 36869, {f: 2, c: 36857}, michael@0: 36881, 36885, 36897, 36877, 36894, 36886, 36875, 36903, 36918, 36917, michael@0: 36921, 36856, {f: 4, c: 36943}, 36878, 36937, 36926, 36950, 36952, 36958, michael@0: 36968, 36975, 36982, 38568, 36978, 36994, 36989, 36993, 36992, 37002, michael@0: 37001, 37007, 37032, 37039, 37041, 37045, 37090, 37092, 25160, 37083, michael@0: 37122, 37138, 37145, 37170, 37168, 37194, 37206, 37208, 37219, 37221, michael@0: 37225, 37235, 37234, 37259, 37257, 37250, 37282, 37291, 37295, 37290, michael@0: 37301, 37300, 37306, {f: 2, c: 37312}, 37321, 37323, 37328, 37334, 37343, michael@0: 37345, 37339, 37372, {f: 2, c: 37365}, 37406, 37375, 37396, 37420, 37397, michael@0: 37393, 37470, 37463, 37445, 37449, 37476, 37448, 37525, 37439, 37451, michael@0: 37456, 37532, 37526, 37523, 37531, 37466, 37583, 37561, 37559, 37609, michael@0: 37647, 37626, 37700, 37678, 37657, 37666, 37658, 37667, 37690, 37685, michael@0: 37691, 37724, 37728, 37756, 37742, 37718, 37808, {f: 2, c: 37804}, 37780, michael@0: 37817, {f: 2, c: 37846}, 37864, 37861, 37848, 37827, 37853, 37840, 37832, michael@0: 37860, 37914, 37908, 37907, 37891, 37895, 37904, 37942, 37931, 37941, michael@0: 37921, 37946, 37953, 37970, 37956, 37979, 37984, 37986, 37982, 37994, michael@0: 37417, 38000, 38005, 38007, 38013, 37978, 38012, 38014, 38017, 38015, michael@0: 38274, 38279, 38282, 38292, 38294, {f: 2, c: 38296}, 38304, 38312, 38311, michael@0: 38317, 38332, 38331, 38329, 38334, 38346, 28662, 38339, 38349, 38348, michael@0: 38357, 38356, 38358, 38364, 38369, 38373, 38370, 38433, 38440, michael@0: {f: 2, c: 38446}, 38466, 38476, 38479, 38475, 38519, 38492, 38494, 38493, michael@0: 38495, 38502, 38514, 38508, 38541, 38552, 38549, 38551, 38570, 38567, michael@0: {f: 2, c: 38577}, 38576, 38580, [12202, 38582], 38584, [12203, 38585], michael@0: 38606, 38603, 38601, 38605, 35149, 38620, 38669, 38613, 38649, 38660, michael@0: 38662, 38664, 38675, 38670, 38673, 38671, 38678, 38681, 38692, 38698, michael@0: 38704, 38713, {f: 2, c: 38717}, 38724, 38726, 38728, 38722, 38729, 38748, michael@0: 38752, 38756, 38758, 38760, 21202, 38763, 38769, 38777, 38789, 38780, michael@0: 38785, 38778, 38790, 38795, {f: 2, c: 38799}, 38812, 38824, 38822, 38819, michael@0: {f: 2, c: 38835}, 38851, 38854, 38856, [12209, 38859], 38876, michael@0: [12210, 38893], 40783, 38898, 31455, 38902, 38901, 38927, 38924, 38968, michael@0: 38948, 38945, 38967, 38973, 38982, 38991, 38987, 39019, {f: 3, c: 39023}, michael@0: 39028, 39027, 39082, 39087, 39089, 39094, 39108, 39107, 39110, 39145, michael@0: 39147, 39171, 39177, 39186, 39188, 39192, 39201, {f: 2, c: 39197}, 39204, michael@0: 39200, 39212, 39214, {f: 2, c: 39229}, 39234, 39241, 39237, 39248, 39243, michael@0: {f: 2, c: 39249}, 39244, 39253, {f: 2, c: 39319}, 39333, {f: 2, c: 39341}, michael@0: 39356, 39391, 39387, 39389, 39384, 39377, {f: 2, c: 39405}, michael@0: {f: 2, c: 39409}, 39419, 39416, 39425, 39439, 39429, 39394, 39449, 39467, michael@0: 39479, 39493, 39490, 39488, 39491, 39486, 39509, 39501, 39515, 39511, michael@0: 39519, 39522, 39525, 39524, 39529, 39531, 39530, 39597, 39600, 39612, michael@0: 39616, 39631, 39633, {f: 2, c: 39635}, 39646, [12221, 39647], michael@0: {f: 2, c: 39650}, 39654, 39663, 39659, 39662, 39668, 39665, 39671, 39675, michael@0: 39686, 39704, 39706, 39711, {f: 2, c: 39714}, [12222, 39717], michael@0: {f: 4, c: 39719}, 39726, [12223, 39727], [12224, 39730], 39748, 39747, michael@0: 39759, {f: 2, c: 39757}, 39761, 39768, 39796, 39827, 39811, 39825, michael@0: {f: 2, c: 39830}, {f: 2, c: 39839}, 39848, 39860, 39872, 39882, 39865, michael@0: 39878, 39887, {f: 2, c: 39889}, 39907, 39906, 39908, 39892, 39905, 39994, michael@0: 39922, 39921, 39920, 39957, 39956, 39945, 39955, 39948, 39942, 39944, michael@0: 39954, 39946, 39940, 39982, 39963, 39973, 39972, 39969, 39984, 40007, michael@0: 39986, 40006, 39998, 40026, 40032, 40039, 40054, 40056, 40167, 40172, michael@0: 40176, 40201, 40200, 40171, 40195, 40198, 40234, 40230, 40367, 40227, michael@0: 40223, 40260, 40213, 40210, 40257, 40255, 40254, 40262, 40264, michael@0: {f: 2, c: 40285}, 40292, 40273, 40272, 40281, 40306, 40329, 40327, 40363, michael@0: 40303, 40314, 40346, 40356, 40361, 40370, 40388, 40385, 40379, 40376, michael@0: 40378, 40390, 40399, 40386, 40409, 40403, 40440, 40422, 40429, 40431, michael@0: 40445, {f: 2, c: 40474}, 40478, [12228, 40565], 40569, 40573, 40577, 40584, michael@0: {f: 2, c: 40587}, 40594, 40597, 40593, 40605, [12230, 40613], 40617, 40632, michael@0: 40618, 40621, 38753, 40652, {f: 3, c: 40654}, 40660, 40668, 40670, 40669, michael@0: 40672, 40677, 40680, 40687, 40692, {f: 2, c: 40694}, [12235, 40697], michael@0: {f: 2, c: 40699}, [12236, 40701], {f: 2, c: 40711}, 30391, 40725, 40737, michael@0: 40748, 40766, [12241, 40778], [12242, 40786], 40788, 40803, michael@0: {f: 3, c: 40799}, {f: 2, c: 40806}, 40812, 40810, 40823, 40818, 40822, michael@0: 40853, [12244, 40860], [12245, 40864], 22575, 27079, 36953, 29796, 0, michael@0: {f: 76, c: 9472}, {f: 20, c: 9312}, {f: 10, c: 8544}, 13129, 13076, 0, michael@0: 13133, 0, 13095, 0, 13110, 13137, 0, 13069, 13094, 0, 13099, 13130, 0, michael@0: {f: 3, c: 13212}, {f: 2, c: 13198}, 13252, 13217, 12317, 12319, 8470, michael@0: 13261, 0, {f: 5, c: 12964}, {f: 2, c: 12849}, 12857, 13182, 13181, 13180, michael@0: 8750, 8721, {s: 3}, 8735, 8895, 0, 0, 21854, {s: 7}, 167133, 0, 0, 28976, michael@0: 0, 40407, {s: 4}, 64054, 0, 0, 22169, 15694, {s: 4}, 20448, 0, 0, 36544, 0, michael@0: 194797, {s: 4}, 153716, 32363, 33606, 167670, {s: 3}, 40572, 0, 0, 26171, michael@0: 0, 40628, {s: 4}, 26629, {s: 5}, 23650, 0, 194780, 0, 32353, 0, 0, 64070, michael@0: {s: 5}, 34083, 37292, {s: 7}, 34796, {s: 8}, 25620, 0, 0, 39506, {s: 4}, michael@0: 64074, 0, 194692, {s: 4}, 31774, {s: 6}, 64016, 25681, 0, 0, 63980, 22625, michael@0: 39002, 0, 194679, {s: 3}, 31153, 0, 28678, {s: 9}, 22218, {s: 3}, 21085, 0, michael@0: 28497, 37297, {s: 10}, 64106, {s: 6}, 38960, 0, 40629, {s: 9}, 33802, michael@0: 63939, {f: 2, c: 63890}, 63897, 0, 34847, 194575, 0, 194771, 194584, michael@0: {s: 7}, 137754, 23643, {s: 4}, 25890, 0, 0, 26618, 0, 26766, 0, 148432, michael@0: 194848, {s: 21}, 34110, {s: 15}, 30562, {s: 12}, 65075, 0, michael@0: {f: 2, c: 65073}, {s: 4}, 65072, {f: 2, c: 65077}, {f: 2, c: 65081}, 0, 0, michael@0: {f: 2, c: 65079}, {f: 2, c: 65087}, {f: 2, c: 65085}, {f: 4, c: 65089}, michael@0: {f: 2, c: 65083}, {s: 41}, {f: 3, c: 12436}, 0, 0, 22099, {s: 41}, 65508, michael@0: 65287, 65282, 0, 9665, 9655, 8681, 8679, 8678, 8680, 9634, 9831, 9825, michael@0: 9828, 9826, 13216, 13218, {f: 2, c: 13220}, 13207, 8467, 13208, 13235, michael@0: 13234, 13233, 13232, {f: 3, c: 13189}, 13259, 13200, 13268, 13206, 13090, michael@0: 13078, 13080, 13077, 13059, 13091, 13143, 13122, 13113, 13115, 13056, michael@0: 13105, 13127, 13086, 13098, 0, 13183, 8481, 9742, 12342, 12320, {s: 3}, michael@0: {f: 9, c: 9352}, {f: 20, c: 9332}, 12881, {f: 10, c: 8560}, michael@0: {f: 10, c: 12882}, {f: 26, c: 9372}, 12867, 12861, 12863, 12852, 12856, michael@0: 12851, 12860, 12866, 12862, 12854, 12853, 12859, 12864, 12858, 12976, michael@0: 12973, 12969, 12975, 12948, 12970, 12952, 12971, 12946, 12945, 12947, michael@0: 12972, 12974, 12950, {s: 8}, {f: 3, c: 9131}, 0, {f: 3, c: 9127}, 0, 13260, michael@0: 13061, 0, 0, 13215, 13219, 13222, 0, 0, 12958, {f: 2, c: 13192}, 13256, michael@0: 8749, 0, 12848, {f: 6, c: 12842}, 12855, 12865, 10145, {s: 3}, 9673, 9824, michael@0: 9829, 9827, 9830, {f: 4, c: 9728}, 9758, {f: 2, c: 9756}, 9759, 12953, michael@0: 9450, {f: 2, c: 8554}, {s: 3}, {f: 8, c: 9601}, 9615, 9614, 9613, 9612, michael@0: 9611, 9610, 9609, {f: 2, c: 9620}, {f: 2, c: 9581}, 9584, 9583, 9552, 9566, michael@0: 9578, 9569, {f: 2, c: 9698}, 9701, 9700, 0, 0, {f: 3, c: 9585}, {s: 20}, michael@0: 20956, 29081, {f: 9, c: 10102}, {s: 3}, {f: 2, c: 8570}, {s: 3}, 8575, michael@0: 8458, 8457, 0, 0, 12292, 8646, {f: 2, c: 8644}, 0, {f: 4, c: 12535}, 0, 0, michael@0: 12957, {s: 3}, 13179, {s: 3}, 13107, 13134, {s: 30}, 32394, 35100, 37704, michael@0: 37512, 34012, 20425, 28859, 26161, 26824, 37625, 26363, 24389, michael@0: [12033, 20008], 20193, 20220, 20224, 20227, 20281, 20310, 20370, 20362, michael@0: 20378, 20372, 20429, 20544, 20514, 20479, 20510, 20550, 20592, 20546, michael@0: 20628, 20724, 20696, 20810, 20836, 20893, 20926, 20972, 21013, 21148, michael@0: 21158, 21184, 21211, 21248, 0, 21284, 21362, 21395, 21426, 21469, 64014, michael@0: 21660, 21642, 21673, 21759, 21894, 22361, 22373, 22444, 22472, 22471, michael@0: 64015, 0, 22686, 22706, 22795, 22867, 22875, 22877, 22883, 22948, 22970, michael@0: 23382, 23488, 29999, 23512, 0, 23582, 23718, 23738, 23797, 23847, 23891, 0, michael@0: 23874, 23917, {f: 2, c: 23992}, 24016, 24353, 24372, 24423, 24503, 24542, michael@0: 24669, 24709, 24714, 24798, 24789, 24864, 24818, 24849, 24887, 24880, michael@0: 24984, 25107, 25254, 25589, 25696, 25757, 25806, 25934, 26112, 26133, michael@0: 26121, 26158, 0, 26148, 26213, 26199, 26201, 64018, 26227, 26265, 26272, michael@0: 26290, 26303, 26362, 26382, 0, 26470, 26555, 26706, 26560, 0, 26692, 26831, michael@0: 64019, 26984, 64020, 27032, 27106, 27184, 27243, 27206, 27251, 27262, michael@0: 27362, 27364, 27606, 27711, 27740, 27782, 27759, 27866, 27908, 28039, michael@0: 28015, 28054, 28076, 28111, 28152, 28146, 28156, 28217, 28252, 28199, michael@0: 28220, 28351, 28552, 28597, 28661, 28677, 28679, 28712, 28805, 28843, michael@0: 28943, 28932, 29020, {f: 2, c: 28998}, 0, 29121, 29182, 29361, 29374, michael@0: 29476, 64022, 29559, 29629, 29641, 29654, 29667, 29650, 29703, 29685, michael@0: 29734, 29738, 29737, 29742, 0, 29833, 29855, 29953, 30063, 30338, 30364, michael@0: 30366, 30363, 30374, 64023, 30534, 21167, 30753, 30798, 30820, 30842, michael@0: 31024, {f: 3, c: 64024}, 31124, 64027, 31131, 31441, 31463, 64028, 31467, michael@0: 31646, 64029, 32072, 0, 32183, 32160, 32214, 32338, 32583, 32673, 64030, michael@0: 33537, 33634, 33663, 33735, 33782, 33864, 33972, 34131, 34137, 34155, michael@0: 64031, 34224, {f: 2, c: 64032}, 34823, 35061, 35346, 35383, 35449, 35495, michael@0: 35518, 35551, 64034, 35574, 35667, 35711, 36080, 36084, 36114, 36214, michael@0: 64035, 36559, 0, 64037, 36967, 37086, 64038, 37141, 37159, 37338, 37335, michael@0: 37342, {f: 2, c: 37357}, {f: 2, c: 37348}, 37382, 37392, 37386, 37434, michael@0: 37440, 37436, 37454, 37465, 37457, 37433, 37479, 37543, {f: 2, c: 37495}, michael@0: 37607, 37591, 37593, 37584, 64039, 37589, 37600, 37587, 37669, 37665, michael@0: 37627, 64040, 37662, 37631, 37661, 37634, 37744, 37719, 37796, 37830, michael@0: 37854, 37880, 37937, 37957, 37960, 38290, 0, 64041, 38557, 38575, 38707, michael@0: 38715, 38723, 38733, 38735, [12205, 38737], 0, 38999, 39013, michael@0: {f: 2, c: 64042}, 39207, 64044, 39326, 39502, 39641, 39644, 39797, 39794, michael@0: 39823, 39857, 39867, 39936, 40304, 40299, 64045, 40473, 40657, 0, 92, michael@0: {s: 634}, 8364, 8486, 0, 0, 64256, {f: 2, c: 64259}, 257, 299, 363, 275, michael@0: 333, 256, 298, 362, 274, 332, {f: 4, c: 8539}, {f: 2, c: 8531}, 8304, michael@0: {f: 6, c: 8308}, {f: 10, c: 8320}, 461, 282, 0, 7868, 463, 0, 296, 465, 0, michael@0: 467, 366, 360, 462, 283, 0, 7869, 464, 0, 297, 466, 0, 468, 367, 361, 593, michael@0: 8049, 8048, 509, 0, 596, 0, 0, 601, 0, 0, 602, 0, 0, 603, 8051, 8050, 0, michael@0: 331, 629, 652, 0, 0, 658, 643, 720, {s: 682}, {f: 10, c: 12832}, {s: 108}, michael@0: {f: 4, c: 12892}, {f: 15, c: 12977}, {s: 50}, {f: 26, c: 9424}, michael@0: {f: 26, c: 9398}, {s: 48}, {f: 47, c: 13008}, 0, {f: 10, c: 12928}, 12944, michael@0: {f: 6, c: 12938}, 0, 12959, {s: 6}, {f: 2, c: 12960}, 12955, 12954, 12963, michael@0: 12962, 12951, 0, 12956, 12949, {s: 6}, 9676, {s: 11}, 10111, michael@0: {f: 10, c: 9451}, {s: 510}, 8414, {s: 815}, 13274, {s: 3}, 8448, 13250, 0, michael@0: 0, 8453, 0, 13169, 0, 0, 13197, 13211, {s: 3}, {f: 2, c: 13271}, {s: 3}, michael@0: {f: 2, c: 13057}, 13060, 13062, 0, 13064, 0, 13063, 13066, 0, 13065, 0, michael@0: 13067, 0, 13068, {f: 6, c: 13070}, 0, 13079, 0, 13081, 0, {f: 4, c: 13082}, michael@0: {f: 3, c: 13087}, 13092, 0, 13093, 0, 0, {f: 2, c: 13096}, 0, 13101, 0, 0, michael@0: {f: 3, c: 13102}, 13106, 0, 0, {f: 2, c: 13108}, 13116, {s: 3}, 13111, 0, michael@0: 13112, 13114, 13117, 13121, {f: 3, c: 13118}, {f: 4, c: 13123}, 13128, michael@0: {f: 2, c: 13131}, {f: 2, c: 13135}, 0, 0, 13138, 13140, 0, 0, 13139, michael@0: {f: 2, c: 13141}, {s: 132}, 8501, 976, 8714, 8463, 0, 981, 987, 977, 0, michael@0: {f: 2, c: 9832}, 9836, {s: 5}, 12347, 0, {f: 3, c: 12339}, 8252, 8265, michael@0: {s: 5}, 8723, 0, 8771, {f: 2, c: 8818}, {s: 6}, {f: 2, c: 12312}, michael@0: {f: 2, c: 65375}, {s: 10}, 9115, {f: 2, c: 9117}, 9120, {s: 4}, 9121, michael@0: {f: 2, c: 9123}, 9126, {s: 12}, [9116, 9119, 9122, 9125, 9130], {s: 8}, michael@0: 9986, 0, 0, 12349, 0, 12447, 0, 0, 8709, 8864, 8854, 8856, 8853, 8855, michael@0: {s: 4}, 9664, 9654, {s: 4}, 8656, 8596, {f: 2, c: 8600}, {f: 2, c: 8598}, michael@0: 8652, 8651, {s: 10}, 12336, 8967, {s: 8}, 10048, 10047, {s: 7}, 9643, 0, michael@0: 9642, 0, 10010, {s: 12}, 9702, {s: 4}, 10070, {s: 379}, {f: 2, c: 65093}, michael@0: {s: 679}, 64103, 64098, 32227, [12232, 40643], 28331, 64082, 64061, 64069, michael@0: 64062, 27114, 28212, 64096, 64071, 64056, 64066, 64078, 34395, 64105, michael@0: 64052, 64099, 25581, 25802, 30799, 64084, 63856, 64077, 64097, 64072, michael@0: 64076, {f: 2, c: 64091}, 64081, 64067, 64090, 28041, 29376, 0, 194885, michael@0: 64086, 64080, 64049, 64059, 24034, 64063, 64101, 21373, 64055, 64095, michael@0: 24501, 64064, 0, 64083, 0, 64085, 64104, 64068, 64089, 26202, 64053, 64075, michael@0: 64100, 64065, 64048, 0, 64057, 64051, 27493, 64058, 27599, 64050, 25150, michael@0: 64079, 63773, 63964, 63798, 28122, 63952, 26310, 27511, 64087, 37706, 0, michael@0: 37636, {s: 120}, 133390, {s: 120}, 35999, 11991, [11965, 158033], {s: 5}, michael@0: 37555, 38321, 0, 0, 194812, {s: 13}, 194965, {s: 8}, 194794, 0, 26478, michael@0: 11974, 0, 194594, {s: 13}, 13314, 0, 0, 26083, {s: 4}, 134071, {s: 10}, michael@0: 171339, 0, 194611, 24378, {s: 8}, 11945, 0, 20465, {s: 7}, 63753, {s: 7}, michael@0: 11964, 0, 0, 194732, 26435, {s: 3}, 133732, 35329, 25142, 0, 0, 21555, michael@0: 23067, {s: 3}, 25221, 0, 0, 194819, {s: 6}, 21567, {s: 9}, 27506, {s: 4}, michael@0: 29986, 19256, 0, 0, 24063, {s: 6}, 194827, 29626, 134047, {s: 3}, 194600, michael@0: 0, 194849, {s: 5}, 194623, {s: 16}, 194675, {f: 2, c: 11916}, 23577, michael@0: {s: 3}, 131083, 23426, 194642, {s: 5}, 11997, [11999, 39136], michael@0: [11998, 169599], 14221, 0, [11927, 14586], 0, 194887, 0, [11909, 20155], michael@0: 131490, {s: 7}, 13599, 0, 194738, 0, 0, [11971, 35200], {s: 4}, 31237, michael@0: {s: 4}, 35498, 0, 32085, 0, 28568, {s: 7}, 25591, 30246, {s: 4}, michael@0: [11978, 163767], {s: 5}, 146686, {s: 5}, 13351, 0, 0, 33067, 0, 0, 194842, michael@0: {s: 5}, 11950, {s: 5}, 194714, {s: 3}, 194831, {s: 19}, 22305, 135741, michael@0: 194586, 0, 64003, {s: 7}, 21534, 15240, 20839, {s: 4}, 63839, {s: 9}, michael@0: 20023, {s: 13}, [11946, 150804], 24421, 23020, 194658, 0, 24217, {s: 46}, michael@0: 13416, {s: 8}, 21200, {s: 9}, 26625, 0, 195024, 195039, {s: 5}, 153215, 0, michael@0: 0, 11959, {s: 4}, 36534, 63775, {s: 3}, 63875, {s: 5}, 31867, 63906, 0, michael@0: 63898, 0, [11961, 32770], 157360, {s: 4}, [11911, 132648], 0, 0, 131210, michael@0: 194604, [11915, 13630], {s: 4}, 21589, 0, 22841, 0, 0, 23414, 194669, michael@0: 23572, 14306, 23782, 0, 20040, 0, 0, 194742, {s: 4}, 158105, 25371, 0, 0, michael@0: 26211, 0, 194779, 0, 0, 27126, 27014, {s: 3}, 27596, 0, 28183, 0, 0, 27818, michael@0: {s: 3}, [11942, 20012], 0, 0, 29935, 30069, 30188, 30286, 16305, 30570, michael@0: 30633, {s: 6}, 31571, 0, 0, 16996, {s: 3}, 194924, 0, 0, 32328, {s: 5}, michael@0: 11955, {s: 4}, 33089, 17491, 0, [11966, 33401], [11967, 64094], michael@0: [11968, 64093], 0, 20857, 33626, {s: 3}, 17701, 0, 34292, 131248, {s: 4}, michael@0: 34429, 0, 13358, 35014, {s: 6}, 18406, {s: 8}, 36808, {s: 19}, 166279, 0, michael@0: 0, 167447, 0, 0, 38969, {s: 6}, 39432, {s: 4}, 39903, {s: 10}, 148206, michael@0: {s: 5}, 21385, 0, 64017, 194785, 0, 146622, 132625, 0, {f: 2, c: 19972}, michael@0: 19999, 20011, {f: 2, c: 20015}, {f: 2, c: 20032}, 20036, [11907, 20058], michael@0: 20095, 20109, 20118, 20153, 20176, 20192, 20221, 20223, 20235, 20245, michael@0: 20320, 20283, 20297, 20308, 20346, {f: 2, c: 20349}, 20375, 20414, 20431, michael@0: 20477, {f: 2, c: 20480}, 20496, 20507, 20519, 20526, 20567, 20582, 20586, michael@0: 20539, 20623, 20630, 20636, 20684, 20710, 20713, 20719, 20744, 20747, michael@0: 20752, 20763, 20766, 20831, 20897, 20924, 0, 20974, 20980, 20993, michael@0: [11913, 20994], 21011, 21065, 21089, 21094, 21139, 21192, 21232, michael@0: {f: 2, c: 21258}, 21310, 21324, 21323, 21345, 21356, 21419, 21466, 21478, michael@0: 21493, 21543, 21581, 21606, 21611, 21620, 21645, 21654, 21665, 21677, michael@0: 21689, 21695, 21702, 21709, 21774, 21803, 21813, 21834, 21856, 0, 21896, michael@0: 21902, 22024, {f: 2, c: 22030}, 22071, 22079, 22089, 22091, 22095, 22118, michael@0: 22121, 22127, {f: 2, c: 22129}, 22165, 22170, {f: 2, c: 22188}, 22193, michael@0: 22217, 22237, 22244, 22282, 22293, 22307, 22319, {f: 2, c: 22323}, 22348, michael@0: 22384, 22412, 22428, 22456, 22502, 22509, {f: 2, c: 22517}, 22527, 22537, michael@0: 22560, 22578, 22652, 22656, 22697, 22734, 22736, 22740, 22746, 22761, michael@0: 22796, 22820, 22831, 22881, 22893, 22986, 22994, 23005, {f: 2, c: 23011}, michael@0: 23044, 23052, 23075, 23111, 23125, 23139, 23149, 23166, 23198, 23207, michael@0: 23212, 23219, 23264, 23296, 23321, 23333, 23341, 23361, 23420, michael@0: {f: 2, c: 23422}, 23434, [11919, 23587], 23595, 23600, 23651, 23657, 23676, michael@0: 23755, 23762, 23796, 23844, 23846, 23875, 23878, 23882, 23954, 23956, michael@0: 23961, 23968, 24024, 24032, 24056, 24064, 24082, {f: 2, c: 24084}, 24088, michael@0: 24110, 24152, {f: 2, c: 24171}, 24232, 24234, {f: 2, c: 24254}, 0, 24274, michael@0: 24327, 24334, {f: 2, c: 24348}, 24354, 24360, 24374, 24379, 24384, michael@0: [12089, 24400], 24408, 24420, 24457, 24476, 24487, 24484, 24495, 24504, michael@0: [11926, 24516], 24521, 24545, 24553, 24557, 24572, 24599, 24602, 24627, michael@0: 24673, 24703, 24734, 24740, 24752, 24779, 24795, 24824, {f: 3, c: 24850}, michael@0: 24860, 24956, 24973, 24991, 25000, 25026, 25055, 25109, 25129, 25155, michael@0: 25158, [11928, 25164], 25169, 25174, 25284, 25340, 25354, 25357, 25368, michael@0: 25401, {f: 2, c: 25410}, 25445, 25460, 25469, 25476, 25479, 25488, 25502, michael@0: 25553, 25564, 25609, 25616, 25634, 25684, 25691, 25709, 25723, michael@0: {f: 2, c: 25790}, 25829, 25847, 25851, 25860, 25878, 25881, 25927, 25959, michael@0: 25985, 25989, 26050, 26096, 26098, 26156, 26188, {f: 2, c: 26203}, 26209, michael@0: 26219, 0, 26276, 26312, 26348, 26373, 26387, 26419, 26440, 26444, 26486, michael@0: 26491, 26544, 26546, 26617, 26583, 26585, 26608, 26668, {f: 2, c: 26672}, michael@0: 26715, 26738, 26741, 26746, 26756, 26789, 26802, 26832, 26838, 26856, michael@0: 26861, {f: 2, c: 26864}, 26876, 26897, 26899, 26933, 26939, 26967, 26979, michael@0: 26994, {f: 2, c: 27007}, 27046, 27053, 27063, {f: 2, c: 27094}, 27137, michael@0: 27151, 27157, 27176, 27188, 27198, 27205, {f: 2, c: 27216}, 27222, 27227, michael@0: 27267, 27273, 27281, {f: 3, c: 27293}, 27356, 27367, 27372, 27422, 27428, michael@0: 27445, 27462, 27478, 27488, 27522, 27582, 27617, 27633, 27664, 27699, michael@0: [11937, 27701], 11938, 27737, 27766, 27771, 27781, 27797, 27804, 27856, michael@0: 27860, 27862, 27872, {f: 2, c: 27883}, 27886, 27914, 27918, 27921, 27950, michael@0: 27991, 27998, 28005, 28034, 28095, 28100, 28106, 28118, 28137, 28194, michael@0: 28241, 28359, 28362, 28366, 28413, 28442, 28458, 28463, 28467, 28506, michael@0: 28510, 28514, 28541, 28555, 28557, 28562, 28564, 28570, {f: 2, c: 28583}, michael@0: 28598, 28634, 28638, 0, 28729, 28732, 0, 28756, {f: 2, c: 28765}, 28772, michael@0: [11939, 28780], 28798, 28801, 28821, 28855, {f: 2, c: 28883}, 28888, 28892, michael@0: 28935, 28960, 28977, 29002, 29010, 29024, 29049, 29074, 0, 29131, 29139, michael@0: 29142, 29184, 29213, 29227, 29240, 29249, 29267, {f: 2, c: 29269}, 29276, michael@0: 29325, [11944, 29357], 29364, 29383, 29435, {f: 2, c: 29444}, 29480, 29489, michael@0: 29507, 29548, 29564, 29571, {f: 2, c: 29573}, 29589, {f: 3, c: 29598}, michael@0: 29606, 29611, 29621, 29623, 29628, 29647, 29657, 29673, 29684, 29693, michael@0: 29700, 29706, {f: 2, c: 29722}, 29732, 29736, 29740, {f: 3, c: 29743}, michael@0: 29753, 29764, 29767, 29771, 29773, 29777, 29783, 29798, 29803, 29809, michael@0: 29824, {f: 3, c: 29829}, 29840, 29848, 29852, 29856, 29859, 29864, 29867, michael@0: 29877, 29887, 29896, 29914, 29918, 30030, 30073, 30081, 30096, michael@0: [12135, 30098], 30099, 30132, 30180, 30201, 30208, 30218, {f: 2, c: 30229}, michael@0: 30233, 30238, 30253, 30261, 30275, 30283, 30309, 30317, 30319, 30321, michael@0: 30324, {f: 2, c: 30372}, 30405, 30412, 30444, 30460, 30516, 30518, 30556, michael@0: {f: 2, c: 30559}, 30578, 30589, 30613, 30634, 30694, 30704, 30708, 30726, michael@0: 30754, {f: 2, c: 30765}, 30768, 30773, 30824, 30878, 30920, 30924, 30926, michael@0: 30948, {f: 2, c: 30944}, 30962, 30967, 30971, 31025, 0, [11949, 31035], michael@0: 31037, 31045, {f: 2, c: 31067}, 31115, 31126, 31128, [12145, 31160], 31163, michael@0: 31178, 31194, 31235, 31241, 31249, 31262, 31277, 31289, 31301, 31308, michael@0: 31325, 0, 31341, 31352, 31392, 31395, 31411, {f: 2, c: 31419}, 31430, michael@0: 31495, 31508, 31527, 31537, 31559, 31566, 31584, 31593, 31597, 31602, michael@0: 31633, 31663, 31703, 31705, 31755, 31759, 31776, 31782, 31793, 31798, michael@0: 31825, 31833, 31847, 31854, 31856, 31932, 31935, {f: 2, c: 31944}, 31959, michael@0: 31961, 31965, 31979, {f: 3, c: 32007}, 32019, 32029, 32035, 32065, 32083, michael@0: 32089, 32093, 32122, 32134, {f: 2, c: 32139}, 32204, 32235, 32241, 32249, michael@0: 32264, 32273, 32277, 32288, 32327, 32354, 32366, 32371, 32397, 32401, michael@0: 32408, 32580, 32591, [11947, 11954, 32594], [11953, 32595], 32609, 32657, michael@0: 32703, 32718, 32735, 32741, 32748, {f: 2, c: 32750}, 32762, 32782, 32785, michael@0: 32788, 32804, 32806, 32826, 32828, 32864, 32881, 32885, 32926, 32934, michael@0: 32939, {f: 2, c: 32983}, 33046, 33048, 33082, 33098, 33100, 33153, 33156, michael@0: 33204, 33231, 33273, 33283, 33313, 33330, 33332, 33350, 33355, 33359, michael@0: 33422, 33454, 33463, 33470, 33478, 33534, 33603, 33617, 33621, 33670, michael@0: 33677, 33682, 33688, 33705, {f: 2, c: 33727}, 33770, 33807, 33809, 33866, michael@0: 33910, 33960, 33967, 33984, 33986, 34032, 34045, 34060, 34100, 34142, michael@0: 34191, 34231, 34254, 34221, 34322, 34345, 34386, 34403, 34412, 34415, michael@0: 34426, 34445, 34449, 34456, {f: 2, c: 34471}, 34554, 34557, 34571, 34579, michael@0: 34585, 34590, 34600, 34622, 34673, 34696, 34713, {f: 2, c: 34732}, 34741, michael@0: 34774, 34795, 34797, 34817, 0, 34822, 34827, 34836, 34844, 34902, 34911, michael@0: [11970, 34916], 34968, 34986, {f: 2, c: 35005}, 35018, 35026, 35035, michael@0: {f: 2, c: 35056}, 35078, {f: 3, c: 35096}, 35111, 35120, 35134, 35195, michael@0: 35284, 35286, 35301, 35313, 35335, 35343, 35349, 35362, 35406, 35455, michael@0: 35572, 35615, 35639, {f: 2, c: 35651}, 35668, 35740, 35742, 35911, 35924, michael@0: 35955, 36004, 36057, 36065, 36088, 36094, 36123, 36201, 36204, 36228, michael@0: 36237, 36245, 36262, 36294, 36302, 36324, 36332, 36384, 36427, 36460, michael@0: 36464, 36474, 36498, 36526, 36531, 36561, 36564, 36601, 36631, 36662, michael@0: 36774, [12193, 36789], [11981, 36790], 0, 36832, 36836, 36854, 36866, michael@0: 36908, 36932, 37000, 37013, 37017, 37019, 37026, 37044, 37079, 37085, michael@0: 37108, 37143, 37148, 37169, 37178, 37181, 37192, 37211, 37217, 37220, michael@0: 37262, 37278, 37288, {f: 2, c: 37293}, 37298, 37308, 37360, 37367, 37371, michael@0: 37383, 37416, 37427, 37432, 37443, 37447, 37455, 37472, 37570, michael@0: {f: 2, c: 37579}, 37599, 37645, 37653, 37663, 37671, 37703, 37714, 0, michael@0: 37738, 37741, 37787, 37818, 37801, 37825, 37834, 37858, 37882, 37885, michael@0: 37903, 37940, 37951, 37973, 37995, 38002, [11986, 38264], 38310, 38313, 0, michael@0: 38324, 38333, 38362, [11983, 11990, 38429], 38465, 38488, 38532, 38564, michael@0: 38569, 38610, 195060, 38622, 38633, 38641, 38658, 38665, 38746, 38755, michael@0: 38766, 38771, 38810, 38818, {f: 2, c: 38837}, 38873, 38878, 38900, 38922, michael@0: 38926, 38942, 38947, 38955, 38974, {f: 2, c: 38994}, 39001, 39020, 39096, michael@0: 39098, 39103, 39112, 39141, {f: 2, c: 39218}, 39232, 39245, 39260, 39263, michael@0: 39345, {f: 2, c: 39353}, 39369, 39426, 39446, 39460, 39463, michael@0: {f: 2, c: 39469}, 39478, 39480, 39498, 39510, {f: 2, c: 39605}, 39673, michael@0: 39683, 39712, {f: 2, c: 39731}, 39795, 39801, 39847, 39873, 39879, 39895, michael@0: 39911, 39915, 39927, 39930, 39933, 39947, 39975, 39978, 39990, 40001, michael@0: 40019, 40035, 40048, 40055, 40194, 40258, 40263, 40291, 40297, 40316, michael@0: 40318, 40333, 40369, 40387, 40391, 40406, 40415, 40427, 40436, 40469, michael@0: 40477, 40612, 40616, 40620, 40679, 40686, 40720, 40722, 40727, 40729, michael@0: 40751, 40759, 40761, 40769, 40773, 40791, 40808, 40817, 40821, 40848, michael@0: 40852, 40866, 0, 13317, 194564, 22048, 24267, 11925, 0, 144954, 0, 28665, michael@0: 28390, 29107, [11940, 64073], {s: 4}, [11980, 64102], 0, 23986, 0, 20435, michael@0: 20697, 20720, 20931, 22134, 27220, 27905, 28112, 28226, 28377, 29668, michael@0: 29729, 30060, 30801, 34805, 144382, 29608, 15091, 13531, 17420, 16010, 0, michael@0: 0, 19432, 0, 16090, 15138, 0, 17786, 16531, 0, 18021, 16643, 17043, 18094, michael@0: 13448, 140809, {f: 3, c: 63584}, 63610, 63615, {s: 23}, {f: 2, c: 8836}, michael@0: {f: 2, c: 8842}, 8713, 0, {f: 2, c: 8965}, {s: 9}, {f: 2, c: 8741}, michael@0: {s: 14}, 8802, 0, 8773, 8776, {f: 2, c: 8822}, {s: 4}, 8487, {s: 209}, michael@0: {f: 2, c: 8922}, 8533, 8984, {f: 2, c: 7742}, {f: 2, c: 504}, 470, 472, michael@0: 474, 476, 260, 728, 317, 346, 350, 356, 377, 379, 261, 731, 318, 347, 711, michael@0: 351, 357, 378, 733, 380, 340, 258, 313, 262, 268, 280, 270, 323, 327, 336, michael@0: 344, 368, 354, 341, 259, 314, 263, 269, 281, 271, 273, 324, 328, 337, 345, michael@0: 369, 355, 729, 264, 284, 292, 308, 348, 364, 265, 285, 293, 309, 349, 365, michael@0: 625, 651, 638, 620, 622, 633, 648, 598, 627, 637, 642, 656, 635, 621, 607, michael@0: 626, 669, 654, 609, 624, 641, 295, 661, 660, 614, 664, 450, 595, 599, 644, michael@0: 608, 403, 616, 649, 600, 604, 606, 592, 623, 650, 612, 594, 653, 613, 674, michael@0: 673, 597, 657, 634, 615, 865, 712, 716, 721, 8255, 783, {f: 5, c: 741}, 0, michael@0: 0, 805, 812, 825, 796, {f: 2, c: 799}, 829, 809, 815, 734, 804, 816, 828, michael@0: 820, {f: 2, c: 797}, {f: 2, c: 792}, 810, {f: 2, c: 826}, 794, {s: 3}, michael@0: {f: 2, c: 610}, 618, 628, 630, 632, 640, 655, 665, 668, 671, 688, 690, 695, michael@0: 704, {f: 2, c: 736}, {s: 6}, 8862, {s: 287}, 12348, 12543, 0, michael@0: {f: 2, c: 12310}, 9838, 9835, {f: 2, c: 10548}, 10687, 0, 12448, 0, michael@0: {f: 2, c: 10746}, {s: 13}, 962, {f: 10, c: 9461}, {f: 2, c: 9750}, 9649, michael@0: {f: 10, c: 12784}, 0, {f: 6, c: 12794}, {f: 15, c: 9150}, 0, 0, 10003, 0, michael@0: 9251, 9166, {f: 4, c: 9680}, {f: 2, c: 8263}, 0, 8273, 8258, michael@0: {f: 16, c: 12688}, {s: 13}, {f: 2, c: 9136}, {f: 12, c: 9842}, michael@0: {f: 2, c: 12441}, 8413, {s: 450}, 20296, 20319, 20330, 20332, 20494, 20504, michael@0: 20545, 20722, 20688, 20742, 20739, 20789, 20821, 20823, 13493, 20938, michael@0: 20962, 21079, 21196, 21206, 21243, 21276, 21347, 21405, 21522, 21631, michael@0: 21640, 21840, 21889, 21933, 21966, 22075, 22174, 22185, 22195, 22391, michael@0: 22396, 135963, 22479, 22500, 22628, 22665, 136302, 22738, 22752, 34369, michael@0: 22923, 22930, 22979, 23059, 23143, 23159, 23172, 23236, 137405, 23421, michael@0: 23443, 23570, 64060, 136884, 23674, 23695, 23711, 23715, 23722, 23760, michael@0: 138804, 23821, 23879, 23937, 23972, 23975, 24011, 24158, 24313, 24320, michael@0: 24322, 24355, 24381, 24404, 24445, 24589, 24596, 24600, 24629, 24647, michael@0: 24733, 24788, 24797, 24875, 25020, 25017, 25122, 25178, 25199, 25302, michael@0: 25468, 25573, 25721, 25796, 25808, 25897, 26013, 26170, 26146, 26155, michael@0: 26160, 26163, 26184, 143812, {f: 2, c: 26231}, 26253, 26299, 26331, 26344, michael@0: 26439, 26497, 26515, 26520, 26523, 26620, 26653, 26787, 26890, 26953, michael@0: 144836, 26946, 26980, 27045, 27087, 15286, 15299, 27113, 27125, 145215, michael@0: 27195, 145251, 27284, 27301, 15375, 27419, 27436, 27495, 27561, 27565, michael@0: 27607, 27647, 27653, 27764, 27800, 27899, 27846, 27953, 27961, 27967, michael@0: 27992, 28052, 28074, 28123, 28125, 28228, 28254, 28337, 28353, 28432, michael@0: 28505, 28513, 28542, 28556, 28576, 28604, 28615, 28618, 28656, 28750, michael@0: 28789, 28836, 28900, 28971, 28958, 28974, 29009, 29032, 29061, 29063, michael@0: 29114, 29124, 29205, 15935, 29339, 149489, 29479, 29520, 29542, 29602, michael@0: 29739, 29766, 29794, 29805, 29862, 29865, 29897, 29951, 29975, 16242, michael@0: 30158, 30210, 30216, 30308, 30337, 30365, 30378, 30390, 30414, 30420, michael@0: 30438, 30449, 30474, 30489, {f: 2, c: 30541}, 30586, 30592, 30612, 30688, michael@0: 152718, 30787, 30830, 30896, 152846, 30893, 30976, 31004, 31022, 31028, michael@0: 31046, 31097, 31176, 153457, 31188, 31198, 31211, 31213, 31365, 154052, michael@0: 31438, 31485, 31506, 31533, 31547, 31599, 31745, 31795, 155041, 31853, michael@0: 31865, 31887, 31892, 31904, 31957, 32049, 32092, 32131, 32166, 32194, michael@0: 32296, 32663, 32731, 32821, 32823, 32970, 32992, 33011, 33120, michael@0: {f: 2, c: 33127}, 33133, 33211, 33226, 33239, 17499, 33376, 33396, 158463, michael@0: 33441, {f: 2, c: 33443}, 33449, 33471, 33493, 33533, 33536, 33570, 33581, michael@0: 33594, 33607, 33661, 33703, 33743, 33745, 33761, 33793, 33798, 33887, michael@0: 33904, 33907, 33925, 33950, 33978, 159296, 34098, 34078, 34095, 34148, michael@0: 34170, 34188, 34210, 34251, 34285, 34303, {f: 2, c: 34308}, 34320, 159988, michael@0: 34328, 34360, 34391, 34402, 17821, 34421, 34488, 34556, 34695, 17898, michael@0: 34826, 34832, 35022, 161412, 35122, 35129, 35136, 35220, 35318, 35399, michael@0: 35421, 35425, 35445, 35536, 35654, 35673, 35689, 35741, 35913, 35944, michael@0: 36271, 36305, 36311, 36387, 36413, 36475, 164471, 18500, 36602, 36638, michael@0: 36653, 36692, 164813, 36840, 36846, 36872, 36909, 37015, 37043, 37054, michael@0: {f: 2, c: 37060}, 37063, 37103, 37140, 37142, {f: 2, c: 37154}, 37167, michael@0: 37172, 37251, 37361, 37705, {f: 2, c: 37732}, 37795, 37855, 37892, 37939, michael@0: 37962, 37987, 38001, 38286, 38303, 38316, 38326, 38347, 38352, 38355, michael@0: 18864, 38366, 38565, 38639, 38734, 38805, 38830, 38842, 38849, 38857, michael@0: 38875, 38998, 39143, 39256, 39427, 39617, 39619, 39630, 39638, 39682, michael@0: 39688, 19479, 39725, 39774, 39782, 39812, 39818, 39838, 39886, 39909, michael@0: 39928, 39971, {f: 2, c: 40015}, 40037, {f: 2, c: 40221}, 40259, 40274, michael@0: 40330, 40342, 40384, 40364, 40380, 172432, 40423, 40455, 40606, 40623, michael@0: 40855, 131209, 19970, 19983, 19986, 20009, 20014, 20039, 131234, 20049, michael@0: 13318, 131236, 20073, 20125, 13356, 20156, 20163, 20168, 20203, 20186, michael@0: 20209, 20213, 20246, 20324, 20279, 20286, 20312, 131603, {f: 2, c: 20343}, michael@0: 20354, 20357, 20454, 20402, 20421, 20427, 20434, 13418, 20466, 20499, michael@0: 20508, 20558, 20563, 20579, 20643, 20616, {f: 2, c: 20626}, 20629, 20650, michael@0: 131883, 20657, {f: 2, c: 20666}, 20676, 20679, 20723, 131969, 20686, michael@0: 131953, 20692, 20705, 13458, 132089, 20759, 132170, 20832, 132361, 20851, michael@0: 20867, 20875, 13500, 20888, 20899, 20909, 13511, 132566, 20979, 21010, michael@0: 21014, 132943, 21077, 21084, 21100, 21111, 21124, 21122, 133127, 21144, michael@0: 133178, 21156, {f: 2, c: 21178}, 21194, 21201, 133305, 21239, 21301, 21314, michael@0: 133500, 133533, 21351, 21370, 21412, 21428, 133843, 21431, 21440, 133917, michael@0: {f: 2, c: 13661}, 21461, 13667, 21492, 21540, 21544, 13678, 21571, 21602, michael@0: 21612, 21653, 21664, 21670, 21678, 21687, 21690, 21699, 134469, 21740, michael@0: 21743, 21745, 21747, {f: 2, c: 21760}, 21769, 21820, 21825, 13734, 21831, michael@0: 13736, 21860, 134625, 21885, 21890, 21905, 13765, 21970, 134805, 134765, michael@0: 21951, 21961, 21964, 21969, 21981, 13786, 21986, 134756, 21993, 22056, michael@0: 135007, 22023, 22032, 22064, 13812, 22077, 22080, 22087, 22110, 22112, michael@0: 22125, 13829, 22152, 22156, 22173, 22184, 22194, 22213, 22221, 22239, michael@0: 22248, {f: 2, c: 22262}, 135681, 135765, 22313, 135803, {f: 2, c: 22341}, michael@0: 22349, 135796, 22376, 22383, {f: 3, c: 22387}, 22395, 135908, 135895, michael@0: 22426, {f: 2, c: 22429}, 22440, 22487, 135933, 22476, 135990, 136004, michael@0: 22494, 22512, 13898, 22520, 22523, 22525, 22532, 22558, 22567, 22585, michael@0: 136132, 22601, 22604, 22631, {f: 2, c: 22666}, 22669, {f: 2, c: 22671}, michael@0: 22676, 22685, 22698, 22705, 136301, 22723, 22733, 22754, {f: 2, c: 22771}, michael@0: {f: 2, c: 22789}, 22797, 22804, 136663, 13969, 22845, 13977, 22854, 13974, michael@0: 158761, 22879, 136775, {f: 2, c: 22901}, 22908, 22943, 22958, 22972, 22984, michael@0: 22989, 23006, 23015, 23022, 136966, 137026, 14031, 23053, 23063, 23079, michael@0: 23085, 23141, 23162, 23179, 23196, {f: 2, c: 23199}, 23202, 23217, 23221, michael@0: 23226, 23231, 23258, 23260, 23269, 23280, 23278, 23285, 23304, 23319, michael@0: 23348, 23372, 23378, 23400, 23407, 23425, 23428, 137667, 23446, 23468, michael@0: {f: 2, c: 14177}, 23502, 23510, 14188, 14187, 23537, 23549, 14197, 23555, michael@0: 23593, 138326, 23647, {f: 2, c: 23655}, 23664, 138541, 138565, 138616, michael@0: 138594, 23688, 23690, 14273, 138657, 138652, 23712, 23714, 23719, 138642, michael@0: 23725, 23733, 138679, 23753, 138720, 138803, 23814, 23824, 23851, 23837, michael@0: 23840, 23857, 23865, 14312, 23905, 23914, 14324, 23920, 139038, 14333, michael@0: 23944, 14336, 23959, 23984, 23988, 139126, 24017, 24023, 139258, 24036, michael@0: 24041, 14383, 14390, 14400, 24095, 24126, 24137, 14428, 24150, 14433, michael@0: {f: 2, c: 24173}, 139643, 24229, 24236, 24249, 24262, 24281, 140062, 24317, michael@0: 24328, 140205, 24350, 24391, 24419, 24434, 24446, 24463, 24482, 24519, michael@0: 24523, {f: 3, c: 24530}, 24546, {f: 2, c: 24558}, 24563, 14615, 24610, michael@0: 24612, 14618, 24652, 24725, 24744, 141043, 24753, 24766, 24776, 24793, michael@0: 24814, 24821, 24848, 24857, 24862, 24890, 14703, 24897, 24902, 24928, michael@0: 141403, {f: 2, c: 24978}, 24983, 24997, 25005, 141483, 25045, 25053, 25077, michael@0: 141711, 25123, 25170, 25185, 25188, 25211, 25197, 25203, 25241, 25301, michael@0: 142008, 25341, 25347, 25360, {f: 2, c: 142159}, 25394, 25397, michael@0: {f: 2, c: 25403}, 25409, 25412, 25422, 142150, 25433, 142365, 142246, michael@0: 25452, 25497, 142372, 25492, 25533, {f: 2, c: 25556}, 25568, michael@0: {f: 2, c: 25579}, 25586, 25630, 25637, 25641, 25647, 25690, 25693, 25715, michael@0: 25725, 25735, 25745, 25759, {f: 2, c: 25803}, 25813, 25815, 142817, 25828, michael@0: 25855, 14958, 25871, 25876, 14963, 25886, 25906, 25924, 25940, 25963, michael@0: 25978, 25988, 25994, 26034, 26037, 26040, 26047, 26057, 26068, 15062, michael@0: 26105, 26108, 26116, 26120, 26145, 26154, 26181, 26193, 26190, 15082, michael@0: 143811, 143861, 143798, 26218, {f: 2, c: 26220}, 26235, 26240, 26256, michael@0: 26258, 15118, 26285, 26289, 26293, 15130, 15132, 15063, 26369, 26386, michael@0: 144242, 26393, 144339, 144338, 26445, 26452, 26461, 144336, 144356, 144341, michael@0: 26484, 144346, 26514, 144351, 33635, 26640, 26563, 26568, 26578, 26587, michael@0: 26615, 144458, 144465, 144459, 26648, 26655, 26669, 144485, 26675, 26683, michael@0: 26686, 26693, 26697, 26700, 26709, 26711, 15223, 26731, 26734, 26748, michael@0: 26754, 26768, 26774, 15213, {f: 3, c: 26776}, 26780, {f: 2, c: 26794}, michael@0: 26804, 26811, 26875, 144612, 144730, 26819, 26821, 26828, 26841, michael@0: {f: 2, c: 26852}, 26860, 26871, 26883, 26887, 15239, 144788, 15245, 26950, michael@0: 26985, 26988, 27002, 27026, 15268, 27030, 27056, 27066, 27068, 27072, michael@0: 27089, 144953, 144967, 144952, 27107, {f: 2, c: 27118}, 27123, 15309, michael@0: 27124, 27134, 27153, 27162, 27165, 145180, {f: 2, c: 27186}, 27199, 27209, michael@0: 27258, 27214, 27218, 27236, 145164, 27275, 15344, 27297, 145252, 27307, michael@0: 27325, 27334, 27348, 27344, 27357, 145407, 145383, {f: 3, c: 27377}, 27389, michael@0: 145444, 27403, {f: 3, c: 27407}, 145469, 27415, 15398, 27439, 27466, 27480, michael@0: 27500, 27509, [11934, 27514], 27521, 27547, 27566, 146072, 27581, michael@0: {f: 3, c: 27591}, 27610, {f: 2, c: 27622}, 27630, 27650, 27658, 27662, michael@0: 27702, 146559, 27725, 27739, 27757, 27780, 27785, 15555, 27796, 27799, michael@0: 27821, 27842, 15570, 27868, 27881, 27885, 146688, 27904, 27940, michael@0: {f: 2, c: 27942}, 27751, 27951, 27964, 27995, 28000, 28016, michael@0: {f: 2, c: 28032}, 28042, 28045, 28049, 28056, 146752, 146938, 146937, michael@0: 146899, 28075, 28078, 28084, 28098, 27956, 28104, 28110, 28127, 28150, michael@0: 28214, 28190, 15633, 28210, {f: 2, c: 28232}, {f: 2, c: 28235}, 28239, michael@0: {f: 2, c: 28243}, 28247, 28259, 15646, 28307, 28327, 28340, 28355, 28469, michael@0: 28395, 28409, 28411, 28426, 28428, 28440, 28453, 28470, 28476, 147326, michael@0: 28498, 28503, 28512, 28520, 28560, 28566, 28606, 28575, 28581, 28591, michael@0: 15716, {f: 2, c: 28616}, 28649, 147606, 28668, 28672, 28682, 28707, 147715, michael@0: 28730, 28739, 28743, 28747, 15770, 28773, 28777, 28782, 28790, 28806, michael@0: 28823, 147910, 28831, 28849, 147966, 28908, 28874, 28881, 28931, 28934, michael@0: 28936, 28940, 15808, 28975, 29008, 29011, 29022, 15828, 29078, 29056, michael@0: 29083, 29088, 29090, {f: 2, c: 29102}, 148412, 29145, 29148, 29191, 15877, michael@0: 29236, 29241, 29250, 29271, 29283, 149033, {f: 2, c: 29294}, 29304, 29311, michael@0: 29326, 149157, 29358, 29360, 29377, 15968, 29388, 15974, 15976, 29427, michael@0: 29434, 29447, 29458, {f: 2, c: 29464}, 16003, 29497, 29484, 29491, 29501, michael@0: 29522, 16020, 29547, 149654, {f: 2, c: 29550}, 29553, 29569, 29578, 29588, michael@0: 29592, 29596, 29605, 29625, 29631, 29637, 29643, 29665, 29671, 29689, michael@0: 29715, 29690, 29697, 29779, 29760, 29763, 29778, 29789, 29825, 29832, michael@0: 150093, 29842, 29847, 29849, 29857, 29861, 29866, 29881, 29883, 29882, michael@0: 29910, 29912, 29931, 150358, 29946, 150383, 29984, 29988, 29994, 16215, michael@0: 150550, {f: 2, c: 30013}, 30016, 30024, 30032, 30034, 30066, 30065, 30074, michael@0: {f: 2, c: 30077}, 30092, 16245, 30114, 16247, 30128, 30135, michael@0: {f: 2, c: 30143}, 30150, 30159, 30163, 30173, {f: 2, c: 30175}, 30183, michael@0: 30190, 30193, 30211, 30232, 30215, 30223, 16302, 151054, 30227, michael@0: {f: 2, c: 30235}, 151095, 30245, 30248, 30268, 30259, 151146, 16329, 30273, michael@0: 151179, 30281, 30293, 16343, 30318, 30357, 30369, 30368, {f: 2, c: 30375}, michael@0: 30383, 151626, 30409, 151637, 30440, 151842, 30487, 30490, 30509, 30517, michael@0: 151977, 16441, 152037, 152013, 30552, 152094, 30588, 152140, 16472, 30618, michael@0: 30623, 30626, 30628, {f: 2, c: 30686}, 30692, 30698, 30700, 30715, 152622, michael@0: 30725, 30729, 30733, 30745, 30764, 30791, 30826, 152793, 30858, 30868, michael@0: 30884, 30877, 30879, 30907, 30933, 30950, {f: 2, c: 30969}, 30974, 152999, michael@0: 30992, 31003, 31013, 31050, 31064, 16645, 31079, 31090, 31125, 31137, michael@0: 31145, 31156, 31170, 31175, {f: 2, c: 31180}, 31190, 16712, 153513, 153524, michael@0: 16719, 31242, 31253, 31259, 16739, 31288, 31303, 31318, 31321, 31324, michael@0: 31327, 31335, 31338, 31349, 31362, 31370, 31376, 31404, 154068, 16820, michael@0: 31417, 31422, 16831, 31436, 31464, 31476, 154340, 154339, 154353, 31549, michael@0: 31530, {f: 2, c: 31534}, 16870, 16883, 31615, 31553, 16878, 31573, 31609, michael@0: 31588, 31590, 31603, 154546, 16903, 31632, 31643, 16910, 31669, 31676, michael@0: 31685, 31690, 154699, 154724, 31700, 31702, 31706, 31722, 31728, 31747, michael@0: 31758, 31813, 31818, 31831, 31838, 31841, 31849, 31855, 155182, 155222, michael@0: 155237, 31910, 155234, {f: 2, c: 31926}, 155352, 31940, 155330, 31949, michael@0: 155368, 155427, 31974, 155484, 31989, 32003, 17094, 32018, 32030, 155616, michael@0: 155604, {f: 2, c: 32061}, 32064, 32071, 155660, 155643, 17110, 32090, michael@0: 32106, 32112, 17117, 32127, 155671, 32136, 32151, 155744, 32157, 32167, michael@0: 32170, 32182, 32192, 32215, 32217, 32230, 17154, 155885, 64088, 32272, michael@0: 32279, 32285, 32295, 32300, 32325, 32373, 32382, {f: 2, c: 32390}, 17195, michael@0: 32410, 17219, 32572, 32571, 32574, 32579, 13505, 156272, 156294, michael@0: {f: 2, c: 32611}, 32621, {f: 2, c: 32637}, 32656, 20859, 146702, 32662, michael@0: 32668, 32685, 156674, 32707, 32719, 32739, 32754, 32778, 32776, 32790, michael@0: 32812, 32816, 32835, 32870, 32891, 32921, 32924, 32932, 32935, 32952, michael@0: 157310, 32965, 32981, 32998, 33037, 33013, 33019, 17390, 33077, 33054, michael@0: 17392, 33060, 33063, 33068, 157469, 33085, 17416, 33129, 17431, 17436, michael@0: 33157, 17442, 33176, 33202, 33217, 33219, 33238, 33243, 157917, 33252, michael@0: 157930, 33260, 33277, 33279, 158063, 33284, 158173, 33305, 33314, 158238, michael@0: 33340, 33353, 33349, 158296, 17526, 17530, 33367, 158348, 33372, 33379, michael@0: 158391, 17553, 33405, 33407, 33411, 33418, 33427, {f: 2, c: 33447}, 33458, michael@0: 33460, 33466, 33468, 33506, 33512, 33527, {f: 2, c: 33543}, 33548, 33620, michael@0: 33563, 33565, 33584, 33596, 33604, 33623, 17598, 17620, 17587, michael@0: {f: 2, c: 33684}, 33691, 33693, 33737, 33744, 33748, 33757, 33765, 33785, michael@0: 33813, 158835, 33815, 33849, 33871, {f: 2, c: 33873}, {f: 2, c: 33881}, michael@0: 33884, 158941, 33893, 33912, 33916, 33921, 17677, 33943, 33958, 33982, michael@0: 17672, {f: 2, c: 33998}, 34003, 159333, 34023, 34026, 34031, 34033, 34042, michael@0: 34075, {f: 2, c: 34084}, 34091, 34127, 34159, 17731, 34129, michael@0: {f: 2, c: 34145}, 159636, 34171, 34173, 34175, 34177, 34182, 34195, 34205, michael@0: 34207, 159736, {f: 2, c: 159734}, 34236, 34247, 34250, {f: 2, c: 34264}, michael@0: 34271, 34273, 34278, 34294, 34304, 34321, 34334, 34337, 34340, 34343, michael@0: 160013, 34361, 34364, 160057, 34368, 34387, 34390, 34423, 34439, 34441, michael@0: {f: 2, c: 34460}, 34481, 34483, 34497, 34499, 34513, 34517, 34519, 34531, michael@0: 34534, 17848, 34565, 34567, 34574, 34576, 34591, 34593, 34595, 34609, michael@0: 34618, 34624, 34627, 34641, 34648, {f: 2, c: 34660}, 34674, 34684, 160731, michael@0: 160730, 34727, 34697, 34699, 34707, 34720, 160766, 17893, 34750, 160784, michael@0: 34753, 34766, 34783, 160841, 34787, {f: 2, c: 34789}, 34794, 34835, 34856, michael@0: 34862, 34866, 34876, 17935, 34890, 34904, 161301, 161300, 34921, 161329, michael@0: 34927, 34976, 35004, 35008, 161427, 35025, 35027, 17985, 35073, 161550, michael@0: 35127, 161571, 35138, 35141, 35145, 161618, 35170, 35209, 35216, 35231, michael@0: 35248, 35255, 35288, 35307, 18081, 35315, 35325, 35327, 18095, 35345, michael@0: 35348, 162181, 35361, 35381, 35390, 35397, 35405, 35416, 35502, 35472, michael@0: 35511, 35543, 35580, 162436, 35594, 35589, 35597, 35612, 35629, 18188, michael@0: 35665, 35678, 35702, 35713, 35723, {f: 2, c: 35732}, 35897, 162739, 35901, michael@0: 162750, 162759, 35909, 35919, 35927, 35945, 35949, 163000, 35987, 35986, michael@0: 35993, 18276, 35995, 36054, 36053, 163232, 36081, 163344, 36105, 36110, michael@0: 36296, 36313, 36364, 18429, 36349, 36358, 163978, 36372, 36374, michael@0: {f: 2, c: 36385}, 36391, 164027, 18454, 36406, 36409, 36436, 36450, 36461, michael@0: 36463, 36504, 36510, 36533, 36539, 164482, 18510, 164595, 36608, 36616, michael@0: 36651, 36672, 36682, 36696, 164876, 36772, 36788, 164949, 36801, 36806, michael@0: 64036, 36810, 36813, 36819, 36821, 36849, 36853, 36859, 36876, 36919, michael@0: 165227, 36931, 36957, {f: 2, c: 165320}, 36997, 37004, 37008, 37025, 18613, michael@0: 37040, 37046, 37059, 37064, 165591, 37084, 37087, 165626, 37110, 37106, michael@0: 37120, 37099, {f: 2, c: 37118}, 37124, 37126, 37144, 37150, 37175, 37177, michael@0: {f: 2, c: 37190}, 37207, 37209, 37236, 37241, 37253, 37299, 37302, michael@0: {f: 2, c: 37315}, 166217, 166214, 37356, 37377, {f: 2, c: 37398}, 166251, michael@0: 37442, 37450, 37462, 37473, 37477, 37480, 166280, {f: 2, c: 37500}, 37503, michael@0: 37513, 37517, 37527, 37529, 37535, 37547, {f: 2, c: 166330}, 37554, michael@0: {f: 2, c: 37567}, 37574, 37582, 37605, 37649, 166430, 166441, 37623, 37673, michael@0: 166513, 166467, 37713, 37722, 37739, 37745, 37747, 37793, 166553, 166605, michael@0: 37768, 37771, 37775, 37790, 37877, 166628, 166621, 37873, 37831, 37852, michael@0: 37863, 37897, {f: 2, c: 37910}, 37883, 37938, 37947, 166849, 166895, 37997, michael@0: 37999, 38265, 38278, {f: 2, c: 38284}, 167184, 167281, 38344, 167419, michael@0: 167455, 38444, {f: 2, c: 38451}, 167478, 38460, 38497, 167561, 38530, michael@0: 167659, 38554, 167730, 18919, 38579, 38586, 38589, 18938, 167928, 38616, michael@0: 38618, 38621, 18948, 38676, 38691, 18985, 38710, 38721, 38727, 38743, michael@0: 38747, 38762, 168608, 168625, 38806, 38814, {f: 2, c: 38833}, 38846, 38860, michael@0: 38865, 38868, 38872, 38881, 38897, 38916, 38925, 38932, 38934, 19132, michael@0: 169104, {f: 2, c: 38962}, 38949, 38983, 39014, 39083, 39085, 39088, 169423, michael@0: 39095, {f: 2, c: 39099}, 39106, 39111, 39115, 39137, 39139, 39146, michael@0: {f: 2, c: 39152}, 39155, 39176, 19259, 169712, {f: 2, c: 39190}, 169753, michael@0: {f: 3, c: 39194}, 169808, 39217, {f: 3, c: 39226}, 39233, 39238, 39246, michael@0: 39264, 39331, 39334, 39357, 39359, 39363, 39380, 39385, 39390, 170182, michael@0: 39408, 39417, 39420, 39434, 39441, 39450, 39456, 39473, 39492, 39500, michael@0: 39512, 19394, 39599, 19402, 39607, 19410, 39609, 170610, 39622, 39632, michael@0: 39634, 39637, 39648, 39653, 39657, 39692, 39696, 39698, 39702, 39708, michael@0: 39723, 39741, 19488, 39755, 39779, 39781, {f: 2, c: 39787}, michael@0: {f: 2, c: 39798}, 39846, 39852, 171483, 39858, 39864, 39870, 39923, 39896, michael@0: 39901, 39914, 39919, 39918, 171541, 171658, 171593, 39958, michael@0: {f: 3, c: 39960}, 39965, 39970, 39977, 171716, 39985, 39991, 40005, 40028, michael@0: 171753, {f: 2, c: 40009}, 171739, 40020, 40024, 40027, 40029, 40031, michael@0: {f: 3, c: 40041}, {f: 2, c: 40045}, 40050, 40053, 40058, 40166, 40178, michael@0: 40203, [171982, 171991], 40209, {f: 2, c: 40215}, 172079, 19652, 172058, michael@0: 40242, 19665, 40266, 40287, 40290, 172281, 172162, 40307, {f: 2, c: 40310}, michael@0: 40324, 40345, 40353, 40383, 40373, 40377, 40381, 40393, 40410, 40416, michael@0: 40419, 19719, 40458, 40450, 40461, 40476, 40571, 139800, 40576, 40581, michael@0: 40603, 172940, 40637, 173111, 40671, 40703, 40706, 19831, 40707, 40762, michael@0: 40765, 40774, 40787, 40789, 40792, 173553, 40797, 173570, 40809, 40813, michael@0: 40816, 173746, 11948, 13844, 14509, 15820, 16348, 17854, 17936, 19326, michael@0: 19512, 19681, 19980, {f: 2, c: 20003}, 20089, 20211, 20236, 20249, 20267, michael@0: 20270, 20273, 20356, 20382, 20407, 20484, 20492, 20556, 20575, 20578, michael@0: 20599, 20622, 20638, 20642, 20675, 20712, 20721, 20734, 20743, michael@0: {f: 3, c: 20748}, 20787, 20792, 20852, 20868, 20920, 20922, 20936, 20943, michael@0: 20945, {f: 2, c: 20947}, 20952, 20959, 20997, 21030, 21032, 21035, michael@0: {f: 2, c: 21041}, 21045, 21052, 21082, 21088, 21102, {f: 2, c: 21112}, michael@0: 21130, 21132, 21217, 21225, 21233, 21251, 21265, 21279, 21293, 21298, michael@0: 21309, 21349, 21357, 21369, 21374, 21396, 21401, 21418, 21423, 21434, michael@0: 21441, {f: 2, c: 21444}, 21472, 21523, 21546, 21553, {f: 2, c: 21556}, michael@0: 21580, 21671, 21674, 21681, 21691, 21710, 21738, 21756, 21765, 21768, michael@0: 21781, 21799, 21802, 21814, 21841, 21862, 21903, 21906, 21908, 21924, michael@0: 21938, 21955, 21958, 21971, 21979, 21996, 21998, 22001, 22006, 22008, michael@0: 22021, 22029, {f: 2, c: 22033}, 22060, 22069, 22073, 22093, 22100, 22149, michael@0: 22175, 22182, 22199, 22220, 22223, 22233, 22241, 22251, 22253, 22257, michael@0: 22279, 22284, {f: 2, c: 22298}, 22301, 22316, 22318, {f: 2, c: 22333}, michael@0: 22367, 22379, 22381, 22394, 22403, 22423, 22446, 22485, 22503, 22541, michael@0: 22566, 22605, 22607, 22623, 22637, 22655, 22657, 22680, 22716, 22815, michael@0: 22819, 22873, 22905, 22935, 22959, 22963, 23007, 23025, 23032, 23218, michael@0: 23224, 23274, 23286, 23323, 23325, 23329, 23352, 23479, 23511, 23520, michael@0: 23583, 23594, 23596, 23606, 23641, 23644, 23661, 23773, 23809, 23860, michael@0: 23869, 23897, 23934, 23939, 24007, 24057, 24104, 24114, 24117, 24155, michael@0: 24168, 24170, 24183, 24192, 24203, 24243, 24253, 24273, {f: 2, c: 24276}, michael@0: 24397, 24492, 24554, 24583, 24649, 24660, 24679, 24763, 24772, 24829, michael@0: 24842, 24854, 24874, 24886, 24926, 24932, 24955, 24957, 24959, 24989, michael@0: 25016, 25052, 25058, 25061, 25064, 25092, 25095, 25137, 25145, 25149, michael@0: 25210, 25232, 25256, 25306, 25332, 25366, 25386, 25398, 25414, 25419, michael@0: 25427, 25457, 25461, 25471, 25474, 25482, {f: 2, c: 25518}, 25578, michael@0: {f: 2, c: 25592}, 25618, 25624, 25632, 25636, 25642, 25653, 25661, 25663, michael@0: 25682, 25695, 25716, 25744, {f: 2, c: 25752}, 25772, 25779, 25837, 25840, michael@0: 25883, 25887, 25902, 25929, 25952, 26002, 26005, 26036, 26046, 26056, michael@0: 26062, 26064, 26079, 26238, {f: 2, c: 26251}, 26291, 26304, 26319, 26405, michael@0: 26421, 26453, 26496, 26511, 26513, 26532, 26545, 26549, 26558, 26664, michael@0: 26758, 26859, 26869, 26903, 26931, 26936, 26971, 26981, 27048, 27051, michael@0: 27055, 27109, 27121, 27210, 27221, 27239, 27249, 27311, {f: 2, c: 27336}, michael@0: 27395, 27451, 27455, {f: 2, c: 27517}, 27568, 27639, 27641, 27652, 27657, michael@0: 27661, 27692, 27722, 27730, 27732, 27769, 27820, 27828, 27858, 28001, michael@0: 28028, 28089, 28144, 28229, 28275, 28283, 28285, 28297, 28348, michael@0: {f: 2, c: 28378}, 28454, 28457, 28464, 28551, 28573, 28590, 28599, 28685, michael@0: 28704, 28745, 28824, 28848, {f: 2, c: 28885}, 28997, 29106, 29172, 29207, michael@0: 29215, 29251, {f: 2, c: 29263}, 29274, 29280, 29288, 29303, 29316, 29385, michael@0: 29413, 29428, 29442, 29451, 29470, 29474, {f: 2, c: 29498}, 29517, 29528, michael@0: 29543, 29810, 29871, 29919, 29924, 29940, 29947, 29974, 29985, 30015, michael@0: 30046, 30105, 30116, 30145, 30148, 30156, 30167, 30172, 30177, 30191, michael@0: 30212, 30220, 30237, 30258, 30264, 30277, 30282, 30303, 30381, 30397, michael@0: 30425, 30443, 30448, 30457, 30464, 30478, 30498, 30504, 30511, 30521, michael@0: 30526, 30533, 30538, 30543, 30558, 30564, 30567, 30572, 30596, michael@0: {f: 2, c: 30604}, 30614, 30631, 30639, 30647, 30654, 30665, 30673, 30681, michael@0: 30705, 30775, 30812, 30846, 30872, 30881, 30897, 30899, 30921, 30931, michael@0: 30988, 31007, {f: 2, c: 31015}, 31039, 31042, 31060, 31083, 31100, 31147, michael@0: 31172, 31210, 31234, 31244, 31280, 31290, 31300, 31360, 31366, 31380, michael@0: 31413, 31421, 31486, 31531, 31607, 31648, 31660, 31664, 31720, 31730, michael@0: 31736, 31740, 31742, 31753, 31784, 31791, 31810, {f: 2, c: 31826}, michael@0: {f: 3, c: 31835}, 31858, 31869, 31879, 31902, 31930, 31943, 31955, 31962, michael@0: 32060, 32077, 32130, 32133, 32141, 32145, 32158, 32179, 32185, 32208, michael@0: 32229, {f: 2, c: 32245}, 32303, 32310, 32324, 32367, 32376, 32385, 32573, michael@0: 32603, 32605, 32613, 32625, {f: 2, c: 32639}, 32651, 32674, michael@0: {f: 3, c: 32765}, 32775, 32781, 32798, 32825, 32904, 32910, 32975, 32980, michael@0: 33005, 33008, 33015, 33018, 33022, 33027, 33047, 33072, 33111, 33135, michael@0: 33139, 33163, 33168, 33179, 33182, 33227, 33237, {f: 2, c: 33245}, 33249, michael@0: 33263, 33270, 33280, 33291, {f: 2, c: 33299}, 33306, 33338, 33348, 33389, michael@0: 33412, 33417, 33425, 33450, 33456, 33488, 33514, 33519, 33526, 33622, michael@0: 33656, 33784, 33788, 33880, 33939, 33969, 33981, 34043, 34118, 34134, michael@0: 34141, 34181, 34200, 34370, 34374, 34496, 34580, 34594, 34606, 34617, michael@0: 34653, 34683, 34700, 34702, {f: 2, c: 34711}, 34718, 34723, 34734, 34751, michael@0: 34761, 34778, 34840, 34843, 34861, 34874, 34885, 34891, 34894, 34901, michael@0: 34906, 34926, {f: 3, c: 34970}, 35021, 35040, 35055, {f: 2, c: 35086}, michael@0: 35110, 35125, 35162, 35164, 35179, 35184, 35196, 35237, 35253, 35260, michael@0: 35285, 35401, 35415, 35431, 35454, 35462, 35478, 35510, 35529, 35537, michael@0: 35549, 35564, 35573, 35590, 35599, 35601, 35653, 35666, 35693, 35704, michael@0: 35708, 35710, 35717, 35743, 35915, 35923, 35963, 36026, 36037, 36041, michael@0: 36050, 36076, 36085, 36087, 36097, 36099, 36119, 36124, 36206, 36241, michael@0: 36255, 36267, 36274, 36309, 36327, {f: 2, c: 36337}, 36340, 36353, 36363, michael@0: 36390, 36401, {f: 2, c: 36416}, 36429, 36431, 36444, 36449, 36457, 36465, michael@0: 36469, 36471, 36489, 36496, 36501, 36506, 36519, 36521, 36525, 36584, michael@0: 36592, 36615, 36632, 36645, 36647, 36652, 36661, 36666, 36675, 36679, michael@0: 36689, 36693, {f: 3, c: 36768}, 36773, 36868, 36891, 36911, 36940, 36955, michael@0: 36976, 36980, 36985, 37003, 37016, 37024, 37042, 37053, 37065, 37104, michael@0: 37125, 37157, 37210, 37223, 37242, 37258, 37265, 37269, 37296, 37307, michael@0: 37309, 37314, 37317, 37376, 37385, 37411, 37494, 37518, 37551, michael@0: {f: 2, c: 37563}, 37569, 37571, 37573, 37576, 37652, 37683, 37686, 37720, michael@0: 37759, 37762, 37770, 37819, 37836, 37862, 37881, 37890, {f: 2, c: 37901}, michael@0: 37934, 37964, 38280, 38305, 38335, 38342, 38345, {f: 2, c: 38353}, 38368, michael@0: 38372, 38374, 38436, 38449, 38456, 38461, 38484, 38516, 38523, 38527, michael@0: 38529, 38531, 38537, 38550, 38574, 38659, 38683, {f: 2, c: 38689}, 38696, michael@0: 38705, 38759, 38774, 38781, 38783, 38809, 38815, 38828, 38841, 38861, michael@0: 38880, 38895, 38919, 38950, 38958, {f: 2, c: 39010}, 39092, 39109, 39170, michael@0: 39185, 39189, 39221, 39240, 39252, 39262, 39393, 39436, 39440, 39459, michael@0: 39489, 39505, {f: 2, c: 39613}, 39681, 39689, 39691, {f: 2, c: 39693}, michael@0: 39705, 39733, 39752, 39765, 39784, 39808, 39814, 39824, 39837, 39856, michael@0: 39871, 39880, 39935, 39938, 39964, 39989, 40004, 40022, 40033, 40040, michael@0: 40240, 40253, 40298, 40315, 40421, 40425, 40435, 40570, {f: 3, c: 40578}, michael@0: 40624, 40676, 40688, 40690, 40713, 40719, 40724, 40731, 40738, 40742, michael@0: {f: 2, c: 40746}, 40756, 40794, 40815, 40862, 40869, 131317, 151044, michael@0: 151538, 163187, 194581, 194630, 194713, 194726, 194789, 195038, 13790, michael@0: {s: 4}, 172722, 0, 0, 131416, {s: 4}, 132529, 0, 0, 132844, {s: 6}, 134488, michael@0: {s: 21}, 154060, {s: 9}, 14756, 14776, 142914, 0, 0, 14940, 0, 0, 143339, michael@0: 0, 0, 162228, 0, 15044, 15051, {s: 5}, 14981, {s: 8}, 15347, 27384, {s: 5}, michael@0: 15665, {s: 9}, 147531, 0, 15936, 14497, {s: 34}, 158878, {s: 12}, 18207, michael@0: 162876, {s: 4}, 18462, {s: 71}, 39709, 39724, 20482, 20958, 21255, 23532, michael@0: 63784, 26142, 63785, 28746, 64021, 21857, 27706, 31328, 156492, 34819, michael@0: 38315, 38741, 171581, 173594], michael@0: 'Adobe-Korea1': [{f: 95, c: 32}, 8361, 8208, 169, 0, 0, [12288, 12644], michael@0: {f: 2, c: 12289}, 12539, 8229, [8230, 8943], 168, 12291, {f: 2, c: 8211}, michael@0: 8214, 65340, 65374, {f: 2, c: 8216}, {f: 2, c: 8220}, {f: 2, c: 12308}, michael@0: {f: 10, c: 12296}, 177, 215, 247, 8800, {f: 2, c: 8804}, 8734, 8756, 176, michael@0: {f: 2, c: 8242}, 8451, 8491, {f: 2, c: 65504}, 65509, 9794, 9792, 8736, michael@0: 8869, 8978, 8706, 8711, 8801, 8786, 167, 8251, 9734, 9733, 9675, 9679, michael@0: 9678, 9671, 9670, 9633, 9632, 9651, 9650, 9661, 9660, 8594, michael@0: {f: 2, c: 8592}, {f: 2, c: 8595}, 12307, 171, 187, 8730, 8765, 8733, 8757, michael@0: {f: 2, c: 8747}, 8712, 8715, {f: 2, c: 8838}, {f: 2, c: 8834}, 8746, 8745, michael@0: {f: 2, c: 8743}, 65506, 8658, 8660, 8704, 8707, 180, 732, 711, 728, 733, michael@0: 730, 729, 184, 731, 161, 191, 8758, 8750, 8721, 8719, 164, 8457, 8240, michael@0: 9665, 9664, 9655, 9654, 9828, {f: 2, c: 9824}, 9829, 9831, 9827, 9673, michael@0: 9672, 9635, {f: 2, c: 9680}, 9618, {f: 2, c: 9636}, 9640, 9639, 9638, 9641, michael@0: 9832, 9743, 9742, 9756, 9758, 182, {f: 2, c: 8224}, 8597, 8599, 8601, 8598, michael@0: 8600, 9837, {f: 2, c: 9833}, 9836, 12927, 12828, 8470, 13255, 8482, 13250, michael@0: 13272, 8481, {f: 59, c: 65281}, 65510, {f: 33, c: 65341}, 65507, michael@0: {f: 51, c: 12593}, {f: 42, c: 12645}, {f: 10, c: 8560}, {f: 10, c: 8544}, michael@0: {f: 17, c: 913}, {f: 7, c: 931}, {f: 17, c: 945}, {f: 7, c: 963}, 9472, michael@0: 9474, 9484, 9488, 9496, 9492, 9500, 9516, 9508, 9524, 9532, 9473, 9475, michael@0: 9487, 9491, 9499, 9495, 9507, 9523, 9515, 9531, 9547, 9504, 9519, 9512, michael@0: 9527, 9535, 9501, 9520, 9509, 9528, 9538, 9490, 9489, 9498, 9497, 9494, michael@0: 9493, 9486, 9485, {f: 2, c: 9502}, {f: 2, c: 9505}, {f: 2, c: 9510}, michael@0: {f: 2, c: 9513}, {f: 2, c: 9517}, {f: 2, c: 9521}, {f: 2, c: 9525}, michael@0: {f: 2, c: 9529}, {f: 2, c: 9533}, {f: 2, c: 9536}, {f: 8, c: 9539}, michael@0: {f: 3, c: 13205}, 8467, 13208, 13252, {f: 4, c: 13219}, {f: 10, c: 13209}, michael@0: 13258, {f: 3, c: 13197}, 13263, {f: 2, c: 13192}, 13256, {f: 2, c: 13223}, michael@0: {f: 10, c: 13232}, {f: 5, c: 13184}, {f: 6, c: 13242}, {f: 5, c: 13200}, michael@0: 8486, {f: 2, c: 13248}, {f: 3, c: 13194}, 13270, 13253, {f: 3, c: 13229}, michael@0: 13275, {f: 4, c: 13225}, 13277, 13264, 13267, 13251, 13257, 13276, 13254, michael@0: 198, 208, 170, 294, 306, 319, 321, 216, 338, 186, 222, 358, 330, michael@0: {f: 28, c: 12896}, {f: 26, c: 9424}, {f: 15, c: 9312}, 189, michael@0: {f: 2, c: 8531}, 188, 190, {f: 4, c: 8539}, 230, 273, 240, 295, 305, 307, michael@0: 312, 320, 322, 248, 339, 223, 254, 359, 331, 329, {f: 28, c: 12800}, michael@0: {f: 26, c: 9372}, {f: 15, c: 9332}, 185, {f: 2, c: 178}, 8308, 8319, michael@0: {f: 4, c: 8321}, {f: 83, c: 12353}, {f: 86, c: 12449}, {f: 6, c: 1040}, michael@0: 1025, {f: 32, c: 1046}, 1105, {f: 26, c: 1078}, {f: 2, c: 44032}, 44036, michael@0: {f: 4, c: 44039}, {f: 8, c: 44048}, {f: 5, c: 44057}, 44064, 44068, michael@0: {f: 2, c: 44076}, {f: 3, c: 44079}, {f: 2, c: 44088}, 44092, 44096, 44107, michael@0: 44109, 44116, 44120, 44124, {f: 2, c: 44144}, 44148, {f: 2, c: 44151}, michael@0: 44154, {f: 2, c: 44160}, {f: 4, c: 44163}, {f: 4, c: 44169}, 44176, 44180, michael@0: {f: 2, c: 44188}, {f: 3, c: 44191}, {f: 3, c: 44200}, 44204, michael@0: {f: 2, c: 44207}, {f: 2, c: 44216}, {f: 3, c: 44219}, 44225, 44228, 44232, michael@0: 44236, 44245, 44247, {f: 2, c: 44256}, 44260, {f: 2, c: 44263}, 44266, michael@0: 44268, {f: 3, c: 44271}, 44275, {f: 2, c: 44277}, {f: 2, c: 44284}, 44288, michael@0: 44292, 44294, {f: 2, c: 44300}, 44303, 44305, 44312, 44316, 44320, 44329, michael@0: {f: 2, c: 44332}, {f: 2, c: 44340}, 44344, 44348, {f: 2, c: 44356}, 44359, michael@0: 44361, 44368, 44372, 44376, 44385, 44387, {f: 2, c: 44396}, 44400, michael@0: {f: 4, c: 44403}, {f: 3, c: 44411}, 44415, {f: 2, c: 44417}, michael@0: {f: 2, c: 44424}, 44428, 44432, {f: 2, c: 44444}, 44452, 44471, michael@0: {f: 2, c: 44480}, 44484, 44488, {f: 2, c: 44496}, 44499, 44508, 44512, michael@0: 44516, {f: 2, c: 44536}, 44540, {f: 3, c: 44543}, {f: 2, c: 44552}, 44555, michael@0: 44557, 44564, {f: 2, c: 44592}, 44596, {f: 2, c: 44599}, 44602, michael@0: {f: 2, c: 44608}, 44611, {f: 2, c: 44613}, 44618, {f: 3, c: 44620}, 44624, michael@0: 44628, 44630, {f: 2, c: 44636}, {f: 3, c: 44639}, 44645, {f: 2, c: 44648}, michael@0: 44652, 44656, {f: 2, c: 44664}, {f: 3, c: 44667}, {f: 2, c: 44676}, 44684, michael@0: {f: 3, c: 44732}, 44736, 44740, {f: 2, c: 44748}, {f: 3, c: 44751}, michael@0: {f: 2, c: 44760}, 44764, 44776, 44779, 44781, 44788, 44792, 44796, michael@0: {f: 2, c: 44807}, 44813, 44816, {f: 2, c: 44844}, 44848, 44850, 44852, michael@0: {f: 2, c: 44860}, 44863, {f: 3, c: 44865}, {f: 2, c: 44872}, 44880, michael@0: {f: 2, c: 44892}, {f: 2, c: 44900}, 44921, 44928, 44932, 44936, michael@0: {f: 2, c: 44944}, 44949, 44956, {f: 2, c: 44984}, 44988, 44992, michael@0: {f: 3, c: 44999}, 45003, {f: 2, c: 45005}, 45012, 45020, {f: 2, c: 45032}, michael@0: {f: 2, c: 45040}, 45044, 45048, {f: 2, c: 45056}, 45060, 45068, 45072, michael@0: 45076, {f: 2, c: 45084}, 45096, {f: 2, c: 45124}, 45128, 45130, 45132, michael@0: 45134, {f: 3, c: 45139}, 45143, 45145, 45149, {f: 2, c: 45180}, 45184, michael@0: 45188, {f: 2, c: 45196}, 45199, 45201, {f: 3, c: 45208}, 45212, michael@0: {f: 4, c: 45215}, {f: 2, c: 45224}, {f: 5, c: 45227}, 45233, michael@0: {f: 3, c: 45235}, 45240, 45244, {f: 2, c: 45252}, {f: 3, c: 45255}, michael@0: {f: 2, c: 45264}, 45268, 45272, 45280, 45285, {f: 2, c: 45320}, michael@0: {f: 2, c: 45323}, 45328, {f: 2, c: 45330}, {f: 2, c: 45336}, michael@0: {f: 3, c: 45339}, {f: 3, c: 45347}, 45352, 45356, {f: 2, c: 45364}, michael@0: {f: 3, c: 45367}, {f: 2, c: 45376}, 45380, 45384, {f: 2, c: 45392}, michael@0: {f: 2, c: 45396}, 45400, 45404, 45408, {f: 2, c: 45432}, 45436, 45440, michael@0: 45442, {f: 2, c: 45448}, 45451, 45453, {f: 3, c: 45458}, 45464, 45468, michael@0: 45480, 45516, 45520, 45524, {f: 2, c: 45532}, 45535, {f: 2, c: 45544}, michael@0: 45548, 45552, 45561, 45563, 45565, {f: 2, c: 45572}, 45576, michael@0: {f: 2, c: 45579}, {f: 2, c: 45588}, 45591, 45593, 45600, 45620, 45628, michael@0: 45656, 45660, 45664, {f: 2, c: 45672}, {f: 2, c: 45684}, 45692, michael@0: {f: 2, c: 45700}, 45705, {f: 2, c: 45712}, 45716, {f: 3, c: 45720}, michael@0: {f: 2, c: 45728}, 45731, {f: 2, c: 45733}, 45738, 45740, 45744, 45748, michael@0: {f: 2, c: 45768}, 45772, 45776, 45778, {f: 2, c: 45784}, 45787, 45789, michael@0: 45794, {f: 3, c: 45796}, 45800, {f: 5, c: 45803}, {f: 3, c: 45811}, michael@0: {f: 5, c: 45815}, {f: 3, c: 45823}, 45828, 45832, {f: 2, c: 45840}, michael@0: {f: 3, c: 45843}, 45852, {f: 3, c: 45908}, 45912, {f: 2, c: 45915}, michael@0: {f: 2, c: 45918}, {f: 2, c: 45924}, 45927, 45929, 45931, 45934, michael@0: {f: 2, c: 45936}, 45940, 45944, {f: 2, c: 45952}, {f: 3, c: 45955}, 45964, michael@0: 45968, 45972, {f: 2, c: 45984}, 45992, 45996, {f: 2, c: 46020}, 46024, michael@0: {f: 2, c: 46027}, 46030, 46032, {f: 2, c: 46036}, 46039, 46041, 46043, michael@0: 46045, 46048, 46052, 46056, 46076, 46096, 46104, 46108, 46112, michael@0: {f: 2, c: 46120}, 46123, 46132, {f: 2, c: 46160}, 46164, 46168, michael@0: {f: 2, c: 46176}, 46179, 46181, 46188, 46208, 46216, 46237, 46244, 46248, michael@0: 46252, 46261, 46263, 46265, 46272, 46276, 46280, 46288, 46293, michael@0: {f: 2, c: 46300}, 46304, {f: 2, c: 46307}, 46310, {f: 2, c: 46316}, 46319, michael@0: 46321, 46328, {f: 2, c: 46356}, 46360, {f: 2, c: 46363}, {f: 2, c: 46372}, michael@0: {f: 4, c: 46375}, {f: 2, c: 46384}, 46388, 46392, {f: 2, c: 46400}, michael@0: {f: 3, c: 46403}, {f: 3, c: 46411}, 46416, 46420, {f: 2, c: 46428}, michael@0: {f: 3, c: 46431}, {f: 2, c: 46496}, 46500, 46504, {f: 2, c: 46506}, michael@0: {f: 2, c: 46512}, {f: 3, c: 46515}, {f: 3, c: 46523}, 46528, 46532, michael@0: {f: 2, c: 46540}, {f: 3, c: 46543}, 46552, 46572, {f: 2, c: 46608}, 46612, michael@0: 46616, 46629, 46636, 46644, 46664, 46692, 46696, {f: 2, c: 46748}, 46752, michael@0: 46756, {f: 2, c: 46763}, 46769, 46804, 46832, 46836, 46840, michael@0: {f: 2, c: 46848}, 46853, {f: 2, c: 46888}, 46892, {f: 2, c: 46895}, michael@0: {f: 2, c: 46904}, 46907, 46916, 46920, 46924, {f: 2, c: 46932}, 46944, michael@0: 46948, 46952, {f: 2, c: 46960}, 46963, 46965, {f: 2, c: 46972}, 46976, michael@0: 46980, {f: 2, c: 46988}, {f: 4, c: 46991}, {f: 4, c: 46998}, 47004, 47008, michael@0: {f: 2, c: 47016}, {f: 3, c: 47019}, {f: 2, c: 47028}, 47032, 47047, 47049, michael@0: {f: 2, c: 47084}, 47088, 47092, {f: 2, c: 47100}, {f: 3, c: 47103}, michael@0: {f: 3, c: 47111}, 47116, 47120, {f: 2, c: 47128}, 47131, 47133, michael@0: {f: 2, c: 47140}, 47144, 47148, {f: 2, c: 47156}, {f: 3, c: 47159}, 47168, michael@0: 47172, 47185, 47187, {f: 2, c: 47196}, 47200, 47204, {f: 2, c: 47212}, michael@0: 47215, 47217, 47224, 47228, 47245, 47272, 47280, 47284, 47288, michael@0: {f: 2, c: 47296}, 47299, 47301, 47308, 47312, 47316, 47325, 47327, 47329, michael@0: {f: 2, c: 47336}, 47340, 47344, {f: 2, c: 47352}, 47355, 47357, 47364, michael@0: 47384, 47392, {f: 2, c: 47420}, 47424, 47428, 47436, 47439, 47441, michael@0: {f: 2, c: 47448}, 47452, 47456, {f: 2, c: 47464}, 47467, 47469, michael@0: {f: 2, c: 47476}, 47480, 47484, {f: 2, c: 47492}, 47495, {f: 2, c: 47497}, michael@0: {f: 2, c: 47501}, {f: 2, c: 47532}, 47536, 47540, {f: 2, c: 47548}, 47551, michael@0: 47553, {f: 2, c: 47560}, 47564, {f: 5, c: 47566}, {f: 2, c: 47576}, 47579, michael@0: {f: 2, c: 47581}, 47585, {f: 3, c: 47587}, 47592, 47596, {f: 2, c: 47604}, michael@0: {f: 4, c: 47607}, {f: 2, c: 47616}, 47624, 47637, {f: 2, c: 47672}, 47676, michael@0: 47680, 47682, {f: 2, c: 47688}, 47691, {f: 2, c: 47693}, {f: 3, c: 47699}, michael@0: 47704, 47708, {f: 2, c: 47716}, {f: 3, c: 47719}, {f: 2, c: 47728}, 47732, michael@0: 47736, {f: 3, c: 47747}, 47751, 47756, {f: 2, c: 47784}, {f: 2, c: 47787}, michael@0: 47792, 47794, {f: 2, c: 47800}, 47803, 47805, 47812, 47816, michael@0: {f: 2, c: 47832}, 47868, 47872, 47876, 47885, 47887, 47889, 47896, 47900, michael@0: 47904, 47913, 47915, {f: 3, c: 47924}, 47928, {f: 4, c: 47931}, michael@0: {f: 2, c: 47940}, 47943, 47945, 47949, {f: 2, c: 47951}, 47956, 47960, michael@0: 47969, 47971, 47980, 48008, 48012, 48016, 48036, 48040, 48044, 48052, michael@0: 48055, 48064, 48068, 48072, 48080, 48083, {f: 2, c: 48120}, 48124, michael@0: {f: 2, c: 48127}, 48130, {f: 2, c: 48136}, {f: 3, c: 48139}, 48143, 48145, michael@0: {f: 5, c: 48148}, {f: 5, c: 48155}, {f: 2, c: 48164}, 48167, 48169, 48173, michael@0: {f: 2, c: 48176}, 48180, 48184, {f: 2, c: 48192}, {f: 3, c: 48195}, 48201, michael@0: {f: 2, c: 48204}, 48208, 48221, {f: 2, c: 48260}, 48264, {f: 2, c: 48267}, michael@0: 48270, {f: 2, c: 48276}, 48279, {f: 2, c: 48281}, {f: 2, c: 48288}, 48292, michael@0: {f: 2, c: 48295}, {f: 2, c: 48304}, {f: 3, c: 48307}, {f: 2, c: 48316}, michael@0: 48320, 48324, 48333, {f: 3, c: 48335}, 48341, 48344, 48348, michael@0: {f: 3, c: 48372}, 48376, 48380, {f: 2, c: 48388}, 48391, 48393, 48400, michael@0: 48404, 48420, 48428, 48448, {f: 2, c: 48456}, 48460, 48464, michael@0: {f: 2, c: 48472}, 48484, 48488, {f: 2, c: 48512}, 48516, {f: 4, c: 48519}, michael@0: {f: 2, c: 48528}, 48531, 48533, {f: 2, c: 48537}, 48540, 48548, 48560, michael@0: 48568, {f: 2, c: 48596}, 48600, 48604, 48617, 48624, 48628, 48632, 48640, michael@0: 48643, 48645, {f: 2, c: 48652}, 48656, 48660, {f: 2, c: 48668}, 48671, michael@0: {f: 2, c: 48708}, 48712, 48716, 48718, {f: 2, c: 48724}, 48727, michael@0: {f: 3, c: 48729}, {f: 2, c: 48736}, 48740, 48744, 48746, {f: 2, c: 48752}, michael@0: {f: 3, c: 48755}, {f: 3, c: 48763}, 48768, 48772, {f: 2, c: 48780}, michael@0: {f: 3, c: 48783}, {f: 2, c: 48792}, 48808, {f: 2, c: 48848}, 48852, michael@0: {f: 2, c: 48855}, 48864, {f: 3, c: 48867}, 48876, 48897, {f: 2, c: 48904}, michael@0: {f: 2, c: 48920}, {f: 3, c: 48923}, {f: 2, c: 48960}, 48964, 48968, michael@0: {f: 2, c: 48976}, 48981, 49044, 49072, 49093, {f: 2, c: 49100}, 49104, michael@0: 49108, 49116, 49119, 49121, 49212, 49233, 49240, 49244, 49248, michael@0: {f: 2, c: 49256}, {f: 2, c: 49296}, 49300, 49304, {f: 2, c: 49312}, 49315, michael@0: 49317, {f: 2, c: 49324}, {f: 2, c: 49327}, {f: 4, c: 49331}, michael@0: {f: 2, c: 49340}, {f: 3, c: 49343}, 49349, {f: 2, c: 49352}, 49356, 49360, michael@0: {f: 2, c: 49368}, {f: 3, c: 49371}, {f: 2, c: 49380}, 49384, 49388, michael@0: {f: 2, c: 49396}, 49399, 49401, 49408, 49412, 49416, 49424, 49429, michael@0: {f: 5, c: 49436}, {f: 2, c: 49443}, {f: 2, c: 49446}, {f: 2, c: 49452}, michael@0: {f: 3, c: 49455}, 49462, {f: 2, c: 49464}, 49468, 49472, {f: 2, c: 49480}, michael@0: {f: 3, c: 49483}, {f: 2, c: 49492}, 49496, 49500, {f: 2, c: 49508}, michael@0: {f: 3, c: 49511}, 49520, 49524, 49528, 49541, {f: 3, c: 49548}, 49552, michael@0: 49556, 49558, {f: 2, c: 49564}, 49567, 49569, 49573, {f: 2, c: 49576}, michael@0: 49580, 49584, 49597, 49604, 49608, 49612, 49620, {f: 2, c: 49623}, 49632, michael@0: 49636, 49640, {f: 2, c: 49648}, 49651, {f: 2, c: 49660}, 49664, 49668, michael@0: {f: 2, c: 49676}, 49679, 49681, {f: 2, c: 49688}, 49692, {f: 2, c: 49695}, michael@0: {f: 2, c: 49704}, 49707, 49709, 49711, {f: 2, c: 49713}, 49716, 49736, michael@0: {f: 2, c: 49744}, 49748, 49752, 49760, 49765, {f: 2, c: 49772}, 49776, michael@0: 49780, {f: 2, c: 49788}, 49791, 49793, {f: 2, c: 49800}, 49808, 49816, michael@0: 49819, 49821, {f: 2, c: 49828}, 49832, {f: 2, c: 49836}, {f: 2, c: 49844}, michael@0: 49847, 49849, {f: 2, c: 49884}, 49888, {f: 2, c: 49891}, {f: 3, c: 49899}, michael@0: 49903, 49905, 49910, {f: 2, c: 49912}, {f: 2, c: 49915}, 49920, michael@0: {f: 2, c: 49928}, {f: 2, c: 49932}, {f: 3, c: 49939}, 49944, 49948, michael@0: {f: 2, c: 49956}, {f: 2, c: 49960}, 49989, {f: 2, c: 50024}, 50028, 50032, michael@0: 50034, {f: 2, c: 50040}, {f: 2, c: 50044}, 50052, 50056, 50060, 50112, michael@0: {f: 2, c: 50136}, 50140, {f: 2, c: 50143}, 50146, {f: 2, c: 50152}, 50157, michael@0: {f: 2, c: 50164}, 50168, 50184, 50192, 50212, 50220, 50224, 50228, michael@0: {f: 2, c: 50236}, 50248, {f: 2, c: 50276}, 50280, 50284, {f: 2, c: 50292}, michael@0: 50297, 50304, 50324, 50332, 50360, 50364, 50409, {f: 2, c: 50416}, 50420, michael@0: 50424, 50426, {f: 3, c: 50431}, 50444, 50448, 50452, 50460, michael@0: {f: 2, c: 50472}, 50476, 50480, {f: 2, c: 50488}, 50491, 50493, michael@0: {f: 2, c: 50500}, {f: 3, c: 50504}, {f: 3, c: 50508}, {f: 3, c: 50515}, michael@0: {f: 3, c: 50519}, {f: 2, c: 50525}, {f: 2, c: 50528}, 50532, 50536, michael@0: {f: 2, c: 50544}, {f: 3, c: 50547}, {f: 2, c: 50556}, 50560, 50564, 50567, michael@0: {f: 2, c: 50572}, 50575, 50577, 50581, {f: 2, c: 50583}, 50588, 50592, michael@0: 50601, {f: 2, c: 50612}, {f: 2, c: 50616}, {f: 4, c: 50619}, michael@0: {f: 7, c: 50628}, 50636, 50638, {f: 2, c: 50640}, 50644, 50648, michael@0: {f: 2, c: 50656}, 50659, 50661, {f: 3, c: 50668}, 50672, 50676, michael@0: {f: 2, c: 50678}, {f: 6, c: 50684}, {f: 4, c: 50693}, 50700, 50704, michael@0: {f: 2, c: 50712}, {f: 2, c: 50715}, {f: 2, c: 50724}, 50728, michael@0: {f: 3, c: 50732}, 50736, {f: 3, c: 50739}, 50743, 50745, 50747, michael@0: {f: 2, c: 50752}, 50756, 50760, {f: 2, c: 50768}, {f: 3, c: 50771}, michael@0: {f: 2, c: 50780}, 50784, 50796, 50799, 50801, {f: 2, c: 50808}, 50812, michael@0: 50816, {f: 2, c: 50824}, 50827, 50829, {f: 2, c: 50836}, 50840, 50844, michael@0: {f: 2, c: 50852}, 50855, 50857, {f: 2, c: 50864}, 50868, {f: 3, c: 50872}, michael@0: {f: 2, c: 50880}, 50883, 50885, {f: 2, c: 50892}, 50896, 50900, michael@0: {f: 2, c: 50908}, {f: 2, c: 50912}, {f: 2, c: 50920}, 50924, 50928, michael@0: {f: 2, c: 50936}, 50941, {f: 2, c: 50948}, 50952, 50956, {f: 2, c: 50964}, michael@0: 50967, 50969, {f: 2, c: 50976}, 50980, 50984, {f: 2, c: 50992}, 50995, michael@0: 50997, 50999, {f: 2, c: 51004}, 51008, 51012, 51018, {f: 2, c: 51020}, michael@0: 51023, {f: 8, c: 51025}, 51036, 51040, 51048, 51051, {f: 2, c: 51060}, michael@0: 51064, {f: 3, c: 51068}, {f: 3, c: 51075}, {f: 4, c: 51079}, 51086, michael@0: {f: 2, c: 51088}, 51092, {f: 3, c: 51094}, 51098, {f: 2, c: 51104}, michael@0: {f: 4, c: 51107}, {f: 2, c: 51116}, 51120, 51124, {f: 2, c: 51132}, michael@0: {f: 3, c: 51135}, {f: 2, c: 51144}, 51148, 51150, 51152, 51160, 51165, michael@0: 51172, 51176, 51180, {f: 2, c: 51200}, 51204, 51208, 51210, michael@0: {f: 2, c: 51216}, 51219, {f: 2, c: 51221}, {f: 2, c: 51228}, 51232, 51236, michael@0: {f: 2, c: 51244}, 51247, 51249, 51256, 51260, 51264, {f: 2, c: 51272}, michael@0: {f: 2, c: 51276}, 51284, {f: 2, c: 51312}, 51316, 51320, 51322, michael@0: {f: 2, c: 51328}, 51331, {f: 3, c: 51333}, {f: 3, c: 51339}, 51348, 51357, michael@0: 51359, 51361, 51368, {f: 2, c: 51388}, 51396, 51400, 51404, michael@0: {f: 2, c: 51412}, 51415, 51417, {f: 2, c: 51424}, 51428, 51445, michael@0: {f: 2, c: 51452}, 51456, {f: 3, c: 51460}, {f: 2, c: 51468}, 51471, 51473, michael@0: 51480, 51500, 51508, {f: 2, c: 51536}, 51540, 51544, {f: 2, c: 51552}, michael@0: 51555, 51564, 51568, 51572, 51580, {f: 2, c: 51592}, 51596, 51600, michael@0: {f: 2, c: 51608}, 51611, 51613, {f: 2, c: 51648}, 51652, {f: 2, c: 51655}, michael@0: 51658, {f: 2, c: 51664}, 51667, {f: 2, c: 51669}, {f: 2, c: 51673}, michael@0: {f: 2, c: 51676}, 51680, 51682, 51684, 51687, {f: 2, c: 51692}, michael@0: {f: 3, c: 51695}, {f: 2, c: 51704}, 51708, 51712, {f: 2, c: 51720}, michael@0: {f: 3, c: 51723}, 51732, 51736, 51753, {f: 2, c: 51788}, 51792, 51796, michael@0: {f: 2, c: 51804}, {f: 3, c: 51807}, 51816, 51837, 51844, 51864, michael@0: {f: 2, c: 51900}, 51904, 51908, {f: 2, c: 51916}, 51919, 51921, 51923, michael@0: {f: 2, c: 51928}, 51936, 51948, 51956, 51976, 51984, 51988, 51992, michael@0: {f: 2, c: 52000}, 52033, {f: 2, c: 52040}, 52044, 52048, {f: 2, c: 52056}, michael@0: 52061, 52068, {f: 2, c: 52088}, 52124, 52152, 52180, 52196, 52199, 52201, michael@0: {f: 2, c: 52236}, 52240, 52244, {f: 2, c: 52252}, {f: 2, c: 52257}, michael@0: {f: 3, c: 52263}, 52268, 52270, 52272, {f: 2, c: 52280}, {f: 4, c: 52283}, michael@0: {f: 2, c: 52292}, 52296, 52300, {f: 2, c: 52308}, {f: 3, c: 52311}, 52320, michael@0: 52324, 52326, 52328, 52336, 52341, {f: 2, c: 52376}, 52380, 52384, michael@0: {f: 2, c: 52392}, {f: 3, c: 52395}, {f: 2, c: 52404}, 52408, 52412, michael@0: {f: 2, c: 52420}, 52423, 52425, 52432, 52436, 52452, 52460, 52464, 52481, michael@0: {f: 2, c: 52488}, 52492, 52496, {f: 2, c: 52504}, 52507, 52509, 52516, michael@0: 52520, 52524, 52537, 52572, 52576, 52580, {f: 2, c: 52588}, 52591, 52593, michael@0: 52600, 52616, {f: 2, c: 52628}, 52632, 52636, {f: 2, c: 52644}, 52647, michael@0: 52649, 52656, 52676, 52684, 52688, 52712, 52716, 52720, {f: 2, c: 52728}, michael@0: 52731, 52733, 52740, 52744, 52748, 52756, 52761, {f: 2, c: 52768}, 52772, michael@0: 52776, {f: 2, c: 52784}, 52787, 52789, {f: 2, c: 52824}, 52828, michael@0: {f: 3, c: 52831}, {f: 2, c: 52840}, 52843, 52845, {f: 2, c: 52852}, 52856, michael@0: 52860, {f: 2, c: 52868}, 52871, 52873, {f: 2, c: 52880}, 52884, 52888, michael@0: {f: 2, c: 52896}, {f: 3, c: 52899}, {f: 2, c: 52908}, 52929, michael@0: {f: 2, c: 52964}, 52968, {f: 2, c: 52971}, {f: 2, c: 52980}, michael@0: {f: 3, c: 52983}, {f: 2, c: 52992}, 52996, 53000, {f: 2, c: 53008}, 53011, michael@0: 53013, 53020, 53024, 53028, {f: 2, c: 53036}, {f: 3, c: 53039}, 53048, michael@0: {f: 2, c: 53076}, 53080, 53084, {f: 2, c: 53092}, 53095, 53097, michael@0: {f: 2, c: 53104}, 53108, 53112, 53120, 53125, 53132, 53153, 53160, 53168, michael@0: 53188, {f: 2, c: 53216}, 53220, 53224, {f: 2, c: 53232}, 53235, 53237, michael@0: 53244, 53248, 53252, 53265, 53272, 53293, {f: 2, c: 53300}, 53304, 53308, michael@0: {f: 2, c: 53316}, 53319, 53321, 53328, 53332, 53336, 53344, michael@0: {f: 2, c: 53356}, 53360, 53364, {f: 2, c: 53372}, 53377, {f: 2, c: 53412}, michael@0: 53416, 53420, {f: 2, c: 53428}, 53431, 53433, {f: 2, c: 53440}, 53444, michael@0: {f: 2, c: 53448}, {f: 2, c: 53456}, {f: 3, c: 53459}, {f: 2, c: 53468}, michael@0: 53472, 53476, {f: 2, c: 53484}, {f: 3, c: 53487}, 53496, 53517, michael@0: {f: 2, c: 53552}, 53556, 53560, 53562, {f: 2, c: 53568}, {f: 3, c: 53571}, michael@0: {f: 2, c: 53580}, 53584, 53588, {f: 2, c: 53596}, 53599, 53601, 53608, michael@0: 53612, 53628, 53636, 53640, {f: 2, c: 53664}, 53668, 53672, michael@0: {f: 2, c: 53680}, 53683, 53685, 53690, 53692, 53696, 53720, 53748, 53752, michael@0: 53767, 53769, 53776, {f: 2, c: 53804}, 53808, 53812, {f: 2, c: 53820}, michael@0: 53823, 53825, 53832, 53852, 53860, {f: 2, c: 53888}, 53892, 53896, michael@0: {f: 2, c: 53904}, 53909, 53916, 53920, 53924, 53932, 53937, michael@0: {f: 2, c: 53944}, 53948, {f: 2, c: 53951}, 53954, {f: 2, c: 53960}, 53963, michael@0: 53972, 53976, 53980, {f: 2, c: 53988}, {f: 2, c: 54000}, 54004, 54008, michael@0: {f: 2, c: 54016}, 54019, 54021, {f: 3, c: 54028}, 54032, 54036, 54038, michael@0: {f: 2, c: 54044}, {f: 3, c: 54047}, 54053, {f: 2, c: 54056}, 54060, 54064, michael@0: {f: 2, c: 54072}, {f: 3, c: 54075}, {f: 2, c: 54084}, {f: 2, c: 54140}, michael@0: 54144, 54148, {f: 2, c: 54156}, {f: 3, c: 54159}, {f: 2, c: 54168}, 54172, michael@0: 54176, {f: 2, c: 54184}, 54187, 54189, 54196, 54200, 54204, michael@0: {f: 2, c: 54212}, {f: 2, c: 54216}, 54224, 54232, 54241, 54243, michael@0: {f: 2, c: 54252}, 54256, 54260, {f: 2, c: 54268}, 54271, 54273, 54280, michael@0: 54301, 54336, 54340, 54364, 54368, 54372, 54381, 54383, {f: 2, c: 54392}, michael@0: 54396, {f: 2, c: 54399}, 54402, {f: 2, c: 54408}, 54411, 54413, 54420, michael@0: 54441, 54476, 54480, 54484, 54492, 54495, 54504, 54508, 54512, 54520, michael@0: 54523, 54525, 54532, 54536, 54540, {f: 2, c: 54548}, 54551, michael@0: {f: 2, c: 54588}, 54592, 54596, {f: 2, c: 54604}, 54607, 54609, michael@0: {f: 2, c: 54616}, 54620, 54624, 54629, {f: 2, c: 54632}, 54635, 54637, michael@0: {f: 2, c: 54644}, 54648, 54652, {f: 2, c: 54660}, {f: 3, c: 54663}, 54672, michael@0: 54693, {f: 2, c: 54728}, 54732, 54736, 54738, {f: 2, c: 54744}, 54747, michael@0: 54749, {f: 2, c: 54756}, 54760, 54764, {f: 2, c: 54772}, 54775, 54777, michael@0: {f: 2, c: 54784}, 54788, 54792, {f: 2, c: 54800}, {f: 3, c: 54803}, 54812, michael@0: 54816, 54820, 54829, {f: 2, c: 54840}, 54844, 54848, 54853, michael@0: {f: 2, c: 54856}, 54859, 54861, 54865, {f: 2, c: 54868}, 54872, 54876, michael@0: 54887, 54889, {f: 2, c: 54896}, 54900, 54915, 54917, {f: 2, c: 54924}, michael@0: 54928, 54932, 54941, 54943, 54945, 54952, 54956, 54960, 54969, 54971, michael@0: {f: 2, c: 54980}, 54984, 54988, 54993, 54996, 54999, 55001, 55008, 55012, michael@0: 55016, 55024, 55029, {f: 2, c: 55036}, 55040, 55044, 55057, michael@0: {f: 2, c: 55064}, 55068, 55072, {f: 2, c: 55080}, 55083, 55085, michael@0: {f: 2, c: 55092}, 55096, 55100, 55108, 55111, 55113, {f: 2, c: 55120}, michael@0: 55124, {f: 4, c: 55126}, {f: 2, c: 55136}, 55139, 55141, 55145, 55148, michael@0: 55152, 55156, {f: 2, c: 55164}, 55169, {f: 2, c: 55176}, 55180, 55184, michael@0: {f: 2, c: 55192}, 55195, 55197, 20285, 20339, 20551, 20729, 21152, 21487, michael@0: 21621, 21733, 22025, 23233, 23478, 26247, {f: 2, c: 26550}, 26607, 27468, michael@0: 29634, 30146, 31292, 33499, 33540, 34903, 34952, 35382, [36040, 63747], michael@0: 36303, 36603, 36838, 39381, 21051, 21364, 21508, 24682, 24932, 27580, michael@0: 29647, 33050, 35258, [12179, 35282], 38307, 20355, 21002, 22718, 22904, michael@0: 23014, [12082, 24178], 24185, 25031, 25536, 26438, 26604, 26751, 28567, michael@0: 30286, 30475, 30965, 31240, 31487, 31777, 32925, [12169, 33390], 33393, michael@0: 35563, 38291, 20075, 21917, 26359, 28212, 30883, 31469, 33883, 35088, michael@0: 34638, 38824, 21208, 22350, 22570, 23884, 24863, 25022, 25121, 25954, michael@0: 26577, 27204, 28187, [12130, 29976], 30131, 30435, 30640, 32058, 37039, michael@0: {f: 2, c: 37969}, 40853, 21283, 23724, 30002, 32987, 37440, 38296, 21083, michael@0: 22536, 23004, 23713, 23831, 24247, 24378, 24394, 24951, 27743, 30074, michael@0: 30086, 31968, 32115, 32177, 32652, 33108, 33313, 34193, 35137, 35611, michael@0: 37628, [38477, 64009], 40007, 20171, 20215, 20491, 20977, 22607, 24887, michael@0: 24894, 24936, 25913, 27114, 28433, 30117, 30342, 30422, 31623, 33445, michael@0: 33995, 37799, 38283, 21888, 23458, 22353, 31923, 32697, 37301, 20520, michael@0: 21435, 23621, 24040, 25298, 25454, 25818, 25831, 28192, 28844, 31067, michael@0: 36317, 36382, 36989, 37445, 37624, 20094, 20214, 20581, [12081, 24062], michael@0: 24314, 24838, 26967, 33137, 34388, 36423, 37749, 39467, 20062, 20625, michael@0: 26480, 26688, 20745, 21133, 21138, 27298, 30652, 37392, 40660, 21163, michael@0: 24623, 36850, 20552, 25001, 25581, 25802, 26684, 27268, 28608, 33160, michael@0: 35233, 38548, 22533, 29309, [12125, 29356], 29956, 32121, 32365, 32937, michael@0: [12178, 35211, 64010], 35700, 36963, 40273, 25225, 27770, 28500, 32080, michael@0: 32570, 35363, 20860, 24906, 31645, 35609, 37463, 37772, 20140, 20435, michael@0: 20510, 20670, 20742, 21185, 21197, 21375, 22384, 22659, 24218, 24465, michael@0: 24950, 25004, 25806, 25964, 26223, 26299, [26356, 63745], 26775, 28039, michael@0: 28805, 28913, 29855, 29861, 29898, 30169, 30828, 30956, 31455, 31478, michael@0: 32069, 32147, 32789, 32831, 33051, 33686, 35686, 36629, 36885, 37857, michael@0: 38915, 38968, 39514, 39912, 20418, 21843, 22586, [22865, 63753], 23395, michael@0: 23622, 24760, 25106, 26690, 26800, 26856, 28330, 30028, 30328, 30926, michael@0: 31293, 31995, 32363, 32380, 35336, 35489, 35903, 38542, 40388, 21476, michael@0: 21481, 21578, 21617, 22266, 22993, 23396, 23611, 24235, 25335, 25911, michael@0: 25925, 25970, 26272, 26543, 27073, 27837, 30204, 30352, 30590, 31295, michael@0: 32660, 32771, 32929, 33167, 33510, 33533, 33776, 34241, 34865, 34996, michael@0: 35493, 36764, 37678, 38599, 39015, [12220, 39640], [12238, 40723], 21741, michael@0: 26011, 26354, 26767, 31296, [12181, 35895], 40288, 22256, 22372, 23825, michael@0: 26118, 26801, 26829, 28414, 29736, 34974, 39908, 27752, [12219, 39592], michael@0: 20379, 20844, 20849, 21151, 23380, [12079, 24037], 24656, 24685, 25329, michael@0: 25511, 25915, 29657, 31354, 34467, 36002, 38799, [20018, 63749], 23521, michael@0: [12093, 25096], 26524, [12128, 29916], 31185, 33747, 35463, 35506, 36328, michael@0: 36942, 37707, 38982, [24275, 64011], 27112, 34303, 37101, 20896, 23448, michael@0: 23532, 24931, 26874, 27454, 28748, 29743, 29912, 31649, 32592, 33733, michael@0: 35264, 36011, 38364, 39208, 21038, 24669, 25324, 36866, 20362, 20809, michael@0: 21281, 22745, 24291, 26336, 27960, 28826, 29378, 29654, 31568, 33009, michael@0: 37979, 21350, 25499, 32619, 20054, 20608, 22602, 22750, 24618, 24871, michael@0: 25296, 27088, 39745, 23439, 32024, 32945, 36703, 20132, 20689, 21676, michael@0: 21932, 23308, 23968, 24039, 25898, 25934, 26657, 27211, 29409, 30350, michael@0: 30703, 32094, 32761, 33184, 34126, 34527, 36611, 36686, 37066, 39171, michael@0: 39509, 39851, 19992, 20037, 20061, 20167, 20465, 20855, 21246, 21312, michael@0: [12061, 21475], [21477, 63750], 21646, 22036, 22389, 22434, 23495, 23943, michael@0: 24272, 25084, 25304, 25937, 26552, 26601, 27083, 27472, 27590, 27628, michael@0: 27714, 28317, 28792, 29399, 29590, 29699, 30655, 30697, 31350, 32127, michael@0: 32777, [12165, 33276], 33285, 33290, 33503, 34914, 35635, 36092, 36544, michael@0: 36881, 37041, 37476, 37558, 39378, 39493, 40169, 40407, michael@0: [12244, 40860, 63751, 63752], 22283, 23616, 33738, 38816, 38827, 40628, michael@0: 21531, 31384, 32676, 35033, 36557, 37089, 22528, 23624, 25496, 31391, michael@0: 23470, [12088, 24339], 31353, 31406, 33422, 36524, 20518, 21048, 21240, michael@0: 21367, 22280, 25331, 25458, 27402, 28099, 30519, 21413, 29527, 34152, michael@0: 36470, 38357, 26426, 27331, 28528, 35437, 36556, 39243, 26231, 27512, michael@0: 36020, [12225, 39740], 21483, 22317, 22862, 25542, 27131, 29674, 30789, michael@0: 31418, 31429, 31998, 33909, 35215, 36211, 36917, 38312, 21243, 22343, michael@0: 30023, 31584, 33740, 37406, 27224, 20811, 21067, 21127, 25119, 26840, michael@0: 26997, 38553, 20677, 21156, 21220, 25027, [12100, 26020], 26681, 27135, michael@0: 29822, 31563, 33465, 33771, 35250, 35641, 36817, 39241, 20170, 22935, michael@0: 25810, 26129, 27278, 29748, 31105, 31165, 33449, {f: 2, c: 34942}, 35167, michael@0: 37670, 20235, 21450, 24613, 25201, 27762, 32026, 32102, 20120, 20834, michael@0: 30684, 32943, 20225, 20238, 20854, 20864, 21980, 22120, 22331, 22522, michael@0: 22524, 22804, 22855, 22931, 23492, 23696, 23822, [12080, 24049], 24190, michael@0: 24524, 25216, 26071, 26083, {f: 2, c: 26398}, 26462, 26827, 26820, 27231, michael@0: 27450, 27683, 27773, 27778, 28103, 29592, 29734, 29738, 29826, 29859, michael@0: 30072, 30079, 30849, 30959, 31041, {f: 2, c: 31047}, 31098, 31637, 32000, michael@0: 32186, 32648, 32774, 32813, 32908, 35352, 35663, [35912, 63744], 36215, michael@0: 37665, 37668, 39138, 39249, {f: 2, c: 39438}, 39525, 40594, 32202, 20342, michael@0: 21513, 25326, 26708, [12198, 37329, 63754], 21931, 20794, 23068, 25062, michael@0: [25295, 63835], 25343, 37027, [35582, 63837], 26262, 29014, 38627, 25423, michael@0: 25466, 21335, 26511, 26976, 28275, 30007, 32013, 34930, 22218, 23064, michael@0: 20035, 20839, [22856, 63756], 26608, 32784, [12069, 22899, 63873], michael@0: [24180, 63886], [25754, 63889], [31178, 63893], [24565, 63907], 24684, michael@0: 25288, [25467, 63908], [23527, 63839, 63914], 23511, 21162, 22900, 24361, michael@0: [24594, 63840], 29785, 39377, 28611, 33215, 36786, 24817, 33126, michael@0: [23615, 63933], 23273, 35365, [26491, 63944], [32016, 63951], 33021, 23612, michael@0: [27877, 63971], [21311, 63979], [28346, 63980], 22810, [33590, 63998], michael@0: [20025, 63838], 20150, 20294, 21934, 22296, 22727, 24406, 26039, 26086, michael@0: 27264, 27573, 28237, 30701, 31471, 31774, 32222, 34507, 34962, 37170, michael@0: 37723, 25787, 28606, 29562, 30136, 36948, 21846, 22349, 25018, 25812, michael@0: 26311, 28129, 28251, 28525, 28601, 30192, 32835, 33213, 34113, 35203, michael@0: 35527, 35674, 37663, 27795, 30035, 31572, 36367, 36957, 21776, 22530, michael@0: 22616, 24162, 25095, 25758, 26848, 30070, [31958, 64003], 34739, 40680, michael@0: 20195, 22408, 22382, [12068, 22823], 23565, 23729, 24118, 24453, 25140, michael@0: 25825, 29619, 33274, 34955, 36024, 38538, 40667, [23429, 64004], 24503, michael@0: 24755, 20498, [12049, 20992], 21040, 22294, 22581, 22615, 23566, 23648, michael@0: 23798, 23947, [24230, 64001], 24466, 24764, 25361, 25481, 25623, 26691, michael@0: 26873, 27330, 28120, 28193, 28372, 28644, 29182, 30428, 30585, 31153, michael@0: 31291, 33796, 35241, 36077, 36339, 36424, 36867, 36884, 36947, 37117, michael@0: 37709, 38518, 38876, 27602, 28678, 29272, 29346, 29544, 30563, 31167, michael@0: 31716, 32411, [35712, 63834], 22697, 24775, 25958, 26109, 26302, 27788, michael@0: 28958, 29129, 35930, 38931, 20077, 31361, 20189, 20908, 20941, 21205, michael@0: 21516, 24999, 26481, 26704, 26847, [27934, 64005], 28540, 30140, 30643, michael@0: 31461, 33012, 33891, 37509, 20828, [12099, 26007], 26460, 26515, 30168, michael@0: 31431, 33651, [12182, 35910], 36887, 38957, 23663, 33216, 33434, 36929, michael@0: 36975, 37389, 24471, 23965, 27225, 29128, 30331, 31561, 34276, 35588, michael@0: 37159, 39472, [21895, 63755], [25078, 63757], [30313, 63758], michael@0: [32645, 63759], [34367, 63760], [34746, 63761], [35064, 63762], michael@0: [37007, 63763], [27931, 63765], [28889, 63766], [29662, 63767], 32097, michael@0: [33853, 63768], [37226, 63769], [39409, 63770], [20098, 63771], michael@0: [21365, 63772], [27396, 63773], 27410, 28734, [29211, 63774], michael@0: [34349, 63775], [40478, 63776], 21068, 36771, [23888, 63777], 25829, 25900, michael@0: 27414, [28651, 63778], 31811, 32412, [34253, 63779], [35172, 63780], 35261, michael@0: [25289, 63781], [33240, 63782], [34847, 63783], [24266, 63784], michael@0: [26391, 63785], [28010, 63786], [29436, 63787], 29701, 29807, 34690, michael@0: [37086, 63788], [20358, 63789], 23821, 24480, 33802, [20919, 63790], michael@0: [25504, 63861], [30053, 63862], [20142, 63863], 20486, [20841, 63864], michael@0: [20937, 63865], [26753, 63866], 27153, 31918, 31921, [31975, 63867], michael@0: [33391, 63868], [35538, 63869], 36635, [37327, 63870], 20406, 20791, michael@0: [21237, 63871], [21570, 63872], [24300, 63874], 24942, 25150, michael@0: [26053, 63875], 27354, [28670, 63876], [31018, 63877], 34268, 34851, michael@0: [38317, 63878], 39522, [39530, 63879], [40599, 63880], [40654, 63881], michael@0: [12050, 21147, 63882], [26310, 63883], [27511, 63884], 28701, 31019, michael@0: [36706, 63885], 38722, [24976, 63887], [25088, 63888], 25891, michael@0: [28451, 63890], [29001, 63891], [29833, 63892], [32244, 63894], michael@0: [32879, 63895], [34030, 63897], [36646, 63896], [36899, 63898], michael@0: [37706, 63899], 20925, [21015, 63900], [21155, 63901], 27916, michael@0: [28872, 63903], [35010, 63904], [24265, 63906], 25986, [27566, 63909], michael@0: 28610, [31806, 63910], [29557, 63911], [20196, 63912], 20278, michael@0: [22265, 63913], 23738, [23994, 63915], [24604, 63916], [29618, 63917], michael@0: 31533, [32666, 63919], 32718, [32838, 63920], 36894, [37428, 63921], michael@0: [38646, 63922], [38728, 63923], [38936, 63924], 40801, [20363, 63925], michael@0: 28583, [31150, 63926], [37300, 63927], [38583, 63928], [21214, 63791], michael@0: 25736, [25796, 63792], [27347, 63793], 28510, 28696, [29200, 63794], michael@0: [30439, 63795], [12156, 32769, 63796], [34310, 63797], [34396, 63798], michael@0: [36335, 63799], 36613, [38706, 63800], [39791, 63801], [40442, 63802], michael@0: [12228, 40565], [30860, 63803], [31103, 63804], [32160, 63805], michael@0: [33737, 63806], [37636, 63807], [12229, 40575, 63808], 40595, michael@0: [35542, 63809], [22751, 63810], [24324, 63811], 26407, 28711, 29903, michael@0: [31840, 63812], [32894, 63813], 20769, 28712, [29282, 63814], michael@0: [30922, 63815], [36034, 63816], 36058, 36084, [38647, 63817], michael@0: [20102, 63930], [20698, 63931], [23534, 63932], 24278, [26009, 63934], michael@0: [29134, 63936], [30274, 63937], 30637, 32842, [34044, 63938], michael@0: [36988, 63939], 39719, [12243, 40845, 63940], [22744, 63818], 23105, michael@0: [23650, 63819], [27155, 63820], [28122, 63821], [28431, 63822], 30267, michael@0: [32047, 63823], [32311, 63824], 34078, 35128, 37860, [38475, 63825], michael@0: [21129, 63943], 26066, [26611, 63945], 27060, [27969, 63946], michael@0: [28316, 63947], 28687, [29705, 63948], 29792, [30041, 63949], 30244, michael@0: [30827, 63950], 35628, [39006, 63952], [20845, 63953], [25134, 63954], michael@0: [38520, 63955], 20374, [20523, 63956], [23833, 63957], [28138, 63958], michael@0: 32184, [36650, 63959], [24459, 63960], [24900, 63961], [26647, 63962], michael@0: [38534, 63964], [21202, 63826], [32907, 63827], [20956, 63828], michael@0: [20940, 63829], 26974, [31260, 63830], [32190, 63831], [33777, 63832], michael@0: [38517, 63833], 20442, [21033, 63965], 21400, [21519, 63966], 21774, michael@0: [23653, 63967], 24743, [26446, 63969], [26792, 63970], 28012, 29313, 29432, michael@0: [29702, 63972], 29827, [30178, 63973], 31852, [32633, 63974], 32696, 33673, michael@0: [35023, 63975], [35041, 63976], [12197, 37324, 63977], 37328, michael@0: [38626, 63978], 39881, [21533, 63981], 28542, [29136, 63982], michael@0: [29848, 63983], [34298, 63984], 36522, [38563, 63985], [40023, 63986], michael@0: [40607, 63987], [26519, 63988], [28107, 63989], 29747, [33256, 63990], michael@0: 38678, 30764, [12148, 31435, 63991], [31520, 63992], [31890, 63993], 25705, michael@0: 29802, 30194, 30908, 30952, [12218, 39340], 39764, [12231, 40635], 23518, michael@0: 24149, 28448, 33180, 33707, 37000, 19975, 21325, 23081, 24018, 24398, michael@0: 24930, 25405, 26217, 26364, 28415, 28459, 28771, 30622, 33836, 34067, michael@0: 34875, 36627, 39237, 39995, 21788, 25273, 26411, 27819, 33545, 35178, michael@0: 38778, 20129, 22916, {f: 2, c: 24536}, 26395, 32178, 32596, 33426, 33579, michael@0: 33725, 36638, 37017, 22475, 22969, 23186, 23504, 26151, 26522, 26757, michael@0: 27599, 29028, 32629, 36023, 36067, 36993, 39749, 33032, 35978, 38476, michael@0: 39488, [12230, 40613], 23391, 27667, 29467, 30450, 30431, 33804, 20906, michael@0: 35219, 20813, 20885, 21193, 26825, 27796, 30468, 30496, 32191, 32236, michael@0: [12207, 38754], 40629, 28357, 34065, 20901, 21517, 21629, 26126, 26269, michael@0: 26919, 28319, [12139, 30399], 30609, 33559, 33986, 34719, 37225, 37528, michael@0: 40180, 34946, 20398, 20882, 21215, 22982, 24125, 24917, {f: 2, c: 25720}, michael@0: 26286, 26576, 27169, 27597, [12113, 27611], 29279, 29281, 29761, 30520, michael@0: [12141, 30683], 32791, 33468, 33541, 35584, 35624, 35980, [12106, 26408], michael@0: 27792, 29287, [12140, 30446], 30566, 31302, 40361, 27519, 27794, 22818, michael@0: 26406, 33945, 21359, 22675, 22937, 24287, 25551, 26164, 26483, 28218, michael@0: 29483, 31447, 33495, 37672, 21209, 24043, 25006, 25035, 25098, 25287, michael@0: 25771, [12102, 26080], 26969, 27494, [12111, 27595], 28961, 29687, 30045, michael@0: 32326, 33310, 33538, 34154, 35491, 36031, 38695, 40289, 22696, 40664, michael@0: 20497, 21006, 21563, 21839, [12098, 25991], 27766, {f: 2, c: 32010}, 32862, michael@0: 34442, [12200, 38272], 38639, 21247, 27797, 29289, 21619, 23194, 23614, michael@0: 23883, 24396, 24494, 26410, 26806, 26979, 28220, 28228, 30473, michael@0: [12150, 31859], 32654, 34183, 35598, 36855, 38753, 40692, 23735, 24758, michael@0: 24845, 25003, 25935, {f: 2, c: 26107}, 27665, 27887, 29599, 29641, 32225, michael@0: 38292, 23494, 34588, 35600, 21085, 21338, 25293, 25615, 25778, 26420, michael@0: 27192, 27850, 29632, 29854, 31636, 31893, 32283, 33162, 33334, 34180, michael@0: 36843, 38649, 39361, 20276, 21322, 21453, 21467, 25292, 25644, 25856, michael@0: 26001, 27075, 27886, 28504, 29677, 30036, 30242, 30436, 30460, 30928, michael@0: [30971, 63844], 31020, 32070, 33324, 34784, 36820, 38930, 39151, 21187, michael@0: 25300, 25765, 28196, 28497, 30332, 36299, 37297, 37474, 39662, 39747, michael@0: 20515, 20621, 22346, 22952, 23592, 24135, 24439, 25151, 25918, michael@0: [12101, 26041], 26049, 26121, 26507, 27036, 28354, 30917, 32033, 32938, michael@0: 33152, 33323, 33459, 33953, 34444, 35370, 35607, 37030, 38450, 40848, michael@0: 20493, 20467, 22521, 24472, 25308, 25490, 26479, 28227, 28953, 30403, michael@0: 32972, 32986, {f: 2, c: 35060}, 35097, 36064, 36649, 37197, 38506, 20271, michael@0: 20336, 24091, 26575, 26658, [12137, 30333], 30334, 39748, 24161, 27146, michael@0: 29033, 29140, 30058, 32321, 34115, 34281, 39132, 20240, 31567, 32624, michael@0: 38309, 20961, 24070, 26805, 27710, 27726, 27867, 29359, 31684, 33539, michael@0: 27861, 29754, 20731, 21128, 22721, 25816, 27287, 29863, 30294, 30887, michael@0: 34327, 38370, 38713, 21342, 24321, 35722, 36776, 36783, 37002, 21029, michael@0: 30629, 40009, 40712, 19993, 20482, 20853, 23643, 24183, 26142, 26170, michael@0: 26564, 26821, 28851, 29953, 30149, 31177, 31453, 36647, 39200, 39432, michael@0: 20445, 22561, 22577, 23542, 26222, 27493, 27921, 28282, 28541, 29668, michael@0: 29995, 33769, 35036, 35091, 35676, 36628, 20239, 20693, 21264, michael@0: [12056, 21340], 23443, [24489, 63846], 26381, 31119, 33145, 33583, 34068, michael@0: 35079, 35206, 36665, [36667, 64007], 39333, 39954, 26412, 20086, 20472, michael@0: 22857, 23553, {f: 2, c: 23791}, 25447, 26834, 28925, 29090, 29739, 32299, michael@0: 34028, 34562, 36898, 37586, 40179, [19981, 63847], 20184, 20463, 20613, michael@0: 21078, 21103, 21542, 21648, 22496, 22827, 23142, 23386, 23413, 23500, michael@0: 24220, 25206, 25975, 26023, 28014, 28325, [12119, 29238], 31526, 31807, michael@0: [12152, 32566], {f: 2, c: 33104}, 33178, 33344, 33433, 33705, 35331, 36000, michael@0: 36070, 36091, 36212, 36282, 37096, 37340, [12201, 38428], 38468, 39385, michael@0: 40167, [21271, 63843], 20998, 21545, 22132, 22707, 22868, 22894, 24575, michael@0: 24996, 25198, 26128, 27774, 28954, 30406, 31881, 31966, 32027, 33452, michael@0: 36033, 38640, 20315, 24343, 24447, 25282, 23849, 26379, 26842, 30844, michael@0: 32323, 40300, 19989, 20633, [12052, 21269], 21290, 21329, 22915, 23138, michael@0: 24199, 24754, 24970, 25161, 25209, 26000, 26503, 27047, [12112, 27604], michael@0: {f: 3, c: 27606}, 27832, 29749, 30202, 30738, 30865, 31189, 31192, 31875, michael@0: 32203, 32737, 32933, 33086, 33218, 33778, 34586, 35048, 35513, 35692, michael@0: 36027, 37145, [12206, 38750], [12214, 39131], [12240, 40763], 22188, 23338, michael@0: 24428, 25996, 27315, 27567, 27996, 28657, 28693, 29277, 29613, 36007, michael@0: 36051, 38971, 24977, 27703, 32856, 39425, 20045, 20107, 20123, 20181, michael@0: 20282, 20284, 20351, 20447, 20735, 21490, 21496, 21766, 21987, 22235, michael@0: [12064, 22763], 22882, 23057, 23531, 23546, 23556, 24051, 24107, 24473, michael@0: 24605, 25448, 26012, 26031, 26614, 26619, 26797, 27515, 27801, 27863, michael@0: 28195, 28681, 29509, 30722, 31038, 31040, 31072, 31169, 31721, 32023, michael@0: 32114, 32902, 33293, 33678, 34001, 34503, 35039, 35408, 35422, 35613, michael@0: 36060, 36198, 36781, 37034, 39164, 39391, 40605, 21066, 26388, 20632, michael@0: 21034, [12077, 23665], 25955, 27733, 29642, 29987, 30109, 31639, 33948, michael@0: 37240, 38704, 20087, 25746, [27578, 63856], 29022, 34217, 19977, 26441, michael@0: 26862, 28183, 33439, 34072, 34923, 25591, 28545, 37394, 39087, 19978, michael@0: 20663, 20687, 20767, 21830, 21930, 22039, 23360, 23577, 23776, 24120, michael@0: 24202, 24224, 24258, 24819, 26705, 27233, 28248, 29245, 29248, michael@0: [29376, 63994], 30456, 31077, 31665, 32724, 35059, 35316, 35443, 35937, michael@0: 36062, 38684, [22622, 63852], 29885, 36093, 21959, 31329, [32034, 63850], michael@0: [12170, 33394], 29298, [12131, 29983], 29989, 31513, 22661, 22779, 23996, michael@0: 24207, 24246, 24464, 24661, 25234, 25471, 25933, 26257, 26329, 26360, michael@0: 26646, 26866, 29312, 29790, 31598, 32110, 32214, 32626, 32997, 33298, michael@0: 34223, 35199, 35475, 36893, 37604, [12233, 40653], [12239, 40736], michael@0: [12067, 22805], 22893, 24109, 24796, 26132, 26227, 26512, 27728, 28101, michael@0: 28511, [12143, 30707], 30889, 33990, 37323, 37675, 20185, 20682, 20808, michael@0: 21892, 23307, 23459, 25159, 25982, 26059, 28210, 29053, 29697, 29764, michael@0: 29831, 29887, 30316, 31146, 32218, 32341, 32680, 33146, 33203, 33337, michael@0: 34330, 34796, 35445, 36323, 36984, 37521, 37925, 39245, 39854, 21352, michael@0: 23633, 26964, 27844, 27945, 28203, [12166, 33292], 34203, 35131, 35373, michael@0: [35498, 63855, 63905], 38634, 40807, 21089, 26297, 27570, 32406, 34814, michael@0: 36109, 38275, 38493, 25885, 28041, 29166, 22478, 22995, 23468, 24615, michael@0: 24826, 25104, 26143, 26207, 29481, 29689, 30427, [30465, 63853], 31596, michael@0: 32854, 32882, 33125, 35488, 37266, 19990, 21218, 27506, 27927, 31237, michael@0: 31545, 32048, 36016, 21484, 22063, 22609, 23477, [12073, 23567], 23569, michael@0: 24034, 25152, 25475, 25620, 26157, 26803, 27836, 28040, 28335, 28703, michael@0: 28836, 29138, 29990, 30095, 30094, 30233, 31505, 31712, 31787, 32032, michael@0: 32057, 34092, 34157, 34311, 35380, 36877, 36961, 37045, 37559, 38902, michael@0: 39479, 20439, 23660, 26463, 28049, 31903, 32396, 35606, 36118, 36895, michael@0: 23403, 24061, 25613, 33984, 36956, 39137, [29575, 63841, 63963], 23435, michael@0: 24730, 26494, 28126, 35359, 35494, 36865, 38924, 21047, 28753, 30862, michael@0: 37782, 34928, 37335, 20462, 21463, 22013, 22234, 22402, 22781, 23234, michael@0: 23432, 23723, 23744, 24101, 24833, 25101, [12095, 25163], 25480, 25628, michael@0: 25910, [25976, 63849], 27193, 27530, [12116, 27700], 27929, 28465, 29159, michael@0: 29417, 29560, 29703, 29874, 30246, 30561, 31168, 31319, 31466, 31929, michael@0: 32143, 32172, 32353, 32670, 33065, 33585, 33936, 34010, 34282, 34966, michael@0: 35504, 35728, 36664, 36930, 36995, 37228, 37526, 37561, 38539, michael@0: {f: 2, c: 38567}, 38614, 38656, 38920, [12216, 39318], 39635, 39706, 21460, michael@0: 22654, 22809, 23408, 23487, 28113, 28506, 29087, 29729, 29881, 32901, michael@0: 33789, 24033, 24455, 24490, 24642, 26092, 26642, 26991, 27219, 27529, michael@0: 27957, 28147, 29667, 30462, 30636, 31565, 32020, 33059, 33308, 33600, michael@0: 34036, 34147, 35426, 35524, 37255, 37662, 38918, 39348, 25100, 34899, michael@0: 36848, 37477, 23815, 23847, 23913, 29791, 33181, 34664, 28629, michael@0: [25342, 63859], 32722, 35126, 35186, 19998, 20056, 20711, 21213, 21319, michael@0: 25215, 26119, 32361, 34821, 38494, 20365, 21273, 22070, 22987, 23204, michael@0: [12075, 23608], 23630, 23629, 24066, 24337, 24643, 26045, 26159, 26178, michael@0: 26558, 26612, 29468, [12142, 30690], [12144, 31034], 32709, 33940, 33997, michael@0: 35222, 35430, 35433, 35553, [12183, 35925], 35962, 22516, 23508, 24335, michael@0: 24687, 25325, 26893, 27542, 28252, 29060, 31698, 34645, [35672, 63996], michael@0: 36606, [12215, 39135], 39166, 20280, 20353, 20449, 21627, 23072, 23480, michael@0: 24892, 26032, 26216, 29180, 30003, 31070, 32051, 33102, [12162, 33251], michael@0: 33688, 34218, 34254, 34563, 35338, [12189, 36523], [12191, 36763], 36805, michael@0: 22833, 23460, 23526, 24713, 23529, 23563, [12092, 24515], 27777, 28145, michael@0: 28683, 29978, 33455, 35574, [20160, 63997], [12055, 21313], 38617, michael@0: [12114, 27663], 20126, 20420, 20818, 21854, 23077, 23784, 25105, michael@0: [12123, 29273], 33469, 33706, 34558, 34905, 35357, 38463, 38597, 39187, michael@0: 40201, 40285, 22538, 23731, 23997, 24132, [24801, 63929], 24853, 25569, michael@0: [27138, 63764, 63836, 63935], 28197, 37122, 37716, 38990, 39952, 40823, michael@0: 23433, 23736, 25353, 26191, 26696, 30524, 38593, 38797, 38996, 39839, michael@0: 26017, 35585, 36555, 38332, 21813, 23721, 24022, 24245, 26263, 30284, michael@0: 33780, 38343, 22739, 25276, 29390, 40232, 20208, 22830, 24591, 26171, michael@0: 27523, 31207, 40230, 21395, 21696, 22467, 23830, 24859, 26326, 28079, michael@0: 30861, 33406, 38552, 38724, 21380, 25212, 25494, 28082, 32266, 33099, michael@0: 38989, 27387, 32588, 40367, 40474, 20063, 20539, 20918, 22812, 24825, michael@0: 25590, 26928, 29242, 32822, 37326, 24369, 32004, [33509, 63860], 33903, michael@0: 33979, 34277, 36493, 20335, 22756, 23363, 24665, 25562, 25880, 25965, michael@0: 26264, 26954, 27171, 27915, 28673, 29036, 30162, 30221, 31155, 31344, michael@0: [12154, 32650], 35140, 35731, 37312, 38525, 39178, 22276, 24481, 26044, michael@0: 28417, 30208, 31142, 35486, 39341, [12226, 39770], 40812, 20740, 25014, michael@0: 25233, 27277, 33222, 20547, 22576, 24422, 28937, [12180, 35328], 35578, michael@0: 23420, 34326, 20474, 20796, 22196, 22852, 25513, 28153, 23978, 26989, michael@0: 20870, 20104, 20313, 22914, 27487, 27741, 29877, 30998, 33287, 33349, michael@0: 33593, 36671, 36701, 39192, 20134, 22495, 24441, [26131, 63968], 30123, michael@0: 32377, 35695, 36870, 39515, 22181, 22567, 23032, 23071, 23476, 24310, michael@0: 25424, 25403, 26941, 27783, 27839, 28046, 28051, 28149, 28436, 28895, michael@0: 28982, 29017, 29123, 29141, 30799, 30831, 31605, 32227, 32303, 34893, michael@0: 36575, 37467, 40182, 24709, 28037, 29105, 38321, 21421, 26579, 28814, michael@0: 28976, 29744, 33398, 33490, 38331, 39653, 40573, 26308, 29121, michael@0: [33865, 63854], 22603, 23992, 24433, 26144, 26254, 27001, 27054, 27704, michael@0: 27891, 28214, 28481, 28634, 28699, 28719, 29008, 29151, 29552, 29787, michael@0: 29908, 30408, 31310, 32403, 33521, 35424, 36814, 37704, 38681, 20034, michael@0: 20522, 21000, 21473, 26355, 27757, 28618, 29450, 30591, 31330, 33454, michael@0: 34269, 34306, 35028, 35427, 35709, 35947, 37555, 38675, 38928, 20116, michael@0: 20237, 20425, 20658, 21320, 21566, 21555, 21978, 22626, 22714, 22887, michael@0: 23067, 23524, 24735, 25034, 25942, 26111, 26212, 26791, 27738, 28595, michael@0: 28879, 29100, 29522, 31613, 34568, 35492, 39986, 40711, 23627, 27779, michael@0: 29508, [12127, 29577], 37434, 28331, 29797, 30239, 31337, 32277, 34314, michael@0: 20800, 22725, 25793, 29934, 29973, 30320, 32705, 37013, 38605, 39252, michael@0: 28198, [12129, 29926], {f: 2, c: 31401}, 33253, 34521, 34680, 35355, 23113, michael@0: 23436, 23451, 26785, 26880, 28003, 29609, 29715, 29740, 30871, 32233, michael@0: 32747, 33048, 33109, 33694, 35916, [38446, 63942], 38929, [12104, 26352], michael@0: 24448, 26106, 26505, 27754, 29579, 20525, 23043, 27498, 30702, 22806, michael@0: 23916, 24013, 29477, 30031, 20709, 20985, 22575, 22829, 22934, 23002, michael@0: 23525, 23970, 25303, 25622, 25747, 25854, 26332, 27208, 29183, 29796, michael@0: 31368, 31407, 32327, 32350, 32768, 33136, 34799, 35201, 35616, 36953, michael@0: 36992, 39250, 24958, 27442, 28020, 32287, 35109, 36785, 20433, 20653, michael@0: 20887, 21191, 22471, 22665, 23481, 24248, 24898, 27029, 28044, 28263, michael@0: 28342, 29076, 29794, [12132, 29992], 29996, 32883, 33592, 33993, 36362, michael@0: 37780, 37854, 20110, 20305, 20598, 20778, [12060, 21448], 21451, 21491, michael@0: 23431, 23507, 23588, 24858, 24962, 26100, [12124, 29275], 29591, 29760, michael@0: 30402, 31056, 31121, 31161, 32006, [12155, 32701], 33419, 34261, 34398, michael@0: 36802, 36935, 37109, 37354, 38533, [12204, 38632], 38633, 21206, 24423, michael@0: 26093, 26161, 26671, 29020, 31286, 37057, 38922, 20113, 27218, 27550, michael@0: 28560, 29065, 32792, 33464, 34131, 36939, 38549, 38642, 38907, 34074, michael@0: 39729, 20112, 29066, 38596, 20803, 21407, 21729, 22291, 22290, 22435, michael@0: 23195, 23236, 23491, 24616, 24895, 25588, 27781, 27961, 28274, 28304, michael@0: 29232, 29503, 29783, 33489, 34945, 36677, 36960, 38498, 39000, 40219, michael@0: [12105, 26376], 36234, 37470, 20301, 20553, 20702, 21361, 22285, 22996, michael@0: 23041, 23561, 24944, 26256, 28205, 29234, 29771, 32239, 32963, 33806, michael@0: 33894, 34111, 34655, 34907, 35096, 35586, 36949, [12209, 38859], 39759, michael@0: 20083, 20369, 20754, 20842, 21807, 21929, 23418, 23461, {f: 2, c: 24188}, michael@0: 24254, 24736, 24799, {f: 2, c: 24840}, 25540, 25912, 26377, 26580, 26586, michael@0: {f: 2, c: 26977}, 27833, 27943, 28216, 28641, {f: 2, c: 29494}, 29788, michael@0: 30001, 30290, 32173, 33278, 33848, 35029, 35480, 35547, 35565, 36400, michael@0: 36418, 36938, 36926, 36986, [12195, 37193], 37321, 37742, 22537, 27603, michael@0: [12161, 32905], 32946, 20801, 22891, 23609, 28516, 29607, 32996, 36103, michael@0: 37399, 38287, [12160, 32895], 25102, 28700, 32104, 34701, 22432, 24681, michael@0: 24903, 27575, 35518, 37504, 38577, [12036, 20057], 21535, 28139, 34093, michael@0: 38512, [12211, 38899], 39150, 25558, 27875, [12194, 37009], 20957, 25033, michael@0: 33210, 40441, 20381, 20506, 20736, 23452, 24847, 25087, 25836, 26885, michael@0: 27589, 30097, 30691, 32681, 33380, 34191, 34811, [12176, 34915], 35516, michael@0: 35696, 37291, [12038, 20108], 20197, 20234, 22839, 23016, 24050, 24347, michael@0: 24411, 24609, 29246, 29669, [30064, 63842], 30157, 31227, [12157, 32780], michael@0: [12159, 32819], 32900, 33505, 33617, 36029, 36019, 36999, 39156, 39180, michael@0: 28727, 30410, 32714, 32716, 32764, 35610, [12040, 20154], 20161, 20995, michael@0: 21360, [21693, 63902], 22240, 23035, 23493, 24341, 24525, 28270, 32106, michael@0: 33589, 34451, 35469, 38765, 38775, [12032, 19968], 20314, 20350, 22777, michael@0: [12103, 26085], 28322, 36920, 37808, 39353, 20219, 22764, 22922, 23001, michael@0: 24641, 31252, 33615, 36035, [12042, 20837], 21316, 20173, 21097, 23381, michael@0: 33471, 20180, [21050, 63999], 21672, 22985, 23039, [12070, 23376], 23383, michael@0: 23388, 24675, 24904, 28363, [28825, 63995], 29038, 29574, 29943, 30133, michael@0: 30913, 32043, 32773, [12163, 33258], 33576, 34071, 34249, 35566, 36039, michael@0: 38604, 20316, 21242, 22204, 26027, 26152, 28796, 28856, 29237, 32189, michael@0: 33421, 37196, 38592, 40306, 23409, 26855, 27544, 28538, 30430, 23697, michael@0: 26283, 28507, 31668, 31786, 34870, 38620, 19976, 20183, 21280, 22580, michael@0: 22715, 22767, 22892, 23559, 24115, 24196, 24373, 25484, 26290, 26454, michael@0: 27167, 27299, 27404, 28479, 29254, 29520, 29835, 31456, 31911, 33144, michael@0: 33247, 33255, 33674, 33900, 34083, 34196, 34255, 35037, 36115, 37292, michael@0: [12199, 38263], 38556, 20877, 21705, 22312, 23472, 25165, 26448, 26685, michael@0: 26771, 28221, 28371, 28797, 32289, 35009, 36001, 36617, 40779, 40782, michael@0: 29229, 31631, 35533, 37658, 20295, 20302, 20786, 21632, 22992, 24213, michael@0: 25269, 26485, 26990, 27159, 27822, 28186, 29401, 29482, 30141, 31672, michael@0: 32053, 33511, 33785, 33879, 34295, 35419, 36015, 36487, 36889, 37048, michael@0: 38606, 40799, 21219, 21514, 23265, 23490, 25688, 25973, 28404, 29380, michael@0: 30340, 31309, 31515, 31821, 32318, 32735, 33659, 35627, 36042, michael@0: [12186, 36196], 36321, 36447, 36842, 36857, 36969, 37841, 20291, 20346, michael@0: 20659, 20840, 20856, 21069, 21098, 22625, 22652, 22880, 23560, 23637, michael@0: 24283, 24731, 25136, 26643, 27583, 27656, 28593, 29006, 29728, michael@0: [12133, 30000], 30008, 30033, 30322, 31564, 31627, 31661, 31686, 32399, michael@0: 35438, 36670, 36681, 37439, 37523, 37666, 37931, 38651, 39002, 39019, michael@0: 39198, [20999, 64000], 25130, 25240, 27993, 30308, 31434, 31680, 32118, michael@0: 21344, 23742, 24215, 28472, 28857, 31896, 38673, 39822, 40670, 25509, michael@0: 25722, 34678, 19969, 20117, 20141, 20572, 20597, 21576, 22979, 23450, michael@0: 24128, 24237, 24311, 24449, 24773, 25402, 25919, 25972, 26060, 26230, michael@0: 26232, 26622, 26984, 27273, 27491, 27712, 28096, 28136, 28191, 28254, michael@0: 28702, 28833, 29582, 29693, 30010, 30555, 30855, 31118, 31243, 31357, michael@0: 31934, 32142, 33351, 35330, 35562, 35998, 37165, 37194, 37336, 37478, michael@0: 37580, 37664, 38662, 38742, 38748, 38914, [12237, 40718], 21046, 21137, michael@0: 21884, 22564, 24093, 24351, 24716, 25552, 26799, 28639, 31085, 31532, michael@0: 33229, 34234, 35069, 35576, 36420, 37261, 38500, 38555, 38717, 38988, michael@0: [12241, 40778], 20430, 20806, 20939, 21161, 22066, 24340, 24427, 25514, michael@0: 25805, 26089, 26177, 26362, 26361, 26397, 26781, 26839, 27133, 28437, michael@0: 28526, 29031, 29157, [12118, 29226], 29866, 30522, 31062, 31066, 31199, michael@0: 31264, 31381, 31895, 31967, 32068, 32368, 32903, 34299, 34468, 35412, michael@0: 35519, 36249, 36481, 36896, 36973, 37347, 38459, 38613, [12227, 40165], michael@0: 26063, 31751, [12188, 36275], 37827, 23384, 23562, 21330, 25305, 29469, michael@0: 20519, 23447, 24478, 24752, 24939, 26837, 28121, 29742, 31278, 32066, michael@0: 32156, 32305, 33131, 36394, 36405, 37758, 37912, 20304, 22352, 24038, michael@0: 24231, 25387, 32618, 20027, 20303, 20367, 20570, 23005, 32964, 21610, michael@0: 21608, 22014, 22863, 23449, 24030, 24282, 26205, 26417, 26609, 26666, michael@0: 27880, 27954, 28234, 28557, 28855, 29664, 30087, 31820, 32002, 32044, michael@0: 32162, [12168, 33311], 34523, 35387, 35461, [12187, 36208], 36490, 36659, michael@0: 36913, 37198, 37202, 37956, 39376, [12149, 31481], 31909, 20426, 20737, michael@0: 20934, 22472, 23535, 23803, 26201, 27197, 27994, 28310, 28652, 28940, michael@0: 30063, 31459, 34850, 36897, 36981, 38603, 39423, 33537, 20013, 20210, michael@0: 34886, 37325, 21373, 27355, 26987, 27713, 33914, 22686, 24974, 26366, michael@0: 25327, 28893, 29969, 30151, 32338, 33976, 35657, 36104, 20043, 21482, michael@0: 21675, 22320, 22336, 24535, 25345, 25351, 25711, [12096, 25903], 26088, michael@0: 26234, 26525, 26547, [12108, 27490], 27744, 27802, 28460, 30693, 30757, michael@0: 31049, 31063, 32025, 32930, 33026, [12164, 33267], 33437, 33463, 34584, michael@0: 35468, 36100, 36286, 36978, 30452, 31257, 31287, 32340, 32887, 21767, michael@0: 21972, 22645, 25391, 25634, 26185, 26187, 26733, 27035, 27524, 27941, michael@0: 28337, 29645, 29800, 29857, 30043, 30137, 30433, 30494, 30603, 31206, michael@0: 32265, 32285, 33275, 34095, 34967, 35386, 36049, 36587, michael@0: [12192, 36784, 63857], 36914, 37805, 38499, 38515, 38663, 20356, 21489, michael@0: 23018, 23241, 24089, 26702, 29894, 30142, 31209, 31378, 33187, 34541, michael@0: 36074, 36300, 36845, 26015, 26389, 22519, 28503, 32221, 36655, 37878, michael@0: 38598, 24501, 25074, 28548, 19988, 20376, 20511, 21449, 21983, 23919, michael@0: 24046, 27425, 27492, 30923, 31642, 36425, [12190, 36554, 63746], 36974, michael@0: 25417, 25662, 30528, 31364, 37679, 38015, 40810, 25776, 28591, 29158, michael@0: 29864, 29914, 31428, 31762, 32386, 31922, 32408, 35738, 36106, 38013, michael@0: 39184, 39244, 21049, 23519, 25830, 26413, 32046, 20717, [21443, 63851], michael@0: 22649, {f: 2, c: 24920}, 25082, 26028, 31449, 35730, 35734, 20489, 20513, michael@0: 21109, 21809, 23100, 24288, 24432, 24884, 25950, 26124, 26166, 26274, michael@0: 27085, 28356, 28466, 29462, 30241, 31379, 33081, 33369, 33750, 33980, michael@0: 20661, 22512, 23488, 23528, 24425, 25505, 30758, 32181, 33756, 34081, michael@0: 37319, 37365, 20874, 26613, 31574, 36012, 20932, 22971, 24765, 34389, michael@0: 20508, 21076, 23610, 24957, 25114, [25299, 64002], 25842, 26021, 28364, michael@0: 30240, 33034, 36448, 38495, 38587, 20191, 21315, 21912, 22825, 24029, michael@0: 25797, 27849, 28154, 29588, 31359, [12167, 33307], 34214, 36068, 36368, michael@0: 36983, 37351, 38369, 38433, 38854, 20984, 21746, 21894, 24505, 25764, michael@0: 28552, 32180, 36639, 36685, 37941, 20681, 23574, 27838, 28155, 29979, michael@0: 30651, 31805, 31844, 35449, 35522, 22558, 22974, 24086, 25463, 29266, michael@0: 30090, 30571, 35548, 36028, 36626, 24307, 26228, 28152, 32893, 33729, michael@0: 35531, [12205, 38737], 39894, 21059, 26367, 28053, 28399, 32224, 35558, michael@0: 36910, 36958, 39636, 21021, 21119, 21736, 24980, 25220, 25307, 26786, michael@0: 26898, 26970, 27189, 28818, 28966, 30813, 30977, 30990, 31186, 31245, michael@0: 32918, [12171, 33400], 33493, 33609, 34121, 35970, 36229, 37218, 37259, michael@0: 37294, 20419, 22225, 29165, 30679, 34560, 35320, [12072, 23544], 24534, michael@0: 26449, 37032, 21474, 22618, 23541, 24740, 24961, 25696, 32317, 32880, michael@0: 34085, 37507, 25774, 20652, 23828, 26368, 22684, 25277, 25512, 26894, michael@0: 27000, 27166, 28267, 30394, 31179, 33467, 33833, 35535, 36264, 36861, michael@0: 37138, 37195, 37276, 37648, 37656, 37786, 38619, 39478, 39949, 19985, michael@0: 30044, 31069, 31482, 31569, 31689, 32302, 33988, 36441, 36468, 36600, michael@0: 36880, 26149, 26943, 29763, 20986, 26414, 40668, 20805, 24544, 27798, michael@0: 34802, 34909, 34935, 24756, 33205, 33795, 36101, 21462, 21561, 22068, michael@0: 23094, 23601, 28810, 32736, 32858, 33030, 33261, 36259, 37257, 39519, michael@0: 40434, 20596, 20164, 21408, 24827, 28204, 23652, 20360, 20516, 21988, michael@0: 23769, 24159, 24677, 26772, 27835, 28100, 29118, 30164, 30196, 30305, michael@0: 31258, 31305, 32199, 32251, 32622, 33268, 34473, 36636, 38601, 39347, michael@0: [12242, 40786], 21063, 21189, 39149, 35242, 19971, 26578, 28422, 20405, michael@0: 23522, 26517, [27784, 63858], 28024, 29723, 30759, 37341, 37756, 34756, michael@0: 31204, 31281, 24555, 20182, 21668, 21822, 22702, 22949, 24816, 25171, michael@0: 25302, 26422, 26965, 33333, 38464, 39345, 39389, 20524, 21331, 21828, michael@0: 22396, 25176, 25826, 26219, 26589, 28609, 28655, 29730, 29752, 35351, michael@0: 37944, 21585, 22022, 22374, 24392, 24986, 27470, 28760, 28845, 32187, michael@0: 35477, 22890, 33067, 25506, 30472, 32829, 36010, 22612, 25645, 27067, michael@0: 23445, 24081, 28271, 34153, 20812, 21488, 22826, 24608, 24907, 27526, michael@0: 27760, 27888, 31518, 32974, 33492, 36294, 37040, 39089, 25799, 28580, michael@0: 25745, 25860, 20814, 21520, [12063, 22303], 35342, 24927, 26742, 30171, michael@0: 31570, 32113, 36890, 22534, 27084, 33151, 35114, 36864, 38969, 20600, michael@0: 22871, 22956, 25237, 36879, 39722, 24925, 29305, 38358, 22369, 23110, michael@0: 24052, 25226, 25773, 25850, 26487, 27874, 27966, 29228, 29750, 30772, michael@0: 32631, 33453, 36315, 38935, 21028, 22338, 26495, 29256, 29923, 36009, michael@0: 36774, 37393, 38442, [12043, 20843], 21485, 25420, 20329, 21764, 24726, michael@0: 25943, 27803, 28031, 29260, 29437, 31255, 35207, [12185, 35997], 24429, michael@0: 28558, 28921, 33192, 24846, [20415, 63845], 20559, 25153, [12122, 29255], michael@0: 31687, 32232, 32745, 36941, 38829, 39449, 36022, 22378, 24179, 26544, michael@0: 33805, 35413, 21536, 23318, 24163, 24290, 24330, 25987, 32954, 34109, michael@0: 38281, 38491, 20296, 21253, 21261, 21263, 21638, 21754, 22275, 24067, michael@0: 24598, 25243, 25265, 25429, 27873, 28006, 30129, 30770, 32990, 33071, michael@0: 33502, 33889, 33970, 34957, 35090, 36875, 37610, 39165, 39825, 24133, michael@0: [26292, 64006], 26333, 28689, 29190, 20469, 21117, 24426, 24915, 26451, michael@0: 27161, 28418, 29922, 31080, 34920, 35961, 39111, 39108, 39491, 21697, michael@0: 31263, 26963, 35575, 35914, [12213, 39080], 39342, 24444, 25259, 30130, michael@0: [12138, 30382], 34987, 36991, 38466, 21305, 24380, 24517, [27852, 63848], michael@0: 29644, 30050, [12134, 30091], 31558, 33534, 39325, 20047, 36924, 19979, michael@0: 20309, 21414, 22799, 24264, 26160, 27827, 29781, 33655, 34662, 36032, michael@0: 36944, 38686, 39957, 22737, 23416, 34384, 35604, 40372, 23506, 24680, michael@0: 24717, 26097, 27735, 28450, 28579, 28698, 32597, 32752, {f: 2, c: 38289}, michael@0: 38480, 38867, 21106, 36676, 20989, 21547, 21688, 21859, 21898, 27323, michael@0: 28085, 32216, 33382, 37532, 38519, 40569, 21512, 21704, 30418, 34532, michael@0: 38308, 38356, 38492, 20130, 20233, 23022, 23270, 24055, 24658, 25239, michael@0: 26477, 26689, 27782, 28207, 32568, 32923, 33322, 38917, 20133, 20565, michael@0: 21683, 22419, 22874, 23401, 23475, 25032, 26999, 28023, 28707, 34809, michael@0: 35299, 35442, 35559, 36994, 39405, 39608, 21182, 26680, 20502, 24184, michael@0: 26447, 33607, [12175, 34892, 64008], 20139, 21521, 22190, 29670, 37141, michael@0: 38911, 39177, 39255, [12217, 39321], 22099, 22687, 34395, 35377, 25010, michael@0: 27382, 29563, 36562, 27463, 38570, 39511, 22869, 29184, 36203, michael@0: [12208, 38761], 20436, 23796, 24358, 25080, 26203, 27883, 28843, michael@0: [12126, 29572], 29625, 29694, 30505, 30541, 32067, 32098, 32291, 33335, michael@0: 34898, 36066, 37449, 39023, 23377, [12147, 31348], [12174, 34880], michael@0: [12212, 38913], 23244, 20448, 21332, 22846, 23805, 25406, 28025, 29433, michael@0: 33029, 33031, 33698, 37583, 38960, 20136, 20804, 21009, 22411, 24418, michael@0: 27842, 28366, 28677, 28752, 28847, 29074, 29673, [29801, 63918], 33610, michael@0: 34722, 34913, 36872, 37026, 37795, 39336, 20846, 24407, 24800, 24935, michael@0: 26291, 34137, 36426, 37295, 38795, 20046, 20114, 21628, 22741, 22778, michael@0: 22909, 23733, 24359, [12094, 25142], 25160, 26122, 26215, 27627, 28009, michael@0: 28111, 28246, 28408, 28564, 28640, 28649, 28765, 29392, 29733, 29786, michael@0: 29920, 30355, 31068, 31946, 32286, 32993, 33446, 33899, 33983, 34382, michael@0: 34399, 34676, 35703, 35946, 37804, 38912, 39013, 24785, 25110, 37239, michael@0: 23130, 26127, 28151, 28222, 29759, 39746, 24573, 24794, 31503, 21700, michael@0: 24344, 27742, 27859, 27946, 28888, 32005, 34425, 35340, 40251, 21270, michael@0: 21644, 23301, 27194, [12117, 28779], 30069, 31117, [12146, 31166], 33457, michael@0: 33775, 35441, 35649, 36008, 38772, 25844, 25899, {f: 2, c: 30906}, 31339, michael@0: 20024, 21914, 22864, 23462, 24187, 24739, 25563, 27489, 26213, 26707, michael@0: 28185, 29029, 29872, 32008, 36996, 39529, 39973, 27963, [28369, 63748], michael@0: 29502, 35905, 38346, 20976, 24140, 24488, 24653, 24822, 24880, 24908, michael@0: {f: 2, c: 26179}, 27045, 27841, 28255, 28361, 28514, 29004, 29852, 30343, michael@0: 31681, 31783, 33618, 34647, 36945, 38541, [12232, 40643], 21295, 22238, michael@0: 24315, 24458, 24674, 24724, 25079, 26214, 26371, 27292, 28142, 28590, michael@0: 28784, 29546, 32362, 33214, 33588, 34516, 35496, 36036, 21123, 29554, michael@0: 23446, 27243, 37892, 21742, 22150, 23389, 25928, 25989, 26313, 26783, michael@0: 28045, 28102, [12120, 29243], 32948, 37237, 39501, 20399, 20505, 21402, michael@0: 21518, 21564, 21897, 21957, 24127, 24460, 26429, 29030, 29661, 36869, michael@0: 21211, 21235, 22628, 22734, 28932, 29071, 29179, 34224, 35347, michael@0: [26248, 63941], 34216, 21927, 26244, 29002, 33841, 21321, 21913, 27585, michael@0: 24409, 24509, 25582, 26249, 28999, 35569, 36637, 40638, 20241, 25658, michael@0: 28875, 30054, 34407, 24676, 35662, 40440, 20807, 20982, 21256, 27958, michael@0: 33016, [12234, 40657], 26133, 27427, 28824, 30165, 21507, 23673, 32007, michael@0: 35350, [12107, 27424], 27453, 27462, 21560, 24688, 27965, 32725, 33288, michael@0: 20694, 20958, 21916, 22123, 22221, 23020, 23305, 24076, 24985, 24984, michael@0: 25137, 26206, 26342, 29081, {f: 2, c: 29113}, 29351, 31143, 31232, 32690, michael@0: 35440, {s: 163}, {f: 4, c: 12310}, {s: 14}, 8223, 8219, {f: 2, c: 8314}, michael@0: {s: 7}, 8316, 0, {f: 2, c: 8317}, {s: 23}, 700, {s: 44}, 8942, 8759, michael@0: {s: 20}, {f: 10, c: 10122}, {s: 36}, {f: 26, c: 9398}, {s: 61}, michael@0: {f: 2, c: 8826}, {f: 2, c: 8910}, {f: 2, c: 8832}, {f: 4, c: 8816}, 0, michael@0: 8842, 0, 8843, {f: 2, c: 8822}, 8825, {f: 2, c: 8922}, {s: 5}, 8773, 8771, michael@0: 8776, 0, 8868, {s: 78}, 8244, {s: 11}, 9839, {s: 4}, 8258, {s: 4}, 10045, michael@0: 0, 0, 8226, {s: 4}, {f: 2, c: 8249}, {s: 16}, 10010, 10006, 0, 9711, michael@0: {s: 3}, 10070, 0, 9676, {s: 24}, 9775, {s: 6}, 12320, 0, {f: 10, c: 10102}, michael@0: {s: 17}, 12306, 12342, {s: 13}, 8710, 0, 8735, 0, {f: 2, c: 8741}, 0, 8787, michael@0: 8785, {f: 2, c: 8806}, 8723, {f: 3, c: 8853}, 0, 8980, 0, 0, 8802, 0, 9649, michael@0: 0, 8738, 8784, 0, 0, 8867, 0, 0, {f: 2, c: 8814}, 8837, 8836, 8713, 8716, michael@0: {f: 2, c: 8891}, 8794, 8966, {s: 6}, 12958, 0, 8252, {s: 11}, 9702, {s: 3}, michael@0: 9663, 9653, 9657, 9667, {s: 4}, 9674, 12849, 12857, 13259, {f: 5, c: 9327}, michael@0: {s: 18}, 8656, 8655, 8653, {s: 37}, 8657, 8659, {s: 8}, 8626, 8625, 0, michael@0: 8628, 8624, 8627, {s: 14}, 8636, 8640, {s: 10}, {f: 2, c: 8644}, {s: 144}, michael@0: {f: 5, c: 9347}, {s: 33}, 12948, {s: 15}, 12965, {s: 93}, 8672, 8674, 8673, michael@0: 8675, {s: 4}, 8678, 8680, 8679, 8681, {s: 20}, 9757, 9759, {s: 76}, 12944, michael@0: {f: 6, c: 12938}, {s: 15}, {f: 2, c: 12318}, 8246, 0, 8245, {s: 3}, 12540, michael@0: 0, 0, {f: 2, c: 44034}, {f: 2, c: 44037}, {f: 5, c: 44043}, 44056, michael@0: {f: 2, c: 44062}, {f: 3, c: 44065}, {f: 7, c: 44069}, 44078, michael@0: {f: 6, c: 44082}, {f: 2, c: 44090}, {f: 3, c: 44093}, {f: 10, c: 44097}, michael@0: 44108, {f: 6, c: 44110}, {f: 3, c: 44117}, {f: 3, c: 44121}, michael@0: {f: 19, c: 44125}, {f: 2, c: 44146}, {f: 2, c: 44149}, 44153, michael@0: {f: 5, c: 44155}, 44162, {f: 2, c: 44167}, {f: 3, c: 44173}, michael@0: {f: 3, c: 44177}, {f: 7, c: 44181}, 44190, {f: 6, c: 44194}, 44203, michael@0: {f: 2, c: 44205}, {f: 7, c: 44209}, 44218, {f: 3, c: 44222}, michael@0: {f: 2, c: 44226}, {f: 3, c: 44229}, {f: 3, c: 44233}, {f: 8, c: 44237}, michael@0: 44246, {f: 8, c: 44248}, {f: 2, c: 44258}, {f: 2, c: 44261}, 44265, 44267, michael@0: {f: 2, c: 44269}, 44274, 44276, {f: 5, c: 44279}, {f: 2, c: 44286}, michael@0: {f: 3, c: 44289}, 44293, {f: 5, c: 44295}, 44302, 44304, {f: 6, c: 44306}, michael@0: {f: 3, c: 44313}, {f: 3, c: 44317}, {f: 8, c: 44321}, {f: 2, c: 44330}, michael@0: {f: 6, c: 44334}, {f: 2, c: 44342}, {f: 3, c: 44345}, {f: 7, c: 44349}, michael@0: 44358, 44360, {f: 6, c: 44362}, {f: 3, c: 44369}, {f: 3, c: 44373}, michael@0: {f: 8, c: 44377}, 44386, {f: 8, c: 44388}, {f: 2, c: 44398}, michael@0: {f: 2, c: 44401}, {f: 4, c: 44407}, 44414, 44416, {f: 5, c: 44419}, michael@0: {f: 2, c: 44426}, {f: 3, c: 44429}, {f: 11, c: 44433}, {f: 6, c: 44446}, michael@0: {f: 18, c: 44453}, {f: 8, c: 44472}, {f: 2, c: 44482}, {f: 3, c: 44485}, michael@0: {f: 7, c: 44489}, 44498, {f: 8, c: 44500}, {f: 3, c: 44509}, michael@0: {f: 3, c: 44513}, {f: 19, c: 44517}, {f: 2, c: 44538}, {f: 2, c: 44541}, michael@0: {f: 6, c: 44546}, 44554, 44556, {f: 6, c: 44558}, {f: 27, c: 44565}, michael@0: {f: 2, c: 44594}, {f: 2, c: 44597}, 44601, {f: 5, c: 44603}, 44610, 44612, michael@0: {f: 3, c: 44615}, 44619, 44623, {f: 3, c: 44625}, 44629, {f: 5, c: 44631}, michael@0: 44638, {f: 3, c: 44642}, {f: 2, c: 44646}, {f: 2, c: 44650}, michael@0: {f: 3, c: 44653}, {f: 7, c: 44657}, 44666, {f: 6, c: 44670}, michael@0: {f: 6, c: 44678}, {f: 47, c: 44685}, 44735, {f: 3, c: 44737}, michael@0: {f: 7, c: 44741}, 44750, {f: 6, c: 44754}, {f: 2, c: 44762}, michael@0: {f: 11, c: 44765}, {f: 2, c: 44777}, 44780, {f: 6, c: 44782}, michael@0: {f: 3, c: 44789}, {f: 3, c: 44793}, {f: 10, c: 44797}, {f: 4, c: 44809}, michael@0: {f: 2, c: 44814}, {f: 27, c: 44817}, {f: 2, c: 44846}, 44849, 44851, michael@0: {f: 7, c: 44853}, 44862, 44864, {f: 4, c: 44868}, {f: 6, c: 44874}, michael@0: {f: 11, c: 44881}, {f: 6, c: 44894}, {f: 19, c: 44902}, {f: 6, c: 44922}, michael@0: {f: 3, c: 44929}, {f: 3, c: 44933}, {f: 7, c: 44937}, {f: 3, c: 44946}, michael@0: {f: 6, c: 44950}, {f: 27, c: 44957}, {f: 2, c: 44986}, {f: 3, c: 44989}, michael@0: {f: 6, c: 44993}, 45002, 45004, {f: 5, c: 45007}, {f: 7, c: 45013}, michael@0: {f: 11, c: 45021}, {f: 6, c: 45034}, {f: 2, c: 45042}, {f: 3, c: 45045}, michael@0: {f: 7, c: 45049}, {f: 2, c: 45058}, {f: 7, c: 45061}, {f: 3, c: 45069}, michael@0: {f: 3, c: 45073}, {f: 7, c: 45077}, {f: 10, c: 45086}, {f: 27, c: 45097}, michael@0: {f: 2, c: 45126}, 45129, 45131, 45133, {f: 4, c: 45135}, 45142, 45144, michael@0: {f: 3, c: 45146}, {f: 30, c: 45150}, {f: 2, c: 45182}, {f: 3, c: 45185}, michael@0: {f: 7, c: 45189}, 45198, 45200, {f: 6, c: 45202}, 45211, {f: 2, c: 45213}, michael@0: {f: 5, c: 45219}, 45226, 45232, 45234, {f: 2, c: 45238}, {f: 3, c: 45241}, michael@0: {f: 7, c: 45245}, 45254, {f: 6, c: 45258}, {f: 2, c: 45266}, michael@0: {f: 3, c: 45269}, {f: 7, c: 45273}, {f: 4, c: 45281}, {f: 34, c: 45286}, michael@0: 45322, {f: 3, c: 45325}, 45329, {f: 4, c: 45332}, 45338, {f: 5, c: 45342}, michael@0: {f: 2, c: 45350}, {f: 3, c: 45353}, {f: 7, c: 45357}, 45366, michael@0: {f: 6, c: 45370}, {f: 2, c: 45378}, {f: 3, c: 45381}, {f: 7, c: 45385}, michael@0: {f: 2, c: 45394}, {f: 2, c: 45398}, {f: 3, c: 45401}, {f: 3, c: 45405}, michael@0: {f: 23, c: 45409}, {f: 2, c: 45434}, {f: 3, c: 45437}, 45441, michael@0: {f: 5, c: 45443}, 45450, 45452, {f: 4, c: 45454}, {f: 3, c: 45461}, michael@0: {f: 3, c: 45465}, {f: 11, c: 45469}, {f: 35, c: 45481}, {f: 3, c: 45517}, michael@0: {f: 3, c: 45521}, {f: 7, c: 45525}, 45534, {f: 8, c: 45536}, michael@0: {f: 2, c: 45546}, {f: 3, c: 45549}, {f: 8, c: 45553}, 45562, 45564, michael@0: {f: 6, c: 45566}, {f: 2, c: 45574}, {f: 2, c: 45577}, {f: 7, c: 45581}, michael@0: 45590, 45592, {f: 6, c: 45594}, {f: 19, c: 45601}, {f: 7, c: 45621}, michael@0: {f: 27, c: 45629}, {f: 3, c: 45657}, {f: 3, c: 45661}, {f: 7, c: 45665}, michael@0: {f: 10, c: 45674}, {f: 6, c: 45686}, {f: 7, c: 45693}, {f: 3, c: 45702}, michael@0: {f: 6, c: 45706}, {f: 2, c: 45714}, {f: 3, c: 45717}, {f: 5, c: 45723}, michael@0: 45730, 45732, {f: 3, c: 45735}, 45739, {f: 3, c: 45741}, {f: 3, c: 45745}, michael@0: {f: 19, c: 45749}, {f: 2, c: 45770}, {f: 3, c: 45773}, 45777, michael@0: {f: 5, c: 45779}, 45786, 45788, {f: 4, c: 45790}, 45795, 45799, michael@0: {f: 2, c: 45801}, {f: 3, c: 45808}, 45814, {f: 3, c: 45820}, michael@0: {f: 2, c: 45826}, {f: 3, c: 45829}, {f: 7, c: 45833}, 45842, michael@0: {f: 6, c: 45846}, {f: 55, c: 45853}, 45911, {f: 2, c: 45913}, 45917, michael@0: {f: 4, c: 45920}, 45926, 45928, 45930, {f: 2, c: 45932}, 45935, michael@0: {f: 2, c: 45938}, {f: 3, c: 45941}, {f: 7, c: 45945}, 45954, michael@0: {f: 6, c: 45958}, {f: 3, c: 45965}, {f: 3, c: 45969}, {f: 11, c: 45973}, michael@0: {f: 6, c: 45986}, {f: 3, c: 45993}, {f: 23, c: 45997}, {f: 2, c: 46022}, michael@0: {f: 2, c: 46025}, 46029, 46031, {f: 3, c: 46033}, 46038, 46040, 46042, michael@0: 46044, {f: 2, c: 46046}, {f: 3, c: 46049}, {f: 3, c: 46053}, michael@0: {f: 19, c: 46057}, {f: 19, c: 46077}, {f: 7, c: 46097}, {f: 3, c: 46105}, michael@0: {f: 3, c: 46109}, {f: 7, c: 46113}, 46122, {f: 8, c: 46124}, michael@0: {f: 27, c: 46133}, {f: 2, c: 46162}, {f: 3, c: 46165}, {f: 7, c: 46169}, michael@0: 46178, 46180, {f: 6, c: 46182}, {f: 19, c: 46189}, {f: 7, c: 46209}, michael@0: {f: 20, c: 46217}, {f: 6, c: 46238}, {f: 3, c: 46245}, {f: 3, c: 46249}, michael@0: {f: 8, c: 46253}, 46262, 46264, {f: 6, c: 46266}, {f: 3, c: 46273}, michael@0: {f: 3, c: 46277}, {f: 7, c: 46281}, {f: 4, c: 46289}, {f: 6, c: 46294}, michael@0: {f: 2, c: 46302}, {f: 2, c: 46305}, 46309, {f: 5, c: 46311}, 46318, 46320, michael@0: {f: 6, c: 46322}, {f: 27, c: 46329}, {f: 2, c: 46358}, {f: 2, c: 46361}, michael@0: {f: 7, c: 46365}, 46374, {f: 5, c: 46379}, {f: 2, c: 46386}, michael@0: {f: 3, c: 46389}, {f: 7, c: 46393}, 46402, {f: 5, c: 46406}, michael@0: {f: 2, c: 46414}, {f: 3, c: 46417}, {f: 7, c: 46421}, 46430, michael@0: {f: 62, c: 46434}, {f: 2, c: 46498}, {f: 3, c: 46501}, 46505, michael@0: {f: 4, c: 46508}, 46514, {f: 5, c: 46518}, {f: 2, c: 46526}, michael@0: {f: 3, c: 46529}, {f: 7, c: 46533}, 46542, {f: 6, c: 46546}, michael@0: {f: 19, c: 46553}, {f: 35, c: 46573}, {f: 2, c: 46610}, {f: 3, c: 46613}, michael@0: {f: 12, c: 46617}, {f: 6, c: 46630}, {f: 7, c: 46637}, {f: 19, c: 46645}, michael@0: {f: 27, c: 46665}, {f: 3, c: 46693}, {f: 51, c: 46697}, {f: 2, c: 46750}, michael@0: {f: 3, c: 46753}, {f: 6, c: 46757}, {f: 4, c: 46765}, {f: 34, c: 46770}, michael@0: {f: 27, c: 46805}, {f: 3, c: 46833}, {f: 3, c: 46837}, {f: 7, c: 46841}, michael@0: {f: 3, c: 46850}, {f: 34, c: 46854}, {f: 2, c: 46890}, {f: 2, c: 46893}, michael@0: {f: 7, c: 46897}, 46906, {f: 8, c: 46908}, {f: 3, c: 46917}, michael@0: {f: 3, c: 46921}, {f: 7, c: 46925}, {f: 10, c: 46934}, {f: 3, c: 46945}, michael@0: {f: 3, c: 46949}, {f: 7, c: 46953}, 46962, 46964, {f: 6, c: 46966}, michael@0: {f: 2, c: 46974}, {f: 3, c: 46977}, {f: 7, c: 46981}, 46990, michael@0: {f: 3, c: 46995}, {f: 2, c: 47002}, {f: 3, c: 47005}, {f: 7, c: 47009}, michael@0: 47018, {f: 6, c: 47022}, {f: 2, c: 47030}, {f: 14, c: 47033}, 47048, michael@0: {f: 34, c: 47050}, {f: 2, c: 47086}, {f: 3, c: 47089}, {f: 7, c: 47093}, michael@0: 47102, {f: 5, c: 47106}, {f: 2, c: 47114}, {f: 3, c: 47117}, michael@0: {f: 7, c: 47121}, 47130, 47132, {f: 6, c: 47134}, {f: 2, c: 47142}, michael@0: {f: 3, c: 47145}, {f: 7, c: 47149}, 47158, {f: 6, c: 47162}, michael@0: {f: 3, c: 47169}, {f: 12, c: 47173}, 47186, {f: 8, c: 47188}, michael@0: {f: 2, c: 47198}, {f: 3, c: 47201}, {f: 7, c: 47205}, 47214, 47216, michael@0: {f: 6, c: 47218}, {f: 3, c: 47225}, {f: 16, c: 47229}, {f: 26, c: 47246}, michael@0: {f: 7, c: 47273}, {f: 3, c: 47281}, {f: 3, c: 47285}, {f: 7, c: 47289}, michael@0: 47298, 47300, {f: 6, c: 47302}, {f: 3, c: 47309}, {f: 3, c: 47313}, michael@0: {f: 8, c: 47317}, 47326, 47328, {f: 6, c: 47330}, {f: 2, c: 47338}, michael@0: {f: 3, c: 47341}, {f: 7, c: 47345}, 47354, 47356, {f: 6, c: 47358}, michael@0: {f: 19, c: 47365}, {f: 7, c: 47385}, {f: 27, c: 47393}, {f: 2, c: 47422}, michael@0: {f: 3, c: 47425}, {f: 7, c: 47429}, {f: 2, c: 47437}, 47440, michael@0: {f: 6, c: 47442}, {f: 2, c: 47450}, {f: 3, c: 47453}, {f: 7, c: 47457}, michael@0: 47466, 47468, {f: 6, c: 47470}, {f: 2, c: 47478}, {f: 3, c: 47481}, michael@0: {f: 7, c: 47485}, 47494, 47496, {f: 2, c: 47499}, {f: 29, c: 47503}, michael@0: {f: 2, c: 47534}, {f: 3, c: 47537}, {f: 7, c: 47541}, 47550, 47552, michael@0: {f: 6, c: 47554}, {f: 2, c: 47562}, 47565, {f: 5, c: 47571}, 47578, 47580, michael@0: {f: 2, c: 47583}, 47586, {f: 2, c: 47590}, {f: 3, c: 47593}, michael@0: {f: 7, c: 47597}, 47606, {f: 5, c: 47611}, {f: 6, c: 47618}, michael@0: {f: 12, c: 47625}, {f: 34, c: 47638}, {f: 2, c: 47674}, {f: 3, c: 47677}, michael@0: 47681, {f: 5, c: 47683}, 47690, 47692, {f: 4, c: 47695}, {f: 2, c: 47702}, michael@0: {f: 3, c: 47705}, {f: 7, c: 47709}, 47718, {f: 6, c: 47722}, michael@0: {f: 2, c: 47730}, {f: 3, c: 47733}, {f: 10, c: 47737}, 47750, michael@0: {f: 4, c: 47752}, {f: 27, c: 47757}, 47786, {f: 3, c: 47789}, 47793, michael@0: {f: 5, c: 47795}, 47802, 47804, {f: 6, c: 47806}, {f: 3, c: 47813}, michael@0: {f: 15, c: 47817}, {f: 34, c: 47834}, {f: 3, c: 47869}, {f: 3, c: 47873}, michael@0: {f: 8, c: 47877}, 47886, 47888, {f: 6, c: 47890}, {f: 3, c: 47897}, michael@0: {f: 3, c: 47901}, {f: 8, c: 47905}, 47914, {f: 8, c: 47916}, 47927, michael@0: {f: 2, c: 47929}, {f: 5, c: 47935}, 47942, 47944, {f: 3, c: 47946}, 47950, michael@0: {f: 3, c: 47953}, {f: 3, c: 47957}, {f: 8, c: 47961}, 47970, michael@0: {f: 8, c: 47972}, {f: 27, c: 47981}, {f: 3, c: 48009}, {f: 3, c: 48013}, michael@0: {f: 19, c: 48017}, {f: 3, c: 48037}, {f: 3, c: 48041}, {f: 7, c: 48045}, michael@0: {f: 2, c: 48053}, {f: 8, c: 48056}, {f: 3, c: 48065}, {f: 3, c: 48069}, michael@0: {f: 7, c: 48073}, {f: 2, c: 48081}, {f: 36, c: 48084}, {f: 2, c: 48122}, michael@0: {f: 2, c: 48125}, 48129, {f: 5, c: 48131}, 48138, 48142, 48144, michael@0: {f: 2, c: 48146}, {f: 2, c: 48153}, {f: 4, c: 48160}, 48166, 48168, michael@0: {f: 3, c: 48170}, {f: 2, c: 48174}, {f: 2, c: 48178}, {f: 3, c: 48181}, michael@0: {f: 7, c: 48185}, 48194, {f: 3, c: 48198}, {f: 2, c: 48202}, michael@0: {f: 2, c: 48206}, {f: 12, c: 48209}, {f: 38, c: 48222}, {f: 2, c: 48262}, michael@0: {f: 2, c: 48265}, 48269, {f: 5, c: 48271}, 48278, 48280, {f: 5, c: 48283}, michael@0: {f: 2, c: 48290}, {f: 2, c: 48293}, {f: 7, c: 48297}, 48306, michael@0: {f: 6, c: 48310}, {f: 2, c: 48318}, {f: 3, c: 48321}, {f: 8, c: 48325}, michael@0: 48334, {f: 3, c: 48338}, {f: 2, c: 48342}, {f: 3, c: 48345}, michael@0: {f: 23, c: 48349}, 48375, {f: 3, c: 48377}, {f: 7, c: 48381}, 48390, 48392, michael@0: {f: 6, c: 48394}, {f: 3, c: 48401}, {f: 15, c: 48405}, {f: 7, c: 48421}, michael@0: {f: 19, c: 48429}, {f: 7, c: 48449}, {f: 2, c: 48458}, {f: 3, c: 48461}, michael@0: {f: 7, c: 48465}, {f: 10, c: 48474}, {f: 3, c: 48485}, {f: 23, c: 48489}, michael@0: {f: 2, c: 48514}, {f: 2, c: 48517}, {f: 5, c: 48523}, 48530, 48532, michael@0: {f: 3, c: 48534}, 48539, {f: 7, c: 48541}, {f: 11, c: 48549}, michael@0: {f: 7, c: 48561}, {f: 27, c: 48569}, {f: 2, c: 48598}, {f: 3, c: 48601}, michael@0: {f: 12, c: 48605}, {f: 6, c: 48618}, {f: 3, c: 48625}, {f: 3, c: 48629}, michael@0: {f: 7, c: 48633}, {f: 2, c: 48641}, 48644, {f: 6, c: 48646}, michael@0: {f: 2, c: 48654}, {f: 3, c: 48657}, {f: 7, c: 48661}, 48670, michael@0: {f: 36, c: 48672}, {f: 2, c: 48710}, {f: 3, c: 48713}, 48717, michael@0: {f: 5, c: 48719}, 48726, 48728, {f: 4, c: 48732}, {f: 2, c: 48738}, michael@0: {f: 3, c: 48741}, 48745, {f: 5, c: 48747}, 48754, {f: 5, c: 48758}, michael@0: {f: 2, c: 48766}, {f: 3, c: 48769}, {f: 7, c: 48773}, 48782, michael@0: {f: 6, c: 48786}, {f: 14, c: 48794}, {f: 39, c: 48809}, {f: 2, c: 48850}, michael@0: {f: 2, c: 48853}, {f: 7, c: 48857}, {f: 2, c: 48865}, {f: 6, c: 48870}, michael@0: {f: 20, c: 48877}, {f: 6, c: 48898}, {f: 14, c: 48906}, 48922, michael@0: {f: 34, c: 48926}, {f: 2, c: 48962}, {f: 3, c: 48965}, {f: 7, c: 48969}, michael@0: {f: 3, c: 48978}, {f: 62, c: 48982}, {f: 27, c: 49045}, {f: 20, c: 49073}, michael@0: {f: 6, c: 49094}, {f: 2, c: 49102}, {f: 3, c: 49105}, {f: 7, c: 49109}, michael@0: {f: 2, c: 49117}, 49120, {f: 90, c: 49122}, {f: 20, c: 49213}, michael@0: {f: 6, c: 49234}, {f: 3, c: 49241}, {f: 3, c: 49245}, {f: 7, c: 49249}, michael@0: {f: 38, c: 49258}, {f: 2, c: 49298}, {f: 3, c: 49301}, {f: 7, c: 49305}, michael@0: 49314, 49316, {f: 6, c: 49318}, 49326, {f: 2, c: 49329}, {f: 5, c: 49335}, michael@0: 49342, {f: 3, c: 49346}, {f: 2, c: 49350}, {f: 2, c: 49354}, michael@0: {f: 3, c: 49357}, {f: 7, c: 49361}, 49370, {f: 6, c: 49374}, michael@0: {f: 2, c: 49382}, {f: 3, c: 49385}, {f: 7, c: 49389}, 49398, 49400, michael@0: {f: 6, c: 49402}, {f: 3, c: 49409}, {f: 3, c: 49413}, {f: 7, c: 49417}, michael@0: {f: 4, c: 49425}, {f: 6, c: 49430}, {f: 2, c: 49441}, 49445, michael@0: {f: 4, c: 49448}, 49454, {f: 4, c: 49458}, 49463, {f: 2, c: 49466}, michael@0: {f: 3, c: 49469}, {f: 7, c: 49473}, 49482, {f: 6, c: 49486}, michael@0: {f: 2, c: 49494}, {f: 3, c: 49497}, {f: 7, c: 49501}, 49510, michael@0: {f: 6, c: 49514}, {f: 3, c: 49521}, {f: 3, c: 49525}, {f: 12, c: 49529}, michael@0: {f: 6, c: 49542}, 49551, {f: 3, c: 49553}, 49557, {f: 5, c: 49559}, 49566, michael@0: 49568, {f: 3, c: 49570}, {f: 2, c: 49574}, {f: 2, c: 49578}, michael@0: {f: 3, c: 49581}, {f: 12, c: 49585}, {f: 6, c: 49598}, {f: 3, c: 49605}, michael@0: {f: 3, c: 49609}, {f: 7, c: 49613}, {f: 2, c: 49621}, {f: 7, c: 49625}, michael@0: {f: 3, c: 49633}, {f: 3, c: 49637}, {f: 7, c: 49641}, 49650, michael@0: {f: 8, c: 49652}, {f: 2, c: 49662}, {f: 3, c: 49665}, {f: 7, c: 49669}, michael@0: 49678, 49680, {f: 6, c: 49682}, {f: 2, c: 49690}, {f: 2, c: 49693}, michael@0: {f: 7, c: 49697}, 49706, 49708, 49710, 49712, 49715, {f: 19, c: 49717}, michael@0: {f: 7, c: 49737}, {f: 2, c: 49746}, {f: 3, c: 49749}, {f: 7, c: 49753}, michael@0: {f: 4, c: 49761}, {f: 6, c: 49766}, {f: 2, c: 49774}, {f: 3, c: 49777}, michael@0: {f: 7, c: 49781}, 49790, 49792, {f: 6, c: 49794}, {f: 6, c: 49802}, michael@0: {f: 7, c: 49809}, {f: 2, c: 49817}, 49820, {f: 6, c: 49822}, michael@0: {f: 2, c: 49830}, {f: 3, c: 49833}, {f: 6, c: 49838}, 49846, 49848, michael@0: {f: 34, c: 49850}, {f: 2, c: 49886}, {f: 2, c: 49889}, {f: 6, c: 49893}, michael@0: 49902, 49904, {f: 4, c: 49906}, 49911, 49914, {f: 3, c: 49917}, michael@0: {f: 7, c: 49921}, {f: 2, c: 49930}, {f: 5, c: 49934}, {f: 2, c: 49942}, michael@0: {f: 3, c: 49945}, {f: 7, c: 49949}, {f: 2, c: 49958}, {f: 27, c: 49962}, michael@0: {f: 34, c: 49990}, {f: 2, c: 50026}, {f: 3, c: 50029}, 50033, michael@0: {f: 5, c: 50035}, {f: 2, c: 50042}, {f: 6, c: 50046}, {f: 3, c: 50053}, michael@0: {f: 3, c: 50057}, {f: 51, c: 50061}, {f: 23, c: 50113}, {f: 2, c: 50138}, michael@0: {f: 2, c: 50141}, 50145, {f: 5, c: 50147}, {f: 3, c: 50154}, michael@0: {f: 6, c: 50158}, {f: 2, c: 50166}, {f: 15, c: 50169}, {f: 7, c: 50185}, michael@0: {f: 19, c: 50193}, {f: 7, c: 50213}, {f: 3, c: 50221}, {f: 3, c: 50225}, michael@0: {f: 7, c: 50229}, {f: 10, c: 50238}, {f: 27, c: 50249}, {f: 2, c: 50278}, michael@0: {f: 3, c: 50281}, {f: 7, c: 50285}, {f: 3, c: 50294}, {f: 6, c: 50298}, michael@0: {f: 19, c: 50305}, {f: 7, c: 50325}, {f: 27, c: 50333}, {f: 3, c: 50361}, michael@0: {f: 44, c: 50365}, {f: 6, c: 50410}, {f: 2, c: 50418}, {f: 3, c: 50421}, michael@0: 50425, {f: 4, c: 50427}, {f: 10, c: 50434}, {f: 3, c: 50445}, michael@0: {f: 3, c: 50449}, {f: 7, c: 50453}, {f: 11, c: 50461}, {f: 2, c: 50474}, michael@0: {f: 3, c: 50477}, {f: 7, c: 50481}, 50490, 50492, {f: 6, c: 50494}, michael@0: {f: 2, c: 50502}, 50507, {f: 4, c: 50511}, 50518, {f: 3, c: 50522}, 50527, michael@0: {f: 2, c: 50530}, {f: 3, c: 50533}, {f: 7, c: 50537}, 50546, michael@0: {f: 6, c: 50550}, {f: 2, c: 50558}, {f: 3, c: 50561}, {f: 2, c: 50565}, michael@0: {f: 4, c: 50568}, 50574, 50576, {f: 3, c: 50578}, 50582, {f: 3, c: 50585}, michael@0: {f: 3, c: 50589}, {f: 8, c: 50593}, {f: 10, c: 50602}, {f: 2, c: 50614}, michael@0: 50618, {f: 5, c: 50623}, 50635, 50637, 50639, {f: 2, c: 50642}, michael@0: {f: 3, c: 50645}, {f: 7, c: 50649}, 50658, 50660, {f: 6, c: 50662}, 50671, michael@0: {f: 3, c: 50673}, 50677, {f: 4, c: 50680}, {f: 3, c: 50690}, michael@0: {f: 3, c: 50697}, {f: 3, c: 50701}, {f: 7, c: 50705}, 50714, michael@0: {f: 7, c: 50717}, {f: 2, c: 50726}, {f: 3, c: 50729}, 50735, michael@0: {f: 2, c: 50737}, 50742, 50744, 50746, {f: 4, c: 50748}, {f: 2, c: 50754}, michael@0: {f: 3, c: 50757}, {f: 7, c: 50761}, 50770, {f: 6, c: 50774}, michael@0: {f: 2, c: 50782}, {f: 11, c: 50785}, {f: 2, c: 50797}, 50800, michael@0: {f: 6, c: 50802}, {f: 2, c: 50810}, {f: 3, c: 50813}, {f: 7, c: 50817}, michael@0: 50826, 50828, {f: 6, c: 50830}, {f: 2, c: 50838}, {f: 3, c: 50841}, michael@0: {f: 7, c: 50845}, 50854, 50856, {f: 6, c: 50858}, {f: 2, c: 50866}, michael@0: {f: 3, c: 50869}, {f: 5, c: 50875}, 50882, 50884, {f: 6, c: 50886}, michael@0: {f: 2, c: 50894}, {f: 3, c: 50897}, {f: 7, c: 50901}, {f: 2, c: 50910}, michael@0: {f: 6, c: 50914}, {f: 2, c: 50922}, {f: 3, c: 50925}, {f: 7, c: 50929}, michael@0: {f: 3, c: 50938}, {f: 6, c: 50942}, {f: 2, c: 50950}, {f: 3, c: 50953}, michael@0: {f: 7, c: 50957}, 50966, 50968, {f: 6, c: 50970}, {f: 2, c: 50978}, michael@0: {f: 3, c: 50981}, {f: 7, c: 50985}, 50994, 50996, 50998, {f: 4, c: 51000}, michael@0: {f: 2, c: 51006}, {f: 3, c: 51009}, {f: 5, c: 51013}, 51019, 51022, 51024, michael@0: {f: 3, c: 51033}, {f: 3, c: 51037}, {f: 7, c: 51041}, {f: 2, c: 51049}, michael@0: {f: 8, c: 51052}, {f: 2, c: 51062}, {f: 3, c: 51065}, {f: 4, c: 51071}, michael@0: 51078, {f: 3, c: 51083}, 51087, {f: 2, c: 51090}, 51093, 51097, michael@0: {f: 5, c: 51099}, 51106, {f: 5, c: 51111}, {f: 2, c: 51118}, michael@0: {f: 3, c: 51121}, {f: 7, c: 51125}, 51134, {f: 6, c: 51138}, michael@0: {f: 2, c: 51146}, 51149, 51151, {f: 7, c: 51153}, {f: 4, c: 51161}, michael@0: {f: 6, c: 51166}, {f: 3, c: 51173}, {f: 3, c: 51177}, {f: 19, c: 51181}, michael@0: {f: 2, c: 51202}, {f: 3, c: 51205}, 51209, {f: 5, c: 51211}, 51218, 51220, michael@0: {f: 5, c: 51223}, {f: 2, c: 51230}, {f: 3, c: 51233}, {f: 7, c: 51237}, michael@0: 51246, 51248, {f: 6, c: 51250}, {f: 3, c: 51257}, {f: 3, c: 51261}, michael@0: {f: 7, c: 51265}, {f: 2, c: 51274}, {f: 6, c: 51278}, {f: 27, c: 51285}, michael@0: {f: 2, c: 51314}, {f: 3, c: 51317}, 51321, {f: 5, c: 51323}, 51330, 51332, michael@0: {f: 3, c: 51336}, {f: 6, c: 51342}, {f: 8, c: 51349}, 51358, 51360, michael@0: {f: 6, c: 51362}, {f: 19, c: 51369}, {f: 6, c: 51390}, {f: 3, c: 51397}, michael@0: {f: 3, c: 51401}, {f: 7, c: 51405}, 51414, 51416, {f: 6, c: 51418}, michael@0: {f: 2, c: 51426}, {f: 16, c: 51429}, {f: 6, c: 51446}, {f: 2, c: 51454}, michael@0: {f: 3, c: 51457}, {f: 5, c: 51463}, 51470, 51472, {f: 6, c: 51474}, michael@0: {f: 19, c: 51481}, {f: 7, c: 51501}, {f: 27, c: 51509}, {f: 2, c: 51538}, michael@0: {f: 3, c: 51541}, {f: 7, c: 51545}, 51554, {f: 8, c: 51556}, michael@0: {f: 3, c: 51565}, {f: 3, c: 51569}, {f: 7, c: 51573}, {f: 11, c: 51581}, michael@0: {f: 2, c: 51594}, {f: 3, c: 51597}, {f: 7, c: 51601}, 51610, 51612, michael@0: {f: 34, c: 51614}, {f: 2, c: 51650}, {f: 2, c: 51653}, 51657, michael@0: {f: 5, c: 51659}, 51666, 51668, {f: 2, c: 51671}, 51675, {f: 2, c: 51678}, michael@0: 51681, 51683, {f: 2, c: 51685}, {f: 4, c: 51688}, 51694, {f: 6, c: 51698}, michael@0: {f: 2, c: 51706}, {f: 3, c: 51709}, {f: 7, c: 51713}, 51722, michael@0: {f: 6, c: 51726}, {f: 3, c: 51733}, {f: 16, c: 51737}, {f: 34, c: 51754}, michael@0: {f: 2, c: 51790}, {f: 3, c: 51793}, {f: 7, c: 51797}, 51806, michael@0: {f: 6, c: 51810}, {f: 20, c: 51817}, {f: 6, c: 51838}, {f: 19, c: 51845}, michael@0: {f: 35, c: 51865}, {f: 2, c: 51902}, {f: 3, c: 51905}, {f: 7, c: 51909}, michael@0: 51918, 51920, 51922, {f: 4, c: 51924}, {f: 6, c: 51930}, {f: 11, c: 51937}, michael@0: {f: 7, c: 51949}, {f: 19, c: 51957}, {f: 7, c: 51977}, {f: 3, c: 51985}, michael@0: {f: 3, c: 51989}, {f: 7, c: 51993}, {f: 31, c: 52002}, {f: 6, c: 52034}, michael@0: {f: 2, c: 52042}, {f: 3, c: 52045}, {f: 7, c: 52049}, {f: 3, c: 52058}, michael@0: {f: 6, c: 52062}, {f: 19, c: 52069}, {f: 34, c: 52090}, {f: 27, c: 52125}, michael@0: {f: 27, c: 52153}, {f: 15, c: 52181}, {f: 2, c: 52197}, 52200, michael@0: {f: 34, c: 52202}, {f: 2, c: 52238}, {f: 3, c: 52241}, {f: 7, c: 52245}, michael@0: {f: 3, c: 52254}, {f: 4, c: 52259}, {f: 2, c: 52266}, 52269, 52271, michael@0: {f: 7, c: 52273}, 52282, {f: 5, c: 52287}, {f: 2, c: 52294}, michael@0: {f: 3, c: 52297}, {f: 7, c: 52301}, 52310, {f: 6, c: 52314}, michael@0: {f: 3, c: 52321}, 52325, 52327, {f: 7, c: 52329}, {f: 4, c: 52337}, michael@0: {f: 34, c: 52342}, {f: 2, c: 52378}, {f: 3, c: 52381}, {f: 7, c: 52385}, michael@0: 52394, {f: 6, c: 52398}, {f: 2, c: 52406}, {f: 3, c: 52409}, michael@0: {f: 7, c: 52413}, 52422, 52424, {f: 6, c: 52426}, {f: 3, c: 52433}, michael@0: {f: 15, c: 52437}, {f: 7, c: 52453}, {f: 3, c: 52461}, {f: 16, c: 52465}, michael@0: {f: 6, c: 52482}, {f: 2, c: 52490}, {f: 3, c: 52493}, {f: 7, c: 52497}, michael@0: 52506, 52508, {f: 6, c: 52510}, {f: 3, c: 52517}, {f: 3, c: 52521}, michael@0: {f: 12, c: 52525}, {f: 34, c: 52538}, {f: 3, c: 52573}, {f: 3, c: 52577}, michael@0: {f: 7, c: 52581}, 52590, 52592, {f: 6, c: 52594}, {f: 15, c: 52601}, michael@0: {f: 11, c: 52617}, {f: 2, c: 52630}, {f: 3, c: 52633}, {f: 7, c: 52637}, michael@0: 52646, 52648, {f: 6, c: 52650}, {f: 19, c: 52657}, {f: 7, c: 52677}, michael@0: {f: 3, c: 52685}, {f: 23, c: 52689}, {f: 3, c: 52713}, {f: 3, c: 52717}, michael@0: {f: 7, c: 52721}, 52730, 52732, {f: 6, c: 52734}, {f: 3, c: 52741}, michael@0: {f: 3, c: 52745}, {f: 7, c: 52749}, {f: 4, c: 52757}, {f: 6, c: 52762}, michael@0: {f: 2, c: 52770}, {f: 3, c: 52773}, {f: 7, c: 52777}, 52786, 52788, michael@0: {f: 34, c: 52790}, {f: 2, c: 52826}, {f: 2, c: 52829}, {f: 6, c: 52834}, michael@0: 52842, 52844, {f: 6, c: 52846}, {f: 2, c: 52854}, {f: 3, c: 52857}, michael@0: {f: 7, c: 52861}, 52870, 52872, {f: 6, c: 52874}, {f: 2, c: 52882}, michael@0: {f: 3, c: 52885}, {f: 7, c: 52889}, 52898, {f: 6, c: 52902}, michael@0: {f: 19, c: 52910}, {f: 34, c: 52930}, {f: 2, c: 52966}, {f: 2, c: 52969}, michael@0: {f: 7, c: 52973}, 52982, {f: 6, c: 52986}, {f: 2, c: 52994}, michael@0: {f: 3, c: 52997}, {f: 7, c: 53001}, 53010, 53012, {f: 6, c: 53014}, michael@0: {f: 3, c: 53021}, {f: 3, c: 53025}, {f: 7, c: 53029}, 53038, michael@0: {f: 6, c: 53042}, {f: 27, c: 53049}, {f: 2, c: 53078}, {f: 3, c: 53081}, michael@0: {f: 7, c: 53085}, 53094, 53096, {f: 6, c: 53098}, {f: 2, c: 53106}, michael@0: {f: 3, c: 53109}, {f: 7, c: 53113}, {f: 4, c: 53121}, {f: 6, c: 53126}, michael@0: {f: 20, c: 53133}, {f: 6, c: 53154}, {f: 7, c: 53161}, {f: 19, c: 53169}, michael@0: {f: 27, c: 53189}, {f: 2, c: 53218}, {f: 3, c: 53221}, {f: 7, c: 53225}, michael@0: 53234, 53236, {f: 6, c: 53238}, {f: 3, c: 53245}, {f: 3, c: 53249}, michael@0: {f: 12, c: 53253}, {f: 6, c: 53266}, {f: 20, c: 53273}, {f: 6, c: 53294}, michael@0: {f: 2, c: 53302}, {f: 3, c: 53305}, {f: 7, c: 53309}, 53318, 53320, michael@0: {f: 6, c: 53322}, {f: 3, c: 53329}, {f: 3, c: 53333}, {f: 7, c: 53337}, michael@0: {f: 11, c: 53345}, {f: 2, c: 53358}, {f: 3, c: 53361}, {f: 7, c: 53365}, michael@0: {f: 3, c: 53374}, {f: 34, c: 53378}, {f: 2, c: 53414}, {f: 3, c: 53417}, michael@0: {f: 7, c: 53421}, 53430, 53432, {f: 6, c: 53434}, {f: 2, c: 53442}, michael@0: {f: 3, c: 53445}, {f: 6, c: 53450}, 53458, {f: 6, c: 53462}, michael@0: {f: 2, c: 53470}, {f: 3, c: 53473}, {f: 7, c: 53477}, 53486, michael@0: {f: 6, c: 53490}, {f: 20, c: 53497}, {f: 34, c: 53518}, {f: 2, c: 53554}, michael@0: {f: 3, c: 53557}, 53561, {f: 5, c: 53563}, 53570, {f: 6, c: 53574}, michael@0: {f: 2, c: 53582}, {f: 3, c: 53585}, {f: 7, c: 53589}, 53598, 53600, michael@0: {f: 6, c: 53602}, {f: 3, c: 53609}, {f: 15, c: 53613}, {f: 7, c: 53629}, michael@0: {f: 3, c: 53637}, {f: 23, c: 53641}, {f: 2, c: 53666}, {f: 3, c: 53669}, michael@0: {f: 7, c: 53673}, 53682, 53684, {f: 4, c: 53686}, 53691, {f: 3, c: 53693}, michael@0: {f: 23, c: 53697}, {f: 27, c: 53721}, {f: 3, c: 53749}, {f: 14, c: 53753}, michael@0: 53768, {f: 6, c: 53770}, {f: 27, c: 53777}, {f: 2, c: 53806}, michael@0: {f: 3, c: 53809}, {f: 7, c: 53813}, 53822, 53824, {f: 6, c: 53826}, michael@0: {f: 19, c: 53833}, {f: 7, c: 53853}, {f: 27, c: 53861}, {f: 2, c: 53890}, michael@0: {f: 3, c: 53893}, {f: 7, c: 53897}, {f: 3, c: 53906}, {f: 6, c: 53910}, michael@0: {f: 3, c: 53917}, {f: 3, c: 53921}, {f: 7, c: 53925}, {f: 4, c: 53933}, michael@0: {f: 6, c: 53938}, {f: 2, c: 53946}, {f: 2, c: 53949}, 53953, michael@0: {f: 5, c: 53955}, 53962, {f: 8, c: 53964}, {f: 3, c: 53973}, michael@0: {f: 3, c: 53977}, {f: 7, c: 53981}, {f: 10, c: 53990}, {f: 2, c: 54002}, michael@0: {f: 3, c: 54005}, {f: 7, c: 54009}, 54018, 54020, {f: 6, c: 54022}, 54031, michael@0: {f: 3, c: 54033}, 54037, {f: 5, c: 54039}, 54046, {f: 3, c: 54050}, michael@0: {f: 2, c: 54054}, {f: 2, c: 54058}, {f: 3, c: 54061}, {f: 7, c: 54065}, michael@0: 54074, {f: 6, c: 54078}, {f: 54, c: 54086}, {f: 2, c: 54142}, michael@0: {f: 3, c: 54145}, {f: 7, c: 54149}, 54158, {f: 6, c: 54162}, michael@0: {f: 2, c: 54170}, {f: 3, c: 54173}, {f: 7, c: 54177}, 54186, 54188, michael@0: {f: 6, c: 54190}, {f: 3, c: 54197}, {f: 3, c: 54201}, {f: 7, c: 54205}, michael@0: {f: 2, c: 54214}, {f: 6, c: 54218}, {f: 7, c: 54225}, {f: 8, c: 54233}, michael@0: 54242, {f: 8, c: 54244}, {f: 2, c: 54254}, {f: 3, c: 54257}, michael@0: {f: 7, c: 54261}, 54270, 54272, {f: 6, c: 54274}, {f: 20, c: 54281}, michael@0: {f: 34, c: 54302}, {f: 3, c: 54337}, {f: 23, c: 54341}, {f: 3, c: 54365}, michael@0: {f: 3, c: 54369}, {f: 8, c: 54373}, 54382, {f: 8, c: 54384}, michael@0: {f: 2, c: 54394}, {f: 2, c: 54397}, 54401, {f: 5, c: 54403}, 54410, 54412, michael@0: {f: 6, c: 54414}, {f: 20, c: 54421}, {f: 34, c: 54442}, {f: 3, c: 54477}, michael@0: {f: 3, c: 54481}, {f: 7, c: 54485}, {f: 2, c: 54493}, {f: 8, c: 54496}, michael@0: {f: 3, c: 54505}, {f: 3, c: 54509}, {f: 7, c: 54513}, {f: 2, c: 54521}, michael@0: 54524, {f: 6, c: 54526}, {f: 3, c: 54533}, {f: 3, c: 54537}, michael@0: {f: 7, c: 54541}, 54550, {f: 36, c: 54552}, {f: 2, c: 54590}, michael@0: {f: 3, c: 54593}, {f: 7, c: 54597}, 54606, 54608, {f: 6, c: 54610}, michael@0: {f: 2, c: 54618}, {f: 3, c: 54621}, {f: 4, c: 54625}, {f: 2, c: 54630}, michael@0: 54634, 54636, {f: 6, c: 54638}, {f: 2, c: 54646}, {f: 3, c: 54649}, michael@0: {f: 7, c: 54653}, 54662, {f: 6, c: 54666}, {f: 20, c: 54673}, michael@0: {f: 34, c: 54694}, {f: 2, c: 54730}, {f: 3, c: 54733}, 54737, michael@0: {f: 5, c: 54739}, 54746, 54748, {f: 6, c: 54750}, {f: 2, c: 54758}, michael@0: {f: 3, c: 54761}, {f: 7, c: 54765}, 54774, 54776, {f: 6, c: 54778}, michael@0: {f: 2, c: 54786}, {f: 3, c: 54789}, {f: 7, c: 54793}, 54802, michael@0: {f: 6, c: 54806}, {f: 3, c: 54813}, {f: 3, c: 54817}, {f: 8, c: 54821}, michael@0: {f: 10, c: 54830}, {f: 2, c: 54842}, {f: 3, c: 54845}, {f: 4, c: 54849}, michael@0: {f: 2, c: 54854}, 54858, 54860, {f: 3, c: 54862}, {f: 2, c: 54866}, michael@0: {f: 2, c: 54870}, {f: 3, c: 54873}, {f: 10, c: 54877}, 54888, michael@0: {f: 6, c: 54890}, {f: 2, c: 54898}, {f: 14, c: 54901}, 54916, michael@0: {f: 6, c: 54918}, {f: 2, c: 54926}, {f: 3, c: 54929}, {f: 8, c: 54933}, michael@0: 54942, 54944, {f: 6, c: 54946}, {f: 3, c: 54953}, {f: 3, c: 54957}, michael@0: {f: 8, c: 54961}, 54970, {f: 8, c: 54972}, {f: 2, c: 54982}, michael@0: {f: 3, c: 54985}, {f: 4, c: 54989}, {f: 2, c: 54994}, {f: 2, c: 54997}, michael@0: 55000, {f: 6, c: 55002}, {f: 3, c: 55009}, {f: 3, c: 55013}, michael@0: {f: 7, c: 55017}, {f: 4, c: 55025}, {f: 6, c: 55030}, {f: 2, c: 55038}, michael@0: {f: 3, c: 55041}, {f: 12, c: 55045}, {f: 6, c: 55058}, {f: 2, c: 55066}, michael@0: {f: 3, c: 55069}, {f: 7, c: 55073}, 55082, 55084, {f: 6, c: 55086}, michael@0: {f: 2, c: 55094}, {f: 3, c: 55097}, {f: 7, c: 55101}, {f: 2, c: 55109}, michael@0: 55112, {f: 6, c: 55114}, {f: 2, c: 55122}, 55125, {f: 6, c: 55130}, 55138, michael@0: 55140, {f: 3, c: 55142}, {f: 2, c: 55146}, {f: 3, c: 55149}, michael@0: {f: 3, c: 55153}, {f: 7, c: 55157}, {f: 3, c: 55166}, {f: 6, c: 55170}, michael@0: {f: 2, c: 55178}, {f: 3, c: 55181}, {f: 7, c: 55185}, 55194, 55196, michael@0: {f: 6, c: 55198}], michael@0: 'Adobe-CNS1': [{f: 95, c: 32}, {s: 3}, 12288, 65292, {f: 2, c: 12289}, 65294, michael@0: 8226, 65307, 65306, 65311, 65281, 65072, 8230, 8229, 65104, 65380, 65106, michael@0: 183, {f: 4, c: 65108}, 65372, 8211, 65073, 8212, {s: 4}, {f: 2, c: 65288}, michael@0: {f: 2, c: 65077}, 65371, 65373, {f: 2, c: 65079}, {f: 2, c: 12308}, michael@0: {f: 2, c: 65081}, {f: 2, c: 12304}, {f: 2, c: 65083}, {f: 2, c: 12298}, michael@0: {f: 2, c: 65085}, {f: 2, c: 12296}, {f: 2, c: 65087}, {f: 2, c: 12300}, michael@0: {f: 2, c: 65089}, {f: 2, c: 12302}, {f: 2, c: 65091}, {f: 6, c: 65113}, michael@0: {f: 2, c: 8216}, {f: 2, c: 8220}, {f: 2, c: 12317}, 8245, 8242, 65283, michael@0: 65286, 65290, 8251, 167, 12291, 9675, 9679, 9651, 9650, 9678, 9734, 9733, michael@0: 9671, 9670, 9633, 9632, 9661, 9660, 12963, 8453, 8254, 0, 65343, 0, michael@0: {f: 2, c: 65097}, {f: 2, c: 65101}, {f: 2, c: 65099}, {f: 3, c: 65119}, michael@0: 65291, 65293, 215, 247, 177, 8730, 65308, 65310, 65309, {f: 2, c: 8806}, michael@0: 8800, 8734, 8786, 8801, {f: 5, c: 65122}, 8764, {f: 2, c: 8745}, 8869, michael@0: 8736, 8735, 8895, 13266, 13265, 8747, 8750, 8757, 8756, 9792, 9794, 9793, michael@0: 9737, 8593, 8595, 8594, 8592, {f: 2, c: 8598}, 8601, 8600, 8741, 8739, 0, michael@0: 0, 65295, 65340, 65284, 165, 12306, {f: 2, c: 162}, 65285, 65312, 8451, michael@0: 8457, {f: 3, c: 65129}, 13269, {f: 3, c: 13212}, 13262, 13217, michael@0: {f: 2, c: 13198}, 13252, 176, [20825, 58834], [20827, 58835], michael@0: [20830, 58837], [20829, 58836], 20833, 20835, 21991, [29929, 58044], michael@0: [31950, 58191], {f: 8, c: 9601}, 9615, 9614, 9613, 9612, 9611, 9610, 9609, michael@0: 9532, 9524, 9516, 9508, 9500, 9620, 9472, 9474, 9621, 9484, 9488, 9492, michael@0: 9496, {f: 2, c: 9581}, 9584, 9583, 9552, 9566, 9578, 9569, {f: 2, c: 9698}, michael@0: 9701, 9700, {f: 3, c: 9585}, {f: 10, c: 65296}, {f: 10, c: 8544}, michael@0: {f: 9, c: 12321}, 0, [21316, 57443], 0, {f: 26, c: 65313}, michael@0: {f: 26, c: 65345}, {f: 17, c: 913}, {f: 7, c: 931}, {f: 17, c: 945}, michael@0: {f: 7, c: 963}, {f: 37, c: 12549}, 729, 714, 711, 715, [9312, 63153], michael@0: [9313, 63154], [9314, 63155], [9315, 63156], [9316, 63157], [9317, 63158], michael@0: [9318, 63159], [9319, 63160], [9320, 63161], [9321, 63162], [9332, 63163], michael@0: [9333, 63164], [9334, 63165], [9335, 63166], [9336, 63167], [9337, 63168], michael@0: [9338, 63169], [9339, 63170], [9340, 63171], [9341, 63172], [8560, 63173], michael@0: [8561, 63174], [8562, 63175], [8563, 63176], [8564, 63177], [8565, 63178], michael@0: [8566, 63179], [8567, 63180], [8568, 63181], [8569, 63182], [12033, 20008], michael@0: [12034, 20022, 63183], [12035, 20031, 63184], [12037, 20101, 63185], michael@0: [12039, 20128, 63186], [12044, 20866, 63187], [12045, 20886, 63188], michael@0: [12046, 20907, 63189], [12051, 21241, 63190], [12054, 21304, 63191], michael@0: [12057, 21353, 63192], [12059, 21430, 63193], michael@0: [12065, 12066, 22786, 22794, 63194], [12071, 23424, 63195], michael@0: [12078, 24027, 63196], [12083, 24186, 63197], [12084, 24191, 63198], michael@0: [12085, 24308], [12089, 24400, 63200], [12090, 24417, 63201], michael@0: [12097, 25908, 63202], [12102, 26080], [12135, 30098, 63204], michael@0: [12136, 30326], [12193, 36789, 63206], [12202, 38582], {f: 32, c: 9216}, michael@0: 9249, [12032, 19968], [12036, 20057], 19969, 19971, 20035, 20061, 20102, michael@0: [12038, 20108], [12040, 20154], [12041, 20799], [12042, 20837], michael@0: [12043, 20843], [12047, 20960], [12049, 20992], 20993, [12050, 21147], michael@0: [12052, 21269], [12055, 21313], [12056, 21340], [12060, 21448], 19977, michael@0: 19979, 19976, 19978, 20011, 20024, 20961, 20037, 20040, 20063, 20062, michael@0: 20110, 20129, [20800, 64012], 20995, 21242, 21315, 21449, [12061, 21475], michael@0: [12063, 22303], [12064, 22763], [12067, 22805], [12068, 22823], michael@0: [12069, 22899], [12070, 23376], 23377, 23379, [12072, 23544], michael@0: [12073, 23567], [12074, 23586], [12075, 23608], [12077, 23665], 24029, michael@0: [12079, 24037], [12080, 24049], {f: 2, c: 24050}, [12081, 24062], michael@0: [12082, 24178], [12086, 24318], [12087, 24331], [12088, 24339], 25165, michael@0: 19985, 19984, 19981, 20013, 20016, 20025, 20043, 23609, 20104, 20113, michael@0: 20117, 20114, 20116, 20130, 20161, 20160, 20163, {f: 2, c: 20166}, 20173, michael@0: {f: 2, c: 20170}, 20164, 20803, 20801, 20839, {f: 2, c: 20845}, 20844, michael@0: 20887, 20982, {f: 3, c: 20998}, 21243, {f: 2, c: 21246}, 21270, 21305, michael@0: 21320, 21319, 21317, 21342, 21380, 21451, 21450, 21453, 22764, 22825, michael@0: 22827, 22826, 22829, 23380, 23569, 23588, 23610, 23663, 24052, 24187, michael@0: 24319, {f: 2, c: 24340}, [12092, 24515], [12093, 25096], [12094, 25142], michael@0: [12095, 25163], 25166, [12096, 25903], [12098, 25991], [12099, 26007], michael@0: [12100, 26020], [12101, 26041], [12103, 26085], [12104, 26352], michael@0: [12105, 26376], [12106, 26408], [12107, 27424], [12108, 27490], michael@0: [12109, 27513], [12111, 27595], [12112, 27604], [12113, 27611], michael@0: [12114, 27663], [12116, 27700], [12117, 28779], [12118, 29226], michael@0: [12119, 29238], [12120, 29243], [12122, 29255], [12123, 29273], michael@0: [12124, 29275], [12125, 29356], 29579, 19993, 19990, 19989, 19988, 19992, michael@0: 20027, 20045, 20047, 20046, 20197, 20184, {f: 4, c: 20180}, michael@0: {f: 2, c: 20195}, 20185, 20190, 20805, 20804, {f: 2, c: 20873}, 20908, michael@0: {f: 2, c: 20985}, 20984, 21002, 21152, 21151, [21253, 57435], 21254, 21271, michael@0: 21277, 20191, 21322, 21321, 21345, 21344, 21359, 21358, 21435, 21487, michael@0: 21476, 21491, 21484, 21486, 21481, 21480, 21500, 21496, 21493, 21483, michael@0: 21478, 21482, 21490, 21489, 21488, 21477, 21485, 21499, 22235, 22234, michael@0: 22806, 22830, 22833, 22900, 22902, 23381, 23427, 23612, 24040, 24039, michael@0: 24038, {f: 2, c: 24066}, 24179, 24188, 24321, 24344, 24343, 24517, 25098, michael@0: {f: 2, c: 25171}, 25170, 25169, 26021, 26086, 26414, 26412, michael@0: {f: 2, c: 26410}, 26413, 27491, 27597, 27665, 27664, 27704, 27713, 27712, michael@0: 27710, 29359, [12126, 29572], [12127, 29577], [12128, 29916], michael@0: [12129, 29926], [12130, 29976], [12131, 29983], [12132, 29992], 29993, michael@0: [12133, 30000], {f: 3, c: 30001}, [12134, 30091], [12137, 30333], michael@0: [12138, 30382], [12139, 30399], [12140, 30446], [12141, 30683], michael@0: [12142, 30690], [12143, 30707], [12144, 31034], [12146, 31166], michael@0: [12147, 31348], [12148, 31435], {f: 2, c: 19998}, {f: 2, c: 20050}, 20073, michael@0: 20121, 20132, 20134, 20133, 20223, 20233, 20249, 20234, 20245, 20237, michael@0: {f: 2, c: 20240}, 20239, 20210, 20214, 20219, 20208, 20211, 20221, 20225, michael@0: 20235, 20809, 20807, 20806, 20808, 20840, 20849, 20877, 20912, 21015, michael@0: {f: 2, c: 21009}, 21006, 21014, 21155, 21256, 21281, 21280, michael@0: {f: 2, c: 21360}, 21513, 21519, 21516, 21514, 21520, 21505, 21515, 21508, michael@0: 21521, 21517, 21512, 21507, 21518, 21510, 21522, 22240, 22238, 22237, michael@0: 22323, 22320, 22312, 22317, 22316, 22319, 22313, {f: 2, c: 22809}, michael@0: {f: 2, c: 22839}, 22916, 22904, 22915, 22909, 22905, 22914, 22913, michael@0: {f: 2, c: 23383}, {f: 2, c: 23431}, 23429, 23433, 23546, 23574, 23673, michael@0: 24030, 24070, 24182, 24180, 24335, 24347, 24537, 24534, 25102, michael@0: {f: 2, c: 25100}, 25104, 25187, 25179, 25176, 25910, 26089, 26088, michael@0: {f: 2, c: 26092}, {f: 2, c: 26354}, 26377, 26429, 26420, 26417, 26421, michael@0: 27425, 27492, 27515, 27670, 27741, 27735, 27737, {f: 2, c: 27743}, 27728, michael@0: 27733, 27745, 27739, {f: 2, c: 27725}, 28784, 29279, 29277, 30334, michael@0: [12149, 31481], [12150, 31859], [12151, 31992], [12152, 32566], michael@0: [12154, 32650], [12155, 32701], [12156, 32769], 32771, [12157, 32780], michael@0: [12158, 32786], [12159, 32819], [12160, 32895], [12161, 32905], michael@0: {f: 2, c: 32907}, [12162, 33251], [12163, 33258], [12164, 33267], michael@0: [12165, 33276], [12166, 33292], [12167, 33307], [12168, 33311], michael@0: [12169, 33390], [12170, 33394], 33406, [12173, 34411], [12174, 34880], michael@0: [12175, 34892], [12176, 34915], 35199, 38433, 20018, 20136, 20301, 20303, michael@0: 20295, 20311, 20318, 20276, 20315, 20309, 20272, {f: 2, c: 20304}, 20285, michael@0: 20282, 20280, 20291, 20308, 20284, 20294, 20323, 20316, 20320, 20271, michael@0: 20302, 20278, 20313, 20317, 20296, 20314, 20812, 20811, 20813, 20853, michael@0: {f: 2, c: 20918}, 21029, 21028, {f: 2, c: 21033}, 21032, 21163, michael@0: {f: 2, c: 21161}, 21164, 21283, 21363, 21365, 21533, 21549, 21534, 21566, michael@0: 21542, 21582, 21543, 21574, 21571, 21555, 21576, 21570, 21531, 21545, michael@0: 21578, 21561, 21563, 21560, 21550, {f: 2, c: 21557}, 21536, 21564, 21568, michael@0: 21553, 21547, 21535, 21548, 22250, 22256, 22244, 22251, 22346, 22353, michael@0: 22336, 22349, 22343, 22350, 22334, 22352, 22351, 22331, 22767, 22846, michael@0: 22941, 22930, 22952, 22942, 22947, 22937, 22934, 22925, 22948, 22931, michael@0: 22922, 22949, 23389, 23388, {f: 2, c: 23386}, 23436, 23435, 23439, 23596, michael@0: {f: 2, c: 23616}, 23615, 23614, {f: 2, c: 23696}, 23700, 23692, 24043, michael@0: 24076, 24207, 24199, 24202, 24311, 24324, 24351, 24420, 24418, 24439, michael@0: 24441, 24536, 24524, 24535, 24525, 24561, 24555, 24568, 24554, 25106, michael@0: 25105, 25220, 25239, 25238, 25216, 25206, 25225, 25197, 25226, 25212, michael@0: 25214, 25209, 25203, 25234, 25199, 25240, 25198, 25237, 25235, 25233, michael@0: 25222, 25913, 25915, 25912, 26097, 26356, 26463, {f: 4, c: 26446}, 26460, michael@0: 26454, [26462, 57801], 26441, 26438, 26464, 26451, 26455, 27493, 27599, michael@0: 27714, 27742, 27801, 27777, {f: 2, c: 27784}, 27781, 27803, 27754, 27770, michael@0: 27792, 27760, 27788, 27752, 27798, 27794, 27773, 27779, 27762, 27774, michael@0: 27764, 27782, 27766, 27789, 27796, 27800, 27778, 28790, {f: 2, c: 28796}, michael@0: 28792, 29282, 29281, 29280, 29380, 29378, 29590, 29996, 29995, michael@0: {f: 2, c: 30007}, 30338, 30447, 30691, 31169, 31168, 31167, 31350, 31995, michael@0: 32597, 32918, 32915, 32925, 32920, 32923, 32922, 32946, 33391, 33426, michael@0: 33419, 33421, [12178, 35211], [12179, 35282], [12180, 35328], michael@0: [12181, 35895], [12182, 35910], [12183, 35925], [12185, 35997], michael@0: [12186, 36196], [12187, 36208], [12188, 36275], [12189, 36523], michael@0: [12190, 36554], [12191, 36763], [12192, 36784], 36802, 36806, 36805, 36804, michael@0: 24033, [12194, 37009], 37026, 37034, 37030, 37027, [12195, 37193], michael@0: [12196, 37318], [12197, 37324], 38450, 38446, 38449, 38442, 38444, 20006, michael@0: 20054, 20083, 20107, 20123, 20126, {f: 2, c: 20139}, 20335, 20381, 20365, michael@0: 20339, 20351, 20332, 20379, 20363, 20358, 20355, 20336, 20341, 20360, michael@0: 20329, 20347, 20374, 20350, 20367, 20369, 20346, 20820, 20818, 20821, michael@0: 20841, 20855, 20854, 20856, 20925, 20989, 21051, 21048, 21047, 21050, michael@0: 21040, 21038, 21046, 21057, 21182, 21179, 21330, 21332, 21331, 21329, michael@0: 21350, {f: 3, c: 21367}, 21462, 21460, 21463, 21619, 21621, 21654, 21624, michael@0: 21653, 21632, 21627, 21623, 21636, 21650, 21638, 21628, 21648, 21617, michael@0: 21622, 21644, 21658, 21602, 21608, 21643, 21629, 21646, 22266, 22403, michael@0: 22391, 22378, 22377, 22369, 22374, 22372, 22396, 22812, 22857, michael@0: {f: 2, c: 22855}, 22852, 22868, 22974, 22971, 22996, 22969, 22958, 22993, michael@0: 22982, 22992, 22989, 22987, 22995, 22986, 22959, 22963, 22994, 22981, michael@0: 23391, 23396, 23395, 23447, 23450, 23448, 23452, 23449, 23451, 23578, michael@0: 23624, {f: 2, c: 23621}, 23735, 23713, 23736, 23721, 23723, 23729, 23731, michael@0: 24088, 24090, 24086, 24085, 24091, 24081, 24184, 24218, 24215, 24220, michael@0: {f: 2, c: 24213}, 24310, {f: 2, c: 24358}, 24361, {f: 2, c: 24448}, 24447, michael@0: 24444, 24541, 24544, 24573, 24565, 24575, 24591, 24596, 24623, 24629, michael@0: 24598, 24618, 24597, 24609, 24615, 24617, 24619, 24603, 25110, 25109, michael@0: 25151, 25150, 25152, 25215, 25289, 25292, 25284, 25279, 25282, 25273, michael@0: 25298, 25307, 25259, {f: 2, c: 25299}, 25291, 25288, 25256, 25277, 25276, michael@0: [25296, 60582], 25305, 25287, 25293, 25269, 25306, 25265, 25304, michael@0: {f: 2, c: 25302}, 25286, 25260, [25294, 61010], 25918, 26023, 26044, 26106, michael@0: 26132, 26131, 26124, 26118, 26114, 26126, 26112, 26127, 26133, 26122, michael@0: 26119, 26381, 26379, 26477, 26507, 26517, 26481, 26524, 26483, 26487, michael@0: 26503, 26525, 26519, {f: 2, c: 26479}, 26495, 26505, 26494, 26512, 26485, michael@0: 26522, 26515, 26492, 26474, 26482, 27427, {f: 2, c: 27494}, 27519, 27667, michael@0: 27675, 27875, 27880, 27891, 27825, 27852, 27877, 27827, {f: 2, c: 27837}, michael@0: 27836, 27874, 27819, 27861, 27859, 27832, 27844, 27833, 27841, 27822, michael@0: 27863, 27845, 27889, 27839, 27835, 27873, 27867, 27850, 27820, 27887, michael@0: 27868, 27862, 27872, 28821, 28814, 28818, 28810, 28825, {f: 2, c: 29228}, michael@0: 29240, 29256, 29287, 29289, 29376, 29390, 29401, 29399, 29392, 29609, michael@0: 29608, 29599, 29611, 29605, 30013, 30109, {f: 2, c: 30105}, 30340, 30402, michael@0: 30450, 30452, 30693, 30717, 31038, {f: 2, c: 31040}, 31177, 31176, 31354, michael@0: 31353, 31482, 31998, 32596, 32652, 32651, [32773, 58236], 32954, 32933, michael@0: 32930, 32945, 32929, 32939, 32937, 32948, 32938, 32943, 33253, 33278, michael@0: 33293, 33459, 33437, 33433, 33453, 33469, 33439, 33465, 33457, 33452, michael@0: 33445, 33455, 33464, 33443, 33456, 33470, 33463, 34382, 34417, 21021, michael@0: 34920, 36555, 36814, 36820, 36817, 37045, 37048, 37041, 37046, 37319, michael@0: [12198, 37329], [12199, 38263], [12200, 38272], [12201, 38428], 38464, michael@0: 38463, 38459, 38468, 38466, [12203, 38585], [12204, 38632], 38738, michael@0: [12206, 38750], 20127, {f: 2, c: 20141}, 20449, 20405, 20399, 20415, 20448, michael@0: 20433, 20431, 20445, 20419, 20406, 20440, 20447, 20426, 20439, 20398, michael@0: 20432, 20420, 20418, 20442, 20430, 20446, 20407, 20823, 20882, 20881, michael@0: 20896, 21070, 21059, 21066, 21069, 21068, 21067, 21063, 21191, 21193, michael@0: 21187, 21185, 21261, 21335, 21371, 21402, 21467, 21676, 21696, 21672, michael@0: 21710, 21705, 21688, 21670, 21683, 21703, 21698, 21693, 21674, 21697, michael@0: 21700, 21704, 21679, 21675, 21681, 21691, 21673, 21671, 21695, 22271, michael@0: 22402, 22411, 22432, 22435, 22434, 22478, 22446, 22419, 22869, 22865, michael@0: 22863, 22862, 22864, 23004, 23000, 23039, 23011, 23016, 23043, 23013, michael@0: 23018, 23002, 23014, 23041, 23035, 23401, 23459, 23462, 23460, 23458, michael@0: 23461, 23553, {f: 2, c: 23630}, 23629, 23627, 23769, 23762, 24055, 24093, michael@0: 24101, 24095, 24189, 24224, 24230, 24314, 24328, 24365, 24421, 24456, michael@0: 24453, {f: 2, c: 24458}, 24455, 24460, 24457, 24594, 24605, 24608, 24613, michael@0: 24590, 24616, 24653, 24688, 24680, [24674, 60712], 24646, 24643, 24684, michael@0: 24683, 24682, 24676, 25153, 25308, 25366, 25353, 25340, 25325, 25345, michael@0: 25326, 25341, 25351, 25329, 25335, 25327, 25324, 25342, 25332, 25361, michael@0: 25346, 25919, 25925, 26027, 26045, 26082, 26149, 26157, 26144, 26151, michael@0: 26159, 26143, 26152, 26161, 26148, 26359, 26623, 26579, 26609, 26580, michael@0: 26576, 26604, 26550, 26543, 26613, 26601, 26607, 26564, 26577, 26548, michael@0: 26586, 26597, 26552, 26575, 26590, 26611, 26544, 26585, 26594, 26589, michael@0: 26578, 27498, 27523, 27526, 27573, 27602, 27607, 27679, 27849, 27915, michael@0: 27954, 27946, 27969, 27941, 27916, 27953, 27934, 27927, 27963, michael@0: {f: 2, c: 27965}, 27958, 27931, 27893, 27961, 27943, 27960, 27945, 27950, michael@0: 27957, 27918, 27947, 28843, 28858, 28851, 28844, 28847, 28845, 28856, michael@0: 28846, 28836, 29232, 29298, 29295, 29300, 29417, {f: 2, c: 29408}, 29623, michael@0: 29642, 29627, 29618, 29645, 29632, 29619, 29978, 29997, 30031, 30028, michael@0: 30030, 30027, 30123, {f: 2, c: 30116}, {f: 2, c: 30114}, 30328, michael@0: {f: 3, c: 30342}, 30408, 30406, 30403, 30405, 30465, 30457, 30456, 30473, michael@0: 30475, 30462, 30460, 30471, 30684, 30722, 30740, {f: 2, c: 30732}, 31046, michael@0: 31049, 31048, 31047, {f: 2, c: 31161}, {f: 2, c: 31185}, 31179, 31359, michael@0: 31361, 31487, 31485, 31869, 32002, 32005, 32000, 32009, 32007, 32004, michael@0: 32006, 32568, 32654, 32703, 32784, 32781, 32785, 32822, 32982, 32997, michael@0: 32986, {f: 2, c: 32963}, 32972, 32993, 32987, 32974, 32990, 32996, 32989, michael@0: 33268, 33314, 33511, 33539, 33541, 33507, 33499, 33510, 33540, 33509, michael@0: 33538, 33545, 33490, 33495, 33521, 33537, 33500, 33492, 33489, 33502, michael@0: 33491, 33503, 33519, 33542, 34384, 34425, 34427, 34426, 34893, 34923, michael@0: 35201, 35284, 35336, {f: 2, c: 35330}, 35998, 36000, 36212, 36211, 36276, michael@0: 36557, 36556, 36848, 36838, 36834, 36842, 36837, 36845, 36843, 36836, michael@0: 36840, 37066, 37070, 37057, 37059, 37195, 37194, 37325, 38274, 38480, michael@0: {f: 3, c: 38475}, [12207, 38754], [12208, 38761], [12209, 38859], michael@0: [12210, 38893], [12211, 38899], [12212, 38913], [12213, 39080], michael@0: [12214, 39131], [12215, 39135], [12216, 39318], [12217, 39321], 20056, michael@0: 20147, {f: 2, c: 20492}, 20515, 20463, 20518, 20517, 20472, [20521, 57375], michael@0: 20502, 20486, 20540, 20511, 20506, 20498, 20497, 20474, 20480, 20500, michael@0: 20520, 20465, 20513, 20491, 20505, 20504, 20467, 20462, 20525, 20522, michael@0: 20478, 20523, 20489, 20860, {f: 2, c: 20900}, 20898, 20941, 20940, 20934, michael@0: 20939, 21078, 21084, 21076, 21083, 21085, 21290, [21375, 57459], 21407, michael@0: 21405, 21471, 21736, 21776, 21761, 21815, 21756, 21733, 21746, 21766, michael@0: 21754, 21780, 21737, 21741, 21729, 21769, 21742, 21738, 21734, 21799, michael@0: 21767, 21757, 21775, {f: 2, c: 22275}, 22466, 22484, 22475, 22467, 22537, michael@0: 22799, {f: 2, c: 22871}, 22874, 23057, 23064, 23068, 23071, 23067, 23059, michael@0: 23020, 23072, 23075, 23081, 23077, 23052, 23049, 23403, 23640, 23472, michael@0: 23475, 23478, 23476, 23470, 23477, 23481, 23480, 23556, 23633, 23637, michael@0: 23632, 23789, 23805, 23803, 23786, 23784, 23792, 23798, 23809, 23796, michael@0: 24046, 24109, 24107, 24235, 24237, 24231, 24369, 24466, 24465, 24464, michael@0: 24665, 24675, 24677, 24656, 24661, 24685, 24681, 24687, 24708, 24735, michael@0: 24730, 24717, 24724, 24716, 24709, 24726, 25159, 25331, 25352, 25343, michael@0: 25422, 25406, 25391, 25429, 25410, 25414, 25423, 25417, 25402, 25424, michael@0: 25405, {f: 2, c: 25386}, 25384, 25421, 25420, {f: 2, c: 25928}, 26009, michael@0: 26049, 26053, 26178, 26185, 26191, 26179, 26194, 26188, 26181, 26177, michael@0: 26360, {f: 2, c: 26388}, 26391, 26657, 26680, 26696, 26694, 26707, 26681, michael@0: 26690, 26708, 26665, 26803, 26647, 26700, 26705, 26685, 26612, 26704, michael@0: 26688, 26684, 26691, 26666, 26693, 26643, 26648, 26689, 27530, 27529, michael@0: 27575, 27683, {f: 2, c: 27687}, 27686, 27684, 27888, 28010, 28053, 28040, michael@0: 28039, 28006, 28024, 28023, 27993, 28051, 28012, 28041, 28014, 27994, michael@0: 28020, 28009, 28044, 28042, 28025, 28037, 28005, 28052, 28874, 28888, michael@0: 28900, 28889, 28872, 28879, 29241, 29305, 29436, 29433, 29437, 29432, michael@0: 29431, 29574, 29677, 29705, 29678, 29664, 29674, 29662, 30036, 30045, michael@0: 30044, 30042, 30041, 30142, 30149, 30151, {f: 2, c: 30130}, 30141, 30140, michael@0: 30137, 30146, 30136, 30347, 30384, 30410, {f: 2, c: 30413}, 30505, michael@0: {f: 2, c: 30495}, 30504, 30697, 30768, 30759, 30776, 30749, 30772, 30775, michael@0: 30757, 30765, 30752, 30751, 30770, 31061, 31056, 31072, 31071, 31062, michael@0: 31070, 31069, 31063, 31066, 31204, [31203, 60418], 31207, 31199, 31206, michael@0: 31209, 31192, 31364, 31368, 31449, 31494, 31505, 31881, 32033, 32023, michael@0: 32011, 32010, 32032, 32034, 32020, 32016, 32021, 32026, 32028, 32013, michael@0: 32025, 32027, 32570, 32607, 32660, 32709, 32705, 32774, 32772, 32792, michael@0: 32789, 32793, 32791, 32829, 32831, 33009, 33026, 33008, 33029, 33005, michael@0: 33012, 33030, 33016, 33011, 33032, 33021, 33034, 33020, 33007, 33261, michael@0: 33260, 33280, 33296, {f: 2, c: 33322}, 33320, 33324, 33467, 33579, 33618, michael@0: 33620, 33610, 33592, 33616, 33609, 33589, 33588, 33615, 33586, 33593, michael@0: 33590, 33559, 33600, 33585, 33576, 33603, 34388, 34442, 34474, 34451, michael@0: 34468, 34473, 34444, 34467, 34460, 34928, 34935, {f: 2, c: 34945}, 34941, michael@0: 34937, 35352, 35344, 35342, 35340, 35349, 35338, 35351, 35347, 35350, michael@0: 35343, 35345, 35912, 35962, 35961, {f: 2, c: 36001}, [36215, 58442], 36524, michael@0: 36562, 36564, 36559, 36785, 36865, 36870, 36855, 36864, 36858, 36852, michael@0: 36867, 36861, 36869, 36856, 37013, 37089, 37085, 37090, 37202, 37197, michael@0: 37196, 37336, 37341, 37335, 37340, 37337, 38275, {f: 2, c: 38498}, 38497, michael@0: 38491, 38493, 38500, 38488, 38494, 38587, 39138, [12218, 39340], michael@0: [12219, 39592], [12220, 39640], [12222, 39717], [12224, 39730], michael@0: [12225, 39740], 20094, 20602, [20605, 57382], 20572, 20551, 20547, 20556, michael@0: 20570, 20553, 20581, 20598, 20558, 20565, 20597, 20596, 20599, 20559, michael@0: 20495, 20591, 20589, 20828, 20885, 20976, 21098, 21103, 21202, 21209, michael@0: 21208, 21205, 21264, 21263, 21273, {f: 2, c: 21311}, 21310, 21443, 26364, michael@0: 21830, 21866, 21862, 21828, 21854, 21857, 21827, 21834, 21809, 21846, michael@0: 21839, 21845, 21807, 21860, 21816, 21806, 21852, 21804, 21859, 21811, michael@0: 21825, 21847, 22280, 22283, 22281, 22495, 22533, 22538, 22534, 22496, michael@0: 22500, 22522, 22530, 22581, 22519, 22521, 22816, 22882, 23094, 23105, michael@0: 23113, 23142, 23146, 23104, 23100, 23138, 23130, 23110, 23114, 23408, michael@0: 23495, 23493, 23492, 23490, 23487, 23494, 23561, 23560, 23559, 23648, michael@0: {f: 2, c: 23644}, 23815, 23814, 23822, 23835, 23830, 23842, 23825, 23849, michael@0: 23828, 23833, 23844, 23847, 23831, 24034, 24120, 24118, 24115, 24119, michael@0: {f: 2, c: 24247}, 24246, 24245, 24254, 24373, 24375, 24407, 24428, 24425, michael@0: 24427, 24471, 24473, 24478, 24472, 24481, 24480, 24476, 24703, 24739, michael@0: 24713, 24736, 24744, 24779, 24756, 24806, 24765, 24773, 24763, 24757, michael@0: 24796, 24764, 24792, 24789, 24774, 24799, 24760, 24794, 24775, michael@0: {f: 2, c: 25114}, 25160, 25504, 25511, 25458, 25494, 25506, 25509, 25463, michael@0: 25447, 25496, 25514, 25457, 25513, 25481, 25475, 25499, 25451, 25512, michael@0: 25476, 25480, 25497, 25505, 25516, 25490, 25487, 25472, 25467, 25449, michael@0: 25448, 25466, 25949, 25942, 25937, 25945, 25943, 21855, 25935, 25944, michael@0: 25941, 25940, 26012, 26011, 26028, 26063, {f: 2, c: 26059}, 26062, 26205, michael@0: 26202, 26212, 26216, 26214, 26206, 26361, 21207, 26395, 26753, 26799, michael@0: 26786, 26771, 26805, 26751, 26742, 26801, 26791, 26775, 26800, 26755, michael@0: 26820, 26797, 26758, 26757, 26772, 26781, 26792, 26783, 26785, 26754, michael@0: 27442, 27578, {f: 2, c: 27627}, 27691, 28046, 28092, 28147, 28121, 28082, michael@0: 28129, 28108, 28132, 28155, 28154, 28165, 28103, 28107, 28079, 28113, michael@0: 28078, 28126, 28153, 28088, 28151, 28149, 28101, 28114, 28186, 28085, michael@0: 28122, 28139, 28120, 28138, 28145, 28142, 28136, 28102, 28100, 28074, michael@0: 28140, 28095, 28134, 28921, {f: 2, c: 28937}, 28925, 28911, 29245, 29309, michael@0: 29313, 29468, 29467, 29462, 29459, 29465, 29575, 29701, 29706, 29699, michael@0: 29702, 29694, 29709, 29920, {f: 2, c: 29942}, 29980, 29986, michael@0: {f: 2, c: 30053}, 30050, 30064, 30095, {f: 2, c: 30164}, 30133, 30154, michael@0: 30157, 30350, 30420, 30418, 30427, 30519, 30526, 30524, 30518, 30520, michael@0: 30522, 30827, 30787, 30798, 31077, 31080, 31085, 31227, 31378, 31381, michael@0: 31520, 31528, 31515, 31532, 31526, 31513, 31518, 31534, 31890, 31895, michael@0: 31893, 32070, 32067, 32113, 32046, 32057, 32060, 32064, 32048, 32051, michael@0: 32068, 32047, 32066, 32050, 32049, 32573, 32670, 32666, 32716, 32718, michael@0: 32722, 32796, 32842, 32838, 33071, 33046, 33059, 33067, 33065, 33072, michael@0: 33060, 33282, 33333, 33335, 33334, 33337, 33678, 33694, 33688, 33656, michael@0: 33698, 33686, 33725, 33707, 33682, 33674, 33683, 33673, 33696, 33655, michael@0: {f: 2, c: 33659}, 33670, 33703, 34389, 24426, 34503, 34496, 34486, 34500, michael@0: 34485, 34502, 34507, 34481, 34479, 34505, 34899, 34974, 34952, 34987, michael@0: 34962, 34966, 34957, 34955, 35219, 35215, 35370, 35357, 35363, 35365, michael@0: 35377, 35373, 35359, 35355, 35362, 35913, 35930, 36009, 36012, 36011, michael@0: 36008, 36010, 36007, 36199, 36198, 36286, 36282, 36571, 36575, 36889, michael@0: 36877, 36890, 36887, 36899, 36895, 36893, 36880, 36885, 36894, 36896, michael@0: 36879, 36898, 36886, 36891, 36884, 37096, 37101, [37117, 58488], 37207, michael@0: 37326, 37365, 37350, 37347, 37351, 37357, 37353, 38281, 38506, 38517, michael@0: 38515, 38520, 38512, 38516, {f: 2, c: 38518}, 38508, 38592, 38634, 38633, michael@0: 31456, 31455, {f: 2, c: 38914}, [12226, 39770], [12227, 40165], michael@0: [12228, 40565], [12229, 40575], [12230, 40613], [12231, 40635], 20642, michael@0: 20621, 20613, 20633, 20625, 20608, 20630, 20632, 20634, 26368, 20977, michael@0: 21106, {f: 2, c: 21108}, 21097, 21214, 21213, 21211, 21338, 21413, 21883, michael@0: 21888, 21927, 21884, 21898, 21917, 21912, 21890, 21916, 21930, 21908, michael@0: 21895, 21899, 21891, 21939, 21934, 21919, 21822, 21938, 21914, 21947, michael@0: 21932, 21937, 21886, 21897, 21931, 21913, 22285, 22575, 22570, 22580, michael@0: 22564, {f: 2, c: 22576}, 22561, 22557, 22560, {f: 2, c: 22777}, 22880, michael@0: [23159, 57587], 23194, 23167, 23186, 23195, 23207, 23411, 23409, 23506, michael@0: 23500, 23507, 23504, {f: 2, c: 23562}, 23601, 23884, 23888, 23860, 23879, michael@0: 24061, 24133, 24125, 24128, 24131, 24190, 24266, {f: 2, c: 24257}, 24260, michael@0: 24380, 24429, {f: 2, c: 24489}, 24488, 24785, 24801, 24754, 24758, 24800, michael@0: 24860, 24867, 24826, 24853, 24816, 24827, 24820, 24936, 24817, 24846, michael@0: 24822, 24841, 24832, 24850, 25119, 25161, 25507, 25484, 25551, 25536, michael@0: 25577, 25545, 25542, 25549, 25554, 25571, 25552, 25569, 25558, michael@0: {f: 2, c: 25581}, 25462, 25588, 25578, 25563, 25682, 25562, 25593, 25950, michael@0: 25958, {f: 2, c: 25954}, 26001, 26000, 26031, 26222, 26224, [26228, 57786], michael@0: 26230, 26223, 26257, 26234, 26238, 26231, {f: 2, c: 26366}, 26399, 26397, michael@0: 26874, 26837, 26848, 26840, 26839, 26885, 26847, 26869, 26862, 26855, michael@0: 26873, 26834, 26866, 26851, 26827, 26829, 26893, 26898, 26894, 26825, michael@0: 26842, 26990, 26875, 27454, 27450, 27453, 27544, 27542, 27580, 27631, michael@0: {f: 2, c: 27694}, 27692, [28207, 57904], 28216, 28244, 28193, 28210, 28263, michael@0: 28234, 28192, 28197, 28195, 28187, 28251, 28248, 28196, 28246, 28270, michael@0: 28205, 28198, 28271, 28212, 28237, 28218, 28204, 28227, [28189, 57901], michael@0: 28222, 28363, 28297, 28185, 28238, 28259, 28228, 28274, 28265, 28255, michael@0: {f: 2, c: 28953}, 28966, 28976, 28961, 28982, [29038, 57958], 28956, 29260, michael@0: 29316, 29312, 29494, 29477, 29492, 29481, 29754, 29738, 29747, 29730, michael@0: 29733, {f: 2, c: 29749}, 29748, 29743, 29723, 29734, 29736, michael@0: {f: 2, c: 29989}, 30059, 30058, 30178, 30171, 30179, 30169, 30168, 30174, michael@0: 30176, {f: 2, c: 30331}, 30358, 30355, 30388, 30428, 30543, 30701, 30813, michael@0: 30828, 30831, 31245, 31240, 31243, 31237, 31232, 31384, 31383, 31382, michael@0: 31461, 31459, 31561, 31574, 31558, 31568, 31570, 31572, 31565, 31563, michael@0: 31567, [31569, 60510], 31903, 31909, 32094, 32080, 32104, 32085, 32043, michael@0: 32110, 32114, 32097, 32102, 32098, 32112, 32115, 21892, {f: 2, c: 32724}, michael@0: 32779, 32850, 32901, 33109, 33108, 33099, 33105, 33102, 33081, 33094, michael@0: 33086, 33100, 33107, 33140, 33298, 33308, 33769, 33795, 33784, 33805, michael@0: 33760, 33733, 33803, [33729, 58309], 33775, 33777, 33780, 33879, 33802, michael@0: 33776, 33804, 33740, 33789, 33778, 33738, 33848, 33806, 33796, 33756, michael@0: 33799, 33748, 33759, 34395, 34527, 34521, 34541, 34516, 34523, 34532, michael@0: 34512, 34526, 34903, {f: 2, c: 35009}, 34993, 35203, 35222, 35387, 35424, michael@0: 35413, 35422, 35388, 35393, 35412, 35419, 35408, 35398, 35380, 35386, michael@0: 35382, 35414, 35937, 35970, 36015, 36028, 36019, 36029, 36033, 36027, michael@0: 36032, 36020, 36023, 36022, 36031, 36024, 36234, 36229, 36225, 36302, michael@0: 36317, 36299, 36314, 36305, 36300, 36315, 36294, 36603, 36600, 36604, michael@0: 36764, 36910, 36917, 36913, 36920, 36914, 36918, 37122, 37109, 37129, michael@0: 37118, 37219, 37221, 37327, {f: 2, c: 37396}, 37411, 37385, 37406, 37389, michael@0: 37392, 37383, 37393, 38292, 38287, 38283, 38289, 38291, 38290, 38286, michael@0: 38538, 38542, 38539, 38525, {f: 2, c: 38533}, 38541, 38514, 38532, 38593, michael@0: 38597, 38596, {f: 2, c: 38598}, 38639, 38642, 38860, {f: 2, c: 38917}, michael@0: 38920, 39143, 39146, 39151, 39145, 39154, 39149, 39342, 39341, michael@0: [12232, 40643], [12233, 40653], [12234, 40657], 20098, 20653, 20661, michael@0: {f: 2, c: 20658}, 20677, 20670, 20652, 20663, 20667, 20655, 20679, 21119, michael@0: 21111, 21117, 21215, 21222, 21220, {f: 2, c: 21218}, 21295, 21983, 21992, michael@0: 21971, 21990, 21966, 21980, 21959, 21969, {f: 2, c: 21987}, 21999, 21978, michael@0: 21985, {f: 2, c: 21957}, 21989, 21961, {f: 2, c: 22290}, 22622, 22609, michael@0: 22616, 22615, 22618, 22612, 22635, 22604, 22637, 22602, 22626, 22610, michael@0: 22603, 22887, 23233, 23241, 23244, 23230, 23229, 23228, 23219, 23234, michael@0: 23218, 23913, 23919, 24140, 24185, 24265, 24264, 24338, 24409, 24492, michael@0: 24494, 24858, 24847, 24904, 24863, 24819, 24859, 24825, 24833, 24840, michael@0: 24910, 24908, 24900, 24909, 24894, 24884, 24871, 24845, 24838, 24887, michael@0: {f: 2, c: 25121}, 25619, 25662, 25630, 25642, 25645, 25661, 25644, 25615, michael@0: 25628, 25620, 25613, 25654, {f: 2, c: 25622}, 25606, 25964, 26015, 26032, michael@0: 26263, 26249, {f: 2, c: 26247}, 26262, 26244, 26264, 26253, 26371, 27028, michael@0: 26989, 26970, 26999, 26976, 26964, 26997, 26928, 27010, 26954, 26984, michael@0: 26987, 26974, 26963, 27001, 27014, 26973, 26979, 26971, 27463, 27506, michael@0: 27584, 27583, 27603, 27645, 28322, 28335, 28371, 28342, 28354, 28304, michael@0: 28317, 28359, 28357, 28325, 28312, 28348, 28346, 28331, 28369, 28310, michael@0: 28316, 28356, 28372, 28330, 28327, 28340, 29006, 29017, 29033, 29028, michael@0: 29001, 29031, 29020, 29036, 29030, 29004, 29029, 29022, 28998, 29032, michael@0: 29014, 29242, 29266, 29495, 29509, 29503, 29502, 29807, 29786, 29781, michael@0: 29791, 29790, 29761, 29759, 29785, 29787, [29788, 58019], 30070, 30072, michael@0: 30208, 30192, 30209, 30194, 30193, 30202, 30207, 30196, 30195, michael@0: {f: 2, c: 30430}, 30555, 30571, 30566, 30558, 30563, 30585, 30570, 30572, michael@0: 30556, 30565, 30568, 30562, 30702, 30862, 30896, {f: 2, c: 30871}, 30860, michael@0: 30857, 30844, 30865, 30867, 30847, 31098, 31103, 31105, 33836, 31165, michael@0: 31260, 31258, 31264, 31252, 31263, 31262, {f: 2, c: 31391}, 31607, 31680, michael@0: 31584, 31598, 31591, 31921, 31923, 31925, 32147, 32121, 32145, 32129, michael@0: 32143, 32091, 32622, {f: 2, c: 32617}, 32626, 32681, 32680, 32676, 32854, michael@0: 32856, 32902, 32900, 33137, 33136, 33144, 33125, 33134, 33139, 33131, michael@0: {f: 2, c: 33145}, 33126, 33285, 33351, 33922, 33911, 33853, 33841, 33909, michael@0: 33894, 33899, 33865, 33900, 33883, 33852, 33845, 33889, 33891, 33897, michael@0: 33901, 33862, 34398, 34396, 34399, 34553, 34579, 34568, 34567, 34560, michael@0: 34558, 34555, {f: 2, c: 34562}, 34566, 34570, 34905, 35039, 35028, 35033, michael@0: 35036, 35032, 35037, 35041, 35018, 35029, 35026, 35228, 35299, 35435, michael@0: {f: 2, c: 35442}, 35430, 35433, 35440, 35463, 35452, 35427, 35488, 35441, michael@0: 35461, 35437, 35426, 35438, 35436, 35449, 35451, 35390, 35432, 35938, michael@0: 35978, 35977, 36042, {f: 2, c: 36039}, 36036, 36018, 36035, 36034, 36037, michael@0: 36321, 36319, 36328, 36335, 36339, 36346, 36330, 36324, 36326, 36530, michael@0: 36611, 36617, 36606, 36618, 36767, 36786, 36939, 36938, 36947, 36930, michael@0: 36948, 36924, 36949, 36944, 36935, 36943, 36942, 36941, 36945, 36926, michael@0: 36929, 37138, 37143, 37228, 37226, 37225, 37321, 37431, 37463, 37432, michael@0: 37437, 37440, 37438, 37467, 37451, 37476, 37457, 37428, 37449, 37453, michael@0: 37445, 37433, 37439, 37466, 38296, 38552, {f: 2, c: 38548}, 38605, 38603, michael@0: {f: 2, c: 38601}, 38647, 38651, 38649, 38646, 38742, 38772, 38774, michael@0: {f: 2, c: 38928}, 38931, 38922, 38930, 38924, 39164, 39156, michael@0: {f: 2, c: 39165}, 39347, 39345, 39348, 39649, 40169, 40578, [12237, 40718], michael@0: [12238, 40723], [12239, 40736], 20711, 20718, 20709, 20694, [20717, 60903], michael@0: 20698, 20693, 20687, 20689, 20721, 20686, 20713, 20834, 20979, 21123, michael@0: 21122, 21297, 21421, 22014, 22016, 22043, 22039, 22013, 22036, 22022, michael@0: 22025, {f: 2, c: 22029}, 22007, 22038, 22047, 22024, 22032, 22006, 22296, michael@0: 22294, 22645, 22654, 22659, 22675, 22666, 22649, 22661, 22653, 22781, michael@0: 22821, 22818, 22820, 22890, 22889, 23265, 23270, 23273, 23255, 23254, michael@0: 23256, 23267, 23413, 23518, 23527, 23521, {f: 2, c: 23525}, 23528, 23522, michael@0: 23524, 23519, 23565, 23650, 23940, 23943, 24155, 24163, 24149, 24151, michael@0: 24148, 24275, 24278, 24330, 24390, 24432, 24505, 24903, 24895, 24907, michael@0: 24951, {f: 2, c: 24930}, 24927, 24922, 24920, 24949, 25130, 25735, 25688, michael@0: 25684, 25764, 25720, 25695, 25722, 25681, 25703, 25652, 25709, 25723, michael@0: 25970, 26017, 26071, 26070, 26274, 26280, 26269, 27036, 27048, 27029, michael@0: 27073, 27054, 27091, 27083, 27035, 27063, 27067, 27051, 27060, 27088, michael@0: 27085, 27053, 27084, 27046, 27075, 27043, 27465, 27468, 27699, 28467, michael@0: 28436, 28414, 28435, 28404, 28457, 28478, 28448, 28460, 28431, 28418, michael@0: 28450, 28415, 28399, 28422, 28465, 28472, 28466, 28451, 28437, 28459, michael@0: 28463, 28552, 28458, 28396, 28417, 28402, 28364, 28407, 29076, 29081, michael@0: 29053, 29066, 29060, 29074, 29246, 29330, 29334, 29508, 29520, 29796, michael@0: 29795, 29802, 29808, 29805, 29956, 30097, 30247, 30221, 30219, 30217, michael@0: 30227, 30433, 30435, 30596, 30589, 30591, 30561, 30913, 30879, 30887, michael@0: 30899, 30889, 30883, {f: 2, c: 31118}, 31117, 31278, 31281, 31402, 31401, michael@0: 31469, 31471, 31649, 31637, 31627, 31605, 31639, 31645, 31636, 31631, michael@0: [31672, 58170], 31623, 31620, 31929, {f: 2, c: 31933}, 32187, 32176, 32156, michael@0: {f: 2, c: 32189}, 32160, 32202, 32180, 32178, 32177, 32186, 32162, 32191, michael@0: 32181, 32184, 32173, [32210, 58202], 32199, 32172, 32624, {f: 2, c: 32736}, michael@0: 32735, 32862, 32858, 32903, 33104, 33152, 33167, 33160, 33162, 33151, michael@0: 33154, 33255, 33274, 33287, 33300, 33310, 33355, 33993, 33983, 33990, michael@0: 33988, 33945, 33950, 33970, 33948, 33995, 33976, 33984, 34003, 33936, michael@0: 33980, 34001, 33994, 34623, 34588, 34619, 34594, 34597, 34612, 34584, michael@0: 34645, 34615, 34601, 35059, 35074, 35060, 35065, 35064, 35069, 35048, michael@0: 35098, 35055, 35494, 35468, 35486, 35491, 35469, 35489, 35475, 35492, michael@0: 35498, 35493, 35496, 35480, 35473, 35482, 35495, 35946, 35981, 35980, michael@0: 36051, {f: 2, c: 36049}, 36203, 36249, 36245, 36348, 36628, 36626, 36629, michael@0: 36627, 36771, 36960, 36952, 36956, 36963, 36953, 36958, 36962, 36957, michael@0: 36955, 37145, 37144, 37150, 37237, 37240, 37239, 37236, 37496, 37548, michael@0: 37504, 37509, 37528, 37526, 37499, 37523, 37532, 37544, 37500, 37521, michael@0: 38305, {f: 2, c: 38312}, 38307, 38309, 38308, 38553, 38556, 38555, 38604, michael@0: 38610, 38656, 38780, 38789, 38902, {f: 2, c: 38935}, 39087, 39089, 39171, michael@0: 39173, 39180, 39177, 39361, {f: 2, c: 39599}, 39654, {f: 2, c: 39745}, michael@0: 40180, 40182, 40179, 40636, [12240, 40763], [12241, 40778], 20740, 20736, michael@0: 20731, 20725, 20729, 20738, {f: 2, c: 20744}, 20741, 20956, michael@0: {f: 3, c: 21127}, 21133, 21130, 21232, 21426, 22062, 22075, 22073, 22066, michael@0: 22079, 22068, 22057, 22099, 22094, 22103, 22132, 22070, {f: 2, c: 22063}, michael@0: 22656, 22687, 22686, 22707, 22684, 22702, 22697, 22694, 22893, 23305, michael@0: 23291, 23307, 23285, 23308, 23304, 23534, 23532, 23529, 23531, michael@0: {f: 2, c: 23652}, 23965, 23956, 24162, 24159, 24161, 24290, 24282, 24287, michael@0: 24285, 24291, 24288, 24392, 24433, 24503, 24501, 24950, 24935, 24942, michael@0: 24925, 24917, 24962, 24956, 24944, 24939, 24958, 24999, 24976, 25003, michael@0: 24974, 25004, 24986, 24996, 24980, 25006, 25134, 25705, 25711, 25721, michael@0: 25758, 25778, 25736, [25744, 57745], 25776, 25765, 25747, 25749, 25769, michael@0: 25746, 25774, 25773, 25771, 25754, 25772, 25753, 25762, 25779, 25973, michael@0: {f: 2, c: 25975}, 26286, 26283, 26292, 26289, 27171, 27167, 27112, 27137, michael@0: 27166, 27161, 27133, 27169, 27155, 27146, 27123, 27138, 27141, 27117, michael@0: 27153, 27472, 27470, 27556, {f: 2, c: 27589}, 28479, 28540, 28548, 28497, michael@0: 28518, 28500, 28550, 28525, 28507, 28536, 28526, 28558, 28538, 28528, michael@0: 28516, 28567, 28504, 28373, 28527, 28512, 28511, 29087, 29100, 29105, michael@0: 29096, 29270, 29339, 29518, 29527, 29801, 29835, 29827, 29822, 29824, michael@0: 30079, 30240, 30249, 30239, 30244, 30246, {f: 2, c: 30241}, 30362, 30394, michael@0: 30436, 30606, 30599, 30604, 30609, 30603, 30923, 30917, 30906, 30922, michael@0: 30910, 30933, 30908, 30928, 31295, 31292, 31296, 31293, 31287, 31291, michael@0: 31407, 31406, 31661, 31665, 31684, 31668, {f: 2, c: 31686}, 31681, 31648, michael@0: 31692, 31946, 32224, 32244, 32239, 32251, 32216, 32236, 32221, 32232, michael@0: 32227, 32218, 32222, 32233, 32158, 32217, 32242, 32249, 32629, 32631, michael@0: 32687, 32745, 32806, {f: 3, c: 33179}, 33184, 33178, 33176, 34071, 34109, michael@0: 34074, 34030, {f: 2, c: 34092}, 34067, 34065, 34083, 34081, 34068, 34028, michael@0: 34085, 34047, 34054, 34690, 34676, 34678, 34656, 34662, 34680, 34664, michael@0: 34649, 34647, 34636, 34643, 34907, 34909, 35088, 35079, {f: 2, c: 35090}, michael@0: 35093, 35082, 35516, 35538, 35527, 35524, 35477, 35531, 35576, 35506, michael@0: 35529, 35522, 35519, 35504, 35542, 35533, 35510, 35513, 35547, 35916, michael@0: 35918, 35948, 36064, 36062, 36070, 36068, {f: 2, c: 36076}, michael@0: {f: 2, c: 36066}, 36060, 36074, 36065, 36205, 36255, 36259, 36395, 36368, michael@0: 36381, 36386, 36367, 36393, 36383, 36385, 36382, 36538, 36637, 36635, michael@0: 36639, 36649, 36646, 36650, 36636, 36638, 36645, 36969, 36974, 36968, michael@0: 36973, 36983, 37168, 37165, 37159, 37169, 37255, 37257, 37259, 37251, michael@0: 37573, 37563, 37559, 37610, 37604, 37569, 37555, 37564, 37586, 37575, michael@0: 37616, 37554, 38317, 38321, 38660, {f: 2, c: 38662}, 38665, 38752, 38797, michael@0: 38795, 38799, 38945, 38955, 38940, 39091, 39178, 39187, 39186, 39192, michael@0: 39389, 39376, 39391, 39387, 39377, 39381, 39378, 39385, 39607, michael@0: {f: 2, c: 39662}, 39719, 39749, 39748, 39799, 39791, 40198, 40201, 40195, michael@0: 40617, 40638, 40654, 22696, [12242, 40786], 20754, 20760, 20756, 20752, michael@0: 20757, 20864, 20906, 20957, 21137, 21139, 21235, 22105, 22123, 22137, michael@0: 22121, 22116, 22136, 22122, 22120, 22117, 22129, 22127, 22124, 22114, michael@0: 22134, 22721, 22718, 22727, 22725, 22894, 23325, 23348, 23416, 23536, michael@0: 23566, 24394, 25010, 24977, 25001, 24970, 25037, 25014, 25022, 25034, michael@0: 25032, 25136, 25797, 25793, 25803, {f: 2, c: 25787}, 25818, 25796, 25799, michael@0: 25794, 25805, 25791, 25810, 25812, 25790, 25972, 26310, 26313, 26297, michael@0: 26308, 26311, 26296, 27197, 27192, 27194, 27225, 27243, 27224, 27193, michael@0: 27204, 27234, 27233, 27211, 27207, 27189, 27231, 27208, 27481, 27511, michael@0: 27653, 28610, 28593, 28577, 28611, 28580, 28609, 28583, 28595, 28608, michael@0: 28601, [28598, 60318], 28582, 28576, 28596, 29118, 29129, 29136, 29138, michael@0: 29128, 29141, 29113, 29134, 29145, 29148, {f: 2, c: 29123}, 29544, 29852, michael@0: 29859, 29848, 29855, 29854, 29922, {f: 2, c: 29964}, 30260, 30264, 30266, michael@0: 30439, 30437, 30624, {f: 2, c: 30622}, 30629, 30952, 30938, 30956, 30951, michael@0: 31142, {f: 2, c: 31309}, 31302, 31308, 31307, 31418, 31705, 31761, 31689, michael@0: 31716, 31707, 31713, 31721, 31718, {f: 2, c: 31957}, 32266, 32273, 32264, michael@0: 32283, 32291, 32286, [32285, 58211], 32265, 32272, 32633, 32690, michael@0: {f: 2, c: 32752}, 32750, [32808, 58239], 33203, 33193, 33192, 33275, 33288, michael@0: {f: 2, c: 33368}, 34122, 34137, 34120, {f: 2, c: 34152}, 34115, 34121, michael@0: 34157, 34154, 34142, 34691, 34719, 34718, 34722, 34701, 34913, 35114, michael@0: 35122, 35109, 35115, 35105, 35242, [35238, 58391], 35558, 35578, 35563, michael@0: 35569, 35584, 35548, 35559, 35566, 35582, {f: 2, c: 35585}, 35575, 35565, michael@0: 35571, 35574, 35580, 35947, 35949, 35987, 36084, 36420, 36401, 36404, michael@0: 36418, 36409, 36405, 36667, 36655, 36664, 36659, 36776, 36774, 36981, michael@0: 36980, 36984, 36978, 36988, 36986, 37172, 37266, 37664, 37686, 37624, michael@0: 37683, 37679, 37666, 37628, 37675, 37636, 37658, 37648, 37670, 37665, michael@0: 37653, 37678, 37657, 38331, {f: 2, c: 38567}, 38570, 38613, 38670, 38673, michael@0: 38678, 38669, 38675, 38671, 38747, [38748, 58565], 38758, 38808, 38960, michael@0: 38968, 38971, 38967, 38957, 38969, 38948, 39184, 39208, 39198, 39195, michael@0: 39201, 39194, 39405, 39394, 39409, 39608, 39612, 39675, 39661, 39720, michael@0: 39825, 40213, 40227, 40230, 40232, 40210, 40219, 40664, 40660, michael@0: [12243, 40845], [12244, 40860], 20778, 20767, 20769, 20786, 21237, 22158, michael@0: 22144, 22160, 22149, 22151, 22159, 22741, 22739, 22737, 22734, 23344, michael@0: 23338, 23332, 23418, 23607, 23656, 23996, 23994, 23997, 23992, 24171, michael@0: 24396, 24509, 25033, 25026, 25031, 25062, 25035, 25138, 25140, 25806, michael@0: 25802, 25816, 25824, 25840, 25830, 25836, 25841, 25826, 25837, michael@0: {f: 2, c: 25986}, 26329, 26326, 27264, 27284, 27268, 27298, 27292, 27355, michael@0: 27299, 27262, 27287, 27280, 27296, 27484, 27566, 27610, 27656, 28632, michael@0: 28657, {f: 2, c: 28639}, 28635, 28644, 28651, 28655, 28544, 28652, 28641, michael@0: 28649, 28629, 28654, 28656, 29159, [29151, 60361], 29166, 29158, 29157, michael@0: 29165, 29164, 29172, 29152, 29237, 29254, 29552, 29554, 29865, 29872, michael@0: 29862, 29864, 30278, 30274, 30284, 30442, 30643, 30634, 30640, 30636, michael@0: 30631, 30637, 30703, 30967, 30970, 30964, 30959, 30977, 31143, 31146, michael@0: 31319, 31423, 31751, 31757, 31742, 31735, 31756, 31712, 31968, 31964, michael@0: 31966, 31970, 31967, 31961, 31965, 32302, 32318, 32326, 32311, 32306, michael@0: 32323, 32299, 32317, 32305, 32325, 32321, 32308, 32313, 32328, 32309, michael@0: 32319, 32303, 32580, 32755, 32764, {f: 2, c: 32881}, 32880, 32879, 32883, michael@0: 33222, 33219, 33210, 33218, 33216, 33215, 33213, 33225, 33214, 33256, michael@0: 33289, 33393, 34218, 34180, 34174, 34204, 34193, 34196, 34223, 34203, michael@0: 34183, 34216, 34186, 34214, 34407, 34752, 34769, 34739, 34770, 34758, michael@0: 34731, 34747, 34746, 34760, 34763, 35131, 35126, 35140, 35128, 35133, michael@0: 35244, 35598, 35607, 35609, 35611, 35594, 35616, 35613, 35588, 35600, michael@0: 35905, 35903, 35955, 36090, 36093, 36092, 36088, 36091, 36264, 36425, michael@0: 36427, 36424, 36426, 36676, 36670, 36674, 36677, 36671, 36991, 36989, michael@0: 36996, {f: 2, c: 36993}, 36992, 37177, 37283, 37278, 37276, 37709, 37762, michael@0: 37672, 37749, 37706, 37733, 37707, 37656, 37758, 37740, 37723, 37744, michael@0: 37722, 37716, {f: 3, c: 38346}, 38344, 38342, 38577, 38584, 38614, 38684, michael@0: 38686, 38816, 38867, 38982, 39094, 39221, 39425, 39423, 39854, 39851, michael@0: 39850, 39853, 40251, 40255, 40587, 40655, 40670, {f: 2, c: 40668}, 40667, michael@0: 40766, 40779, 21474, 22165, 22190, 22745, 22744, 23352, 24413, 25059, michael@0: 25139, 25844, 25842, 25854, 25862, {f: 2, c: 25850}, 25847, 26039, 26332, michael@0: 26406, 27315, 27308, 27331, 27323, 27320, 27330, {f: 2, c: 27310}, 27487, michael@0: 27512, 27567, 28681, 28683, 28670, 28678, 28666, 28689, 28687, michael@0: {f: 2, c: 29179}, 29182, 29176, 29559, 29557, 29863, 29887, 29973, 30294, michael@0: 30296, 30290, 30653, 30655, {f: 2, c: 30651}, 30990, 31150, michael@0: {f: 2, c: 31329}, 31328, {f: 2, c: 31428}, 31787, 31783, 31786, 31774, michael@0: 31779, 31777, 31975, {f: 2, c: 32340}, 32350, 32346, 32353, 32338, 32345, michael@0: 32584, 32761, 32763, 32887, 32886, 33229, 33231, 33290, 34255, 34217, michael@0: 34253, 34256, 34249, 34224, 34234, 34233, 34799, 34796, 34802, 34784, michael@0: 35206, 35250, 35316, 35624, 35641, 35628, 35627, 35920, 36101, 36441, michael@0: 36451, 36454, 36452, 36447, 36437, 36544, 36681, 36685, 36999, 36995, michael@0: 37000, {f: 2, c: 37291}, 37328, 37780, 37770, 37782, 37794, 37811, 37806, michael@0: 37804, 37808, 37784, 37786, 37783, 38356, 38358, 38352, 38357, 38626, michael@0: 38620, 38617, 38619, 38622, 38692, 38819, 38822, 38829, 38905, 38989, michael@0: 38991, 38988, 38990, 38995, 39098, {f: 2, c: 39230}, 39229, 39214, 39333, michael@0: 39438, 39617, 39683, 39686, 39759, 39758, 39757, 39882, 39881, 39933, michael@0: 39880, 39872, 40273, 40285, 40288, 40672, 40725, 40748, 20787, 22181, michael@0: 22184, {f: 2, c: 22750}, 22754, 23541, 40848, 24300, 25074, 25079, 25078, michael@0: 25077, 25856, 25871, 26336, 26333, 27365, 27357, 27354, 27347, 28699, michael@0: 28703, 28712, 28698, 28701, 28693, 28696, 29190, 29197, 29272, 29346, michael@0: 29560, 29562, 29885, 29898, 29923, 30087, 30086, 30303, 30305, 30663, michael@0: 31001, 31153, 31339, 31337, {f: 2, c: 31806}, 31800, 31805, 31799, 31808, michael@0: 32363, 32365, 32377, {f: 2, c: 32361}, 32371, 32645, 32694, 32697, 32696, michael@0: 33240, 34281, 34269, 34282, 34261, {f: 2, c: 34276}, 34295, 34811, 34821, michael@0: 34829, 34809, 34814, 35168, 35167, 35158, 35166, 35649, 35676, 35672, michael@0: 35657, 35674, {f: 2, c: 35662}, 35654, 35673, 36104, 36106, 36476, 36466, michael@0: 36487, 36470, 36460, 36474, 36468, 36692, 36686, 36781, {f: 2, c: 37002}, michael@0: 37297, 37294, 37857, 37841, 37855, 37827, 37832, {f: 2, c: 37852}, 37846, michael@0: 37858, 37837, 37848, 37860, 37847, 37864, 38364, 38580, 38627, 38698, michael@0: 38695, 38753, 38876, 38907, 39006, 39000, 39003, 39100, 39237, 39241, michael@0: 39446, 39449, 39693, 39912, 39911, 39894, 39899, 40329, 40289, 40306, michael@0: 40298, 40300, 40594, 40599, 40595, 40628, 21240, 22199, 22198, 22196, michael@0: 22204, 22756, 23360, 23363, 23421, 23542, 24009, 25080, 25082, 25880, michael@0: 25876, 25881, 26342, 26407, 27372, 28734, 28720, 28722, 29200, 29563, michael@0: 29903, 30306, 30309, 31014, 31018, 31020, 31019, 31431, 31478, 31820, michael@0: 31811, 31821, {f: 2, c: 31983}, 36782, 32381, 32380, 32386, 32588, 32768, michael@0: 33242, 33382, 34299, 34297, 34321, 34298, 34310, 34315, 34311, 34314, michael@0: {f: 2, c: 34836}, 35172, 35258, 35320, 35696, 35692, 35686, 35695, 35679, michael@0: 35691, 36111, 36109, 36489, 36481, 36485, 36482, 37300, 37323, 37912, michael@0: 37891, 37885, 38369, 38704, 39108, 39250, 39249, 39336, 39467, 39472, michael@0: 39479, 39477, 39955, 39949, 40569, 40629, 40680, 40751, 40799, 40803, michael@0: 40801, {f: 2, c: 20791}, 22209, 22208, 22210, 22804, 23660, 24013, 25084, michael@0: 25086, 25885, 25884, 26005, 26345, 27387, 27396, 27386, 27570, 28748, michael@0: 29211, 29351, 29910, 29908, 30313, 30675, 31824, 32399, 32396, 32700, michael@0: 34327, 34349, 34330, 34851, 34850, 34849, 34847, 35178, 35180, 35261, michael@0: 35700, 35703, 35709, 36115, 36490, 36493, 36491, 36703, 36783, 37306, michael@0: 37934, 37939, 37941, 37946, 37944, 37938, 37931, 38370, {f: 2, c: 38712}, michael@0: 38706, [38911, 58586], 39015, 39013, 39255, 39493, 39491, 39488, 39486, michael@0: 39631, 39764, 39761, 39981, 39973, 40367, 40372, 40386, 40376, 40605, michael@0: 40687, 40729, 40796, {f: 2, c: 40806}, 20796, 20795, 22216, 22218, 22217, michael@0: 23423, 24020, 24018, 24398, 25087, 25892, 27402, 27489, 28753, 28760, michael@0: 29568, 29924, 30090, 30318, 30316, 31155, 31840, 31839, 32894, 32893, michael@0: 33247, 35186, 35183, 35324, 35712, {f: 2, c: 36118}, 36497, 36499, 36705, michael@0: 37192, 37956, {f: 2, c: 37969}, {f: 2, c: 38717}, 38851, 38849, 39019, michael@0: 39253, 39509, 39501, 39634, 39706, 40009, 39985, 39998, 39995, 40403, michael@0: 40407, 40756, 40812, 40810, 40852, 22220, 24022, 25088, 25891, 25899, michael@0: 25898, 26348, 27408, 29914, 31434, 31844, 31843, 31845, 32403, 32406, michael@0: 32404, 33250, 34360, 34367, 34865, 35722, 37008, 37007, 37987, 37984, michael@0: 37988, 38760, 39023, 39260, {f: 2, c: 39514}, 39511, {f: 2, c: 39635}, michael@0: 39633, 40020, 40023, 40022, 40421, 40607, 40692, 22225, 22761, 25900, michael@0: 28766, {f: 2, c: 30321}, [30679, 60226], 32592, 32648, 34870, 34873, 34914, michael@0: 35731, 35730, 35734, 33399, 36123, 37312, 37994, 38722, 38728, 38724, michael@0: 38854, 39024, 39519, 39714, 39768, 40031, {f: 2, c: 40441}, michael@0: {f: 2, c: 40572}, 40711, 40823, 40818, 24307, 27414, 28771, 31852, 31854, michael@0: 34875, 35264, 36513, 37313, 38002, 38000, 39025, 39262, 39638, 39715, michael@0: 40652, 28772, 30682, 35738, 38007, 38857, 39522, 39525, 32412, 35740, michael@0: 36522, 37317, {f: 2, c: 38013}, 38012, {f: 2, c: 40055}, 40695, 35924, michael@0: 38015, 40474, 29224, 39530, 39729, 40475, 40478, 31858, 20034, 20060, michael@0: [12048, 20981], [12053, 21274], [12058, 21378], 19975, 19980, 20039, 20109, michael@0: [12062, 22231], [12076, 23662], [12091, 24435], 19983, 20871, 19982, 20014, michael@0: 20115, 20162, 20169, 20168, 20888, 21244, 21356, 21433, 22304, 22787, michael@0: 22828, [23568, 60417], 24063, 26081, [12110, 27571], 27596, [12115, 27668], michael@0: [12121, 29247], 20017, 20028, 20200, 20188, 20201, 20193, 20189, 20186, michael@0: 21004, 21001, 21276, 21324, {f: 2, c: 22306}, 22807, 22831, 23425, 23428, michael@0: 23570, 23611, 23668, 23667, 24068, 24192, 24194, 24521, 25097, 25168, michael@0: 27669, 27702, 27715, 27711, 27707, 29358, 29360, 29578, [12145, 31160], michael@0: 32906, 38430, 20238, 20248, 20268, 20213, 20244, 20209, 20224, 20215, michael@0: 20232, 20253, 20226, 20229, 20258, 20243, 20228, 20212, 20242, 20913, michael@0: 21011, 21008, 21158, 21282, 21279, 21325, 21386, 21511, 22241, 22239, michael@0: 22318, 22314, 22324, 22844, 22912, 22908, 22917, 22907, 22910, 22903, michael@0: 22911, 23382, 23573, 23589, 23676, {f: 2, c: 23674}, 23678, 24031, michael@0: [24181, 57646], 24196, 24322, 24346, 24436, 24533, 24532, 24527, 25180, michael@0: 25182, 25188, 25185, 25190, 25186, 25177, 25184, 25178, 25189, 25911, michael@0: 26095, 26094, 26430, 26425, 26424, 26427, 26426, 26431, 26428, 26419, michael@0: 27672, 27718, 27730, 27740, 27727, [27722, 60796], 27732, {f: 2, c: 27723}, michael@0: 28785, 29278, {f: 2, c: 29364}, 29582, 29994, 30335, 31349, [12153, 32593], michael@0: [12171, 33400], 33404, 33408, 33405, 33407, [12172, 34381], [12177, 35198], michael@0: 37017, [37015, 59347], 37016, 37019, 37012, 38434, 38436, 38432, 38435, michael@0: 20310, 20283, 20322, 20297, 20307, 20324, 20286, 20327, 20306, 20319, michael@0: 20289, 20312, 20269, 20275, 20287, 20321, 20879, 20921, 21020, 21022, michael@0: 21025, {f: 2, c: 21165}, 21257, 21347, 21362, {f: 2, c: 21390}, 21552, michael@0: 21559, 21546, 21588, 21573, 21529, 21532, 21541, 21528, 21565, 21583, michael@0: 21569, 21544, 21540, 21575, 22254, 22247, 22245, 22337, 22341, 22348, michael@0: 22345, 22347, 22354, 22790, 22848, 22950, 22936, 22944, 22935, 22926, michael@0: 22946, 22928, 22927, 22951, 22945, 23438, 23442, 23592, 23594, 23693, michael@0: 23695, 23688, 23691, 23689, 23698, 23690, 23686, 23699, 23701, 24032, michael@0: 24074, 24078, 24203, 24201, 24204, 24200, 24205, 24325, 24349, 24440, michael@0: 24438, 24530, 24529, 24528, 24557, 24552, 24558, 24563, 24545, 24548, michael@0: 24547, 24570, 24559, 24567, 24571, 24576, 24564, 25146, 25219, 25228, michael@0: {f: 2, c: 25230}, 25236, 25223, 25201, 25211, 25210, 25200, 25217, 25224, michael@0: 25207, 25213, 25202, 25204, 26096, 26100, 26099, 26098, 26101, 26437, michael@0: 26439, 26457, 26453, 26444, 26440, 26461, 26445, 26458, 26443, 27600, michael@0: {f: 2, c: 27673}, 27768, 27751, 27755, 27780, 27787, 27791, 27761, 27759, michael@0: 27753, 27802, 27757, 27783, 27797, [27804, 57900], 27750, 27763, 27749, michael@0: 27771, 27790, 28788, 28794, 29283, 29375, 29373, 29379, 29382, 29377, michael@0: 29370, 29381, 29589, 29591, {f: 2, c: 29587}, 29586, 30010, 30009, michael@0: {f: 2, c: 30100}, 30337, 31037, 32820, 32917, 32921, 32912, 32914, 32924, michael@0: 33424, 33423, 33413, 33422, 33425, 33427, 33418, {f: 2, c: 33411}, michael@0: [12184, 35960], 36809, 36799, 37023, 37025, 37029, 37022, 37031, 37024, michael@0: 38448, 38440, 38447, 38445, 20019, 20376, 20348, 20357, 20349, 20352, michael@0: 20359, 20342, 20340, 20361, 20356, 20343, 20300, 20375, 20330, 20378, michael@0: 20345, 20353, 20344, 20368, 20380, 20372, 20382, 20370, 20354, 20373, michael@0: 20331, 20334, 20894, 20924, 20926, 21045, {f: 2, c: 21042}, 21062, 21041, michael@0: 21180, {f: 2, c: 21258}, 21308, 21394, 21396, 21639, 21631, 21633, 21649, michael@0: 21634, 21640, 21611, 21626, 21630, 21605, 21612, 21620, 21606, 21645, michael@0: 21615, 21601, 21600, 21656, 21603, 21607, 21604, 22263, 22265, 22383, michael@0: 22386, 22381, 22379, 22385, 22384, 22390, 22400, 22389, 22395, michael@0: {f: 2, c: 22387}, 22370, 22376, 22397, 22796, 22853, 22965, 22970, 22991, michael@0: 22990, 22962, 22988, 22977, 22966, 22972, 22979, 22998, 22961, 22973, michael@0: 22976, 22984, 22964, 22983, 23394, 23397, 23443, 23445, 23620, 23623, michael@0: 23726, 23716, 23712, 23733, 23727, 23720, 23724, 23711, 23715, 23725, michael@0: 23714, 23722, 23719, 23709, 23717, 23734, 23728, 23718, 24087, 24084, michael@0: 24089, 24360, {f: 3, c: 24354}, 24404, 24450, 24446, 24445, 24542, 24549, michael@0: 24621, 24614, 24601, 24626, 24587, 24628, 24586, 24599, 24627, 24602, michael@0: 24606, 24620, 24610, 24589, 24592, 24622, 24595, 24593, 24588, 24585, michael@0: 24604, 25108, 25149, 25261, 25268, 25297, 25278, 25258, 25270, 25290, michael@0: 25262, 25267, 25263, 25275, 25257, 25264, 25272, 25917, 26024, 26043, michael@0: 26121, 26108, 26116, 26130, 26120, 26107, 26115, 26123, 26125, 26117, michael@0: 26109, 26129, 26128, 26358, 26378, 26501, 26476, 26510, 26514, 26486, michael@0: 26491, 26520, 26502, 26500, 26484, 26509, 26508, 26490, 26527, 26513, michael@0: 26521, 26499, 26493, 26497, {f: 2, c: 26488}, 26516, 27429, 27520, 27518, michael@0: 27614, 27677, 27795, 27884, 27883, 27886, 27865, 27830, 27860, 27821, michael@0: 27879, 27831, 27856, 27842, 27834, 27843, 27846, 27885, 27890, 27858, michael@0: 27869, 27828, 27786, 27805, 27776, 27870, 27840, 27952, 27853, 27847, michael@0: 27824, 27897, 27855, 27881, 27857, 28820, 28824, 28805, 28819, 28806, michael@0: 28804, 28817, 28822, 28802, 28826, 28803, 29290, 29398, 29387, 29400, michael@0: 29385, 29404, 29394, 29396, 29402, 29388, 29393, 29604, 29601, 29613, michael@0: 29606, 29602, 29600, 29612, 29597, 29917, 29928, {f: 2, c: 30015}, 30014, michael@0: 30092, 30104, 30383, 30451, 30449, 30448, 30453, 30712, 30716, 30713, michael@0: 30715, 30714, 30711, 31042, 31039, 31173, 31352, 31355, 31483, 31861, michael@0: 31997, 32821, 32911, 32942, 32931, 32952, 32949, 32941, 33312, 33440, michael@0: 33472, 33451, 33434, 33432, 33435, 33461, 33447, 33454, 33468, 33438, michael@0: 33466, 33460, 33448, 33441, 33449, 33474, 33444, 33475, 33462, 33442, michael@0: 34416, 34415, {f: 2, c: 34413}, 35926, 36818, 36811, 36819, 36813, 36822, michael@0: 36821, 36823, 37042, 37044, 37039, 37043, 37040, 38457, 38461, 38460, michael@0: 38458, 38467, 20429, 20421, 20435, 20402, 20425, 20427, 20417, 20436, michael@0: 20444, 20441, [20411, 60346], 20403, 20443, 20423, 20438, 20410, 20416, michael@0: 20409, 20460, 21060, 21065, 21184, 21186, 21309, 21372, 21399, 21398, michael@0: 21401, 21400, 21690, 21665, 21677, 21669, 21711, 21699, 33549, 21687, michael@0: 21678, 21718, 21686, {f: 2, c: 21701}, 21664, 21616, 21692, 21666, 21694, michael@0: 21618, 21726, 21680, 22453, {f: 2, c: 22430}, 22436, 22412, 22423, 22429, michael@0: 22427, 22420, 22424, 22415, 22425, 22437, 22426, 22421, 22772, 22797, michael@0: 22867, 23009, 23006, 23022, 23040, 23025, 23005, 23034, 23037, 23036, michael@0: 23030, 23012, 23026, 23031, 23003, 23017, 23027, 23029, 23008, 23038, michael@0: 23028, 23021, 23464, 23628, 23760, 23768, 23756, 23767, 23755, 23771, michael@0: 23774, 23770, 23753, 23751, 23754, 23766, {f: 2, c: 23763}, 23759, 23752, michael@0: 23750, 23758, 23775, 23800, 24057, {f: 3, c: 24097}, 24096, 24100, 24240, michael@0: 24228, 24226, 24219, 24227, 24229, 24327, 24366, 24406, 24454, 24631, michael@0: 24633, 24660, 24690, 24670, 24645, 24659, 24647, 24649, 24667, 24652, michael@0: 24640, 24642, 24671, 24612, 24644, 24664, 24678, 24686, {f: 2, c: 25154}, michael@0: 25295, 25357, 25355, 25333, 25358, 25347, 25323, 25337, 25359, 25356, michael@0: 25336, 25334, 25344, {f: 2, c: 25363}, 25338, 25365, 25339, 25328, 25921, michael@0: 25923, 26026, 26047, 26166, 26145, 26162, 26165, 26140, 26150, 26146, michael@0: 26163, 26155, 26170, 26141, 26164, 26169, 26158, {f: 2, c: 26383}, 26561, michael@0: 26610, 26568, 26554, 26588, 26555, 26616, 26584, 26560, 26551, 26565, michael@0: 26603, 26596, 26591, 26549, 26573, 26547, 26615, 26614, 26606, 26595, michael@0: 26562, 26553, 26574, 26599, 26608, 26546, 26620, 26566, 26605, 26572, michael@0: 26542, 26598, 26587, 26618, {f: 2, c: 26569}, 26563, 26602, 26571, 27432, michael@0: 27522, 27524, 27574, 27606, 27608, 27616, {f: 2, c: 27680}, 27944, 27956, michael@0: 27949, 27935, 27964, 27967, 27922, 27914, 27866, 27955, 27908, 27929, michael@0: 27962, 27930, 27921, 27904, 27933, 27970, 27905, 27928, 27959, 27907, michael@0: 27919, 27968, 27911, 27936, 27948, 27912, 27938, 27913, 27920, 28855, michael@0: 28831, 28862, 28849, 28848, 28833, {f: 2, c: 28852}, 28841, 29249, michael@0: {f: 2, c: 29257}, 29292, 29296, 29299, 29294, 29386, 29412, 29416, 29419, michael@0: 29407, 29418, 29414, 29411, 29573, 29644, 29634, 29640, 29637, 29625, michael@0: 29622, 29621, 29620, 29675, 29631, 29639, 29630, 29635, 29638, 29624, michael@0: 29643, 29932, 29934, 29998, {f: 2, c: 30023}, 30119, 30122, 30329, 30404, michael@0: 30472, {f: 3, c: 30467}, 30474, 30455, 30459, 30458, {f: 2, c: 30695}, michael@0: 30726, {f: 2, c: 30737}, 30725, 30736, 30735, 30734, [30729, 58095], 30723, michael@0: 30739, 31050, 31052, 31051, 31045, 31044, 31189, 31181, 31183, 31190, michael@0: 31182, 31360, 31358, 31441, {f: 2, c: 31488}, 31866, {f: 2, c: 31864}, michael@0: {f: 3, c: 31871}, 32003, 32008, 32001, 32600, 32657, 32653, 32702, 32775, michael@0: {f: 2, c: 32782}, 32788, 32823, 32984, 32967, 32992, 32977, 32968, 32962, michael@0: 32976, 32965, 32995, 32985, 32988, 32970, 32981, 32969, 32975, 32983, michael@0: 32998, 32973, 33279, 33313, 33428, 33497, 33534, 33529, 33543, 33512, michael@0: 33536, 33493, 33594, 33515, 33494, 33524, 33516, 33505, 33522, 33525, michael@0: 33548, 33531, 33526, 33520, 33514, 33508, 33504, 33530, 33523, 33517, michael@0: 34423, 34420, 34428, 34419, 34881, 34894, 34919, 34922, 34921, 35283, michael@0: 35332, 35335, 36210, 36835, 36833, 36846, 36832, 37105, 37053, 37055, michael@0: 37077, 37061, 37054, 37063, 37067, 37064, [37332, 60294], 37331, 38484, michael@0: 38479, 38481, 38483, 38474, 38478, 20510, 20485, 20487, 20499, 20514, michael@0: 20528, 20507, 20469, 20468, 20531, 20535, 20524, {f: 2, c: 20470}, 20503, michael@0: 20508, 20512, 20519, 20533, 20527, 20529, 20494, 20826, 20884, 20883, michael@0: 20938, {f: 2, c: 20932}, 20936, 20942, 21089, 21082, 21074, michael@0: {f: 2, c: 21086}, 21077, 21090, 21197, 21262, 21406, 21798, 21730, 21783, michael@0: 21778, 21735, 21747, 21732, 21786, 21759, 21764, 21768, 21739, 21777, michael@0: 21765, 21745, 21770, 21755, {f: 2, c: 21751}, 21728, 21774, 21763, 21771, michael@0: {f: 2, c: 22273}, 22476, 22578, 22485, 22482, 22458, 22470, 22461, 22460, michael@0: 22456, 22454, 22463, 22471, 22480, 22457, 22465, 22798, 22858, 23065, michael@0: 23062, {f: 2, c: 23085}, 23061, 23055, 23063, 23050, 23070, 23091, 23404, michael@0: 23463, 23469, 23468, 23555, 23638, 23636, 23788, 23807, 23790, 23793, michael@0: 23799, 23808, 23801, 24105, 24104, 24232, 24238, 24234, 24236, 24371, michael@0: 24368, 24423, 24669, 24666, 24679, 24641, 24738, 24712, 24704, 24722, michael@0: 24705, 24733, 24707, 24725, 24731, 24727, 24711, 24732, 24718, 25113, michael@0: 25158, 25330, 25360, 25430, 25388, {f: 2, c: 25412}, 25398, 25411, 25572, michael@0: 25401, 25419, 25418, 25404, 25385, 25409, 25396, 25432, 25428, 25433, michael@0: 25389, 25415, 25395, 25434, 25425, 25400, 25431, 25408, 25416, 25930, michael@0: 25926, 26054, {f: 2, c: 26051}, 26050, 26186, 26207, 26183, 26193, michael@0: {f: 2, c: 26386}, 26655, 26650, 26697, {f: 2, c: 26674}, 26683, 26699, michael@0: 26703, 26646, 26673, 26652, 26677, 26667, 26669, 26671, 26702, 26692, michael@0: 26676, 26653, 26642, 26644, 26662, 26664, 26670, 26701, 26682, 26661, michael@0: 26656, 27436, 27439, 27437, 27441, 27444, 27501, 32898, 27528, 27622, michael@0: 27620, 27624, 27619, 27618, 27623, 27685, 28026, {f: 2, c: 28003}, 28022, michael@0: 27917, 28001, 28050, 27992, 28002, 28013, 28015, 28049, 28045, 28143, michael@0: 28031, 28038, 27998, [28007, 59078], 28000, 28055, 28016, 28028, 27999, michael@0: 28034, 28056, 27951, 28008, 28043, 28030, 28032, 28036, 27926, 28035, michael@0: 28027, 28029, 28021, 28048, 28892, 28883, 28881, 28893, 28875, 32569, michael@0: 28898, 28887, 28882, 28894, 28896, 28884, 28877, {f: 3, c: 28869}, 28890, michael@0: 28878, 28897, 29250, 29304, 29303, 29302, 29440, 29434, 29428, 29438, michael@0: 29430, 29427, 29435, 29441, 29651, 29657, 29669, 29654, 29628, 29671, michael@0: 29667, 29673, 29660, 29650, 29659, 29652, 29661, 29658, {f: 2, c: 29655}, michael@0: 29672, {f: 2, c: 29918}, {f: 2, c: 29940}, 29985, 30043, 30047, 30128, michael@0: 30145, 30139, 30148, 30144, 30143, 30134, 30138, 30346, 30409, 30493, michael@0: 30491, 30480, 30483, 30482, 30499, 30481, 30485, {f: 2, c: 30489}, 30498, michael@0: 30503, 30755, 30764, 30754, 30773, 30767, 30760, 30766, 30763, 30753, michael@0: 30761, 30771, 30762, 30769, 31060, 31067, 31055, 31068, 31059, 31058, michael@0: 31057, {f: 2, c: 31211}, 31200, 31214, 31213, 31210, 31196, 31198, 31197, michael@0: 31366, 31369, 31365, {f: 2, c: 31371}, 31370, 31367, 31448, 31504, 31492, michael@0: 31507, 31493, 31503, 31496, 31498, 31502, 31497, 31506, 31876, 31889, michael@0: 31882, 31884, 31880, 31885, 31877, 32030, 32029, 32017, 32014, 32024, michael@0: 32022, 32019, 32031, 32018, 32015, 32012, 32604, 32609, 32606, 32608, michael@0: 32605, 32603, 32662, 32658, 32707, 32706, 32704, 32790, 32830, 32825, michael@0: 33018, 33010, 33017, 33013, 33025, 33019, 33024, 33281, 33327, 33317, michael@0: 33587, 33581, 33604, 33561, 33617, 33573, 33622, 33599, 33601, 33574, michael@0: 33564, 33570, 33602, 33614, 33563, 33578, 33544, 33596, 33613, 33558, michael@0: 33572, 33568, 33591, 33583, 33577, 33607, 33605, 33612, 33619, 33566, michael@0: 33580, 33611, 33575, 33608, 34387, 34386, 34466, 34472, 34454, 34445, michael@0: 34449, 34462, 34439, 34455, 34438, 34443, 34458, 34437, 34469, 34457, michael@0: 34465, 34471, 34453, 34456, 34446, 34461, 34448, 34452, {f: 2, c: 34883}, michael@0: 34925, {f: 2, c: 34933}, 34930, 34944, 34929, 34943, 34927, 34947, 34942, michael@0: 34932, 34940, 35346, 35911, 35927, 35963, 36004, 36003, 36214, 36216, michael@0: 36277, 36279, 36278, 36561, 36563, 36862, 36853, 36866, 36863, 36859, michael@0: 36868, 36860, 36854, 37078, 37088, {f: 2, c: 37081}, 37091, 37087, 37093, michael@0: 37080, 37083, 37079, 37084, 37092, 37200, {f: 2, c: 37198}, 37333, 37346, michael@0: 37338, 38492, 38495, 38588, 39139, [12221, 39647], [12223, 39727], 20095, michael@0: 20592, 20586, 20577, 20574, 20576, 20563, 20555, 20573, 20594, 20552, michael@0: 20557, 20545, 20571, 20554, 20578, 20501, 20549, 20575, 20585, 20587, michael@0: {f: 2, c: 20579}, 20550, 20544, 20590, 20595, 20567, 20561, 20944, 21099, michael@0: 21101, 21100, 21102, 21206, 21203, 21293, 21404, {f: 2, c: 21877}, 21820, michael@0: 21837, 21840, 21812, 21802, 21841, 21858, 21814, 21813, 21808, 21842, michael@0: 21829, 21772, 21810, 21861, 21838, 21817, 21832, 21805, 21819, 21824, michael@0: 21835, 22282, 22279, 22523, 22548, 22498, 22518, 22492, 22516, 22528, michael@0: 22509, 22525, 22536, 22520, 22539, 22515, 22479, 22535, 22510, 22499, michael@0: 22514, 22501, 22508, 22497, 22542, 22524, 22544, 22503, 22529, 22540, michael@0: 22513, 22505, 22512, 22541, 22532, 22876, 23136, 23128, 23125, michael@0: [23143, 60437], 23134, 23096, 23093, 23149, 23120, 23135, 23141, 23148, michael@0: 23123, 23140, 23127, 23107, 23133, 23122, 23108, 23131, 23112, 23182, michael@0: 23102, 23117, 23097, 23116, 23152, 23145, 23111, 23121, 23126, 23106, michael@0: 23132, 23410, 23406, 23489, 23488, 23641, 23838, 23819, 23837, 23834, michael@0: 23840, 23820, 23848, 23821, 23846, 23845, 23823, 23856, 23826, 23843, michael@0: 23839, 23854, 24126, 24116, 24241, 24244, 24249, {f: 2, c: 24242}, 24374, michael@0: 24376, 24475, 24470, 24479, 24714, 24720, 24710, 24766, 24752, 24762, michael@0: {f: 2, c: 24787}, 24783, 24804, 24793, 24797, 24776, 24753, 24795, 24759, michael@0: 24778, 24767, 24771, 24781, 24768, 25394, 25445, 25482, 25474, 25469, michael@0: 25533, 25502, 25517, 25501, 25495, 25515, 25486, 25455, 25479, 25488, michael@0: 25454, 25519, 25461, 25500, 25453, 25518, 25468, 25508, 25403, 25503, michael@0: 25464, 25477, 25473, 25489, 25485, 25456, 25939, 26061, 26213, 26209, michael@0: 26203, 26201, 26204, 26210, 26392, 26745, 26759, 26768, 26780, michael@0: {f: 2, c: 26733}, 26798, 26795, 26966, 26735, 26787, 26796, 26793, 26741, michael@0: 26740, 26802, 26767, 26743, 26770, 26748, 26731, 26738, 26794, 26752, michael@0: 26737, 26750, 26779, 26774, 26763, 26784, 26761, 26788, 26744, 26747, michael@0: 26769, 26764, 26762, 26749, 27446, 27443, {f: 2, c: 27447}, 27537, 27535, michael@0: {f: 2, c: 27533}, 27532, 27690, 28096, 28075, 28084, 28083, 28276, 28076, michael@0: 28137, 28130, 28087, 28150, 28116, 28160, 28104, 28128, 28127, 28118, michael@0: 28094, 28133, {f: 2, c: 28124}, 28123, 28148, 28106, 28093, 28141, 28144, michael@0: 28090, 28117, 28098, 28111, 28105, 28112, 28146, 28115, 28157, 28119, michael@0: 28109, 28131, 28091, 28922, 28941, 28919, 28951, 28916, 28940, 28912, michael@0: 28932, 28915, 28944, 28924, 28927, 28934, 28947, 28928, 28920, 28918, michael@0: 28939, 28930, 28942, 29310, {f: 2, c: 29307}, 29311, 29469, 29463, 29447, michael@0: 29457, 29464, 29450, 29448, 29439, 29455, 29470, 29576, 29686, 29688, michael@0: 29685, 29700, 29697, 29693, 29703, 29696, 29690, 29692, 29695, 29708, michael@0: 29707, 29684, 29704, 30052, 30051, 30158, 30162, 30159, {f: 2, c: 30155}, michael@0: 30161, 30160, 30351, 30345, 30419, 30521, 30511, 30509, {f: 2, c: 30513}, michael@0: 30516, 30515, 30525, 30501, 30523, 30517, 30792, 30802, 30793, 30797, michael@0: 30794, 30796, 30758, 30789, 30800, 31076, 31079, {f: 2, c: 31081}, 31075, michael@0: 31083, 31073, 31163, 31226, 31224, {f: 2, c: 31222}, 31375, 31380, 31376, michael@0: 31541, 31547, 31540, 31525, 31536, 31522, 31524, 31539, 31512, 31530, michael@0: 31517, 31537, 31531, 31533, 31535, 31538, 31544, 31514, 31523, 31892, michael@0: 31896, 31894, 31907, 32053, 32061, 32056, 32054, 32058, 32069, 32044, michael@0: 32041, 32065, 32071, {f: 2, c: 32062}, 32074, 32059, 32040, 32611, 32661, michael@0: {f: 2, c: 32668}, 32667, {f: 2, c: 32714}, 32717, {f: 2, c: 32720}, 32711, michael@0: 32719, 32713, 32799, 32798, 32795, 32839, 32835, 32840, 33048, 33061, michael@0: 33049, 33051, 33069, 33055, 33068, 33054, 33057, 33045, 33063, 33053, michael@0: 33058, 33297, 33336, 33331, 33338, 33332, 33330, 33396, 33680, 33699, michael@0: 33704, 33677, 33658, 33651, 33700, 33652, 33679, 33665, 33685, 33689, michael@0: 33653, 33684, 33705, 33661, 33667, 33676, 33693, 33691, 33706, 33675, michael@0: 33662, 33701, 33711, 33672, 33687, 33712, 33663, 33702, 33671, 33710, michael@0: 33654, 34393, 34390, 34495, 34487, 34498, 34497, 34501, 34490, 34480, michael@0: 34504, 34489, 34483, 34488, 34508, 34484, {f: 2, c: 34491}, 34499, michael@0: {f: 2, c: 34493}, 34898, 34953, 34965, 34984, 34978, 34986, 34970, 34961, michael@0: 34977, 34975, 34968, 34983, 34969, 34971, 34967, 34980, 34988, 34956, michael@0: 34963, 34958, 35202, 35286, 35289, 35285, 35376, 35367, 35372, 35358, michael@0: 35897, 35899, {f: 2, c: 35932}, 35965, 36005, 36221, 36219, 36217, 36284, michael@0: 36290, 36281, 36287, 36289, 36568, 36574, 36573, 36572, 36567, michael@0: {f: 2, c: 36576}, 36900, 36875, 36881, 36892, 36876, 36897, 37103, 37098, michael@0: 37104, 37108, {f: 2, c: 37106}, 37076, {f: 2, c: 37099}, 37097, 37206, michael@0: 37208, 37210, 37203, 37205, 37356, 37364, 37361, 37363, 37368, 37348, michael@0: 37369, {f: 2, c: 37354}, 37367, 37352, 37358, 38266, 38278, 38280, 38524, michael@0: 38509, 38507, 38513, 38511, 38591, 38762, 38916, 39141, 39319, 20635, michael@0: 20629, 20628, 20638, 20619, 20643, 20611, 20620, 20622, 20637, 20584, michael@0: 20636, 20626, 20610, 20615, 20831, 20948, 21266, 21265, 21412, 21415, michael@0: 21905, 21928, 21925, 21933, 21879, 22085, 21922, 21907, 21896, 21903, michael@0: 21941, 21889, 21923, 21906, 21924, 21885, 21900, 21926, 21887, 21909, michael@0: 21921, 21902, 22284, 22569, 22583, 22553, 22558, 22567, 22563, 22568, michael@0: 22517, 22600, 22565, 22556, 22555, 22579, 22591, 22582, 22574, 22585, michael@0: 22584, 22573, 22572, 22587, 22881, 23215, 23188, 23199, 23162, 23202, michael@0: 23198, 23160, 23206, 23164, 23205, 23212, 23189, 23214, 23095, 23172, michael@0: 23178, 23191, 23171, 23179, 23209, 23163, 23165, 23180, 23196, 23183, michael@0: 23187, 23197, 23530, 23501, 23499, 23508, 23505, 23498, 23502, 23564, michael@0: 23600, 23863, 23875, 23915, 23873, 23883, 23871, 23861, 23889, 23886, michael@0: 23893, 23859, 23866, 23890, 23869, 23857, 23897, 23874, 23865, 23881, michael@0: 23864, 23868, 23858, 23862, 23872, 23877, 24132, 24129, [24408, 57673], michael@0: 24486, 24485, 24491, 24777, 24761, 24780, 24802, 24782, 24772, 24852, michael@0: 24818, 24842, 24854, 24837, 24821, 24851, 24824, 24828, 24830, 24769, michael@0: 24835, 24856, 24861, 24848, 24831, 24836, 24843, 25162, 25492, 25521, michael@0: 25520, 25550, 25573, 25576, 25583, 25539, 25757, 25587, 25546, 25568, michael@0: 25590, 25557, 25586, 25589, 25697, 25567, 25534, 25565, 25564, 25540, michael@0: 25560, 25555, 25538, 25543, 25548, 25547, 25544, 25584, 25559, 25561, michael@0: 25906, 25959, 25962, 25956, 25948, 25960, 25957, 25996, {f: 2, c: 26013}, michael@0: 26030, 26064, 26066, 26236, 26220, 26235, 26240, 26225, 26233, 26218, michael@0: 26226, 26369, 26892, 26835, 26884, 26844, 26922, 26860, 26858, 26865, michael@0: 26895, 26838, 26871, 26859, 26852, 26870, 26899, 26896, 26867, 26849, michael@0: 26887, 26828, 26888, 26992, 26804, 26897, 26863, 26822, 26900, 26872, michael@0: 26832, 26877, 26876, 26856, 26891, 26890, 26903, 26830, 26824, michael@0: {f: 2, c: 26845}, 26854, 26868, 26833, 26886, 26836, 26857, 26901, 26917, michael@0: 26823, 27449, 27451, 27455, 27452, 27540, 27543, 27545, 27541, 27581, michael@0: 27632, {f: 2, c: 27634}, 27696, 28156, {f: 2, c: 28230}, 28191, 28233, michael@0: 28296, {f: 2, c: 28220}, 28229, 28258, 28203, 28223, 28225, 28253, 28275, michael@0: 28188, 28211, 28235, 28224, 28241, 28219, 28163, 28206, 28254, 28264, michael@0: 28252, 28257, 28209, 28200, 28256, 28273, 28267, 28217, 28194, 28208, michael@0: 28243, 28261, 28199, 28280, 28260, 28279, 28245, 28281, 28242, 28262, michael@0: {f: 2, c: 28213}, 28250, 28960, 28958, 28975, 28923, 28974, 28977, 28963, michael@0: 28965, 28962, 28978, 28959, 28968, 28986, 28955, 29259, 29274, michael@0: {f: 2, c: 29320}, 29318, 29317, 29323, 29458, 29451, 29488, 29474, 29489, michael@0: 29491, 29479, 29490, 29485, 29478, 29475, 29493, 29452, 29742, 29740, michael@0: 29744, 29739, 29718, 29722, 29729, 29741, 29745, 29732, 29731, 29725, michael@0: 29737, 29728, 29746, 29947, 29999, 30063, 30060, 30183, 30170, 30177, michael@0: 30182, 30173, 30175, 30180, 30167, 30357, 30354, 30426, {f: 2, c: 30534}, michael@0: 30532, 30541, 30533, 30538, 30542, {f: 2, c: 30539}, 30686, 30700, 30816, michael@0: {f: 2, c: 30820}, 30812, 30829, 30833, 30826, 30830, 30832, 30825, 30824, michael@0: 30814, 30818, 31092, 31091, 31090, 31088, 31234, 31242, 31235, 31244, michael@0: 31236, 31385, 31462, 31460, 31562, 31559, 31556, 31560, 31564, 31566, michael@0: 31552, 31576, 31557, 31906, 31902, 31912, 31905, 32088, 32111, 32099, michael@0: 32083, 32086, 32103, 32106, 32079, 32109, 32092, 32107, 32082, 32084, michael@0: 32105, 32081, 32095, 32078, {f: 2, c: 32574}, {f: 2, c: 32613}, 32674, michael@0: {f: 2, c: 32672}, 32727, 32849, {f: 2, c: 32847}, 33022, 32980, 33091, michael@0: 33098, 33106, 33103, 33095, 33085, 33101, 33082, 33254, 33262, michael@0: {f: 3, c: 33271}, 33284, {f: 2, c: 33340}, 33343, 33397, 33595, michael@0: [33743, 60382], 33785, 33827, 33728, 33768, 33810, 33767, 33764, 33788, michael@0: 33782, 33808, 33734, 33736, 33771, 33763, 33727, 33793, 33757, 33765, michael@0: 33752, 33791, 33761, 33739, 33742, 33750, 33781, 33737, 33801, michael@0: [33807, 58332], 33758, 33809, 33798, 33730, 33779, 33749, 33786, 33735, michael@0: 33745, 33770, 33811, 33690, 33731, 33772, 33774, 33732, 33787, 33751, michael@0: 33762, 33819, 33755, 33790, 34520, 34530, 34534, 34515, 34531, 34522, michael@0: 34538, 34525, 34539, 34524, 34540, 34537, 34519, 34536, 34513, 34888, michael@0: 34902, 34901, 35002, 35031, 35001, 35000, 35008, 35006, 34998, 35004, michael@0: 34999, 35005, 34994, 35073, 35017, 35221, 35224, 35223, 35293, michael@0: {f: 2, c: 35290}, 35406, 35405, 35385, 35417, 35392, {f: 2, c: 35415}, michael@0: {f: 2, c: 35396}, 35410, 35400, 35409, 35402, 35404, 35407, 35935, 35969, michael@0: 35968, 36026, 36030, 36016, 36025, 36021, 36228, 36224, 36233, 36312, michael@0: 36307, 36301, 36295, 36310, 36316, 36303, 36309, 36313, 36296, 36311, michael@0: 36293, 36591, 36599, 36602, 36601, 36582, 36590, 36581, 36597, michael@0: {f: 2, c: 36583}, 36598, 36587, 36593, 36588, 36596, 36585, 36909, 36916, michael@0: 36911, 37126, 37164, [37124, 60367], 37119, 37116, 37128, 37113, 37115, michael@0: 37121, 37120, 37127, 37125, 37123, 37217, 37220, 37215, 37218, 37216, michael@0: 37377, 37386, 37413, 37379, 37402, 37414, 37391, 37388, 37376, 37394, michael@0: 37375, 37373, 37382, 37380, 37415, 37378, 37404, 37412, 37401, 37399, michael@0: 37381, 37398, 38267, 38285, 38284, 38288, 38535, 38526, {f: 2, c: 38536}, michael@0: 38531, 38528, 38594, 38600, 38595, 38641, 38640, 38764, 38768, 38766, michael@0: 38919, 39081, 39147, 40166, [12235, 40697], {f: 2, c: 20099}, 20150, 20669, michael@0: 20671, 20678, 20654, 20676, 20682, 20660, 20680, 20674, 20656, 20673, michael@0: 20666, 20657, 20683, 20681, 20662, 20664, 20951, 21114, 21112, michael@0: {f: 2, c: 21115}, 21955, 21979, 21964, 21968, 21963, 21962, 21981, michael@0: [21952, 64013], 21972, 21956, 21993, 21951, 21970, 21901, 21967, 21973, michael@0: 21986, 21974, 21960, 22002, 21965, 21977, 21954, 22292, 22611, 22632, michael@0: 22628, 22607, 22605, 22601, 22639, 22613, 22606, 22621, 22617, 22629, michael@0: 22619, 22589, 22627, 22641, 22780, 23239, 23236, 23243, 23226, 23224, michael@0: 23217, 23221, 23216, 23231, 23240, 23227, 23238, 23223, 23232, 23242, michael@0: 23220, 23222, 23245, 23225, 23184, 23510, {f: 2, c: 23512}, 23583, 23603, michael@0: 23921, 23907, 23882, 23909, 23922, 23916, 23902, 23912, 23911, 23906, michael@0: 24048, 24143, 24142, 24138, 24141, 24139, 24261, 24268, 24262, 24267, michael@0: 24263, 24384, 24495, 24493, 24823, {f: 2, c: 24905}, 24875, 24901, 24886, michael@0: 24882, 24878, 24902, 24879, 24911, 24873, 24896, 25120, 37224, 25123, michael@0: 25125, 25124, 25541, 25585, 25579, 25616, 25618, 25609, 25632, 25636, michael@0: 25651, 25667, 25631, 25621, 25624, 25657, 25655, {f: 2, c: 25634}, 25612, michael@0: 25638, 25648, 25640, 25665, 25653, 25647, 25610, 25626, 25664, 25637, michael@0: 25639, 25611, 25575, 25627, 25646, 25633, 25614, 25967, 26002, 26067, michael@0: 26246, 26252, 26261, 26256, 26251, 26250, 26265, 26260, 26232, 26400, michael@0: 26982, 26975, 26936, 26958, 26978, 26993, 26943, 26949, 26986, 26937, michael@0: 26946, 26967, 26969, 27002, {f: 2, c: 26952}, 26933, 26988, 26931, 26941, michael@0: 26981, 26864, 27000, 26932, 26985, 26944, 26991, 26948, 26998, 26968, michael@0: 26945, 26996, 26956, 26939, 26955, 26935, 26972, 26959, 26961, 26930, michael@0: 26962, 26927, 27003, 26940, 27462, 27461, 27459, 27458, 27464, 27457, michael@0: 27547, {f: 2, c: 27643}, 27641, {f: 2, c: 27639}, 28315, 28374, 28360, michael@0: 28303, 28352, 28319, {f: 2, c: 28307}, 28320, 28337, 28345, 28358, 28370, michael@0: 28349, 28353, 28318, 28361, 28343, 28336, 28365, 28326, 28367, 28338, michael@0: 28350, 28355, 28380, 28376, 28313, 28306, 28302, 28301, 28324, 28321, michael@0: 28351, 28339, 28368, 28362, 28311, 28334, 28323, 28999, 29012, 29010, michael@0: 29027, 29024, 28993, 29021, [29026, 61080], 29042, 29048, 29034, 29025, michael@0: 28994, 29016, 28995, 29003, 29040, 29023, 29008, 29011, 28996, 29005, michael@0: 29018, 29263, 29325, 29324, 29329, 29328, 29326, 29500, 29506, 29499, michael@0: 29498, 29504, 29514, 29513, 29764, {f: 2, c: 29770}, 29778, 29777, 29783, michael@0: 29760, {f: 2, c: 29775}, 29774, 29762, 29766, 29773, 29780, 29921, 29951, michael@0: 29950, 29949, 29981, 30073, 30071, 27011, 30191, 30223, 30211, 30199, michael@0: 30206, 30204, [30201, 60782], 30200, 30224, 30203, 30198, 30189, 30197, michael@0: 30205, 30361, 30389, 30429, 30549, {f: 2, c: 30559}, 30546, 30550, 30554, michael@0: 30569, 30567, 30548, 30553, 30573, 30688, 30855, 30874, 30868, 30863, michael@0: 30852, 30869, {f: 2, c: 30853}, 30881, 30851, 30841, 30873, 30848, 30870, michael@0: 30843, 31100, 31106, 31101, 31097, 31249, {f: 2, c: 31256}, 31250, 31255, michael@0: 31253, 31266, 31251, 31259, 31248, 31395, 31394, 31390, 31467, 31590, michael@0: 31588, 31597, 31604, 31593, 31602, 31589, 31603, 31601, 31600, 31585, michael@0: 31608, 31606, 31587, 31922, 31924, 31919, 32136, 32134, 32128, 32141, michael@0: 32127, 32133, 32122, 32142, 32123, 32131, 32124, 32140, 32148, 32132, michael@0: 32125, 32146, 32621, 32619, {f: 2, c: 32615}, 32620, 32678, 32677, 32679, michael@0: {f: 2, c: 32731}, 32801, 33124, 33120, 33143, 33116, 33129, 33115, 33122, michael@0: 33138, 26401, 33118, 33142, 33127, 33135, 33092, 33121, 33309, 33353, michael@0: 33348, 33344, 33346, 33349, 34033, 33855, 33878, 33910, 33913, 33935, michael@0: 33933, 33893, 33873, 33856, 33926, 33895, 33840, 33869, 33917, 33882, michael@0: 33881, 33908, 33907, 33885, 34055, 33886, 33847, 33850, 33844, 33914, michael@0: 33859, 33912, 33842, 33861, 33833, 33753, 33867, 33839, 33858, 33837, michael@0: 33887, 33904, 33849, 33870, 33868, 33874, 33903, 33989, 33934, 33851, michael@0: 33863, 33846, 33843, 33896, 33918, 33860, 33835, 33888, 33876, 33902, michael@0: 33872, 34571, 34564, 34551, 34572, 34554, 34518, 34549, 34637, 34552, michael@0: 34574, 34569, 34561, 34550, 34573, 34565, 35030, 35019, {f: 2, c: 35021}, michael@0: 35038, 35035, 35034, 35020, 35024, 35205, 35227, 35295, 35301, 35300, michael@0: 35297, 35296, 35298, 35292, 35302, 35446, 35462, 35455, 35425, 35391, michael@0: 35447, 35458, 35460, 35445, 35459, 35457, 35444, 35450, 35900, 35915, michael@0: 35914, 35941, 35940, 35942, 35974, {f: 2, c: 35972}, 36044, michael@0: {f: 2, c: 36200}, 36241, 36236, {f: 2, c: 36238}, 36237, {f: 2, c: 36243}, michael@0: 36240, 36242, 36336, 36320, 36332, 36337, 36334, 36304, 36329, 36323, michael@0: 36322, 36327, 36338, 36331, 36340, 36614, 36607, 36609, 36608, 36613, michael@0: {f: 2, c: 36615}, 36610, [36619, 60507], 36946, 36927, 36932, 36937, 36925, michael@0: 37136, 37133, 37135, 37137, 37142, 37140, 37131, 37134, {f: 2, c: 37230}, michael@0: 37448, 37458, 37424, 37434, 37478, 37427, 37477, 37470, 37507, 37422, michael@0: 37450, 37446, 37485, 37484, 37455, 37472, 37479, 37487, 37430, 37473, michael@0: 37488, 37425, 37460, 37475, 37456, 37490, 37454, 37459, 37452, 37462, michael@0: 37426, 38303, 38300, 38302, 38299, {f: 2, c: 38546}, 38545, 38551, 38606, michael@0: 38650, 38653, 38648, 38645, 38771, {f: 2, c: 38775}, 38770, 38927, michael@0: {f: 2, c: 38925}, 39084, 39158, 39161, 39343, 39346, 39344, 39349, 39597, michael@0: 39595, 39771, 40170, 40173, 40167, 40576, [12236, 40701], 20710, 20692, michael@0: 20695, 20712, 20723, 20699, 20714, 20701, 20708, 20691, 20716, 20720, michael@0: 20719, 20707, 20704, 20952, {f: 2, c: 21120}, 21225, 21227, 21296, 21420, michael@0: 22055, 22037, 22028, 22034, 22012, 22031, 22044, 22017, 22035, 22018, michael@0: 22010, 22045, 22020, 22015, 22009, 22665, 22652, 22672, 22680, 22662, michael@0: 22657, 22655, 22644, 22667, 22650, 22663, 22673, 22670, 22646, 22658, michael@0: 22664, 22651, 22676, 22671, 22782, 22891, 23260, 23278, 23269, 23253, michael@0: 23274, 23258, 23277, 23275, 23283, 23266, 23264, 23259, 23276, 23262, michael@0: 23261, 23257, 23272, 23263, 23415, 23520, 23523, 23651, 23938, 23936, michael@0: 23933, 23942, 23930, 23937, 23927, 23946, 23945, 23944, 23934, 23932, michael@0: 23949, 23929, 23935, {f: 2, c: 24152}, 24147, 24280, 24273, 24279, 24270, michael@0: 24284, 24277, 24281, 24274, 24276, 24388, 24387, 24431, 24502, 24876, michael@0: 24872, 24897, 24926, 24945, 24947, {f: 2, c: 24914}, 24946, 24940, 24960, michael@0: 24948, 24916, 24954, 24923, 24933, 24891, 24938, 24929, 24918, 25129, michael@0: 25127, 25131, 25643, 25677, 25691, 25693, 25716, 25718, {f: 2, c: 25714}, michael@0: 25725, 25717, 25702, 25766, 25678, 25730, 25694, 25692, 25675, 25683, michael@0: 25696, 25680, 25727, 25663, 25708, 25707, 25689, 25701, 25719, 25971, michael@0: 26016, 26273, 26272, 26271, 26373, 26372, 26402, 27057, 27062, 27081, michael@0: 27040, 27086, 27030, 27056, 27052, 27068, 27025, 27033, 27022, 27047, michael@0: 27021, 27049, 27070, 27055, 27071, 27076, 27069, 27044, 27092, 27065, michael@0: 27082, 27034, 27087, 27059, 27027, 27050, 27041, 27038, 27097, 27031, michael@0: 27024, 27074, 27061, 27045, 27078, 27466, 27469, 27467, {f: 3, c: 27550}, michael@0: {f: 2, c: 27587}, 27646, 28366, 28405, 28401, 28419, 28453, 28408, 28471, michael@0: 28411, 28462, 28425, 28494, {f: 2, c: 28441}, 28455, 28440, 28475, 28434, michael@0: 28397, 28426, 28470, 28531, 28409, 28398, 28461, 28480, 28464, 28476, michael@0: 28469, 28395, 28423, 28430, 28483, 28421, 28413, 28406, 28473, 28444, michael@0: 28412, 28474, 28447, 28429, 28446, 28424, 28449, 29063, 29072, 29065, michael@0: 29056, 29061, 29058, 29071, 29051, 29062, 29057, 29079, 29252, 29267, michael@0: 29335, 29333, 29331, 29507, 29517, 29521, 29516, 29794, 29811, 29809, michael@0: 29813, 29810, 29799, 29806, 29952, {f: 2, c: 29954}, 30077, 30096, 30230, michael@0: 30216, 30220, 30229, 30225, 30218, 30228, 30392, 30593, 30588, 30597, michael@0: 30594, 30574, 30592, 30575, 30590, 30595, 30898, 30890, 30900, 30893, michael@0: 30888, 30846, 30891, 30878, 30885, 30880, 30892, 30882, 30884, 31128, michael@0: {f: 2, c: 31114}, 31126, 31125, 31124, 31123, 31127, 31112, 31122, 31120, michael@0: 31275, 31306, 31280, 31279, 31272, 31270, 31400, {f: 2, c: 31403}, 31470, michael@0: 31624, 31644, 31626, 31633, 31632, 31638, 31629, 31628, 31643, 31630, michael@0: 31621, 31640, 21124, 31641, 31652, 31618, 31931, 31935, 31932, 31930, michael@0: 32167, 32183, 32194, 32163, 32170, 32193, 32192, 32197, 32157, 32206, michael@0: 32196, 32198, {f: 2, c: 32203}, 32175, 32185, 32150, 32188, 32159, 32166, michael@0: 32174, 32169, 32161, 32201, 32627, {f: 2, c: 32738}, 32741, 32734, 32804, michael@0: 32861, 32860, 33161, 33158, 33155, 33159, 33165, 33164, 33163, 33301, michael@0: 33943, 33956, 33953, 33951, 33978, 33998, 33986, 33964, 33966, 33963, michael@0: 33977, 33972, 33985, 33997, 33962, 33946, 33969, 34000, 33949, 33959, michael@0: 33979, 33954, 33940, 33991, 33996, 33947, 33961, 33967, [33960, 58327], michael@0: 34006, 33944, 33974, 33999, 33952, 34007, 34004, 34002, 34011, 33968, michael@0: 33937, 34401, 34611, 34595, 34600, 34667, 34624, 34606, 34590, 34593, michael@0: 34585, 34587, 34627, 34604, 34625, 34622, 34630, 34592, 34610, 34602, michael@0: 34605, 34620, 34578, 34618, 34609, 34613, 34626, {f: 2, c: 34598}, 34616, michael@0: 34596, 34586, 34608, 34577, 35063, 35047, {f: 2, c: 35057}, 35066, 35070, michael@0: 35054, 35068, 35062, 35067, 35056, 35052, 35051, 35229, 35233, 35231, michael@0: 35230, 35305, 35307, 35304, 35499, 35481, 35467, 35474, 35471, 35478, michael@0: 35901, {f: 2, c: 35944}, 36053, 36047, 36055, 36246, 36361, 36354, 36351, michael@0: 36365, 36349, 36362, 36355, 36359, 36358, 36357, 36350, 36352, 36356, michael@0: {f: 2, c: 36624}, 36622, 36621, 37155, 37148, 37152, 37154, 37151, 37149, michael@0: 37146, 37156, 37153, 37147, 37242, 37234, 37241, 37235, 37541, 37540, michael@0: 37494, 37531, 37498, 37536, 37524, 37546, 37517, 37542, 37530, 37547, michael@0: 37497, 37527, 37503, 37539, 37614, 37518, 37506, 37525, 37538, 37501, michael@0: 37512, 37537, 37514, 37510, 37516, 37529, 37543, 37502, 37511, 37545, michael@0: 37533, 37515, 37421, 38558, 38561, 38655, 38744, 38781, 38778, 38782, michael@0: 38787, 38784, 38786, 38779, 38788, 38785, 38783, 38862, 38861, 38934, michael@0: {f: 2, c: 39085}, 39170, 39168, 39175, 39325, 39324, 39363, 39353, 39355, michael@0: 39354, 39362, 39357, 39367, 39601, 39651, 39655, {f: 2, c: 39742}, michael@0: {f: 2, c: 39776}, 39775, {f: 2, c: 40177}, 40181, 40615, 20735, 20739, michael@0: 20784, 20728, {f: 2, c: 20742}, 20726, 20734, {f: 2, c: 20747}, 20733, michael@0: 20746, {f: 2, c: 21131}, 21233, 21231, 22088, 22082, 22092, 22069, 22081, michael@0: 22090, 22089, 22086, 22104, 22106, 22080, 22067, 22077, 22060, 22078, michael@0: 22072, 22058, 22074, 22298, 22699, 22685, 22705, 22688, 22691, 22703, michael@0: 22700, 22693, 22689, 22783, 23295, 23284, 23293, 23287, 23286, 23299, michael@0: 23288, 23298, 23289, 23297, 23303, 23301, 23311, 23655, 23961, 23959, michael@0: 23967, 23954, 23970, 23955, 23957, 23968, 23964, 23969, 23962, 23966, michael@0: 24169, 24157, 24160, 24156, 32243, 24283, 24286, 24289, 24393, 24498, michael@0: 24971, 24963, 24953, 25009, 25008, 24994, 24969, 24987, 24979, 25007, michael@0: 25005, 24991, 24978, 25002, 24993, 24973, 24934, 25011, 25133, 25710, michael@0: 25712, 25750, 25760, 25733, 25751, 25756, 25743, 25739, 25738, 25740, michael@0: 25763, 25759, 25704, 25777, 25752, 25974, 25978, 25977, 25979, michael@0: {f: 2, c: 26034}, 26293, 26288, 26281, 26290, 26295, 26282, 26287, 27136, michael@0: 27142, 27159, 27109, 27128, 27157, 27121, 27108, 27168, 27135, 27116, michael@0: 27106, 27163, 27165, 27134, 27175, 27122, 27118, 27156, 27127, 27111, michael@0: 27200, 27144, 27110, 27131, 27149, 27132, 27115, 27145, 27140, 27160, michael@0: 27173, 27151, 27126, 27174, 27143, 27124, 27158, 27473, 27557, 27555, michael@0: 27554, 27558, 27649, 27648, 27647, 27650, 28481, 28454, 28542, 28551, michael@0: 28614, 28562, 28557, 28553, 28556, 28514, 28495, 28549, 28506, 28566, michael@0: 28534, 28524, 28546, 28501, 28530, 28498, 28496, 28503, 28564, 28563, michael@0: 28509, 28416, 28513, 28523, 28541, 28519, 28560, 28499, 28555, 28521, michael@0: 28543, 28565, 28515, 28535, 28522, 28539, 29106, 29103, 29083, 29104, michael@0: 29088, 29082, 29097, 29109, 29085, 29093, 29086, 29092, 29089, 29098, michael@0: 29084, 29095, 29107, 29336, 29338, 29528, 29522, {f: 3, c: 29534}, 29533, michael@0: 29531, 29537, 29530, 29529, 29538, 29831, {f: 2, c: 29833}, 29830, 29825, michael@0: 29821, 29829, 29832, 29820, [29817, 58868], 29960, 29959, 30078, 30245, michael@0: 30238, 30233, 30237, 30236, 30243, 30234, 30248, 30235, {f: 3, c: 30364}, michael@0: 30363, 30605, 30607, 30601, 30600, 30925, 30907, 30927, 30924, 30929, michael@0: 30926, 30932, 30920, {f: 2, c: 30915}, 30921, 31130, 31137, 31136, 31132, michael@0: 31138, [31131, 59175], 27510, 31289, 31410, 31412, 31411, 31671, 31691, michael@0: 31678, 31660, 31694, 31663, 31673, 31690, 31669, 31941, 31944, 31948, michael@0: 31947, 32247, 32219, 32234, 32231, 32215, 32225, 32259, 32250, 32230, michael@0: 32246, 32241, 32240, 32238, 32223, 32630, 32684, 32688, 32685, 32749, michael@0: 32747, 32746, 32748, 32742, 32744, 32868, 32871, 33187, 33183, 33182, michael@0: 33173, 33186, 33177, 33175, 33302, 33359, 33363, 33362, 33360, 33358, michael@0: 33361, 34084, 34107, 34063, 34048, 34089, 34062, 34057, 34061, 34079, michael@0: 34058, 34087, 34076, 34043, 34091, 34042, 34056, 34060, 34036, 34090, michael@0: 34034, 34069, 34039, 34027, 34035, 34044, 34066, 34026, 34025, 34070, michael@0: 34046, 34088, 34077, 34094, 34050, 34045, 34078, 34038, 34097, 34086, michael@0: {f: 2, c: 34023}, 34032, 34031, 34041, 34072, 34080, 34096, 34059, 34073, michael@0: 34095, 34402, 34646, {f: 2, c: 34659}, 34679, 34785, 34675, 34648, 34644, michael@0: 34651, 34642, 34657, 34650, 34641, 34654, 34669, 34666, 34640, 34638, michael@0: 34655, 34653, 34671, 34668, 34682, 34670, 34652, 34661, 34639, 34683, michael@0: 34677, 34658, 34663, 34665, 34906, 35077, 35084, 35092, 35083, michael@0: {f: 3, c: 35095}, 35078, 35094, 35089, 35086, 35081, 35234, 35236, 35235, michael@0: 35309, 35312, 35308, 35535, 35526, 35512, 35539, 35537, {f: 2, c: 35540}, michael@0: 35515, 35543, 35518, 35520, 35525, 35544, 35523, 35514, 35517, 35545, michael@0: 35902, 35917, 35983, 36069, 36063, 36057, 36072, 36058, 36061, 36071, michael@0: 36256, 36252, 36257, 36251, 36384, 36387, 36389, 36388, 36398, 36373, michael@0: 36379, 36374, 36369, 36377, {f: 2, c: 36390}, 36372, 36370, 36376, 36371, michael@0: 36380, 36375, 36378, 36652, 36644, 36632, 36634, 36640, 36643, michael@0: {f: 2, c: 36630}, 36979, 36976, 36975, 36967, 36971, 37167, 37163, michael@0: {f: 2, c: 37161}, 37170, 37158, 37166, {f: 2, c: 37253}, 37258, michael@0: {f: 2, c: 37249}, 37252, 37248, 37584, {f: 2, c: 37571}, 37568, 37593, michael@0: 37558, 37583, 37617, 37599, 37592, 37609, 37591, 37597, 37580, 37615, michael@0: 37570, 37608, 37578, 37576, 37582, 37606, 37581, 37589, 37577, 37600, michael@0: 37598, 37607, 37585, 37587, 37557, 37601, 37669, 37574, 37556, 38268, michael@0: 38316, 38315, 38318, 38320, 38564, 38562, 38611, 38661, 38664, 38658, michael@0: 38746, 38794, 38798, 38792, 38864, 38863, 38942, 38941, 38950, 38953, michael@0: 38952, 38944, 38939, 38951, 39090, 39176, 39162, 39185, 39188, michael@0: {f: 2, c: 39190}, 39189, 39388, 39373, 39375, {f: 2, c: 39379}, 39374, michael@0: 39369, [39382, 60270], 39384, 39371, 39383, 39372, 39603, 39660, 39659, michael@0: 39667, 39666, 39665, 39750, 39747, 39783, 39796, 39793, 39782, 39798, michael@0: 39797, 39792, 39784, 39780, 39788, 40188, 40186, 40189, 40191, 40183, michael@0: 40199, 40192, 40185, 40187, 40200, 40197, 40196, 40579, 40659, michael@0: {f: 2, c: 40719}, 20764, 20755, 20759, 20762, 20753, 20958, 21300, 21473, michael@0: 22128, 22112, 22126, 22131, 22118, 22115, 22125, 22130, 22110, 22135, michael@0: 22300, 22299, 22728, 22717, 22729, 22719, 22714, 22722, 22716, 22726, michael@0: 23319, 23321, 23323, 23329, 23316, 23315, 23312, 23318, [23336, 59539], michael@0: 23322, 23328, 23326, 23535, 23980, 23985, 23977, 23975, 23989, 23984, michael@0: 23982, 23978, 23976, 23986, 23981, 23983, 23988, {f: 2, c: 24167}, 24166, michael@0: 24175, 24297, 24295, 24294, 24296, 24293, 24395, 24508, 24507, 24989, michael@0: 25000, 24982, 25029, 25012, 25030, 25025, 25036, 25018, 25023, 25016, michael@0: 24972, 25815, 25814, 25808, 25807, 25801, 25789, 25737, 25795, 25819, michael@0: 25843, 25817, 25907, 25983, 25980, 26018, 26312, 26302, 26304, michael@0: {f: 2, c: 26314}, 26319, 26301, 26299, 26298, 26316, 26403, 27188, 27238, michael@0: 27209, 27239, 27186, 27240, 27198, 27229, 27245, 27254, 27227, 27217, michael@0: 27176, 27226, 27195, 27199, 27201, 27242, 27236, 27216, 27215, 27220, michael@0: 27247, 27241, 27232, 27196, 27230, 27222, 27221, {f: 2, c: 27213}, 27206, michael@0: 27477, 27476, 27478, 27559, {f: 2, c: 27562}, 27592, 27591, 27652, 27651, michael@0: 27654, 28589, 28619, 28579, 28615, 28604, 28622, 28616, 28510, 28612, michael@0: 28605, 28574, 28618, 28584, 28676, 28581, 28590, 28602, 28588, 28586, michael@0: 28623, 28607, 28600, 28578, 28617, 28587, 28621, 28591, 28594, 28592, michael@0: 29125, 29122, 29119, 29112, 29142, {f: 2, c: 29120}, 29131, 29140, 29130, michael@0: 29127, 29135, 29117, 29144, 29116, 29126, {f: 2, c: 29146}, michael@0: {f: 2, c: 29341}, 29545, {f: 2, c: 29542}, 29548, 29541, 29547, 29546, michael@0: 29823, 29850, 29856, 29844, 29842, 29845, 29857, 29963, 30080, 30255, michael@0: 30253, 30257, 30269, 30259, 30268, 30261, 30258, 30256, 30395, 30438, michael@0: 30618, 30621, 30625, 30620, 30619, {f: 2, c: 30626}, 30613, 30617, 30615, michael@0: 30941, 30953, 30949, 30954, 30942, 30947, 30939, {f: 2, c: 30945}, 30957, michael@0: {f: 2, c: 30943}, 31140, 31300, 31304, 31303, 31414, 31416, 31413, 31409, michael@0: 31415, 31710, 31715, 31719, 31709, 31701, 31717, 31706, 31720, 31737, michael@0: 31700, 31722, 31714, 31708, 31723, 31704, 31711, 31954, 31956, 31959, michael@0: {f: 2, c: 31952}, 32274, 32289, 32279, 32268, {f: 2, c: 32287}, 32275, michael@0: 32270, 32284, 32277, 32282, 32290, 32267, 32271, 32278, 32269, 32276, michael@0: 32293, 32292, 32579, {f: 2, c: 32635}, 32634, 32689, 32751, 32810, 32809, michael@0: 32876, 33201, 33190, 33198, 33209, 33205, 33195, 33200, 33196, 33204, michael@0: 33202, 33207, 33191, 33266, {f: 3, c: 33365}, 34134, 34117, 34155, 34125, michael@0: 34131, 34145, 34136, 34112, 34118, 34148, 34113, 34146, 34116, 34129, michael@0: 34119, 34147, 34110, 34139, 34161, 34126, 34158, 34165, 34133, 34151, michael@0: 34144, 34188, 34150, 34141, 34132, 34149, 34156, 34403, 34405, 34404, michael@0: 34724, 34715, 34703, 34711, 34707, 34706, 34696, 34689, 34710, 34712, michael@0: 34681, 34695, 34723, 34693, {f: 2, c: 34704}, 34717, 34692, 34708, 34716, michael@0: 34714, 34697, 35102, 35110, 35120, {f: 2, c: 35117}, 35111, 35121, 35106, michael@0: 35113, 35107, 35119, 35116, 35103, 35313, 35552, 35554, 35570, michael@0: {f: 2, c: 35572}, 35549, 35604, 35556, 35551, 35568, 35528, 35550, 35553, michael@0: 35560, 35583, 35567, 35579, {f: 2, c: 35985}, 35984, 36085, 36078, 36081, michael@0: 36080, 36083, 36204, 36206, 36261, 36263, 36403, 36414, 36408, 36416, michael@0: 36421, 36406, {f: 2, c: 36412}, 36417, 36400, 36415, 36541, [36662, 60329], michael@0: 36654, 36661, 36658, 36665, 36663, 36660, 36982, 36985, 36987, 36998, michael@0: 37114, 37171, {f: 2, c: 37173}, 37267, {f: 2, c: 37264}, 37261, 37263, michael@0: 37671, 37662, 37640, 37663, 37638, 37647, 37754, 37688, 37692, 37659, michael@0: 37667, 37650, 37633, 37702, 37677, 37646, 37645, 37579, 37661, 37626, michael@0: 37651, 37625, 37623, 37684, 37634, 37668, 37631, 37673, 37689, 37685, michael@0: 37674, 37652, 37644, 37643, 37630, 37641, 37632, 37627, 37654, 38332, michael@0: 38349, 38334, {f: 2, c: 38329}, 38326, 38335, 38325, 38333, 38569, 38612, michael@0: 38667, 38674, 38672, 38809, 38807, 38804, 38896, 38904, 38965, 38959, michael@0: 38962, 39204, 39199, 39207, 39209, 39326, 39406, 39404, 39397, 39396, michael@0: 39408, 39395, 39402, 39401, 39399, 39609, 39615, 39604, 39611, 39670, michael@0: 39674, 39673, 39671, 39731, 39808, 39813, 39815, 39804, 39806, 39803, michael@0: 39810, 39827, 39826, 39824, 39802, 39829, 39805, 39816, 40229, 40215, michael@0: 40224, 40222, 40212, 40233, 40221, 40216, 40226, 40208, 40217, 40223, michael@0: 40584, {f: 2, c: 40582}, 40622, 40621, {f: 2, c: 40661}, 40698, 40722, michael@0: 40765, 20774, 20773, 20770, 20772, 20768, 20777, 21236, 22163, michael@0: {f: 2, c: 22156}, 22150, 22148, 22147, 22142, 22146, 22143, 22145, 22742, michael@0: 22740, 22735, 22738, 23341, 23333, 23346, 23331, 23340, 23335, 23334, michael@0: 23343, 23342, 23419, {f: 2, c: 23537}, 23991, 24172, 24170, 24510, 25027, michael@0: 25013, 25020, 25063, 25056, 25061, 25060, 25064, 25054, 25839, 25833, michael@0: 25827, 25835, 25828, 25832, 25985, 25984, 26038, 26074, 26322, 27277, michael@0: 27286, 27265, 27301, 27273, 27295, 27291, 27297, 27294, 27271, 27283, michael@0: 27278, 27285, 27267, 27304, 27300, 27281, 27263, 27302, 27290, 27269, michael@0: 27276, 27282, 27483, 27565, 27657, 28620, 28585, 28660, 28628, 28643, michael@0: 28636, 28653, 28647, 28646, 28638, 28658, 28637, 28642, 28648, 29153, michael@0: 29169, 29160, 29170, 29156, 29168, 29154, 29555, {f: 2, c: 29550}, 29847, michael@0: 29874, 29867, 29840, 29866, 29869, 29873, 29861, 29871, {f: 3, c: 29968}, michael@0: 29967, 30084, 30275, {f: 2, c: 30280}, 30279, 30372, 30441, 30645, 30635, michael@0: 30642, 30647, 30646, 30644, 30641, 30632, 30704, 30963, 30973, 30978, michael@0: {f: 2, c: 30971}, 30975, 30962, 30981, 30969, 30974, 30980, 31147, 31144, michael@0: 31324, 31323, 31318, 31320, 31316, 31322, 31422, {f: 2, c: 31424}, 31749, michael@0: 31759, 31730, 31744, 31743, 31739, 31758, 31732, 31755, 31731, 31746, michael@0: 31753, 31747, 31745, 31736, 31741, [31750, 58176], {f: 2, c: 31728}, 31760, michael@0: 31754, 31976, 32301, 32316, 32322, 32307, 38984, 32312, 32298, 32329, michael@0: 32320, 32327, 32297, 32332, 32304, 32315, 32310, 32324, 32314, 32581, michael@0: 32639, 32638, 32637, 32756, 32754, 32812, 33211, 33220, 33228, 33226, michael@0: 33221, 33223, 33212, 33257, 33371, 33370, 33372, 34179, 34176, 34191, michael@0: 34215, 34197, 34208, 34187, 34211, 34171, 34212, 34202, 34206, 34167, michael@0: 34172, 34185, 34209, 34170, 34168, 34135, 34190, 34198, 34182, 34189, michael@0: 34201, 34205, 34177, 34210, 34178, 34184, 34181, 34169, 34166, 34200, michael@0: 34192, 34207, 34408, 34750, 34730, 34733, 34757, 34736, 34732, 34745, michael@0: 34741, 34748, 34734, 34761, 34755, 34754, 34764, 34743, 34735, 34756, michael@0: 34762, 34740, 34742, 34751, 34744, 34749, 34782, 34738, 35125, 35123, michael@0: 35132, 35134, 35137, 35154, 35127, 35138, 35245, 35247, 35246, michael@0: {f: 2, c: 35314}, 35614, 35608, 35606, 35601, 35589, 35595, 35618, 35599, michael@0: 35602, 35605, 35591, 35597, 35592, 35590, 35612, 35603, 35610, 35919, michael@0: 35952, 35954, 35953, 35951, 35989, 35988, 36089, 36207, 36430, 36429, michael@0: 36435, 36432, 36428, 36423, 36675, 36672, 36997, 36990, 37176, 37274, michael@0: 37282, 37275, 37273, 37279, 37281, 37277, 37280, 37793, 37763, 37807, michael@0: 37732, 37718, 37703, 37756, 37720, 37724, 37750, 37705, {f: 2, c: 37712}, michael@0: 37728, 37741, 37775, 37708, 37738, 37753, 37719, 37717, 37714, 37711, michael@0: 37745, 37751, 37755, 37729, 37726, 37731, 37735, 37710, 37721, 38343, michael@0: 38336, 38345, 38339, 38341, 38327, 38574, 38576, 38572, 38688, 38687, michael@0: 38680, 38685, 38681, 38810, 38817, 38812, 38814, 38813, 38869, 38868, michael@0: 38897, 38977, 38980, 38986, 38985, 38981, 38979, 39205, {f: 2, c: 39211}, michael@0: 39210, 39219, 39218, 39215, 39213, 39217, 39216, 39320, 39331, 39329, michael@0: 39426, 39418, 39412, 39415, 39417, 39416, 39414, 39419, {f: 2, c: 39421}, michael@0: 39420, 39427, 39614, 39678, 39677, 39681, 39676, 39752, 39834, 39848, michael@0: 39838, 39835, 39846, 39841, 39845, 39844, 39814, 39842, 39840, 39855, michael@0: 40243, 40257, 40295, 40246, {f: 2, c: 40238}, 40241, 40248, 40240, 40261, michael@0: {f: 2, c: 40258}, 40254, 40247, 40256, 40253, 32757, 40237, 40586, 40585, michael@0: 40589, 40624, 40648, 40666, 40699, 40703, 40740, 40739, 40738, 40788, michael@0: [12245, 40864], 20785, {f: 2, c: 20781}, 22168, 22172, 22167, 22170, 22173, michael@0: 22169, 22896, 23356, {f: 2, c: 23657}, 24000, {f: 2, c: 24173}, 25048, michael@0: 25055, {f: 2, c: 25069}, 25073, 25066, 25072, 25067, 25046, 25065, 25855, michael@0: 25860, 25853, 25848, 25857, 25859, 25852, 26004, 26075, {f: 2, c: 26330}, michael@0: 26328, 27333, 27321, 27325, 27361, 27334, 27322, {f: 2, c: 27318}, 27335, michael@0: 27316, 27309, 27486, 27593, 27659, 28679, {f: 2, c: 28684}, 28673, 28677, michael@0: 28692, 28686, {f: 2, c: 28671}, 28667, 28710, 28668, 28663, 28682, michael@0: [29185, 60224], 29183, 29177, 29187, 29181, 29558, 29880, 29888, 29877, michael@0: 29889, 29886, 29878, 29883, 29890, 29972, 29971, 30300, 30308, 30297, michael@0: 30288, 30291, 30295, 30298, 30374, 30397, 30444, 30658, 30650, 30988, michael@0: {f: 2, c: 30995}, 30985, 30992, 30994, 30993, 31149, 31148, 31327, 31772, michael@0: 31785, 31769, 31776, 31775, 31789, 31773, 31782, 31784, 31778, 31781, michael@0: 31792, 32348, 32336, 32342, 32355, 32344, 32354, 32351, 32337, 32352, michael@0: 32343, 32339, 32693, 32691, {f: 2, c: 32759}, 32885, {f: 2, c: 33233}, michael@0: 33232, 33375, 33374, 34228, 34246, 34240, 34243, 34242, 34227, 34229, michael@0: 34237, 34247, 34244, 34239, 34251, 34254, 34248, 34245, 34225, 34230, michael@0: 34258, 34340, 34232, 34231, 34238, 34409, 34791, 34790, 34786, 34779, michael@0: 34795, 34794, 34789, 34783, 34803, 34788, 34772, 34780, 34771, 34797, michael@0: 34776, 34787, 34775, 34777, 34817, 34804, 34792, 34781, 35155, 35147, michael@0: 35151, 35148, 35142, {f: 2, c: 35152}, 35145, 35626, 35623, 35619, 35635, michael@0: 35632, 35637, 35655, 35631, 35644, 35646, 35633, 35621, 35639, 35622, michael@0: 35638, 35630, 35620, 35643, 35645, 35642, 35906, 35957, 35993, 35992, michael@0: 35991, 36094, 36100, 36098, 36096, 36444, 36450, 36448, 36439, 36438, michael@0: 36446, 36453, 36455, 36443, 36442, 36449, 36445, 36457, 36436, michael@0: {f: 3, c: 36678}, 36683, 37160, {f: 2, c: 37178}, 37182, 37288, 37285, michael@0: 37287, 37295, 37290, 37813, 37772, 37778, 37815, 37787, 37789, 37769, michael@0: 37799, 37774, 37802, 37790, 37798, 37781, 37768, 37785, 37791, 37760, michael@0: 37773, 37809, 37777, 37810, 37796, 37800, 37812, 37795, {f: 2, c: 38354}, michael@0: 38353, 38579, 38615, 38618, 24002, 38623, 38616, 38621, 38691, 38690, michael@0: 38693, 38828, 38830, 38824, 38827, 38820, 38826, 38818, 38821, 38871, michael@0: 38873, 38870, 38872, 38906, {f: 3, c: 38992}, 39096, 39233, 39228, 39226, michael@0: 39439, 39435, 39433, 39437, 39428, 39441, 39434, 39429, 39431, 39430, michael@0: 39616, 39644, 39688, {f: 2, c: 39684}, 39721, 39733, 39754, 39756, 39755, michael@0: 39879, 39878, 39875, 39871, 39873, 39861, 39864, 39891, 39862, 39876, michael@0: 39865, 39869, 40284, 40275, 40271, 40266, 40283, 40267, 40281, 40278, michael@0: 40268, 40279, 40274, 40276, 40287, 40280, 40282, 40590, 40588, 40671, michael@0: 40705, 40704, [40726, 58693], 40741, 40747, 40746, 40745, 40744, 40780, michael@0: 40789, {f: 2, c: 20788}, 21142, 21239, 21428, 22187, 22189, michael@0: {f: 2, c: 22182}, 22186, 22188, 22746, 22749, 22747, 22802, michael@0: {f: 3, c: 23357}, 24003, 24176, 24511, 25083, 25863, 25872, 25869, 25865, michael@0: 25868, 25870, 25988, 26078, 26077, 26334, 27367, 27360, 27340, 27345, michael@0: 27353, 27339, 27359, 27356, 27344, 27371, 27343, 27341, 27358, 27488, michael@0: 27568, 27660, 28697, 28711, 28704, 28694, 28715, {f: 3, c: 28705}, 28713, michael@0: 28695, 28708, 28700, 29196, 29194, 29191, 29186, 29189, {f: 2, c: 29349}, michael@0: 29348, 29347, 29345, 29899, 29893, 29879, 29891, 29974, 30304, michael@0: {f: 2, c: 30665}, 30660, 30705, 31005, 31003, 31009, 31004, 30999, 31006, michael@0: 31152, {f: 2, c: 31335}, 31795, 31804, 31801, 31788, 31803, 31980, 31978, michael@0: 32374, 32373, 32376, 32368, 32375, 32367, 32378, 32370, 32372, 32360, michael@0: 32587, 32586, 32643, 32646, 32695, {f: 2, c: 32765}, 32888, 33239, 33237, michael@0: 33291, 33380, 33377, 33379, 34283, 34289, 34285, 34265, 34273, 34280, michael@0: 34266, 34263, 34284, 34290, 34296, 34264, 34271, 34275, 34268, 34257, michael@0: 34288, 34278, 34287, 34270, 34274, 34816, 34810, 34819, {f: 2, c: 34806}, michael@0: 34825, 34828, 34827, 34822, 34812, 34824, 34815, 34826, 34818, 35170, michael@0: {f: 2, c: 35162}, 35159, 35169, 35164, 35160, 35165, 35161, 35208, 35255, michael@0: 35254, 35318, 35664, 35656, 35658, 35648, 35667, 35670, 35668, 35659, michael@0: 35669, 35665, 35650, 35666, 35671, 35907, 35959, 35958, 35994, michael@0: {f: 2, c: 36102}, 36105, 36268, 36266, 36269, 36267, 36461, 36472, 36467, michael@0: 36458, 36463, 36475, 36546, 36690, 36689, {f: 2, c: 36687}, 36691, 36788, michael@0: 37184, 37183, 37296, 37293, 37854, 37831, 37839, 37826, 37850, 37840, michael@0: 37881, 37868, 37836, 37849, 37801, 37862, 37834, 37844, 37870, 37859, michael@0: 37845, 37828, 37838, 37824, 37842, 37797, 37863, 38269, {f: 2, c: 38362}, michael@0: 38625, 38697, {f: 2, c: 38699}, 38696, 38694, 38835, 38839, 38838, michael@0: {f: 3, c: 38877}, 39004, 39001, 39005, 38999, 39103, 39101, 39099, 39102, michael@0: 39240, 39239, 39235, {f: 2, c: 39334}, 39450, 39445, 39461, 39453, 39460, michael@0: 39451, 39458, 39456, 39463, 39459, 39454, 39452, 39444, 39618, 39691, michael@0: 39690, 39694, 39692, 39735, {f: 2, c: 39914}, 39904, 39902, 39908, 39910, michael@0: 39906, 39920, 39892, 39895, 39916, 39900, 39897, 39909, 39893, 39905, michael@0: 39898, 40311, 40321, 40330, 40324, 40328, 40305, 40320, 40312, 40326, michael@0: {f: 2, c: 40331}, 40317, 40299, {f: 2, c: 40308}, 40304, 40297, 40325, michael@0: 40307, 40315, 40322, 40303, 40313, 40319, 40327, 40296, 40596, 40593, michael@0: 40640, 40700, 40749, {f: 2, c: 40768}, 40781, {f: 3, c: 40790}, 21303, michael@0: 22194, 22197, 22195, 22755, 23365, {f: 2, c: 24006}, {f: 2, c: 24302}, michael@0: {f: 2, c: 24512}, 25081, 25879, 25878, 25877, 25875, 26079, 26344, michael@0: {f: 2, c: 26339}, 27379, 27376, 27370, 27368, 27385, 27377, michael@0: {f: 2, c: 27374}, 28732, 28725, 28719, 28727, 28724, 28721, 28738, 28728, michael@0: 28735, 28730, 28729, 28714, 28736, 28731, 28723, 28737, {f: 2, c: 29203}, michael@0: 29352, 29565, 29564, 29882, 30379, 30378, 30398, 30445, 30668, michael@0: {f: 2, c: 30670}, 30669, 30706, 31013, 31011, {f: 2, c: 31015}, 31012, michael@0: 31017, 31154, 31342, {f: 2, c: 31340}, 31479, 31817, 31816, 31818, 31815, michael@0: 31813, 31982, 32379, 32382, 32385, 32384, 32698, 32767, 32889, 33243, michael@0: 33241, {f: 2, c: 33384}, 34338, 34303, 34305, 34302, 34331, 34304, 34294, michael@0: 34308, 34313, 34309, 34316, 34301, 34841, {f: 2, c: 34832}, 34839, 34835, michael@0: 34838, 35171, 35174, 35257, 35319, 35680, 35690, 35677, 35688, 35683, michael@0: 35685, 35687, 35693, 36270, 36486, 36488, 36484, 36697, {f: 2, c: 36694}, michael@0: 36693, 36696, 36698, 37005, 37187, 37185, 37303, 37301, {f: 2, c: 37298}, michael@0: 37899, 37907, 37883, 37920, 37903, 37908, 37886, 37909, 37904, 37928, michael@0: 37913, 37901, 37877, 37888, 37879, 37895, 37902, 37910, 37906, 37882, michael@0: 37897, 37880, 37948, 37898, 37887, 37884, 37900, 37878, 37905, 37894, michael@0: 38366, 38368, 38367, {f: 2, c: 38702}, 38841, 38843, {f: 2, c: 38909}, michael@0: 39008, {f: 2, c: 39010}, 39007, {f: 2, c: 39105}, 39248, 39246, 39257, michael@0: 39244, 39243, 39251, 39474, 39476, 39473, 39468, 39466, 39478, 39465, michael@0: 39470, 39480, 39469, 39623, 39626, 39622, 39696, 39698, 39697, 39947, michael@0: 39944, 39927, 39941, 39954, 39928, 40000, 39943, 39950, 39942, 39959, michael@0: 39956, 39945, 40351, 40345, 40356, 40349, 40338, 40344, 40336, 40347, michael@0: 40352, 40340, 40348, 40362, 40343, 40353, 40346, 40354, 40360, 40350, michael@0: 40355, 40383, 40361, 40342, {f: 2, c: 40358}, 40601, 40603, 40602, 40677, michael@0: 40676, 40679, 40678, 40752, 40750, 40795, 40800, 40798, 40797, 40793, michael@0: 40849, 20794, 20793, 21144, 21143, 22211, {f: 2, c: 22205}, 23368, 23367, michael@0: 24011, 24015, 24305, 25085, 25883, 27394, 27388, 27395, 27384, 27392, michael@0: {f: 2, c: 28739}, 28746, {f: 2, c: 28744}, {f: 2, c: 28741}, 29213, 29210, michael@0: 29209, 29566, 29975, 30314, 30672, 31021, 31025, 31023, 31828, 31827, michael@0: 31986, 32394, [32391, 60229], 32392, 32395, 32390, 32397, 32589, 32699, michael@0: 32816, 33245, 34328, 34346, 34342, 34335, 34339, 34332, 34329, 34343, michael@0: 34350, 34337, 34336, 34345, 34334, 34341, 34857, 34845, 34843, 34848, michael@0: 34852, 34844, 34859, 34890, 35181, 35177, 35182, 35179, 35322, 35705, michael@0: 35704, 35653, {f: 2, c: 35706}, 36112, 36116, 36271, 36494, 36492, 36702, michael@0: 36699, 36701, 37190, {f: 2, c: 37188}, 37305, 37951, 37947, 37942, 37929, michael@0: 37949, 37936, 37945, 37930, 37943, 37932, 37952, 37937, 38373, 38372, michael@0: 38371, 38709, 38714, 38847, 38881, 39012, 39113, 39110, 39104, 39256, michael@0: 39254, 39481, 39485, 39494, 39492, 39490, 39489, 39482, 39487, 39629, michael@0: 39701, {f: 2, c: 39703}, 39702, 39738, 39762, 39979, 39965, 39964, 39980, michael@0: 39971, {f: 2, c: 39976}, 39972, 39969, 40375, 40374, 40380, 40385, 40391, michael@0: 40394, 40399, 40382, 40389, 40387, 40379, 40373, 40398, {f: 2, c: 40377}, michael@0: 40364, 40392, 40369, 40365, 40396, 40371, 40397, 40370, 40570, 40604, michael@0: 40683, 40686, 40685, 40731, 40728, 40730, 40753, 40782, 40805, 40804, michael@0: 40850, 20153, 22214, 22213, 22219, 22897, {f: 2, c: 23371}, 24021, 24017, michael@0: 24306, 25889, 25888, 25894, 25890, 27403, {f: 2, c: 27400}, 27661, michael@0: {f: 3, c: 28757}, 28754, {f: 2, c: 29214}, 29353, 29567, 29912, 29909, michael@0: 29913, 29911, 30317, 30381, 31029, 31156, {f: 2, c: 31344}, 31831, 31836, michael@0: 31833, 31835, 31834, 31988, 31985, 32401, 32591, 32647, 33246, 33387, michael@0: {f: 2, c: 34356}, 34355, 34348, 34354, 34358, 34860, 34856, 34854, 34858, michael@0: 34853, 35185, 35263, 35262, 35323, 35710, 35716, 35714, 35718, 35717, michael@0: 35711, 36117, 36501, 36500, 36506, 36498, 36496, {f: 2, c: 36502}, 36704, michael@0: 36706, 37191, 37964, 37968, {f: 2, c: 37962}, 37967, 37959, 37957, michael@0: {f: 2, c: 37960}, 37958, 38719, 38883, 39018, 39017, 39115, 39252, 39259, michael@0: 39502, {f: 2, c: 39507}, 39500, 39503, 39496, 39498, 39497, 39506, 39504, michael@0: 39632, 39705, 39723, 39739, 39766, 39765, 40006, 40008, 39999, 40004, michael@0: 39993, 39987, 40001, 39996, 39991, 39988, 39986, 39997, 39990, 40411, michael@0: 40402, 40414, 40410, 40395, 40400, 40412, 40401, 40415, 40425, 40409, michael@0: 40408, 40406, 40437, 40405, 40413, 40630, 40688, 40757, 40755, 40754, michael@0: 40770, 40811, 40853, 40866, 20797, 21145, 22760, 22759, 22898, 23373, michael@0: 24024, 34863, 24399, 25089, {f: 2, c: 25091}, 25897, 25893, 26006, 26347, michael@0: {f: 2, c: 27409}, 27407, 27594, 28763, 28762, 29218, 29570, 29569, 29571, michael@0: 30320, 30676, 31847, 31846, 32405, 33388, 34362, 34368, 34361, 34364, michael@0: 34353, 34363, 34366, 34864, 34866, 34862, 34867, 35190, 35188, 35187, michael@0: 35326, 35724, 35726, 35723, 35720, 35909, 36121, 36504, 36708, 36707, michael@0: 37308, 37986, 37973, 37981, 37975, 37982, {f: 2, c: 38852}, 38912, 39510, michael@0: 39513, {f: 3, c: 39710}, 40018, 40024, 40016, 40010, 40013, 40011, 40021, michael@0: 40025, 40012, 40014, 40443, 40439, 40431, 40419, 40427, 40440, 40420, michael@0: 40438, 40417, 40430, 40422, 40434, [40432, 60370], 40418, 40428, 40436, michael@0: 40435, 40424, 40429, 40642, 40656, {f: 2, c: 40690}, 40710, 40732, 40760, michael@0: 40759, 40758, 40771, 40783, 40817, 40816, {f: 2, c: 40814}, 22227, 22221, michael@0: 23374, 23661, 25901, {f: 2, c: 26349}, 27411, 28767, 28769, 28765, 28768, michael@0: 29219, 29915, 29925, 30677, 31032, 31159, 31158, 31850, 32407, 32649, michael@0: 33389, 34371, 34872, 34871, 34869, 34891, {f: 2, c: 35732}, michael@0: {f: 3, c: 36510}, 36509, 37310, 37309, 37314, 37995, {f: 2, c: 37992}, michael@0: 38629, 38726, 38723, 38727, 38855, 38885, 39518, 39637, 39769, 40035, michael@0: 40039, 40038, 40034, 40030, 40032, 40450, 40446, 40455, 40451, 40454, michael@0: 40453, {f: 2, c: 40448}, 40457, 40447, 40445, 40452, 40608, 40734, 40774, michael@0: {f: 3, c: 40820}, 22228, 25902, 26040, {f: 2, c: 27416}, 27415, 27418, michael@0: 28770, 29222, 29354, {f: 2, c: 30680}, 31033, 31849, 31851, 31990, 32410, michael@0: 32408, 32411, 32409, {f: 2, c: 33248}, {f: 3, c: 34374}, {f: 2, c: 35193}, michael@0: 35196, 35195, 35327, {f: 2, c: 35736}, 36517, 36516, 36515, 37998, 37997, michael@0: 37999, 38001, 38003, 38729, 39026, 39263, 40040, 40046, 40045, 40459, michael@0: 40461, 40464, 40463, 40466, 40465, 40609, 40693, 40713, 40775, 40824, michael@0: 40827, 40826, 40825, 22302, 28774, 31855, 34876, 36274, 36518, 37315, michael@0: 38004, 38008, 38006, 38005, 39520, [39726, 60830], 40052, 40051, 40049, michael@0: 40053, 40468, 40467, 40694, 40714, 40868, 28776, 28773, 31991, 34410, michael@0: 34878, 34877, 34879, 35742, 35996, 36521, 36553, 38731, {f: 2, c: 39027}, michael@0: 39116, 39265, 39339, 39524, {f: 2, c: 39526}, 39716, 40469, 40471, 40776, michael@0: 25095, 27422, 29223, 34380, 36520, 38018, {f: 2, c: 38016}, 39529, 39528, michael@0: 40473, 34379, 35743, 38019, 40057, 40631, 30325, 39531, 40058, 40477, michael@0: {f: 2, c: 28777}, 29225, 40612, 40830, 40777, 40856, {s: 97}, 65075, 0, michael@0: 65076, 65103, [168, 776, 63208], [710, 63209, 65342], [12541, 63210], michael@0: [12542, 63211], [12445, 63212], [12446, 63213], 0, [12293, 63216], michael@0: [12294, 63217], [12295, 63218], [12540, 63219], [63220, 65339], michael@0: [63221, 65341], [10045, 63222], [12353, 63223], [12354, 63224], michael@0: [12355, 63225], [12356, 63226], [12357, 63227], [12358, 63228], michael@0: [12359, 63229], [12360, 63230], [12361, 63231], [12362, 63232], michael@0: [12363, 63233], [12364, 63234], [12365, 63235], [12366, 63236], michael@0: [12367, 63237], [12368, 63238], [12369, 63239], [12370, 63240], michael@0: [12371, 63241], [12372, 63242], [12373, 63243], [12374, 63244], michael@0: [12375, 63245], [12376, 63246], [12377, 63247], [12378, 63248], michael@0: [12379, 63249], [12380, 63250], [12381, 63251], [12382, 63252], michael@0: [12383, 63253], [12384, 63254], [12385, 63255], [12386, 63256], michael@0: [12387, 63257], [12388, 63258], [12389, 63259], [12390, 63260], michael@0: [12391, 63261], [12392, 63262], [12393, 63263], [12394, 63264], michael@0: [12395, 63265], [12396, 63266], [12397, 63267], [12398, 63268], michael@0: [12399, 63269], [12400, 63270], [12401, 63271], [12402, 63272], michael@0: [12403, 63273], [12404, 63274], [12405, 63275], [12406, 63276], michael@0: [12407, 63277], [12408, 63278], [12409, 63279], [12410, 63280], michael@0: [12411, 63281], [12412, 63282], [12413, 63283], [12414, 63284], michael@0: [12415, 63285], [12416, 63286], [12417, 63287], [12418, 63288], michael@0: [12419, 63289], [12420, 63290], [12421, 63291], [12422, 63292], michael@0: [12423, 63293], [12424, 63294], [12425, 63295], [12426, 63296], michael@0: [12427, 63297], [12428, 63298], [12429, 63299], [12430, 63300], michael@0: [12431, 63301], [12432, 63302], [12433, 63303], [12434, 63304], michael@0: [12435, 63305], [12449, 63306], [12450, 63307], [12451, 63308], michael@0: [12452, 63309], [12453, 63310], [12454, 63311], [12455, 63312], michael@0: [12456, 63313], [12457, 63314], [12458, 63315], [12459, 63316], michael@0: [12460, 63317], [12461, 63318], [12462, 63319], [12463, 63320], michael@0: [12464, 63321], [12465, 63322], [12466, 63323], [12467, 63324], michael@0: [12468, 63325], [12469, 63326], [12470, 63327], [12471, 63328], michael@0: [12472, 63329], [12473, 63330], [12474, 63331], [12475, 63332], michael@0: [12476, 63333], [12477, 63334], [12478, 63335], [12479, 63336], michael@0: [12480, 63337], [12481, 63338], [12482, 63339], [12483, 63340], michael@0: [12484, 63341], [12485, 63342], [12486, 63343], [12487, 63344], michael@0: [12488, 63345], [12489, 63346], [12490, 63347], [12491, 63348], michael@0: [12492, 63349], [12493, 63350], [12494, 63351], [12495, 63352], michael@0: [12496, 63353], [12497, 63354], [12498, 63355], [12499, 63356], michael@0: [12500, 63357], [12501, 63358], [12502, 63359], [12503, 63360], michael@0: [12504, 63361], [12505, 63362], [12506, 63363], [12507, 63364], michael@0: [12508, 63365], [12509, 63366], [12510, 63367], [12511, 63368], michael@0: [12512, 63369], [12513, 63370], [12514, 63371], [12515, 63372], michael@0: [12516, 63373], [12517, 63374], [12518, 63375], [12519, 63376], michael@0: [12520, 63377], [12521, 63378], [12522, 63379], [12523, 63380], michael@0: [12524, 63381], [12525, 63382], [12526, 63383], [12527, 63384], michael@0: [12528, 63385], [12529, 63386], [12530, 63387], [12531, 63388], michael@0: [12532, 63389], [12533, 63390], [12534, 63391], [1040, 63392], michael@0: [1041, 63393], [1042, 63394], [1043, 63395], [1044, 63396], [1045, 63397], michael@0: [1025, 63398], [1046, 63399], [1047, 63400], [1048, 63401], [1049, 63402], michael@0: [1050, 63403], [1051, 63404], [1052, 63405], [1053, 63406], [1054, 63407], michael@0: [1055, 63408], [1056, 63409], [1057, 63410], [1058, 63411], [1059, 63412], michael@0: [1060, 63413], [1061, 63414], [1062, 63415], [1063, 63416], [1064, 63417], michael@0: [1065, 63418], [1066, 63419], [1067, 63420], [1068, 63421], [1069, 63422], michael@0: [1070, 63423], [1071, 63424], [1072, 63425], [1073, 63426], [1074, 63427], michael@0: [1075, 63428], [1076, 63429], [1077, 63430], [1105, 63431], [1078, 63432], michael@0: [1079, 63433], [1080, 63434], [1081, 63435], [1082, 63436], [1083, 63437], michael@0: [1084, 63438], [1085, 63439], [1086, 63440], [1087, 63441], [1088, 63442], michael@0: [1089, 63443], [1090, 63444], [1091, 63445], [1092, 63446], [1093, 63447], michael@0: [1094, 63448], [1095, 63449], [1096, 63450], [1097, 63451], [1098, 63452], michael@0: [1099, 63453], [1100, 63454], [1101, 63455], [1102, 63456], [1103, 63457], michael@0: [8679, 63458], [8632, 63459], [8633, 63460], [20033, 63461], michael@0: [63462, 131276], [20058, 63463], [63464, 131210], [20994, 63465], michael@0: [17553, 63466], 63467, [20872, 63468], [13853, 63469], [63470, 161287], michael@0: {s: 40}, [172, 63511, 65506], [63512, 65508], [63513, 65287], michael@0: [63514, 65282], [12849, 63515], [8470, 63516], [8481, 63517], 30849, michael@0: [37561, 58501], 35023, 22715, 24658, 31911, 23290, 9556, 9574, 9559, 9568, michael@0: 9580, 9571, 9562, 9577, 9565, 9554, 9572, 9557, {s: 3}, 9560, 9575, 9563, michael@0: 9555, 9573, 9558, 9567, 9579, 9570, 9561, 9576, 9564, 9553, {s: 5}, 9619, michael@0: {s: 26}, [58129, 147159], [22462, 58130], [58131, 159443], [28990, 58132], michael@0: [58133, 153568], [27042, 58135], [58136, 166889], [23412, 58137], michael@0: [31305, 58138], [58139, 153825], [58140, 169177], [31333, 58141], michael@0: [31357, 58142], [58143, 154028], [31419, 58144], [31408, 58145], michael@0: [31426, 58146], [31427, 58147], [29137, 58148], [58149, 156813], michael@0: [16842, 58150], [31450, 58151], [31453, 58152], [31466, 58153], michael@0: [16879, 58154], [21682, 58155], [58156, 154625], [31499, 58157], michael@0: [31573, 58158], [31529, 58159], [58160, 152334], [58161, 154878], michael@0: [31650, 58162], [31599, 58163], [33692, 58164], [58165, 154548], michael@0: [58166, 158847], [31696, 58167], [33825, 58168], [31634, 58169], 0, michael@0: [58171, 154912], 0, [33938, 58174], [31738, 58175], 0, [31797, 58177], michael@0: [58178, 154817], [31812, 58179], [31875, 58180], [58181, 149634], michael@0: [31910, 58182], [58184, 148856], [31945, 58185], [31943, 58186], michael@0: [31974, 58187], 0, [31987, 58189], [31989, 58190], [32359, 58192], michael@0: [17693, 58193], [58194, 159300], [32093, 58195], [58196, 159446], michael@0: [32137, 58198], [32171, 58199], [28981, 58200], [32179, 58201], 32214, michael@0: [58203, 147543], [58204, 155689], [32228, 58205], [15635, 58206], michael@0: [32245, 58207], [58208, 137209], [32229, 58209], [58210, 164717], 0, michael@0: [58212, 155937], [58213, 155994], [32366, 58214], 0, [17195, 58216], michael@0: [37996, 58217], [32295, 58218], [32576, 58219], [32577, 58220], michael@0: [32583, 58221], [31030, 58222], [58223, 156368], [39393, 58224], michael@0: [32663, 58225], [58226, 156497], [32675, 58227], [58228, 136801], michael@0: [58229, 131176], [17756, 58230], [58231, 145254], [58233, 164666], michael@0: [32762, 58234], [58235, 156809], 0, [32776, 58237], [32797, 58238], 0, michael@0: [32815, 58240], [58241, 172167], [58242, 158915], [32827, 58243], michael@0: [32828, 58244], [32865, 58245], [58246, 141076], [18825, 58247], michael@0: [58248, 157222], [58249, 146915], [58250, 157416], [26405, 58251], michael@0: [32935, 58252], [58253, 166472], [33031, 58254], [33050, 58255], michael@0: [22704, 58256], [58257, 141046], [27775, 58258], [58259, 156824], michael@0: [25831, 58261], [58262, 136330], [33304, 58263], [58264, 137310], michael@0: [27219, 58265], [58266, 150117], [58267, 150165], [17530, 58268], michael@0: [33321, 58269], [58271, 158290], [58272, 146814], [20473, 58273], michael@0: [58274, 136445], [34018, 58275], [33634, 58276], 0, [58278, 149927], michael@0: [58279, 144688], [58280, 137075], [58281, 146936], [33450, 58282], michael@0: [26907, 58283], [58284, 194964], [16859, 58285], [34123, 58286], michael@0: [33488, 58287], [33562, 58288], [58289, 134678], [58290, 137140], michael@0: [14017, 58291], [58292, 143741], [58293, 144730], [33403, 58294], michael@0: [33506, 58295], [33560, 58296], [58297, 147083], [58298, 159139], michael@0: [58299, 158469], [58300, 158615], [58301, 144846], [15807, 58302], michael@0: [33565, 58303], [21996, 58304], [33669, 58305], [17675, 58306], michael@0: [58307, 159141], [33708, 58308], 0, [33747, 58310], [58312, 159444], michael@0: [27223, 58313], [34138, 58314], [13462, 58315], [58316, 159298], michael@0: [33880, 58318], [58319, 154596], [33905, 58320], [15827, 58321], michael@0: [17636, 58322], [27303, 58323], [33866, 58324], [31064, 58326], 0, michael@0: [58328, 158614], [58329, 159351], [58330, 159299], [34014, 58331], 0, michael@0: [33681, 58333], [17568, 58334], [33939, 58335], [34020, 58336], michael@0: [58337, 154769], [16960, 58338], [58339, 154816], [17731, 58340], michael@0: [34100, 58341], [23282, 58342], 0, [17703, 58344], [34163, 58345], michael@0: [17686, 58346], [26559, 58347], [34326, 58348], [58349, 165413], michael@0: [58350, 165435], [34241, 58351], [58352, 159880], [34306, 58353], michael@0: [58354, 136578], [58355, 159949], [58356, 194994], [17770, 58357], michael@0: [34344, 58358], [13896, 58359], [58360, 137378], [21495, 58361], michael@0: [58362, 160666], [34430, 58363], 0, [58365, 172280], [34798, 58366], michael@0: [58367, 142375], [34737, 58368], [34778, 58369], [34831, 58370, 60990], michael@0: [22113, 58371], [34412, 58372], [26710, 58373], [17935, 58374], michael@0: [34885, 58375], [34886, 58376], [58377, 161248], [58378, 146873], michael@0: [58379, 161252], [34910, 58380], [34972, 58381], [18011, 58382], michael@0: [34996, 58383], [34997, 58384], [35013, 58386], [58388, 161551], michael@0: [35207, 58389], {s: 3}, [35239, 58393], [35260, 58394], [58395, 166437], michael@0: [35303, 58396], [58397, 162084], [58398, 162493], [35484, 58399], michael@0: [30611, 58400], [37374, 58401], [35472, 58402], [58403, 162393], michael@0: [31465, 58404], [58405, 162618], [18195, 58407], [58408, 162616], michael@0: [29052, 58409], [35596, 58410], [35615, 58411], [58412, 152624], michael@0: [58413, 152933], [35647, 58414], 0, [35661, 58416], [35497, 58417], michael@0: [58418, 150138], [35728, 58419], [35739, 58420], [35503, 58421], michael@0: [58422, 136927], [17941, 58423], [34895, 58424], [35995, 58425], michael@0: [58426, 163156], [58427, 163215], [58428, 195028], [14117, 58429], michael@0: [58430, 163155], [36054, 58431], [58432, 163224], [58433, 163261], michael@0: [36114, 58434], [36099, 58435], [58436, 137488], [36059, 58437], michael@0: [28764, 58438], [36113, 58439], [16080, 58441], 0, [36265, 58443], michael@0: [58444, 163842], [58445, 135188], [58446, 149898], [15228, 58447], michael@0: [58448, 164284], [58449, 160012], [31463, 58450], [36525, 58451], michael@0: [36534, 58452], [36547, 58453], [37588, 58454], [36633, 58455], michael@0: [36653, 58456], [58457, 164709], [58458, 164882], [36773, 58459], michael@0: [37635, 58460], [58461, 172703], [58462, 133712], [36787, 58463], 0, michael@0: [58465, 166366], [58466, 165181], [58467, 146875], [24312, 58468], michael@0: [58469, 143970], [36857, 58470], 0, [58474, 140069], [14720, 58475], michael@0: [58476, 159447], [36919, 58477], [58478, 165180], [58479, 162494], michael@0: [36961, 58480], [58481, 165228], [58482, 165387], [37032, 58483], michael@0: [58484, 165651], [37060, 58485], [58486, 165606], [37038, 58487], 0, michael@0: [37223, 58489], [37289, 58491], [37316, 58492], [31916, 58493], michael@0: [58494, 166195], [58495, 138889], [37390, 58496], [27807, 58497], michael@0: [37441, 58498], [37474, 58499], [58500, 153017], [58502, 166598], michael@0: [58503, 146587], [58504, 166668], [58505, 153051], [58506, 134449], michael@0: [37676, 58507], [37739, 58508], [58509, 166625], [58510, 166891], michael@0: [23235, 58512], [58513, 166626], [58514, 166629], [18789, 58515], michael@0: [37444, 58516], [58517, 166892], [58518, 166969], [58519, 166911], michael@0: [37747, 58520], [37979, 58521], [36540, 58522], [38277, 58523], michael@0: [38310, 58524], [37926, 58525], [38304, 58526], [28662, 58527], michael@0: [17081, 58528], [58530, 165592], [58531, 135804], [58532, 146990], michael@0: [18911, 58533], [27676, 58534], [38523, 58535], [38550, 58536], michael@0: [16748, 58537], [38563, 58538], [58539, 159445], [25050, 58540], 58541, michael@0: [30965, 58542], [58543, 166624], [38589, 58544], [21452, 58545], michael@0: [18849, 58546], [58547, 158904], [58548, 131700], [58549, 156688], michael@0: [58550, 168111], [58551, 168165], [58552, 150225], [58553, 137493], michael@0: [58554, 144138], [38705, 58555], [34370, 58556], [38710, 58557], michael@0: [18959, 58558], [17725, 58559], [17797, 58560], [58561, 150249], michael@0: [28789, 58562], [23361, 58563], [38683, 58564], 0, [58566, 168405], michael@0: [38743, 58567], [23370, 58568], [58569, 168427], [38751, 58570], michael@0: [37925, 58571], [20688, 58572], [58573, 143543], [58574, 143548], michael@0: [38793, 58575], [38815, 58576], [38833, 58577], [38846, 58578], michael@0: [38848, 58579], [38866, 58580], [38880, 58581], [58582, 152684], michael@0: [38894, 58583], [29724, 58584], [58585, 169011], 0, [38901, 58587], michael@0: [58588, 168989], [58589, 162170], [19153, 58590], [38964, 58591], michael@0: [38963, 58592], [38987, 58593], [39014, 58594], [15118, 58595], michael@0: [58596, 160117], [15697, 58597], [58598, 132656], [58599, 147804], michael@0: [58600, 153350], [39114, 58601], [39095, 58602], [39112, 58603], michael@0: [39111, 58604], [19199, 58605], [58606, 159015], [58607, 136915], michael@0: [21936, 58608], [39137, 58609], [39142, 58610], [39148, 58611], michael@0: [37752, 58612], [39225, 58613], [58614, 150057], [19314, 58615], michael@0: [58616, 170071], [58617, 170245], [39413, 58618], [39436, 58619], michael@0: [39483, 58620], [39440, 58621], [39512, 58622], [58623, 153381], michael@0: [14020, 58624], [58625, 168113], [58626, 170965], [39648, 58627], michael@0: [39650, 58628], [58629, 170757], [39668, 58630], [19470, 58631], michael@0: [39700, 58632], [39725, 58633], [58634, 165376], [20532, 58635], michael@0: [39732, 58636], [14531, 58638], [58639, 143485], [39760, 58640], michael@0: [39744, 58641], [58642, 171326], [23109, 58643], [58644, 137315], michael@0: [39822, 58645], [39938, 58647], [39935, 58648], [39948, 58649], michael@0: [58650, 171624], [40404, 58651], [58652, 171959], [58653, 172434], michael@0: [58654, 172459], [58655, 172257], [58656, 172323], [58657, 172511], michael@0: [40318, 58658], [40323, 58659], [58660, 172340], [40462, 58661], michael@0: [40388, 58663], [58665, 172435], [58666, 172576], [58667, 137531], michael@0: [58668, 172595], [40249, 58669], [58670, 172217], [58671, 172724], michael@0: [40592, 58672], [40597, 58673], [40606, 58674], [40610, 58675], michael@0: [19764, 58676], [40618, 58677], [40623, 58678], [58679, 148324], michael@0: [40641, 58680], [15200, 58681], [14821, 58682], [15645, 58683], michael@0: [20274, 58684], [14270, 58685], [58686, 166955], [40706, 58687], michael@0: [40712, 58688], [19350, 58689], [37924, 58690], [58691, 159138], michael@0: [40727, 58692, 60836], 0, [40761, 58694], [22175, 58695], [22154, 58696], michael@0: [40773, 58697], [39352, 58698], [58699, 168075], [38898, 58700], michael@0: [33919, 58701], 0, [40809, 58703], [31452, 58704], [40846, 58705], michael@0: [29206, 58706], [19390, 58707], [58708, 149877], [58709, 149947], michael@0: [29047, 58710], [58711, 150008], [58712, 148296], [58713, 150097], michael@0: [29598, 58714], [58715, 166874], [58716, 137466], [31135, 58717], michael@0: [58718, 166270], [58719, 167478], [37737, 58720], [37875, 58721], michael@0: [58722, 166468], [37612, 58723], [37761, 58724], [37835, 58725], michael@0: [58726, 166252], [58727, 148665], [29207, 58728], [16107, 58729], michael@0: [30578, 58730], [31299, 58731], [28880, 58732], [58733, 148595], michael@0: [58734, 148472], [29054, 58735], [58736, 137199], [28835, 58737], michael@0: [58738, 137406], [58739, 144793], [16071, 58740], [58741, 137349], michael@0: [58742, 152623], [58743, 137208], [14114, 58744], [58745, 136955], michael@0: [58746, 137273], [14049, 58747], [58748, 137076], [58749, 137425], michael@0: [58750, 155467], [14115, 58751], [58752, 136896], [22363, 58753], michael@0: [58754, 150053], [58755, 136190], [58756, 135848], [58757, 136134], michael@0: [58758, 136374], [34051, 58759, 58761], [58760, 145062], 0, [33877, 58762], michael@0: [58763, 149908], [58764, 160101], [58765, 146993], [58766, 152924], michael@0: [58767, 147195], [58768, 159826], [17652, 58769], [58770, 145134], michael@0: [58771, 170397], [58772, 159526], [26617, 58773], [14131, 58774], michael@0: [15381, 58775], [15847, 58776], [22636, 58777], [58778, 137506], michael@0: [26640, 58779], [16471, 58780], [58781, 145215], [58782, 147681], michael@0: [58783, 147595], [58784, 147727], [58785, 158753], [21707, 58786], michael@0: [22174, 58787], [58788, 157361], [22162, 58789], [58790, 135135], michael@0: [58791, 134056], [58792, 134669], 0, [58794, 166675], [37788, 58795], michael@0: [20216, 58796], [20779, 58797], [14361, 58798], [58799, 148534], michael@0: [20156, 58800], [58801, 132197], 0, [20299, 58803], [20362, 58804], michael@0: [58805, 153169], [23144, 58806], [58807, 131499], [58808, 132043], michael@0: [14745, 58809], [58810, 131850], [58811, 132116], [13365, 58812], michael@0: [20265, 58813], [58814, 131776], [58815, 167603], [58816, 131701], michael@0: [35546, 58817], [58818, 131596], [20120, 58819], [20685, 58820], michael@0: [20749, 58821], [20386, 58822], [20227, 58823], [58824, 150030], michael@0: [58825, 147082], [20290, 58826], [20526, 58827], [20588, 58828], michael@0: [20609, 58829], [20428, 58830], [20453, 58831], [20568, 58832], michael@0: [20732, 58833], [28278, 58838], [58839, 144789], [58840, 147001], michael@0: [58841, 147135], [28018, 58842], [58843, 137348], [58844, 147081], michael@0: [20904, 58845], [20931, 58846], [58847, 132576], [17629, 58848], michael@0: [58849, 132259], [58850, 132242], [58851, 132241], [36218, 58852], michael@0: [58853, 166556], [58854, 132878], [21081, 58855], [21156, 58856], michael@0: [58857, 133235], [21217, 58858], 0, [18042, 58860], [29068, 58861], michael@0: [58862, 148364], [58863, 134176], [58864, 149932], [58865, 135396], michael@0: [27089, 58866], [58867, 134685], 0, [16094, 58869], [29849, 58870], michael@0: [29716, 58871], [29782, 58872], [29592, 58873], [19342, 58874], michael@0: [58875, 150204], [58876, 147597], [21456, 58877], [13700, 58878], michael@0: [29199, 58879], [58880, 147657], [21940, 58881], [58882, 131909], michael@0: [21709, 58883], [58884, 134086], [22301, 58885], [37469, 58886], michael@0: [38644, 58887], [22493, 58889], [22413, 58890], [22399, 58891], michael@0: [13886, 58892], [22731, 58893], [23193, 58894], [58895, 166470], michael@0: [58896, 136954], [58897, 137071], [58898, 136976], [23084, 58899], michael@0: [22968, 58900], [23166, 58902], [23247, 58903], [23058, 58904], michael@0: [58905, 153926], [58906, 137715], [58907, 137313], [58908, 148117], michael@0: [14069, 58909], [27909, 58910], [29763, 58911], [23073, 58912], michael@0: [58913, 155267], [23169, 58914], [58915, 166871], [58916, 132115], michael@0: [37856, 58917], [29836, 58918], [58919, 135939], [28933, 58920], michael@0: [18802, 58921], [37896, 58922], [58923, 166395], [37821, 58924], michael@0: [14240, 58925], [23582, 58926], [23710, 58927], [24158, 58928], michael@0: [24136, 58929], [58930, 137622], [58931, 137596], [58932, 146158], michael@0: [24269, 58933], [23375, 58934], [58935, 137475], [58936, 137476], michael@0: [14081, 58937], [58938, 137376], [14045, 58939], [58940, 136958], michael@0: [14035, 58941], [33066, 58942], [58943, 166471], [58944, 138682], michael@0: [58945, 144498], [58946, 166312], [24332, 58947, 60916], [24334, 58948], michael@0: [58949, 137511], [58950, 137131], [23147, 58951], [58952, 137019], michael@0: [23364, 58953], [58955, 161277], [34912, 58956], [24702, 58957], michael@0: [58958, 141408], [58959, 140843], [24539, 58960], [16056, 58961], michael@0: [58962, 140719], [58963, 140734], [58964, 168072], [58965, 159603], michael@0: [25024, 58966], [58967, 131134], [58968, 131142], [58969, 140827], michael@0: [24985, 58970], [24984, 58971], [24693, 58972], [58973, 142491], michael@0: [58974, 142599], [58975, 149204], [58976, 168269], [25713, 58977], michael@0: [58978, 149093], [58979, 142186], [14889, 58980], [58981, 142114], michael@0: [58982, 144464], [58983, 170218], [58984, 142968], [25399, 58985], michael@0: [25782, 58987], [25393, 58988], [25553, 58989], [58990, 149987], michael@0: [58991, 142695], [25252, 58992], [58993, 142497], [25659, 58994], michael@0: [25963, 58995], [26994, 58996], [15348, 58997], [58998, 143502], michael@0: [58999, 144045], [59000, 149897], [59001, 144043], [21773, 59002], michael@0: [59003, 144096], [59004, 137433], [59005, 169023], [26318, 59006], michael@0: [59007, 144009], [59008, 143795], [15072, 59009], [59011, 152964], michael@0: [59012, 166690], [59013, 152975], [59014, 136956], [59015, 152923], michael@0: [59016, 152613], [30958, 59017], [59018, 143619], [59019, 137258], michael@0: [59020, 143924], [13412, 59021], [59022, 143887], [59023, 143746], michael@0: [59024, 148169], [26254, 59025], [59026, 159012], [26219, 59027], michael@0: [19347, 59028], [26160, 59029], [59030, 161904], [59031, 138731], michael@0: [26211, 59032], [59033, 144082], [59034, 144097], [26142, 59035], michael@0: [59036, 153714], [14545, 59037], [59038, 145466], [59039, 145340], michael@0: [15257, 59040], [59041, 145314], [59042, 144382], [29904, 59043], michael@0: [15254, 59044], [59046, 149034], [26806, 59047], 0, [15300, 59049], michael@0: [27326, 59050], [59052, 145365], [59053, 148615], [27187, 59054], michael@0: [27218, 59055], [27337, 59056], [27397, 59057], [59058, 137490], michael@0: [25873, 59059], [26776, 59060], [27212, 59061], [15319, 59062], michael@0: [27258, 59063], [27479, 59064], [59065, 147392], [59066, 146586], michael@0: [37792, 59067], [37618, 59068], [59069, 166890], [59070, 166603], michael@0: [37513, 59071], [59072, 163870], [59073, 166364], [37991, 59074], michael@0: [28069, 59075], [28427, 59076], 0, [59079, 147327], [15759, 59080], michael@0: [28164, 59081], [59082, 147516], [23101, 59083], [28170, 59084], michael@0: [22599, 59085], [27940, 59086], [30786, 59087], [28987, 59088], michael@0: [59089, 148250], [59090, 148086], [28913, 59091], [29264, 59092, 61085], michael@0: [29319, 59093], [29332, 59094], [59095, 149391], [59096, 149285], michael@0: [20857, 59097], [59098, 150180], [59099, 132587], [29818, 59100], michael@0: [59101, 147192], [59102, 144991], [59103, 150090], [59104, 149783], michael@0: [59105, 155617], [16134, 59106], [16049, 59107], [59108, 150239], michael@0: [59109, 166947], [59110, 147253], [24743, 59111], [16115, 59112], michael@0: [29900, 59113], [29756, 59114], [37767, 59115], [29751, 59116], michael@0: [17567, 59117], [59118, 159210], [17745, 59119], [30083, 59120], michael@0: [16227, 59121], [59122, 150745], [59123, 150790], [16216, 59124], michael@0: [30037, 59125], [30323, 59126], [59127, 173510], 0, [29800, 59129, 61070], michael@0: [59130, 166604], [59131, 149931], [59132, 149902], [15099, 59133], michael@0: [15821, 59134], [59135, 150094], [16127, 59136], [59137, 149957], michael@0: [59138, 149747], [37370, 59139], [22322, 59140], [37698, 59141], michael@0: [59142, 166627], [59143, 137316], [20703, 59144], [59145, 152097], michael@0: [59146, 152039], [30584, 59147], [59148, 143922], [30478, 59149], michael@0: [30479, 59150], [30587, 59151], [59152, 149143], [59153, 145281], michael@0: [14942, 59154], [59155, 149744], [29752, 59156], [29851, 59157], michael@0: [16063, 59158], [59159, 150202], [59160, 150215], [16584, 59161], michael@0: [59162, 150166], [59163, 156078], [37639, 59164], [59165, 152961], michael@0: [30750, 59166], [30861, 59167], [30856, 59168], [30930, 59169], michael@0: [29648, 59170], [31065, 59171], [59172, 161601], [59173, 153315], michael@0: [16654, 59174], 0, 0, [31141, 59177], [27181, 59178], [59179, 147194], michael@0: [31290, 59180], [31220, 59181], [16750, 59182], [59183, 136934], michael@0: [16690, 59184], [37429, 59185], [31217, 59186], [59187, 134476], michael@0: [59188, 149900], [59189, 131737], [59190, 146874], [59191, 137070], michael@0: [13719, 59192], [21867, 59193], [13680, 59194], [13994, 59195], michael@0: [59196, 131540], [59197, 134157], [31458, 59198], [23129, 59199], michael@0: [59200, 141045], [59201, 154287], [59202, 154268], [23053, 59203], michael@0: [59204, 131675], [30960, 59205], [23082, 59206], [59207, 154566], michael@0: [31486, 59208], [16889, 59209], [31837, 59210], [31853, 59211], michael@0: [16913, 59212], [59213, 154547], [59214, 155324], [59215, 155302], michael@0: [31949, 59216], [59217, 150009], [59218, 137136], [31886, 59219], michael@0: [31868, 59220], [31918, 59221], [27314, 59222], [32220, 59223], michael@0: [32263, 59224], [32211, 59225], [32590, 59226], [59227, 156257], michael@0: [59228, 155996], [59229, 162632], [32151, 59230], [59231, 155266], michael@0: [17002, 59232], [59233, 158581], [59234, 133398], [26582, 59235], michael@0: [59236, 131150], [59237, 144847], [22468, 59238], [59239, 156690], michael@0: [59240, 156664], [32733, 59242], [31527, 59243], [59244, 133164], michael@0: [59245, 154345], [59246, 154947], [31500, 59247], [59248, 155150], michael@0: [39398, 59249], [34373, 59250], [39523, 59251], [27164, 59252], michael@0: [59253, 144447], [59255, 150007], [59256, 157101], [39455, 59257], michael@0: [59258, 157088], 0, [59260, 160039], [59261, 158929], [17642, 59262], michael@0: [33079, 59263], [17410, 59264], [32966, 59265], [33033, 59266], michael@0: [33090, 59267], [59268, 157620], [39107, 59269], [59270, 158274], michael@0: [33378, 59271], [33381, 59272], [59273, 158289], [33875, 59274], michael@0: [59275, 159143], [34320, 59276], [59277, 160283], [23174, 59278], michael@0: [16767, 59279], [59280, 137280], [23339, 59281], [59282, 137377], michael@0: [23268, 59283], [59284, 137432], [34464, 59285], [59286, 195004], michael@0: [59287, 146831], [34861, 59288], [59289, 160802], [23042, 59290], michael@0: [34926, 59291], [20293, 59292], [34951, 59293], [35007, 59294], michael@0: [35046, 59295], [35173, 59296], [35149, 59297], [59298, 153219], michael@0: [35156, 59299], [59300, 161669], [59301, 161668], [59302, 166901], michael@0: [59303, 166873], [59304, 166812], [59305, 166393], [16045, 59306], michael@0: [33955, 59307], [18165, 59308], [18127, 59309], [14322, 59310], michael@0: [35389, 59311], [35356, 59312], [59313, 169032], [24397, 59314], michael@0: [37419, 59315], [59316, 148100], [26068, 59317], [28969, 59318], michael@0: [28868, 59319], [59320, 137285], [40301, 59321], [35999, 59322], michael@0: [36073, 59323], [59324, 163292], [22938, 59325], [30659, 59326], michael@0: [23024, 59327], [14036, 59329], [36394, 59330], [36519, 59331], michael@0: [59332, 150537], [36656, 59333], [36682, 59334], [17140, 59335], michael@0: [27736, 59336], [28603, 59337], [59338, 140065], [18587, 59339], michael@0: [28537, 59340], [28299, 59341], [59342, 137178], [39913, 59343], michael@0: [14005, 59344], [59345, 149807], [37051, 59346], 0, [21873, 59348], michael@0: [18694, 59349], [37307, 59350], [37892, 59351], [59352, 166475], michael@0: [16482, 59353], [59354, 166652], [37927, 59355], [59356, 166941], michael@0: [59357, 166971], [34021, 59358], [35371, 59359], [38297, 59360], michael@0: [38311, 59361], [38295, 59362], [38294, 59363], [59364, 167220], michael@0: [29765, 59365], [16066, 59366], [59367, 149759], [59368, 150082], michael@0: [59369, 148458], [16103, 59370], [59371, 143909], [38543, 59372], michael@0: [59373, 167655], [59374, 167526], [59375, 167525], [16076, 59376], michael@0: [59377, 149997], [59378, 150136], [59379, 147438], [29714, 59380], michael@0: [29803, 59381], [16124, 59382], [38721, 59383], [59384, 168112], michael@0: [26695, 59385], [18973, 59386], [59387, 168083], [59388, 153567], 0, michael@0: [37736, 59390], [59391, 166281], [59392, 166950], [59393, 166703], michael@0: [59394, 156606], [37562, 59395], [23313, 59396], [35689, 59397], michael@0: [18748, 59398], [29689, 59399], [59400, 147995], [38811, 59401], 0, michael@0: [39224, 59403], [59404, 134950], [24001, 59405], [59406, 166853], michael@0: [59407, 150194], [38943, 59408], [59409, 169178], [37622, 59410], michael@0: [59411, 169431], [37349, 59412], [17600, 59413], [59414, 166736], michael@0: [59415, 150119], [59416, 166756], [39132, 59417], [59418, 166469], michael@0: [16128, 59419], [37418, 59420], [18725, 59421], [33812, 59422], michael@0: [39227, 59423], [39245, 59424], [59425, 162566], [15869, 59426], 0, michael@0: [19311, 59428], [39338, 59429], [39516, 59430], [59431, 166757], michael@0: [59432, 153800], [27279, 59433], [39457, 59434], [23294, 59435], michael@0: [39471, 59436], [59437, 170225], [19344, 59438], [59439, 170312], michael@0: [39356, 59440], [19389, 59441], [19351, 59442], [37757, 59443], michael@0: [22642, 59444], [59445, 135938], [22562, 59446], [59447, 149944], michael@0: [59448, 136424], [30788, 59449], [59450, 141087], [59451, 146872], michael@0: [26821, 59452], [15741, 59453], [37976, 59454], [14631, 59455], michael@0: [24912, 59456], [59457, 141185], [59458, 141675], [24839, 59459], michael@0: [40015, 59460], [40019, 59461], [40059, 59462], [39989, 59463], michael@0: [39952, 59464], [39807, 59465], [39887, 59466], [59467, 171565], michael@0: [39839, 59468], [59469, 172533], [59470, 172286], [40225, 59471], michael@0: [19630, 59472], [59473, 147716], [40472, 59474], [19632, 59475], michael@0: [40204, 59476], [59477, 172468], [59478, 172269], [59479, 172275], michael@0: [59480, 170287], [40357, 59481], [33981, 59482], [59483, 159250], michael@0: [59484, 159711], [59485, 158594], [34300, 59486], [17715, 59487], michael@0: [59488, 159140], [59489, 159364], [59490, 159216], [33824, 59491], michael@0: [34286, 59492], [59493, 159232], [59494, 145367], [59495, 155748], michael@0: [31202, 59496], [59497, 144796], [59498, 144960], [59500, 149982], michael@0: [15714, 59501], [37851, 59502], [37566, 59503], [37704, 59504], michael@0: [59505, 131775], [30905, 59506], [37495, 59507], [37965, 59508], michael@0: [20452, 59509], [13376, 59510], [36964, 59511], [59512, 152925], michael@0: [30781, 59513], [30804, 59514], [30902, 59515], [30795, 59516], michael@0: [59517, 137047], [59518, 143817], [59519, 149825], [13978, 59520], michael@0: [20338, 59521], [28634, 59522], [28633, 59523], 0, [28702, 59524, 59525], michael@0: [21524, 59526], [59527, 147893], [22459, 59528], [22771, 59529], michael@0: [22410, 59530], [40214, 59531], [22487, 59532], [28980, 59533], michael@0: [13487, 59534], [59535, 147884], [29163, 59536], [59537, 158784], michael@0: [59538, 151447], 0, [59540, 137141], [59541, 166473], [24844, 59542], michael@0: [23246, 59543], [23051, 59544], [17084, 59545], [59546, 148616], michael@0: [14124, 59547], [19323, 59548], [59549, 166396], [37819, 59550], michael@0: [37816, 59551], [59552, 137430], [59553, 134941], [33906, 59554], michael@0: [59555, 158912], [59556, 136211], [59557, 148218], [59558, 142374], michael@0: [59559, 148417], [22932, 59560], [59561, 146871], [59562, 157505], michael@0: [32168, 59563], [59564, 155995], [59565, 155812], [59566, 149945], michael@0: [59567, 149899], [59568, 166394], [37605, 59569], [29666, 59570], michael@0: [16105, 59571], [29876, 59572], [59573, 166755], [59574, 137375], michael@0: [16097, 59575], [59576, 150195], [27352, 59577], [29683, 59578], michael@0: [29691, 59579], [16086, 59580], [59581, 150078], [59582, 150164], michael@0: [59583, 137177], [59584, 150118], [59585, 132007], [59586, 136228], michael@0: [59587, 149989], [29768, 59588], [59589, 149782], [28837, 59590], michael@0: [59591, 149878], [37508, 59592], [29670, 59593], [37727, 59594], michael@0: [59595, 132350], [37681, 59596], [59597, 166606], [59598, 166422], michael@0: [37766, 59599], [59600, 166887], [59601, 153045], [18741, 59602], michael@0: [59603, 166530], [29035, 59604], [59605, 149827], [59606, 134399], michael@0: [22180, 59607], [59608, 132634], [59609, 134123], [59610, 134328], michael@0: [21762, 59611], [31172, 59612], [59613, 137210], [32254, 59614], michael@0: [59615, 136898], [59616, 150096], [59617, 137298], [17710, 59618], michael@0: [37889, 59619], [14090, 59620], [59621, 166592], [59622, 149933], michael@0: [22960, 59623], [59624, 137407], [59625, 137347], [59626, 160900], michael@0: [23201, 59627], [14050, 59628], [59629, 146779], [14000, 59630], michael@0: [37471, 59631], [23161, 59632], [59633, 166529], [59634, 137314], michael@0: [37748, 59635], [15565, 59636], [59637, 133812], [19094, 59638], michael@0: [14730, 59639], [20724, 59640], [15721, 59641], [15692, 59642], michael@0: [59643, 136092], [29045, 59644], [17147, 59645], [59646, 164376], michael@0: [28175, 59647], [59648, 168164], [17643, 59649], [27991, 59650], michael@0: [59651, 163407], [28775, 59652], [27823, 59653], [15574, 59654], michael@0: [59655, 147437], [59656, 146989], [28162, 59657], [28428, 59658], michael@0: [15727, 59659], [59660, 132085], [30033, 59661], [14012, 59662], michael@0: [13512, 59663], [18048, 59664], [16090, 59665], [18545, 59666], michael@0: [22980, 59667], [37486, 59668], [18750, 59669], [36673, 59670], michael@0: [59671, 166940], [59672, 158656], [22546, 59673], [22472, 59674], michael@0: [14038, 59675], [59676, 136274], [28926, 59677], [59678, 148322], michael@0: [59679, 150129], [59680, 143331], [59681, 135856], [59682, 140221], michael@0: [26809, 59683], [26983, 59684], [59685, 136088], [59686, 144613], michael@0: [59687, 162804], [59688, 145119], [59689, 166531], [59690, 145366], michael@0: [59691, 144378], [59692, 150687], [27162, 59693], [59694, 145069], michael@0: [59695, 158903], [33854, 59696], [17631, 59697], [17614, 59698], michael@0: [59699, 159014], [59700, 159057], [59701, 158850], [59702, 159710], 0, 0, michael@0: [33597, 59705], [59706, 137018], [33773, 59707], [59708, 158848], michael@0: [59709, 159827], [59710, 137179], [22921, 59711], [23170, 59712], michael@0: [59713, 137139], [23137, 59714], [23153, 59715], [59716, 137477], michael@0: [59717, 147964], [14125, 59718], [23023, 59719], [59720, 137020], michael@0: [14023, 59721], [29070, 59722], [37776, 59723], [26266, 59724], michael@0: [59725, 148133], [23150, 59726], [23083, 59727], [59728, 148115], michael@0: [27179, 59729], [59730, 147193], [59731, 161590], [59732, 148571], michael@0: [59733, 148170], [28957, 59734], [59735, 148057], [59736, 166369], michael@0: [20400, 59737], [59738, 159016], [23746, 59739], [59740, 148686], michael@0: [59741, 163405], [59742, 148413], [27148, 59743], [59744, 148054], michael@0: [59745, 135940], 0, [28979, 59747], [59748, 148457], [15781, 59749], michael@0: [27871, 59750], [59751, 194597], [23019, 59754], [24412, 59757], michael@0: [59764, 144128], [31955, 59776], [59783, 162548], [59786, 153334], michael@0: [59790, 162584], [36972, 59791], [33270, 59795], [30476, 59797], michael@0: [27810, 59799], [22269, 59800], [22633, 59828], [26465, 59832], michael@0: [23646, 59838], [22770, 59841], [28857, 59843], [26627, 59853], michael@0: [36795, 59859], [36796, 59861], [20001, 59871], [31545, 59898], michael@0: [15820, 59902], [29482, 57990, 59909], [30048, 59912], [22586, 59920], michael@0: [33446, 59932], [27018, 59940], [24803, 59944], [20206, 59984], michael@0: [39364, 60002], [40639, 60023], [21249, 60025], [26528, 60038], michael@0: [24808, 60046], [20916, 60053], [31363, 60064], [39994, 60075], michael@0: [31432, 60093], [26906, 60098], [22956, 60100], [22592, 60102], michael@0: [21610, 60114], [24807, 60123], [22138, 60125], [26965, 60132], michael@0: [39983, 60133], [34725, 60134], [23584, 60141], [24075, 60143], michael@0: [26398, 60147], [33965, 60157], [35713, 60161], [20088, 60166], michael@0: [25283, 60176], [26709, 60180], 0, [33533, 60190], [35237, 60194], michael@0: [36768, 60196], [38840, 60198], [38983, 60200], [39613, 60201], michael@0: [24497, 60218], [26184, 60219], [26303, 60220], [60221, 162425], 0, michael@0: [60225, 149946], 0, 0, [60230, 131910], [26382, 60232], [26904, 60233], michael@0: [60235, 161367], [60236, 155618], [60239, 161278], [60240, 139418], michael@0: [18640, 60241], [19128, 60242], [60244, 166554], [60247, 147515], michael@0: [60250, 150085], [60251, 132554], [20946, 60252], [60253, 132625], michael@0: [22943, 60254], [60255, 138920], [15294, 60256], [60257, 146687], michael@0: [14747, 60262], [60264, 165352], [60265, 170441], [14178, 60266], michael@0: [60267, 139715], [35678, 60268], [60269, 166734], 0, [29193, 60274], michael@0: [60276, 134264], [60280, 132985], [36570, 60281], [21135, 60283], michael@0: [29041, 60285], [60288, 147274], [60289, 150183], [21948, 60290], michael@0: [60293, 158546], [13427, 60295], [60297, 161330], [18200, 60299], michael@0: [60303, 149823], [20582, 60305], [13563, 60306], [60307, 144332], 0, michael@0: [18300, 60310], [60311, 166216], [60315, 138640], 0, [60320, 162834], michael@0: [36950, 60321], [60323, 151450], [35682, 60324], [23899, 60327], michael@0: [60328, 158711], 0, [60331, 137500], [35562, 60332], [60333, 150006], michael@0: [60335, 147439], [19392, 60337], [60340, 141083], [37989, 60341], michael@0: [60342, 153569], [24981, 60343], [23079, 60344], [60345, 194765], 0, michael@0: [60348, 148769], [20074, 60350], [60351, 149812], [38486, 60352], michael@0: [28047, 60353], [60354, 158909], [35191, 60356], [60359, 156689], 0, michael@0: [31554, 60363], [60364, 168128], [60365, 133649], 0, [31301, 60369], michael@0: [39462, 60372], [13919, 60374], [60375, 156777], [60376, 131105], michael@0: [31107, 60377], [23852, 60380], [60381, 144665], 0, [18128, 60384], michael@0: [30011, 60386], [34917, 60387], [22710, 60389], [14108, 60390], michael@0: [60391, 140685], [15444, 60394], [37505, 60397], [60398, 139642], michael@0: [37680, 60400], [60402, 149968], [27705, 60403], [60406, 134904], michael@0: [34855, 60407], [35061, 60408], [60409, 141606], [60410, 164979], michael@0: [60411, 137137], [28344, 60412], [60413, 150058], [60414, 137248], michael@0: [14756, 60415], 0, 0, [17727, 60419], [26294, 60420], [60421, 171181], michael@0: [60422, 170148], [35139, 60423], [16607, 60427], [60428, 136714], michael@0: [14753, 60429], [60430, 145199], [60431, 164072], [60432, 136133], michael@0: [29101, 60433], [33638, 60434], [60436, 168360], 0, [19639, 60438], michael@0: [60439, 159919], [60440, 166315], [60445, 147834], [31555, 60446], michael@0: [31102, 60447], [28597, 60449], [60450, 172767], [27139, 60451], michael@0: [60452, 164632], [21410, 60453], [60454, 159239], [37823, 60455], michael@0: [26678, 60456], [38749, 59389, 60457], [60458, 164207], [60460, 158133], michael@0: [60461, 136173], [60462, 143919], [23941, 60464], [60465, 166960], michael@0: [22293, 60467], [38947, 60468], [60469, 166217], [23979, 60470], michael@0: [60471, 149896], [26046, 60472], [27093, 60473], [21458, 60474], michael@0: [60475, 150181], [60476, 147329], [15377, 60477], [26422, 60478], michael@0: [60482, 139169], [13770, 60490], [18682, 60493], 0, [30728, 60496], michael@0: [37461, 60497], [17394, 60499], [17375, 60501], [23032, 60505], 0, michael@0: [22155, 60518], [60520, 169449], [36882, 60541], [21953, 60546], michael@0: [17673, 60551], [32383, 60552], [28502, 60553], [27313, 60554], michael@0: [13540, 60556], [60558, 161949], [14138, 60559], 0, [60562, 163876], michael@0: [60565, 162366], [15851, 60567], [60569, 146615], [60574, 156248], michael@0: [22207, 60575], [36366, 60577], [23405, 60578], [25566, 60581], 0, michael@0: [25904, 60585], [22061, 60586], [21530, 60588], [60591, 171416], michael@0: [19581, 60592], [22050, 60593], [22046, 60594], [32585, 60595], michael@0: [22901, 60597], [60598, 146752], [34672, 60599], [33047, 60604], michael@0: [40286, 60605], [36120, 60606], [30267, 60607], [40005, 60608], michael@0: [30286, 60609], [30649, 60610], [37701, 60611], [21554, 60612], michael@0: [33096, 60613], [33527, 60614], [22053, 60615], [33074, 60616], michael@0: [33816, 60617], [32957, 60618], [21994, 60619], [31074, 60620], michael@0: [22083, 60621], [21526, 60622], [60623, 134813], [13774, 60624], michael@0: [22021, 57509, 60625], [22001, 60626], [26353, 60627], [60628, 164578], michael@0: [13869, 60629], [30004, 60630], [22000, 60631], [21946, 60632], michael@0: [21655, 60633], [21874, 60634], [60635, 134209], [60636, 134294], michael@0: [24272, 57652, 60637], [60639, 134774], [60640, 142434], [60641, 134818], michael@0: [40619, 60642], [32090, 60643], 0, [60645, 135285], [25245, 60646], michael@0: [38765, 60647], [21652, 60648], [36045, 60649], [29174, 60650], michael@0: [37238, 60651], [25596, 60652], [25529, 60653], [25598, 60654], michael@0: [21865, 60655], [60656, 142147], [40050, 60657], [60658, 143027], michael@0: [20890, 60659], [13535, 60660], [60661, 134567], [20903, 60662], michael@0: [21581, 60663], [21790, 60664], [21779, 60665], [30310, 60666], michael@0: [36397, 60667], [60668, 157834], [30129, 60669], [32950, 60670], michael@0: [34820, 60671], 0, [35015, 60673], [33206, 60674], [33820, 60675], michael@0: [17644, 60677], [29444, 60678], [33547, 60681], [22139, 60683], michael@0: [37232, 60690], [37384, 60692], [60696, 134905], [29286, 60697], michael@0: [18254, 60699], [60701, 163833], [16634, 60703], [40029, 60704], michael@0: [25887, 60705], [18675, 60707], [60708, 149472], [60709, 171388], 0, michael@0: [60713, 161187], 60715, [60716, 155720], [29091, 60718], [32398, 60719], michael@0: [40272, 60720], [13687, 60723], [27826, 60725], [21351, 60726], michael@0: [14812, 60728], [60731, 149016], [33325, 60734], [21579, 60735], 60739, michael@0: [14930, 60740], [29556, 60742], [60743, 171692], [19721, 60744], michael@0: [39917, 60745], 0, [19547, 60748], [60751, 171998], [33884, 60752], michael@0: [60754, 160434], [25390, 60757], [32037, 60758], [14890, 60761], michael@0: [36872, 60762], [21196, 60763], [15988, 60764], [13946, 60765], michael@0: [17897, 60766], [60767, 132238], [30272, 60768], [23280, 60769], michael@0: [60770, 134838], [30842, 60771], [18358, 60772], [22695, 60773], michael@0: [16575, 60774], [22140, 60775], [39819, 60776], [23924, 60777], michael@0: [30292, 60778], [60779, 173108], [40581, 60780], [19681, 60781], 0, michael@0: [14331, 60783], [24857, 60784], [60786, 148466], 60787, [22109, 60788], michael@0: [60792, 171526], [21044, 60793], [13741, 60795], 0, [40316, 60797], michael@0: [31830, 60798], [39737, 60799], [22494, 60800], [23635, 60802], michael@0: [25811, 60803], [60804, 169168], [60805, 156469], [34477, 60807], michael@0: [60808, 134440], [60811, 134513], 60812, [20990, 60813], [60814, 139023], michael@0: [23950, 60815], [38659, 60816], [60817, 138705], [40577, 60818], michael@0: [36940, 60819], [31519, 60820], [39682, 60821], [23761, 60822], michael@0: [31651, 60823], [25192, 60824], [25397, 60825], [39679, 60826], michael@0: [31695, 60827], [39722, 60828], [31870, 60829], 0, [31810, 60831], michael@0: [31878, 60832], [39957, 60833], [31740, 60834], [39689, 60835], 0, 39982, michael@0: [40794, 60839], [21875, 60840], [23491, 60841], [20477, 60842], michael@0: [40600, 60843], [20466, 60844], [21088, 60845], [21201, 60847], michael@0: [22375, 60848], [20566, 60849], [22967, 60850], [24082, 60851], michael@0: [38856, 60852], [40363, 60853], [36700, 60854], [21609, 60855], michael@0: [38836, 60856], [39232, 60857], [38842, 60858], [21292, 60859], michael@0: [24880, 60860], [26924, 60861], [21466, 60862], [39946, 60863], michael@0: [40194, 60864], [19515, 60865], [38465, 60866], [27008, 60867], michael@0: [20646, 60868], [30022, 60869], [60870, 137069], [39386, 60871], michael@0: [21107, 60872], 60873, [37209, 60874], [38529, 60875], [37212, 60876], michael@0: 60877, [37201, 60878], [60879, 167575], [25471, 60880], [27338, 60882], michael@0: [22033, 60883], [37262, 60884], [30074, 60885], [25221, 60886], michael@0: [29519, 60888], [31856, 60889], [60890, 154657], 60892, [30422, 60894], michael@0: [39837, 60895], [20010, 60896], [60897, 134356], [33726, 60898], michael@0: [34882, 60899], 60900, [23626, 60901], [27072, 60902], 0, 0, michael@0: [21023, 60905], [24053, 60906], [20174, 60907], [27697, 60908], michael@0: [60909, 131570], [20281, 60910], [21660, 60911], 0, [21146, 60913], michael@0: [36226, 60914], [13822, 60915], 0, [13811, 60917], 60918, [27474, 60919], michael@0: [37244, 60920], [40869, 60921], [39831, 60922], [38958, 60923], michael@0: [39092, 60924], [39610, 60925], [40616, 60926], [40580, 60927], michael@0: [31508, 60929], 60930, [27642, 60931], [34840, 60932], [32632, 60933], michael@0: 60934, [22048, 60935], [60936, 173642], [36471, 60937], [40787, 60938], michael@0: 60939, [36308, 60940], [36431, 60941], [40476, 60942], [36353, 60943], michael@0: [25218, 60944], [60945, 164733], [36392, 60946], [36469, 60947], michael@0: [31443, 60948], [31294, 60950], [30936, 60951], [27882, 60952], michael@0: [35431, 60953], [30215, 60954], [40742, 60956], [27854, 60957], michael@0: [34774, 60958], [30147, 60959], [60960, 172722], [30803, 60961], michael@0: [36108, 60963], [29410, 60964], [29553, 60965], [35629, 60966], michael@0: [29442, 60967], [29937, 60968], [36075, 60969], [60970, 150203], michael@0: [34351, 60971], [24506, 60972], [34976, 60973], [17591, 60974], 60975, michael@0: [60977, 159237], 60978, [35454, 60979], [60980, 140571], 60981, michael@0: [24829, 60982], [30311, 60983], [39639, 60984], [40260, 60985], michael@0: [37742, 58859, 60986], [39823, 60987], [34805, 60988], 60989, 0, michael@0: [36087, 60991], [29484, 60992], [38689, 60993], [39856, 60994], michael@0: [13782, 60995], [29362, 60996], [19463, 60997], [31825, 60998], michael@0: [39242, 60999], [24921, 61001], [19460, 61002], [40598, 61003], michael@0: [24957, 61004], 61005, [22367, 61006], [24943, 61007], [25254, 61008], michael@0: [25145, 61009], 0, [14940, 61011], [25058, 61012], [21418, 61013], michael@0: [25444, 61015], [26626, 61016], [13778, 61017], [23895, 61018], michael@0: [36826, 61020], [61021, 167481], 61022, [20697, 61023], [30982, 61025], michael@0: [21298, 61026], [38456, 61027], [61028, 134971], [16485, 61029], 61030, michael@0: [30718, 61031], 61032, [31938, 61033], [61034, 155418], [31962, 61035], michael@0: [31277, 61036], [32870, 61037], [32867, 61038], [32077, 61039], michael@0: [29957, 61040], [29938, 61041], [35220, 61042], [33306, 61043], michael@0: [26380, 61044], [32866, 61045], [61046, 160902], [32859, 61047], michael@0: [29936, 61048], [33027, 61049], [30500, 61050], [35209, 61051], michael@0: [61052, 157644], [30035, 61053], [34729, 61055], [34766, 61056], michael@0: [33224, 61057], [34700, 61058], [35401, 61059], [36013, 61060], michael@0: [35651, 61061], [30507, 61062], [29944, 61063], [34010, 61064], michael@0: [27058, 61066], [36262, 61067], 61068, [35241, 58392, 61069], 0, michael@0: [28089, 61071], [34753, 61072], [61073, 147473], [29927, 61074], michael@0: [15835, 61075], [29046, 61076], [24740, 57702, 61077], [24988, 61078], michael@0: [15569, 61079], 0, [24695, 61081], 61082, [32625, 61083], 0, michael@0: [24809, 61086], [19326, 61087], [57344, 132423], [37595, 57345], michael@0: [57346, 132575], [57347, 147397], [34124, 57348], [17077, 57349], michael@0: [29679, 57350], [20917, 57351], [13897, 57352], [57353, 149826], michael@0: [57354, 166372], [37700, 57355], [57356, 137691], [33518, 57357], michael@0: [57358, 146632], [30780, 57359], [26436, 57360], [25311, 57361], michael@0: [57362, 149811], [57363, 166314], [57364, 131744], [57365, 158643], michael@0: [57366, 135941], [20395, 57367], [57368, 140525], [20488, 57369], michael@0: [57370, 159017], [57371, 162436], [57372, 144896], [57373, 150193], michael@0: [57374, 140563], 0, [57376, 131966], [24484, 57377], [57378, 131968], michael@0: [57379, 131911], [28379, 57380], [57381, 132127], 20702, [20737, 57383], michael@0: [13434, 57384], [20750, 57385], [39020, 57386], [14147, 57387], michael@0: [33814, 57388], [57389, 149924], [57390, 132231], [20832, 57391], michael@0: [57392, 144308], [20842, 57393], [57394, 134143], [57395, 139516], michael@0: [57396, 131813], [57397, 140592], [57398, 132494], [57399, 143923], michael@0: [57400, 137603], [23426, 57401], [34685, 57402], [57403, 132531], michael@0: [57404, 146585], [20914, 57405], [20920, 57406], [40244, 57407], michael@0: [20937, 57408], [20943, 57409], [20945, 57410], [15580, 57411], michael@0: [20947, 57412], [57413, 150182], [20915, 57414], 0, 0, [20973, 57417], michael@0: [33741, 57418], [26942, 57419], [57420, 145197], [24443, 57421], michael@0: [21003, 57422], [21030, 57423], [21052, 57424], [21173, 57425], michael@0: [21079, 57426], [21140, 57427], [21177, 57428], [21189, 57429], michael@0: [31765, 57430], [34114, 57431], [21216, 57432], [34317, 57433], michael@0: [57434, 158483], 0, [57436, 166622], [21833, 57437], [28377, 57438], michael@0: [57439, 147328], [57440, 133460], [57441, 147436], [21299, 57442], 0, michael@0: [57444, 134114], [27851, 57445], [57446, 136998], [26651, 57447], michael@0: [29653, 57448], [24650, 57449], [16042, 57450], [14540, 57451], michael@0: [57452, 136936], [29149, 57453], [17570, 57454], [21357, 57455], michael@0: [21364, 57456], [57457, 165547], [21374, 57458], 0, [57460, 136598], michael@0: [57461, 136723], [30694, 57462], [21395, 57463], [57464, 166555], michael@0: [21408, 57465], [21419, 57466], [21422, 57467], [29607, 57468], michael@0: [57469, 153458], [16217, 57470], [29596, 57471], [21441, 57472], michael@0: [21445, 57473], [27721, 57474], [20041, 57475], [22526, 57476], michael@0: [21465, 57477], [15019, 57478], [57479, 134031], [21472, 57480], michael@0: [57481, 147435], [57482, 142755], [21494, 57483], [57484, 134263], michael@0: [21523, 57485], [28793, 57486], [21803, 57487], [26199, 57488], michael@0: [27995, 57489], [21613, 57490], [57491, 158547], [57492, 134516], michael@0: [21853, 57493], [21647, 57494], [21668, 57495], [18342, 57496], michael@0: [57497, 136973], [57498, 134877], [15796, 57499], [57500, 134477], michael@0: [57501, 166332], [57502, 140952], [21831, 57503], [19693, 57504], michael@0: [21551, 57505], [29719, 57506], [21894, 57507], [21929, 57508], 0, michael@0: [57510, 137431], [57511, 147514], [17746, 57512], [57513, 148533], michael@0: [26291, 57514], [57515, 135348], [22071, 57516], [26317, 57517], michael@0: [57518, 144010], [26276, 57519], 0, [22093, 57521], [22095, 57522], michael@0: [30961, 57523], [22257, 57524], [38791, 57525], [21502, 57526], michael@0: [22272, 57527], [22255, 57528], [22253, 57529], [57530, 166758], michael@0: [13859, 57531], [57532, 135759], [22342, 57533], [57534, 147877], michael@0: [27758, 57535], [28811, 57536], [22338, 57537], [14001, 57538], michael@0: [57539, 158846], [22502, 57540], [57541, 136214], [22531, 57542], michael@0: [57543, 136276], [57544, 148323], [22566, 57545], [57546, 150517], 0, michael@0: [22698, 57548], [13665, 57549], [22752, 57550], [22748, 57551], michael@0: [57552, 135740], [22779, 57553], [23551, 57554], [22339, 57555], michael@0: [57556, 172368], [57557, 148088], [37843, 57558], [13729, 57559], michael@0: [22815, 57560], [26790, 57561], [14019, 57562], [28249, 57563], michael@0: [57564, 136766], [23076, 57565], 0, [57567, 136850], [34053, 57568], michael@0: [22985, 57569], [57570, 134478], [57571, 158849], [57572, 159018], michael@0: [57573, 137180], [23001, 57574], [57575, 137211], [57576, 137138], michael@0: [57577, 159142], [28017, 57578], [57579, 137256], [57580, 136917], michael@0: [23033, 57581], [57582, 159301], [23211, 57583], [23139, 57584], michael@0: [14054, 57585], [57586, 149929], 0, [14088, 57588], [23190, 57589], michael@0: [29797, 57590], [23251, 57591], [57592, 159649], [57593, 140628], michael@0: [57595, 137489], [14130, 57596], [57597, 136888], [24195, 57598], michael@0: [21200, 57599], [23414, 57600], [25992, 57601], [23420, 57602], michael@0: [57603, 162318], [16388, 57604], [18525, 57605], [57606, 131588], michael@0: [23509, 57607], [57609, 137780], [57610, 154060], [57611, 132517], michael@0: [23539, 57612], [23453, 57613], [19728, 57614], [23557, 57615], michael@0: [57616, 138052], [23571, 57617], [29646, 57618], [23572, 57619], michael@0: [57620, 138405], [57621, 158504], [23625, 57622], [18653, 57623], michael@0: [23685, 57624], [23785, 57625], [23791, 57626], [23947, 57627], michael@0: [57628, 138745], [57629, 138807], [23824, 57630], [23832, 57631], michael@0: [23878, 57632], [57633, 138916], [23738, 57634], [24023, 57635], michael@0: [33532, 57636], [14381, 57637], [57638, 149761], [57639, 139337], michael@0: [57640, 139635], [33415, 57641], [14390, 57642], [15298, 57643], michael@0: [24110, 57644], [27274, 57645], 0, 57647, [57648, 148668], [57649, 134355], michael@0: [21414, 57650], [20151, 57651], 0, [21416, 57653], [57654, 137073], michael@0: [24073, 57655], 57656, [57657, 164994], [24313, 57658], [24315, 57659], michael@0: [14496, 57660], [24316, 57661], [26686, 57662], [37915, 57663], michael@0: [24333, 57664], [57665, 131521], [57666, 194708], [15070, 57667], michael@0: [57669, 135994], [24378, 57670], [57671, 157832], [57672, 140240], michael@0: [57674, 140401], [24419, 57675], [57677, 159342], [24434, 57678], michael@0: [37696, 57679], [57680, 166454], [24487, 57681], [23990, 57682], michael@0: [15711, 57683], [57684, 152144], [57685, 139114], [57686, 159992], michael@0: [57687, 140904], [37334, 57688], [57689, 131742], [57690, 166441], michael@0: [24625, 57691], [26245, 57692], [14691, 57694], [15815, 57695], michael@0: [13881, 57696], [22416, 57697], [57698, 141236], [31089, 57699], michael@0: [15936, 57700], [24734, 57701], 0, 0, [57704, 149890], [57705, 149903], michael@0: [57706, 162387], [29860, 57707], [20705, 57708], [23200, 57709], michael@0: [24932, 57710], [24898, 57712], [57713, 194726], [57714, 159442], michael@0: [24961, 57715], [20980, 57716], [57717, 132694], [24967, 57718], michael@0: [23466, 57719], [57720, 147383], [57721, 141407], [25043, 57722], michael@0: [57723, 166813], [57724, 170333], [25040, 57725], [14642, 57726], michael@0: [57727, 141696], [57728, 141505], [24611, 57729], [24924, 57730], michael@0: [25886, 57731], [25483, 57732], [57733, 131352], [25285, 57734], michael@0: [57735, 137072], [25301, 57736], [57737, 142861], [25452, 57738], michael@0: [57739, 149983], [14871, 57740], [25656, 57741], [25592, 57742], michael@0: [57743, 136078], [57744, 137212], [28554, 57746], [57747, 142902], 0, michael@0: [57750, 153373], [25825, 57751], [25829, 57752], [38011, 57753], michael@0: [14950, 57754], [25658, 57755], [14935, 57756], [25933, 57757], michael@0: [28438, 57758], [57759, 150056], [57760, 150051], [25989, 57761], michael@0: [25965, 57762], [25951, 57763], 0, [26037, 57765], [57766, 149824], michael@0: [19255, 57767], [26065, 57768], [16600, 57769], [57770, 137257], 57771, michael@0: [26083, 57772], [24543, 57773], [57774, 144384], [26136, 57775], michael@0: [57776, 143863], [57777, 143864], [26180, 57778], [57779, 143780], michael@0: [57780, 143781], [26187, 57781], [57782, 134773], [26215, 57783], michael@0: [57784, 152038], [26227, 57785], 0, [57788, 143921], [57789, 165364], michael@0: [57790, 143816], [57791, 152339], [30661, 57792], [57793, 141559], michael@0: [39332, 57794], [26370, 57795], [57796, 148380], [57797, 150049], michael@0: [27130, 57799], [57800, 145346], 0, [26471, 57802], [26466, 57803], michael@0: [57804, 147917], [57805, 168173], [26583, 57806], [17641, 57807], michael@0: [26658, 57808], [28240, 57809], [37436, 57810], [26625, 57811], michael@0: [57812, 144358], [57813, 159136], [26717, 57814], [57815, 144495], michael@0: [27105, 57816], [27147, 57817], [57818, 166623], [26995, 57819], michael@0: [26819, 57820], [57821, 144845], [26881, 57822], [26880, 57823], michael@0: [14849, 57825], [57826, 144956], [15232, 57827], [26540, 57828], michael@0: [26977, 57829], [57830, 166474], [17148, 57831], [26934, 57832], michael@0: [27032, 57833], [15265, 57834], [57835, 132041], [33635, 57836], michael@0: [20624, 57837], [27129, 57838], [57839, 144985], [57840, 139562], michael@0: [27205, 57841], [57842, 145155], [27293, 57843], [15347, 57844], michael@0: [26545, 57845], [27336, 57846], [57847, 168348], [15373, 57848], michael@0: [27421, 57849], [57850, 133411], [24798, 57851, 60308], [27445, 57852], michael@0: [27508, 57853], [57854, 141261], [28341, 57855], [57856, 146139], 0, michael@0: [57858, 137560], [14144, 57859], [21537, 57860], [57861, 146266], michael@0: [27617, 57862], [57863, 147196], [27612, 57864], [27703, 57865], michael@0: [57866, 140427], [57867, 149745], [57868, 158545], [27738, 57869], michael@0: [33318, 57870], [27769, 57871], [57872, 146876], [17605, 57873], michael@0: [57874, 146877], [57875, 147876], [57876, 149772], [57877, 149760], michael@0: [57878, 146633], [14053, 57879], [15595, 57880], [57881, 134450], michael@0: [39811, 57882], [57883, 143865], [57884, 140433], [32655, 57885], michael@0: [26679, 57886], [57887, 159013], [57888, 159137], [57889, 159211], michael@0: [28054, 57890], [27996, 57891], [28284, 57892], [28420, 57893], michael@0: [57894, 149887], [57895, 147589], [57896, 159346], [34099, 57897], michael@0: [57898, 159604], [20935, 57899], 0, 0, [33838, 57902], [57903, 166689], 0, michael@0: [57905, 146991], [29779, 57906], [57907, 147330], [31180, 57908], michael@0: [28239, 57909], [23185, 57910], [57911, 143435], [28664, 57912], michael@0: [14093, 57913], [28573, 57914], [57915, 146992], [28410, 57916], michael@0: [57917, 136343], [57918, 147517], [17749, 57919], [37872, 57920], michael@0: [28484, 57921], [28508, 57922], [15694, 57923], [28532, 57924], michael@0: [57925, 168304], [15675, 57926], [28575, 57927], [57928, 147780], michael@0: [28627, 57929], [57930, 147601], [57931, 147797], [57932, 147513], michael@0: [57933, 147440], [57934, 147380], [57935, 147775], [20959, 57936], michael@0: [57937, 147798], [57938, 147799], [57939, 147776], [57940, 156125], michael@0: [28747, 57941], [28798, 57942], [28839, 57943], 0, [28876, 57945], michael@0: [28885, 57946], [28886, 57947], [28895, 57948], [16644, 57949], michael@0: [15848, 57950], [29108, 57951], [29078, 57952], [57953, 148087], michael@0: [28971, 57954], [28997, 57955], [23176, 57956], [29002, 57957], 0, michael@0: [57960, 148325], [29007, 57961], [37730, 57962], [57963, 148161], michael@0: [28972, 57964], [57965, 148570], [57966, 150055], [57967, 150050], michael@0: [29114, 57968], [57969, 166888], [28861, 57970], [29198, 57971], michael@0: [37954, 57972], [29205, 57973], [22801, 57974], [37955, 57975], michael@0: [29220, 57976], [37697, 57977], [57978, 153093], [29230, 57979], michael@0: [29248, 57980], [57981, 149876], [26813, 57982], [29269, 57983], michael@0: [29271, 57984], [15957, 57985], [57986, 143428], [26637, 57987], michael@0: [28477, 57988], [29314, 57989], 0, [29483, 57991], [57992, 149539], michael@0: [57993, 165931], [18669, 57994], [57995, 165892], [29480, 57996], michael@0: [29486, 57997], [29647, 57998], [29610, 57999], [58000, 134202], michael@0: [58001, 158254], [29641, 58002], [29769, 58003], [58004, 147938], michael@0: [58005, 136935], [58006, 150052], [26147, 58007], [14021, 58008], michael@0: [58009, 149943], [58010, 149901], [58011, 150011], [29687, 58012], michael@0: [29717, 58013], [26883, 58014], [58015, 150054], [29753, 58016], michael@0: [16087, 58018], 0, [58020, 141485], [29792, 58021], [58022, 167602], michael@0: [29767, 58023], [29668, 58024], [29814, 58025], [33721, 58026], michael@0: [29804, 58027], [29812, 58029], [37873, 58030], [27180, 58031], michael@0: [29826, 58032], [18771, 58033], [58034, 150156], [58035, 147807], michael@0: [58036, 150137], [58037, 166799], [23366, 58038], [58039, 166915], michael@0: [58040, 137374], [29896, 58041], [58042, 137608], [29966, 58043], michael@0: [29982, 58045], [58046, 167641], [58047, 137803], [23511, 58048], michael@0: [58049, 167596], [37765, 58050], [30029, 58051], [30026, 58052], michael@0: [30055, 58053], [30062, 58054], [58055, 151426], [16132, 58056], michael@0: [58057, 150803], [30094, 58058], [29789, 58059], [30110, 58060], michael@0: [30132, 58061], [30210, 58062], [30252, 58063], [30289, 58064], michael@0: [30287, 58065], [30319, 58066], 58067, [58068, 156661], [30352, 58069], michael@0: [33263, 58070], [14328, 58071], [58072, 157969], [58073, 157966], michael@0: [30369, 58074], [30373, 58075], [30391, 58076], [30412, 58077], michael@0: [58078, 159647], [33890, 58079], [58080, 151709], [58081, 151933], michael@0: [58082, 138780], [30494, 58083], [30502, 58084], [30528, 58085], michael@0: [25775, 58086], [58087, 152096], [30552, 58088], [58089, 144044], michael@0: [30639, 58090], [58091, 166244], [58092, 166248], [58093, 136897], michael@0: [30708, 58094], 0, [26826, 58098], [30895, 58099], [30919, 58100], michael@0: [30931, 58101], [38565, 58102], [31022, 58103], [58104, 153056], michael@0: [30935, 58105], [31028, 58106], [30897, 58107], [58108, 161292], michael@0: [36792, 58109], [34948, 58110], [58113, 140828], [31110, 58114], michael@0: [35072, 58115], [26882, 58116], [31104, 58117], [58118, 153687], michael@0: [31133, 58119], [58120, 162617], [31036, 58121], [31145, 58122], michael@0: [28202, 58123], [58124, 160038], [16040, 58125], [31174, 58126], michael@0: [58127, 168205], [31188, 58128], 0, [21797, 62526], 0, [62528, 134210], michael@0: [62529, 134421], [62530, 151851], [21904, 62531], [62532, 142534], michael@0: [14828, 62533], [62534, 131905], [36422, 62535], [62536, 150968], michael@0: [62537, 169189], 0, [62539, 164030], [30586, 62540], [62541, 142392], michael@0: [14900, 62542], [18389, 62543], [62544, 164189], [62545, 158194], michael@0: [62546, 151018], [25821, 62547], [62548, 134524], [62549, 135092], michael@0: [62550, 134357], 0, [25741, 62552], [36478, 62553], [62554, 134806], 0, michael@0: [62556, 135012], [62557, 142505], [62558, 164438], [62559, 148691], 0, michael@0: [62561, 134470], [62562, 170573], [62563, 164073], [18420, 62564], michael@0: [62565, 151207], [62566, 142530], [39602, 62567], [14951, 62568], michael@0: [62569, 169460], [16365, 62570], [13574, 62571], [62572, 152263], michael@0: [62573, 169940], 0, [62575, 142660], [40302, 62576], [38933, 62577], 0, michael@0: [17369, 62579], 0, [25780, 62581], [21731, 62582], 0, [62584, 142282], 0, michael@0: [14843, 62586], 0, [62588, 157402], [62589, 157462], [62590, 162208], michael@0: [25834, 62591], [62592, 151634], [62593, 134211], [36456, 62594], 0, michael@0: [62596, 166732], [62597, 132913], 0, [18443, 62599], [62600, 131497], michael@0: [16378, 62601], [22643, 62602], [62603, 142733], 0, [62605, 148936], michael@0: [62606, 132348], [62607, 155799], [62608, 134988], 0, [21881, 62610], 0, michael@0: [17338, 62612], 0, [19124, 62614], [62615, 141926], [62616, 135325], michael@0: [33194, 62617], [39157, 62618], [62619, 134556], [25465, 62620], michael@0: [14846, 62621], [62622, 141173], [36288, 62623], [22177, 62624], michael@0: [25724, 62625], [15939, 62626], 0, [62628, 173569], [62629, 134665], michael@0: [62630, 142031], 0, 0, [62633, 135368], [62634, 145858], [14738, 62635], michael@0: [14854, 62636], [62637, 164507], [13688, 62638], [62639, 155209], michael@0: [62640, 139463], 0, 0, [62643, 142514], [62644, 169760], [13500, 62645], michael@0: [27709, 62646], [62647, 151099], 0, 0, [62650, 161140], [62651, 142987], michael@0: [62652, 139784], [62653, 173659], [62654, 167117], [62655, 134778], michael@0: [62656, 134196], [62683, 161337], [62684, 142286], [62687, 142417], michael@0: [14872, 62689], [62691, 135367], [62693, 173618], [62695, 167122], michael@0: [62696, 167321], [62697, 167114], [38314, 62698], 0, [62706, 161630], michael@0: [28992, 62708], 0, [20822, 62385], 0, [20616, 62487], 0, [13459, 62489], michael@0: [20870, 62491], [24130, 63037], [20997, 62495], [21031, 62436], michael@0: [21113, 62497], 0, [13651, 62504], [21442, 62505], [21343, 62715], 0, michael@0: [21823, 62520], 0, [21976, 59986], [13789, 62722], [22049, 63067], 0, michael@0: [22100, 60044], [60148, 135291], 0, [60153, 135379], 0, [61095, 135934], 0, michael@0: 0, [14265, 60104], [23745, 61099], [23829, 63066], [23894, 63030], michael@0: [14392, 63036], [20097, 62477], [24253, 63038], [14612, 63042], michael@0: [25017, 63050], [25232, 63054], [25368, 63056], [25690, 63063], michael@0: [25745, 62381], [33133, 62709], [33156, 59922], [33171, 59924], michael@0: [26624, 63080], [15292, 63093], [29327, 60517], [29389, 59781], 0, michael@0: [29497, 59785], [30018, 59811], [30172, 59817], [16320, 59818], michael@0: [60278, 151205], [16343, 59820], 0, 30336, [30348, 59824, 151388], michael@0: [16552, 59845], [30777, 59846], [16643, 59855], [31377, 59863], michael@0: [31771, 59876], [31981, 59884], [32659, 62658], [32686, 59892], 0, michael@0: [33535, 59936], [22623, 59981], [34482, 59960], 0, [34699, 59963], michael@0: [35143, 59969], 0, [35369, 59972], 0, [36465, 59988], [60484, 164233], michael@0: [36528, 59990], 0, [37214, 62443], [37260, 62441], [39182, 60051], michael@0: [39196, 60054], 0, 0, [39809, 60066], [40384, 60080], [40339, 60078], michael@0: [40620, 60085], [19857, 60540], 0, 37818, [40571, 60084], [28809, 63148], michael@0: [29512, 59788], 0, [31129, 59858], [36791, 59997], 0, [39234, 60056], michael@0: {s: 193}, 8364, {s: 4}, [12443, 63518], [12444, 63519], [11904, 63520], michael@0: {f: 5, c: 62211}, [62216, 131340], 62217, [62218, 131281], [62219, 131277], michael@0: {f: 2, c: 62220}, [62222, 131275], [62223, 139240], 62224, [62225, 131274], michael@0: {f: 4, c: 62226}, [62230, 131342], {f: 2, c: 62231}, {f: 2, c: 62776}, michael@0: [62778, 138177], [62779, 194680], [12205, 38737, 62780], [62781, 131206], michael@0: [20059, 62782], [20155, 62783], [13630, 62784], [23587, 62785], michael@0: [24401, 62786], [24516, 62787], [14586, 62788], [25164, 62789], michael@0: [25909, 62790], [27514, 62791], [27701, 62792], [27706, 62793], michael@0: [28780, 62794], [29227, 62795], [20012, 62796], [29357, 62797], michael@0: [62798, 149737], [32594, 62799], [31035, 62800], [31993, 62801], michael@0: [32595, 62802], [62803, 156266], [13505, 62804], [62806, 156491], michael@0: [32770, 62807], [32896, 62808], [62809, 157202], [62810, 158033], michael@0: [21341, 62811], [34916, 62812], [35265, 62813], [62814, 161970], michael@0: [35744, 62815], [36125, 62816], [38021, 62817], [38264, 62818], michael@0: [38271, 62819], [38376, 62820], [62821, 167439], [38886, 62822], michael@0: [39029, 62823], [39118, 62824], [39134, 62825], [39267, 62826], michael@0: [62827, 170000], [40060, 62828], [40479, 62829], [40644, 62830], michael@0: [27503, 62831], [62832, 63751], [20023, 62833], [62834, 131207], michael@0: [38429, 62835], [25143, 62836], [38050, 62837], [11908, 63521], michael@0: [11910, 63522], [11911, 63523], [11912, 63524], [11914, 63525], michael@0: [11916, 63526], [11917, 63527], [11925, 63528], [11932, 63529], michael@0: [11941, 63531], [11943, 63532], [11946, 63533], [11948, 63534], michael@0: [11950, 63535], [11958, 63536], [11964, 63537], [11966, 63538], michael@0: [11978, 63540], [11980, 63541], [11981, 63542], [11983, 63543], michael@0: [11990, 63544], [11991, 63545], [11998, 63546], [62368, 172969], michael@0: [62369, 135493], [25866, 62371], [20029, 62374], [28381, 62375], michael@0: [40270, 62376], [37343, 62377], [62380, 161589], [20250, 62382], michael@0: [20264, 62383], [20392, 62384], [20852, 62386], [20892, 62387], michael@0: [20964, 62388], [21153, 62389], [21160, 62390], [21307, 62391], michael@0: [21326, 62392], [21457, 62393], [21464, 62394], [22242, 62395], michael@0: [22768, 62396], [22788, 62397], [22791, 62398], [22834, 62399], michael@0: [22836, 62400], [23398, 62401], [23454, 62402], [23455, 62403], michael@0: [23706, 62404], [24198, 62405], [24635, 62406], [25993, 62407], michael@0: [26622, 62408], [26628, 62409], [26725, 62410], [27982, 62411], michael@0: [28860, 62412], [30005, 62413], [32420, 62414], [32428, 62415], michael@0: [32442, 62416], [32455, 62417], [32463, 62418], [32479, 62419], michael@0: [32518, 62420], [32567, 62421], [33402, 62422], [33487, 62423], michael@0: [33647, 62424], [35270, 62425], [35774, 62426], [35810, 62427], michael@0: [36710, 62428], [36711, 62429], [36718, 62430], [29713, 62431], michael@0: [31996, 62432], [32205, 62433], [26950, 62434], [31433, 62435], michael@0: [30904, 62442], [32956, 62444], [36107, 62446], [33014, 62447], michael@0: [62448, 133607], [32927, 62451], [40647, 62452], [19661, 62453], michael@0: [40393, 62454], [40460, 62455], [19518, 62456], [62457, 171510], michael@0: [62458, 159758], [40458, 62459], [62460, 172339], [13761, 62461], michael@0: [28314, 62463], [33342, 62464], [29977, 62465], [18705, 62467], michael@0: [39532, 62468], [39567, 62469], [40857, 62470], [31111, 62471], michael@0: [62472, 164972], [62473, 138698], [62474, 132560], [62475, 142054], michael@0: [20004, 62476], [20096, 62478], [20103, 62479], [20159, 62480], michael@0: [20203, 62481], [20279, 62482], [13388, 62483], [20413, 62484], michael@0: [15944, 62485], [20483, 62486], [13437, 62488], [13477, 62490], michael@0: [22789, 62492], [20955, 62493], [20988, 62494], [20105, 62496], michael@0: [21136, 62498], [21287, 62499], [13767, 62500], [21417, 62501], michael@0: [13649, 62502], [21424, 62503], [21539, 62506], [13677, 62507], michael@0: [13682, 62508], [13953, 62509], [21651, 62510], [21667, 62511], michael@0: [21684, 62512], [21689, 62513], [21712, 62514], [21743, 62515], michael@0: [21784, 62516], [21795, 62517], [21800, 62518], [13720, 62519], michael@0: [13733, 62521], [13759, 62522], [21975, 62523], [13765, 62524], michael@0: [62525, 163204], [16467, 62538], [62551, 135412], [62555, 134155], michael@0: [62574, 161992], [62580, 155813], [62583, 142668], [62585, 135287], michael@0: [62587, 135279], [62595, 139681], [62609, 134550], [16571, 62611], michael@0: [62631, 142537], [22098, 62641], [62642, 134961], [62657, 157724], michael@0: [62659, 135375], [62660, 141315], [62661, 141625], [13819, 62662], michael@0: [62663, 152035], [62664, 134796], [62665, 135053], [62666, 134826], michael@0: [16275, 62667], [62668, 134960], [62669, 134471], [62670, 135503], michael@0: [62671, 134732], [62673, 134827], [62674, 134057], [62675, 134472], michael@0: [62676, 135360], [62677, 135485], [16377, 62678], [62679, 140950], michael@0: [25650, 62680], [62681, 135085], [62682, 144372], [62685, 134526], michael@0: [62686, 134527], [62688, 142421], [62690, 134808], [62692, 134958], michael@0: [62694, 158544], [21708, 62699], [33476, 62700], [21945, 62701], michael@0: [62703, 171715], [39974, 62704], [39606, 62705], [62707, 142830], michael@0: [33004, 62710], [23580, 62711], [62712, 157042], [33076, 62713], michael@0: [14231, 62714], [62716, 164029], [37302, 62717], [62718, 134906], michael@0: [62719, 134671], [62720, 134775], [62721, 134907], [62723, 151019], michael@0: [13833, 62724], [62725, 134358], [22191, 62726], [62727, 141237], michael@0: [62728, 135369], [62729, 134672], [62730, 134776], [62731, 135288], michael@0: [62732, 135496], [62733, 164359], [62734, 136277], [62735, 134777], michael@0: [62736, 151120], [62737, 142756], [23124, 62738], [62739, 135197], michael@0: [62740, 135198], [62741, 135413], [62742, 135414], [22428, 62743], michael@0: [62744, 134673], [62745, 161428], [62746, 164557], [62747, 135093], michael@0: [62748, 134779], [62749, 151934], [14083, 62750], [62751, 135094], michael@0: [62752, 135552], [62753, 152280], [62754, 172733], [62755, 149978], michael@0: [62756, 137274], [62757, 147831], [62758, 164476], [22681, 62759], michael@0: [21096, 62760], [13850, 62761], [62762, 153405], [31666, 62763], michael@0: [23400, 62764], [18432, 62765], [19244, 62766], [40743, 62767], michael@0: [18919, 62768], [39967, 62769], [39821, 62770], [62771, 154484], michael@0: [62772, 143677], [22011, 62773], [13810, 62774], [22153, 62775], michael@0: [23870, 63028], [23880, 63029], [15868, 63031], [14351, 63032], michael@0: [23972, 63033], [23993, 63034], [14368, 63035], [24357, 63039], michael@0: [24451, 63040], [14600, 63041], [14655, 63043], [14669, 63044], michael@0: [24791, 63045], [24893, 63046], [23781, 63047], [14729, 63048], michael@0: [25015, 63049], [25039, 63051], [14776, 63052], [25132, 63053], michael@0: [25317, 63055], [14840, 63057], [22193, 63058], [14851, 63059], michael@0: [25570, 63060], [25595, 63061], [25607, 63062], [14923, 63064], michael@0: [25792, 63065], [40863, 63068], [14999, 63069], [25990, 63070], michael@0: [15037, 63071], [26111, 63072], [26195, 63073], [15090, 63074], michael@0: [26258, 63075], [15138, 63076], [26390, 63077], [15170, 63078], michael@0: [26532, 63079], [15192, 63081], [26698, 63082], [26756, 63083], michael@0: [15218, 63084], [15217, 63085], [15227, 63086], [26889, 63087], michael@0: [26947, 63088], [29276, 63089], [26980, 63090], [27039, 63091], michael@0: [27013, 63092], [27094, 63094], [15325, 63095], [27237, 63096], michael@0: [27252, 63097], [27249, 63098], [27266, 63099], [15340, 63100], michael@0: [27289, 63101], [15346, 63102], [27307, 63103], [27317, 63104], michael@0: [27348, 63105], [27382, 63106], [27521, 63107], [27585, 63108], michael@0: [27626, 63109], [27765, 63110], [27818, 63111], [15563, 63112], michael@0: [27906, 63113], [27910, 63114], [27942, 63115], [28033, 63116], michael@0: [15599, 63117], [28068, 63118], [28081, 63119], [28181, 63120], michael@0: [28184, 63121], [28201, 63122], [28294, 63123], [63124, 166336], michael@0: [28347, 63125], [28386, 63126], [28378, 63127], [40831, 63128], michael@0: [28392, 63129], [28393, 63130], [28452, 63131], [28468, 63132], michael@0: [15686, 63133], [63134, 147265], [28545, 63135], [28606, 63136], michael@0: [15722, 63137], [15733, 63138], [29111, 63139], [23705, 63140], michael@0: [15754, 63141], [28716, 63142], [15761, 63143], [28752, 63144], michael@0: [28756, 63145], [28783, 63146], [28799, 63147], [63149, 131877], michael@0: [17345, 63150], [13809, 63151], [63152, 134872], [13902, 58134], michael@0: [15789, 58172], [58173, 154725], [26237, 58183], [31860, 58188], michael@0: [29837, 58197], [32402, 58215], [17667, 58232], [58260, 151480], michael@0: [58270, 133901], [58277, 158474], [13438, 58311], [58317, 143087], michael@0: [58325, 146613], [58343, 159385], [34673, 58364], [25537, 58385], michael@0: [30583, 58387], [35210, 58390], [58406, 147343], [35660, 58415], michael@0: [58440, 150729], [18730, 58464], [58471, 172052], [58472, 165564], michael@0: [58473, 165121], [15088, 58490], [28815, 58511], [58529, 140922], michael@0: [58637, 158120], [58646, 148043], [26760, 58662], [58664, 139611], michael@0: [40802, 58702], [37830, 58793], [58802, 131967], [37734, 58888], michael@0: [37519, 58901], [34324, 58954], [58986, 173147], [16784, 59010], michael@0: [26511, 59045], [26654, 59048], [14435, 59051], [59077, 149996], michael@0: [15129, 59128], [33942, 59176], [59241, 149858], [14818, 59254], michael@0: [33920, 59259], [17262, 59328], [38769, 59402], [39323, 59427], michael@0: [18733, 59499], [28439, 59703], [59704, 160009], [28838, 59746], michael@0: [59752, 150095], [32357, 59753], [23855, 59755], [15859, 59756], michael@0: [59758, 150109], [59759, 137183], [32164, 59760], [33830, 59761], michael@0: [21637, 59762], [59763, 146170], [59765, 131604], [22398, 59766], michael@0: [59767, 133333], [59768, 132633], [16357, 59769], [59770, 139166], michael@0: [59771, 172726], [28675, 59772], [59773, 168283], [23920, 59774], michael@0: [29583, 59775], [59777, 166489], [59778, 168992], [20424, 59779], michael@0: [32743, 59780], [29456, 59782], [29496, 59784], [29505, 59787], michael@0: [16041, 59789], [29173, 59792], [59793, 149746], [29665, 59794], michael@0: [16074, 59796], [16081, 59798], [29721, 59801], [29726, 59802], michael@0: [29727, 59803], [16098, 59804], [16112, 59805], [16116, 59806], michael@0: [16122, 59807], [29907, 59808], [16142, 59809], [16211, 59810], michael@0: [30061, 59812], [30066, 59813], [30093, 59814], [16252, 59815], michael@0: [30152, 59816], [30285, 59819], [30324, 59821], [16348, 59822], michael@0: [30330, 59823], [29064, 59825], [22051, 59826], [35200, 59827], michael@0: [16413, 59829], [30531, 59830], [16441, 59831], [16453, 59833], michael@0: [13787, 59834], [30616, 59835], [16490, 59836], [16495, 59837], michael@0: [30654, 59839], [30667, 59840], [30744, 59842], [30748, 59844], michael@0: [30791, 59847], [30801, 59848], [30822, 59849], [33864, 59850], michael@0: [59851, 152885], [31027, 59852], [31026, 59854], [16649, 59856], michael@0: [31121, 59857], [31238, 59860], [16743, 59862], [16818, 59864], michael@0: [31420, 59865], [33401, 59866], [16836, 59867], [31439, 59868], michael@0: [31451, 59869], [16847, 59870], [31586, 59872], [31596, 59873], michael@0: [31611, 59874], [31762, 59875], [16992, 59877], [17018, 59878], michael@0: [31867, 59879], [31900, 59880], [17036, 59881], [31928, 59882], michael@0: [17044, 59883], [36755, 59885], [28864, 59886], [59887, 134351], michael@0: [32207, 59888], [32212, 59889], [32208, 59890], [32253, 59891], michael@0: [32692, 59893], [29343, 59894], [17303, 59895], [32800, 59896], michael@0: [32805, 59897], [32814, 59899], [32817, 59900], [32852, 59901], michael@0: [22452, 59903], [28832, 59904], [32951, 59905], [33001, 59906], michael@0: [17389, 59907], [33036, 59908], [33038, 59910], [33042, 59911], michael@0: [33044, 59913], [17409, 59914], [15161, 59915], [33110, 59916], michael@0: [33113, 59917], [33114, 59918], [17427, 59919], [33148, 59921], michael@0: [17445, 59923], [17453, 59925], [33189, 59926], [22511, 59927], michael@0: [33217, 59928], [33252, 59929], [33364, 59930], [17551, 59931], michael@0: [33398, 59933], [33482, 59934], [33496, 59935], [17584, 59937], michael@0: [33623, 59938], [38505, 59939], [33797, 59941], [28917, 59942], michael@0: [33892, 59943], [33928, 59945], [17668, 59946], [33982, 59947], michael@0: [34017, 59948], [34040, 59949], [34064, 59950], [34104, 59951], michael@0: [34130, 59952], [17723, 59953], [34159, 59954], [34160, 59955], michael@0: [34272, 59956], [17783, 59957], [34418, 59958], [34450, 59959], michael@0: [34543, 59961], [38469, 59962], [17926, 59964], [17943, 59965], michael@0: [34990, 59966], [35071, 59967], [35108, 59968], [35217, 59970], michael@0: [59971, 162151], [35384, 59973], [35476, 59974], [35508, 59975], michael@0: [35921, 59976], [36052, 59977], [36082, 59978], [36124, 59979], michael@0: [18328, 59980], [36291, 59982], [18413, 59983], [36410, 59985], michael@0: [22356, 59987], [22005, 59989], [18487, 59991], [36558, 59992], michael@0: [36578, 59993], [36580, 59994], [36589, 59995], [36594, 59996], michael@0: [36801, 59998], [36810, 59999], [36812, 60000], [36915, 60001], michael@0: [18605, 60003], [39136, 60004], [37395, 60005], [18718, 60006], michael@0: [37416, 60007], [37464, 60008], [37483, 60009], [37553, 60010], michael@0: [37550, 60011], [37567, 60012], [37603, 60013], [37611, 60014], michael@0: [37619, 60015], [37620, 60016], [37629, 60017], [37699, 60018], michael@0: [37764, 60019], [37805, 60020], [18757, 60021], [18769, 60022], michael@0: [37911, 60024], [37917, 60026], [37933, 60027], [37950, 60028], michael@0: [18794, 60029], [37972, 60030], [38009, 60031], [38189, 60032], michael@0: [38306, 60033], [18855, 60034], [38388, 60035], [38451, 60036], michael@0: [18917, 60037], [18980, 60039], [38720, 60040], [18997, 60041], michael@0: [38834, 60042], [38850, 60043], [19172, 60045], [39097, 60047], michael@0: [19225, 60048], [39153, 60049], [22596, 60050], [39193, 60052], michael@0: [39223, 60055], [39261, 60057], [39266, 60058], [19312, 60059], michael@0: [39365, 60060], [19357, 60061], [39484, 60062], [39695, 60063], michael@0: [39785, 60065], [39901, 60067], [39921, 60068], [39924, 60069], michael@0: [19565, 60070], [39968, 60071], [14191, 60072], [60073, 138178], michael@0: [40265, 60074], [40702, 60076], [22096, 60077], [40381, 60079], michael@0: [40444, 60081], [38134, 60082], [36790, 60083], [40625, 60086], michael@0: [40637, 60087], [40646, 60088], [38108, 60089], [40674, 60090], michael@0: [40689, 60091], [40696, 60092], [40772, 60094], [60095, 131220], michael@0: [60096, 131767], [60097, 132000], [38083, 60099], [60101, 132311], michael@0: [38081, 60103], [60105, 132565], [60106, 132629], [60107, 132726], michael@0: [60108, 136890], [22359, 60109], [29043, 60110], [60111, 133826], michael@0: [60112, 133837], [60113, 134079], [60115, 194619], [60116, 134091], michael@0: [21662, 60117], [60118, 134139], [60119, 134203], [60120, 134227], michael@0: [60121, 134245], [60122, 134268], [60124, 134285], [60126, 134325], michael@0: [60127, 134365], [60128, 134381], [60129, 134511], [60130, 134578], michael@0: [60131, 134600], [60135, 134660], [60136, 134670], [60137, 134871], michael@0: [60138, 135056], [60139, 134957], [60140, 134771], [60142, 135100], michael@0: [60144, 135260], [60145, 135247], [60146, 135286], [60149, 135304], michael@0: [60150, 135318], [13895, 60151], [60152, 135359], [60154, 135471], michael@0: [60155, 135483], [21348, 60156], [60158, 135907], [60159, 136053], michael@0: [60160, 135990], [60162, 136567], [60163, 136729], [60164, 137155], michael@0: [60165, 137159], [28859, 60167], [60168, 137261], [60169, 137578], michael@0: [60170, 137773], [60171, 137797], [60172, 138282], [60173, 138352], michael@0: [60174, 138412], [60175, 138952], [60177, 138965], [60178, 139029], michael@0: [29080, 60179], [60181, 139333], [27113, 60182], [14024, 60183], michael@0: [60184, 139900], [60185, 140247], [60186, 140282], [60187, 141098], michael@0: [60188, 141425], [60189, 141647], [60191, 141671], [60192, 141715], michael@0: [60193, 142037], [60195, 142056], [60197, 142094], [60199, 142143], michael@0: [60202, 142412], [60204, 142472], [60205, 142519], [60206, 154600], michael@0: [60207, 142600], [60208, 142610], [60209, 142775], [60210, 142741], michael@0: [60211, 142914], [60212, 143220], [60213, 143308], [60214, 143411], michael@0: [60215, 143462], [60216, 144159], [60217, 144350], [60222, 144743], michael@0: [60223, 144883], [60227, 144922], [60228, 145174], [22709, 60231], michael@0: [60234, 146087], [60237, 146961], [60238, 147129], [60243, 147737], michael@0: [60245, 148206], [60246, 148237], [60248, 148276], [60249, 148374], michael@0: [60258, 148484], [60259, 148694], [22408, 60260], [60261, 149108], michael@0: [60263, 149295], [60271, 149522], [60272, 149755], [60273, 150037], michael@0: [60275, 150208], [22885, 60277], [60279, 151430], [60282, 151596], michael@0: [22335, 60284], [60286, 152217], [60287, 152601], [60291, 152646], michael@0: [60292, 152686], [60296, 152895], [60298, 152926], [60300, 152930], michael@0: [60301, 152934], [60302, 153543], [60304, 153693], [60309, 153859], michael@0: [60312, 154286], [60313, 154505], [60314, 154630], [22433, 60316], michael@0: [29009, 60317], [60319, 155906], [60322, 156082], [60325, 156674], michael@0: [60326, 156746], [60330, 156804], [60334, 156808], [60336, 156946], michael@0: [60338, 157119], [60339, 157365], [22201, 60347], [60349, 157436], michael@0: [13848, 60355], [60357, 157593], [60358, 157806], [60360, 157790], michael@0: [60362, 157895], [60366, 157990], [60368, 158009], [60371, 158202], michael@0: [60373, 158253], [60378, 158260], [60379, 158555], [60383, 158621], michael@0: [60385, 158884], [60388, 159150], [60392, 159819], [60393, 160205], michael@0: [60395, 160384], [60396, 160389], [60399, 160395], [60401, 160486], michael@0: [38047, 60404], [60405, 160848], [14009, 60416], [60424, 161740], michael@0: [60425, 161880], [22230, 60426], [60435, 162269], [60441, 162301], michael@0: [60442, 162314], [60443, 162571], [60444, 163174], [60448, 163849], michael@0: [60459, 163875], [60463, 163912], [60466, 163971], [60479, 163984], michael@0: [60480, 164084], [60481, 164142], [60483, 164175], [60485, 164271], michael@0: [60486, 164378], [60487, 164614], [60488, 164655], [60489, 164746], michael@0: [60491, 164968], [60492, 165546], [25574, 60494], [60495, 166230], michael@0: [60498, 166328], [60500, 166375], [60502, 166376], [60503, 166726], michael@0: [60504, 166868], [60506, 166921], [60508, 167877], [60509, 168172], michael@0: [60511, 168208], [60512, 168252], [15863, 60513], [60514, 168286], michael@0: [60515, 150218], [36816, 60516], [60519, 169191], [60521, 169392], michael@0: [60522, 169400], [60523, 169778], [60524, 170193], [60525, 170313], michael@0: [60526, 170346], [60527, 170435], [60528, 170536], [60529, 170766], michael@0: [60530, 171354], [60531, 171419], [32415, 60532], [60533, 171768], michael@0: [60534, 171811], [19620, 60535], [38215, 60536], [60537, 172691], michael@0: [29090, 60538], [60539, 172799], [60542, 173515], [19868, 60543], michael@0: [60544, 134300], [36798, 60545], [36794, 60547], [60548, 140464], michael@0: [36793, 60549], [60550, 150163], [20202, 60555], [60557, 166700], michael@0: [36480, 60560], [60561, 137205], [60563, 166764], [60564, 166809], michael@0: [60566, 157359], [60568, 161365], [60570, 153141], [60571, 153942], michael@0: [20122, 60572], [60573, 155265], [60576, 134765], [60579, 147080], michael@0: [60580, 150686], [60583, 137206], [60584, 137339], [60587, 154698], michael@0: [60589, 152337], [15814, 60590], [60596, 155352], [19996, 60600], michael@0: [60601, 135146], [60602, 134473], [60603, 145082], [60638, 151880], michael@0: [21982, 60644], [34694, 60672], [60676, 135361], [60679, 149254], michael@0: [23440, 60680], [60682, 157843], [60684, 141044], [60685, 163119], michael@0: [60686, 147875], [60687, 163187], [60688, 159440], [60689, 160438], michael@0: [60691, 135641], [60693, 146684], [60694, 173737], [60695, 134828], michael@0: [60698, 138402], [60700, 151490], [60702, 135147], [60706, 142752], michael@0: [60710, 135148], [60711, 134666], [60714, 135149], [60717, 135559], michael@0: [19994, 60721], [19972, 60722], [23309, 60724], [13996, 60727], michael@0: [21373, 60729], [13989, 60730], [22682, 60732], [60733, 150382], michael@0: [22442, 60736], [60737, 154261], [60738, 133497], [60741, 140389], michael@0: [60746, 146686], [60747, 171824], [60749, 151465], [60750, 169374], michael@0: [60753, 146870], [60755, 157619], [60756, 145184], [60759, 147191], michael@0: [60760, 146988], [60785, 143578], [60789, 135849], [22439, 60790], michael@0: [60791, 149859], [60794, 159918], [60801, 137068], [60806, 160100], michael@0: [60809, 159010], [60810, 150242], [39963, 60837], [60838, 149822], michael@0: [15878, 60846], [60881, 159011], [60887, 132092], [60891, 146685], michael@0: [60893, 149785], [22394, 60904], [21722, 60912], [29050, 60928], michael@0: [60949, 150135], [60955, 166490], [60962, 194624], [60976, 137275], michael@0: [61000, 155993], [61014, 144373], [61019, 166850], [61024, 138566], michael@0: [61054, 159441], [13877, 61065], [61084, 166701], [21024, 61088], michael@0: [15384, 61089], [61090, 146631], [61091, 155351], [61092, 161366], michael@0: [61093, 152881], [61094, 137540], [61096, 170243], [61097, 159196], michael@0: [61098, 159917], [61100, 156077], [61101, 166415], [61102, 145015], michael@0: [61103, 131310], [61104, 157766], [61105, 151310], [17762, 61106], michael@0: [23327, 61107], [61108, 156492], [40784, 61109], [40614, 61110], michael@0: [61111, 156267], [20962, 57415], [21314, 57416], [26285, 57520], michael@0: [22620, 57547], [21843, 57566], [15749, 57594], [24928, 57608], michael@0: [18606, 57668], [38845, 57676], [57693, 137335], [24755, 57703], michael@0: [33828, 57711], [38932, 57748], [57749, 147596], [57764, 143486], michael@0: [57787, 138813], [15147, 57798], [15666, 57824], [57857, 132021], michael@0: [28801, 57944], [23708, 57959], [58017, 132547], [14128, 58028], michael@0: [58096, 136054], [58097, 150034], [58111, 166699], [58112, 155779], michael@0: [256, 62233], [193, 62234], [461, 62235], [192, 62236], [274, 62237], michael@0: [201, 62238], [282, 62239], [200, 62240], [332, 62241], [211, 62242], michael@0: [465, 62243], [210, 62244], 62245, [7870, 62246], 62247, [7872, 62248], michael@0: [202, 62249], [257, 62250], [225, 62251], [462, 62252], [224, 62253], michael@0: [593, 62254], [275, 62255], [233, 62256], [283, 62257], [232, 62258], michael@0: [299, 62259], [237, 62260], [464, 62261], [236, 62262], [333, 62263], michael@0: [243, 62264], [466, 62265], [242, 62266], [363, 62267], [250, 62268], michael@0: [468, 62269], [249, 62270], [470, 62271], [472, 62272], [474, 62273], michael@0: [476, 62274], [252, 62275], 62276, [7871, 62277], 62278, [7873, 62279], michael@0: [234, 62280], [609, 62281], [643, 63551], [592, 63552], [603, 63553], michael@0: [596, 63554], [629, 63555], [339, 63556], [248, 63557], [331, 63558], michael@0: [650, 63559], [618, 63560], {f: 2, c: 62282}, [11933, 63530], michael@0: [11974, 63539], [12003, 63547], 20539, 28158, [62841, 171123], 62842, michael@0: [15817, 62843], 34959, [62845, 147790], 28791, 23797, [19232, 62848], michael@0: [62849, 152013], [13657, 62850], [62851, 154928], 24866, [62853, 166450], michael@0: 36775, 37366, 29073, 26393, 29626, [62859, 144001], [62860, 172295], michael@0: [15499, 62861], [62862, 137600], [19216, 62863], 30948, 29698, 20910, michael@0: [62867, 165647], [16393, 62868], 27235, [62870, 172730], [16931, 62871], michael@0: 34319, 31274, [62875, 170311], [62876, 166634], 38741, 28749, 21284, michael@0: [62880, 139390], 37876, 30425, [62883, 166371], 62884, 30685, 20131, 20464, michael@0: 20668, 20015, 20247, 62891, 21556, 32139, 22674, 22736, [62896, 138678], michael@0: 24210, 24217, 24514, [62900, 141074], 25995, [62902, 144377], 26905, 27203, michael@0: [62905, 146531], 27903, 29184, [62909, 148741], 29580, [16091, 62911], michael@0: [62912, 150035], 23317, 29881, 35715, [62916, 154788], [62917, 153237], michael@0: 31379, 31724, 31939, 32364, 33528, 34199, 62924, 34960, 62926, 36537, michael@0: 62928, 36815, 34143, 39392, 37409, 62933, [62934, 167353], [62935, 136255], michael@0: [16497, 62936], [17058, 62937], 23066, 39016, 26475, [17014, 62944], 22333, michael@0: 34262, [62948, 149883], 33471, [62950, 160013], [19585, 62951], michael@0: [62952, 159092], 23931, [62954, 158485], [62955, 159678], {f: 2, c: 62956}, michael@0: 23446, 62959, 32347], michael@0: 'Adobe-GB1': [{f: 95, c: 32}, {f: 3, c: 12288}, [183, 12539], 713, 711, 168, michael@0: 12291, 12293, 8212, 65374, 8214, [8230, 8943], {f: 2, c: 8216}, michael@0: {f: 2, c: 8220}, {f: 2, c: 12308}, {f: 8, c: 12296}, {f: 2, c: 12310}, michael@0: {f: 2, c: 12304}, 177, 215, 247, 8758, {f: 2, c: 8743}, 8721, 8719, 8746, michael@0: 8745, 8712, 8759, 8730, 8869, 8741, 8736, 8978, 8857, 8747, 8750, 8801, michael@0: 8780, 8776, 8765, 8733, 8800, {f: 2, c: 8814}, {f: 2, c: 8804}, 8734, 8757, michael@0: 8756, 9794, 9792, 176, {f: 2, c: 8242}, 8451, 65284, 164, {f: 2, c: 65504}, michael@0: 8240, 167, 8470, 9734, 9733, 9675, 9679, 9678, 9671, 9670, 9633, 9632, michael@0: 9651, 9650, 8251, 8594, {f: 2, c: 8592}, 8595, 12307, {f: 20, c: 9352}, michael@0: {f: 20, c: 9332}, {f: 10, c: 9312}, {f: 10, c: 12832}, {f: 12, c: 8544}, michael@0: {f: 3, c: 65281}, 65509, {f: 89, c: 65285}, 65507, {f: 83, c: 12353}, michael@0: {f: 86, c: 12449}, {f: 17, c: 913}, {f: 7, c: 931}, {f: 17, c: 945}, michael@0: {f: 7, c: 963}, {f: 7, c: 59277}, {f: 2, c: 65077}, {f: 2, c: 65081}, michael@0: {f: 2, c: 65087}, {f: 2, c: 65085}, {f: 4, c: 65089}, {f: 2, c: 59284}, michael@0: {f: 2, c: 65083}, {f: 2, c: 65079}, 65073, 59286, {f: 2, c: 65075}, michael@0: {f: 6, c: 1040}, 1025, {f: 32, c: 1046}, 1105, {f: 26, c: 1078}, 257, 225, michael@0: 462, 224, 275, 233, 283, 232, 299, 237, 464, 236, 333, 243, 466, 242, 363, michael@0: 250, 468, 249, 470, 472, 474, 476, 252, 234, 593, 7743, 324, 328, 505, 609, michael@0: {f: 37, c: 12549}, 0, {f: 76, c: 9472}, {s: 126}, 21834, 38463, 22467, michael@0: 25384, 21710, 21769, 21696, 30353, 30284, 34108, 30702, 33406, 30861, michael@0: 29233, 38552, 38797, 27688, 23433, 20474, 25353, 26263, 23736, 33018, michael@0: 26696, 32942, 26114, 30414, 20985, 25942, 29100, 32753, 34948, 20658, michael@0: 22885, 25034, 28595, 33453, 25420, 25170, 21485, 21543, 31494, michael@0: [12043, 20843], 30116, 24052, 25300, 36299, 38774, 25226, 32793, 22365, michael@0: 38712, 32610, 29240, [12137, 30333], 26575, 30334, 25670, 20336, 36133, michael@0: 25308, 31255, 26001, 29677, 25644, 25203, 33324, 39041, 26495, 29256, michael@0: 25198, 25292, 20276, 29923, 21322, 21150, 32458, 37030, 24110, 26758, michael@0: 27036, 33152, 32465, 26834, 30917, 34444, 38225, 20621, 35876, 33502, michael@0: 32990, 21253, 35090, 21093, 34180, 38649, 20445, 22561, 39281, 23453, michael@0: 25265, 25253, 26292, 35961, 40077, 29190, 26479, 30865, 24754, 21329, michael@0: 21271, 36744, 32972, 36125, 38049, 20493, 29384, 22791, 24811, 28953, michael@0: 34987, 22868, 33519, 26412, 31528, 23849, 32503, 29997, 27893, 36454, michael@0: 36856, 36924, [12240, 40763], [12112, 27604], 37145, 31508, 24444, 30887, michael@0: 34006, 34109, 27605, 27609, 27606, 24065, 24199, 30201, 38381, 25949, michael@0: 24330, 24517, 36767, 22721, 33218, 36991, 38491, 38829, 36793, 32534, michael@0: 36140, 25153, 20415, 21464, 21342, {f: 2, c: 36776}, 36779, 36941, 26631, michael@0: 24426, 33176, 34920, 40150, 24971, 21035, 30250, 24428, 25996, 28626, michael@0: 28392, 23486, 25672, 20853, 20912, 26564, 19993, 31177, 39292, 28851, michael@0: 30149, 24182, 29627, 33760, 25773, 25320, 38069, 27874, 21338, 21187, michael@0: 25615, 38082, 31636, 20271, 24091, 33334, 33046, 33162, 28196, 27850, michael@0: 39539, 25429, [12056, 21340], 21754, 34917, 22496, 19981, 24067, 27493, michael@0: 31807, 37096, 24598, 25830, 29468, 35009, 26448, 25165, 36130, 30572, michael@0: 36393, 37319, 24425, 33756, 34081, 39184, 21442, 34453, 27531, 24813, michael@0: 24808, 28799, 33485, 33329, 20179, 27815, 34255, 25805, 31961, 27133, michael@0: 26361, 33609, 21397, 31574, 20391, 20876, 27979, 23618, 36461, 25554, michael@0: 21449, 33580, 33590, 26597, 30900, 25661, 23519, 23700, 24046, 35815, michael@0: 25286, 26612, 35962, 25600, 25530, 34633, 39307, 35863, 32544, 38130, michael@0: 20135, 38416, 39076, 26124, 29462, 22330, 23581, 24120, 38271, 20607, michael@0: 32928, [12058, 21378], 25950, 30021, 21809, 20513, 36229, 25220, 38046, michael@0: 26397, 22066, 28526, 24034, 21557, 28818, 36710, 25199, 25764, 25507, michael@0: 24443, 28552, 37108, [12162, 33251], [12192, 36784], 23576, 26216, 24561, michael@0: 27785, 38472, 36225, 34924, 25745, 31216, 22478, 27225, 25104, 21576, michael@0: 20056, 31243, 24809, 28548, 35802, 25215, 36894, 39563, 31204, 21507, michael@0: 30196, 25345, 21273, 27744, 36831, 24347, 39536, 32827, 40831, 20360, michael@0: 23610, [12186, 36196], 32709, 26021, 28861, 20805, 20914, [12173, 34411], michael@0: 23815, 23456, 25277, 37228, 30068, 36364, 31264, 24833, 31609, 20167, michael@0: 32504, 30597, 19985, 33261, 21021, 20986, 27249, 21416, 36487, 38148, michael@0: 38607, 28353, 38500, 26970, 30784, 20648, 30679, 25616, 35302, 22788, michael@0: 25571, 24029, 31359, 26941, 20256, 33337, 21912, 20018, 30126, 31383, michael@0: 24162, 24202, 38383, 21019, 21561, 28810, 25462, 38180, 22402, 26149, michael@0: 26943, 37255, 21767, 28147, 32431, 34850, 25139, 32496, 30133, 33576, michael@0: 30913, 38604, 36766, 24904, 29943, 35789, 27492, 21050, 36176, 27425, michael@0: 32874, 33905, 22257, 21254, 20174, 19995, 20945, 31895, 37259, 31751, michael@0: 20419, 36479, 31713, 31388, 25703, 23828, 20652, 33030, 30209, 31929, michael@0: 28140, 32736, 26449, 23384, [12072, 23544], 30923, 25774, 25619, 25514, michael@0: 25387, 38169, 25645, 36798, 31572, 30249, 25171, [12068, 22823], 21574, michael@0: [12109, 27513], 20643, 25140, 24102, 27526, 20195, 36151, 34955, 24453, michael@0: 36910, 24608, 32829, 25285, 20025, 21333, 37112, 25528, 32966, 26086, michael@0: 27694, 20294, 24814, 28129, 35806, 24377, 34507, 24403, 25377, 20826, michael@0: 33633, 26723, [12049, 20992], 25443, 36424, 20498, 23707, 31095, 23548, michael@0: 21040, 31291, 24764, 36947, 30423, 24503, 24471, 30340, 36460, 28783, michael@0: 30331, 31561, 30634, 20979, 37011, 22564, 20302, 28404, 36842, 25932, michael@0: 31515, 29380, 28068, 32735, 23265, 25269, 24213, 22320, 33922, 31532, michael@0: 24093, 24351, 36882, 32532, 39072, 25474, 28359, 30872, 28857, 20856, michael@0: 38747, 22443, 30005, 20291, 30008, 24215, 24806, 22880, 28096, 27583, michael@0: 30857, 21500, 38613, 20939, 20993, 25481, 21514, 38035, 35843, 36300, michael@0: 29241, 30879, 34678, 36845, 35853, 21472, 19969, 30447, 21486, 38025, michael@0: 39030, [12237, 40718], 38189, 23450, 35746, 20002, 19996, 20908, 33891, michael@0: 25026, 21160, 26635, 20375, 24683, 20923, 27934, 20828, 25238, michael@0: [12099, 26007], 38497, [12182, 35910], 36887, 30168, 37117, 30563, 27602, michael@0: 29322, 29420, 35835, 22581, 30585, 36172, 26460, 38208, 32922, 24230, michael@0: 28193, 22930, 31471, 30701, 38203, 27573, 26029, 32526, 22534, 20817, michael@0: 38431, 23545, 22697, 21544, 36466, 25958, 39039, 22244, 38045, 30462, michael@0: 36929, 25479, 21702, 22810, 22842, 22427, 36530, 26421, 36346, 33333, michael@0: 21057, 24816, 22549, 34558, 23784, 40517, 20420, 39069, 35769, 23077, michael@0: 24694, 21380, 25212, 36943, 37122, 39295, 24681, [12157, 32780], michael@0: [12041, 20799], [12159, 32819], 23572, 39285, 27953, [12038, 20108], 36144, michael@0: 21457, 32602, 31567, 20240, 20047, 38400, 27861, 29648, 34281, 24070, michael@0: 30058, 32763, 27146, 30718, 38034, 32321, 20961, 28902, 21453, 36820, michael@0: 33539, 36137, 29359, 39277, 27867, 22346, 33459, [12101, 26041], 32938, michael@0: 25151, 38450, 22952, 20223, 35775, 32442, 25918, 33778, [12206, 38750], michael@0: 21857, 39134, 32933, 21290, 35837, 21536, 32954, 24223, 27832, 36153, michael@0: 33452, 37210, 21545, 27675, 20998, 32439, 22367, 28954, 27774, 31881, michael@0: 22859, 20221, 24575, 24868, 31914, 20016, 23553, 26539, 34562, 23792, michael@0: 38155, 39118, 30127, 28925, 36898, 20911, 32541, 35773, 22857, 20964, michael@0: 20315, 21542, 22827, 25975, 32932, 23413, 25206, 25282, 36752, 24133, michael@0: 27679, 31526, 20239, 20440, 26381, 28014, 28074, 31119, 34993, 24343, michael@0: 29995, 25242, 36741, 20463, 37340, 26023, 33071, 33105, 24220, 33104, michael@0: 36212, 21103, 35206, 36171, 22797, 20613, 20184, [12201, 38428], michael@0: [12119, 29238], 33145, 36127, 23500, 35747, 38468, 22919, 32538, 21648, michael@0: 22134, 22030, 35813, 25913, 27010, 38041, 30422, 28297, [12082, 24178], michael@0: [12130, 29976], 26438, 26577, 31487, 32925, 36214, 24863, 31174, 25954, michael@0: 36195, 20872, 21018, 38050, 32568, 32923, 32434, 23703, 28207, 26464, michael@0: 31705, 30347, [12220, 39640], 33167, 32660, 31957, 25630, 38224, 31295, michael@0: 21578, 21733, 27468, 25601, [12093, 25096], 40509, 33011, 30105, 21106, michael@0: [12208, 38761], 33883, 26684, 34532, 38401, 38548, 38124, 20010, 21508, michael@0: 32473, 26681, 36319, 32789, 26356, 24218, 32697, 22466, 32831, 26775, michael@0: [12079, 24037], 25915, 21151, 24685, 40858, 20379, 36524, 20844, 23467, michael@0: [12088, 24339], 24041, 27742, 25329, 36129, 20849, 38057, 21246, 27807, michael@0: 33503, 29399, 22434, 26500, 36141, 22815, 36764, 33735, 21653, 31629, michael@0: 20272, 27837, 23396, 22993, [12238, 40723], 21476, 34506, [12219, 39592], michael@0: [12181, 35895], 32929, 25925, 39038, 22266, 38599, 21038, [12128, 29916], michael@0: 21072, 23521, 25346, 35074, 20054, 25296, 24618, 26874, 20851, 23448, michael@0: 20896, 35266, 31649, 39302, 32592, 24815, 28748, 36143, 20809, michael@0: [12084, 24191], 36891, 29808, 35268, 22317, 30789, 24402, 40863, 38394, michael@0: 36712, [12225, 39740], 35809, 30328, 26690, 26588, 36330, 36149, 21053, michael@0: 36746, 28378, 26829, 38149, 37101, 22269, 26524, 35065, 36807, 21704, michael@0: 39608, 23401, 28023, 27686, 20133, 23475, 39559, 37219, 25000, 37039, michael@0: 38889, 21547, 28085, 23506, 20989, 21898, 32597, 32752, 25788, 25421, michael@0: 26097, 25022, 24717, 28938, 27735, 27721, 22831, 26477, 33322, 22741, michael@0: 22158, 35946, 27627, 37085, 22909, 32791, 21495, 28009, 21621, 21917, michael@0: 33655, 33743, 26680, [12146, 31166], 21644, 20309, 21512, 30418, 35977, michael@0: 38402, 27827, 28088, 36203, 35088, 40548, 36154, 22079, [12234, 40657], michael@0: 30165, 24456, 29408, 24680, 21756, 20136, 27178, 34913, 24658, 36720, michael@0: 21700, 28888, 34425, 40511, 27946, 23439, 24344, 32418, 21897, 20399, michael@0: 29492, 21564, 21402, 20505, 21518, 21628, 20046, 24573, 29786, 22774, michael@0: 33899, 32993, 34676, 29392, 31946, 28246, 24359, 34382, 21804, 25252, michael@0: 20114, 27818, 25143, 33457, 21719, 21326, 29502, 28369, 30011, 21010, michael@0: 21270, 35805, 27088, 24458, 24576, 28142, 22351, 27426, 29615, 26707, michael@0: 36824, 32531, 25442, 24739, 21796, 30186, 35938, 28949, 28067, 23462, michael@0: 24187, 33618, 24908, 40644, 30970, 34647, 31783, 30343, 20976, 24822, michael@0: 29004, 26179, 24140, 24653, 35854, 28784, 25381, 36745, 24509, 24674, michael@0: 34516, 22238, 27585, 24724, 24935, 21321, 24800, 26214, 36159, 31229, michael@0: 20250, 28905, 27719, 35763, 35826, 32472, 33636, 26127, 23130, 39746, michael@0: 27985, 28151, 35905, 27963, 20249, [12117, 28779], 33719, 25110, 24785, michael@0: 38669, 36135, 31096, 20987, 22334, 22522, 26426, 30072, 31293, 31215, michael@0: 31637, 32908, 39269, 36857, 28608, 35749, 40481, 23020, 32489, 32521, michael@0: 21513, 26497, 26840, 36753, 31821, 38598, 21450, 24613, 30142, 27762, michael@0: 21363, 23241, 32423, 25380, [12047, 20960], 33034, [12080, 24049], 34015, michael@0: 25216, 20864, 23395, 20238, 31085, 21058, 24760, 27982, 23492, 23490, michael@0: 35745, 35760, 26082, 24524, 38469, 22931, 32487, 32426, 22025, 26551, michael@0: 22841, 20339, 23478, 21152, 33626, 39050, 36158, 30002, 38078, 20551, michael@0: 31292, 20215, 26550, 39550, 23233, 27516, 30417, 22362, 23574, 31546, michael@0: 38388, 29006, 20860, 32937, 33392, 22904, 32516, 33575, 26816, 26604, michael@0: 30897, 30839, 25315, 25441, 31616, 20461, 21098, 20943, 33616, 27099, michael@0: 37492, 36341, 36145, 35265, 38190, 31661, 20214, 20581, 33328, 21073, michael@0: 39279, 28176, 28293, 28071, 24314, 20725, 23004, 23558, 27974, 27743, michael@0: 30086, 33931, 26728, 22870, 35762, 21280, 37233, 38477, 34121, 26898, michael@0: 30977, 28966, 33014, 20132, 37066, 27975, 39556, 23047, 22204, 25605, michael@0: 38128, 30699, 20389, 33050, 29409, [12179, 35282], 39290, 32564, 32478, michael@0: 21119, 25945, 37237, 36735, 36739, 21483, 31382, 25581, 25509, 30342, michael@0: 31224, 34903, 38454, 25130, 21163, 33410, 26708, 26480, 25463, 30571, michael@0: 31469, 27905, 32467, 35299, 22992, 25106, 34249, 33445, 30028, 20511, michael@0: 20171, 30117, 35819, 23626, [12081, 24062], 31563, [12100, 26020], michael@0: [12198, 37329], 20170, 27941, 35167, 32039, 38182, 20165, 35880, 36827, michael@0: 38771, 26187, 31105, 36817, 28908, 28024, 23613, 21170, 33606, 20834, michael@0: 33550, 30555, 26230, 40120, 20140, 24778, 31934, 31923, 32463, 20117, michael@0: 35686, 26223, 39048, 38745, 22659, 25964, 38236, 24452, 30153, 38742, michael@0: 31455, 31454, 20928, 28847, 31384, 25578, 31350, 32416, 29590, michael@0: [12210, 38893], 20037, 28792, 20061, 37202, 21417, 25937, 26087, michael@0: [12165, 33276], 33285, 21646, 23601, 30106, 38816, 25304, 29401, 30141, michael@0: 23621, 39545, 33738, 23616, 21632, 30697, 20030, 27822, 32858, 25298, michael@0: 25454, 24040, 20855, 36317, 36382, 38191, 20465, 21477, 24807, 28844, michael@0: 21095, 25424, 40515, 23071, 20518, 30519, 21367, 32482, 25733, 25899, michael@0: 25225, 25496, 20500, 29237, 35273, 20915, 35776, 32477, 22343, 33740, michael@0: 38055, 20891, 21531, 23803, 20426, 31459, 27994, 37089, 39567, 21888, michael@0: 21654, 21345, 21679, 24320, 25577, 26999, 20975, 24936, 21002, 22570, michael@0: 21208, 22350, 30733, 30475, 24247, 24951, 31968, 25179, 25239, 20130, michael@0: 28821, 32771, 25335, 28900, 38752, 22391, 33499, 26607, 26869, 30933, michael@0: 39063, 31185, 22771, 21683, 21487, 28212, 20811, 21051, 23458, 35838, michael@0: 32943, 21827, 22438, 24691, 22353, 21549, 31354, 24656, 23380, 25511, michael@0: 25248, [12061, 21475], 25187, 23495, 26543, 21741, 31391, 33510, 37239, michael@0: 24211, 35044, 22840, 22446, 25358, 36328, 33007, 22359, 31607, 20393, michael@0: 24555, 23485, 27454, 21281, 31568, 29378, 26694, 30719, 30518, 26103, michael@0: 20917, 20111, 30420, 23743, 31397, 33909, 22862, 39745, 20608, 39304, michael@0: 24871, 28291, 22372, 26118, 25414, 22256, 25324, 25193, 24275, 38420, michael@0: 22403, 25289, 21895, 34593, 33098, 36771, 21862, 33713, 26469, 36182, michael@0: 34013, 23146, 26639, 25318, 31726, 38417, 20848, 28572, 35888, 25597, michael@0: 35272, 25042, 32518, 28866, 28389, 29701, 27028, 29436, 24266, 37070, michael@0: 26391, 28010, 25438, 21171, 29282, [12156, 32769], 20332, 23013, 37226, michael@0: 28889, 28061, 21202, 20048, 38647, 38253, 34174, 30922, 32047, 20769, michael@0: 22418, 25794, 32907, 31867, 27882, 26865, 26974, 20919, 21400, 26792, michael@0: 29313, 40654, 31729, 29432, 31163, 28435, 29702, 26446, [12197, 37324], michael@0: 40100, 31036, 33673, 33620, 21519, 26647, 20029, 21385, 21169, 30782, michael@0: 21382, 21033, 20616, 20363, 20432, 30178, [12148, 31435], 31890, 27813, michael@0: [12202, 38582], [12050, 21147], 29827, 21737, 20457, 32852, 33714, 36830, michael@0: 38256, 24265, 24604, 28063, 24088, 25947, 33080, 38142, 24651, 28860, michael@0: 32451, 31918, 20937, 26753, 31921, 33391, 20004, 36742, 37327, 26238, michael@0: 20142, 35845, 25769, 32842, 20698, 30103, 29134, 23525, 36797, 28518, michael@0: 20102, 25730, 38243, 24278, 26009, 21015, 35010, 28872, 21155, 29454, michael@0: 29747, 26519, 30967, 38678, 20020, 37051, 40158, 28107, 20955, 36161, michael@0: 21533, 25294, 29618, 33777, 38646, 40836, 38083, 20278, 32666, 20940, michael@0: 28789, 38517, 23725, 39046, 21478, 20196, 28316, 29705, 27060, 30827, michael@0: 39311, 30041, 21016, 30244, 27969, 26611, 20845, 40857, 32843, 21657, michael@0: 31548, 31423, 38534, 22404, 25314, 38471, 27004, 23044, 25602, 31699, michael@0: 28431, 38475, 33446, 21346, 39045, 24208, 28809, 25523, 21348, 34383, michael@0: 40065, 40595, 30860, 38706, 36335, 36162, [12229, 40575], 28510, 31108, michael@0: 24405, 38470, 25134, 39540, 21525, 38109, 20387, 26053, 23653, 23649, michael@0: 32533, 34385, 27695, 24459, 29575, 28388, 32511, 23782, 25371, 23402, michael@0: 28390, 21365, 20081, 25504, 30053, 25249, 36718, 20262, 20177, 27814, michael@0: 32438, 35770, 33821, 34746, 32599, 36923, 38179, 31657, 39585, 35064, michael@0: 33853, 27931, 39558, 32476, 22920, [12231, 40635], 29595, 30721, 34434, michael@0: 39532, 39554, 22043, 21527, 22475, 20080, 40614, 21334, 36808, 33033, michael@0: 30610, 39314, 34542, 28385, 34067, 26364, 24930, 28459, 35881, 33426, michael@0: 33579, 30450, 27667, 24537, 33725, 29483, 33541, 38170, [12113, 27611], michael@0: [12141, 30683], 38086, 21359, 33538, 20882, 24125, 35980, 36152, 20040, michael@0: 29611, 26522, 26757, 37238, 38665, 29028, 27809, 30473, 23186, 38209, michael@0: 27599, 32654, 26151, 23504, 22969, 23194, 38376, 38391, 20204, 33804, michael@0: 33945, 27308, 30431, 38192, 29467, 26790, 23391, 30511, 37274, 38753, michael@0: 31964, 36855, 35868, 24357, [12150, 31859], 31192, 35269, 27852, 34588, michael@0: 23494, 24130, 26825, 30496, 32501, 20885, 20813, 21193, 23081, 32517, michael@0: [12207, 38754], 33495, 25551, 30596, 34256, 31186, 28218, 24217, 22937, michael@0: 34065, 28781, 27665, 25279, [12139, 30399], 25935, 24751, 38397, 26126, michael@0: 34719, 40483, 38125, 21517, 21629, 35884, {f: 2, c: 25720}, 34321, 27169, michael@0: 33180, 30952, 25705, 39764, 25273, 26411, 33707, 22696, 40664, 27819, michael@0: 28448, 23518, 38476, 35851, 29279, 26576, 25287, 29281, 20137, 22982, michael@0: 27597, 22675, 26286, 24149, 21215, 24917, [12106, 26408], [12140, 30446], michael@0: 30566, 29287, 31302, 25343, 21738, 21584, 38048, 37027, 23068, 32435, michael@0: 27670, 20035, 22902, 32784, 22856, 21335, 30007, 38590, 22218, 25376, michael@0: 33041, 24700, 38393, 28118, 21602, 39297, 20869, 23273, 33021, 22958, michael@0: 38675, 20522, 27877, 23612, 25311, 20320, 21311, 33147, 36870, 28346, michael@0: 34091, 25288, 24180, 30910, 25781, 25467, 24565, 23064, 37247, 40479, michael@0: 23615, 25423, 32834, 23421, 21870, 38218, 38221, 28037, 24744, 26592, michael@0: 29406, 20957, 23425, 25319, 27870, [12124, 29275], 25197, 38062, 32445, michael@0: 33043, 27987, 20892, 24324, 22900, 21162, 24594, [12069, 22899], 26262, michael@0: 34384, 30111, 25386, 25062, 31983, 35834, 21734, 27431, 40485, 27572, michael@0: 34261, 21589, 20598, 27812, 21866, 36276, 29228, 24085, 24597, 29750, michael@0: 25293, 25490, 29260, 24472, 28227, 27966, 25856, 28504, 30424, 30928, michael@0: 30460, 30036, 21028, 21467, 20051, 24222, 26049, 32810, 32982, 25243, michael@0: 21638, 21032, 28846, 34957, 36305, 27873, 21624, 32986, 22521, 35060, michael@0: 36180, 38506, 37197, 20329, 27803, 21943, 30406, 30768, 25256, 28921, michael@0: 28558, 24429, 34028, 26842, 30844, 31735, 33192, 26379, 40527, 25447, michael@0: 30896, 22383, 30738, 38713, 25209, 25259, 21128, 29749, 27607, 21860, michael@0: 33086, 30130, [12138, 30382], 21305, 30174, 20731, 23617, 35692, 31687, michael@0: 20559, [12122, 29255], 39575, 39128, 28418, 29922, 31080, 25735, 30629, michael@0: 25340, 39057, 36139, 21697, 32856, 20050, 22378, 33529, 33805, 24179, michael@0: 20973, 29942, 35780, 23631, 22369, 27900, 39047, 23110, 30772, 39748, michael@0: 36843, 31893, 21078, 25169, 38138, 20166, 33670, 33889, 33769, 33970, michael@0: 22484, 26420, 22275, 26222, 28006, 35889, 26333, 28689, 26399, 27450, michael@0: 26646, 25114, 22971, 19971, 20932, 28422, 26578, 27791, 20854, 26827, michael@0: 22855, 27495, 30054, 23822, 33040, 40784, 26071, 31048, 31041, 39569, michael@0: 36215, 23682, 20062, 20225, 21551, 22865, 30732, 22120, [12115, 27668], michael@0: 36804, 24323, 27773, 27875, 35755, 25488, 24688, 27965, 29301, 25190, michael@0: 38030, 38085, 21315, 36801, 31614, 20191, 35878, 20094, 40660, 38065, michael@0: 38067, 21069, 28508, 36963, 27973, 35892, 22545, 23884, [12107, 27424], michael@0: 27465, 26538, 21595, 33108, 32652, 22681, 34103, 24378, 25250, 27207, michael@0: 38201, 25970, 24708, 26725, 30631, 20052, 20392, 24039, 38808, 25772, michael@0: 32728, 23789, 20431, 31373, 20999, 33540, 19988, 24623, 31363, 38054, michael@0: 20405, 20146, 31206, 29748, 21220, 33465, 25810, 31165, 23517, 27777, michael@0: 38738, 36731, 27682, 20542, 21375, 28165, 25806, 26228, 27696, 24773, michael@0: 39031, 35831, 24198, 29756, 31351, 31179, 19992, 37041, 29699, 27714, michael@0: 22234, 37195, 27845, 36235, 21306, 34502, 26354, 36527, 23624, 39537, michael@0: 28192, 21462, 23094, 40843, 36259, 21435, 22280, 39079, 26435, 37275, michael@0: 27849, 20840, 30154, 25331, [12125, 29356], 21048, 21149, 32570, 28820, michael@0: 30264, 21364, 40522, 27063, 30830, 38592, 35033, 32676, 28982, 29123, michael@0: 20873, 26579, 29924, 22756, 25880, 22199, 35753, 39286, 25200, 32469, michael@0: 24825, 28909, 22764, 20161, [12040, 20154], 24525, 38887, 20219, 35748, michael@0: 20995, 22922, 32427, 25172, 20173, [12103, 26085], 25102, 33592, 33993, michael@0: 33635, 34701, 29076, 28342, 23481, 32466, 20887, 25545, 26580, michael@0: [12161, 32905], 33593, 34837, 20754, 23418, 22914, 36785, 20083, 27741, michael@0: [12042, 20837], 35109, 36719, 38446, 34122, 29790, 38160, 38384, 28070, michael@0: 33509, 24369, 25746, 27922, 33832, 33134, 40131, 22622, 36187, 19977, michael@0: 21441, 20254, 25955, 26705, 21971, 20007, 25620, 39578, 25195, 23234, michael@0: 29791, [12170, 33394], 28073, 26862, 20711, 33678, 30722, 26432, 21049, michael@0: 27801, 32433, 20667, 21861, 29022, 31579, 26194, 29642, 33515, 26441, michael@0: [12077, 23665], 21024, 29053, 34923, 38378, 38485, 25797, 36193, 33203, michael@0: 21892, 27733, 25159, 32558, 22674, 20260, 21830, 36175, 26188, 19978, michael@0: 23578, 35059, 26786, 25422, 31245, 28903, 33421, 21242, 38902, 23569, michael@0: 21736, 37045, 32461, 22882, 36170, 34503, [12166, 33292], 33293, 36198, michael@0: 25668, 23556, 24913, 28041, 31038, 35774, 30775, 30003, 21627, 20280, michael@0: [12189, 36523], 28145, 23072, 32453, 31070, 27784, 23457, 23158, 29978, michael@0: 32958, 24910, 28183, 22768, [12131, 29983], 29989, 29298, 21319, 32499, michael@0: 30465, 30427, 21097, 32988, 22307, 24072, 22833, 29422, 26045, 28287, michael@0: 35799, [12075, 23608], 34417, [12055, 21313], [12143, 30707], 25342, 26102, michael@0: 20160, [12215, 39135], 34432, 23454, 35782, 21490, [12142, 30690], 20351, michael@0: 23630, 39542, 22987, 24335, [12144, 31034], [12064, 22763], 19990, 26623, michael@0: 20107, 25325, 35475, 36893, 21183, 26159, 21980, 22124, 36866, 20181, michael@0: 20365, 37322, 39280, [12114, 27663], 24066, 24643, 23460, 35270, 35797, michael@0: 25910, [12095, 25163], [12216, 39318], 23432, 23551, 25480, 21806, 21463, michael@0: 30246, 20861, 34092, 26530, 26803, 27530, 25234, 36755, 21460, 33298, michael@0: 28113, 30095, 20070, 36174, 23408, 29087, 34223, 26257, 26329, 32626, michael@0: 34560, [12233, 40653], [12239, 40736], 23646, 26415, 36848, 26641, 26463, michael@0: 25101, 31446, 22661, 24246, 25968, 28465, 24661, 21047, 32781, 25684, michael@0: 34928, 29993, 24069, 26643, 25332, 38684, 21452, 29245, 35841, michael@0: [12116, 27700], 30561, 31246, 21550, 30636, 39034, 33308, 35828, 30805, michael@0: 26388, 28865, 26031, 25749, 22070, 24605, 31169, 21496, 19997, 27515, michael@0: 32902, 23546, 21987, 22235, 20282, 20284, 39282, 24051, 26494, 32824, michael@0: 24578, 39042, 36865, 23435, 35772, 35829, 25628, 33368, 25822, 22013, michael@0: 33487, 37221, 20439, 32032, 36895, 31903, 20723, 22609, 28335, 23487, michael@0: 35785, 32899, 37240, 33948, 31639, 34429, 38539, 38543, 32485, 39635, michael@0: 30862, 23681, 31319, 36930, 38567, 31071, 23385, 25439, 31499, 34001, michael@0: 26797, 21766, 32553, 29712, 32034, 38145, 25152, 22604, 20182, 23427, michael@0: 22905, 22612, 29549, 25374, 36427, 36367, 32974, 33492, 25260, 21488, michael@0: 27888, 37214, 22826, 24577, 27760, 22349, 25674, 36138, 30251, 28393, michael@0: 22363, 27264, 30192, 28525, 35885, 35848, 22374, 27631, 34962, 30899, michael@0: 25506, 21497, 28845, 27748, 22616, 25642, 22530, 26848, 33179, 21776, michael@0: 31958, 20504, 36538, 28108, 36255, 28907, 25487, 28059, 28372, 32486, michael@0: 33796, 26691, 36867, 28120, 38518, 35752, 22871, 29305, 34276, 33150, michael@0: 30140, 35466, 26799, 21076, 36386, 38161, 25552, 39064, 36420, 21884, michael@0: 20307, 26367, 22159, 24789, 28053, 21059, 23625, 22825, 28155, 22635, michael@0: [12133, 30000], 29980, 24684, 33300, 33094, 25361, 26465, 36834, 30522, michael@0: 36339, 36148, 38081, 24086, 21381, 21548, 28867, 27712, 24311, 20572, michael@0: 20141, 24237, 25402, 33351, 36890, 26704, 37230, 30643, 21516, 38108, michael@0: 24420, 31461, 26742, 25413, 31570, 32479, 30171, 20599, 25237, 22836, michael@0: 36879, 20984, 31171, 31361, 22270, 24466, 36884, 28034, 23648, michael@0: [12063, 22303], 21520, 20820, 28237, 22242, 25512, 39059, 33151, 34581, michael@0: 35114, 36864, 21534, 23663, 33216, 25302, 25176, 33073, 40501, 38464, michael@0: 39534, 39548, 26925, 22949, 25299, 21822, 25366, 21703, 34521, 27964, michael@0: 23043, [12129, 29926], 34972, 27498, 22806, 35916, 24367, 28286, 29609, michael@0: 39037, 20024, 28919, 23436, 30871, 25405, 26202, 30358, 24779, 23451, michael@0: 23113, 19975, 33109, 27754, 29579, 20129, 26505, [12153, 32593], 24448, michael@0: 26106, 26395, 24536, 22916, 23041, 24013, 24494, 21361, 38886, 36829, michael@0: 26693, 22260, 21807, 24799, 20026, 28493, 32500, 33479, 33806, 22996, michael@0: 20255, 20266, 23614, 32428, 26410, 34074, 21619, 30031, 32963, 21890, michael@0: 39759, 20301, 28205, 35859, 23561, 24944, 21355, 30239, 28201, 34442, michael@0: [12098, 25991], 38395, 32441, 21563, 31283, 32010, 38382, 21985, 32705, michael@0: 29934, 25373, 34583, 28065, 31389, 25105, 26017, 21351, 25569, 27779, michael@0: 24043, 21596, 38056, 20044, 27745, 35820, 23627, [12102, 26080], 33436, michael@0: 26791, 21566, 21556, [12111, 27595], 27494, 20116, 25410, 21320, 33310, michael@0: 20237, 20398, 22366, 25098, 38654, 26212, 29289, 21247, 21153, 24735, michael@0: 35823, 26132, 29081, 26512, 35199, 30802, 30717, 26224, 22075, 21560, michael@0: 38177, 29306, 31232, 24687, 24076, 24713, 33181, [12067, 22805], 24796, michael@0: 29060, 28911, 28330, 27728, 29312, 27268, 34989, 24109, 20064, 23219, michael@0: 21916, 38115, 27927, 31995, 38553, 25103, 32454, 30606, 34430, 21283, michael@0: 38686, 36758, 26247, 23777, 20384, 29421, 19979, 21414, 22799, 21523, michael@0: 25472, 38184, 20808, 20185, 40092, 32420, 21688, 36132, 34900, 33335, michael@0: 38386, 28046, 24358, 23244, 26174, 38505, 29616, 29486, 21439, 33146, michael@0: 39301, 32673, 23466, 38519, 38480, 32447, 30456, 21410, 38262, michael@0: [12217, 39321], 31665, 35140, 28248, 20065, 32724, 31077, 35814, 24819, michael@0: 21709, 20139, 39033, 24055, 27233, 20687, 21521, 35937, 33831, 30813, michael@0: 38660, 21066, 21742, 22179, 38144, 28040, 23477, 28102, 26195, michael@0: [12073, 23567], 23389, 26657, 32918, 21880, 31505, 25928, 26964, 20123, michael@0: 27463, 34638, 38795, 21327, 25375, 25658, 37034, 26012, 32961, 35856, michael@0: 20889, 26800, 21368, 34809, 25032, 27844, 27899, 35874, 23633, 34218, michael@0: 33455, 38156, 27427, [12191, 36763], 26032, 24571, [12092, 24515], 20449, michael@0: 34885, 26143, 33125, 29481, 24826, 20852, 21009, 22411, 24418, 37026, michael@0: [12175, 34892], 37266, 24184, 26447, 24615, 22995, 20804, 20982, 33016, michael@0: 21256, 27769, 38596, 29066, 20241, 20462, 32670, 26429, 21957, 38152, michael@0: 31168, 34966, 32483, 22687, 25100, 38656, 34394, 22040, 39035, 24464, michael@0: 35768, 33988, 37207, 21465, 26093, 24207, 30044, 24676, 32110, 23167, michael@0: 32490, 32493, 36713, 21927, 23459, 24748, 26059, [12126, 29572], 36873, michael@0: 30307, 30505, 32474, 38772, 34203, 23398, [12147, 31348], 38634, michael@0: [12174, 34880], 21195, 29071, 24490, 26092, 35810, 23547, 39535, 24033, michael@0: 27529, 27739, 35757, 35759, 36874, 36805, 21387, 25276, 40486, 40493, michael@0: 21568, 20011, 33469, [12123, 29273], 34460, 23830, 34905, 28079, 38597, michael@0: 21713, 20122, 35766, 28937, 21693, 38409, 28895, 28153, 30416, 20005, michael@0: 30740, 34578, 23721, 24310, [12180, 35328], 39068, 38414, 28814, 27839, michael@0: 22852, 25513, 30524, 34893, 28436, 33395, 22576, 29141, 21388, 30746, michael@0: 38593, 21761, 24422, 28976, 23476, 35866, 39564, 27523, 22830, 40495, michael@0: 31207, 26472, 25196, 20335, 30113, [12154, 32650], 27915, 38451, 27687, michael@0: 20208, 30162, 20859, 26679, 28478, 36992, 33136, 22934, 29814, 25671, michael@0: 23591, 36965, 31377, 35875, 23002, 21676, 33280, 33647, 35201, 32768, michael@0: 26928, 22094, 32822, 29239, 37326, 20918, 20063, 39029, 25494, 19994, michael@0: 21494, 26355, 33099, 22812, 28082, [12032, 19968], 22777, 21307, 25558, michael@0: 38129, 20381, 20234, [12176, 34915], 39056, 22839, 36951, 31227, 20202, michael@0: 33008, 30097, 27778, 23452, 23016, 24413, 26885, 34433, 20506, 24050, michael@0: [12036, 20057], 30691, 20197, 33402, 25233, 26131, [12194, 37009], 23673, michael@0: 20159, 24441, 33222, 36920, 32900, 30123, 20134, 35028, 24847, 27589, michael@0: 24518, 20041, 30410, 28322, 35811, 35758, 35850, 35793, 24322, 32764, michael@0: 32716, 32462, 33589, 33643, 22240, 27575, [12211, 38899], 38452, 23035, michael@0: 21535, 38134, 28139, 23493, 39278, 23609, 24341, 38544, 21360, 33521, michael@0: 27185, 23156, 40560, 24212, 32552, 33721, {f: 2, c: 33828}, 33639, 34631, michael@0: 36814, 36194, 30408, 24433, 39062, 30828, 26144, 21727, 25317, 20323, michael@0: 33219, 30152, 24248, 38605, 36362, 34553, 21647, 27891, 28044, 27704, michael@0: 24703, 21191, [12132, 29992], 24189, 20248, 24736, 24551, 23588, 30001, michael@0: 37038, 38080, 29369, 27833, 28216, [12195, 37193], 26377, 21451, 21491, michael@0: 20305, 37321, 35825, [12060, 21448], 24188, 36802, 28132, 20110, 30402, michael@0: 27014, 34398, 24858, 33286, 20313, 20446, 36926, 40060, 24841, 28189, michael@0: 28180, 38533, 20104, 23089, [12204, 38632], 19982, 23679, 31161, 23431, michael@0: 35821, [12155, 32701], [12127, 29577], 22495, 33419, 37057, 21505, 36935, michael@0: 21947, 23786, 24481, 24840, 27442, 29425, 32946, 35465, 28020, 23507, michael@0: 35029, 39044, 35947, 39533, 40499, 28170, 20900, 20803, 22435, 34945, michael@0: 21407, 25588, 36757, 22253, 21592, 22278, 29503, 28304, 32536, 36828, michael@0: 33489, 24895, 24616, 38498, [12104, 26352], 32422, 36234, 36291, 38053, michael@0: 23731, 31908, [12105, 26376], 24742, 38405, 32792, 20113, 37095, 21248, michael@0: 38504, 20801, 36816, 34164, 37213, 26197, 38901, 23381, 21277, 30776, michael@0: 26434, 26685, 21705, 28798, 23472, 36733, 20877, 22312, 21681, 25874, michael@0: 26242, 36190, 36163, 33039, 33900, 36973, 31967, 20991, 34299, 26531, michael@0: 26089, 28577, 34468, 36481, 22122, 36896, 30338, 28790, 29157, 36131, michael@0: 25321, 21017, 27901, 36156, 24590, 22686, 24974, 26366, 36192, 25166, michael@0: 21939, 28195, 26413, 36711, 38113, 38392, 30504, 26629, 27048, 21643, michael@0: 20045, 28856, 35784, 25688, 25995, 23429, 31364, 20538, 23528, 30651, michael@0: 27617, 35449, 31896, 27838, 30415, 26025, 36759, 23853, 23637, 34360, michael@0: 26632, 21344, 25112, 31449, 28251, 32509, 27167, 31456, 24432, 28467, michael@0: 24352, 25484, 28072, 26454, 19976, 24080, 36134, 20183, 32960, 30260, michael@0: 38556, 25307, 26157, 25214, 27836, 36213, 29031, 32617, 20806, 32903, michael@0: 21484, 36974, 25240, 21746, 34544, 36761, 32773, 38167, 34071, 36825, michael@0: 27993, 29645, 26015, 30495, 29956, 30759, 33275, 36126, 38024, 20390, michael@0: 26517, 30137, 35786, 38663, 25391, 38215, 38453, 33976, 25379, 30529, michael@0: 24449, 29424, 20105, 24596, 25972, 25327, 27491, 25919, 24103, 30151, michael@0: 37073, 35777, 33437, 26525, [12096, 25903], 21553, 34584, 30693, 32930, michael@0: 33026, 27713, 20043, 32455, 32844, 30452, 26893, 27542, 25191, 20540, michael@0: 20356, 22336, 25351, [12108, 27490], 36286, 21482, 26088, 32440, 24535, michael@0: 25370, 25527, [12164, 33267], 33268, 32622, 24092, 23769, 21046, 26234, michael@0: 31209, 31258, 36136, 28825, 30164, 28382, 27835, 31378, 20013, 30405, michael@0: 24544, 38047, 34935, 32456, 31181, 32959, 37325, 20210, 20247, michael@0: [12168, 33311], 21608, 24030, 27954, 35788, 31909, 36724, 32920, 24090, michael@0: 21650, 30385, 23449, 26172, 39588, 29664, 26666, 34523, 26417, 29482, michael@0: 35832, 35803, 36880, [12149, 31481], 28891, 29038, 25284, 30633, 22065, michael@0: 20027, 33879, 26609, 21161, 34496, 36142, 38136, 31569, 20303, 27880, michael@0: 31069, 39547, 25235, [12118, 29226], 25341, 19987, 30742, 36716, 25776, michael@0: 36186, 31686, 26729, 24196, 35013, 22918, 25758, 22766, 29366, 26894, michael@0: 38181, 36861, 36184, 22368, 32512, 35846, 20934, 25417, 25305, 21331, michael@0: 26700, 29730, 33537, 37196, 21828, 30528, 28796, 27978, 20857, 21672, michael@0: 36164, 23039, 28363, 28100, 23388, 32043, 20180, 31869, 28371, michael@0: [12070, 23376], [12163, 33258], 28173, 23383, 39683, 26837, 36394, 23447, michael@0: 32508, 24635, 32437, 37049, [12187, 36208], 22863, 25549, 31199, michael@0: [12188, 36275], 21330, 26063, 31062, 35781, 38459, 32452, 38075, 32386, michael@0: 22068, 37257, 26368, 32618, 23562, 36981, 26152, 24038, 20304, 26590, michael@0: 20570, 20316, 22352, 24231, 20109, 19980, 20800, 19984, 24319, 21317, michael@0: 19989, 20120, 19998, [12224, 39730], 23404, 22121, [12033, 20008], 31162, michael@0: [12035, 20031], [12052, 21269], 20039, 22829, [12120, 29243], 21358, 27664, michael@0: 22239, 32996, 39319, 27603, 30590, 40727, [12034, 20022], 20127, 40720, michael@0: 20060, 20073, 20115, 33416, 23387, 21868, 22031, 20164, 21389, 21405, michael@0: 21411, 21413, 21422, 38757, 36189, [12053, 21274], 21493, 21286, 21294, michael@0: 21310, 36188, 21350, 21347, 20994, 21000, 21006, 21037, 21043, michael@0: {f: 2, c: 21055}, 21068, 21086, 21089, 21084, 33967, 21117, 21122, 21121, michael@0: 21136, 21139, [12044, 20866], 32596, 20155, 20163, 20169, 20162, 20200, michael@0: 20193, 20203, 20190, 20251, 20211, 20258, 20324, 20213, 20261, 20263, michael@0: 20233, 20267, 20318, 20327, 25912, 20314, 20317, 20319, 20311, 20274, michael@0: 20285, 20342, 20340, 20369, 20361, 20355, 20367, 20350, 20347, 20394, michael@0: 20348, 20396, 20372, 20454, 20456, 20458, 20421, 20442, 20451, 20444, michael@0: 20433, 20447, 20472, 20521, 20556, 20467, 20524, 20495, 20526, 20525, michael@0: 20478, 20508, 20492, 20517, 20520, 20606, 20547, 20565, 20552, 20558, michael@0: 20588, 20603, 20645, 20647, 20649, 20666, 20694, 20742, 20717, 20716, michael@0: 20710, 20718, 20743, 20747, 20189, 27709, 20312, 20325, 20430, michael@0: [12245, 40864], 27718, 31860, 20846, 24061, 40649, 39320, 20865, 22804, michael@0: [12051, 21241], 21261, 35335, 21264, 20971, 22809, 20821, [12039, 20128], michael@0: 20822, 20147, 34926, 34980, 20149, 33044, 35026, 31104, 23348, 34819, michael@0: 32696, [12046, 20907], 20913, 20925, 20924, 20935, [12045, 20886], 20898, michael@0: 20901, 35744, {f: 2, c: 35750}, 35754, {f: 2, c: 35764}, 35767, michael@0: {f: 2, c: 35778}, 35787, 35791, 35790, {f: 3, c: 35794}, 35798, michael@0: {f: 2, c: 35800}, 35804, {f: 2, c: 35807}, 35812, {f: 2, c: 35816}, 35822, michael@0: 35824, 35827, 35830, 35833, 35836, {f: 2, c: 35839}, 35842, 35844, 35847, michael@0: 35852, 35855, {f: 2, c: 35857}, {f: 3, c: 35860}, 35865, 35867, 35864, michael@0: 35869, {f: 3, c: 35871}, 35877, 35879, {f: 2, c: 35882}, {f: 2, c: 35886}, michael@0: {f: 2, c: 35890}, {f: 2, c: 35893}, [12057, 21353], 21370, 38429, 38434, michael@0: 38433, 38449, 38442, 38461, 38460, 38466, 38473, 38484, 38495, 38503, michael@0: 38508, 38514, 38516, 38536, 38541, 38551, 38576, 37015, 37019, 37021, michael@0: 37017, 37036, 37025, 37044, 37043, 37046, 37050, 37048, 37040, 37071, michael@0: 37061, 37054, 37072, 37060, 37063, 37075, 37094, 37090, 37084, 37079, michael@0: 37083, 37099, 37103, 37118, 37124, 37154, 37150, 37155, 37169, 37167, michael@0: 37177, 37187, 37190, 21005, 22850, 21154, {f: 2, c: 21164}, 21182, 21759, michael@0: 21200, 21206, 21232, 21471, 29166, 30669, [12085, 24308], [12048, 20981], michael@0: 20988, [12223, 39727], [12059, 21430], 24321, 30042, 24047, 22348, 22441, michael@0: 22433, 22654, 22716, 22725, 22737, 22313, 22316, 22314, 22323, 22329, michael@0: {f: 2, c: 22318}, 22364, 22331, 22338, 22377, 22405, 22379, 22406, 22396, michael@0: 22395, 22376, 22381, 22390, 22387, 22445, 22436, 22412, 22450, 22479, michael@0: 22439, 22452, 22419, 22432, 22485, 22488, 22490, 22489, 22482, 22456, michael@0: 22516, 22511, 22520, 22500, 22493, 22539, 22541, 22525, 22509, 22528, michael@0: 22558, 22553, 22596, 22560, 22629, 22636, 22657, 22665, 22682, 22656, michael@0: 39336, 40729, 25087, 33401, 33405, 33407, 33423, 33418, 33448, 33412, michael@0: 33422, 33425, 33431, 33433, 33451, 33464, 33470, 33456, 33480, 33482, michael@0: 33507, 33432, 33463, 33454, {f: 2, c: 33483}, 33473, 33449, 33460, 33441, michael@0: 33450, 33439, 33476, 33486, 33444, 33505, 33545, 33527, 33508, 33551, michael@0: 33543, 33500, 33524, 33490, 33496, 33548, 33531, 33491, 33553, 33562, michael@0: 33542, {f: 2, c: 33556}, 33504, 33493, 33564, 33617, {f: 2, c: 33627}, michael@0: 33544, 33682, 33596, 33588, 33585, 33691, 33630, 33583, 33615, 33607, michael@0: 33603, 33631, 33600, 33559, 33632, 33581, 33594, 33587, 33638, 33637, michael@0: 33640, 33563, 33641, 33644, 33642, {f: 2, c: 33645}, 33712, 33656, michael@0: {f: 2, c: 33715}, 33696, 33706, 33683, 33692, 33669, 33660, 33718, 33705, michael@0: 33661, 33720, 33659, 33688, 33694, 33704, 33722, 33724, 33729, 33793, michael@0: 33765, 33752, 22535, 33816, 33803, 33757, 33789, 33750, 33820, 33848, michael@0: 33809, 33798, 33748, 33759, 33807, 33795, {f: 2, c: 33784}, 33770, 33733, michael@0: 33728, 33830, 33776, 33761, 33884, 33873, 33882, 33881, 33907, michael@0: {f: 2, c: 33927}, 33914, 33929, 33912, 33852, 33862, 33897, 33910, 33932, michael@0: 33934, 33841, 33901, 33985, 33997, 34000, 34022, 33981, 34003, 33994, michael@0: 33983, 33978, 34016, 33953, 33977, 33972, 33943, 34021, 34019, 34060, michael@0: 29965, 34104, 34032, 34105, 34079, 34106, 34134, 34107, 34047, 34044, michael@0: 34137, 34120, 34152, 34148, 34142, 34170, 30626, 34115, 34162, 34171, michael@0: 34212, 34216, 34183, 34191, 34169, 34222, 34204, 34181, 34233, 34231, michael@0: 34224, 34259, 34241, 34268, 34303, 34343, 34309, 34345, 34326, 34364, michael@0: [12086, 24318], 24328, 22844, 22849, 32823, 22869, 22874, 22872, 21263, michael@0: [12074, 23586], 23589, 23596, 23604, 25164, 25194, 25247, 25275, 25290, michael@0: 25306, 25303, 25326, 25378, 25334, 25401, 25419, 25411, 25517, 25590, michael@0: 25457, 25466, 25486, 25524, 25453, 25516, 25482, 25449, 25518, 25532, michael@0: 25586, 25592, 25568, 25599, 25540, 25566, 25550, 25682, 25542, 25534, michael@0: 25669, 25665, 25611, 25627, 25632, 25612, 25638, 25633, 25694, 25732, michael@0: 25709, 25750, 25722, {f: 2, c: 25783}, 25753, 25786, 25792, 25808, 25815, michael@0: 25828, 25826, 25865, 25893, 25902, [12087, 24331], 24530, 29977, 24337, michael@0: 21343, 21489, 21501, 21481, 21480, 21499, 21522, 21526, 21510, 21579, michael@0: {f: 3, c: 21586}, 21590, 21571, 21537, 21591, 21593, 21539, 21554, 21634, michael@0: 21652, 21623, 21617, 21604, {f: 2, c: 21658}, 21636, 21622, 21606, 21661, michael@0: 21712, 21677, 21698, 21684, 21714, 21671, 21670, {f: 2, c: 21715}, 21618, michael@0: 21667, 21717, 21691, 21695, 21708, {f: 2, c: 21721}, 21724, michael@0: {f: 2, c: 21673}, 21668, 21725, 21711, 21726, 21787, 21735, 21792, 21757, michael@0: 21780, 21747, {f: 2, c: 21794}, 21775, 21777, 21799, 21802, 21863, 21903, michael@0: 21941, 21833, 21869, 21825, 21845, 21823, 21840, 21820, 21815, 21846, michael@0: {f: 3, c: 21877}, 21811, 21808, 21852, 21899, 21970, 21891, 21937, 21945, michael@0: 21896, 21889, 21919, 21886, 21974, 21905, 21883, 21983, {f: 2, c: 21949}, michael@0: 21908, 21913, 21994, 22007, 21961, 22047, 21969, {f: 2, c: 21995}, 21972, michael@0: 21990, 21981, 21956, 21999, 21989, {f: 2, c: 22002}, {f: 2, c: 21964}, michael@0: 21992, 22005, 21988, 36756, 22046, 22024, 22028, 22017, 22052, 22051, michael@0: 22014, 22016, 22055, 22061, 22104, 22073, 22103, 22060, 22093, 22114, michael@0: 22105, 22108, 22092, 22100, 22150, 22116, 22129, 22123, {f: 2, c: 22139}, michael@0: 22149, 22163, 22191, 22228, [12062, 22231], 22237, 22241, 22261, 22251, michael@0: 22265, 22271, 22276, 22282, 22281, 22300, 24079, 24089, 24084, 24081, michael@0: 24113, {f: 2, c: 24123}, 24119, 24132, 24148, 24155, 24158, 24161, 23692, michael@0: 23674, 23693, 23696, 23702, 23688, {f: 2, c: 23704}, 23697, 23706, 23708, michael@0: 23733, 23714, 23741, 23724, 23723, 23729, 23715, 23745, 23735, 23748, michael@0: 23762, 23780, 23755, 23781, {f: 2, c: 23810}, 23847, 23846, 23854, 23844, michael@0: 23838, 23814, 23835, 23896, 23870, 23860, 23869, 23916, 23899, 23919, michael@0: 23901, 23915, 23883, 23882, 23913, 23924, 23938, 23961, 23965, 35955, michael@0: 23991, 24005, [12091, 24435], 24439, 24450, 24455, 24457, 24460, 24469, michael@0: 24473, 24476, 24488, 24493, 24501, 24508, 34914, [12090, 24417], 29357, michael@0: 29360, 29364, {f: 2, c: 29367}, 29379, 29377, 29390, 29389, 29394, 29416, michael@0: 29423, 29417, 29426, 29428, 29431, 29441, 29427, 29443, {f: 2, c: 29434}, michael@0: 29463, 29459, 29473, 29450, 29470, 29469, 29461, 29474, 29497, 29477, michael@0: 29484, 29496, 29489, 29520, 29517, 29527, 29536, 29548, 29551, 29566, michael@0: [12167, 33307], 22821, 39143, 22820, [12065, 22786], 39267, michael@0: {f: 6, c: 39271}, 39284, 39287, 39293, 39296, 39300, 39303, 39306, 39309, michael@0: {f: 2, c: 39312}, {f: 3, c: 39315}, 24192, 24209, 24203, 24214, 24229, michael@0: 24224, 24249, 24245, 24254, 24243, 36179, 24274, 24273, 24283, 24296, michael@0: 24298, 33210, 24516, 24521, 24534, 24527, 24579, 24558, 24580, 24545, michael@0: 24548, 24574, {f: 2, c: 24581}, 24554, 24557, 24568, 24601, 24629, 24614, michael@0: 24603, 24591, 24589, 24617, 24619, 24586, 24639, 24609, {f: 2, c: 24696}, michael@0: 24699, 24698, 24642, 24682, 24701, 24726, 24730, 24749, 24733, 24707, michael@0: 24722, 24716, 24731, 24812, 24763, 24753, 24797, 24792, 24774, 24794, michael@0: 24756, 24864, 24870, 24853, 24867, 24820, 24832, 24846, 24875, 24906, michael@0: 24949, 25004, 24980, 24999, 25015, 25044, 25077, 24541, 38579, 38377, michael@0: 38379, 38385, 38387, {f: 2, c: 38389}, 38396, 38398, {f: 2, c: 38403}, michael@0: 38406, 38408, {f: 4, c: 38410}, 38415, 38418, {f: 3, c: 38421}, michael@0: {f: 2, c: 38425}, 20012, [12121, 29247], 25109, 27701, 27732, 27740, 27722, michael@0: 27811, 27781, 27792, 27796, 27788, {f: 2, c: 27752}, 27764, 27766, 27782, michael@0: 27817, 27856, 27860, 27821, {f: 2, c: 27895}, 27889, 27863, 27826, 27872, michael@0: 27862, 27898, 27883, 27886, 27825, 27859, 27887, 27902, 27961, 27943, michael@0: 27916, 27971, 27976, 27911, 27908, 27929, 27918, 27947, 27981, 27950, michael@0: 27957, 27930, 27983, 27986, 27988, 27955, 28049, 28015, 28062, 28064, michael@0: 27998, {f: 2, c: 28051}, 27996, 28000, 28028, 28003, 28186, 28103, 28101, michael@0: 28126, 28174, 28095, 28128, 28177, 28134, 28125, 28121, 28182, 28075, michael@0: 28172, 28078, 28203, 28270, 28238, 28267, 28338, 28255, 28294, michael@0: {f: 2, c: 28243}, 28210, 28197, 28228, 28383, 28337, 28312, 28384, 28461, michael@0: 28386, 28325, 28327, 28349, 28347, 28343, 28375, 28340, 28367, 28303, michael@0: 28354, 28319, 28514, {f: 2, c: 28486}, 28452, 28437, 28409, 28463, 28470, michael@0: 28491, 28532, 28458, 28425, 28457, 28553, 28557, 28556, 28536, 28530, michael@0: 28540, 28538, 28625, 28617, 28583, 28601, 28598, 28610, 28641, 28654, michael@0: 28638, 28640, 28655, 28698, 28707, 28699, 28729, 28725, 28751, 28766, michael@0: [12071, 23424], 23428, 23445, 23443, 23461, 23480, 29999, 39582, 25652, michael@0: 23524, 23534, 35120, 23536, 36423, 35591, 36790, 36819, 36821, 36837, michael@0: 36846, 36836, 36841, 36838, 36851, 36840, 36869, 36868, 36875, 36902, michael@0: 36881, 36877, 36886, 36897, {f: 2, c: 36917}, 36909, 36911, 36932, michael@0: {f: 2, c: 36945}, 36944, 36968, 36952, 36962, 36955, 26297, 36980, 36989, michael@0: 36994, 37000, 36995, 37003, [12089, 24400], 24407, 24406, 24408, 23611, michael@0: 21675, 23632, 23641, 23409, 23651, 23654, 32700, 24362, 24361, 24365, michael@0: 33396, 24380, 39739, [12076, 23662], 22913, 22915, 22925, {f: 2, c: 22953}, michael@0: 22947, 22935, 22986, 22955, 22942, 22948, 22994, 22962, 22959, 22999, michael@0: 22974, {f: 2, c: 23045}, 23005, 23048, 23011, 23000, 23033, 23052, 23049, michael@0: 23090, 23092, 23057, 23075, 23059, 23104, 23143, 23114, 23125, 23100, michael@0: 23138, 23157, 33004, 23210, 23195, 23159, 23162, 23230, 23275, 23218, michael@0: 23250, 23252, 23224, 23264, 23267, 23281, 23254, 23270, 23256, 23260, michael@0: 23305, 23319, 23318, 23346, 23351, 23360, 23573, 23580, 23386, 23397, michael@0: 23411, 23377, 23379, 23394, 39541, {f: 2, c: 39543}, 39546, 39551, 39549, michael@0: {f: 2, c: 39552}, 39557, 39560, 39562, 39568, {f: 2, c: 39570}, 39574, michael@0: 39576, {f: 3, c: 39579}, {f: 2, c: 39583}, {f: 2, c: 39586}, 39589, 39591, michael@0: 32415, 32417, 32419, 32421, {f: 2, c: 32424}, 32429, 32432, 32446, michael@0: {f: 3, c: 32448}, 32457, {f: 2, c: 32459}, 32464, 32468, 32471, 32475, michael@0: {f: 2, c: 32480}, 32488, 32491, {f: 2, c: 32494}, {f: 2, c: 32497}, 32525, michael@0: 32502, {f: 2, c: 32506}, 32510, {f: 3, c: 32513}, {f: 2, c: 32519}, michael@0: {f: 2, c: 32523}, 32527, {f: 2, c: 32529}, 32535, 32537, 32540, 32539, michael@0: 32543, {f: 7, c: 32545}, {f: 4, c: 32554}, {f: 5, c: 32559}, 32565, michael@0: [12083, 24186], 30079, [12078, 24027], 30014, 37013, 29582, 29585, 29614, michael@0: 29602, 29599, 29647, 29634, 29649, 29623, 29619, 29632, 29641, 29640, michael@0: 29669, 29657, 39036, 29706, 29673, 29671, 29662, 29626, 29682, 29711, michael@0: 29738, 29787, 29734, 29733, 29736, 29744, 29742, 29740, 29723, 29722, michael@0: 29761, 29788, 29783, 29781, 29785, 29815, 29805, 29822, 29852, 29838, michael@0: {f: 2, c: 29824}, 29831, 29835, 29854, {f: 2, c: 29864}, 29840, 29863, michael@0: 29906, 29882, {f: 3, c: 38890}, 26444, 26451, 26462, 26440, 26473, 26533, michael@0: 26503, 26474, 26483, 26520, 26535, 26485, 26536, 26526, 26541, 26507, michael@0: 26487, 26492, 26608, 26633, 26584, 26634, 26601, 26544, 26636, 26585, michael@0: 26549, 26586, 26547, 26589, 26624, 26563, 26552, 26594, 26638, 26561, michael@0: 26621, {f: 2, c: 26674}, {f: 2, c: 26720}, 26702, 26722, 26692, 26724, michael@0: 26755, 26653, 26709, 26726, 26689, 26727, 26688, 26686, 26698, 26697, michael@0: 26665, 26805, 26767, 26740, 26743, 26771, 26731, 26818, 26990, 26876, michael@0: {f: 2, c: 26911}, 26873, 26916, 26864, 26891, 26881, 26967, 26851, 26896, michael@0: 26993, 26937, 26976, 26946, 26973, 27012, 26987, 27008, 27032, 27000, michael@0: 26932, 27084, {f: 2, c: 27015}, 27086, 27017, 26982, 26979, 27001, 27035, michael@0: 27047, 27067, 27051, 27053, 27092, 27057, 27073, 27082, 27103, 27029, michael@0: 27104, 27021, 27135, 27183, 27117, {f: 2, c: 27159}, 27237, 27122, 27204, michael@0: 27198, 27296, 27216, 27227, 27189, 27278, 27257, 27197, 27176, 27224, michael@0: 27260, 27281, 27280, 27305, 27287, 27307, 29495, 29522, {f: 2, c: 27521}, michael@0: 27527, 27524, {f: 2, c: 27538}, 27533, {f: 2, c: 27546}, 27553, 27562, michael@0: 36715, 36717, {f: 3, c: 36721}, {f: 2, c: 36725}, 36728, 36727, michael@0: {f: 2, c: 36729}, 36732, 36734, {f: 2, c: 36737}, 36740, 36743, 36747, michael@0: {f: 3, c: 36749}, 36760, 36762, 36558, 25099, 25111, 25115, 25119, 25122, michael@0: 25121, 25125, 25124, 25132, 33255, 29935, 29940, 29951, 29967, 29969, michael@0: 29971, [12097, 25908], {f: 3, c: 26094}, 26122, 26137, 26482, 26115, 26133, michael@0: 26112, 28805, 26359, 26141, 26164, 26161, 26166, 26165, 32774, 26207, michael@0: 26196, 26177, 26191, 26198, 26209, 26199, 26231, 26244, 26252, 26279, michael@0: 26269, 26302, {f: 2, c: 26331}, 26342, 26345, {f: 2, c: 36146}, 36150, michael@0: 36155, 36157, 36160, {f: 2, c: 36165}, {f: 2, c: 36168}, 36167, 36173, michael@0: 36181, 36185, 35271, {f: 3, c: 35274}, {f: 4, c: 35278}, 29294, 29343, michael@0: 29277, 29286, 29295, {f: 2, c: 29310}, 29316, 29323, 29325, 29327, 29330, michael@0: 25352, 25394, 25520, 25663, 25816, 32772, 27626, 27635, 27645, 27637, michael@0: 27641, 27653, 27655, 27654, 27661, 27669, {f: 3, c: 27672}, 27681, 27689, michael@0: 27684, 27690, 27698, 25909, 25941, 25963, 29261, 29266, 29270, 29232, michael@0: 34402, 21014, 32927, 32924, 32915, 32956, 26378, 32957, 32945, 32939, michael@0: 32941, 32948, 32951, {f: 4, c: 32999}, 32987, 32962, 32964, 32985, 32973, michael@0: 32983, 26384, 32989, 33003, 33009, 33012, 33005, {f: 2, c: 33037}, 33010, michael@0: 33020, 26389, 33042, 35930, 33078, 33054, 33068, 33048, 33074, 33096, michael@0: 33100, 33107, 33140, {f: 2, c: 33113}, 33137, 33120, 33129, michael@0: {f: 2, c: 33148}, 33133, 33127, 22605, 23221, 33160, 33154, 33169, 28373, michael@0: 33187, 33194, 33228, 26406, 33226, 33211, 33217, 33190, 27428, 27447, michael@0: 27449, 27459, 27462, 27481, {f: 3, c: 39121}, 39125, {f: 2, c: 39129}, michael@0: [12110, 27571], 24384, 27586, 35315, 26000, 40785, 26003, 26044, 26054, michael@0: 26052, 26051, 26060, 26062, 26066, 26070, 28800, 28828, 28822, 28829, michael@0: 28859, 28864, 28855, 28843, 28849, 28904, 28874, 28944, 28947, 28950, michael@0: 28975, 28977, 29043, 29020, 29032, 28997, 29042, 29002, 29048, 29050, michael@0: 29080, 29107, 29109, 29096, 29088, 29152, 29140, 29159, 29177, 29213, michael@0: 29224, 28780, 28952, 29030, 29113, 25150, 25149, 25155, {f: 2, c: 25160}, michael@0: 31035, 31040, 31046, 31049, {f: 2, c: 31067}, 31059, 31066, 31074, 31063, michael@0: 31072, 31087, 31079, 31098, 31109, 31114, 31130, 31143, 31155, 24529, michael@0: 24528, 24636, 24669, 24666, 24679, 24641, 24665, 24675, 24747, 24838, michael@0: 24845, 24925, 25001, 24989, 25035, 25041, 25094, 32896, [12160, 32895], michael@0: 27795, 27894, 28156, 30710, 30712, 30720, 30729, {f: 2, c: 30743}, 30737, michael@0: 26027, 30765, {f: 2, c: 30748}, {f: 3, c: 30777}, 30751, 30780, 30757, michael@0: 30764, 30755, 30761, 30798, 30829, {f: 2, c: 30806}, 30758, 30800, 30791, michael@0: 30796, 30826, 30875, 30867, 30874, 30855, 30876, 30881, 30883, 30898, michael@0: 30905, 30885, 30932, 30937, 30921, 30956, 30962, 30981, 30964, 30995, michael@0: 31012, 31006, 31028, 40859, [12235, 40697], {f: 2, c: 40699}, 30449, 30468, michael@0: 30477, 30457, {f: 2, c: 30471}, 30490, 30498, 30489, 30509, 30502, 30517, michael@0: 30520, {f: 2, c: 30544}, 30535, 30531, 30554, 30568, 30562, 30565, 30591, michael@0: 30605, 30589, 30592, 30604, 30609, {f: 2, c: 30623}, 30640, 30645, 30653, michael@0: 30010, 30016, 30030, 30027, 30024, 30043, 30066, 30073, 30083, 32600, michael@0: 32609, 32607, 35400, 32616, 32628, 32625, 32633, 32641, 32638, 30413, michael@0: 30437, 34866, {f: 3, c: 38021}, 38027, 38026, {f: 2, c: 38028}, michael@0: {f: 2, c: 38031}, 38036, 38039, 38037, {f: 3, c: 38042}, {f: 2, c: 38051}, michael@0: 38059, 38058, 38061, 38060, {f: 2, c: 38063}, 38066, 38068, michael@0: {f: 5, c: 38070}, {f: 2, c: 38076}, 38079, 38084, {f: 7, c: 38088}, michael@0: {f: 3, c: 38096}, {f: 3, c: 38101}, 38105, 38104, 38107, {f: 3, c: 38110}, michael@0: 38114, {f: 2, c: 38116}, {f: 2, c: 38119}, 38122, 38121, 38123, michael@0: {f: 2, c: 38126}, {f: 3, c: 38131}, 38135, 38137, {f: 2, c: 38140}, 38143, michael@0: 38147, 38146, {f: 2, c: 38150}, {f: 2, c: 38153}, {f: 3, c: 38157}, michael@0: {f: 5, c: 38162}, 38168, 38171, {f: 3, c: 38173}, 38178, {f: 2, c: 38186}, michael@0: 38185, 38188, {f: 2, c: 38193}, 38196, {f: 3, c: 38198}, 38204, michael@0: {f: 2, c: 38206}, 38210, 38197, {f: 3, c: 38212}, 38217, 38220, michael@0: {f: 2, c: 38222}, {f: 3, c: 38226}, {f: 4, c: 38230}, 38235, michael@0: {f: 2, c: 38238}, 38237, {f: 2, c: 38241}, {f: 9, c: 38244}, 38255, michael@0: {f: 3, c: 38257}, 38202, 30695, 30700, 38601, 31189, 31213, 31203, 31211, michael@0: 31238, 23879, 31235, 31234, 31262, 31252, 31289, 31287, 31313, 40655, michael@0: 39333, 31344, 30344, 30350, 30355, 30361, 30372, 29918, 29920, 29996, michael@0: 40480, 40482, {f: 5, c: 40488}, 40498, 40497, 40502, 40504, 40503, michael@0: {f: 2, c: 40505}, 40510, {f: 2, c: 40513}, 40516, {f: 4, c: 40518}, michael@0: {f: 2, c: 40523}, 40526, 40529, 40533, 40535, {f: 3, c: 40538}, 40542, michael@0: 40547, {f: 7, c: 40550}, 40561, 40557, 40563, [12135, 30098], 30100, 30102, michael@0: 30112, 30109, 30124, 30115, {f: 2, c: 30131}, 30136, 30148, 30129, 30128, michael@0: 30147, 30146, 30166, 30157, 30179, 30184, 30182, 30180, 30187, 30183, michael@0: 30211, 30193, 30204, 30207, 30224, 30208, 30213, 30220, 30231, 30218, michael@0: 30245, 30232, 30229, 30233, 30235, 30268, 30242, 30240, 30272, 30253, michael@0: 30256, 30271, 30261, 30275, 30270, 30259, 30285, 30302, 30292, 30300, michael@0: 30294, 30315, 30319, 32714, 31462, {f: 2, c: 31352}, 31360, 31366, 31368, michael@0: 31381, 31398, 31392, 31404, 31400, 31405, 31411, 34916, 34921, 34930, michael@0: 34941, 34943, 34946, 34978, 35014, 34999, 35004, 35017, 35042, 35022, michael@0: 35043, 35045, 35057, 35098, 35068, 35048, 35070, 35056, 35105, 35097, michael@0: 35091, 35099, 35082, 35124, 35115, 35126, 35137, 35174, 35195, michael@0: [12134, 30091], 32997, 30386, 30388, 30684, [12158, 32786], 32788, 32790, michael@0: 32796, 32800, 32802, {f: 3, c: 32805}, 32809, 32808, 32817, 32779, 32821, michael@0: 32835, 32838, 32845, 32850, 32873, 32881, 35203, 39032, 39040, 39043, michael@0: 39049, {f: 2, c: 39052}, 39055, 39060, {f: 2, c: 39066}, {f: 2, c: 39070}, michael@0: {f: 2, c: 39073}, {f: 2, c: 39077}, [12172, 34381], 34388, 34412, 34414, michael@0: 34431, 34426, 34428, 34427, 34472, 34445, 34443, 34476, 34461, 34471, michael@0: 34467, 34474, 34451, 34473, 34486, 34500, 34485, 34510, 34480, 34490, michael@0: 34481, 34479, 34505, 34511, 34484, 34537, {f: 2, c: 34545}, 34541, 34547, michael@0: 34512, 34579, 34526, 34548, 34527, 34520, 34513, 34563, 34567, 34552, michael@0: 34568, 34570, 34573, 34569, 34595, 34619, 34590, 34597, 34606, 34586, michael@0: 34622, 34632, 34612, 34609, 34601, 34615, 34623, 34690, 34594, michael@0: {f: 2, c: 34685}, 34683, 34656, 34672, 34636, 34670, 34699, 34643, 34659, michael@0: 34684, 34660, 34649, 34661, 34707, 34735, 34728, 34770, 34758, 34696, michael@0: 34693, 34733, 34711, 34691, 34731, 34789, 34732, 34741, 34739, 34763, michael@0: 34771, 34749, 34769, 34752, 34762, 34779, 34794, 34784, 34798, 34838, michael@0: 34835, 34814, 34826, 34843, 34849, 34873, 34876, [12152, 32566], 32578, michael@0: {f: 2, c: 32580}, 33296, 31482, 31485, 31496, {f: 2, c: 31491}, 31509, michael@0: 31498, 31531, 31503, 31559, 31544, 31530, 31513, 31534, 31537, 31520, michael@0: 31525, 31524, 31539, 31550, 31518, 31576, 31578, 31557, 31605, 31564, michael@0: 31581, 31584, 31598, 31611, 31586, 31602, 31601, 31632, {f: 2, c: 31654}, michael@0: 31672, 31660, 31645, 31656, 31621, 31658, 31644, 31650, 31659, 31668, michael@0: 31697, 31681, 31692, 31709, 31706, {f: 2, c: 31717}, 31722, 31756, 31742, michael@0: 31740, 31759, 31766, 31755, 31775, 31786, 31782, 31800, 31809, 31808, michael@0: 33278, {f: 2, c: 33281}, 33284, 33260, 34884, {f: 3, c: 33313}, 33325, michael@0: 33327, 33320, 33323, 33336, 33339, {f: 2, c: 33331}, 33342, 33348, 33353, michael@0: 33355, 33359, 33370, 33375, 33384, 34942, 34949, 34952, 35032, 35039, michael@0: 35166, 32669, 32671, 32679, {f: 2, c: 32687}, 32690, 31868, 25929, 31889, michael@0: 31901, 31900, 31902, 31906, 31922, {f: 2, c: 31932}, 31937, 31943, michael@0: {f: 2, c: 31948}, 31944, 31941, 31959, 31976, [12169, 33390], 26280, 32703, michael@0: 32718, 32725, 32741, 32737, 32742, 32745, 32750, 32755, [12151, 31992], michael@0: 32119, 32166, 32174, 32327, 32411, 40632, 40628, 36211, 36228, 36244, michael@0: 36241, 36273, 36199, 36205, 35911, 35913, 37194, 37200, {f: 2, c: 37198}, michael@0: 37220, 37218, 37217, 37232, 37225, 37231, {f: 2, c: 37245}, 37234, 37236, michael@0: 37241, 37260, 37253, 37264, 37261, 37265, {f: 2, c: 37282}, 37290, michael@0: {f: 3, c: 37293}, 37301, 37300, 37306, [12183, 35925], 40574, 36280, 36331, michael@0: 36357, 36441, 36457, 36277, 36287, 36284, 36282, 36292, {f: 2, c: 36310}, michael@0: 36314, 36318, {f: 2, c: 36302}, 36315, 36294, 36332, {f: 2, c: 36343}, michael@0: 36323, 36345, 36347, 36324, 36361, 36349, 36372, 36381, 36383, 36396, michael@0: 36398, 36387, 36399, 36410, 36416, 36409, 36405, 36413, 36401, 36425, michael@0: {f: 2, c: 36417}, {f: 2, c: 36433}, 36426, 36464, 36470, 36476, 36463, michael@0: 36468, 36485, 36495, 36500, 36496, 36508, 36510, [12184, 35960], 35970, michael@0: 35978, 35973, 35992, 35988, 26011, 35286, 35294, 35290, 35292, 35301, michael@0: 35307, 35311, 35390, 35622, 38739, 38633, 38643, 38639, 38662, 38657, michael@0: 38664, 38671, 38670, 38698, 38701, 38704, 38718, 40832, 40835, michael@0: {f: 6, c: 40837}, 40844, 40702, 40715, 40717, [12203, 38585], michael@0: {f: 2, c: 38588}, 38606, 38610, 30655, 38624, 37518, 37550, 37576, 37694, michael@0: 37738, 37834, 37775, 37950, 37995, 40063, 40066, {f: 4, c: 40069}, 31267, michael@0: 40075, 40078, {f: 3, c: 40080}, {f: 2, c: 40084}, {f: 2, c: 40090}, michael@0: {f: 6, c: 40094}, {f: 5, c: 40101}, 40107, {f: 2, c: 40109}, michael@0: {f: 8, c: 40112}, {f: 4, c: 40122}, {f: 4, c: 40132}, {f: 7, c: 40138}, michael@0: {f: 3, c: 40147}, {f: 3, c: 40151}, {f: 2, c: 40156}, 40159, 40162, 38780, michael@0: 38789, {f: 2, c: 38801}, 38804, 38831, 38827, 38819, 38834, 38836, 39601, michael@0: 39600, 39607, 40536, 39606, 39610, 39612, 39617, 39616, 39621, 39618, michael@0: {f: 2, c: 39627}, 39633, 39749, 39747, 39751, 39753, 39752, 39757, 39761, michael@0: 39144, 39181, 39214, 39253, 39252, [12221, 39647], 39649, 39654, 39663, michael@0: 39659, 39675, 39661, 39673, 39688, 39695, 39699, 39711, 39715, michael@0: {f: 2, c: 40637}, 32315, 40578, {f: 2, c: 40583}, 40587, 40594, 37846, michael@0: 40605, 40607, {f: 3, c: 40667}, 40672, 40671, 40674, 40681, 40679, 40677, michael@0: 40682, 40687, 40738, 40748, 40751, 40761, 40759, {f: 2, c: 40765}, 40772, michael@0: 12295, {s: 13}, 30362, 34297, 31001, 24859, 39599, 35158, 22761, 32631, michael@0: 25850, 25943, 38930, 36774, 32070, 24171, 32129, 37770, 35607, 39165, michael@0: 23542, 22577, 39825, 36649, [12185, 35997], 37575, 29437, 20633, 24970, michael@0: 32179, 31558, 30050, 25987, 24163, 38281, 37002, 32232, 36022, 35722, michael@0: 36783, 36782, 27161, 40009, 30303, 28693, 28657, 36051, 25839, 39173, michael@0: 25765, 37474, 37457, 39361, 35036, 36001, 21443, 34870, 27544, 24922, michael@0: 24920, 29158, 33980, 33369, 20489, 28356, 21408, 20596, 28204, 23652, michael@0: 35435, 25881, 25723, 34796, 39262, 35730, 32399, 37855, 29987, 38369, michael@0: 39019, 22580, 22039, [12199, 38263], 20767, 33144, 24288, 26274, 37396, michael@0: [12190, 36554], 24505, 22645, 38515, 35183, 31281, 25074, 35488, 39425, michael@0: 36978, 39347, [12242, 40786], 29118, 34909, 34802, 23541, 30087, 36490, michael@0: 31820, 32162, 37276, 37604, 38619, 30990, 20786, 35320, 34389, 20659, michael@0: 30241, 38358, 21109, 37656, 32020, 32189, 36781, 35422, 36060, 32880, michael@0: 24478, 21474, 36517, 31428, 37679, 36948, 24118, 36024, 25812, 21934, michael@0: 37170, 25763, 33213, 24986, 35477, 24392, 30070, 25803, 40680, 34153, michael@0: 27284, 25623, 23798, 31153, 23566, 29128, 37159, 25973, 28364, 36958, michael@0: 32224, 39003, 40670, 22666, 38651, 28593, 37347, 35519, 35548, 37336, michael@0: 38914, 37664, 35330, 26481, 21205, 26847, 20941, [12222, 39717], 29346, michael@0: 29544, 35712, 36077, 37709, 37723, 26039, 32222, 38538, 23565, 22136, michael@0: 38931, 37389, 22890, 22702, 40285, 38989, 35355, 24801, 39187, 20818, michael@0: 29246, 39180, 36019, 30332, 32624, 38309, 31020, 37353, 29033, 31684, michael@0: 36009, 39151, 35370, 32033, [12214, 39131], 35513, 24290, 36027, 32027, michael@0: 22707, 22894, 24996, 31966, 35920, 26963, 37586, [12213, 39080], 30219, michael@0: 39342, 32299, 35575, 40179, 33178, 36667, 25771, 36628, 36070, 24489, michael@0: 36000, 35331, 23142, 32283, 35442, 37411, 33995, 24185, 36245, 36123, michael@0: 23713, 21083, 37628, 32177, 23831, 37804, 25841, 40255, 38307, 37499, michael@0: 20491, 32102, 40852, 38799, 36002, 37390, 28317, 27083, 36092, 34865, michael@0: 39015, 21102, 38364, 35264, 39208, 24931, 36011, 24291, 35215, 27512, michael@0: [12244, 40860], 38312, 36556, 35437, 27331, 36020, 21130, 36645, 37707, michael@0: 22283, 36942, 39405, 38867, 28450, 34399, 38305, 40372, 36032, 36703, michael@0: 40251, 32005, 22778, 35703, 28396, 22057, 33775, 30059, 21123, 35441, michael@0: 25079, 22750, 27489, 29872, 36996, 32233, 35594, 25582, 36637, 36036, michael@0: 31330, 26371, 29172, 21295, 35569, 35496, 32362, 33911, 28222, 29554, michael@0: 36008, 31117, 25802, 27231, 31309, 39249, 35663, 40388, 32318, 32221, michael@0: 26997, 36655, 32026, 25824, 24190, 34186, 21137, 28639, 35336, 35352, michael@0: 38555, 32380, 32000, 22846, 33698, 38960, 36040, 37440, 20729, 39381, michael@0: 27570, 30435, 22533, 31627, 38291, 33393, 32216, 32365, 27298, 40572, michael@0: 25536, 25791, 31777, 20745, 34214, 27323, 37970, 36368, 36068, michael@0: [12178, 35211], 37749, 33382, 21133, 39198, 28472, 28666, 28567, 23559, michael@0: 28479, 34083, 27123, 22892, 35611, 37292, 33184, 28550, 39509, 23308, michael@0: 25898, 37496, 30703, 20709, 39171, 32371, 32094, 36686, 36611, 38542, michael@0: 31680, 28500, 32080, 35489, 32202, 37670, 20677, 35641, 36914, 29180, michael@0: 30433, 21185, 33686, 39912, 39514, 32147, 38968, 37857, 24465, 30169, michael@0: 31478, 31998, 33290, 39378, 33289, 25818, 37624, 25084, 21127, 40273, michael@0: 32121, 35258, 35363, 32118, 37406, 36557, 39423, 38283, 20977, 38982, michael@0: 27579, 35506, 22718, 25031, 25715, 24235, 35122, 35463, 22602, 20744, michael@0: 23532, 31014, 26336, 34407, 24011, 31418, 39243, 28528, 25844, 38346, michael@0: 34847, 33240, 33802, 20358, 36084, 34253, 27396, 25876, 31811, 38348, michael@0: 34349, 28734, 35733, 25900, 35261, 25078, 32412, 29211, 28651, 25736, michael@0: 21214, 28551, 27138, 37939, 22744, 39006, 31852, 38626, 28757, 35023, michael@0: 39881, 31150, 40599, 21426, 21237, 31019, 27511, 28701, 38584, 20486, michael@0: 32879, 34030, 36899, 37934, 24976, 28451, 31806, 25986, 33225, 37832, michael@0: 25088, 29001, 32244, 31975, 20841, 36635, 35538, 30274, 36988, 37904, michael@0: 29557, 33256, 37168, 40023, 36035, 40801, 37428, 38728, 23994, 38936, michael@0: 39230, 21129, [12243, 40845], 32894, 22184, 31840, 22751, 25871, 38580, michael@0: 27155, 23105, 25695, 31757, 34310, 30439, 39025, 24300, 29200, 25796, michael@0: 28407, 34396, 39791, 36034, 37682, 38520, 39522, 37569, 23650, 32311, michael@0: 24942, 28670, 32209, 24018, 25891, 23423, 28772, 20098, 25476, 36650, michael@0: 20523, 20374, 28138, 32184, 35542, 34367, 32645, 37007, 38012, 31854, michael@0: 39486, 39409, 32097, 23229, 29802, 30908, 34718, [12218, 39340], 39393, michael@0: 21966, 36023, [12230, 40613], 36067, 36993, 30622, 39237, 34875, 28415, michael@0: 35646, 37672, 37466, 36031, 37762, [12200, 38272], 24758, 20497, 37683, michael@0: 22818, 35598, 24396, 35219, 32191, 32236, 24287, 28357, 25003, 38313, michael@0: 40180, 37528, 35628, 35584, 30045, 37385, 32013, 38627, 25747, 33126, michael@0: 24817, 39719, 39186, 25836, 33193, 25862, 37312, [12227, 40165], 32886, michael@0: 22169, 38007, 37811, 27320, 29552, 23527, 25840, 28632, 37397, 32016, michael@0: 33215, 28611, 36786, 30247, 35582, 27472, 40407, 27590, 22036, 28442, michael@0: 30436, 40848, 36064, 22132, 40300, 39449, 39108, 38971, 36007, 34315, michael@0: 24977, 35413, 28497, 38935, 25778, 37610, 20693, 27192, 35676, 33229, michael@0: [12241, 40778], 39438, 35912, 21843, 27683, 35350, 29309, 37370, 37467, michael@0: 36983, 31805, 35609, 37666, 37463, 28154, 35700, 22649, 27085, 21958, michael@0: 22715, 34196, 25654, 37740, 27211, 21932, 20689, 32761, 31429, 31434, michael@0: 27453, 35242, 23522, 36629, 27691, 20670, 38915, 35531, 24950, 29898, michael@0: 31406, 36264, 21312, 36544, 39493, 40818, 39028, 27402, 21240, 40306, michael@0: 30906, 35731, 39250, 25854, 32350, 29105, 38860, 35469, 32009, 27054, michael@0: 32104, 36575, 37613, 38287, 28516, 28753, 34217, 39955, 36093, 20632, michael@0: 21930, 39479, 25475, 28544, 27578, 32023, 31721, 26348, 38275, 38493, michael@0: 36109, 32341, 20663, 36062, 29138, 32057, 36050, 25448, 25885, 25086, michael@0: 35373, 32051, 23529, 23352, 33102, 28402, 32882, 32361, 21213, 32854, michael@0: 24107, 29509, 28629, 35433, 26178, 34645, 23526, 35672, 39387, 21218, michael@0: 36969, 37323, 39166, 35222, 35430, 22781, 29560, 27166, 36664, 26360, michael@0: 36118, 23660, 34899, 27193, 31466, 25976, 24101, 38617, 35504, 38918, michael@0: 35500, 30889, 29197, 32114, 39164, 39686, 32883, 24939, 38924, 35359, michael@0: 35494, 25851, 34311, 35380, 32901, 38614, 38568, 32143, 27506, 23403, michael@0: 25613, 32302, 29795, 37782, 29562, 25787, 33274, 24907, 25892, 36010, michael@0: 30321, 28760, 22727, 35674, 35527, 22022, 28271, 29145, 28644, 32295, michael@0: 35342, 39472, 35588, 37563, 38988, 39636, 26781, 36028, 37941, 24307, michael@0: 32893, 28916, 37509, 32113, 38957, 22294, 22615, 22296, 38973, 40213, michael@0: 39345, 39389, 27234, 31402, 35178, 24398, 28771, 38929, 33836, 32178, michael@0: [12209, 38859], 36949, 22285, 29234, 28656, 32173, 33894, 20553, 20702, michael@0: 32239, 35586, 34907, 32862, 32011, 31337, 21839, 25790, 34680, 28198, michael@0: 31401, 21978, 37794, 28879, 35491, 28961, 34154, 22626, 38695, 21209, michael@0: 35492, 37675, 29351, 35186, 32722, 37521, 25138, 32048, 34662, 36676, michael@0: 23805, 20448, 29433, 22151, 37697, 39854, 32406, 36066, 37532, 38289, michael@0: 39023, 38570, 29694, 29563, 32291, 39201, 25010, 32171, 38002, 37129, michael@0: 35443, 38911, 38917, 34157, 22210, 37559, 26313, 22063, 21332, 25406, michael@0: 33029, 35559, 23531, 28681, 35613, 37573, 37313, 33288, 37561, 32137, michael@0: 38920, 35377, 32210, 32396, 36562, 25080, 36984, 30316, 32098, 23416, michael@0: 21211, 35426, 23563, 39348, 35347, 35338, 36956, 22739, 40201, 40232, michael@0: 21854, 20126, 35357, 38329, 40573, 22196, 38996, 38331, 33399, 21421, michael@0: 30831, 35578, 39511, 40230, 26954, 25562, 30221, 38525, 30306, 39178, michael@0: 27171, 22575, 35617, 34277, 29242, [12212, 38913], 26989, 33865, 37291, michael@0: 37541, 38948, 36986, 20736, 34811, 34269, 20740, 25014, 32681, 35427, michael@0: 35696, 35516, 35695, 32377, 34093, 38512, 37504, 39154, 38577, 27387, michael@0: 23344, 40441, 25033, 32403, 29801, 34722, 29151, 29074, 34821, 36111, michael@0: 31310, 21938, 25793, 20653, 30320, 36404, 20778, 24962, 37109, 37438, michael@0: 29494, 35480, 36671, 39192, [12226, 39770], 28417, 33287, 23996, 35486, michael@0: 39729, 29508, 35709, 38928, 39341, 40219, 28149, 36677, 22290, 21729, michael@0: 22291, 32227, 36960, 39000, 32004, 36493, 38000, 38322, 38642, 37142, michael@0: 38549, 36939, 34292, 37270, 26248, 38620, 36617, 25890, 26283, 36106, michael@0: 36124, 33247, 38015, 26839, 31432, 36012, 25799, 21063, 28580, 36042, michael@0: 36104, 36555, 37720, 38296, 35408, 40779, 20661, 27656, 30430, 26028, michael@0: 36670, 23940, 26855, 25136, 32187, 24373, 28466, 24115, 36076, 33081, michael@0: 36249, 34756, 36685, 37754, 36889, 35998, 37341, 20597, 35386, 37806, michael@0: 38499, 24128, 30309, 37165, 35657, 32340, 32887, 22519, 34937, 32025, michael@0: 25711, 25842, 24159, 36074, 28399, 37912, 32066, 31278, 33131, 34886, michael@0: 35589, 36600, 30394, 26205, 39519, 35576, 35461, 29165, 30682, 22225, michael@0: 36015, 37956, 31689, 39376, 23560, 30938, 36681, 36090, 27137, 33674, michael@0: 35037, 22941, 22767, 29376, 37648, 36101, 22684, 32180, 35524, 28310, michael@0: 28609, 36039, 28460, 32156, 32317, 32305, 37138, 35419, 32068, 38013, michael@0: 21959, 21401, 21428, 38760, 36107, 21293, 21297, 36094, 21060, 21132, michael@0: 21108, 20660, 20480, 20630, 20757, 20738, 20756, 20796, 20791, 20712, michael@0: 20674, 20795, 20752, 20794, 20681, 31988, 40652, 22213, 40172, 35131, michael@0: 33248, 35329, 35344, 35340, 35349, 35635, 35406, 35365, 35393, 35382, michael@0: 35398, 35412, 35416, 35410, 35462, 35460, 35455, 35440, 35452, 35445, michael@0: 35436, 35438, 35533, 35554, 35425, 35482, 35493, {f: 2, c: 35473}, 35535, michael@0: 35537, 35529, 35547, 35543, 35522, 35510, 35574, 35563, 35604, 35585, michael@0: 35556, 35565, 35580, 35571, 35558, 35566, 35550, 35624, 35740, 35606, michael@0: 35610, 35600, 35627, 35629, 35670, 35673, 35662, 35742, 35691, 35734, michael@0: 38488, 37178, 37140, 37172, 37087, 37174, 37126, 37192, 33467, 21233, michael@0: 24048, 22538, 22745, 22754, 22752, 22746, 22497, 22607, 22550, 22610, michael@0: 22557, 22628, 34188, 34131, 34294, 33703, 33799, 34031, 33511, 34338, michael@0: 34086, 22603, 29026, 34136, 34045, 34126, 34184, 34234, 29334, 28366, michael@0: 34113, 34254, 34130, 33984, 33874, 33892, 33940, 33845, 34207, 34133, michael@0: 40367, 33939, 32264, 34118, 34146, 34078, 39488, 34362, 37795, 34167, michael@0: 34334, 34298, 34308, 34282, 34330, 22889, 23607, 25451, 25718, 25759, michael@0: 25681, 25692, 25779, 25860, 25878, 25847, 25852, 25883, 22064, 22072, michael@0: 22216, 22182, 21764, 21692, 22144, 22109, 22112, 22069, 22006, 22118, michael@0: 22130, 22156, 22117, 22044, 22062, 21993, 22038, 22208, 22029, 22195, michael@0: 22209, 22127, 36705, 22198, 22165, 22279, 24131, 24172, 24152, 24151, michael@0: 23943, 23796, 23888, 23852, 23975, 23968, 23959, 23821, 23992, 23937, michael@0: 24020, 24480, 29559, 29505, 29546, 29499, 29547, 29568, 29564, 39136, michael@0: 39219, 39145, 39228, {f: 2, c: 39146}, 39149, 39156, 39177, 39185, 39195, michael@0: 39223, 39231, 39235, {f: 3, c: 39240}, 39244, 39266, 24289, 36065, 25082, michael@0: 25006, 24938, 24894, 24757, 24884, 25036, 24927, 25064, 24827, 24887, michael@0: 24818, 24947, 24860, 24978, 38274, 38278, 38344, 38286, 38292, 38284, michael@0: 38373, 38317, 38315, 39726, 38316, 38334, 38326, 39721, 38335, 38333, michael@0: 38332, 38339, 38347, 38356, 38352, 38357, 38366, 28739, 28505, 28711, michael@0: 28696, 28668, 28039, 28025, 28254, 28590, 28687, 28408, 28527, 28150, michael@0: 28543, 28678, 28576, 28683, 28775, 28740, 28677, 28535, 28704, 28703, michael@0: 28722, 28712, 28765, 39467, 36999, 36885, 37008, 23656, 24371, 23285, michael@0: 23255, 23296, 23149, 23304, 23372, 23207, 23291, 23307, 23329, 23338, michael@0: 23321, 39380, 39391, 39385, 39478, 39515, 39377, 39384, 39501, 39498, michael@0: 39394, 39530, 39439, 39437, 39429, 39490, 39469, 39446, 39489, 39470, michael@0: 39480, {f: 2, c: 39491}, 39503, 39525, 39524, 31993, 32006, 32002, michael@0: {f: 2, c: 32007}, 32394, 32028, 32021, 32019, 32058, 32050, 32049, 32272, michael@0: 32060, 32064, 32063, 32093, 32078, 32115, 32134, 32131, 32136, 32190, michael@0: 32186, 32203, 32212, 32196, 32158, 32172, 32185, 32163, 32176, 32199, michael@0: 32217, 32215, 32249, 32242, 32354, 32230, 32246, 32241, 32267, 32225, michael@0: 32265, 32285, 32287, 32286, 32301, 32266, 32273, 32381, 32313, 32309, michael@0: 32306, 32326, 32325, 32392, 32346, 32338, 32366, 32382, 32368, 32367, michael@0: 32408, 29859, 29771, 29903, 38922, 29885, 29759, 29833, 29862, 29908, michael@0: 29914, 38873, 38878, 38876, 27050, 27370, 26776, 26838, 27141, 26783, michael@0: 27355, 27379, 27368, 27359, 27273, 26895, 27208, 26984, 27071, 27194, michael@0: 27292, 27410, 27422, 27357, 27111, 27407, 27414, 27372, 27354, 27384, michael@0: 27315, 27367, 27299, 27347, 27358, 27556, 27550, 27566, 27563, 27567, michael@0: 36564, 36571, 36594, 36603, 36708, 36601, 36604, 36587, 36580, 36706, michael@0: 36602, 36606, 36618, 36615, 36613, 36626, 36646, {f: 2, c: 36638}, 36636, michael@0: 36659, 36678, 36692, 25108, 25127, 29964, 26311, 26308, 26249, 26326, michael@0: 36033, 36016, 36026, 36029, 36100, 36018, 36037, 36112, 36049, 36058, michael@0: 36053, 36075, 36071, 36091, 35224, 35244, 35233, 35263, 35238, 35247, michael@0: 35250, 35255, 27647, 27660, 27692, 29272, 26407, 33110, 33242, 33051, michael@0: 33214, 33121, 33231, 27487, {f: 2, c: 39086}, 39094, 39100, 39110, 39112, michael@0: 36674, 40783, 26005, 29036, 29010, 29079, 29121, 29148, 29182, 31152, michael@0: 31118, 31146, 25055, 24932, 25059, 25095, 28585, 30959, 30893, 30824, michael@0: 30904, 31018, 31025, 30820, 30973, 30951, 30947, 40853, 30616, 30558, michael@0: 30652, 32646, 32648, {f: 3, c: 37330}, 37337, 37335, 37333, 37367, 37351, michael@0: 37348, 37702, 37365, 37369, 37384, 37414, 37445, 37393, 37392, 37377, michael@0: 37415, 37380, 37413, 37376, 37434, 37478, 37431, 37427, 37461, 37437, michael@0: 37432, 37470, {f: 2, c: 37484}, 37439, 37984, 37424, 37449, 37448, 37453, michael@0: 37422, 37433, 37944, 37548, 37536, 37498, 37546, 37614, 37583, 37891, michael@0: 37603, 37946, 37553, 37542, 37799, 37526, 37580, 37545, 37877, 37523, michael@0: 37503, 37801, 37530, 37658, 37547, 37507, 37899, 37544, 37539, 37906, michael@0: 37688, 37617, 37847, 37605, 37616, 37615, 37608, 37564, 37597, 37622, michael@0: {f: 2, c: 37926}, 37571, 37599, 37606, 37650, 37638, 37737, 37659, 37696, michael@0: 37633, 37653, 37678, 37699, {f: 2, c: 37639}, 37663, 37657, 37733, 37703, michael@0: 37750, 37716, 37732, 37802, 37744, 37764, 37860, 37848, 37928, 37767, michael@0: 37836, 37784, 37816, 37823, 37798, 37808, 37813, 37964, 37858, michael@0: {f: 2, c: 37852}, 37837, 37854, 37827, 37831, 37841, 37908, 37917, 37879, michael@0: 37989, 37907, 37997, 37920, 38009, 37881, 37913, 37962, 37938, 37951, michael@0: 37972, 37987, 37758, 31329, 40169, 40182, 40199, 40198, 40227, 40327, michael@0: 40469, 40221, 40223, 40421, 40239, 40409, 40240, 40258, 40478, 40275, michael@0: 40477, 40288, 40274, 40435, 40284, 40289, 40339, 40298, 40303, 40329, michael@0: 40344, 40346, 40384, 40357, 40361, 40386, 40380, 40474, 40403, 40410, michael@0: 40431, 40422, 40434, 40440, 40460, 40442, 40475, 30308, 30296, 30311, michael@0: 30210, {f: 2, c: 30278}, 30281, 30238, 30267, {f: 2, c: 30317}, 30313, michael@0: 30322, 31431, 31414, 35168, 35123, 35165, 35143, 35128, 35172, 30392, michael@0: 32814, 32812, 32889, 32885, 38919, {f: 2, c: 38926}, 38945, 38940, 28481, michael@0: 38950, 38967, 38990, 38995, 39027, 39010, 39001, 39013, 39020, 39024, michael@0: 34787, 34822, 34566, 34851, 34806, 34554, 34799, 34692, 34832, 34760, michael@0: 34833, 34747, 34766, 32588, 31716, 31591, 31849, 31731, 31744, 31691, michael@0: 31836, 31774, 31787, 31779, 31850, 31839, 33380, 33387, 35018, 32677, michael@0: 31986, 31990, 31965, 32310, 40617, 36274, 37317, 37315, 40570, 36489, michael@0: 36428, 36498, 36474, 36437, 36506, 36491, 36499, 36497, 36513, 36451, michael@0: 36522, 36518, 35316, 35318, 38746, 38722, 38717, 38724, 40788, 40799, michael@0: 40793, 40800, 40796, 40806, 40812, 40810, 40823, [12236, 40701], 40703, michael@0: 40713, 35726, 38014, 37864, 39799, 39796, 39809, 39811, 39822, 40056, michael@0: 31308, 39826, 40031, 39824, 39853, 39834, 39850, 39838, 40045, 39851, michael@0: 39837, 40024, 39873, 40058, 39985, 39993, 39971, 39991, 39872, 39882, michael@0: 39879, 39933, 39894, {f: 2, c: 39914}, 39905, 39908, 39911, 39901, 39906, michael@0: 39920, 39899, 39924, 39892, 40029, 39944, 39952, 39949, 39954, 39945, michael@0: 39935, 39968, 39986, 39981, 39976, 39973, 39977, 39987, 39998, 40008, michael@0: 39995, 39989, 40005, 40022, 40020, 40018, 40039, 38851, 38845, 38857, michael@0: 40379, 39631, 39638, 39637, 39768, 39758, 39255, 39260, 39714, 40695, michael@0: 40690, 35180, 38342, 37686, 24390, 34068, 32404, 40803, 22137, 40725, michael@0: 22081, 39662, 35079, 31296, 39091, 38308, 39693, 36852, 24409, 31339, michael@0: 39138, 20642, 34193, 20760, 25458, 21067, 30543, 32397, 26310, 30637, michael@0: [12228, 40565], 22217, 40692, 28635, 25054, 30663, 28720, 40629, 34890, michael@0: 38370, 38854, 31844, 32308, 38822, 40623, 22220, 39089, 27311, 32590, michael@0: 31984, 20418, 32363, 40569, 22190, 39706, 33903, 31142, 31858, 39634, michael@0: 38587, 32251, 35069, 30787, {f: 10, c: 8560}, {f: 2, c: 714}, 729, 8211, michael@0: 8213, 8229, 8245, 8453, 8457, {f: 4, c: 8598}, 8725, 8735, 8739, 8786, michael@0: {f: 2, c: 8806}, 8895, {f: 36, c: 9552}, {f: 15, c: 9601}, {f: 3, c: 9619}, michael@0: {f: 2, c: 9660}, {f: 4, c: 9698}, 9737, 8853, 12306, {f: 2, c: 12317}, michael@0: {f: 9, c: 12321}, 12963, {f: 2, c: 13198}, {f: 3, c: 13212}, 13217, 13252, michael@0: 13262, {f: 2, c: 13265}, 13269, 65072, 65506, 65508, 8481, 12849, 8208, michael@0: 12540, {f: 2, c: 12443}, {f: 2, c: 12541}, 12294, {f: 2, c: 12445}, michael@0: {f: 10, c: 65097}, {f: 4, c: 65108}, {f: 14, c: 65113}, {f: 4, c: 65128}, michael@0: 12350, {f: 12, c: 12272}, 19970, {f: 3, c: 19972}, 19983, 19986, 19991, michael@0: {f: 3, c: 19999}, 20003, 20006, 20009, {f: 2, c: 20014}, 20017, 20019, michael@0: 20021, 20023, 20028, {f: 3, c: 20032}, 20036, 20038, 20042, 20049, 20053, michael@0: 20055, {f: 2, c: 20058}, {f: 4, c: 20066}, {f: 2, c: 20071}, michael@0: {f: 6, c: 20074}, 20082, {f: 10, c: 20084}, {f: 3, c: 20095}, michael@0: {f: 2, c: 20099}, [12037, 20101], 20103, 20106, 20112, {f: 2, c: 20118}, michael@0: 20121, {f: 2, c: 20124}, 20131, 20138, {f: 3, c: 20143}, 20148, michael@0: {f: 4, c: 20150}, {f: 3, c: 20156}, 20168, 20172, {f: 2, c: 20175}, 20178, michael@0: {f: 3, c: 20186}, 20192, 20194, {f: 2, c: 20198}, 20201, {f: 3, c: 20205}, michael@0: 20209, 20212, {f: 3, c: 20216}, 20220, 20222, 20224, {f: 7, c: 20226}, michael@0: {f: 2, c: 20235}, {f: 5, c: 20242}, {f: 2, c: 20252}, 20257, 20259, michael@0: {f: 2, c: 20264}, {f: 3, c: 20268}, 20273, 20275, 20277, 20279, 20281, michael@0: 20283, {f: 5, c: 20286}, {f: 2, c: 20292}, {f: 6, c: 20295}, 20306, 20308, michael@0: 20310, {f: 2, c: 20321}, 20326, 20328, {f: 2, c: 20330}, {f: 2, c: 20333}, michael@0: {f: 2, c: 20337}, 20341, {f: 4, c: 20343}, 20349, {f: 3, c: 20352}, 20357, michael@0: 20359, 20362, 20364, 20366, 20368, {f: 2, c: 20370}, 20373, michael@0: {f: 3, c: 20376}, 20380, {f: 2, c: 20382}, {f: 2, c: 20385}, 20388, 20395, michael@0: 20397, {f: 5, c: 20400}, {f: 9, c: 20406}, {f: 2, c: 20416}, michael@0: {f: 4, c: 20422}, {f: 3, c: 20427}, {f: 5, c: 20434}, 20441, 20443, 20450, michael@0: {f: 2, c: 20452}, 20455, {f: 2, c: 20459}, 20464, 20466, {f: 4, c: 20468}, michael@0: 20473, {f: 3, c: 20475}, 20479, {f: 5, c: 20481}, {f: 2, c: 20487}, 20490, michael@0: 20494, 20496, 20499, {f: 3, c: 20501}, 20507, {f: 2, c: 20509}, 20512, michael@0: {f: 3, c: 20514}, 20519, {f: 11, c: 20527}, 20539, 20541, {f: 4, c: 20543}, michael@0: {f: 3, c: 20548}, {f: 2, c: 20554}, 20557, {f: 5, c: 20560}, michael@0: {f: 4, c: 20566}, 20571, {f: 8, c: 20573}, {f: 6, c: 20582}, michael@0: {f: 7, c: 20589}, {f: 3, c: 20600}, {f: 2, c: 20604}, {f: 4, c: 20609}, michael@0: {f: 2, c: 20614}, {f: 4, c: 20617}, {f: 8, c: 20622}, 20631, michael@0: {f: 8, c: 20634}, 20644, 20646, {f: 2, c: 20650}, {f: 4, c: 20654}, 20662, michael@0: {f: 2, c: 20664}, {f: 2, c: 20668}, {f: 3, c: 20671}, {f: 2, c: 20675}, michael@0: {f: 3, c: 20678}, {f: 5, c: 20682}, 20688, {f: 3, c: 20690}, michael@0: {f: 3, c: 20695}, {f: 3, c: 20699}, {f: 6, c: 20703}, {f: 3, c: 20713}, michael@0: {f: 4, c: 20719}, 20724, {f: 3, c: 20726}, 20730, {f: 4, c: 20732}, 20737, michael@0: 20739, 20741, 20746, {f: 4, c: 20748}, 20753, 20755, {f: 2, c: 20758}, michael@0: {f: 6, c: 20761}, 20768, {f: 8, c: 20770}, {f: 7, c: 20779}, michael@0: {f: 4, c: 20787}, {f: 2, c: 20792}, {f: 2, c: 20797}, 20802, 20807, 20810, michael@0: 20812, {f: 3, c: 20814}, 20819, {f: 3, c: 20823}, 20827, {f: 5, c: 20829}, michael@0: {f: 2, c: 20835}, {f: 2, c: 20838}, 20842, 20847, 20850, 20858, michael@0: {f: 2, c: 20862}, {f: 2, c: 20867}, {f: 2, c: 20870}, {f: 2, c: 20874}, michael@0: {f: 4, c: 20878}, {f: 2, c: 20883}, 20888, 20890, {f: 3, c: 20893}, 20897, michael@0: 20899, {f: 5, c: 20902}, {f: 2, c: 20909}, 20916, {f: 3, c: 20920}, michael@0: {f: 2, c: 20926}, {f: 3, c: 20929}, 20933, 20936, 20938, 20942, 20944, michael@0: {f: 9, c: 20946}, 20956, {f: 2, c: 20958}, {f: 2, c: 20962}, michael@0: {f: 6, c: 20965}, 20972, 20974, 20978, 20980, 20983, 20990, michael@0: {f: 2, c: 20996}, 21001, {f: 2, c: 21003}, {f: 2, c: 21007}, michael@0: {f: 3, c: 21011}, 21020, {f: 2, c: 21022}, {f: 3, c: 21025}, michael@0: {f: 3, c: 21029}, 21034, 21036, 21039, {f: 2, c: 21041}, {f: 2, c: 21044}, michael@0: 21052, 21054, {f: 2, c: 21061}, {f: 2, c: 21064}, {f: 2, c: 21070}, michael@0: {f: 2, c: 21074}, 21077, {f: 4, c: 21079}, 21085, {f: 2, c: 21087}, michael@0: {f: 3, c: 21090}, 21094, 21096, {f: 3, c: 21099}, {f: 2, c: 21104}, 21107, michael@0: {f: 7, c: 21110}, 21118, 21120, {f: 3, c: 21124}, 21131, {f: 2, c: 21134}, michael@0: 21138, {f: 7, c: 21140}, 21148, {f: 4, c: 21156}, {f: 3, c: 21166}, michael@0: {f: 10, c: 21172}, 21184, 21186, {f: 3, c: 21188}, 21192, 21194, michael@0: {f: 4, c: 21196}, 21201, {f: 2, c: 21203}, 21207, 21210, 21212, michael@0: {f: 2, c: 21216}, 21219, {f: 11, c: 21221}, {f: 3, c: 21234}, michael@0: {f: 2, c: 21238}, {f: 3, c: 21243}, {f: 4, c: 21249}, 21255, michael@0: {f: 4, c: 21257}, 21262, {f: 4, c: 21265}, 21272, {f: 2, c: 21275}, michael@0: {f: 2, c: 21278}, 21282, {f: 2, c: 21284}, {f: 3, c: 21287}, michael@0: {f: 2, c: 21291}, 21296, {f: 6, c: 21298}, [12054, 21304], michael@0: {f: 2, c: 21308}, 21314, 21316, 21318, {f: 3, c: 21323}, 21328, michael@0: {f: 2, c: 21336}, 21339, 21341, 21349, 21352, 21354, {f: 2, c: 21356}, michael@0: 21362, 21366, 21369, {f: 4, c: 21371}, {f: 2, c: 21376}, 21379, michael@0: {f: 2, c: 21383}, 21386, {f: 7, c: 21390}, {f: 2, c: 21398}, michael@0: {f: 2, c: 21403}, 21406, 21409, 21412, 21415, {f: 3, c: 21418}, michael@0: {f: 3, c: 21423}, 21427, 21429, {f: 4, c: 21431}, {f: 3, c: 21436}, 21440, michael@0: {f: 4, c: 21444}, {f: 3, c: 21454}, {f: 2, c: 21458}, 21461, 21466, michael@0: {f: 3, c: 21468}, 21473, 21479, 21492, 21498, {f: 3, c: 21502}, 21506, michael@0: 21509, 21511, 21515, 21524, {f: 3, c: 21528}, 21532, 21538, michael@0: {f: 2, c: 21540}, 21546, 21552, 21555, {f: 2, c: 21558}, 21562, 21565, michael@0: 21567, {f: 2, c: 21569}, {f: 2, c: 21572}, 21575, 21577, {f: 4, c: 21580}, michael@0: 21585, 21594, {f: 5, c: 21597}, 21603, 21605, 21607, {f: 8, c: 21609}, michael@0: 21620, {f: 2, c: 21625}, {f: 2, c: 21630}, 21633, 21635, 21637, michael@0: {f: 4, c: 21639}, 21645, 21649, 21651, {f: 2, c: 21655}, 21660, michael@0: {f: 5, c: 21662}, 21669, 21678, 21680, 21682, {f: 3, c: 21685}, michael@0: {f: 2, c: 21689}, 21694, 21699, 21701, {f: 2, c: 21706}, 21718, 21720, michael@0: 21723, 21728, {f: 3, c: 21730}, {f: 2, c: 21739}, {f: 3, c: 21743}, michael@0: {f: 6, c: 21748}, 21755, 21758, 21760, {f: 2, c: 21762}, 21765, 21768, michael@0: {f: 5, c: 21770}, {f: 2, c: 21778}, {f: 6, c: 21781}, {f: 4, c: 21788}, michael@0: 21793, {f: 2, c: 21797}, {f: 2, c: 21800}, 21803, 21805, 21810, michael@0: {f: 3, c: 21812}, {f: 4, c: 21816}, 21821, 21824, 21826, 21829, michael@0: {f: 2, c: 21831}, {f: 4, c: 21835}, {f: 2, c: 21841}, 21844, michael@0: {f: 5, c: 21847}, 21853, {f: 2, c: 21855}, {f: 2, c: 21858}, michael@0: {f: 2, c: 21864}, 21867, {f: 6, c: 21871}, {f: 2, c: 21881}, 21885, 21887, michael@0: {f: 2, c: 21893}, {f: 3, c: 21900}, 21904, {f: 2, c: 21906}, michael@0: {f: 3, c: 21909}, {f: 2, c: 21914}, 21918, {f: 7, c: 21920}, michael@0: {f: 2, c: 21928}, 21931, 21933, {f: 2, c: 21935}, 21940, 21942, 21944, michael@0: 21946, 21948, {f: 5, c: 21951}, 21960, {f: 2, c: 21962}, {f: 2, c: 21967}, michael@0: 21973, {f: 3, c: 21975}, 21979, 21982, 21984, 21986, 21991, michael@0: {f: 2, c: 21997}, {f: 2, c: 22000}, 22004, {f: 5, c: 22008}, 22015, michael@0: {f: 4, c: 22018}, 22023, {f: 2, c: 22026}, {f: 4, c: 22032}, 22037, michael@0: {f: 2, c: 22041}, 22045, {f: 3, c: 22048}, {f: 2, c: 22053}, 22056, michael@0: {f: 2, c: 22058}, 22067, 22071, 22074, {f: 3, c: 22076}, 22080, michael@0: {f: 10, c: 22082}, {f: 5, c: 22095}, {f: 2, c: 22101}, {f: 2, c: 22106}, michael@0: {f: 2, c: 22110}, 22113, 22115, 22119, {f: 2, c: 22125}, 22128, 22131, michael@0: 22133, 22135, 22138, {f: 3, c: 22141}, {f: 4, c: 22145}, {f: 4, c: 22152}, michael@0: 22157, {f: 3, c: 22160}, 22164, {f: 3, c: 22166}, {f: 9, c: 22170}, michael@0: {f: 2, c: 22180}, 22183, {f: 5, c: 22185}, {f: 3, c: 22192}, 22197, michael@0: {f: 4, c: 22200}, {f: 3, c: 22205}, {f: 2, c: 22211}, {f: 2, c: 22214}, michael@0: 22219, {f: 4, c: 22221}, {f: 2, c: 22226}, {f: 2, c: 22229}, michael@0: {f: 2, c: 22232}, 22236, 22243, {f: 6, c: 22245}, 22252, {f: 2, c: 22254}, michael@0: {f: 2, c: 22258}, {f: 3, c: 22262}, {f: 2, c: 22267}, {f: 3, c: 22272}, michael@0: 22277, 22284, {f: 4, c: 22286}, {f: 2, c: 22292}, 22295, {f: 3, c: 22297}, michael@0: {f: 2, c: 22301}, {f: 3, c: 22304}, {f: 4, c: 22308}, 22315, michael@0: {f: 2, c: 22321}, {f: 5, c: 22324}, {f: 2, c: 22332}, 22335, 22337, michael@0: {f: 4, c: 22339}, {f: 2, c: 22344}, 22347, {f: 5, c: 22354}, michael@0: {f: 2, c: 22360}, {f: 2, c: 22370}, 22373, 22375, 22380, 22382, michael@0: {f: 3, c: 22384}, {f: 2, c: 22388}, {f: 3, c: 22392}, {f: 5, c: 22397}, michael@0: {f: 4, c: 22407}, {f: 5, c: 22413}, {f: 7, c: 22420}, {f: 4, c: 22428}, michael@0: 22437, 22440, 22442, 22444, {f: 3, c: 22447}, 22451, {f: 3, c: 22453}, michael@0: {f: 9, c: 22457}, {f: 7, c: 22468}, {f: 2, c: 22476}, {f: 2, c: 22480}, michael@0: 22483, {f: 2, c: 22486}, {f: 2, c: 22491}, 22494, {f: 2, c: 22498}, michael@0: {f: 8, c: 22501}, 22510, {f: 4, c: 22512}, {f: 2, c: 22517}, michael@0: {f: 2, c: 22523}, {f: 2, c: 22526}, 22529, {f: 2, c: 22531}, michael@0: {f: 2, c: 22536}, 22540, {f: 3, c: 22542}, {f: 3, c: 22546}, michael@0: {f: 2, c: 22551}, {f: 3, c: 22554}, 22559, {f: 2, c: 22562}, michael@0: {f: 5, c: 22565}, {f: 4, c: 22571}, {f: 2, c: 22578}, {f: 14, c: 22582}, michael@0: {f: 5, c: 22597}, 22606, 22608, 22611, {f: 2, c: 22613}, {f: 5, c: 22617}, michael@0: {f: 3, c: 22623}, 22627, {f: 5, c: 22630}, {f: 8, c: 22637}, michael@0: {f: 3, c: 22646}, {f: 4, c: 22650}, 22655, 22658, 22660, {f: 3, c: 22662}, michael@0: {f: 7, c: 22667}, {f: 5, c: 22676}, 22683, 22685, {f: 8, c: 22688}, michael@0: {f: 4, c: 22698}, {f: 4, c: 22703}, {f: 7, c: 22708}, 22717, michael@0: {f: 2, c: 22719}, {f: 3, c: 22722}, 22726, {f: 9, c: 22728}, 22738, 22740, michael@0: {f: 2, c: 22742}, {f: 3, c: 22747}, 22753, 22755, {f: 4, c: 22757}, 22762, michael@0: 22765, {f: 2, c: 22769}, {f: 2, c: 22772}, {f: 2, c: 22775}, michael@0: {f: 2, c: 22779}, {f: 4, c: 22782}, 22787, {f: 2, c: 22789}, michael@0: {f: 2, c: 22792}, [12066, 22794], {f: 2, c: 22795}, 22798, michael@0: {f: 4, c: 22800}, {f: 2, c: 22807}, 22811, {f: 2, c: 22813}, michael@0: {f: 2, c: 22816}, 22819, 22822, 22824, 22828, 22832, {f: 2, c: 22834}, michael@0: {f: 2, c: 22837}, 22843, 22845, {f: 2, c: 22847}, 22851, {f: 2, c: 22853}, michael@0: 22858, {f: 2, c: 22860}, 22864, {f: 2, c: 22866}, 22873, {f: 5, c: 22875}, michael@0: 22881, {f: 2, c: 22883}, {f: 3, c: 22886}, 22891, 22893, {f: 4, c: 22895}, michael@0: 22901, 22903, {f: 3, c: 22906}, {f: 3, c: 22910}, 22917, 22921, michael@0: {f: 2, c: 22923}, {f: 4, c: 22926}, {f: 2, c: 22932}, 22936, michael@0: {f: 3, c: 22938}, {f: 4, c: 22943}, {f: 2, c: 22950}, {f: 2, c: 22956}, michael@0: {f: 2, c: 22960}, {f: 6, c: 22963}, 22970, {f: 2, c: 22972}, michael@0: {f: 7, c: 22975}, {f: 3, c: 22983}, {f: 4, c: 22988}, {f: 2, c: 22997}, michael@0: 23001, 23003, {f: 5, c: 23006}, 23012, {f: 2, c: 23014}, {f: 3, c: 23017}, michael@0: {f: 12, c: 23021}, 23034, {f: 3, c: 23036}, 23040, 23042, {f: 2, c: 23050}, michael@0: {f: 4, c: 23053}, 23058, {f: 4, c: 23060}, {f: 3, c: 23065}, michael@0: {f: 2, c: 23069}, {f: 2, c: 23073}, 23076, {f: 3, c: 23078}, michael@0: {f: 7, c: 23082}, 23091, 23093, {f: 5, c: 23095}, {f: 3, c: 23101}, michael@0: {f: 4, c: 23106}, {f: 2, c: 23111}, {f: 10, c: 23115}, {f: 4, c: 23126}, michael@0: {f: 7, c: 23131}, {f: 3, c: 23139}, {f: 2, c: 23144}, {f: 2, c: 23147}, michael@0: {f: 6, c: 23150}, {f: 2, c: 23160}, {f: 4, c: 23163}, {f: 18, c: 23168}, michael@0: {f: 7, c: 23187}, {f: 11, c: 23196}, {f: 2, c: 23208}, {f: 7, c: 23211}, michael@0: 23220, {f: 2, c: 23222}, {f: 4, c: 23225}, {f: 2, c: 23231}, michael@0: {f: 6, c: 23235}, {f: 2, c: 23242}, {f: 5, c: 23245}, 23251, 23253, michael@0: {f: 3, c: 23257}, {f: 3, c: 23261}, 23266, {f: 2, c: 23268}, michael@0: {f: 2, c: 23271}, 23274, {f: 5, c: 23276}, {f: 3, c: 23282}, michael@0: {f: 5, c: 23286}, {f: 4, c: 23292}, {f: 7, c: 23297}, 23306, michael@0: {f: 9, c: 23309}, 23320, {f: 7, c: 23322}, {f: 8, c: 23330}, michael@0: {f: 5, c: 23339}, 23345, 23347, {f: 2, c: 23349}, {f: 7, c: 23353}, michael@0: {f: 11, c: 23361}, {f: 3, c: 23373}, 23378, 23382, 23390, {f: 2, c: 23392}, michael@0: {f: 2, c: 23399}, {f: 3, c: 23405}, 23410, 23412, {f: 2, c: 23414}, 23417, michael@0: {f: 2, c: 23419}, 23422, 23426, 23430, 23434, {f: 2, c: 23437}, michael@0: {f: 3, c: 23440}, 23444, 23446, 23455, {f: 3, c: 23463}, {f: 4, c: 23468}, michael@0: {f: 2, c: 23473}, 23479, {f: 3, c: 23482}, {f: 2, c: 23488}, 23491, michael@0: {f: 4, c: 23496}, {f: 3, c: 23501}, 23505, {f: 9, c: 23508}, 23520, 23523, michael@0: 23530, 23533, 23535, {f: 4, c: 23537}, 23543, {f: 2, c: 23549}, 23552, michael@0: {f: 2, c: 23554}, 23557, 23564, 23568, {f: 2, c: 23570}, 23575, 23577, michael@0: 23579, {f: 4, c: 23582}, 23587, 23590, {f: 4, c: 23592}, {f: 4, c: 23597}, michael@0: {f: 2, c: 23602}, {f: 2, c: 23605}, {f: 2, c: 23619}, {f: 2, c: 23622}, michael@0: {f: 2, c: 23628}, {f: 3, c: 23634}, {f: 3, c: 23638}, {f: 4, c: 23642}, michael@0: 23647, 23655, {f: 3, c: 23657}, 23661, 23664, {f: 7, c: 23666}, michael@0: {f: 4, c: 23675}, 23680, {f: 5, c: 23683}, {f: 3, c: 23689}, michael@0: {f: 2, c: 23694}, {f: 2, c: 23698}, 23701, {f: 4, c: 23709}, michael@0: {f: 5, c: 23716}, 23722, {f: 3, c: 23726}, 23730, 23732, 23734, michael@0: {f: 4, c: 23737}, 23742, 23744, {f: 2, c: 23746}, {f: 6, c: 23749}, michael@0: {f: 6, c: 23756}, {f: 6, c: 23763}, {f: 7, c: 23770}, {f: 2, c: 23778}, michael@0: 23783, 23785, {f: 2, c: 23787}, {f: 2, c: 23790}, {f: 3, c: 23793}, 23797, michael@0: {f: 4, c: 23799}, 23804, {f: 4, c: 23806}, {f: 2, c: 23812}, michael@0: {f: 5, c: 23816}, {f: 5, c: 23823}, 23829, {f: 3, c: 23832}, michael@0: {f: 2, c: 23836}, {f: 5, c: 23839}, 23845, 23848, {f: 2, c: 23850}, michael@0: {f: 5, c: 23855}, {f: 8, c: 23861}, {f: 8, c: 23871}, {f: 2, c: 23880}, michael@0: {f: 3, c: 23885}, {f: 7, c: 23889}, {f: 2, c: 23897}, 23900, michael@0: {f: 11, c: 23902}, 23914, {f: 2, c: 23917}, {f: 4, c: 23920}, michael@0: {f: 12, c: 23925}, 23939, {f: 2, c: 23941}, {f: 15, c: 23944}, 23960, michael@0: {f: 3, c: 23962}, {f: 2, c: 23966}, {f: 6, c: 23969}, {f: 15, c: 23976}, michael@0: 23993, 23995, {f: 8, c: 23997}, {f: 5, c: 24006}, 24012, {f: 4, c: 24014}, michael@0: 24019, {f: 6, c: 24021}, 24028, {f: 2, c: 24031}, {f: 2, c: 24035}, 24042, michael@0: {f: 2, c: 24044}, {f: 2, c: 24053}, {f: 5, c: 24056}, {f: 2, c: 24063}, michael@0: 24068, 24071, {f: 3, c: 24073}, {f: 2, c: 24077}, {f: 2, c: 24082}, 24087, michael@0: {f: 7, c: 24094}, {f: 3, c: 24104}, 24108, {f: 2, c: 24111}, 24114, michael@0: {f: 2, c: 24116}, {f: 2, c: 24121}, {f: 2, c: 24126}, 24129, michael@0: {f: 6, c: 24134}, {f: 7, c: 24141}, 24150, {f: 2, c: 24153}, michael@0: {f: 2, c: 24156}, 24160, {f: 7, c: 24164}, {f: 5, c: 24173}, 24181, 24183, michael@0: {f: 3, c: 24193}, 24197, {f: 2, c: 24200}, {f: 3, c: 24204}, 24210, 24216, michael@0: 24219, 24221, {f: 4, c: 24225}, {f: 3, c: 24232}, 24236, {f: 5, c: 24238}, michael@0: 24244, {f: 4, c: 24250}, {f: 10, c: 24255}, {f: 6, c: 24267}, michael@0: {f: 2, c: 24276}, {f: 4, c: 24279}, {f: 3, c: 24284}, {f: 4, c: 24292}, michael@0: 24297, 24299, {f: 6, c: 24301}, 24309, {f: 2, c: 24312}, {f: 3, c: 24315}, michael@0: {f: 3, c: 24325}, 24329, {f: 3, c: 24332}, 24336, 24338, 24340, 24342, michael@0: {f: 2, c: 24345}, {f: 3, c: 24348}, {f: 4, c: 24353}, 24360, michael@0: {f: 2, c: 24363}, 24366, 24368, 24370, 24372, {f: 3, c: 24374}, 24379, michael@0: {f: 3, c: 24381}, {f: 5, c: 24385}, 24391, {f: 3, c: 24393}, 24397, 24399, michael@0: 24401, 24404, {f: 3, c: 24410}, {f: 3, c: 24414}, 24419, 24421, michael@0: {f: 2, c: 24423}, 24427, {f: 2, c: 24430}, 24434, {f: 3, c: 24436}, 24440, michael@0: 24442, {f: 3, c: 24445}, 24451, 24454, {f: 3, c: 24461}, {f: 2, c: 24467}, michael@0: 24470, {f: 2, c: 24474}, 24477, 24479, {f: 6, c: 24482}, {f: 2, c: 24491}, michael@0: {f: 6, c: 24495}, 24502, 24504, {f: 2, c: 24506}, {f: 5, c: 24510}, michael@0: {f: 2, c: 24519}, {f: 2, c: 24522}, 24526, {f: 3, c: 24531}, michael@0: {f: 3, c: 24538}, {f: 2, c: 24542}, {f: 2, c: 24546}, {f: 2, c: 24549}, michael@0: {f: 2, c: 24552}, 24556, {f: 2, c: 24559}, {f: 3, c: 24562}, michael@0: {f: 2, c: 24566}, {f: 2, c: 24569}, 24572, {f: 3, c: 24583}, michael@0: {f: 2, c: 24587}, {f: 2, c: 24592}, 24595, {f: 2, c: 24599}, 24602, michael@0: {f: 2, c: 24606}, {f: 3, c: 24610}, {f: 3, c: 24620}, {f: 5, c: 24624}, michael@0: {f: 5, c: 24630}, {f: 2, c: 24637}, 24640, {f: 7, c: 24644}, 24652, michael@0: {f: 2, c: 24654}, 24657, {f: 2, c: 24659}, {f: 3, c: 24662}, michael@0: {f: 2, c: 24667}, {f: 4, c: 24670}, {f: 2, c: 24677}, 24686, michael@0: {f: 2, c: 24689}, {f: 2, c: 24692}, 24695, 24702, {f: 3, c: 24704}, michael@0: {f: 4, c: 24709}, {f: 2, c: 24714}, {f: 4, c: 24718}, 24723, 24725, michael@0: {f: 3, c: 24727}, 24732, 24734, {f: 2, c: 24737}, {f: 2, c: 24740}, 24743, michael@0: {f: 2, c: 24745}, 24750, 24752, 24755, 24759, {f: 2, c: 24761}, michael@0: {f: 8, c: 24765}, {f: 3, c: 24775}, {f: 5, c: 24780}, {f: 3, c: 24786}, michael@0: {f: 2, c: 24790}, 24793, 24795, 24798, {f: 4, c: 24802}, 24810, 24821, michael@0: {f: 2, c: 24823}, {f: 4, c: 24828}, {f: 4, c: 24834}, 24839, michael@0: {f: 3, c: 24842}, {f: 5, c: 24848}, {f: 4, c: 24854}, {f: 2, c: 24861}, michael@0: {f: 2, c: 24865}, 24869, {f: 3, c: 24872}, {f: 8, c: 24876}, michael@0: {f: 2, c: 24885}, {f: 6, c: 24888}, {f: 8, c: 24896}, 24905, 24909, michael@0: {f: 2, c: 24911}, {f: 3, c: 24914}, {f: 2, c: 24918}, 24921, michael@0: {f: 2, c: 24923}, 24926, {f: 2, c: 24928}, {f: 2, c: 24933}, 24937, michael@0: {f: 2, c: 24940}, 24943, {f: 2, c: 24945}, 24948, {f: 10, c: 24952}, michael@0: {f: 7, c: 24963}, {f: 2, c: 24972}, 24975, 24979, {f: 5, c: 24981}, michael@0: {f: 2, c: 24987}, {f: 6, c: 24990}, {f: 2, c: 24997}, 25002, 25005, michael@0: {f: 3, c: 25007}, {f: 3, c: 25011}, {f: 6, c: 25016}, {f: 3, c: 25023}, michael@0: {f: 4, c: 25027}, {f: 4, c: 25037}, 25043, {f: 9, c: 25045}, michael@0: {f: 3, c: 25056}, {f: 2, c: 25060}, 25063, {f: 9, c: 25065}, michael@0: {f: 2, c: 25075}, 25081, 25083, 25085, {f: 5, c: 25089}, 25097, 25107, michael@0: 25113, {f: 3, c: 25116}, 25120, 25123, 25126, {f: 2, c: 25128}, 25131, michael@0: 25133, 25135, 25137, 25141, [12094, 25142], {f: 5, c: 25144}, 25154, michael@0: {f: 3, c: 25156}, 25162, {f: 2, c: 25167}, {f: 3, c: 25173}, michael@0: {f: 2, c: 25177}, {f: 7, c: 25180}, {f: 2, c: 25188}, 25192, michael@0: {f: 2, c: 25201}, {f: 2, c: 25204}, {f: 2, c: 25207}, {f: 2, c: 25210}, michael@0: 25213, {f: 3, c: 25217}, {f: 4, c: 25221}, {f: 6, c: 25227}, 25236, 25241, michael@0: {f: 3, c: 25244}, 25251, {f: 2, c: 25254}, {f: 2, c: 25257}, michael@0: {f: 4, c: 25261}, {f: 3, c: 25266}, {f: 3, c: 25270}, 25274, 25278, michael@0: {f: 2, c: 25280}, 25283, 25291, 25295, 25297, 25301, {f: 2, c: 25309}, michael@0: {f: 2, c: 25312}, 25316, {f: 2, c: 25322}, 25328, 25330, 25333, michael@0: {f: 4, c: 25336}, 25344, {f: 4, c: 25347}, {f: 4, c: 25354}, michael@0: {f: 2, c: 25359}, {f: 4, c: 25362}, {f: 3, c: 25367}, 25372, michael@0: {f: 2, c: 25382}, 25385, {f: 3, c: 25388}, {f: 2, c: 25392}, michael@0: {f: 6, c: 25395}, {f: 2, c: 25403}, {f: 3, c: 25407}, 25412, michael@0: {f: 2, c: 25415}, 25418, {f: 4, c: 25425}, {f: 8, c: 25430}, 25440, michael@0: {f: 3, c: 25444}, 25450, 25452, {f: 2, c: 25455}, {f: 3, c: 25459}, michael@0: {f: 2, c: 25464}, {f: 4, c: 25468}, 25473, {f: 2, c: 25477}, 25483, 25485, michael@0: 25489, {f: 3, c: 25491}, 25495, {f: 7, c: 25497}, 25505, 25508, 25510, michael@0: 25515, 25519, {f: 2, c: 25521}, {f: 2, c: 25525}, 25529, 25531, 25533, michael@0: 25535, {f: 3, c: 25537}, 25541, {f: 2, c: 25543}, {f: 3, c: 25546}, 25553, michael@0: {f: 3, c: 25555}, {f: 3, c: 25559}, {f: 3, c: 25563}, 25567, 25570, michael@0: {f: 5, c: 25572}, {f: 2, c: 25579}, {f: 3, c: 25583}, 25587, 25589, 25591, michael@0: {f: 4, c: 25593}, 25598, {f: 2, c: 25603}, {f: 5, c: 25606}, 25614, michael@0: {f: 2, c: 25617}, {f: 2, c: 25621}, {f: 3, c: 25624}, 25629, 25631, michael@0: {f: 4, c: 25634}, {f: 3, c: 25639}, 25643, {f: 6, c: 25646}, 25653, michael@0: {f: 3, c: 25655}, {f: 2, c: 25659}, 25662, 25664, {f: 2, c: 25666}, 25673, michael@0: {f: 6, c: 25675}, 25683, {f: 3, c: 25685}, {f: 3, c: 25689}, 25693, michael@0: {f: 7, c: 25696}, 25704, {f: 3, c: 25706}, 25710, {f: 3, c: 25712}, michael@0: {f: 2, c: 25716}, 25719, {f: 6, c: 25724}, 25731, 25734, {f: 8, c: 25737}, michael@0: 25748, {f: 2, c: 25751}, {f: 4, c: 25754}, {f: 3, c: 25760}, michael@0: {f: 3, c: 25766}, 25770, 25775, 25777, 25780, 25782, 25785, 25789, 25795, michael@0: 25798, {f: 2, c: 25800}, 25804, 25807, 25809, 25811, {f: 2, c: 25813}, michael@0: 25817, {f: 3, c: 25819}, 25823, 25825, 25827, 25829, {f: 5, c: 25831}, michael@0: {f: 2, c: 25837}, 25843, {f: 2, c: 25845}, {f: 2, c: 25848}, 25853, 25855, michael@0: {f: 3, c: 25857}, 25861, {f: 2, c: 25863}, {f: 5, c: 25866}, michael@0: {f: 2, c: 25872}, 25875, 25877, 25879, 25882, 25884, {f: 4, c: 25886}, michael@0: {f: 4, c: 25894}, 25901, {f: 4, c: 25904}, 25911, 25914, {f: 2, c: 25916}, michael@0: {f: 5, c: 25920}, {f: 2, c: 25926}, {f: 2, c: 25930}, {f: 2, c: 25933}, michael@0: 25936, {f: 3, c: 25938}, 25944, 25946, 25948, {f: 3, c: 25951}, michael@0: {f: 2, c: 25956}, {f: 4, c: 25959}, {f: 3, c: 25965}, 25969, 25971, 25974, michael@0: {f: 9, c: 25977}, {f: 3, c: 25988}, {f: 3, c: 25992}, {f: 3, c: 25997}, michael@0: 26002, 26004, 26006, 26008, 26010, {f: 2, c: 26013}, 26016, michael@0: {f: 2, c: 26018}, 26022, 26024, 26026, 26030, {f: 6, c: 26033}, 26040, michael@0: {f: 2, c: 26042}, {f: 3, c: 26046}, 26050, {f: 4, c: 26055}, 26061, michael@0: {f: 2, c: 26064}, {f: 3, c: 26067}, {f: 8, c: 26072}, 26081, michael@0: {f: 2, c: 26083}, {f: 2, c: 26090}, {f: 4, c: 26098}, {f: 2, c: 26104}, michael@0: {f: 5, c: 26107}, 26113, {f: 2, c: 26116}, {f: 3, c: 26119}, 26123, 26125, michael@0: {f: 3, c: 26128}, {f: 3, c: 26134}, {f: 3, c: 26138}, 26142, michael@0: {f: 4, c: 26145}, 26150, {f: 4, c: 26153}, 26158, 26160, {f: 2, c: 26162}, michael@0: {f: 5, c: 26167}, 26173, {f: 2, c: 26175}, {f: 7, c: 26180}, michael@0: {f: 2, c: 26189}, {f: 2, c: 26192}, {f: 2, c: 26200}, {f: 2, c: 26203}, michael@0: 26206, 26208, {f: 2, c: 26210}, 26213, 26215, {f: 5, c: 26217}, michael@0: {f: 3, c: 26225}, 26229, {f: 2, c: 26232}, {f: 3, c: 26235}, michael@0: {f: 3, c: 26239}, 26243, {f: 2, c: 26245}, {f: 2, c: 26250}, michael@0: {f: 4, c: 26253}, {f: 4, c: 26258}, {f: 5, c: 26264}, {f: 4, c: 26270}, michael@0: {f: 4, c: 26275}, {f: 2, c: 26281}, {f: 2, c: 26284}, {f: 5, c: 26287}, michael@0: {f: 4, c: 26293}, {f: 4, c: 26298}, {f: 5, c: 26303}, 26309, 26312, michael@0: {f: 12, c: 26314}, {f: 2, c: 26327}, 26330, {f: 2, c: 26334}, michael@0: {f: 5, c: 26337}, {f: 2, c: 26343}, {f: 2, c: 26346}, {f: 3, c: 26349}, michael@0: 26353, {f: 2, c: 26357}, {f: 2, c: 26362}, 26365, {f: 2, c: 26369}, michael@0: {f: 4, c: 26372}, 26380, {f: 2, c: 26382}, {f: 3, c: 26385}, 26390, michael@0: {f: 3, c: 26392}, 26396, 26398, {f: 6, c: 26400}, 26409, 26414, 26416, michael@0: {f: 2, c: 26418}, {f: 4, c: 26422}, {f: 2, c: 26427}, {f: 2, c: 26430}, michael@0: 26433, {f: 2, c: 26436}, 26439, {f: 2, c: 26442}, 26445, 26450, michael@0: {f: 2, c: 26452}, {f: 5, c: 26455}, 26461, {f: 3, c: 26466}, michael@0: {f: 2, c: 26470}, {f: 2, c: 26475}, 26478, 26484, 26486, {f: 4, c: 26488}, michael@0: 26493, 26496, {f: 2, c: 26498}, {f: 2, c: 26501}, 26504, 26506, michael@0: {f: 4, c: 26508}, {f: 4, c: 26513}, 26518, 26521, 26523, {f: 3, c: 26527}, michael@0: 26532, 26534, 26537, 26540, 26542, {f: 2, c: 26545}, 26548, michael@0: {f: 8, c: 26553}, 26562, {f: 10, c: 26565}, {f: 3, c: 26581}, 26587, 26591, michael@0: 26593, {f: 2, c: 26595}, {f: 3, c: 26598}, {f: 2, c: 26602}, michael@0: {f: 2, c: 26605}, 26610, {f: 8, c: 26613}, 26622, {f: 4, c: 26625}, 26630, michael@0: 26637, 26640, 26642, {f: 2, c: 26644}, {f: 5, c: 26648}, {f: 3, c: 26654}, michael@0: {f: 7, c: 26658}, {f: 7, c: 26667}, {f: 3, c: 26676}, {f: 2, c: 26682}, michael@0: 26687, 26695, 26699, 26701, 26703, 26706, {f: 10, c: 26710}, 26730, michael@0: {f: 8, c: 26732}, 26741, {f: 9, c: 26744}, 26754, 26756, {f: 8, c: 26759}, michael@0: {f: 3, c: 26768}, {f: 3, c: 26772}, {f: 4, c: 26777}, 26782, michael@0: {f: 2, c: 26784}, {f: 3, c: 26787}, {f: 4, c: 26793}, 26798, michael@0: {f: 2, c: 26801}, 26804, {f: 10, c: 26806}, 26817, {f: 6, c: 26819}, 26826, michael@0: 26828, {f: 4, c: 26830}, {f: 2, c: 26835}, 26841, {f: 4, c: 26843}, michael@0: {f: 2, c: 26849}, {f: 3, c: 26852}, {f: 6, c: 26856}, 26863, michael@0: {f: 3, c: 26866}, {f: 3, c: 26870}, 26875, {f: 4, c: 26877}, michael@0: {f: 3, c: 26882}, {f: 5, c: 26886}, 26892, 26897, {f: 12, c: 26899}, michael@0: {f: 3, c: 26913}, {f: 8, c: 26917}, {f: 2, c: 26926}, {f: 3, c: 26929}, michael@0: {f: 4, c: 26933}, {f: 3, c: 26938}, 26942, {f: 2, c: 26944}, michael@0: {f: 7, c: 26947}, {f: 8, c: 26955}, {f: 2, c: 26965}, {f: 2, c: 26968}, michael@0: {f: 2, c: 26971}, 26975, {f: 2, c: 26977}, {f: 2, c: 26980}, 26983, michael@0: {f: 2, c: 26985}, 26988, {f: 2, c: 26991}, {f: 3, c: 26994}, 26998, michael@0: {f: 2, c: 27002}, {f: 3, c: 27005}, 27009, 27011, 27013, {f: 3, c: 27018}, michael@0: {f: 6, c: 27022}, {f: 2, c: 27030}, {f: 2, c: 27033}, {f: 10, c: 27037}, michael@0: 27049, 27052, {f: 2, c: 27055}, {f: 2, c: 27058}, {f: 2, c: 27061}, michael@0: {f: 3, c: 27064}, {f: 3, c: 27068}, 27072, {f: 8, c: 27074}, 27087, michael@0: {f: 3, c: 27089}, {f: 6, c: 27093}, {f: 3, c: 27100}, {f: 6, c: 27105}, michael@0: {f: 5, c: 27112}, {f: 4, c: 27118}, {f: 9, c: 27124}, 27134, 27136, michael@0: {f: 2, c: 27139}, {f: 4, c: 27142}, {f: 8, c: 27147}, {f: 3, c: 27156}, michael@0: {f: 4, c: 27162}, 27168, 27170, {f: 4, c: 27172}, 27177, {f: 4, c: 27179}, michael@0: 27184, {f: 3, c: 27186}, {f: 2, c: 27190}, {f: 2, c: 27195}, michael@0: {f: 5, c: 27199}, {f: 2, c: 27205}, {f: 2, c: 27209}, {f: 4, c: 27212}, michael@0: {f: 7, c: 27217}, 27226, {f: 3, c: 27228}, 27232, {f: 2, c: 27235}, michael@0: {f: 11, c: 27238}, {f: 7, c: 27250}, {f: 2, c: 27258}, {f: 3, c: 27261}, michael@0: {f: 3, c: 27265}, {f: 4, c: 27269}, {f: 4, c: 27274}, 27279, michael@0: {f: 2, c: 27282}, {f: 2, c: 27285}, {f: 4, c: 27288}, {f: 3, c: 27293}, michael@0: 27297, {f: 5, c: 27300}, 27306, {f: 2, c: 27309}, {f: 3, c: 27312}, michael@0: {f: 4, c: 27316}, {f: 2, c: 27321}, {f: 7, c: 27324}, {f: 15, c: 27332}, michael@0: {f: 6, c: 27348}, 27356, {f: 7, c: 27360}, 27369, 27371, {f: 6, c: 27373}, michael@0: {f: 4, c: 27380}, {f: 2, c: 27385}, {f: 8, c: 27388}, {f: 5, c: 27397}, michael@0: {f: 4, c: 27403}, {f: 2, c: 27408}, {f: 3, c: 27411}, {f: 7, c: 27415}, michael@0: 27423, {f: 2, c: 27429}, {f: 10, c: 27432}, {f: 4, c: 27443}, 27448, michael@0: {f: 2, c: 27451}, {f: 4, c: 27455}, {f: 2, c: 27460}, 27464, michael@0: {f: 2, c: 27466}, {f: 3, c: 27469}, {f: 8, c: 27473}, {f: 5, c: 27482}, michael@0: 27488, {f: 2, c: 27496}, {f: 7, c: 27499}, {f: 4, c: 27507}, 27514, michael@0: {f: 4, c: 27517}, 27525, 27528, 27532, {f: 4, c: 27534}, {f: 2, c: 27540}, michael@0: 27543, 27545, {f: 2, c: 27548}, {f: 2, c: 27551}, {f: 2, c: 27554}, michael@0: {f: 5, c: 27557}, {f: 2, c: 27564}, {f: 2, c: 27568}, 27574, michael@0: {f: 2, c: 27576}, {f: 3, c: 27580}, 27584, {f: 2, c: 27587}, michael@0: {f: 4, c: 27591}, 27596, 27598, {f: 2, c: 27600}, 27608, 27610, michael@0: {f: 5, c: 27612}, {f: 8, c: 27618}, {f: 3, c: 27628}, {f: 3, c: 27632}, michael@0: 27636, {f: 3, c: 27638}, {f: 3, c: 27642}, 27646, {f: 5, c: 27648}, michael@0: {f: 3, c: 27657}, 27662, 27666, 27671, {f: 3, c: 27676}, 27680, 27685, michael@0: 27693, 27697, 27699, {f: 2, c: 27702}, {f: 4, c: 27705}, {f: 2, c: 27710}, michael@0: {f: 3, c: 27715}, 27720, {f: 5, c: 27723}, {f: 3, c: 27729}, 27734, michael@0: {f: 3, c: 27736}, {f: 2, c: 27746}, {f: 3, c: 27749}, {f: 5, c: 27755}, michael@0: 27761, 27763, 27765, {f: 2, c: 27767}, {f: 3, c: 27770}, {f: 2, c: 27775}, michael@0: 27780, 27783, {f: 2, c: 27786}, {f: 2, c: 27789}, {f: 2, c: 27793}, michael@0: {f: 4, c: 27797}, 27802, {f: 3, c: 27804}, 27808, 27810, 27816, 27820, michael@0: {f: 2, c: 27823}, {f: 4, c: 27828}, 27834, {f: 4, c: 27840}, michael@0: {f: 3, c: 27846}, 27851, {f: 3, c: 27853}, {f: 2, c: 27857}, michael@0: {f: 3, c: 27864}, {f: 2, c: 27868}, 27871, 27876, {f: 2, c: 27878}, 27881, michael@0: {f: 2, c: 27884}, 27890, 27892, 27897, {f: 2, c: 27903}, {f: 2, c: 27906}, michael@0: {f: 2, c: 27909}, {f: 3, c: 27912}, 27917, {f: 3, c: 27919}, michael@0: {f: 4, c: 27923}, 27928, {f: 2, c: 27932}, {f: 6, c: 27935}, 27942, michael@0: {f: 2, c: 27944}, {f: 2, c: 27948}, {f: 2, c: 27951}, 27956, michael@0: {f: 3, c: 27958}, 27962, {f: 2, c: 27967}, 27970, 27972, 27977, 27980, michael@0: 27984, {f: 4, c: 27989}, 27995, 27997, 27999, {f: 2, c: 28001}, michael@0: {f: 2, c: 28004}, {f: 2, c: 28007}, {f: 3, c: 28011}, {f: 4, c: 28016}, michael@0: {f: 2, c: 28021}, {f: 2, c: 28026}, {f: 5, c: 28029}, {f: 2, c: 28035}, michael@0: 28038, {f: 2, c: 28042}, 28045, {f: 2, c: 28047}, 28050, {f: 5, c: 28054}, michael@0: 28060, 28066, 28069, {f: 2, c: 28076}, {f: 2, c: 28080}, {f: 2, c: 28083}, michael@0: {f: 2, c: 28086}, {f: 6, c: 28089}, {f: 3, c: 28097}, {f: 3, c: 28104}, michael@0: {f: 4, c: 28109}, {f: 4, c: 28114}, 28119, {f: 3, c: 28122}, 28127, michael@0: {f: 2, c: 28130}, 28133, {f: 3, c: 28135}, 28141, {f: 2, c: 28143}, 28146, michael@0: 28148, 28152, {f: 8, c: 28157}, {f: 4, c: 28166}, 28171, 28175, michael@0: {f: 2, c: 28178}, 28181, {f: 2, c: 28184}, {f: 2, c: 28187}, michael@0: {f: 2, c: 28190}, 28194, {f: 2, c: 28199}, 28202, 28206, {f: 2, c: 28208}, michael@0: 28211, {f: 3, c: 28213}, 28217, {f: 3, c: 28219}, {f: 4, c: 28223}, michael@0: {f: 8, c: 28229}, {f: 4, c: 28239}, 28245, 28247, {f: 2, c: 28249}, michael@0: {f: 2, c: 28252}, {f: 11, c: 28256}, {f: 2, c: 28268}, {f: 14, c: 28272}, michael@0: {f: 3, c: 28288}, 28292, {f: 2, c: 28295}, {f: 5, c: 28298}, michael@0: {f: 5, c: 28305}, 28311, {f: 3, c: 28313}, 28318, {f: 2, c: 28320}, michael@0: {f: 2, c: 28323}, 28326, {f: 2, c: 28328}, {f: 4, c: 28331}, 28336, 28339, michael@0: 28341, {f: 2, c: 28344}, 28348, {f: 3, c: 28350}, 28355, 28358, michael@0: {f: 3, c: 28360}, 28365, 28368, 28370, 28374, {f: 2, c: 28376}, michael@0: {f: 3, c: 28379}, 28387, 28391, {f: 2, c: 28394}, {f: 2, c: 28397}, michael@0: {f: 2, c: 28400}, 28403, {f: 2, c: 28405}, {f: 5, c: 28410}, 28416, michael@0: {f: 3, c: 28419}, {f: 2, c: 28423}, {f: 5, c: 28426}, {f: 3, c: 28432}, michael@0: {f: 4, c: 28438}, {f: 5, c: 28443}, 28449, {f: 4, c: 28453}, 28462, 28464, michael@0: {f: 2, c: 28468}, 28471, {f: 5, c: 28473}, 28480, {f: 4, c: 28482}, michael@0: {f: 3, c: 28488}, 28492, {f: 3, c: 28494}, {f: 2, c: 28498}, michael@0: {f: 3, c: 28501}, {f: 2, c: 28506}, 28509, {f: 3, c: 28511}, 28515, 28517, michael@0: {f: 6, c: 28519}, 28529, 28531, {f: 2, c: 28533}, 28537, 28539, michael@0: {f: 2, c: 28541}, {f: 3, c: 28545}, 28549, {f: 2, c: 28554}, michael@0: {f: 8, c: 28559}, {f: 4, c: 28568}, {f: 3, c: 28573}, {f: 2, c: 28578}, michael@0: {f: 2, c: 28581}, 28584, {f: 4, c: 28586}, {f: 2, c: 28591}, 28594, michael@0: {f: 2, c: 28596}, {f: 2, c: 28599}, {f: 6, c: 28602}, {f: 5, c: 28612}, michael@0: {f: 7, c: 28618}, {f: 2, c: 28627}, {f: 2, c: 28630}, {f: 2, c: 28633}, michael@0: {f: 2, c: 28636}, {f: 2, c: 28642}, {f: 6, c: 28645}, {f: 2, c: 28652}, michael@0: {f: 8, c: 28658}, 28667, 28669, {f: 6, c: 28671}, {f: 2, c: 28679}, 28682, michael@0: {f: 3, c: 28684}, 28688, {f: 3, c: 28690}, {f: 2, c: 28694}, 28697, 28700, michael@0: 28702, {f: 2, c: 28705}, {f: 3, c: 28708}, {f: 7, c: 28713}, 28721, michael@0: {f: 2, c: 28723}, {f: 3, c: 28726}, {f: 4, c: 28730}, {f: 4, c: 28735}, michael@0: {f: 7, c: 28741}, {f: 2, c: 28749}, 28752, {f: 3, c: 28754}, michael@0: {f: 2, c: 28758}, {f: 4, c: 28761}, {f: 4, c: 28767}, {f: 2, c: 28773}, michael@0: {f: 3, c: 28776}, 28782, {f: 4, c: 28785}, 28791, {f: 3, c: 28793}, 28797, michael@0: {f: 4, c: 28801}, {f: 3, c: 28806}, {f: 3, c: 28811}, {f: 3, c: 28815}, michael@0: 28819, {f: 2, c: 28823}, {f: 2, c: 28826}, {f: 13, c: 28830}, 28848, 28850, michael@0: {f: 3, c: 28852}, 28858, {f: 2, c: 28862}, {f: 4, c: 28868}, 28873, michael@0: {f: 4, c: 28875}, {f: 8, c: 28880}, 28890, {f: 3, c: 28892}, michael@0: {f: 4, c: 28896}, 28901, 28906, 28910, {f: 4, c: 28912}, {f: 2, c: 28917}, michael@0: 28920, {f: 3, c: 28922}, {f: 11, c: 28926}, {f: 5, c: 28939}, michael@0: {f: 2, c: 28945}, 28948, 28951, {f: 6, c: 28955}, {f: 4, c: 28962}, michael@0: {f: 8, c: 28967}, {f: 4, c: 28978}, {f: 14, c: 28983}, {f: 3, c: 28998}, michael@0: 29003, 29005, {f: 3, c: 29007}, {f: 9, c: 29011}, 29021, {f: 3, c: 29023}, michael@0: 29027, 29029, {f: 2, c: 29034}, 29037, {f: 3, c: 29039}, {f: 4, c: 29044}, michael@0: 29049, {f: 2, c: 29051}, {f: 6, c: 29054}, {f: 5, c: 29061}, michael@0: {f: 4, c: 29067}, {f: 2, c: 29072}, 29075, {f: 2, c: 29077}, michael@0: {f: 5, c: 29082}, {f: 7, c: 29089}, {f: 3, c: 29097}, {f: 4, c: 29101}, michael@0: 29106, 29108, {f: 3, c: 29110}, {f: 4, c: 29114}, {f: 2, c: 29119}, 29122, michael@0: {f: 4, c: 29124}, {f: 5, c: 29129}, {f: 3, c: 29135}, 29139, michael@0: {f: 3, c: 29142}, {f: 2, c: 29146}, {f: 2, c: 29149}, {f: 4, c: 29153}, michael@0: {f: 5, c: 29160}, {f: 5, c: 29167}, {f: 4, c: 29173}, {f: 2, c: 29178}, michael@0: 29181, {f: 7, c: 29183}, {f: 6, c: 29191}, {f: 2, c: 29198}, michael@0: {f: 10, c: 29201}, 29212, {f: 10, c: 29214}, 29225, 29227, michael@0: {f: 3, c: 29229}, {f: 2, c: 29235}, 29244, {f: 7, c: 29248}, michael@0: {f: 3, c: 29257}, {f: 4, c: 29262}, {f: 3, c: 29267}, 29271, 29274, 29276, michael@0: 29278, 29280, {f: 3, c: 29283}, 29288, {f: 4, c: 29290}, {f: 2, c: 29296}, michael@0: {f: 2, c: 29299}, {f: 3, c: 29302}, {f: 2, c: 29307}, {f: 2, c: 29314}, michael@0: {f: 5, c: 29317}, 29324, 29326, {f: 2, c: 29328}, {f: 3, c: 29331}, michael@0: {f: 8, c: 29335}, {f: 2, c: 29344}, {f: 4, c: 29347}, {f: 4, c: 29352}, michael@0: 29358, {f: 3, c: 29361}, 29365, {f: 6, c: 29370}, {f: 3, c: 29381}, michael@0: {f: 4, c: 29385}, 29391, 29393, {f: 4, c: 29395}, 29400, {f: 4, c: 29402}, michael@0: 29407, {f: 6, c: 29410}, {f: 2, c: 29418}, {f: 2, c: 29429}, michael@0: {f: 3, c: 29438}, 29442, {f: 6, c: 29444}, {f: 3, c: 29451}, michael@0: {f: 4, c: 29455}, 29460, {f: 3, c: 29464}, {f: 2, c: 29471}, michael@0: {f: 2, c: 29475}, {f: 3, c: 29478}, 29485, {f: 2, c: 29487}, michael@0: {f: 2, c: 29490}, 29493, 29498, {f: 2, c: 29500}, 29504, {f: 2, c: 29506}, michael@0: {f: 7, c: 29510}, {f: 2, c: 29518}, 29521, {f: 4, c: 29523}, michael@0: {f: 8, c: 29528}, {f: 7, c: 29537}, 29545, 29550, 29553, {f: 2, c: 29555}, michael@0: 29558, 29561, 29565, 29567, {f: 3, c: 29569}, {f: 2, c: 29573}, 29576, michael@0: 29578, {f: 2, c: 29580}, {f: 2, c: 29583}, {f: 4, c: 29586}, michael@0: {f: 4, c: 29591}, {f: 3, c: 29596}, {f: 2, c: 29600}, {f: 6, c: 29603}, michael@0: 29610, {f: 2, c: 29612}, 29617, {f: 3, c: 29620}, {f: 2, c: 29624}, michael@0: {f: 4, c: 29628}, 29633, {f: 5, c: 29635}, {f: 2, c: 29643}, 29646, michael@0: {f: 7, c: 29650}, {f: 4, c: 29658}, 29663, {f: 4, c: 29665}, 29670, 29672, michael@0: {f: 3, c: 29674}, {f: 4, c: 29678}, {f: 11, c: 29683}, {f: 4, c: 29695}, michael@0: 29700, {f: 2, c: 29703}, {f: 4, c: 29707}, {f: 9, c: 29713}, michael@0: {f: 6, c: 29724}, {f: 2, c: 29731}, 29735, 29737, 29739, 29741, 29743, michael@0: {f: 2, c: 29745}, {f: 5, c: 29751}, {f: 2, c: 29757}, 29760, michael@0: {f: 9, c: 29762}, {f: 9, c: 29772}, 29782, 29784, 29789, {f: 3, c: 29792}, michael@0: {f: 5, c: 29796}, {f: 2, c: 29803}, {f: 2, c: 29806}, {f: 5, c: 29809}, michael@0: {f: 6, c: 29816}, 29823, 29826, {f: 3, c: 29828}, 29832, 29834, michael@0: {f: 2, c: 29836}, 29839, {f: 11, c: 29841}, 29853, {f: 4, c: 29855}, michael@0: {f: 2, c: 29860}, {f: 6, c: 29866}, {f: 9, c: 29873}, {f: 2, c: 29883}, michael@0: {f: 12, c: 29886}, {f: 4, c: 29899}, {f: 2, c: 29904}, 29907, michael@0: {f: 5, c: 29909}, 29915, 29917, 29919, 29921, 29925, {f: 7, c: 29927}, michael@0: {f: 4, c: 29936}, 29941, {f: 7, c: 29944}, {f: 4, c: 29952}, michael@0: {f: 7, c: 29957}, 29966, 29968, 29970, {f: 4, c: 29972}, 29979, michael@0: {f: 2, c: 29981}, {f: 3, c: 29984}, 29988, {f: 2, c: 29990}, 29994, 29998, michael@0: 30004, 30006, 30009, {f: 2, c: 30012}, 30015, {f: 4, c: 30017}, michael@0: {f: 2, c: 30022}, {f: 2, c: 30025}, 30029, {f: 4, c: 30032}, michael@0: {f: 4, c: 30037}, {f: 4, c: 30046}, {f: 2, c: 30051}, {f: 3, c: 30055}, michael@0: {f: 6, c: 30060}, 30067, 30069, 30071, {f: 5, c: 30074}, {f: 3, c: 30080}, michael@0: {f: 2, c: 30084}, {f: 3, c: 30088}, {f: 3, c: 30092}, 30096, 30099, 30101, michael@0: 30104, {f: 2, c: 30107}, 30110, 30114, {f: 5, c: 30118}, 30125, michael@0: {f: 2, c: 30134}, {f: 2, c: 30138}, {f: 3, c: 30143}, 30150, michael@0: {f: 2, c: 30155}, {f: 4, c: 30158}, 30163, 30167, 30170, {f: 2, c: 30172}, michael@0: {f: 3, c: 30175}, 30181, 30185, {f: 4, c: 30188}, {f: 2, c: 30194}, michael@0: {f: 4, c: 30197}, {f: 2, c: 30202}, {f: 2, c: 30205}, 30212, michael@0: {f: 4, c: 30214}, {f: 2, c: 30222}, {f: 4, c: 30225}, 30230, 30234, michael@0: {f: 2, c: 30236}, 30243, 30248, 30252, {f: 2, c: 30254}, {f: 2, c: 30257}, michael@0: {f: 2, c: 30262}, {f: 2, c: 30265}, 30269, 30273, {f: 2, c: 30276}, 30280, michael@0: {f: 2, c: 30282}, {f: 6, c: 30286}, 30293, 30295, {f: 3, c: 30297}, 30301, michael@0: {f: 2, c: 30304}, 30310, 30312, 30314, {f: 3, c: 30323}, [12136, 30326], michael@0: 30327, {f: 2, c: 30329}, {f: 3, c: 30335}, 30339, 30341, {f: 2, c: 30345}, michael@0: {f: 2, c: 30348}, {f: 2, c: 30351}, 30354, {f: 2, c: 30356}, michael@0: {f: 2, c: 30359}, {f: 9, c: 30363}, {f: 9, c: 30373}, {f: 2, c: 30383}, michael@0: 30387, {f: 3, c: 30389}, 30393, {f: 4, c: 30395}, {f: 2, c: 30400}, michael@0: {f: 2, c: 30403}, 30407, 30409, {f: 2, c: 30411}, 30419, 30421, michael@0: {f: 2, c: 30425}, {f: 2, c: 30428}, 30432, 30434, 30438, {f: 6, c: 30440}, michael@0: 30448, 30451, {f: 3, c: 30453}, {f: 2, c: 30458}, 30461, {f: 2, c: 30463}, michael@0: {f: 2, c: 30466}, {f: 2, c: 30469}, 30474, 30476, {f: 11, c: 30478}, michael@0: {f: 4, c: 30491}, 30497, {f: 3, c: 30499}, 30503, {f: 3, c: 30506}, 30510, michael@0: {f: 5, c: 30512}, 30521, 30523, {f: 3, c: 30525}, 30530, {f: 3, c: 30532}, michael@0: {f: 7, c: 30536}, {f: 8, c: 30546}, {f: 2, c: 30556}, {f: 2, c: 30559}, michael@0: 30564, 30567, {f: 2, c: 30569}, {f: 12, c: 30573}, {f: 3, c: 30586}, michael@0: {f: 3, c: 30593}, {f: 6, c: 30598}, {f: 2, c: 30607}, {f: 5, c: 30611}, michael@0: {f: 5, c: 30617}, 30625, {f: 2, c: 30627}, 30630, 30632, 30635, michael@0: {f: 2, c: 30638}, {f: 2, c: 30641}, 30644, {f: 5, c: 30646}, 30654, michael@0: {f: 7, c: 30656}, {f: 5, c: 30664}, {f: 9, c: 30670}, {f: 2, c: 30680}, michael@0: {f: 5, c: 30685}, 30692, 30694, 30696, 30698, {f: 3, c: 30704}, michael@0: {f: 2, c: 30708}, 30711, {f: 4, c: 30713}, {f: 6, c: 30723}, michael@0: {f: 2, c: 30730}, {f: 3, c: 30734}, 30739, 30741, 30745, 30747, 30750, michael@0: {f: 3, c: 30752}, 30756, 30760, {f: 2, c: 30762}, {f: 2, c: 30766}, michael@0: {f: 3, c: 30769}, {f: 2, c: 30773}, 30781, 30783, {f: 2, c: 30785}, 30788, michael@0: 30790, {f: 4, c: 30792}, 30797, 30799, 30801, {f: 2, c: 30803}, michael@0: {f: 5, c: 30808}, {f: 6, c: 30814}, {f: 3, c: 30821}, 30825, michael@0: {f: 7, c: 30832}, {f: 4, c: 30840}, {f: 10, c: 30845}, 30856, michael@0: {f: 2, c: 30858}, {f: 2, c: 30863}, 30866, {f: 3, c: 30868}, 30873, michael@0: {f: 2, c: 30877}, 30880, 30882, 30884, 30886, 30888, {f: 3, c: 30890}, michael@0: {f: 2, c: 30894}, {f: 3, c: 30901}, 30907, 30909, {f: 2, c: 30911}, michael@0: {f: 3, c: 30914}, {f: 3, c: 30918}, {f: 4, c: 30924}, {f: 3, c: 30929}, michael@0: {f: 3, c: 30934}, {f: 8, c: 30939}, {f: 3, c: 30948}, {f: 3, c: 30953}, michael@0: {f: 2, c: 30957}, {f: 2, c: 30960}, 30963, {f: 2, c: 30965}, michael@0: {f: 2, c: 30968}, {f: 2, c: 30971}, {f: 3, c: 30974}, {f: 3, c: 30978}, michael@0: {f: 8, c: 30982}, {f: 4, c: 30991}, {f: 5, c: 30996}, {f: 4, c: 31002}, michael@0: {f: 5, c: 31007}, 31013, {f: 3, c: 31015}, {f: 4, c: 31021}, michael@0: {f: 2, c: 31026}, {f: 5, c: 31029}, 31037, 31039, {f: 4, c: 31042}, 31047, michael@0: {f: 9, c: 31050}, {f: 2, c: 31060}, {f: 2, c: 31064}, 31073, michael@0: {f: 2, c: 31075}, 31078, {f: 4, c: 31081}, 31086, {f: 7, c: 31088}, 31097, michael@0: {f: 5, c: 31099}, {f: 2, c: 31106}, {f: 4, c: 31110}, {f: 2, c: 31115}, michael@0: {f: 10, c: 31120}, {f: 11, c: 31131}, {f: 2, c: 31144}, {f: 3, c: 31147}, michael@0: 31151, 31154, {f: 4, c: 31156}, [12145, 31160], 31164, 31167, 31170, michael@0: {f: 2, c: 31172}, {f: 2, c: 31175}, 31178, 31180, {f: 3, c: 31182}, michael@0: {f: 2, c: 31187}, {f: 2, c: 31190}, {f: 6, c: 31193}, {f: 3, c: 31200}, michael@0: 31205, 31208, 31210, 31212, 31214, {f: 7, c: 31217}, {f: 2, c: 31225}, michael@0: 31228, {f: 2, c: 31230}, 31233, {f: 2, c: 31236}, {f: 4, c: 31239}, 31244, michael@0: {f: 5, c: 31247}, {f: 2, c: 31253}, {f: 2, c: 31256}, {f: 3, c: 31259}, michael@0: 31263, {f: 2, c: 31265}, {f: 10, c: 31268}, {f: 2, c: 31279}, 31282, michael@0: {f: 3, c: 31284}, 31288, 31290, 31294, {f: 5, c: 31297}, {f: 5, c: 31303}, michael@0: {f: 2, c: 31311}, {f: 5, c: 31314}, {f: 9, c: 31320}, {f: 6, c: 31331}, michael@0: 31338, {f: 4, c: 31340}, {f: 3, c: 31345}, 31349, {f: 4, c: 31355}, 31362, michael@0: 31365, 31367, {f: 4, c: 31369}, {f: 3, c: 31374}, {f: 2, c: 31379}, michael@0: {f: 3, c: 31385}, 31390, {f: 4, c: 31393}, 31399, 31403, {f: 4, c: 31407}, michael@0: {f: 2, c: 31412}, {f: 3, c: 31415}, {f: 4, c: 31419}, {f: 4, c: 31424}, michael@0: 31430, 31433, {f: 10, c: 31436}, {f: 2, c: 31447}, {f: 4, c: 31450}, michael@0: {f: 2, c: 31457}, 31460, {f: 3, c: 31463}, {f: 2, c: 31467}, 31470, michael@0: {f: 6, c: 31472}, {f: 2, c: 31479}, {f: 2, c: 31483}, 31486, michael@0: {f: 3, c: 31488}, 31493, 31495, 31497, {f: 3, c: 31500}, 31504, michael@0: {f: 2, c: 31506}, {f: 3, c: 31510}, 31514, {f: 2, c: 31516}, 31519, michael@0: {f: 3, c: 31521}, 31527, 31529, 31533, {f: 2, c: 31535}, 31538, michael@0: {f: 4, c: 31540}, 31545, 31547, 31549, {f: 6, c: 31551}, 31560, 31562, michael@0: {f: 2, c: 31565}, 31571, 31573, 31575, 31577, 31580, {f: 2, c: 31582}, michael@0: 31585, {f: 4, c: 31587}, {f: 6, c: 31592}, {f: 2, c: 31599}, michael@0: {f: 2, c: 31603}, 31606, 31608, 31610, {f: 2, c: 31612}, 31615, michael@0: {f: 4, c: 31617}, {f: 5, c: 31622}, 31628, {f: 2, c: 31630}, michael@0: {f: 3, c: 31633}, 31638, {f: 4, c: 31640}, {f: 3, c: 31646}, michael@0: {f: 3, c: 31651}, {f: 3, c: 31662}, {f: 2, c: 31666}, {f: 3, c: 31669}, michael@0: {f: 7, c: 31673}, {f: 2, c: 31682}, 31685, 31688, 31690, {f: 4, c: 31693}, michael@0: 31698, {f: 5, c: 31700}, {f: 2, c: 31707}, {f: 3, c: 31710}, michael@0: {f: 2, c: 31714}, {f: 2, c: 31719}, {f: 3, c: 31723}, {f: 2, c: 31727}, michael@0: 31730, {f: 3, c: 31732}, {f: 4, c: 31736}, 31741, 31743, {f: 6, c: 31745}, michael@0: {f: 3, c: 31752}, 31758, {f: 6, c: 31760}, {f: 7, c: 31767}, 31776, 31778, michael@0: {f: 2, c: 31780}, {f: 2, c: 31784}, {f: 12, c: 31788}, {f: 4, c: 31801}, michael@0: 31810, {f: 8, c: 31812}, {f: 14, c: 31822}, {f: 2, c: 31837}, michael@0: {f: 3, c: 31841}, {f: 4, c: 31845}, 31851, 31853, {f: 3, c: 31855}, michael@0: {f: 6, c: 31861}, {f: 11, c: 31870}, {f: 7, c: 31882}, {f: 2, c: 31891}, michael@0: 31894, {f: 3, c: 31897}, {f: 2, c: 31904}, 31907, {f: 4, c: 31910}, michael@0: {f: 3, c: 31915}, {f: 2, c: 31919}, {f: 5, c: 31924}, {f: 2, c: 31930}, michael@0: {f: 2, c: 31935}, {f: 3, c: 31938}, 31942, 31945, 31947, {f: 7, c: 31950}, michael@0: 31960, {f: 2, c: 31962}, {f: 6, c: 31969}, {f: 6, c: 31977}, 31985, 31987, michael@0: 31989, 31991, 31994, {f: 2, c: 31996}, 31999, 32001, 32003, 32012, michael@0: {f: 2, c: 32014}, {f: 2, c: 32017}, 32022, 32024, {f: 3, c: 32029}, michael@0: {f: 4, c: 32035}, {f: 3, c: 32040}, {f: 3, c: 32044}, {f: 5, c: 32052}, michael@0: 32059, {f: 2, c: 32061}, 32065, 32067, 32069, {f: 7, c: 32071}, 32079, michael@0: {f: 12, c: 32081}, {f: 2, c: 32095}, {f: 3, c: 32099}, 32103, michael@0: {f: 5, c: 32105}, {f: 2, c: 32111}, {f: 2, c: 32116}, 32120, michael@0: {f: 7, c: 32122}, 32130, {f: 2, c: 32132}, 32135, {f: 5, c: 32138}, michael@0: {f: 3, c: 32144}, {f: 8, c: 32148}, 32157, {f: 3, c: 32159}, michael@0: {f: 2, c: 32164}, {f: 4, c: 32167}, 32175, {f: 3, c: 32181}, 32188, michael@0: {f: 4, c: 32192}, {f: 2, c: 32197}, {f: 2, c: 32200}, {f: 5, c: 32204}, michael@0: 32211, {f: 2, c: 32213}, {f: 3, c: 32218}, 32223, 32226, {f: 2, c: 32228}, michael@0: 32231, {f: 2, c: 32234}, {f: 2, c: 32237}, 32240, 32243, 32245, michael@0: {f: 2, c: 32247}, 32250, {f: 12, c: 32252}, {f: 4, c: 32268}, michael@0: {f: 9, c: 32274}, 32284, {f: 3, c: 32288}, {f: 3, c: 32292}, michael@0: {f: 3, c: 32296}, 32300, {f: 2, c: 32303}, 32307, 32312, 32314, 32316, michael@0: {f: 2, c: 32319}, {f: 3, c: 32322}, {f: 10, c: 32328}, 32339, michael@0: {f: 4, c: 32342}, {f: 3, c: 32347}, {f: 3, c: 32351}, {f: 6, c: 32355}, michael@0: 32364, {f: 2, c: 32369}, {f: 5, c: 32372}, {f: 2, c: 32378}, michael@0: {f: 3, c: 32383}, {f: 5, c: 32387}, 32393, 32395, 32398, {f: 3, c: 32400}, michael@0: 32405, 32407, {f: 2, c: 32409}, {f: 2, c: 32413}, 32430, 32436, michael@0: {f: 2, c: 32443}, 32470, 32484, 32492, 32505, 32522, 32528, 32542, 32567, michael@0: 32569, {f: 7, c: 32571}, 32579, {f: 6, c: 32582}, 32589, 32591, michael@0: {f: 2, c: 32594}, 32598, 32601, {f: 4, c: 32603}, 32608, {f: 5, c: 32611}, michael@0: {f: 3, c: 32619}, 32623, 32627, {f: 2, c: 32629}, 32632, {f: 4, c: 32634}, michael@0: {f: 2, c: 32639}, {f: 3, c: 32642}, 32647, 32649, 32651, 32653, michael@0: {f: 5, c: 32655}, {f: 5, c: 32661}, {f: 2, c: 32667}, 32672, michael@0: {f: 2, c: 32674}, 32678, 32680, {f: 5, c: 32682}, 32689, {f: 5, c: 32691}, michael@0: {f: 2, c: 32698}, 32702, 32704, {f: 3, c: 32706}, {f: 4, c: 32710}, 32715, michael@0: 32717, {f: 3, c: 32719}, 32723, {f: 2, c: 32726}, {f: 6, c: 32729}, michael@0: {f: 3, c: 32738}, {f: 2, c: 32743}, {f: 4, c: 32746}, 32751, 32754, michael@0: {f: 5, c: 32756}, 32762, {f: 3, c: 32765}, 32770, {f: 4, c: 32775}, michael@0: {f: 2, c: 32782}, 32785, 32787, {f: 2, c: 32794}, {f: 3, c: 32797}, 32801, michael@0: {f: 2, c: 32803}, 32811, 32813, {f: 2, c: 32815}, 32818, 32820, michael@0: {f: 2, c: 32825}, 32828, 32830, {f: 2, c: 32832}, {f: 2, c: 32836}, michael@0: {f: 3, c: 32839}, {f: 4, c: 32846}, 32851, 32853, 32855, 32857, michael@0: {f: 3, c: 32859}, {f: 10, c: 32863}, {f: 4, c: 32875}, 32884, 32888, michael@0: {f: 3, c: 32890}, {f: 2, c: 32897}, 32904, 32906, {f: 6, c: 32909}, michael@0: {f: 2, c: 32916}, 32919, 32921, 32926, 32931, {f: 3, c: 32934}, 32940, michael@0: 32944, 32947, {f: 2, c: 32949}, {f: 2, c: 32952}, 32955, 32965, michael@0: {f: 5, c: 32967}, {f: 7, c: 32975}, 32984, {f: 2, c: 32991}, michael@0: {f: 2, c: 32994}, 32998, 33006, 33013, 33015, 33017, 33019, michael@0: {f: 4, c: 33022}, {f: 2, c: 33027}, {f: 2, c: 33031}, {f: 2, c: 33035}, michael@0: 33045, 33047, 33049, {f: 2, c: 33052}, {f: 13, c: 33055}, {f: 2, c: 33069}, michael@0: 33072, {f: 3, c: 33075}, 33079, {f: 4, c: 33082}, {f: 7, c: 33087}, 33095, michael@0: 33097, 33101, 33103, 33106, {f: 2, c: 33111}, {f: 5, c: 33115}, michael@0: {f: 3, c: 33122}, 33128, 33130, 33132, 33135, {f: 2, c: 33138}, michael@0: {f: 3, c: 33141}, 33153, {f: 5, c: 33155}, 33161, {f: 4, c: 33163}, 33168, michael@0: {f: 6, c: 33170}, 33177, {f: 2, c: 33182}, {f: 2, c: 33185}, michael@0: {f: 2, c: 33188}, 33191, {f: 8, c: 33195}, {f: 6, c: 33204}, 33212, michael@0: {f: 2, c: 33220}, {f: 2, c: 33223}, 33227, 33230, {f: 8, c: 33232}, 33241, michael@0: {f: 4, c: 33243}, {f: 2, c: 33249}, {f: 3, c: 33252}, 33257, 33259, michael@0: {f: 5, c: 33262}, {f: 5, c: 33269}, 33277, 33279, 33283, 33291, michael@0: {f: 2, c: 33294}, 33297, 33299, {f: 6, c: 33301}, 33309, 33312, michael@0: {f: 4, c: 33316}, 33321, 33326, 33330, 33338, {f: 2, c: 33340}, michael@0: {f: 5, c: 33343}, {f: 2, c: 33349}, 33352, 33354, {f: 3, c: 33356}, michael@0: {f: 8, c: 33360}, {f: 4, c: 33371}, {f: 4, c: 33376}, 33381, 33383, michael@0: {f: 2, c: 33385}, {f: 2, c: 33388}, {f: 2, c: 33397}, [12171, 33400], michael@0: {f: 2, c: 33403}, {f: 2, c: 33408}, 33411, {f: 3, c: 33413}, 33417, 33420, michael@0: 33424, {f: 4, c: 33427}, {f: 2, c: 33434}, 33438, 33440, {f: 2, c: 33442}, michael@0: 33447, 33458, {f: 2, c: 33461}, 33466, 33468, {f: 2, c: 33471}, michael@0: {f: 2, c: 33474}, {f: 2, c: 33477}, 33481, 33488, 33494, {f: 2, c: 33497}, michael@0: 33501, 33506, {f: 3, c: 33512}, {f: 3, c: 33516}, 33520, {f: 2, c: 33522}, michael@0: {f: 2, c: 33525}, 33528, 33530, {f: 5, c: 33532}, {f: 2, c: 33546}, 33549, michael@0: 33552, {f: 2, c: 33554}, 33558, {f: 2, c: 33560}, {f: 10, c: 33565}, michael@0: {f: 2, c: 33577}, 33582, 33584, 33586, 33591, 33595, {f: 3, c: 33597}, michael@0: {f: 2, c: 33601}, {f: 2, c: 33604}, 33608, {f: 5, c: 33610}, 33619, michael@0: {f: 5, c: 33621}, 33629, 33634, {f: 7, c: 33648}, {f: 2, c: 33657}, michael@0: {f: 7, c: 33662}, {f: 2, c: 33671}, {f: 3, c: 33675}, {f: 3, c: 33679}, michael@0: {f: 2, c: 33684}, 33687, {f: 2, c: 33689}, 33693, 33695, 33697, michael@0: {f: 4, c: 33699}, {f: 4, c: 33708}, 33717, 33723, {f: 2, c: 33726}, michael@0: {f: 3, c: 33730}, 33734, {f: 2, c: 33736}, 33739, {f: 2, c: 33741}, michael@0: {f: 4, c: 33744}, 33749, 33751, {f: 3, c: 33753}, 33758, {f: 3, c: 33762}, michael@0: {f: 3, c: 33766}, {f: 4, c: 33771}, {f: 5, c: 33779}, {f: 3, c: 33786}, michael@0: {f: 3, c: 33790}, 33794, 33797, {f: 2, c: 33800}, 33808, {f: 6, c: 33810}, michael@0: {f: 3, c: 33817}, {f: 6, c: 33822}, {f: 3, c: 33833}, {f: 4, c: 33837}, michael@0: {f: 3, c: 33842}, {f: 2, c: 33846}, {f: 3, c: 33849}, {f: 8, c: 33854}, michael@0: {f: 2, c: 33863}, {f: 7, c: 33866}, {f: 4, c: 33875}, 33880, michael@0: {f: 4, c: 33885}, 33890, 33893, {f: 2, c: 33895}, 33898, 33902, 33904, michael@0: 33906, 33908, 33913, {f: 7, c: 33915}, {f: 4, c: 33923}, 33930, 33933, michael@0: {f: 4, c: 33935}, {f: 2, c: 33941}, 33944, {f: 2, c: 33946}, michael@0: {f: 4, c: 33949}, {f: 13, c: 33954}, {f: 2, c: 33968}, 33971, michael@0: {f: 3, c: 33973}, 33979, 33982, {f: 2, c: 33986}, {f: 4, c: 33989}, 33996, michael@0: {f: 2, c: 33998}, 34002, {f: 2, c: 34004}, {f: 6, c: 34007}, 34014, michael@0: {f: 2, c: 34017}, 34020, {f: 5, c: 34023}, 34029, {f: 11, c: 34033}, 34046, michael@0: {f: 12, c: 34048}, {f: 4, c: 34061}, 34066, {f: 2, c: 34069}, michael@0: {f: 2, c: 34072}, {f: 3, c: 34075}, 34080, 34082, {f: 2, c: 34084}, michael@0: {f: 4, c: 34087}, {f: 9, c: 34094}, {f: 3, c: 34110}, 34114, michael@0: {f: 2, c: 34116}, 34119, {f: 3, c: 34123}, {f: 3, c: 34127}, 34132, 34135, michael@0: {f: 4, c: 34138}, {f: 3, c: 34143}, 34147, {f: 3, c: 34149}, michael@0: {f: 2, c: 34155}, {f: 4, c: 34158}, 34163, {f: 2, c: 34165}, 34168, michael@0: {f: 2, c: 34172}, {f: 5, c: 34175}, 34182, 34185, 34187, {f: 2, c: 34189}, michael@0: 34192, {f: 2, c: 34194}, {f: 6, c: 34197}, {f: 2, c: 34205}, michael@0: {f: 4, c: 34208}, 34213, 34215, {f: 3, c: 34219}, {f: 6, c: 34225}, 34232, michael@0: {f: 6, c: 34235}, {f: 7, c: 34242}, {f: 3, c: 34250}, {f: 2, c: 34257}, michael@0: 34260, {f: 6, c: 34262}, {f: 6, c: 34270}, {f: 3, c: 34278}, michael@0: {f: 9, c: 34283}, 34293, {f: 2, c: 34295}, {f: 3, c: 34300}, michael@0: {f: 4, c: 34304}, {f: 3, c: 34312}, {f: 5, c: 34316}, {f: 4, c: 34322}, michael@0: {f: 3, c: 34327}, {f: 3, c: 34331}, {f: 3, c: 34335}, {f: 4, c: 34339}, michael@0: 34344, {f: 3, c: 34346}, {f: 10, c: 34350}, 34361, 34363, {f: 2, c: 34365}, michael@0: {f: 13, c: 34368}, {f: 2, c: 34386}, {f: 4, c: 34390}, 34395, 34397, michael@0: {f: 2, c: 34400}, {f: 4, c: 34403}, {f: 3, c: 34408}, 34413, michael@0: {f: 2, c: 34415}, {f: 7, c: 34418}, {f: 7, c: 34435}, {f: 5, c: 34446}, michael@0: 34452, {f: 6, c: 34454}, {f: 5, c: 34462}, {f: 2, c: 34469}, 34475, michael@0: {f: 2, c: 34477}, {f: 2, c: 34482}, {f: 3, c: 34487}, {f: 5, c: 34491}, michael@0: {f: 3, c: 34497}, 34501, 34504, {f: 2, c: 34508}, {f: 2, c: 34514}, michael@0: {f: 3, c: 34517}, 34522, {f: 2, c: 34524}, {f: 4, c: 34528}, michael@0: {f: 4, c: 34533}, {f: 3, c: 34538}, 34543, {f: 3, c: 34549}, michael@0: {f: 3, c: 34555}, 34559, 34561, {f: 2, c: 34564}, {f: 2, c: 34571}, michael@0: {f: 4, c: 34574}, 34580, 34582, 34585, 34587, 34589, {f: 2, c: 34591}, michael@0: 34596, {f: 3, c: 34598}, {f: 4, c: 34602}, {f: 2, c: 34607}, michael@0: {f: 2, c: 34610}, {f: 2, c: 34613}, {f: 3, c: 34616}, {f: 2, c: 34620}, michael@0: {f: 7, c: 34624}, {f: 2, c: 34634}, 34637, {f: 4, c: 34639}, 34644, 34646, michael@0: 34648, {f: 6, c: 34650}, {f: 2, c: 34657}, {f: 7, c: 34663}, 34671, michael@0: {f: 3, c: 34673}, 34677, 34679, {f: 2, c: 34681}, {f: 3, c: 34687}, michael@0: {f: 2, c: 34694}, {f: 2, c: 34697}, 34700, {f: 5, c: 34702}, michael@0: {f: 3, c: 34708}, {f: 6, c: 34712}, {f: 2, c: 34720}, {f: 5, c: 34723}, michael@0: {f: 2, c: 34729}, 34734, {f: 3, c: 34736}, 34740, {f: 4, c: 34742}, 34748, michael@0: {f: 2, c: 34750}, {f: 3, c: 34753}, 34757, 34759, 34761, {f: 2, c: 34764}, michael@0: {f: 2, c: 34767}, {f: 7, c: 34772}, {f: 4, c: 34780}, {f: 2, c: 34785}, michael@0: 34788, {f: 4, c: 34790}, 34795, 34797, {f: 2, c: 34800}, {f: 3, c: 34803}, michael@0: {f: 2, c: 34807}, 34810, {f: 2, c: 34812}, {f: 4, c: 34815}, 34820, michael@0: {f: 3, c: 34823}, {f: 5, c: 34827}, 34834, 34836, {f: 4, c: 34839}, michael@0: {f: 3, c: 34844}, 34848, {f: 13, c: 34852}, {f: 3, c: 34867}, michael@0: {f: 2, c: 34871}, 34874, {f: 3, c: 34877}, {f: 3, c: 34881}, michael@0: {f: 3, c: 34887}, 34891, {f: 5, c: 34894}, {f: 2, c: 34901}, 34904, 34906, michael@0: 34908, {f: 3, c: 34910}, {f: 2, c: 34918}, 34922, 34925, 34927, 34929, michael@0: {f: 4, c: 34931}, 34936, {f: 3, c: 34938}, 34944, 34947, {f: 2, c: 34950}, michael@0: {f: 2, c: 34953}, 34956, {f: 4, c: 34958}, {f: 3, c: 34963}, michael@0: {f: 5, c: 34967}, {f: 5, c: 34973}, 34979, {f: 6, c: 34981}, 34988, michael@0: {f: 3, c: 34990}, {f: 5, c: 34994}, {f: 4, c: 35000}, {f: 4, c: 35005}, michael@0: {f: 2, c: 35011}, {f: 2, c: 35015}, {f: 3, c: 35019}, {f: 2, c: 35024}, michael@0: 35027, {f: 2, c: 35030}, {f: 2, c: 35034}, 35038, {f: 2, c: 35040}, michael@0: {f: 2, c: 35046}, {f: 7, c: 35049}, 35058, {f: 3, c: 35061}, michael@0: {f: 2, c: 35066}, {f: 3, c: 35071}, {f: 4, c: 35075}, {f: 2, c: 35080}, michael@0: {f: 5, c: 35083}, 35089, {f: 5, c: 35092}, {f: 5, c: 35100}, michael@0: {f: 3, c: 35106}, {f: 4, c: 35110}, {f: 4, c: 35116}, 35121, 35125, 35127, michael@0: {f: 2, c: 35129}, {f: 5, c: 35132}, {f: 2, c: 35138}, {f: 2, c: 35141}, michael@0: {f: 14, c: 35144}, {f: 6, c: 35159}, {f: 3, c: 35169}, 35173, michael@0: {f: 3, c: 35175}, 35179, {f: 2, c: 35181}, {f: 2, c: 35184}, michael@0: {f: 8, c: 35187}, {f: 2, c: 35196}, [12177, 35198], 35200, 35202, michael@0: {f: 2, c: 35204}, {f: 4, c: 35207}, {f: 3, c: 35212}, {f: 3, c: 35216}, michael@0: {f: 2, c: 35220}, 35223, {f: 8, c: 35225}, {f: 4, c: 35234}, michael@0: {f: 3, c: 35239}, 35243, {f: 2, c: 35245}, {f: 2, c: 35248}, michael@0: {f: 4, c: 35251}, {f: 2, c: 35256}, {f: 2, c: 35259}, 35262, 35267, 35277, michael@0: {f: 3, c: 35283}, {f: 3, c: 35287}, 35291, 35293, {f: 4, c: 35295}, 35300, michael@0: {f: 4, c: 35303}, {f: 3, c: 35308}, {f: 3, c: 35312}, 35317, 35319, michael@0: {f: 7, c: 35321}, {f: 3, c: 35332}, 35337, 35339, 35341, 35343, michael@0: {f: 2, c: 35345}, 35348, 35351, {f: 2, c: 35353}, 35356, 35358, michael@0: {f: 3, c: 35360}, 35364, {f: 4, c: 35366}, {f: 2, c: 35371}, michael@0: {f: 3, c: 35374}, {f: 2, c: 35378}, 35381, {f: 3, c: 35383}, michael@0: {f: 3, c: 35387}, {f: 2, c: 35391}, {f: 4, c: 35394}, 35399, michael@0: {f: 5, c: 35401}, 35407, 35409, 35411, {f: 2, c: 35414}, {f: 2, c: 35417}, michael@0: {f: 2, c: 35420}, {f: 2, c: 35423}, {f: 2, c: 35428}, {f: 2, c: 35431}, michael@0: 35434, 35439, 35444, {f: 3, c: 35446}, {f: 2, c: 35450}, {f: 2, c: 35453}, michael@0: {f: 4, c: 35456}, 35464, {f: 2, c: 35467}, {f: 3, c: 35470}, 35476, michael@0: {f: 2, c: 35478}, 35481, {f: 3, c: 35483}, 35487, 35490, 35495, michael@0: {f: 3, c: 35497}, {f: 3, c: 35501}, 35505, {f: 3, c: 35507}, michael@0: {f: 2, c: 35511}, {f: 2, c: 35514}, {f: 2, c: 35517}, {f: 2, c: 35520}, michael@0: 35523, {f: 2, c: 35525}, 35528, 35530, 35532, 35534, 35536, michael@0: {f: 3, c: 35539}, {f: 3, c: 35544}, 35549, {f: 3, c: 35551}, 35555, 35557, michael@0: {f: 3, c: 35560}, 35564, {f: 2, c: 35567}, 35570, {f: 2, c: 35572}, 35577, michael@0: 35579, 35581, 35583, 35587, 35590, {f: 2, c: 35592}, {f: 3, c: 35595}, michael@0: 35599, {f: 3, c: 35601}, 35605, 35608, 35612, {f: 3, c: 35614}, michael@0: {f: 4, c: 35618}, 35623, {f: 2, c: 35625}, {f: 5, c: 35630}, michael@0: {f: 5, c: 35636}, {f: 4, c: 35642}, {f: 10, c: 35647}, {f: 4, c: 35658}, michael@0: {f: 6, c: 35664}, 35671, 35675, {f: 9, c: 35677}, {f: 4, c: 35687}, michael@0: {f: 2, c: 35693}, {f: 3, c: 35697}, {f: 2, c: 35701}, {f: 5, c: 35704}, michael@0: {f: 2, c: 35710}, {f: 9, c: 35713}, {f: 3, c: 35723}, {f: 3, c: 35727}, michael@0: 35732, {f: 5, c: 35735}, 35741, 35743, 35756, 35761, 35771, 35783, 35792, michael@0: 35818, 35849, 35870, {f: 9, c: 35896}, {f: 4, c: 35906}, {f: 2, c: 35914}, michael@0: {f: 3, c: 35917}, {f: 4, c: 35921}, {f: 4, c: 35926}, {f: 6, c: 35931}, michael@0: {f: 7, c: 35939}, {f: 7, c: 35948}, {f: 4, c: 35956}, {f: 7, c: 35963}, michael@0: {f: 2, c: 35971}, {f: 3, c: 35974}, 35979, {f: 7, c: 35981}, michael@0: {f: 3, c: 35989}, {f: 4, c: 35993}, 35999, {f: 4, c: 36003}, michael@0: {f: 2, c: 36013}, 36017, 36021, 36025, 36030, 36038, 36041, michael@0: {f: 6, c: 36043}, 36052, {f: 4, c: 36054}, 36059, 36061, 36063, 36069, michael@0: {f: 2, c: 36072}, {f: 6, c: 36078}, {f: 5, c: 36085}, {f: 5, c: 36095}, michael@0: {f: 2, c: 36102}, 36105, 36108, 36110, {f: 5, c: 36113}, {f: 4, c: 36119}, michael@0: 36128, {f: 2, c: 36177}, 36183, 36191, 36197, {f: 3, c: 36200}, 36204, michael@0: {f: 2, c: 36206}, {f: 2, c: 36209}, {f: 9, c: 36216}, {f: 2, c: 36226}, michael@0: {f: 4, c: 36230}, {f: 5, c: 36236}, {f: 2, c: 36242}, {f: 3, c: 36246}, michael@0: {f: 5, c: 36250}, {f: 3, c: 36256}, {f: 4, c: 36260}, {f: 8, c: 36265}, michael@0: {f: 2, c: 36278}, 36281, 36283, 36285, {f: 3, c: 36288}, 36293, michael@0: {f: 4, c: 36295}, 36301, 36304, {f: 4, c: 36306}, {f: 2, c: 36312}, 36316, michael@0: {f: 3, c: 36320}, {f: 3, c: 36325}, 36329, {f: 2, c: 36333}, michael@0: {f: 3, c: 36336}, 36340, 36342, 36348, {f: 7, c: 36350}, {f: 3, c: 36358}, michael@0: 36363, {f: 2, c: 36365}, {f: 3, c: 36369}, {f: 8, c: 36373}, michael@0: {f: 2, c: 36384}, {f: 5, c: 36388}, 36395, 36397, 36400, {f: 2, c: 36402}, michael@0: {f: 3, c: 36406}, {f: 2, c: 36411}, {f: 2, c: 36414}, 36419, michael@0: {f: 2, c: 36421}, {f: 4, c: 36429}, {f: 2, c: 36435}, {f: 3, c: 36438}, michael@0: {f: 9, c: 36442}, {f: 2, c: 36452}, {f: 2, c: 36455}, {f: 2, c: 36458}, michael@0: 36462, 36465, 36467, 36469, {f: 3, c: 36471}, 36475, {f: 2, c: 36477}, michael@0: 36480, {f: 3, c: 36482}, 36486, 36488, 36492, 36494, {f: 5, c: 36501}, michael@0: 36507, 36509, {f: 2, c: 36511}, {f: 3, c: 36514}, {f: 3, c: 36519}, michael@0: {f: 2, c: 36525}, {f: 2, c: 36528}, {f: 7, c: 36531}, {f: 5, c: 36539}, michael@0: {f: 9, c: 36545}, {f: 3, c: 36559}, 36563, {f: 6, c: 36565}, michael@0: {f: 3, c: 36572}, {f: 4, c: 36576}, {f: 6, c: 36581}, {f: 6, c: 36588}, michael@0: {f: 5, c: 36595}, 36605, {f: 4, c: 36607}, 36612, 36614, 36616, michael@0: {f: 7, c: 36619}, 36627, {f: 5, c: 36630}, {f: 5, c: 36640}, michael@0: {f: 2, c: 36647}, {f: 4, c: 36651}, {f: 3, c: 36656}, {f: 4, c: 36660}, michael@0: {f: 2, c: 36665}, {f: 2, c: 36668}, {f: 2, c: 36672}, 36675, michael@0: {f: 2, c: 36679}, {f: 3, c: 36682}, {f: 5, c: 36687}, {f: 10, c: 36693}, michael@0: 36704, 36707, 36709, 36714, 36736, 36748, 36754, 36765, {f: 3, c: 36768}, michael@0: {f: 2, c: 36772}, 36775, 36778, 36780, {f: 2, c: 36787}, [12193, 36789], michael@0: {f: 2, c: 36791}, {f: 3, c: 36794}, {f: 2, c: 36799}, 36803, 36806, michael@0: {f: 5, c: 36809}, 36815, 36818, {f: 2, c: 36822}, 36826, {f: 2, c: 36832}, michael@0: 36835, 36839, 36844, 36847, {f: 2, c: 36849}, {f: 2, c: 36853}, michael@0: {f: 3, c: 36858}, {f: 2, c: 36862}, {f: 2, c: 36871}, 36876, 36878, 36883, michael@0: 36888, 36892, {f: 2, c: 36900}, {f: 6, c: 36903}, {f: 2, c: 36912}, michael@0: {f: 2, c: 36915}, 36919, {f: 2, c: 36921}, 36925, {f: 2, c: 36927}, 36931, michael@0: {f: 2, c: 36933}, {f: 3, c: 36936}, 36940, 36950, {f: 2, c: 36953}, 36957, michael@0: 36959, 36961, 36964, {f: 2, c: 36966}, {f: 3, c: 36970}, {f: 3, c: 36975}, michael@0: 36979, 36982, 36985, 36987, 36990, {f: 2, c: 36997}, 37001, michael@0: {f: 3, c: 37004}, 37010, 37012, 37014, 37016, 37018, 37020, michael@0: {f: 3, c: 37022}, {f: 2, c: 37028}, {f: 3, c: 37031}, 37035, 37037, 37042, michael@0: 37047, {f: 2, c: 37052}, {f: 2, c: 37055}, {f: 2, c: 37058}, 37062, michael@0: {f: 2, c: 37064}, {f: 3, c: 37067}, 37074, {f: 3, c: 37076}, michael@0: {f: 3, c: 37080}, 37086, 37088, {f: 3, c: 37091}, {f: 2, c: 37097}, 37100, michael@0: 37102, {f: 4, c: 37104}, {f: 2, c: 37110}, {f: 4, c: 37113}, michael@0: {f: 3, c: 37119}, 37123, 37125, {f: 2, c: 37127}, {f: 8, c: 37130}, 37139, michael@0: 37141, {f: 2, c: 37143}, {f: 4, c: 37146}, {f: 3, c: 37151}, michael@0: {f: 3, c: 37156}, {f: 5, c: 37160}, 37166, 37171, 37173, {f: 2, c: 37175}, michael@0: {f: 8, c: 37179}, {f: 2, c: 37188}, 37191, 37201, {f: 4, c: 37203}, michael@0: {f: 2, c: 37208}, {f: 2, c: 37211}, {f: 2, c: 37215}, {f: 3, c: 37222}, michael@0: 37227, 37229, 37235, {f: 3, c: 37242}, {f: 5, c: 37248}, 37254, 37256, michael@0: 37258, {f: 2, c: 37262}, {f: 3, c: 37267}, {f: 3, c: 37271}, michael@0: {f: 5, c: 37277}, {f: 6, c: 37284}, {f: 4, c: 37296}, {f: 4, c: 37302}, michael@0: {f: 5, c: 37307}, 37314, 37316, [12196, 37318], 37320, 37328, 37334, michael@0: {f: 2, c: 37338}, {f: 5, c: 37342}, {f: 2, c: 37349}, 37352, michael@0: {f: 11, c: 37354}, 37366, 37368, {f: 5, c: 37371}, {f: 2, c: 37378}, michael@0: {f: 3, c: 37381}, {f: 3, c: 37386}, 37391, {f: 2, c: 37394}, michael@0: {f: 8, c: 37398}, {f: 4, c: 37407}, 37412, {f: 6, c: 37416}, 37423, michael@0: {f: 2, c: 37425}, {f: 2, c: 37429}, {f: 2, c: 37435}, {f: 4, c: 37441}, michael@0: {f: 2, c: 37446}, {f: 3, c: 37450}, {f: 3, c: 37454}, {f: 3, c: 37458}, michael@0: 37462, {f: 2, c: 37464}, {f: 2, c: 37468}, {f: 3, c: 37471}, michael@0: {f: 3, c: 37475}, {f: 5, c: 37479}, {f: 6, c: 37486}, {f: 3, c: 37493}, michael@0: 37497, {f: 3, c: 37500}, {f: 2, c: 37505}, 37508, {f: 8, c: 37510}, michael@0: {f: 2, c: 37519}, 37522, {f: 2, c: 37524}, 37527, 37529, 37531, michael@0: {f: 3, c: 37533}, {f: 2, c: 37537}, 37540, 37543, 37549, {f: 2, c: 37551}, michael@0: {f: 5, c: 37554}, 37560, 37562, {f: 4, c: 37565}, 37570, 37572, 37574, michael@0: {f: 3, c: 37577}, {f: 2, c: 37581}, {f: 2, c: 37584}, {f: 10, c: 37587}, michael@0: 37598, {f: 3, c: 37600}, 37607, 37609, {f: 2, c: 37611}, {f: 4, c: 37618}, michael@0: 37623, {f: 3, c: 37625}, {f: 4, c: 37629}, {f: 4, c: 37634}, michael@0: {f: 7, c: 37641}, 37649, {f: 2, c: 37651}, {f: 2, c: 37654}, michael@0: {f: 3, c: 37660}, 37665, {f: 3, c: 37667}, 37671, {f: 2, c: 37673}, michael@0: {f: 2, c: 37676}, {f: 2, c: 37680}, {f: 2, c: 37684}, 37687, michael@0: {f: 5, c: 37689}, 37695, 37698, {f: 2, c: 37700}, {f: 3, c: 37704}, 37708, michael@0: {f: 6, c: 37710}, {f: 3, c: 37717}, {f: 2, c: 37721}, {f: 8, c: 37724}, michael@0: {f: 3, c: 37734}, 37739, {f: 3, c: 37741}, {f: 4, c: 37745}, michael@0: {f: 3, c: 37751}, {f: 3, c: 37755}, {f: 3, c: 37759}, 37763, michael@0: {f: 2, c: 37765}, {f: 2, c: 37768}, {f: 4, c: 37771}, {f: 6, c: 37776}, michael@0: 37783, {f: 9, c: 37785}, {f: 2, c: 37796}, 37800, 37803, 37805, 37807, michael@0: {f: 2, c: 37809}, 37812, {f: 2, c: 37814}, {f: 6, c: 37817}, michael@0: {f: 3, c: 37824}, {f: 3, c: 37828}, 37833, 37835, {f: 3, c: 37838}, michael@0: {f: 4, c: 37842}, {f: 3, c: 37849}, 37856, 37859, {f: 3, c: 37861}, michael@0: {f: 12, c: 37865}, 37878, 37880, {f: 9, c: 37882}, {f: 7, c: 37892}, michael@0: {f: 4, c: 37900}, 37905, {f: 3, c: 37909}, {f: 3, c: 37914}, michael@0: {f: 2, c: 37918}, {f: 5, c: 37921}, {f: 5, c: 37929}, {f: 3, c: 37935}, michael@0: 37940, {f: 2, c: 37942}, 37945, {f: 3, c: 37947}, {f: 4, c: 37952}, michael@0: {f: 5, c: 37957}, 37963, {f: 5, c: 37965}, 37971, {f: 11, c: 37973}, michael@0: {f: 2, c: 37985}, 37988, {f: 5, c: 37990}, 37996, {f: 2, c: 37998}, 38001, michael@0: {f: 4, c: 38003}, 38008, {f: 2, c: 38010}, {f: 5, c: 38016}, 38033, 38038, michael@0: 38040, 38087, 38095, {f: 2, c: 38099}, 38106, 38118, 38139, 38172, 38176, michael@0: 38183, 38195, 38205, 38211, 38216, 38219, 38229, 38234, 38240, 38254, michael@0: {f: 2, c: 38260}, {f: 7, c: 38264}, 38273, {f: 2, c: 38276}, michael@0: {f: 2, c: 38279}, 38282, 38285, 38288, 38290, {f: 3, c: 38293}, michael@0: {f: 8, c: 38297}, 38306, {f: 2, c: 38310}, 38314, {f: 4, c: 38318}, michael@0: {f: 3, c: 38323}, {f: 2, c: 38327}, 38330, {f: 3, c: 38336}, michael@0: {f: 2, c: 38340}, 38343, 38345, {f: 3, c: 38349}, {f: 3, c: 38353}, michael@0: {f: 5, c: 38359}, 38365, {f: 2, c: 38367}, {f: 2, c: 38371}, michael@0: {f: 2, c: 38374}, 38380, 38399, 38407, 38419, 38424, 38427, 38430, 38432, michael@0: {f: 7, c: 38435}, {f: 3, c: 38443}, {f: 2, c: 38447}, {f: 4, c: 38455}, michael@0: 38462, 38465, 38467, 38474, {f: 2, c: 38478}, {f: 3, c: 38481}, michael@0: {f: 2, c: 38486}, {f: 2, c: 38489}, 38492, 38494, 38496, {f: 2, c: 38501}, michael@0: 38507, {f: 3, c: 38509}, 38513, {f: 4, c: 38521}, {f: 7, c: 38526}, 38535, michael@0: 38537, 38540, {f: 3, c: 38545}, 38550, 38554, {f: 10, c: 38557}, 38569, michael@0: {f: 5, c: 38571}, 38578, 38581, 38583, 38586, 38591, {f: 2, c: 38594}, michael@0: 38600, {f: 2, c: 38602}, {f: 2, c: 38608}, {f: 2, c: 38611}, michael@0: {f: 2, c: 38615}, 38618, {f: 3, c: 38621}, 38625, {f: 4, c: 38628}, michael@0: {f: 4, c: 38635}, {f: 2, c: 38640}, {f: 2, c: 38644}, 38648, 38650, michael@0: {f: 2, c: 38652}, 38655, {f: 2, c: 38658}, 38661, {f: 3, c: 38666}, michael@0: {f: 3, c: 38672}, {f: 2, c: 38676}, {f: 5, c: 38679}, 38685, michael@0: {f: 8, c: 38687}, {f: 2, c: 38696}, {f: 2, c: 38699}, {f: 2, c: 38702}, michael@0: 38705, {f: 5, c: 38707}, {f: 3, c: 38714}, {f: 3, c: 38719}, 38723, michael@0: {f: 3, c: 38725}, {f: 8, c: 38729}, [12205, 38737], {f: 2, c: 38740}, michael@0: {f: 2, c: 38743}, {f: 2, c: 38748}, 38751, {f: 2, c: 38755}, michael@0: {f: 2, c: 38758}, {f: 9, c: 38762}, 38773, {f: 5, c: 38775}, michael@0: {f: 8, c: 38781}, {f: 5, c: 38790}, 38796, 38798, 38800, 38803, michael@0: {f: 3, c: 38805}, {f: 7, c: 38809}, {f: 2, c: 38817}, {f: 2, c: 38820}, michael@0: {f: 4, c: 38823}, 38828, 38830, {f: 2, c: 38832}, 38835, {f: 8, c: 38837}, michael@0: {f: 5, c: 38846}, {f: 2, c: 38852}, {f: 2, c: 38855}, 38858, michael@0: {f: 6, c: 38861}, {f: 5, c: 38868}, {f: 2, c: 38874}, 38877, michael@0: {f: 7, c: 38879}, 38888, {f: 5, c: 38894}, 38900, {f: 8, c: 38903}, 38912, michael@0: 38916, 38921, 38923, 38925, {f: 3, c: 38932}, {f: 3, c: 38937}, michael@0: {f: 4, c: 38941}, {f: 2, c: 38946}, 38949, {f: 6, c: 38951}, michael@0: {f: 2, c: 38958}, {f: 6, c: 38961}, {f: 2, c: 38969}, 38972, michael@0: {f: 8, c: 38974}, {f: 5, c: 38983}, {f: 4, c: 38991}, {f: 3, c: 38997}, michael@0: 39002, {f: 2, c: 39004}, {f: 3, c: 39007}, {f: 2, c: 39011}, 39014, michael@0: {f: 3, c: 39016}, {f: 2, c: 39021}, 39026, 39051, 39054, 39058, 39061, michael@0: 39065, 39075, {f: 5, c: 39081}, 39088, 39090, {f: 2, c: 39092}, michael@0: {f: 5, c: 39095}, {f: 7, c: 39101}, 39109, 39111, {f: 5, c: 39113}, michael@0: {f: 2, c: 39119}, 39124, {f: 2, c: 39126}, {f: 2, c: 39132}, 39137, michael@0: {f: 4, c: 39139}, 39148, 39150, {f: 2, c: 39152}, 39155, {f: 7, c: 39157}, michael@0: {f: 4, c: 39167}, 39172, {f: 3, c: 39174}, 39179, {f: 2, c: 39182}, michael@0: {f: 4, c: 39188}, {f: 2, c: 39193}, {f: 2, c: 39196}, {f: 2, c: 39199}, michael@0: {f: 6, c: 39202}, {f: 5, c: 39209}, {f: 4, c: 39215}, {f: 3, c: 39220}, michael@0: {f: 4, c: 39224}, 39229, {f: 3, c: 39232}, 39236, {f: 2, c: 39238}, michael@0: {f: 4, c: 39245}, 39251, 39254, {f: 4, c: 39256}, 39261, {f: 3, c: 39263}, michael@0: 39268, 39270, 39283, {f: 2, c: 39288}, 39291, 39294, {f: 2, c: 39298}, michael@0: 39305, 39308, 39310, {f: 11, c: 39322}, {f: 2, c: 39334}, {f: 3, c: 39337}, michael@0: {f: 2, c: 39343}, 39346, {f: 12, c: 39349}, {f: 14, c: 39362}, 39379, michael@0: {f: 2, c: 39382}, 39386, 39388, 39390, 39392, {f: 10, c: 39395}, michael@0: {f: 3, c: 39406}, {f: 13, c: 39410}, 39424, {f: 3, c: 39426}, michael@0: {f: 7, c: 39430}, {f: 6, c: 39440}, {f: 2, c: 39447}, {f: 17, c: 39450}, michael@0: 39468, 39471, {f: 5, c: 39473}, {f: 5, c: 39481}, 39487, {f: 4, c: 39494}, michael@0: {f: 2, c: 39499}, 39502, {f: 5, c: 39504}, 39510, {f: 2, c: 39512}, michael@0: {f: 3, c: 39516}, {f: 2, c: 39520}, 39523, {f: 4, c: 39526}, 39531, 39538, michael@0: 39555, 39561, {f: 2, c: 39565}, {f: 2, c: 39572}, 39577, 39590, michael@0: {f: 6, c: 39593}, {f: 4, c: 39602}, 39609, 39611, {f: 3, c: 39613}, michael@0: {f: 2, c: 39619}, {f: 5, c: 39622}, {f: 2, c: 39629}, 39632, 39639, michael@0: {f: 6, c: 39641}, 39648, {f: 4, c: 39650}, {f: 4, c: 39655}, 39660, michael@0: {f: 9, c: 39664}, 39674, {f: 7, c: 39676}, {f: 2, c: 39684}, 39687, michael@0: {f: 4, c: 39689}, 39694, {f: 3, c: 39696}, {f: 6, c: 39700}, michael@0: {f: 4, c: 39707}, {f: 2, c: 39712}, 39716, 39718, 39720, {f: 4, c: 39722}, michael@0: 39728, {f: 8, c: 39731}, {f: 4, c: 39741}, 39750, {f: 3, c: 39754}, 39760, michael@0: {f: 2, c: 39762}, {f: 3, c: 39765}, 39769, {f: 20, c: 39771}, michael@0: {f: 4, c: 39792}, {f: 2, c: 39797}, {f: 9, c: 39800}, 39810, michael@0: {f: 10, c: 39812}, 39823, {f: 7, c: 39827}, {f: 2, c: 39835}, michael@0: {f: 11, c: 39839}, 39852, {f: 17, c: 39855}, {f: 5, c: 39874}, 39880, michael@0: {f: 9, c: 39883}, 39893, {f: 4, c: 39895}, 39900, {f: 3, c: 39902}, 39907, michael@0: {f: 2, c: 39909}, 39913, {f: 4, c: 39916}, {f: 3, c: 39921}, michael@0: {f: 8, c: 39925}, 39934, {f: 8, c: 39936}, {f: 3, c: 39946}, michael@0: {f: 2, c: 39950}, 39953, {f: 12, c: 39956}, {f: 2, c: 39969}, 39972, michael@0: {f: 2, c: 39974}, {f: 3, c: 39978}, {f: 3, c: 39982}, 39988, 39990, 39992, michael@0: 39994, {f: 2, c: 39996}, {f: 6, c: 39999}, {f: 2, c: 40006}, michael@0: {f: 8, c: 40010}, 40019, 40021, {f: 4, c: 40025}, 40030, {f: 7, c: 40032}, michael@0: {f: 5, c: 40040}, {f: 10, c: 40046}, 40057, 40059, {f: 2, c: 40061}, 40064, michael@0: {f: 2, c: 40067}, {f: 2, c: 40073}, 40076, 40079, 40083, {f: 4, c: 40086}, michael@0: 40093, 40106, 40108, 40111, 40121, {f: 5, c: 40126}, {f: 2, c: 40136}, michael@0: {f: 2, c: 40145}, {f: 2, c: 40154}, {f: 2, c: 40160}, {f: 2, c: 40163}, michael@0: {f: 3, c: 40166}, {f: 2, c: 40170}, {f: 6, c: 40173}, 40181, michael@0: {f: 15, c: 40183}, 40200, {f: 11, c: 40202}, {f: 5, c: 40214}, 40220, michael@0: 40222, {f: 3, c: 40224}, {f: 2, c: 40228}, 40231, {f: 6, c: 40233}, michael@0: {f: 10, c: 40241}, {f: 3, c: 40252}, {f: 2, c: 40256}, {f: 14, c: 40259}, michael@0: {f: 8, c: 40276}, {f: 2, c: 40286}, {f: 8, c: 40290}, 40299, michael@0: {f: 2, c: 40301}, {f: 2, c: 40304}, {f: 20, c: 40307}, 40328, michael@0: {f: 9, c: 40330}, {f: 4, c: 40340}, 40345, {f: 10, c: 40347}, michael@0: {f: 3, c: 40358}, {f: 5, c: 40362}, {f: 4, c: 40368}, {f: 6, c: 40373}, michael@0: {f: 3, c: 40381}, 40385, 40387, {f: 14, c: 40389}, {f: 3, c: 40404}, 40408, michael@0: {f: 10, c: 40411}, {f: 8, c: 40423}, {f: 2, c: 40432}, {f: 4, c: 40436}, michael@0: {f: 17, c: 40443}, {f: 8, c: 40461}, {f: 4, c: 40470}, 40476, 40484, 40487, michael@0: 40494, 40496, 40500, {f: 2, c: 40507}, 40512, 40525, 40528, michael@0: {f: 3, c: 40530}, 40534, 40537, 40541, {f: 4, c: 40543}, 40549, michael@0: {f: 2, c: 40558}, 40562, 40564, {f: 3, c: 40566}, 40571, {f: 2, c: 40576}, michael@0: {f: 4, c: 40579}, {f: 2, c: 40585}, {f: 6, c: 40588}, {f: 3, c: 40596}, michael@0: {f: 5, c: 40600}, 40606, {f: 5, c: 40608}, {f: 2, c: 40615}, michael@0: {f: 5, c: 40618}, {f: 4, c: 40624}, {f: 2, c: 40630}, {f: 2, c: 40633}, michael@0: 40636, {f: 4, c: 40639}, [12232, 40643], {f: 4, c: 40645}, michael@0: {f: 2, c: 40650}, 40656, {f: 2, c: 40658}, {f: 3, c: 40661}, michael@0: {f: 2, c: 40665}, 40673, {f: 2, c: 40675}, 40678, {f: 4, c: 40683}, michael@0: {f: 2, c: 40688}, 40691, {f: 2, c: 40693}, 40696, 40698, {f: 9, c: 40704}, michael@0: 40714, 40716, 40719, {f: 2, c: 40721}, 40724, 40726, 40728, michael@0: {f: 6, c: 40730}, 40737, {f: 9, c: 40739}, {f: 2, c: 40749}, michael@0: {f: 7, c: 40752}, 40760, 40762, 40764, {f: 5, c: 40767}, {f: 5, c: 40773}, michael@0: {f: 3, c: 40780}, 40787, {f: 4, c: 40789}, {f: 2, c: 40794}, michael@0: {f: 2, c: 40797}, 40802, {f: 2, c: 40804}, {f: 3, c: 40807}, 40811, michael@0: {f: 5, c: 40813}, {f: 4, c: 40819}, {f: 7, c: 40824}, {f: 2, c: 40833}, michael@0: {f: 2, c: 40846}, {f: 3, c: 40849}, {f: 3, c: 40854}, {f: 2, c: 40861}, michael@0: {f: 5, c: 40865}, 63788, {f: 3, c: 64013}, 64017, {f: 2, c: 64019}, 64024, michael@0: {f: 3, c: 64031}, {f: 2, c: 64035}, {f: 3, c: 64039}, 11905, michael@0: [59414, 131207], [59415, 131209], [59416, 131276], 11908, 13427, 13383, michael@0: 11912, 11915, 59422, 13726, 13850, 13838, 11916, 11927, 14702, 14616, michael@0: 59430, 14799, 14815, 14963, 14800, {f: 2, c: 59435}, 15182, 15470, 15584, michael@0: 11943, [59441, 136663], 59442, 11946, 16470, 16735, 11950, 17207, 11955, michael@0: {f: 2, c: 11958}, [59451, 141711], 17329, 17324, 11963, 17373, 17622, michael@0: 18017, 17996, [59459, 132361], 18211, 18217, 18300, 18317, 11978, 18759, michael@0: 18810, 18813, {f: 2, c: 18818}, {f: 2, c: 18821}, 18847, 18843, 18871, michael@0: 18870, [59476, 133533], [59477, 147966], 19619, {f: 3, c: 19615}, 19575, michael@0: 19618, {f: 7, c: 19731}, 19886, 59492, {s: 226}, 8364, 165, 0, 0, 12351, michael@0: {s: 17}, 12436, {s: 14}, 12535, 12537, 12536, 12538, 0, {f: 3, c: 12339}, michael@0: {f: 3, c: 12344}, {f: 3, c: 12586}, {f: 24, c: 12704}, 11904, michael@0: {f: 2, c: 11906}, {f: 3, c: 11909}, {f: 2, c: 11913}, {f: 10, c: 11917}, michael@0: {f: 2, c: 11928}, {f: 12, c: 11931}, {f: 2, c: 11944}, {f: 3, c: 11947}, michael@0: {f: 4, c: 11951}, {f: 2, c: 11956}, {f: 3, c: 11960}, {f: 14, c: 11964}, michael@0: {f: 41, c: 11979}, {f: 71, c: 13312}, {f: 43, c: 13384}, michael@0: {f: 298, c: 13428}, {f: 111, c: 13727}, {f: 11, c: 13839}, michael@0: {f: 765, c: 13851}, {f: 85, c: 14617}, {f: 96, c: 14703}, michael@0: {f: 14, c: 14801}, {f: 147, c: 14816}, {f: 218, c: 14964}, michael@0: {f: 287, c: 15183}, {f: 113, c: 15471}, {f: 885, c: 15585}, michael@0: {f: 264, c: 16471}, {f: 471, c: 16736}, {f: 116, c: 17208}, michael@0: {f: 4, c: 17325}, {f: 43, c: 17330}, {f: 248, c: 17374}, michael@0: {f: 373, c: 17623}, {f: 20, c: 17997}, {f: 193, c: 18018}, michael@0: {f: 5, c: 18212}, {f: 82, c: 18218}, {f: 16, c: 18301}, {f: 441, c: 18318}, michael@0: {f: 50, c: 18760}, {f: 2, c: 18811}, {f: 4, c: 18814}, 18820, michael@0: {f: 20, c: 18823}, {f: 3, c: 18844}, {f: 22, c: 18848}, {f: 703, c: 18872}, michael@0: {f: 39, c: 19576}, {f: 111, c: 19620}, {f: 148, c: 19738}, michael@0: {f: 7, c: 19887}] michael@0: }; michael@0: michael@0: michael@0: michael@0: var ARCFourCipher = (function ARCFourCipherClosure() { michael@0: function ARCFourCipher(key) { michael@0: this.a = 0; michael@0: this.b = 0; michael@0: var s = new Uint8Array(256); michael@0: var i, j = 0, tmp, keyLength = key.length; michael@0: for (i = 0; i < 256; ++i) { michael@0: s[i] = i; michael@0: } michael@0: for (i = 0; i < 256; ++i) { michael@0: tmp = s[i]; michael@0: j = (j + tmp + key[i % keyLength]) & 0xFF; michael@0: s[i] = s[j]; michael@0: s[j] = tmp; michael@0: } michael@0: this.s = s; michael@0: } michael@0: michael@0: ARCFourCipher.prototype = { michael@0: encryptBlock: function ARCFourCipher_encryptBlock(data) { michael@0: var i, n = data.length, tmp, tmp2; michael@0: var a = this.a, b = this.b, s = this.s; michael@0: var output = new Uint8Array(n); michael@0: for (i = 0; i < n; ++i) { michael@0: a = (a + 1) & 0xFF; michael@0: tmp = s[a]; michael@0: b = (b + tmp) & 0xFF; michael@0: tmp2 = s[b]; michael@0: s[a] = tmp2; michael@0: s[b] = tmp; michael@0: output[i] = data[i] ^ s[(tmp + tmp2) & 0xFF]; michael@0: } michael@0: this.a = a; michael@0: this.b = b; michael@0: return output; michael@0: } michael@0: }; michael@0: ARCFourCipher.prototype.decryptBlock = ARCFourCipher.prototype.encryptBlock; michael@0: michael@0: return ARCFourCipher; michael@0: })(); michael@0: michael@0: var calculateMD5 = (function calculateMD5Closure() { michael@0: var r = new Uint8Array([ michael@0: 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, michael@0: 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, michael@0: 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, michael@0: 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21]); michael@0: michael@0: var k = new Int32Array([ michael@0: -680876936, -389564586, 606105819, -1044525330, -176418897, 1200080426, michael@0: -1473231341, -45705983, 1770035416, -1958414417, -42063, -1990404162, michael@0: 1804603682, -40341101, -1502002290, 1236535329, -165796510, -1069501632, michael@0: 643717713, -373897302, -701558691, 38016083, -660478335, -405537848, michael@0: 568446438, -1019803690, -187363961, 1163531501, -1444681467, -51403784, michael@0: 1735328473, -1926607734, -378558, -2022574463, 1839030562, -35309556, michael@0: -1530992060, 1272893353, -155497632, -1094730640, 681279174, -358537222, michael@0: -722521979, 76029189, -640364487, -421815835, 530742520, -995338651, michael@0: -198630844, 1126891415, -1416354905, -57434055, 1700485571, -1894986606, michael@0: -1051523, -2054922799, 1873313359, -30611744, -1560198380, 1309151649, michael@0: -145523070, -1120210379, 718787259, -343485551]); michael@0: michael@0: function hash(data, offset, length) { michael@0: var h0 = 1732584193, h1 = -271733879, h2 = -1732584194, h3 = 271733878; michael@0: // pre-processing michael@0: var paddedLength = (length + 72) & ~63; // data + 9 extra bytes michael@0: var padded = new Uint8Array(paddedLength); michael@0: var i, j, n; michael@0: for (i = 0; i < length; ++i) { michael@0: padded[i] = data[offset++]; michael@0: } michael@0: padded[i++] = 0x80; michael@0: n = paddedLength - 8; michael@0: while (i < n) { michael@0: padded[i++] = 0; michael@0: } michael@0: padded[i++] = (length << 3) & 0xFF; michael@0: padded[i++] = (length >> 5) & 0xFF; michael@0: padded[i++] = (length >> 13) & 0xFF; michael@0: padded[i++] = (length >> 21) & 0xFF; michael@0: padded[i++] = (length >>> 29) & 0xFF; michael@0: padded[i++] = 0; michael@0: padded[i++] = 0; michael@0: padded[i++] = 0; michael@0: // chunking michael@0: // TODO ArrayBuffer ? michael@0: var w = new Int32Array(16); michael@0: for (i = 0; i < paddedLength;) { michael@0: for (j = 0; j < 16; ++j, i += 4) { michael@0: w[j] = (padded[i] | (padded[i + 1] << 8) | michael@0: (padded[i + 2] << 16) | (padded[i + 3] << 24)); michael@0: } michael@0: var a = h0, b = h1, c = h2, d = h3, f, g; michael@0: for (j = 0; j < 64; ++j) { michael@0: if (j < 16) { michael@0: f = (b & c) | ((~b) & d); michael@0: g = j; michael@0: } else if (j < 32) { michael@0: f = (d & b) | ((~d) & c); michael@0: g = (5 * j + 1) & 15; michael@0: } else if (j < 48) { michael@0: f = b ^ c ^ d; michael@0: g = (3 * j + 5) & 15; michael@0: } else { michael@0: f = c ^ (b | (~d)); michael@0: g = (7 * j) & 15; michael@0: } michael@0: var tmp = d, rotateArg = (a + f + k[j] + w[g]) | 0, rotate = r[j]; michael@0: d = c; michael@0: c = b; michael@0: b = (b + ((rotateArg << rotate) | (rotateArg >>> (32 - rotate)))) | 0; michael@0: a = tmp; michael@0: } michael@0: h0 = (h0 + a) | 0; michael@0: h1 = (h1 + b) | 0; michael@0: h2 = (h2 + c) | 0; michael@0: h3 = (h3 + d) | 0; michael@0: } michael@0: return new Uint8Array([ michael@0: h0 & 0xFF, (h0 >> 8) & 0xFF, (h0 >> 16) & 0xFF, (h0 >>> 24) & 0xFF, michael@0: h1 & 0xFF, (h1 >> 8) & 0xFF, (h1 >> 16) & 0xFF, (h1 >>> 24) & 0xFF, michael@0: h2 & 0xFF, (h2 >> 8) & 0xFF, (h2 >> 16) & 0xFF, (h2 >>> 24) & 0xFF, michael@0: h3 & 0xFF, (h3 >> 8) & 0xFF, (h3 >> 16) & 0xFF, (h3 >>> 24) & 0xFF michael@0: ]); michael@0: } michael@0: return hash; michael@0: })(); michael@0: michael@0: var NullCipher = (function NullCipherClosure() { michael@0: function NullCipher() {} michael@0: michael@0: NullCipher.prototype = { michael@0: decryptBlock: function NullCipher_decryptBlock(data) { michael@0: return data; michael@0: } michael@0: }; michael@0: michael@0: return NullCipher; michael@0: })(); michael@0: michael@0: var AES128Cipher = (function AES128CipherClosure() { michael@0: var rcon = new Uint8Array([ michael@0: 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, michael@0: 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, michael@0: 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, michael@0: 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, michael@0: 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, michael@0: 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, michael@0: 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, michael@0: 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, michael@0: 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, michael@0: 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, michael@0: 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, michael@0: 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, michael@0: 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, michael@0: 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, michael@0: 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, michael@0: 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, michael@0: 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, michael@0: 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, michael@0: 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, michael@0: 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, michael@0: 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, michael@0: 0x74, 0xe8, 0xcb, 0x8d]); michael@0: michael@0: var s = new Uint8Array([ michael@0: 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, michael@0: 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, michael@0: 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, michael@0: 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, michael@0: 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, michael@0: 0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, michael@0: 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, michael@0: 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, michael@0: 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, michael@0: 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, michael@0: 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec, michael@0: 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, michael@0: 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, michael@0: 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, michael@0: 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, michael@0: 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, michael@0: 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, michael@0: 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, michael@0: 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, michael@0: 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, michael@0: 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, michael@0: 0xb0, 0x54, 0xbb, 0x16]); michael@0: michael@0: var inv_s = new Uint8Array([ michael@0: 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, michael@0: 0x81, 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, michael@0: 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 0x54, 0x7b, 0x94, 0x32, michael@0: 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, michael@0: 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, michael@0: 0x6d, 0x8b, 0xd1, 0x25, 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, michael@0: 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50, michael@0: 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, michael@0: 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, michael@0: 0xb8, 0xb3, 0x45, 0x06, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, michael@0: 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 0x3a, 0x91, 0x11, 0x41, michael@0: 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, michael@0: 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, michael@0: 0x1c, 0x75, 0xdf, 0x6e, 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, michael@0: 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 0xfc, 0x56, 0x3e, 0x4b, michael@0: 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, michael@0: 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, michael@0: 0x27, 0x80, 0xec, 0x5f, 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, michael@0: 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, 0xa0, 0xe0, 0x3b, 0x4d, michael@0: 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, michael@0: 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, michael@0: 0x55, 0x21, 0x0c, 0x7d]); michael@0: michael@0: var mix = new Uint32Array([ michael@0: 0x00000000, 0x0e090d0b, 0x1c121a16, 0x121b171d, 0x3824342c, 0x362d3927, michael@0: 0x24362e3a, 0x2a3f2331, 0x70486858, 0x7e416553, 0x6c5a724e, 0x62537f45, michael@0: 0x486c5c74, 0x4665517f, 0x547e4662, 0x5a774b69, 0xe090d0b0, 0xee99ddbb, michael@0: 0xfc82caa6, 0xf28bc7ad, 0xd8b4e49c, 0xd6bde997, 0xc4a6fe8a, 0xcaaff381, michael@0: 0x90d8b8e8, 0x9ed1b5e3, 0x8ccaa2fe, 0x82c3aff5, 0xa8fc8cc4, 0xa6f581cf, michael@0: 0xb4ee96d2, 0xbae79bd9, 0xdb3bbb7b, 0xd532b670, 0xc729a16d, 0xc920ac66, michael@0: 0xe31f8f57, 0xed16825c, 0xff0d9541, 0xf104984a, 0xab73d323, 0xa57ade28, michael@0: 0xb761c935, 0xb968c43e, 0x9357e70f, 0x9d5eea04, 0x8f45fd19, 0x814cf012, michael@0: 0x3bab6bcb, 0x35a266c0, 0x27b971dd, 0x29b07cd6, 0x038f5fe7, 0x0d8652ec, michael@0: 0x1f9d45f1, 0x119448fa, 0x4be30393, 0x45ea0e98, 0x57f11985, 0x59f8148e, michael@0: 0x73c737bf, 0x7dce3ab4, 0x6fd52da9, 0x61dc20a2, 0xad766df6, 0xa37f60fd, michael@0: 0xb16477e0, 0xbf6d7aeb, 0x955259da, 0x9b5b54d1, 0x894043cc, 0x87494ec7, michael@0: 0xdd3e05ae, 0xd33708a5, 0xc12c1fb8, 0xcf2512b3, 0xe51a3182, 0xeb133c89, michael@0: 0xf9082b94, 0xf701269f, 0x4de6bd46, 0x43efb04d, 0x51f4a750, 0x5ffdaa5b, michael@0: 0x75c2896a, 0x7bcb8461, 0x69d0937c, 0x67d99e77, 0x3daed51e, 0x33a7d815, michael@0: 0x21bccf08, 0x2fb5c203, 0x058ae132, 0x0b83ec39, 0x1998fb24, 0x1791f62f, michael@0: 0x764dd68d, 0x7844db86, 0x6a5fcc9b, 0x6456c190, 0x4e69e2a1, 0x4060efaa, michael@0: 0x527bf8b7, 0x5c72f5bc, 0x0605bed5, 0x080cb3de, 0x1a17a4c3, 0x141ea9c8, michael@0: 0x3e218af9, 0x302887f2, 0x223390ef, 0x2c3a9de4, 0x96dd063d, 0x98d40b36, michael@0: 0x8acf1c2b, 0x84c61120, 0xaef93211, 0xa0f03f1a, 0xb2eb2807, 0xbce2250c, michael@0: 0xe6956e65, 0xe89c636e, 0xfa877473, 0xf48e7978, 0xdeb15a49, 0xd0b85742, michael@0: 0xc2a3405f, 0xccaa4d54, 0x41ecdaf7, 0x4fe5d7fc, 0x5dfec0e1, 0x53f7cdea, michael@0: 0x79c8eedb, 0x77c1e3d0, 0x65daf4cd, 0x6bd3f9c6, 0x31a4b2af, 0x3fadbfa4, michael@0: 0x2db6a8b9, 0x23bfa5b2, 0x09808683, 0x07898b88, 0x15929c95, 0x1b9b919e, michael@0: 0xa17c0a47, 0xaf75074c, 0xbd6e1051, 0xb3671d5a, 0x99583e6b, 0x97513360, michael@0: 0x854a247d, 0x8b432976, 0xd134621f, 0xdf3d6f14, 0xcd267809, 0xc32f7502, michael@0: 0xe9105633, 0xe7195b38, 0xf5024c25, 0xfb0b412e, 0x9ad7618c, 0x94de6c87, michael@0: 0x86c57b9a, 0x88cc7691, 0xa2f355a0, 0xacfa58ab, 0xbee14fb6, 0xb0e842bd, michael@0: 0xea9f09d4, 0xe49604df, 0xf68d13c2, 0xf8841ec9, 0xd2bb3df8, 0xdcb230f3, michael@0: 0xcea927ee, 0xc0a02ae5, 0x7a47b13c, 0x744ebc37, 0x6655ab2a, 0x685ca621, michael@0: 0x42638510, 0x4c6a881b, 0x5e719f06, 0x5078920d, 0x0a0fd964, 0x0406d46f, michael@0: 0x161dc372, 0x1814ce79, 0x322bed48, 0x3c22e043, 0x2e39f75e, 0x2030fa55, michael@0: 0xec9ab701, 0xe293ba0a, 0xf088ad17, 0xfe81a01c, 0xd4be832d, 0xdab78e26, michael@0: 0xc8ac993b, 0xc6a59430, 0x9cd2df59, 0x92dbd252, 0x80c0c54f, 0x8ec9c844, michael@0: 0xa4f6eb75, 0xaaffe67e, 0xb8e4f163, 0xb6edfc68, 0x0c0a67b1, 0x02036aba, michael@0: 0x10187da7, 0x1e1170ac, 0x342e539d, 0x3a275e96, 0x283c498b, 0x26354480, michael@0: 0x7c420fe9, 0x724b02e2, 0x605015ff, 0x6e5918f4, 0x44663bc5, 0x4a6f36ce, michael@0: 0x587421d3, 0x567d2cd8, 0x37a10c7a, 0x39a80171, 0x2bb3166c, 0x25ba1b67, michael@0: 0x0f853856, 0x018c355d, 0x13972240, 0x1d9e2f4b, 0x47e96422, 0x49e06929, michael@0: 0x5bfb7e34, 0x55f2733f, 0x7fcd500e, 0x71c45d05, 0x63df4a18, 0x6dd64713, michael@0: 0xd731dcca, 0xd938d1c1, 0xcb23c6dc, 0xc52acbd7, 0xef15e8e6, 0xe11ce5ed, michael@0: 0xf307f2f0, 0xfd0efffb, 0xa779b492, 0xa970b999, 0xbb6bae84, 0xb562a38f, michael@0: 0x9f5d80be, 0x91548db5, 0x834f9aa8, 0x8d4697a3]); michael@0: michael@0: function expandKey128(cipherKey) { michael@0: var b = 176, result = new Uint8Array(b); michael@0: result.set(cipherKey); michael@0: for (var j = 16, i = 1; j < b; ++i) { michael@0: // RotWord michael@0: var t1 = result[j - 3], t2 = result[j - 2], michael@0: t3 = result[j - 1], t4 = result[j - 4]; michael@0: // SubWord michael@0: t1 = s[t1]; t2 = s[t2]; t3 = s[t3]; t4 = s[t4]; michael@0: // Rcon michael@0: t1 = t1 ^ rcon[i]; michael@0: for (var n = 0; n < 4; ++n) { michael@0: result[j] = (t1 ^= result[j - 16]); j++; michael@0: result[j] = (t2 ^= result[j - 16]); j++; michael@0: result[j] = (t3 ^= result[j - 16]); j++; michael@0: result[j] = (t4 ^= result[j - 16]); j++; michael@0: } michael@0: } michael@0: return result; michael@0: } michael@0: michael@0: function decrypt128(input, key) { michael@0: var state = new Uint8Array(16); michael@0: state.set(input); michael@0: var i, j, k; michael@0: var t, u, v; michael@0: // AddRoundKey michael@0: for (j = 0, k = 160; j < 16; ++j, ++k) { michael@0: state[j] ^= key[k]; michael@0: } michael@0: for (i = 9; i >= 1; --i) { michael@0: // InvShiftRows michael@0: t = state[13]; state[13] = state[9]; state[9] = state[5]; michael@0: state[5] = state[1]; state[1] = t; michael@0: t = state[14]; u = state[10]; state[14] = state[6]; michael@0: state[10] = state[2]; state[6] = t; state[2] = u; michael@0: t = state[15]; u = state[11]; v = state[7]; state[15] = state[3]; michael@0: state[11] = t; state[7] = u; state[3] = v; michael@0: // InvSubBytes michael@0: for (j = 0; j < 16; ++j) { michael@0: state[j] = inv_s[state[j]]; michael@0: } michael@0: // AddRoundKey michael@0: for (j = 0, k = i * 16; j < 16; ++j, ++k) { michael@0: state[j] ^= key[k]; michael@0: } michael@0: // InvMixColumns michael@0: for (j = 0; j < 16; j += 4) { michael@0: var s0 = mix[state[j]], s1 = mix[state[j + 1]], michael@0: s2 = mix[state[j + 2]], s3 = mix[state[j + 3]]; michael@0: t = (s0 ^ (s1 >>> 8) ^ (s1 << 24) ^ (s2 >>> 16) ^ (s2 << 16) ^ michael@0: (s3 >>> 24) ^ (s3 << 8)); michael@0: state[j] = (t >>> 24) & 0xFF; michael@0: state[j + 1] = (t >> 16) & 0xFF; michael@0: state[j + 2] = (t >> 8) & 0xFF; michael@0: state[j + 3] = t & 0xFF; michael@0: } michael@0: } michael@0: // InvShiftRows michael@0: t = state[13]; state[13] = state[9]; state[9] = state[5]; michael@0: state[5] = state[1]; state[1] = t; michael@0: t = state[14]; u = state[10]; state[14] = state[6]; michael@0: state[10] = state[2]; state[6] = t; state[2] = u; michael@0: t = state[15]; u = state[11]; v = state[7]; state[15] = state[3]; michael@0: state[11] = t; state[7] = u; state[3] = v; michael@0: for (j = 0; j < 16; ++j) { michael@0: // InvSubBytes michael@0: state[j] = inv_s[state[j]]; michael@0: // AddRoundKey michael@0: state[j] ^= key[j]; michael@0: } michael@0: return state; michael@0: } michael@0: michael@0: function AES128Cipher(key) { michael@0: this.key = expandKey128(key); michael@0: this.buffer = new Uint8Array(16); michael@0: this.bufferPosition = 0; michael@0: } michael@0: michael@0: function decryptBlock2(data, finalize) { michael@0: var i, j, ii, sourceLength = data.length, michael@0: buffer = this.buffer, bufferLength = this.bufferPosition, michael@0: result = [], iv = this.iv; michael@0: for (i = 0; i < sourceLength; ++i) { michael@0: buffer[bufferLength] = data[i]; michael@0: ++bufferLength; michael@0: if (bufferLength < 16) { michael@0: continue; michael@0: } michael@0: // buffer is full, decrypting michael@0: var plain = decrypt128(buffer, this.key); michael@0: // xor-ing the IV vector to get plain text michael@0: for (j = 0; j < 16; ++j) { michael@0: plain[j] ^= iv[j]; michael@0: } michael@0: iv = buffer; michael@0: result.push(plain); michael@0: buffer = new Uint8Array(16); michael@0: bufferLength = 0; michael@0: } michael@0: // saving incomplete buffer michael@0: this.buffer = buffer; michael@0: this.bufferLength = bufferLength; michael@0: this.iv = iv; michael@0: if (result.length === 0) { michael@0: return new Uint8Array([]); michael@0: } michael@0: // combining plain text blocks into one michael@0: var outputLength = 16 * result.length; michael@0: if (finalize) { michael@0: // undo a padding that is described in RFC 2898 michael@0: var lastBlock = result[result.length - 1]; michael@0: outputLength -= lastBlock[15]; michael@0: result[result.length - 1] = lastBlock.subarray(0, 16 - lastBlock[15]); michael@0: } michael@0: var output = new Uint8Array(outputLength); michael@0: for (i = 0, j = 0, ii = result.length; i < ii; ++i, j += 16) { michael@0: output.set(result[i], j); michael@0: } michael@0: return output; michael@0: } michael@0: michael@0: AES128Cipher.prototype = { michael@0: decryptBlock: function AES128Cipher_decryptBlock(data, finalize) { michael@0: var i, sourceLength = data.length; michael@0: var buffer = this.buffer, bufferLength = this.bufferPosition; michael@0: // waiting for IV values -- they are at the start of the stream michael@0: for (i = 0; bufferLength < 16 && i < sourceLength; ++i, ++bufferLength) { michael@0: buffer[bufferLength] = data[i]; michael@0: } michael@0: if (bufferLength < 16) { michael@0: // need more data michael@0: this.bufferLength = bufferLength; michael@0: return new Uint8Array([]); michael@0: } michael@0: this.iv = buffer; michael@0: this.buffer = new Uint8Array(16); michael@0: this.bufferLength = 0; michael@0: // starting decryption michael@0: this.decryptBlock = decryptBlock2; michael@0: return this.decryptBlock(data.subarray(16), finalize); michael@0: } michael@0: }; michael@0: michael@0: return AES128Cipher; michael@0: })(); michael@0: michael@0: var CipherTransform = (function CipherTransformClosure() { michael@0: function CipherTransform(stringCipherConstructor, streamCipherConstructor) { michael@0: this.stringCipherConstructor = stringCipherConstructor; michael@0: this.streamCipherConstructor = streamCipherConstructor; michael@0: } michael@0: CipherTransform.prototype = { michael@0: createStream: function CipherTransform_createStream(stream, length) { michael@0: var cipher = new this.streamCipherConstructor(); michael@0: return new DecryptStream(stream, length, michael@0: function cipherTransformDecryptStream(data, finalize) { michael@0: return cipher.decryptBlock(data, finalize); michael@0: } michael@0: ); michael@0: }, michael@0: decryptString: function CipherTransform_decryptString(s) { michael@0: var cipher = new this.stringCipherConstructor(); michael@0: var data = stringToBytes(s); michael@0: data = cipher.decryptBlock(data, true); michael@0: return bytesToString(data); michael@0: } michael@0: }; michael@0: return CipherTransform; michael@0: })(); michael@0: michael@0: var CipherTransformFactory = (function CipherTransformFactoryClosure() { michael@0: var defaultPasswordBytes = new Uint8Array([ michael@0: 0x28, 0xBF, 0x4E, 0x5E, 0x4E, 0x75, 0x8A, 0x41, michael@0: 0x64, 0x00, 0x4E, 0x56, 0xFF, 0xFA, 0x01, 0x08, michael@0: 0x2E, 0x2E, 0x00, 0xB6, 0xD0, 0x68, 0x3E, 0x80, michael@0: 0x2F, 0x0C, 0xA9, 0xFE, 0x64, 0x53, 0x69, 0x7A]); michael@0: michael@0: function prepareKeyData(fileId, password, ownerPassword, userPassword, michael@0: flags, revision, keyLength, encryptMetadata) { michael@0: var hashDataSize = 40 + ownerPassword.length + fileId.length; michael@0: var hashData = new Uint8Array(hashDataSize), i = 0, j, n; michael@0: if (password) { michael@0: n = Math.min(32, password.length); michael@0: for (; i < n; ++i) { michael@0: hashData[i] = password[i]; michael@0: } michael@0: } michael@0: j = 0; michael@0: while (i < 32) { michael@0: hashData[i++] = defaultPasswordBytes[j++]; michael@0: } michael@0: // as now the padded password in the hashData[0..i] michael@0: for (j = 0, n = ownerPassword.length; j < n; ++j) { michael@0: hashData[i++] = ownerPassword[j]; michael@0: } michael@0: hashData[i++] = flags & 0xFF; michael@0: hashData[i++] = (flags >> 8) & 0xFF; michael@0: hashData[i++] = (flags >> 16) & 0xFF; michael@0: hashData[i++] = (flags >>> 24) & 0xFF; michael@0: for (j = 0, n = fileId.length; j < n; ++j) { michael@0: hashData[i++] = fileId[j]; michael@0: } michael@0: if (revision >= 4 && !encryptMetadata) { michael@0: hashData[i++] = 0xFF; michael@0: hashData[i++] = 0xFF; michael@0: hashData[i++] = 0xFF; michael@0: hashData[i++] = 0xFF; michael@0: } michael@0: var hash = calculateMD5(hashData, 0, i); michael@0: var keyLengthInBytes = keyLength >> 3; michael@0: if (revision >= 3) { michael@0: for (j = 0; j < 50; ++j) { michael@0: hash = calculateMD5(hash, 0, keyLengthInBytes); michael@0: } michael@0: } michael@0: var encryptionKey = hash.subarray(0, keyLengthInBytes); michael@0: var cipher, checkData; michael@0: michael@0: if (revision >= 3) { michael@0: for (i = 0; i < 32; ++i) { michael@0: hashData[i] = defaultPasswordBytes[i]; michael@0: } michael@0: for (j = 0, n = fileId.length; j < n; ++j) { michael@0: hashData[i++] = fileId[j]; michael@0: } michael@0: cipher = new ARCFourCipher(encryptionKey); michael@0: checkData = cipher.encryptBlock(calculateMD5(hashData, 0, i)); michael@0: n = encryptionKey.length; michael@0: var derivedKey = new Uint8Array(n), k; michael@0: for (j = 1; j <= 19; ++j) { michael@0: for (k = 0; k < n; ++k) { michael@0: derivedKey[k] = encryptionKey[k] ^ j; michael@0: } michael@0: cipher = new ARCFourCipher(derivedKey); michael@0: checkData = cipher.encryptBlock(checkData); michael@0: } michael@0: for (j = 0, n = checkData.length; j < n; ++j) { michael@0: if (userPassword[j] != checkData[j]) { michael@0: return null; michael@0: } michael@0: } michael@0: } else { michael@0: cipher = new ARCFourCipher(encryptionKey); michael@0: checkData = cipher.encryptBlock(defaultPasswordBytes); michael@0: for (j = 0, n = checkData.length; j < n; ++j) { michael@0: if (userPassword[j] != checkData[j]) { michael@0: return null; michael@0: } michael@0: } michael@0: } michael@0: return encryptionKey; michael@0: } michael@0: michael@0: function decodeUserPassword(password, ownerPassword, revision, keyLength) { michael@0: var hashData = new Uint8Array(32), i = 0, j, n; michael@0: n = Math.min(32, password.length); michael@0: for (; i < n; ++i) { michael@0: hashData[i] = password[i]; michael@0: } michael@0: j = 0; michael@0: while (i < 32) { michael@0: hashData[i++] = defaultPasswordBytes[j++]; michael@0: } michael@0: var hash = calculateMD5(hashData, 0, i); michael@0: var keyLengthInBytes = keyLength >> 3; michael@0: if (revision >= 3) { michael@0: for (j = 0; j < 50; ++j) { michael@0: hash = calculateMD5(hash, 0, hash.length); michael@0: } michael@0: } michael@0: michael@0: var cipher, userPassword; michael@0: if (revision >= 3) { michael@0: userPassword = ownerPassword; michael@0: var derivedKey = new Uint8Array(keyLengthInBytes), k; michael@0: for (j = 19; j >= 0; j--) { michael@0: for (k = 0; k < keyLengthInBytes; ++k) { michael@0: derivedKey[k] = hash[k] ^ j; michael@0: } michael@0: cipher = new ARCFourCipher(derivedKey); michael@0: userPassword = cipher.encryptBlock(userPassword); michael@0: } michael@0: } else { michael@0: cipher = new ARCFourCipher(hash.subarray(0, keyLengthInBytes)); michael@0: userPassword = cipher.encryptBlock(ownerPassword); michael@0: } michael@0: return userPassword; michael@0: } michael@0: michael@0: var identityName = Name.get('Identity'); michael@0: michael@0: function CipherTransformFactory(dict, fileId, password) { michael@0: var filter = dict.get('Filter'); michael@0: if (!isName(filter) || filter.name != 'Standard') { michael@0: error('unknown encryption method'); michael@0: } michael@0: this.dict = dict; michael@0: var algorithm = dict.get('V'); michael@0: if (!isInt(algorithm) || michael@0: (algorithm != 1 && algorithm != 2 && algorithm != 4)) { michael@0: error('unsupported encryption algorithm'); michael@0: } michael@0: this.algorithm = algorithm; michael@0: var keyLength = dict.get('Length') || 40; michael@0: if (!isInt(keyLength) || michael@0: keyLength < 40 || (keyLength % 8) !== 0) { michael@0: error('invalid key length'); michael@0: } michael@0: michael@0: // prepare keys michael@0: var ownerPassword = stringToBytes(dict.get('O')).subarray(0, 32); michael@0: var userPassword = stringToBytes(dict.get('U')).subarray(0, 32); michael@0: var flags = dict.get('P'); michael@0: var revision = dict.get('R'); michael@0: var encryptMetadata = (algorithm == 4 && // meaningful when V is 4 michael@0: dict.get('EncryptMetadata') !== false); // makes true as default value michael@0: this.encryptMetadata = encryptMetadata; michael@0: michael@0: var fileIdBytes = stringToBytes(fileId); michael@0: var passwordBytes; michael@0: if (password) { michael@0: passwordBytes = stringToBytes(password); michael@0: } michael@0: michael@0: var encryptionKey = prepareKeyData(fileIdBytes, passwordBytes, michael@0: ownerPassword, userPassword, flags, michael@0: revision, keyLength, encryptMetadata); michael@0: if (!encryptionKey && !password) { michael@0: throw new PasswordException('No password given', michael@0: PasswordResponses.NEED_PASSWORD); michael@0: } else if (!encryptionKey && password) { michael@0: // Attempting use the password as an owner password michael@0: var decodedPassword = decodeUserPassword(passwordBytes, ownerPassword, michael@0: revision, keyLength); michael@0: encryptionKey = prepareKeyData(fileIdBytes, decodedPassword, michael@0: ownerPassword, userPassword, flags, michael@0: revision, keyLength, encryptMetadata); michael@0: } michael@0: michael@0: if (!encryptionKey) { michael@0: throw new PasswordException('Incorrect Password', michael@0: PasswordResponses.INCORRECT_PASSWORD); michael@0: } michael@0: michael@0: this.encryptionKey = encryptionKey; michael@0: michael@0: if (algorithm == 4) { michael@0: this.cf = dict.get('CF'); michael@0: this.stmf = dict.get('StmF') || identityName; michael@0: this.strf = dict.get('StrF') || identityName; michael@0: this.eff = dict.get('EFF') || this.strf; michael@0: } michael@0: } michael@0: michael@0: function buildObjectKey(num, gen, encryptionKey, isAes) { michael@0: var key = new Uint8Array(encryptionKey.length + 9), i, n; michael@0: for (i = 0, n = encryptionKey.length; i < n; ++i) { michael@0: key[i] = encryptionKey[i]; michael@0: } michael@0: key[i++] = num & 0xFF; michael@0: key[i++] = (num >> 8) & 0xFF; michael@0: key[i++] = (num >> 16) & 0xFF; michael@0: key[i++] = gen & 0xFF; michael@0: key[i++] = (gen >> 8) & 0xFF; michael@0: if (isAes) { michael@0: key[i++] = 0x73; michael@0: key[i++] = 0x41; michael@0: key[i++] = 0x6C; michael@0: key[i++] = 0x54; michael@0: } michael@0: var hash = calculateMD5(key, 0, i); michael@0: return hash.subarray(0, Math.min(encryptionKey.length + 5, 16)); michael@0: } michael@0: michael@0: function buildCipherConstructor(cf, name, num, gen, key) { michael@0: var cryptFilter = cf.get(name.name); michael@0: var cfm; michael@0: if (cryptFilter !== null && cryptFilter !== undefined) { michael@0: cfm = cryptFilter.get('CFM'); michael@0: } michael@0: if (!cfm || cfm.name == 'None') { michael@0: return function cipherTransformFactoryBuildCipherConstructorNone() { michael@0: return new NullCipher(); michael@0: }; michael@0: } michael@0: if ('V2' == cfm.name) { michael@0: return function cipherTransformFactoryBuildCipherConstructorV2() { michael@0: return new ARCFourCipher(buildObjectKey(num, gen, key, false)); michael@0: }; michael@0: } michael@0: if ('AESV2' == cfm.name) { michael@0: return function cipherTransformFactoryBuildCipherConstructorAESV2() { michael@0: return new AES128Cipher(buildObjectKey(num, gen, key, true)); michael@0: }; michael@0: } michael@0: error('Unknown crypto method'); michael@0: } michael@0: michael@0: CipherTransformFactory.prototype = { michael@0: createCipherTransform: michael@0: function CipherTransformFactory_createCipherTransform(num, gen) { michael@0: if (this.algorithm == 4) { michael@0: return new CipherTransform( michael@0: buildCipherConstructor(this.cf, this.stmf, michael@0: num, gen, this.encryptionKey), michael@0: buildCipherConstructor(this.cf, this.strf, michael@0: num, gen, this.encryptionKey)); michael@0: } michael@0: // algorithms 1 and 2 michael@0: var key = buildObjectKey(num, gen, this.encryptionKey, false); michael@0: var cipherConstructor = function buildCipherCipherConstructor() { michael@0: return new ARCFourCipher(key); michael@0: }; michael@0: return new CipherTransform(cipherConstructor, cipherConstructor); michael@0: } michael@0: }; michael@0: michael@0: return CipherTransformFactory; michael@0: })(); michael@0: michael@0: michael@0: michael@0: var PatternType = { michael@0: FUNCTION_BASED: 1, michael@0: AXIAL: 2, michael@0: RADIAL: 3, michael@0: FREE_FORM_MESH: 4, michael@0: LATTICE_FORM_MESH: 5, michael@0: COONS_PATCH_MESH: 6, michael@0: TENSOR_PATCH_MESH: 7 michael@0: }; michael@0: michael@0: var Pattern = (function PatternClosure() { michael@0: // Constructor should define this.getPattern michael@0: function Pattern() { michael@0: error('should not call Pattern constructor'); michael@0: } michael@0: michael@0: Pattern.prototype = { michael@0: // Input: current Canvas context michael@0: // Output: the appropriate fillStyle or strokeStyle michael@0: getPattern: function Pattern_getPattern(ctx) { michael@0: error('Should not call Pattern.getStyle: ' + ctx); michael@0: } michael@0: }; michael@0: michael@0: Pattern.parseShading = function Pattern_parseShading(shading, matrix, xref, michael@0: res) { michael@0: michael@0: var dict = isStream(shading) ? shading.dict : shading; michael@0: var type = dict.get('ShadingType'); michael@0: michael@0: switch (type) { michael@0: case PatternType.AXIAL: michael@0: case PatternType.RADIAL: michael@0: // Both radial and axial shadings are handled by RadialAxial shading. michael@0: return new Shadings.RadialAxial(dict, matrix, xref, res); michael@0: case PatternType.FREE_FORM_MESH: michael@0: case PatternType.LATTICE_FORM_MESH: michael@0: case PatternType.COONS_PATCH_MESH: michael@0: case PatternType.TENSOR_PATCH_MESH: michael@0: return new Shadings.Mesh(shading, matrix, xref, res); michael@0: default: michael@0: UnsupportedManager.notify(UNSUPPORTED_FEATURES.shadingPattern); michael@0: return new Shadings.Dummy(); michael@0: } michael@0: }; michael@0: return Pattern; michael@0: })(); michael@0: michael@0: var Shadings = {}; michael@0: michael@0: // A small number to offset the first/last color stops so we can insert ones to michael@0: // support extend. Number.MIN_VALUE appears to be too small and breaks the michael@0: // extend. 1e-7 works in FF but chrome seems to use an even smaller sized number michael@0: // internally so we have to go bigger. michael@0: Shadings.SMALL_NUMBER = 1e-2; michael@0: michael@0: // Radial and axial shading have very similar implementations michael@0: // If needed, the implementations can be broken into two classes michael@0: Shadings.RadialAxial = (function RadialAxialClosure() { michael@0: function RadialAxial(dict, matrix, xref, res) { michael@0: this.matrix = matrix; michael@0: this.coordsArr = dict.get('Coords'); michael@0: this.shadingType = dict.get('ShadingType'); michael@0: this.type = 'Pattern'; michael@0: var cs = dict.get('ColorSpace', 'CS'); michael@0: cs = ColorSpace.parse(cs, xref, res); michael@0: this.cs = cs; michael@0: michael@0: var t0 = 0.0, t1 = 1.0; michael@0: if (dict.has('Domain')) { michael@0: var domainArr = dict.get('Domain'); michael@0: t0 = domainArr[0]; michael@0: t1 = domainArr[1]; michael@0: } michael@0: michael@0: var extendStart = false, extendEnd = false; michael@0: if (dict.has('Extend')) { michael@0: var extendArr = dict.get('Extend'); michael@0: extendStart = extendArr[0]; michael@0: extendEnd = extendArr[1]; michael@0: } michael@0: michael@0: if (this.shadingType === PatternType.RADIAL && michael@0: (!extendStart || !extendEnd)) { michael@0: // Radial gradient only currently works if either circle is fully within michael@0: // the other circle. michael@0: var x1 = this.coordsArr[0]; michael@0: var y1 = this.coordsArr[1]; michael@0: var r1 = this.coordsArr[2]; michael@0: var x2 = this.coordsArr[3]; michael@0: var y2 = this.coordsArr[4]; michael@0: var r2 = this.coordsArr[5]; michael@0: var distance = Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)); michael@0: if (r1 <= r2 + distance && michael@0: r2 <= r1 + distance) { michael@0: warn('Unsupported radial gradient.'); michael@0: } michael@0: } michael@0: michael@0: this.extendStart = extendStart; michael@0: this.extendEnd = extendEnd; michael@0: michael@0: var fnObj = dict.get('Function'); michael@0: var fn; michael@0: if (isArray(fnObj)) { michael@0: var fnArray = []; michael@0: for (var j = 0, jj = fnObj.length; j < jj; j++) { michael@0: var obj = xref.fetchIfRef(fnObj[j]); michael@0: if (!isPDFFunction(obj)) { michael@0: error('Invalid function'); michael@0: } michael@0: fnArray.push(PDFFunction.parse(xref, obj)); michael@0: } michael@0: fn = function radialAxialColorFunction(arg) { michael@0: var out = []; michael@0: for (var i = 0, ii = fnArray.length; i < ii; i++) { michael@0: out.push(fnArray[i](arg)[0]); michael@0: } michael@0: return out; michael@0: }; michael@0: } else { michael@0: if (!isPDFFunction(fnObj)) { michael@0: error('Invalid function'); michael@0: } michael@0: fn = PDFFunction.parse(xref, fnObj); michael@0: } michael@0: michael@0: // 10 samples seems good enough for now, but probably won't work michael@0: // if there are sharp color changes. Ideally, we would implement michael@0: // the spec faithfully and add lossless optimizations. michael@0: var diff = t1 - t0; michael@0: var step = diff / 10; michael@0: michael@0: var colorStops = this.colorStops = []; michael@0: michael@0: // Protect against bad domains so we don't end up in an infinte loop below. michael@0: if (t0 >= t1 || step <= 0) { michael@0: // Acrobat doesn't seem to handle these cases so we'll ignore for michael@0: // now. michael@0: info('Bad shading domain.'); michael@0: return; michael@0: } michael@0: michael@0: var rgbColor; michael@0: for (var i = t0; i <= t1; i += step) { michael@0: rgbColor = cs.getRgb(fn([i]), 0); michael@0: var cssColor = Util.makeCssRgb(rgbColor); michael@0: colorStops.push([(i - t0) / diff, cssColor]); michael@0: } michael@0: michael@0: var background = 'transparent'; michael@0: if (dict.has('Background')) { michael@0: rgbColor = cs.getRgb(dict.get('Background'), 0); michael@0: background = Util.makeCssRgb(rgbColor); michael@0: } michael@0: michael@0: if (!extendStart) { michael@0: // Insert a color stop at the front and offset the first real color stop michael@0: // so it doesn't conflict with the one we insert. michael@0: colorStops.unshift([0, background]); michael@0: colorStops[1][0] += Shadings.SMALL_NUMBER; michael@0: } michael@0: if (!extendEnd) { michael@0: // Same idea as above in extendStart but for the end. michael@0: colorStops[colorStops.length - 1][0] -= Shadings.SMALL_NUMBER; michael@0: colorStops.push([1, background]); michael@0: } michael@0: michael@0: this.colorStops = colorStops; michael@0: } michael@0: michael@0: RadialAxial.prototype = { michael@0: getIR: function RadialAxial_getIR() { michael@0: var coordsArr = this.coordsArr; michael@0: var shadingType = this.shadingType; michael@0: var type, p0, p1, r0, r1; michael@0: if (shadingType == PatternType.AXIAL) { michael@0: p0 = [coordsArr[0], coordsArr[1]]; michael@0: p1 = [coordsArr[2], coordsArr[3]]; michael@0: r0 = null; michael@0: r1 = null; michael@0: type = 'axial'; michael@0: } else if (shadingType == PatternType.RADIAL) { michael@0: p0 = [coordsArr[0], coordsArr[1]]; michael@0: p1 = [coordsArr[3], coordsArr[4]]; michael@0: r0 = coordsArr[2]; michael@0: r1 = coordsArr[5]; michael@0: type = 'radial'; michael@0: } else { michael@0: error('getPattern type unknown: ' + shadingType); michael@0: } michael@0: michael@0: var matrix = this.matrix; michael@0: if (matrix) { michael@0: p0 = Util.applyTransform(p0, matrix); michael@0: p1 = Util.applyTransform(p1, matrix); michael@0: } michael@0: michael@0: return ['RadialAxial', type, this.colorStops, p0, p1, r0, r1]; michael@0: } michael@0: }; michael@0: michael@0: return RadialAxial; michael@0: })(); michael@0: michael@0: // All mesh shading. For now, they will be presented as set of the triangles michael@0: // to be drawn on the canvas and rgb color for each vertex. michael@0: Shadings.Mesh = (function MeshClosure() { michael@0: function MeshStreamReader(stream, context) { michael@0: this.stream = stream; michael@0: this.context = context; michael@0: this.buffer = 0; michael@0: this.bufferLength = 0; michael@0: } michael@0: MeshStreamReader.prototype = { michael@0: get hasData() { michael@0: if (this.stream.end) { michael@0: return this.stream.pos < this.stream.end; michael@0: } michael@0: if (this.bufferLength > 0) { michael@0: return true; michael@0: } michael@0: var nextByte = this.stream.getByte(); michael@0: if (nextByte < 0) { michael@0: return false; michael@0: } michael@0: this.buffer = nextByte; michael@0: this.bufferLength = 8; michael@0: return true; michael@0: }, michael@0: readBits: function MeshStreamReader_readBits(n) { michael@0: var buffer = this.buffer; michael@0: var bufferLength = this.bufferLength; michael@0: if (n === 32) { michael@0: if (bufferLength === 0) { michael@0: return ((this.stream.getByte() << 24) | michael@0: (this.stream.getByte() << 16) | (this.stream.getByte() << 8) | michael@0: this.stream.getByte()) >>> 0; michael@0: } michael@0: buffer = (buffer << 24) | (this.stream.getByte() << 16) | michael@0: (this.stream.getByte() << 8) | this.stream.getByte(); michael@0: var nextByte = this.stream.getByte(); michael@0: this.buffer = nextByte & ((1 << bufferLength) - 1); michael@0: return ((buffer << (8 - bufferLength)) | michael@0: ((nextByte & 0xFF) >> bufferLength)) >>> 0; michael@0: } michael@0: if (n === 8 && bufferLength === 0) { michael@0: return this.stream.getByte(); michael@0: } michael@0: while (bufferLength < n) { michael@0: buffer = (buffer << 8) | this.stream.getByte(); michael@0: bufferLength += 8; michael@0: } michael@0: bufferLength -= n; michael@0: this.bufferLength = bufferLength; michael@0: this.buffer = buffer & ((1 << bufferLength) - 1); michael@0: return buffer >> bufferLength; michael@0: }, michael@0: align: function MeshStreamReader_align() { michael@0: this.buffer = 0; michael@0: this.bufferLength = 0; michael@0: }, michael@0: readFlag: function MeshStreamReader_readFlag() { michael@0: return this.readBits(this.context.bitsPerFlag); michael@0: }, michael@0: readCoordinate: function MeshStreamReader_readCoordinate() { michael@0: var bitsPerCoordinate = this.context.bitsPerCoordinate; michael@0: var xi = this.readBits(bitsPerCoordinate); michael@0: var yi = this.readBits(bitsPerCoordinate); michael@0: var decode = this.context.decode; michael@0: var scale = bitsPerCoordinate < 32 ? 1 / ((1 << bitsPerCoordinate) - 1) : michael@0: 2.3283064365386963e-10; // 2 ^ -32 michael@0: return [ michael@0: xi * scale * (decode[1] - decode[0]) + decode[0], michael@0: yi * scale * (decode[3] - decode[2]) + decode[2] michael@0: ]; michael@0: }, michael@0: readComponents: function MeshStreamReader_readComponents() { michael@0: var numComps = this.context.numComps; michael@0: var bitsPerComponent = this.context.bitsPerComponent; michael@0: var scale = bitsPerComponent < 32 ? 1 / ((1 << bitsPerComponent) - 1) : michael@0: 2.3283064365386963e-10; // 2 ^ -32 michael@0: var decode = this.context.decode; michael@0: var components = []; michael@0: for (var i = 0, j = 4; i < numComps; i++, j += 2) { michael@0: var ci = this.readBits(bitsPerComponent); michael@0: components.push(ci * scale * (decode[j + 1] - decode[j]) + decode[j]); michael@0: } michael@0: if (this.context.colorFn) { michael@0: components = this.context.colorFn(components); michael@0: } michael@0: return this.context.colorSpace.getRgb(components, 0); michael@0: } michael@0: }; michael@0: michael@0: function decodeType4Shading(mesh, reader) { michael@0: var coords = mesh.coords; michael@0: var colors = mesh.colors; michael@0: var operators = []; michael@0: var ps = []; // not maintaining cs since that will match ps michael@0: var verticesLeft = 0; // assuming we have all data to start a new triangle michael@0: while (reader.hasData) { michael@0: var f = reader.readFlag(); michael@0: var coord = reader.readCoordinate(); michael@0: var color = reader.readComponents(); michael@0: if (verticesLeft === 0) { // ignoring flags if we started a triangle michael@0: assert(0 <= f && f <= 2, 'Unknown type4 flag'); michael@0: switch (f) { michael@0: case 0: michael@0: verticesLeft = 3; michael@0: break; michael@0: case 1: michael@0: ps.push(ps[ps.length - 2], ps[ps.length - 1]); michael@0: verticesLeft = 1; michael@0: break; michael@0: case 2: michael@0: ps.push(ps[ps.length - 3], ps[ps.length - 1]); michael@0: verticesLeft = 1; michael@0: break; michael@0: } michael@0: operators.push(f); michael@0: } michael@0: ps.push(coords.length); michael@0: coords.push(coord); michael@0: colors.push(color); michael@0: verticesLeft--; michael@0: michael@0: reader.align(); michael@0: } michael@0: michael@0: var psPacked = new Int32Array(ps); michael@0: michael@0: mesh.figures.push({ michael@0: type: 'triangles', michael@0: coords: psPacked, michael@0: colors: psPacked michael@0: }); michael@0: } michael@0: michael@0: function decodeType5Shading(mesh, reader, verticesPerRow) { michael@0: var coords = mesh.coords; michael@0: var colors = mesh.colors; michael@0: var ps = []; // not maintaining cs since that will match ps michael@0: while (reader.hasData) { michael@0: var coord = reader.readCoordinate(); michael@0: var color = reader.readComponents(); michael@0: ps.push(coords.length); michael@0: coords.push(coord); michael@0: colors.push(color); michael@0: } michael@0: michael@0: var psPacked = new Int32Array(ps); michael@0: michael@0: mesh.figures.push({ michael@0: type: 'lattice', michael@0: coords: psPacked, michael@0: colors: psPacked, michael@0: verticesPerRow: verticesPerRow michael@0: }); michael@0: } michael@0: michael@0: var MIN_SPLIT_PATCH_CHUNKS_AMOUNT = 3; michael@0: var MAX_SPLIT_PATCH_CHUNKS_AMOUNT = 20; michael@0: michael@0: var TRIANGLE_DENSITY = 20; // count of triangles per entire mesh bounds michael@0: michael@0: var getB = (function getBClosure() { michael@0: function buildB(count) { michael@0: var lut = []; michael@0: for (var i = 0; i <= count; i++) { michael@0: var t = i / count, t_ = 1 - t; michael@0: lut.push(new Float32Array([t_ * t_ * t_, 3 * t * t_ * t_, michael@0: 3 * t * t * t_, t * t * t])); michael@0: } michael@0: return lut; michael@0: } michael@0: var cache = []; michael@0: return function getB(count) { michael@0: if (!cache[count]) { michael@0: cache[count] = buildB(count); michael@0: } michael@0: return cache[count]; michael@0: }; michael@0: })(); michael@0: michael@0: function buildFigureFromPatch(mesh, index) { michael@0: var figure = mesh.figures[index]; michael@0: assert(figure.type === 'patch', 'Unexpected patch mesh figure'); michael@0: michael@0: var coords = mesh.coords, colors = mesh.colors; michael@0: var pi = figure.coords; michael@0: var ci = figure.colors; michael@0: michael@0: var figureMinX = Math.min(coords[pi[0]][0], coords[pi[3]][0], michael@0: coords[pi[12]][0], coords[pi[15]][0]); michael@0: var figureMinY = Math.min(coords[pi[0]][1], coords[pi[3]][1], michael@0: coords[pi[12]][1], coords[pi[15]][1]); michael@0: var figureMaxX = Math.max(coords[pi[0]][0], coords[pi[3]][0], michael@0: coords[pi[12]][0], coords[pi[15]][0]); michael@0: var figureMaxY = Math.max(coords[pi[0]][1], coords[pi[3]][1], michael@0: coords[pi[12]][1], coords[pi[15]][1]); michael@0: var splitXBy = Math.ceil((figureMaxX - figureMinX) * TRIANGLE_DENSITY / michael@0: (mesh.bounds[2] - mesh.bounds[0])); michael@0: splitXBy = Math.max(MIN_SPLIT_PATCH_CHUNKS_AMOUNT, michael@0: Math.min(MAX_SPLIT_PATCH_CHUNKS_AMOUNT, splitXBy)); michael@0: var splitYBy = Math.ceil((figureMaxY - figureMinY) * TRIANGLE_DENSITY / michael@0: (mesh.bounds[3] - mesh.bounds[1])); michael@0: splitYBy = Math.max(MIN_SPLIT_PATCH_CHUNKS_AMOUNT, michael@0: Math.min(MAX_SPLIT_PATCH_CHUNKS_AMOUNT, splitYBy)); michael@0: michael@0: var verticesPerRow = splitXBy + 1; michael@0: var figureCoords = new Int32Array((splitYBy + 1) * verticesPerRow); michael@0: var figureColors = new Int32Array((splitYBy + 1) * verticesPerRow); michael@0: var k = 0; michael@0: var cl = new Uint8Array(3), cr = new Uint8Array(3); michael@0: var c0 = colors[ci[0]], c1 = colors[ci[1]], michael@0: c2 = colors[ci[2]], c3 = colors[ci[3]]; michael@0: var bRow = getB(splitYBy), bCol = getB(splitXBy); michael@0: for (var row = 0; row <= splitYBy; row++) { michael@0: cl[0] = ((c0[0] * (splitYBy - row) + c2[0] * row) / splitYBy) | 0; michael@0: cl[1] = ((c0[1] * (splitYBy - row) + c2[1] * row) / splitYBy) | 0; michael@0: cl[2] = ((c0[2] * (splitYBy - row) + c2[2] * row) / splitYBy) | 0; michael@0: michael@0: cr[0] = ((c1[0] * (splitYBy - row) + c3[0] * row) / splitYBy) | 0; michael@0: cr[1] = ((c1[1] * (splitYBy - row) + c3[1] * row) / splitYBy) | 0; michael@0: cr[2] = ((c1[2] * (splitYBy - row) + c3[2] * row) / splitYBy) | 0; michael@0: michael@0: for (var col = 0; col <= splitXBy; col++, k++) { michael@0: if ((row === 0 || row === splitYBy) && michael@0: (col === 0 || col === splitXBy)) { michael@0: continue; michael@0: } michael@0: var x = 0, y = 0; michael@0: var q = 0; michael@0: for (var i = 0; i <= 3; i++) { michael@0: for (var j = 0; j <= 3; j++, q++) { michael@0: var m = bRow[row][i] * bCol[col][j]; michael@0: x += coords[pi[q]][0] * m; michael@0: y += coords[pi[q]][1] * m; michael@0: } michael@0: } michael@0: figureCoords[k] = coords.length; michael@0: coords.push([x, y]); michael@0: figureColors[k] = colors.length; michael@0: var newColor = new Uint8Array(3); michael@0: newColor[0] = ((cl[0] * (splitXBy - col) + cr[0] * col) / splitXBy) | 0; michael@0: newColor[1] = ((cl[1] * (splitXBy - col) + cr[1] * col) / splitXBy) | 0; michael@0: newColor[2] = ((cl[2] * (splitXBy - col) + cr[2] * col) / splitXBy) | 0; michael@0: colors.push(newColor); michael@0: } michael@0: } michael@0: figureCoords[0] = pi[0]; michael@0: figureColors[0] = ci[0]; michael@0: figureCoords[splitXBy] = pi[3]; michael@0: figureColors[splitXBy] = ci[1]; michael@0: figureCoords[verticesPerRow * splitYBy] = pi[12]; michael@0: figureColors[verticesPerRow * splitYBy] = ci[2]; michael@0: figureCoords[verticesPerRow * splitYBy + splitXBy] = pi[15]; michael@0: figureColors[verticesPerRow * splitYBy + splitXBy] = ci[3]; michael@0: michael@0: mesh.figures[index] = { michael@0: type: 'lattice', michael@0: coords: figureCoords, michael@0: colors: figureColors, michael@0: verticesPerRow: verticesPerRow michael@0: }; michael@0: } michael@0: michael@0: function decodeType6Shading(mesh, reader) { michael@0: // A special case of Type 7. The p11, p12, p21, p22 automatically filled michael@0: var coords = mesh.coords; michael@0: var colors = mesh.colors; michael@0: var ps = new Int32Array(16); // p00, p10, ..., p30, p01, ..., p33 michael@0: var cs = new Int32Array(4); // c00, c30, c03, c33 michael@0: while (reader.hasData) { michael@0: var f = reader.readFlag(); michael@0: assert(0 <= f && f <= 3, 'Unknown type6 flag'); michael@0: var i, ii; michael@0: var pi = coords.length; michael@0: for (i = 0, ii = (f !== 0 ? 8 : 12); i < ii; i++) { michael@0: coords.push(reader.readCoordinate()); michael@0: } michael@0: var ci = colors.length; michael@0: for (i = 0, ii = (f !== 0 ? 2 : 4); i < ii; i++) { michael@0: colors.push(reader.readComponents()); michael@0: } michael@0: var tmp1, tmp2, tmp3, tmp4; michael@0: switch (f) { michael@0: case 0: michael@0: ps[12] = pi + 3; ps[13] = pi + 4; ps[14] = pi + 5; ps[15] = pi + 6; michael@0: ps[ 8] = pi + 2; /* values for 5, 6, 9, 10 are */ ps[11] = pi + 7; michael@0: ps[ 4] = pi + 1; /* calculated below */ ps[ 7] = pi + 8; michael@0: ps[ 0] = pi; ps[ 1] = pi + 11; ps[ 2] = pi + 10; ps[ 3] = pi + 9; michael@0: cs[2] = ci + 1; cs[3] = ci + 2; michael@0: cs[0] = ci; cs[1] = ci + 3; michael@0: break; michael@0: case 1: michael@0: tmp1 = ps[12]; tmp2 = ps[13]; tmp3 = ps[14]; tmp4 = ps[15]; michael@0: ps[12] = pi + 5; ps[13] = pi + 4; ps[14] = pi + 3; ps[15] = pi + 2; michael@0: ps[ 8] = pi + 6; /* values for 5, 6, 9, 10 are */ ps[11] = pi + 1; michael@0: ps[ 4] = pi + 7; /* calculated below */ ps[ 7] = pi; michael@0: ps[ 0] = tmp1; ps[ 1] = tmp2; ps[ 2] = tmp3; ps[ 3] = tmp4; michael@0: tmp1 = cs[2]; tmp2 = cs[3]; michael@0: cs[2] = ci + 1; cs[3] = ci; michael@0: cs[0] = tmp1; cs[1] = tmp2; michael@0: break; michael@0: case 2: michael@0: ps[12] = ps[15]; ps[13] = pi + 7; ps[14] = pi + 6; ps[15] = pi + 5; michael@0: ps[ 8] = ps[11]; /* values for 5, 6, 9, 10 are */ ps[11] = pi + 4; michael@0: ps[ 4] = ps[7]; /* calculated below */ ps[ 7] = pi + 3; michael@0: ps[ 0] = ps[3]; ps[ 1] = pi; ps[ 2] = pi + 1; ps[ 3] = pi + 2; michael@0: cs[2] = cs[3]; cs[3] = ci + 1; michael@0: cs[0] = cs[1]; cs[1] = ci; michael@0: break; michael@0: case 3: michael@0: ps[12] = ps[0]; ps[13] = ps[1]; ps[14] = ps[2]; ps[15] = ps[3]; michael@0: ps[ 8] = pi; /* values for 5, 6, 9, 10 are */ ps[11] = pi + 7; michael@0: ps[ 4] = pi + 1; /* calculated below */ ps[ 7] = pi + 6; michael@0: ps[ 0] = pi + 2; ps[ 1] = pi + 3; ps[ 2] = pi + 4; ps[ 3] = pi + 5; michael@0: cs[2] = cs[0]; cs[3] = cs[1]; michael@0: cs[0] = ci; cs[1] = ci + 1; michael@0: break; michael@0: } michael@0: // set p11, p12, p21, p22 michael@0: ps[5] = coords.length; michael@0: coords.push([ michael@0: (-4 * coords[ps[0]][0] - coords[ps[15]][0] + michael@0: 6 * (coords[ps[4]][0] + coords[ps[1]][0]) - michael@0: 2 * (coords[ps[12]][0] + coords[ps[3]][0]) + michael@0: 3 * (coords[ps[13]][0] + coords[ps[7]][0])) / 9, michael@0: (-4 * coords[ps[0]][1] - coords[ps[15]][1] + michael@0: 6 * (coords[ps[4]][1] + coords[ps[1]][1]) - michael@0: 2 * (coords[ps[12]][1] + coords[ps[3]][1]) + michael@0: 3 * (coords[ps[13]][1] + coords[ps[7]][1])) / 9 michael@0: ]); michael@0: ps[6] = coords.length; michael@0: coords.push([ michael@0: (-4 * coords[ps[3]][0] - coords[ps[12]][0] + michael@0: 6 * (coords[ps[2]][0] + coords[ps[7]][0]) - michael@0: 2 * (coords[ps[0]][0] + coords[ps[15]][0]) + michael@0: 3 * (coords[ps[4]][0] + coords[ps[14]][0])) / 9, michael@0: (-4 * coords[ps[3]][1] - coords[ps[12]][1] + michael@0: 6 * (coords[ps[2]][1] + coords[ps[7]][1]) - michael@0: 2 * (coords[ps[0]][1] + coords[ps[15]][1]) + michael@0: 3 * (coords[ps[4]][1] + coords[ps[14]][1])) / 9 michael@0: ]); michael@0: ps[9] = coords.length; michael@0: coords.push([ michael@0: (-4 * coords[ps[12]][0] - coords[ps[3]][0] + michael@0: 6 * (coords[ps[8]][0] + coords[ps[13]][0]) - michael@0: 2 * (coords[ps[0]][0] + coords[ps[15]][0]) + michael@0: 3 * (coords[ps[11]][0] + coords[ps[1]][0])) / 9, michael@0: (-4 * coords[ps[12]][1] - coords[ps[3]][1] + michael@0: 6 * (coords[ps[8]][1] + coords[ps[13]][1]) - michael@0: 2 * (coords[ps[0]][1] + coords[ps[15]][1]) + michael@0: 3 * (coords[ps[11]][1] + coords[ps[1]][1])) / 9 michael@0: ]); michael@0: ps[10] = coords.length; michael@0: coords.push([ michael@0: (-4 * coords[ps[15]][0] - coords[ps[0]][0] + michael@0: 6 * (coords[ps[11]][0] + coords[ps[14]][0]) - michael@0: 2 * (coords[ps[12]][0] + coords[ps[3]][0]) + michael@0: 3 * (coords[ps[2]][0] + coords[ps[8]][0])) / 9, michael@0: (-4 * coords[ps[15]][1] - coords[ps[0]][1] + michael@0: 6 * (coords[ps[11]][1] + coords[ps[14]][1]) - michael@0: 2 * (coords[ps[12]][1] + coords[ps[3]][1]) + michael@0: 3 * (coords[ps[2]][1] + coords[ps[8]][1])) / 9 michael@0: ]); michael@0: mesh.figures.push({ michael@0: type: 'patch', michael@0: coords: new Int32Array(ps), // making copies of ps and cs michael@0: colors: new Int32Array(cs) michael@0: }); michael@0: } michael@0: } michael@0: michael@0: function decodeType7Shading(mesh, reader) { michael@0: var coords = mesh.coords; michael@0: var colors = mesh.colors; michael@0: var ps = new Int32Array(16); // p00, p10, ..., p30, p01, ..., p33 michael@0: var cs = new Int32Array(4); // c00, c30, c03, c33 michael@0: while (reader.hasData) { michael@0: var f = reader.readFlag(); michael@0: assert(0 <= f && f <= 3, 'Unknown type7 flag'); michael@0: var i, ii; michael@0: var pi = coords.length; michael@0: for (i = 0, ii = (f !== 0 ? 12 : 16); i < ii; i++) { michael@0: coords.push(reader.readCoordinate()); michael@0: } michael@0: var ci = colors.length; michael@0: for (i = 0, ii = (f !== 0 ? 2 : 4); i < ii; i++) { michael@0: colors.push(reader.readComponents()); michael@0: } michael@0: var tmp1, tmp2, tmp3, tmp4; michael@0: switch (f) { michael@0: case 0: michael@0: ps[12] = pi + 3; ps[13] = pi + 4; ps[14] = pi + 5; ps[15] = pi + 6; michael@0: ps[ 8] = pi + 2; ps[ 9] = pi + 13; ps[10] = pi + 14; ps[11] = pi + 7; michael@0: ps[ 4] = pi + 1; ps[ 5] = pi + 12; ps[ 6] = pi + 15; ps[ 7] = pi + 8; michael@0: ps[ 0] = pi; ps[ 1] = pi + 11; ps[ 2] = pi + 10; ps[ 3] = pi + 9; michael@0: cs[2] = ci + 1; cs[3] = ci + 2; michael@0: cs[0] = ci; cs[1] = ci + 3; michael@0: break; michael@0: case 1: michael@0: tmp1 = ps[12]; tmp2 = ps[13]; tmp3 = ps[14]; tmp4 = ps[15]; michael@0: ps[12] = pi + 5; ps[13] = pi + 4; ps[14] = pi + 3; ps[15] = pi + 2; michael@0: ps[ 8] = pi + 6; ps[ 9] = pi + 11; ps[10] = pi + 10; ps[11] = pi + 1; michael@0: ps[ 4] = pi + 7; ps[ 5] = pi + 8; ps[ 6] = pi + 9; ps[ 7] = pi; michael@0: ps[ 0] = tmp1; ps[ 1] = tmp2; ps[ 2] = tmp3; ps[ 3] = tmp4; michael@0: tmp1 = cs[2]; tmp2 = cs[3]; michael@0: cs[2] = ci + 1; cs[3] = ci; michael@0: cs[0] = tmp1; cs[1] = tmp2; michael@0: break; michael@0: case 2: michael@0: ps[12] = ps[15]; ps[13] = pi + 7; ps[14] = pi + 6; ps[15] = pi + 5; michael@0: ps[ 8] = ps[11]; ps[ 9] = pi + 8; ps[10] = pi + 11; ps[11] = pi + 4; michael@0: ps[ 4] = ps[7]; ps[ 5] = pi + 9; ps[ 6] = pi + 10; ps[ 7] = pi + 3; michael@0: ps[ 0] = ps[3]; ps[ 1] = pi; ps[ 2] = pi + 1; ps[ 3] = pi + 2; michael@0: cs[2] = cs[3]; cs[3] = ci + 1; michael@0: cs[0] = cs[1]; cs[1] = ci; michael@0: break; michael@0: case 3: michael@0: ps[12] = ps[0]; ps[13] = ps[1]; ps[14] = ps[2]; ps[15] = ps[3]; michael@0: ps[ 8] = pi; ps[ 9] = pi + 9; ps[10] = pi + 8; ps[11] = pi + 7; michael@0: ps[ 4] = pi + 1; ps[ 5] = pi + 10; ps[ 6] = pi + 11; ps[ 7] = pi + 6; michael@0: ps[ 0] = pi + 2; ps[ 1] = pi + 3; ps[ 2] = pi + 4; ps[ 3] = pi + 5; michael@0: cs[2] = cs[0]; cs[3] = cs[1]; michael@0: cs[0] = ci; cs[1] = ci + 1; michael@0: break; michael@0: } michael@0: mesh.figures.push({ michael@0: type: 'patch', michael@0: coords: new Int32Array(ps), // making copies of ps and cs michael@0: colors: new Int32Array(cs) michael@0: }); michael@0: } michael@0: } michael@0: michael@0: function updateBounds(mesh) { michael@0: var minX = mesh.coords[0][0], minY = mesh.coords[0][1], michael@0: maxX = minX, maxY = minY; michael@0: for (var i = 1, ii = mesh.coords.length; i < ii; i++) { michael@0: var x = mesh.coords[i][0], y = mesh.coords[i][1]; michael@0: minX = minX > x ? x : minX; michael@0: minY = minY > y ? y : minY; michael@0: maxX = maxX < x ? x : maxX; michael@0: maxY = maxY < y ? y : maxY; michael@0: } michael@0: mesh.bounds = [minX, minY, maxX, maxY]; michael@0: } michael@0: michael@0: function packData(mesh) { michael@0: var i, ii, j, jj; michael@0: michael@0: var coords = mesh.coords; michael@0: var coordsPacked = new Float32Array(coords.length * 2); michael@0: for (i = 0, j = 0, ii = coords.length; i < ii; i++) { michael@0: var xy = coords[i]; michael@0: coordsPacked[j++] = xy[0]; michael@0: coordsPacked[j++] = xy[1]; michael@0: } michael@0: mesh.coords = coordsPacked; michael@0: michael@0: var colors = mesh.colors; michael@0: var colorsPacked = new Uint8Array(colors.length * 3); michael@0: for (i = 0, j = 0, ii = colors.length; i < ii; i++) { michael@0: var c = colors[i]; michael@0: colorsPacked[j++] = c[0]; michael@0: colorsPacked[j++] = c[1]; michael@0: colorsPacked[j++] = c[2]; michael@0: } michael@0: mesh.colors = colorsPacked; michael@0: michael@0: var figures = mesh.figures; michael@0: for (i = 0, ii = figures.length; i < ii; i++) { michael@0: var figure = figures[i], ps = figure.coords, cs = figure.colors; michael@0: for (j = 0, jj = ps.length; j < jj; j++) { michael@0: ps[j] *= 2; michael@0: cs[j] *= 3; michael@0: } michael@0: } michael@0: } michael@0: michael@0: function Mesh(stream, matrix, xref, res) { michael@0: assert(isStream(stream), 'Mesh data is not a stream'); michael@0: var dict = stream.dict; michael@0: this.matrix = matrix; michael@0: this.shadingType = dict.get('ShadingType'); michael@0: this.type = 'Pattern'; michael@0: this.bbox = dict.get('BBox'); michael@0: var cs = dict.get('ColorSpace', 'CS'); michael@0: cs = ColorSpace.parse(cs, xref, res); michael@0: this.cs = cs; michael@0: this.background = dict.has('Background') ? michael@0: cs.getRgb(dict.get('Background'), 0) : null; michael@0: michael@0: var fnObj = dict.get('Function'); michael@0: var fn; michael@0: if (!fnObj) { michael@0: fn = null; michael@0: } else if (isArray(fnObj)) { michael@0: var fnArray = []; michael@0: for (var j = 0, jj = fnObj.length; j < jj; j++) { michael@0: var obj = xref.fetchIfRef(fnObj[j]); michael@0: if (!isPDFFunction(obj)) { michael@0: error('Invalid function'); michael@0: } michael@0: fnArray.push(PDFFunction.parse(xref, obj)); michael@0: } michael@0: fn = function radialAxialColorFunction(arg) { michael@0: var out = []; michael@0: for (var i = 0, ii = fnArray.length; i < ii; i++) { michael@0: out.push(fnArray[i](arg)[0]); michael@0: } michael@0: return out; michael@0: }; michael@0: } else { michael@0: if (!isPDFFunction(fnObj)) { michael@0: error('Invalid function'); michael@0: } michael@0: fn = PDFFunction.parse(xref, fnObj); michael@0: } michael@0: michael@0: this.coords = []; michael@0: this.colors = []; michael@0: this.figures = []; michael@0: michael@0: var decodeContext = { michael@0: bitsPerCoordinate: dict.get('BitsPerCoordinate'), michael@0: bitsPerComponent: dict.get('BitsPerComponent'), michael@0: bitsPerFlag: dict.get('BitsPerFlag'), michael@0: decode: dict.get('Decode'), michael@0: colorFn: fn, michael@0: colorSpace: cs, michael@0: numComps: fn ? 1 : cs.numComps michael@0: }; michael@0: var reader = new MeshStreamReader(stream, decodeContext); michael@0: michael@0: var patchMesh = false; michael@0: switch (this.shadingType) { michael@0: case PatternType.FREE_FORM_MESH: michael@0: decodeType4Shading(this, reader); michael@0: break; michael@0: case PatternType.LATTICE_FORM_MESH: michael@0: var verticesPerRow = dict.get('VerticesPerRow') | 0; michael@0: assert(verticesPerRow >= 2, 'Invalid VerticesPerRow'); michael@0: decodeType5Shading(this, reader, verticesPerRow); michael@0: break; michael@0: case PatternType.COONS_PATCH_MESH: michael@0: decodeType6Shading(this, reader); michael@0: patchMesh = true; michael@0: break; michael@0: case PatternType.TENSOR_PATCH_MESH: michael@0: decodeType7Shading(this, reader); michael@0: patchMesh = true; michael@0: break; michael@0: default: michael@0: error('Unsupported mesh type.'); michael@0: break; michael@0: } michael@0: michael@0: if (patchMesh) { michael@0: // dirty bounds calculation for determining, how dense shall be triangles michael@0: updateBounds(this); michael@0: for (var i = 0, ii = this.figures.length; i < ii; i++) { michael@0: buildFigureFromPatch(this, i); michael@0: } michael@0: } michael@0: // calculate bounds michael@0: updateBounds(this); michael@0: michael@0: packData(this); michael@0: } michael@0: michael@0: Mesh.prototype = { michael@0: getIR: function Mesh_getIR() { michael@0: return ['Mesh', this.shadingType, this.coords, this.colors, this.figures, michael@0: this.bounds, this.matrix, this.bbox, this.background]; michael@0: } michael@0: }; michael@0: michael@0: return Mesh; michael@0: })(); michael@0: michael@0: Shadings.Dummy = (function DummyClosure() { michael@0: function Dummy() { michael@0: this.type = 'Pattern'; michael@0: } michael@0: michael@0: Dummy.prototype = { michael@0: getIR: function Dummy_getIR() { michael@0: return ['Dummy']; michael@0: } michael@0: }; michael@0: return Dummy; michael@0: })(); michael@0: michael@0: function getTilingPatternIR(operatorList, dict, args) { michael@0: var matrix = dict.get('Matrix'); michael@0: var bbox = dict.get('BBox'); michael@0: var xstep = dict.get('XStep'); michael@0: var ystep = dict.get('YStep'); michael@0: var paintType = dict.get('PaintType'); michael@0: var tilingType = dict.get('TilingType'); michael@0: michael@0: return [ michael@0: 'TilingPattern', args, operatorList, matrix, bbox, xstep, ystep, michael@0: paintType, tilingType michael@0: ]; michael@0: } michael@0: michael@0: michael@0: var PartialEvaluator = (function PartialEvaluatorClosure() { michael@0: function PartialEvaluator(pdfManager, xref, handler, pageIndex, michael@0: uniquePrefix, idCounters, fontCache) { michael@0: this.pdfManager = pdfManager; michael@0: this.xref = xref; michael@0: this.handler = handler; michael@0: this.pageIndex = pageIndex; michael@0: this.uniquePrefix = uniquePrefix; michael@0: this.idCounters = idCounters; michael@0: this.fontCache = fontCache; michael@0: } michael@0: michael@0: var TILING_PATTERN = 1, SHADING_PATTERN = 2; michael@0: michael@0: PartialEvaluator.prototype = { michael@0: hasBlendModes: function PartialEvaluator_hasBlendModes(resources) { michael@0: if (!isDict(resources)) { michael@0: return false; michael@0: } michael@0: michael@0: var processed = Object.create(null); michael@0: if (resources.objId) { michael@0: processed[resources.objId] = true; michael@0: } michael@0: michael@0: var nodes = [resources]; michael@0: while (nodes.length) { michael@0: var key; michael@0: var node = nodes.shift(); michael@0: // First check the current resources for blend modes. michael@0: var graphicStates = node.get('ExtGState'); michael@0: if (isDict(graphicStates)) { michael@0: graphicStates = graphicStates.getAll(); michael@0: for (key in graphicStates) { michael@0: var graphicState = graphicStates[key]; michael@0: var bm = graphicState['BM']; michael@0: if (isName(bm) && bm.name !== 'Normal') { michael@0: return true; michael@0: } michael@0: } michael@0: } michael@0: // Descend into the XObjects to look for more resources and blend modes. michael@0: var xObjects = node.get('XObject'); michael@0: if (!isDict(xObjects)) { michael@0: continue; michael@0: } michael@0: xObjects = xObjects.getAll(); michael@0: for (key in xObjects) { michael@0: var xObject = xObjects[key]; michael@0: if (!isStream(xObject)) { michael@0: continue; michael@0: } michael@0: var xResources = xObject.dict.get('Resources'); michael@0: // Checking objId to detect an infinite loop. michael@0: if (isDict(xResources) && michael@0: (!xResources.objId || !processed[xResources.objId])) { michael@0: nodes.push(xResources); michael@0: if (xResources.objId) { michael@0: processed[xResources.objId] = true; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: return false; michael@0: }, michael@0: michael@0: buildFormXObject: function PartialEvaluator_buildFormXObject(resources, michael@0: xobj, smask, michael@0: operatorList, michael@0: initialState) { michael@0: var matrix = xobj.dict.get('Matrix'); michael@0: var bbox = xobj.dict.get('BBox'); michael@0: var group = xobj.dict.get('Group'); michael@0: if (group) { michael@0: var groupOptions = { michael@0: matrix: matrix, michael@0: bbox: bbox, michael@0: smask: smask, michael@0: isolated: false, michael@0: knockout: false michael@0: }; michael@0: michael@0: var groupSubtype = group.get('S'); michael@0: if (isName(groupSubtype) && groupSubtype.name === 'Transparency') { michael@0: groupOptions.isolated = (group.get('I') || false); michael@0: groupOptions.knockout = (group.get('K') || false); michael@0: var colorSpace = group.get('CS'); michael@0: groupOptions.colorSpace = (colorSpace ? michael@0: ColorSpace.parseToIR(colorSpace, this.xref, resources) : null); michael@0: } michael@0: operatorList.addOp(OPS.beginGroup, [groupOptions]); michael@0: } michael@0: michael@0: operatorList.addOp(OPS.paintFormXObjectBegin, [matrix, bbox]); michael@0: michael@0: this.getOperatorList(xobj, (xobj.dict.get('Resources') || resources), michael@0: operatorList, initialState); michael@0: operatorList.addOp(OPS.paintFormXObjectEnd, []); michael@0: michael@0: if (group) { michael@0: operatorList.addOp(OPS.endGroup, [groupOptions]); michael@0: } michael@0: }, michael@0: michael@0: buildPaintImageXObject: michael@0: function PartialEvaluator_buildPaintImageXObject(resources, image, michael@0: inline, operatorList, michael@0: cacheKey, cache) { michael@0: var self = this; michael@0: var dict = image.dict; michael@0: var w = dict.get('Width', 'W'); michael@0: var h = dict.get('Height', 'H'); michael@0: michael@0: if (!(w && isNum(w)) || !(h && isNum(h))) { michael@0: warn('Image dimensions are missing, or not numbers.'); michael@0: return; michael@0: } michael@0: if (PDFJS.maxImageSize !== -1 && w * h > PDFJS.maxImageSize) { michael@0: warn('Image exceeded maximum allowed size and was removed.'); michael@0: return; michael@0: } michael@0: michael@0: var imageMask = (dict.get('ImageMask', 'IM') || false); michael@0: var imgData, args; michael@0: if (imageMask) { michael@0: // This depends on a tmpCanvas being filled with the michael@0: // current fillStyle, such that processing the pixel michael@0: // data can't be done here. Instead of creating a michael@0: // complete PDFImage, only read the information needed michael@0: // for later. michael@0: michael@0: var width = dict.get('Width', 'W'); michael@0: var height = dict.get('Height', 'H'); michael@0: var bitStrideLength = (width + 7) >> 3; michael@0: var imgArray = image.getBytes(bitStrideLength * height); michael@0: var decode = dict.get('Decode', 'D'); michael@0: var canTransfer = image instanceof DecodeStream; michael@0: var inverseDecode = (!!decode && decode[0] > 0); michael@0: michael@0: imgData = PDFImage.createMask(imgArray, width, height, michael@0: canTransfer, inverseDecode); michael@0: imgData.cached = true; michael@0: args = [imgData]; michael@0: operatorList.addOp(OPS.paintImageMaskXObject, args); michael@0: if (cacheKey) { michael@0: cache.key = cacheKey; michael@0: cache.fn = OPS.paintImageMaskXObject; michael@0: cache.args = args; michael@0: } michael@0: return; michael@0: } michael@0: michael@0: var softMask = (dict.get('SMask', 'SM') || false); michael@0: var mask = (dict.get('Mask') || false); michael@0: michael@0: var SMALL_IMAGE_DIMENSIONS = 200; michael@0: // Inlining small images into the queue as RGB data michael@0: if (inline && !softMask && !mask && !(image instanceof JpegStream) && michael@0: (w + h) < SMALL_IMAGE_DIMENSIONS) { michael@0: var imageObj = new PDFImage(this.xref, resources, image, michael@0: inline, null, null); michael@0: // We force the use of RGBA_32BPP images here, because we can't handle michael@0: // any other kind. michael@0: imgData = imageObj.createImageData(/* forceRGBA = */ true); michael@0: operatorList.addOp(OPS.paintInlineImageXObject, [imgData]); michael@0: return; michael@0: } michael@0: michael@0: // If there is no imageMask, create the PDFImage and a lot michael@0: // of image processing can be done here. michael@0: var uniquePrefix = (this.uniquePrefix || ''); michael@0: var objId = 'img_' + uniquePrefix + (++this.idCounters.obj); michael@0: operatorList.addDependency(objId); michael@0: args = [objId, w, h]; michael@0: michael@0: if (!softMask && !mask && image instanceof JpegStream && michael@0: image.isNativelySupported(this.xref, resources)) { michael@0: // These JPEGs don't need any more processing so we can just send it. michael@0: operatorList.addOp(OPS.paintJpegXObject, args); michael@0: this.handler.send('obj', michael@0: [objId, this.pageIndex, 'JpegStream', image.getIR()]); michael@0: return; michael@0: } michael@0: michael@0: PDFImage.buildImage(self.handler, self.xref, resources, image, inline). michael@0: then(function(imageObj) { michael@0: var imgData = imageObj.createImageData(/* forceRGBA = */ false); michael@0: self.handler.send('obj', [objId, self.pageIndex, 'Image', imgData], michael@0: null, [imgData.data.buffer]); michael@0: }).then(null, function (reason) { michael@0: warn('Unable to decode image: ' + reason); michael@0: self.handler.send('obj', [objId, self.pageIndex, 'Image', null]); michael@0: }); michael@0: michael@0: operatorList.addOp(OPS.paintImageXObject, args); michael@0: if (cacheKey) { michael@0: cache.key = cacheKey; michael@0: cache.fn = OPS.paintImageXObject; michael@0: cache.args = args; michael@0: } michael@0: }, michael@0: michael@0: handleSMask: function PartialEvaluator_handleSmask(smask, resources, michael@0: operatorList, michael@0: stateManager) { michael@0: var smaskContent = smask.get('G'); michael@0: var smaskOptions = { michael@0: subtype: smask.get('S').name, michael@0: backdrop: smask.get('BC') michael@0: }; michael@0: this.buildFormXObject(resources, smaskContent, smaskOptions, michael@0: operatorList, stateManager.state.clone()); michael@0: }, michael@0: michael@0: handleTilingType: michael@0: function PartialEvaluator_handleTilingType(fn, args, resources, michael@0: pattern, patternDict, michael@0: operatorList) { michael@0: // Create an IR of the pattern code. michael@0: var tilingOpList = this.getOperatorList(pattern, michael@0: (patternDict.get('Resources') || resources)); michael@0: // Add the dependencies to the parent operator list so they are resolved michael@0: // before sub operator list is executed synchronously. michael@0: operatorList.addDependencies(tilingOpList.dependencies); michael@0: operatorList.addOp(fn, getTilingPatternIR({ michael@0: fnArray: tilingOpList.fnArray, michael@0: argsArray: tilingOpList.argsArray michael@0: }, patternDict, args)); michael@0: }, michael@0: michael@0: handleSetFont: michael@0: function PartialEvaluator_handleSetFont(resources, fontArgs, fontRef, michael@0: operatorList, state) { michael@0: // TODO(mack): Not needed? michael@0: var fontName; michael@0: if (fontArgs) { michael@0: fontArgs = fontArgs.slice(); michael@0: fontName = fontArgs[0].name; michael@0: } michael@0: var self = this; michael@0: var font = this.loadFont(fontName, fontRef, this.xref, resources, michael@0: operatorList); michael@0: state.font = font; michael@0: var loadedName = font.loadedName; michael@0: if (!font.sent) { michael@0: var fontData = font.translated.exportData(); michael@0: michael@0: self.handler.send('commonobj', [ michael@0: loadedName, michael@0: 'Font', michael@0: fontData michael@0: ]); michael@0: font.sent = true; michael@0: } michael@0: michael@0: return loadedName; michael@0: }, michael@0: michael@0: handleText: function PartialEvaluator_handleText(chars, state) { michael@0: var font = state.font.translated; michael@0: var glyphs = font.charsToGlyphs(chars); michael@0: var isAddToPathSet = !!(state.textRenderingMode & michael@0: TextRenderingMode.ADD_TO_PATH_FLAG); michael@0: if (font.data && (isAddToPathSet || PDFJS.disableFontFace)) { michael@0: for (var i = 0; i < glyphs.length; i++) { michael@0: if (glyphs[i] === null) { michael@0: continue; michael@0: } michael@0: var fontChar = glyphs[i].fontChar; michael@0: if (!font.renderer.hasBuiltPath(fontChar)) { michael@0: var path = font.renderer.getPathJs(fontChar); michael@0: this.handler.send('commonobj', [ michael@0: font.loadedName + '_path_' + fontChar, michael@0: 'FontPath', michael@0: path michael@0: ]); michael@0: } michael@0: } michael@0: } michael@0: michael@0: return glyphs; michael@0: }, michael@0: michael@0: setGState: function PartialEvaluator_setGState(resources, gState, michael@0: operatorList, xref, michael@0: stateManager) { michael@0: michael@0: var self = this; michael@0: // TODO(mack): This should be rewritten so that this function returns michael@0: // what should be added to the queue during each iteration michael@0: function setGStateForKey(gStateObj, key, value) { michael@0: switch (key) { michael@0: case 'Type': michael@0: break; michael@0: case 'LW': michael@0: case 'LC': michael@0: case 'LJ': michael@0: case 'ML': michael@0: case 'D': michael@0: case 'RI': michael@0: case 'FL': michael@0: case 'CA': michael@0: case 'ca': michael@0: gStateObj.push([key, value]); michael@0: break; michael@0: case 'Font': michael@0: var loadedName = self.handleSetFont(resources, null, value[0], michael@0: operatorList, michael@0: stateManager.state); michael@0: operatorList.addDependency(loadedName); michael@0: gStateObj.push([key, [loadedName, value[1]]]); michael@0: break; michael@0: case 'BM': michael@0: gStateObj.push([key, value]); michael@0: break; michael@0: case 'SMask': michael@0: if (isName(value) && value.name === 'None') { michael@0: gStateObj.push([key, false]); michael@0: break; michael@0: } michael@0: var dict = xref.fetchIfRef(value); michael@0: if (isDict(dict)) { michael@0: self.handleSMask(dict, resources, operatorList, stateManager); michael@0: gStateObj.push([key, true]); michael@0: } else { michael@0: warn('Unsupported SMask type'); michael@0: } michael@0: michael@0: break; michael@0: // Only generate info log messages for the following since michael@0: // they are unlikey to have a big impact on the rendering. michael@0: case 'OP': michael@0: case 'op': michael@0: case 'OPM': michael@0: case 'BG': michael@0: case 'BG2': michael@0: case 'UCR': michael@0: case 'UCR2': michael@0: case 'TR': michael@0: case 'TR2': michael@0: case 'HT': michael@0: case 'SM': michael@0: case 'SA': michael@0: case 'AIS': michael@0: case 'TK': michael@0: // TODO implement these operators. michael@0: info('graphic state operator ' + key); michael@0: break; michael@0: default: michael@0: info('Unknown graphic state operator ' + key); michael@0: break; michael@0: } michael@0: } michael@0: michael@0: // This array holds the converted/processed state data. michael@0: var gStateObj = []; michael@0: var gStateMap = gState.map; michael@0: for (var key in gStateMap) { michael@0: var value = gStateMap[key]; michael@0: setGStateForKey(gStateObj, key, value); michael@0: } michael@0: michael@0: operatorList.addOp(OPS.setGState, [gStateObj]); michael@0: }, michael@0: michael@0: loadFont: function PartialEvaluator_loadFont(fontName, font, xref, michael@0: resources, michael@0: parentOperatorList) { michael@0: michael@0: function errorFont() { michael@0: return { michael@0: translated: new ErrorFont('Font ' + fontName + ' is not available'), michael@0: loadedName: 'g_font_error' michael@0: }; michael@0: } michael@0: michael@0: var fontRef; michael@0: if (font) { // Loading by ref. michael@0: assert(isRef(font)); michael@0: fontRef = font; michael@0: } else { // Loading by name. michael@0: var fontRes = resources.get('Font'); michael@0: if (fontRes) { michael@0: fontRef = fontRes.getRaw(fontName); michael@0: } else { michael@0: warn('fontRes not available'); michael@0: return errorFont(); michael@0: } michael@0: } michael@0: if (this.fontCache.has(fontRef)) { michael@0: return this.fontCache.get(fontRef); michael@0: } michael@0: michael@0: font = xref.fetchIfRef(fontRef); michael@0: if (!isDict(font)) { michael@0: return errorFont(); michael@0: } michael@0: michael@0: var preEvaluatedFont = this.preEvaluateFont(font, xref); michael@0: var descriptor = preEvaluatedFont.descriptor; michael@0: var fontID = fontRef.num + '_' + fontRef.gen; michael@0: if (isDict(descriptor)) { michael@0: if (!descriptor.fontAliases) { michael@0: descriptor.fontAliases = Object.create(null); michael@0: } michael@0: michael@0: var fontAliases = descriptor.fontAliases; michael@0: var hash = preEvaluatedFont.hash; michael@0: if (fontAliases[hash]) { michael@0: var aliasFontRef = fontAliases[hash].aliasRef; michael@0: if (aliasFontRef && this.fontCache.has(aliasFontRef)) { michael@0: this.fontCache.putAlias(fontRef, aliasFontRef); michael@0: var cachedFont = this.fontCache.get(fontRef); michael@0: return cachedFont; michael@0: } michael@0: } michael@0: michael@0: if (!fontAliases[hash]) { michael@0: fontAliases[hash] = { michael@0: fontID: Font.getFontID() michael@0: }; michael@0: } michael@0: michael@0: fontAliases[hash].aliasRef = fontRef; michael@0: fontID = fontAliases[hash].fontID; michael@0: } michael@0: michael@0: // Workaround for bad PDF generators that don't reference fonts michael@0: // properly, i.e. by not using an object identifier. michael@0: // Check if the fontRef is a Dict (as opposed to a standard object), michael@0: // in which case we don't cache the font and instead reference it by michael@0: // fontName in font.loadedName below. michael@0: var fontRefIsDict = isDict(fontRef); michael@0: if (!fontRefIsDict) { michael@0: this.fontCache.put(fontRef, font); michael@0: } michael@0: michael@0: // Keep track of each font we translated so the caller can michael@0: // load them asynchronously before calling display on a page. michael@0: font.loadedName = 'g_font_' + (fontRefIsDict ? michael@0: fontName.replace(/\W/g, '') : fontID); michael@0: michael@0: if (!font.translated) { michael@0: var translated; michael@0: try { michael@0: translated = this.translateFont(preEvaluatedFont, xref); michael@0: } catch (e) { michael@0: UnsupportedManager.notify(UNSUPPORTED_FEATURES.font); michael@0: translated = new ErrorFont(e instanceof Error ? e.message : e); michael@0: } michael@0: font.translated = translated; michael@0: } michael@0: michael@0: if (font.translated.loadCharProcs) { michael@0: var charProcs = font.get('CharProcs').getAll(); michael@0: var fontResources = (font.get('Resources') || resources); michael@0: var charProcKeys = Object.keys(charProcs); michael@0: var charProcOperatorList = {}; michael@0: for (var i = 0, n = charProcKeys.length; i < n; ++i) { michael@0: var key = charProcKeys[i]; michael@0: var glyphStream = charProcs[key]; michael@0: var operatorList = this.getOperatorList(glyphStream, fontResources); michael@0: charProcOperatorList[key] = operatorList.getIR(); michael@0: if (!parentOperatorList) { michael@0: continue; michael@0: } michael@0: // Add the dependencies to the parent operator list so they are michael@0: // resolved before sub operator list is executed synchronously. michael@0: parentOperatorList.addDependencies(charProcOperatorList.dependencies); michael@0: } michael@0: font.translated.charProcOperatorList = charProcOperatorList; michael@0: } michael@0: font.loaded = true; michael@0: return font; michael@0: }, michael@0: michael@0: getOperatorList: function PartialEvaluator_getOperatorList(stream, michael@0: resources, michael@0: operatorList, michael@0: initialState) { michael@0: michael@0: var self = this; michael@0: var xref = this.xref; michael@0: var imageCache = {}; michael@0: michael@0: operatorList = (operatorList || new OperatorList()); michael@0: michael@0: resources = (resources || Dict.empty); michael@0: var xobjs = (resources.get('XObject') || Dict.empty); michael@0: var patterns = (resources.get('Pattern') || Dict.empty); michael@0: var stateManager = new StateManager(initialState || new EvalState()); michael@0: var preprocessor = new EvaluatorPreprocessor(stream, xref, stateManager); michael@0: michael@0: var operation, i, ii; michael@0: while ((operation = preprocessor.read())) { michael@0: var args = operation.args; michael@0: var fn = operation.fn; michael@0: var shading; michael@0: michael@0: switch (fn) { michael@0: case OPS.setStrokeColorN: michael@0: case OPS.setFillColorN: michael@0: if (args[args.length - 1].code) { michael@0: break; michael@0: } michael@0: // compile tiling patterns michael@0: var patternName = args[args.length - 1]; michael@0: // SCN/scn applies patterns along with normal colors michael@0: var pattern; michael@0: if (isName(patternName) && michael@0: (pattern = patterns.get(patternName.name))) { michael@0: var dict = (isStream(pattern) ? pattern.dict : pattern); michael@0: var typeNum = dict.get('PatternType'); michael@0: michael@0: if (typeNum == TILING_PATTERN) { michael@0: self.handleTilingType(fn, args, resources, pattern, dict, michael@0: operatorList); michael@0: args = []; michael@0: continue; michael@0: } else if (typeNum == SHADING_PATTERN) { michael@0: shading = dict.get('Shading'); michael@0: var matrix = dict.get('Matrix'); michael@0: pattern = Pattern.parseShading(shading, matrix, xref, michael@0: resources); michael@0: args = pattern.getIR(); michael@0: } else { michael@0: error('Unkown PatternType ' + typeNum); michael@0: } michael@0: } michael@0: break; michael@0: case OPS.paintXObject: michael@0: if (args[0].code) { michael@0: break; michael@0: } michael@0: // eagerly compile XForm objects michael@0: var name = args[0].name; michael@0: if (imageCache.key === name) { michael@0: operatorList.addOp(imageCache.fn, imageCache.args); michael@0: args = []; michael@0: continue; michael@0: } michael@0: michael@0: var xobj = xobjs.get(name); michael@0: if (xobj) { michael@0: assert(isStream(xobj), 'XObject should be a stream'); michael@0: michael@0: var type = xobj.dict.get('Subtype'); michael@0: assert(isName(type), michael@0: 'XObject should have a Name subtype'); michael@0: michael@0: if ('Form' == type.name) { michael@0: stateManager.save(); michael@0: self.buildFormXObject(resources, xobj, null, operatorList, michael@0: stateManager.state.clone()); michael@0: args = []; michael@0: stateManager.restore(); michael@0: continue; michael@0: } else if ('Image' == type.name) { michael@0: self.buildPaintImageXObject(resources, xobj, false, michael@0: operatorList, name, imageCache); michael@0: args = []; michael@0: continue; michael@0: } else { michael@0: error('Unhandled XObject subtype ' + type.name); michael@0: } michael@0: } michael@0: break; michael@0: case OPS.setFont: michael@0: // eagerly collect all fonts michael@0: var loadedName = self.handleSetFont(resources, args, null, michael@0: operatorList, michael@0: stateManager.state); michael@0: operatorList.addDependency(loadedName); michael@0: args[0] = loadedName; michael@0: break; michael@0: case OPS.endInlineImage: michael@0: var cacheKey = args[0].cacheKey; michael@0: if (cacheKey && imageCache.key === cacheKey) { michael@0: operatorList.addOp(imageCache.fn, imageCache.args); michael@0: args = []; michael@0: continue; michael@0: } michael@0: self.buildPaintImageXObject(resources, args[0], true, michael@0: operatorList, cacheKey, imageCache); michael@0: args = []; michael@0: continue; michael@0: case OPS.showText: michael@0: args[0] = this.handleText(args[0], stateManager.state); michael@0: break; michael@0: case OPS.showSpacedText: michael@0: var arr = args[0]; michael@0: var arrLength = arr.length; michael@0: for (i = 0; i < arrLength; ++i) { michael@0: if (isString(arr[i])) { michael@0: arr[i] = this.handleText(arr[i], stateManager.state); michael@0: } michael@0: } michael@0: break; michael@0: case OPS.nextLineShowText: michael@0: args[0] = this.handleText(args[0], stateManager.state); michael@0: break; michael@0: case OPS.nextLineSetSpacingShowText: michael@0: args[2] = this.handleText(args[2], stateManager.state); michael@0: break; michael@0: case OPS.setTextRenderingMode: michael@0: stateManager.state.textRenderingMode = args[0]; michael@0: break; michael@0: // Parse the ColorSpace data to a raw format. michael@0: case OPS.setFillColorSpace: michael@0: case OPS.setStrokeColorSpace: michael@0: args = [ColorSpace.parseToIR(args[0], xref, resources)]; michael@0: break; michael@0: case OPS.shadingFill: michael@0: var shadingRes = resources.get('Shading'); michael@0: if (!shadingRes) { michael@0: error('No shading resource found'); michael@0: } michael@0: michael@0: shading = shadingRes.get(args[0].name); michael@0: if (!shading) { michael@0: error('No shading object found'); michael@0: } michael@0: michael@0: var shadingFill = Pattern.parseShading(shading, null, xref, michael@0: resources); michael@0: var patternIR = shadingFill.getIR(); michael@0: args = [patternIR]; michael@0: fn = OPS.shadingFill; michael@0: break; michael@0: case OPS.setGState: michael@0: var dictName = args[0]; michael@0: var extGState = resources.get('ExtGState'); michael@0: michael@0: if (!isDict(extGState) || !extGState.has(dictName.name)) { michael@0: break; michael@0: } michael@0: michael@0: var gState = extGState.get(dictName.name); michael@0: self.setGState(resources, gState, operatorList, xref, michael@0: stateManager); michael@0: args = []; michael@0: continue; michael@0: } michael@0: operatorList.addOp(fn, args); michael@0: } michael@0: michael@0: // Some PDFs don't close all restores inside object/form. michael@0: // Closing those for them. michael@0: for (i = 0, ii = preprocessor.savedStatesDepth; i < ii; i++) { michael@0: operatorList.addOp(OPS.restore, []); michael@0: } michael@0: michael@0: return operatorList; michael@0: }, michael@0: michael@0: getTextContent: function PartialEvaluator_getTextContent(stream, resources, michael@0: stateManager) { michael@0: michael@0: stateManager = (stateManager || new StateManager(new TextState())); michael@0: michael@0: var textContent = { michael@0: items: [], michael@0: styles: Object.create(null) michael@0: }; michael@0: var bidiTexts = textContent.items; michael@0: var SPACE_FACTOR = 0.35; michael@0: var MULTI_SPACE_FACTOR = 1.5; michael@0: michael@0: var self = this; michael@0: var xref = this.xref; michael@0: michael@0: resources = (xref.fetchIfRef(resources) || Dict.empty); michael@0: michael@0: // The xobj is parsed iff it's needed, e.g. if there is a `DO` cmd. michael@0: var xobjs = null; michael@0: var xobjsCache = {}; michael@0: michael@0: var preprocessor = new EvaluatorPreprocessor(stream, xref, stateManager); michael@0: michael@0: var operation; michael@0: var textState; michael@0: michael@0: function newTextChunk() { michael@0: var font = textState.font; michael@0: if (!(font.loadedName in textContent.styles)) { michael@0: textContent.styles[font.loadedName] = { michael@0: fontFamily: font.fallbackName, michael@0: ascent: font.ascent, michael@0: descent: font.descent, michael@0: vertical: font.vertical michael@0: }; michael@0: } michael@0: return { michael@0: str: '', michael@0: dir: null, michael@0: width: 0, michael@0: height: 0, michael@0: transform: null, michael@0: fontName: font.loadedName michael@0: }; michael@0: } michael@0: michael@0: function runBidi(textChunk) { michael@0: var bidiResult = PDFJS.bidi(textChunk.str, -1, textState.font.vertical); michael@0: textChunk.str = bidiResult.str; michael@0: textChunk.dir = bidiResult.dir; michael@0: return textChunk; michael@0: } michael@0: michael@0: function handleSetFont(fontName, fontRef) { michael@0: var font = textState.font = self.loadFont(fontName, fontRef, xref, michael@0: resources, null).translated; michael@0: textState.fontMatrix = font.fontMatrix ? font.fontMatrix : michael@0: FONT_IDENTITY_MATRIX; michael@0: } michael@0: michael@0: function buildTextGeometry(chars, textChunk) { michael@0: var font = textState.font; michael@0: textChunk = textChunk || newTextChunk(); michael@0: if (!textChunk.transform) { michael@0: // 9.4.4 Text Space Details michael@0: var tsm = [textState.fontSize * textState.textHScale, 0, michael@0: 0, textState.fontSize, michael@0: 0, textState.textRise]; michael@0: var trm = textChunk.transform = Util.transform(textState.ctm, michael@0: Util.transform(textState.textMatrix, tsm)); michael@0: if (!font.vertical) { michael@0: textChunk.height = Math.sqrt(trm[2] * trm[2] + trm[3] * trm[3]); michael@0: } else { michael@0: textChunk.width = Math.sqrt(trm[0] * trm[0] + trm[1] * trm[1]); michael@0: } michael@0: } michael@0: var width = 0; michael@0: var height = 0; michael@0: var glyphs = font.charsToGlyphs(chars); michael@0: var defaultVMetrics = font.defaultVMetrics; michael@0: for (var i = 0; i < glyphs.length; i++) { michael@0: var glyph = glyphs[i]; michael@0: if (!glyph) { // Previous glyph was a space. michael@0: width += textState.wordSpacing * textState.textHScale; michael@0: continue; michael@0: } michael@0: var vMetricX = null; michael@0: var vMetricY = null; michael@0: var glyphWidth = null; michael@0: if (font.vertical) { michael@0: if (glyph.vmetric) { michael@0: glyphWidth = glyph.vmetric[0]; michael@0: vMetricX = glyph.vmetric[1]; michael@0: vMetricY = glyph.vmetric[2]; michael@0: } else { michael@0: glyphWidth = glyph.width; michael@0: vMetricX = glyph.width * 0.5; michael@0: vMetricY = defaultVMetrics[2]; michael@0: } michael@0: } else { michael@0: glyphWidth = glyph.width; michael@0: } michael@0: michael@0: var glyphUnicode = glyph.unicode; michael@0: if (glyphUnicode in NormalizedUnicodes) { michael@0: glyphUnicode = NormalizedUnicodes[glyphUnicode]; michael@0: } michael@0: glyphUnicode = reverseIfRtl(glyphUnicode); michael@0: michael@0: // The following will calculate the x and y of the individual glyphs. michael@0: // if (font.vertical) { michael@0: // tsm[4] -= vMetricX * Math.abs(textState.fontSize) * michael@0: // textState.fontMatrix[0]; michael@0: // tsm[5] -= vMetricY * textState.fontSize * michael@0: // textState.fontMatrix[0]; michael@0: // } michael@0: // var trm = Util.transform(textState.textMatrix, tsm); michael@0: // var pt = Util.applyTransform([trm[4], trm[5]], textState.ctm); michael@0: // var x = pt[0]; michael@0: // var y = pt[1]; michael@0: michael@0: var tx = 0; michael@0: var ty = 0; michael@0: if (!font.vertical) { michael@0: var w0 = glyphWidth * textState.fontMatrix[0]; michael@0: tx = (w0 * textState.fontSize + textState.charSpacing) * michael@0: textState.textHScale; michael@0: width += tx; michael@0: } else { michael@0: var w1 = glyphWidth * textState.fontMatrix[0]; michael@0: ty = w1 * textState.fontSize + textState.charSpacing; michael@0: height += ty; michael@0: } michael@0: textState.translateTextMatrix(tx, ty); michael@0: michael@0: textChunk.str += glyphUnicode; michael@0: } michael@0: michael@0: var a = textState.textLineMatrix[0]; michael@0: var b = textState.textLineMatrix[1]; michael@0: var scaleLineX = Math.sqrt(a * a + b * b); michael@0: a = textState.ctm[0]; michael@0: b = textState.ctm[1]; michael@0: var scaleCtmX = Math.sqrt(a * a + b * b); michael@0: if (!font.vertical) { michael@0: textChunk.width += width * scaleCtmX * scaleLineX; michael@0: } else { michael@0: textChunk.height += Math.abs(height * scaleCtmX * scaleLineX); michael@0: } michael@0: return textChunk; michael@0: } michael@0: michael@0: while ((operation = preprocessor.read())) { michael@0: textState = stateManager.state; michael@0: var fn = operation.fn; michael@0: var args = operation.args; michael@0: switch (fn) { michael@0: case OPS.setFont: michael@0: handleSetFont(args[0].name); michael@0: textState.fontSize = args[1]; michael@0: break; michael@0: case OPS.setTextRise: michael@0: textState.textRise = args[0]; michael@0: break; michael@0: case OPS.setHScale: michael@0: textState.textHScale = args[0] / 100; michael@0: break; michael@0: case OPS.setLeading: michael@0: textState.leading = args[0]; michael@0: break; michael@0: case OPS.moveText: michael@0: textState.translateTextLineMatrix(args[0], args[1]); michael@0: textState.textMatrix = textState.textLineMatrix.slice(); michael@0: break; michael@0: case OPS.setLeadingMoveText: michael@0: textState.leading = -args[1]; michael@0: textState.translateTextLineMatrix(args[0], args[1]); michael@0: textState.textMatrix = textState.textLineMatrix.slice(); michael@0: break; michael@0: case OPS.nextLine: michael@0: textState.carriageReturn(); michael@0: break; michael@0: case OPS.setTextMatrix: michael@0: textState.setTextMatrix(args[0], args[1], args[2], args[3], michael@0: args[4], args[5]); michael@0: textState.setTextLineMatrix(args[0], args[1], args[2], args[3], michael@0: args[4], args[5]); michael@0: break; michael@0: case OPS.setCharSpacing: michael@0: textState.charSpacing = args[0]; michael@0: break; michael@0: case OPS.setWordSpacing: michael@0: textState.wordSpacing = args[0]; michael@0: break; michael@0: case OPS.beginText: michael@0: textState.textMatrix = IDENTITY_MATRIX.slice(); michael@0: textState.textLineMatrix = IDENTITY_MATRIX.slice(); michael@0: break; michael@0: case OPS.showSpacedText: michael@0: var items = args[0]; michael@0: var textChunk = newTextChunk(); michael@0: var offset; michael@0: for (var j = 0, jj = items.length; j < jj; j++) { michael@0: if (typeof items[j] === 'string') { michael@0: buildTextGeometry(items[j], textChunk); michael@0: } else { michael@0: var val = items[j] / 1000; michael@0: if (!textState.font.vertical) { michael@0: offset = -val * textState.fontSize * textState.textHScale * michael@0: textState.textMatrix[0]; michael@0: textState.translateTextMatrix(offset, 0); michael@0: textChunk.width += offset; michael@0: } else { michael@0: offset = -val * textState.fontSize * textState.textMatrix[3]; michael@0: textState.translateTextMatrix(0, offset); michael@0: textChunk.height += offset; michael@0: } michael@0: if (items[j] < 0 && textState.font.spaceWidth > 0) { michael@0: var fakeSpaces = -items[j] / textState.font.spaceWidth; michael@0: if (fakeSpaces > MULTI_SPACE_FACTOR) { michael@0: fakeSpaces = Math.round(fakeSpaces); michael@0: while (fakeSpaces--) { michael@0: textChunk.str += ' '; michael@0: } michael@0: } else if (fakeSpaces > SPACE_FACTOR) { michael@0: textChunk.str += ' '; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: bidiTexts.push(runBidi(textChunk)); michael@0: break; michael@0: case OPS.showText: michael@0: bidiTexts.push(runBidi(buildTextGeometry(args[0]))); michael@0: break; michael@0: case OPS.nextLineShowText: michael@0: textState.carriageReturn(); michael@0: bidiTexts.push(runBidi(buildTextGeometry(args[0]))); michael@0: break; michael@0: case OPS.nextLineSetSpacingShowText: michael@0: textState.wordSpacing = args[0]; michael@0: textState.charSpacing = args[1]; michael@0: textState.carriageReturn(); michael@0: bidiTexts.push(runBidi(buildTextGeometry(args[2]))); michael@0: break; michael@0: case OPS.paintXObject: michael@0: if (args[0].code) { michael@0: break; michael@0: } michael@0: michael@0: if (!xobjs) { michael@0: xobjs = (resources.get('XObject') || Dict.empty); michael@0: } michael@0: michael@0: var name = args[0].name; michael@0: if (xobjsCache.key === name) { michael@0: if (xobjsCache.texts) { michael@0: Util.concatenateToArray(bidiTexts, xobjsCache.texts.items); michael@0: Util.extendObj(textContent.styles, xobjsCache.texts.styles); michael@0: } michael@0: break; michael@0: } michael@0: michael@0: var xobj = xobjs.get(name); michael@0: if (!xobj) { michael@0: break; michael@0: } michael@0: assert(isStream(xobj), 'XObject should be a stream'); michael@0: michael@0: var type = xobj.dict.get('Subtype'); michael@0: assert(isName(type), michael@0: 'XObject should have a Name subtype'); michael@0: michael@0: if ('Form' !== type.name) { michael@0: xobjsCache.key = name; michael@0: xobjsCache.texts = null; michael@0: break; michael@0: } michael@0: michael@0: stateManager.save(); michael@0: var matrix = xobj.dict.get('Matrix'); michael@0: if (isArray(matrix) && matrix.length === 6) { michael@0: stateManager.transform(matrix); michael@0: } michael@0: michael@0: var formTextContent = this.getTextContent( michael@0: xobj, michael@0: xobj.dict.get('Resources') || resources, michael@0: stateManager michael@0: ); michael@0: Util.concatenateToArray(bidiTexts, formTextContent.items); michael@0: Util.extendObj(textContent.styles, formTextContent.styles); michael@0: stateManager.restore(); michael@0: michael@0: xobjsCache.key = name; michael@0: xobjsCache.texts = formTextContent; michael@0: break; michael@0: case OPS.setGState: michael@0: var dictName = args[0]; michael@0: var extGState = resources.get('ExtGState'); michael@0: michael@0: if (!isDict(extGState) || !extGState.has(dictName.name)) { michael@0: break; michael@0: } michael@0: michael@0: var gsState = extGState.get(dictName.name); michael@0: michael@0: for (var i = 0; i < gsState.length; i++) { michael@0: if (gsState[i] === 'Font') { michael@0: handleSetFont(args[0].name); michael@0: } michael@0: } michael@0: break; michael@0: } // switch michael@0: } // while michael@0: michael@0: return textContent; michael@0: }, michael@0: michael@0: extractDataStructures: function michael@0: partialEvaluatorExtractDataStructures(dict, baseDict, michael@0: xref, properties) { michael@0: // 9.10.2 michael@0: var toUnicode = (dict.get('ToUnicode') || baseDict.get('ToUnicode')); michael@0: if (toUnicode) { michael@0: properties.toUnicode = this.readToUnicode(toUnicode, xref, properties); michael@0: } michael@0: if (properties.composite) { michael@0: // CIDSystemInfo helps to match CID to glyphs michael@0: var cidSystemInfo = dict.get('CIDSystemInfo'); michael@0: if (isDict(cidSystemInfo)) { michael@0: properties.cidSystemInfo = { michael@0: registry: cidSystemInfo.get('Registry'), michael@0: ordering: cidSystemInfo.get('Ordering'), michael@0: supplement: cidSystemInfo.get('Supplement') michael@0: }; michael@0: } michael@0: michael@0: var cidToGidMap = dict.get('CIDToGIDMap'); michael@0: if (isStream(cidToGidMap)) { michael@0: properties.cidToGidMap = this.readCidToGidMap(cidToGidMap); michael@0: } michael@0: } michael@0: michael@0: // Based on 9.6.6 of the spec the encoding can come from multiple places michael@0: // and depends on the font type. The base encoding and differences are michael@0: // read here, but the encoding that is actually used is chosen during michael@0: // glyph mapping in the font. michael@0: // TODO: Loading the built in encoding in the font would allow the michael@0: // differences to be merged in here not require us to hold on to it. michael@0: var differences = []; michael@0: var baseEncodingName = null; michael@0: var encoding; michael@0: if (dict.has('Encoding')) { michael@0: encoding = dict.get('Encoding'); michael@0: if (isDict(encoding)) { michael@0: baseEncodingName = encoding.get('BaseEncoding'); michael@0: baseEncodingName = (isName(baseEncodingName) ? michael@0: baseEncodingName.name : null); michael@0: // Load the differences between the base and original michael@0: if (encoding.has('Differences')) { michael@0: var diffEncoding = encoding.get('Differences'); michael@0: var index = 0; michael@0: for (var j = 0, jj = diffEncoding.length; j < jj; j++) { michael@0: var data = diffEncoding[j]; michael@0: if (isNum(data)) { michael@0: index = data; michael@0: } else { michael@0: differences[index++] = data.name; michael@0: } michael@0: } michael@0: } michael@0: } else if (isName(encoding)) { michael@0: baseEncodingName = encoding.name; michael@0: } else { michael@0: error('Encoding is not a Name nor a Dict'); michael@0: } michael@0: // According to table 114 if the encoding is a named encoding it must be michael@0: // one of these predefined encodings. michael@0: if ((baseEncodingName !== 'MacRomanEncoding' && michael@0: baseEncodingName !== 'MacExpertEncoding' && michael@0: baseEncodingName !== 'WinAnsiEncoding')) { michael@0: baseEncodingName = null; michael@0: } michael@0: } michael@0: michael@0: if (baseEncodingName) { michael@0: properties.defaultEncoding = Encodings[baseEncodingName].slice(); michael@0: } else { michael@0: encoding = (properties.type === 'TrueType' ? michael@0: Encodings.WinAnsiEncoding : Encodings.StandardEncoding); michael@0: // The Symbolic attribute can be misused for regular fonts michael@0: // Heuristic: we have to check if the font is a standard one also michael@0: if (!!(properties.flags & FontFlags.Symbolic)) { michael@0: encoding = (!properties.file && /Symbol/i.test(properties.name) ? michael@0: Encodings.SymbolSetEncoding : michael@0: Encodings.MacRomanEncoding); michael@0: } michael@0: properties.defaultEncoding = encoding; michael@0: } michael@0: michael@0: properties.differences = differences; michael@0: properties.baseEncodingName = baseEncodingName; michael@0: properties.dict = dict; michael@0: }, michael@0: michael@0: readToUnicode: function PartialEvaluator_readToUnicode(toUnicode) { michael@0: var cmapObj = toUnicode; michael@0: if (isName(cmapObj)) { michael@0: return CMapFactory.create(cmapObj).map; michael@0: } else if (isStream(cmapObj)) { michael@0: var cmap = CMapFactory.create(cmapObj).map; michael@0: // Convert UTF-16BE michael@0: // NOTE: cmap can be a sparse array, so use forEach instead of for(;;) michael@0: // to iterate over all keys. michael@0: cmap.forEach(function(token, i) { michael@0: var str = []; michael@0: for (var k = 0; k < token.length; k += 2) { michael@0: var w1 = (token.charCodeAt(k) << 8) | token.charCodeAt(k + 1); michael@0: if ((w1 & 0xF800) !== 0xD800) { // w1 < 0xD800 || w1 > 0xDFFF michael@0: str.push(w1); michael@0: continue; michael@0: } michael@0: k += 2; michael@0: var w2 = (token.charCodeAt(k) << 8) | token.charCodeAt(k + 1); michael@0: str.push(((w1 & 0x3ff) << 10) + (w2 & 0x3ff) + 0x10000); michael@0: } michael@0: cmap[i] = String.fromCharCode.apply(String, str); michael@0: }); michael@0: return cmap; michael@0: } michael@0: return null; michael@0: }, michael@0: michael@0: readCidToGidMap: function PartialEvaluator_readCidToGidMap(cidToGidStream) { michael@0: // Extract the encoding from the CIDToGIDMap michael@0: var glyphsData = cidToGidStream.getBytes(); michael@0: michael@0: // Set encoding 0 to later verify the font has an encoding michael@0: var result = []; michael@0: for (var j = 0, jj = glyphsData.length; j < jj; j++) { michael@0: var glyphID = (glyphsData[j++] << 8) | glyphsData[j]; michael@0: if (glyphID === 0) { michael@0: continue; michael@0: } michael@0: var code = j >> 1; michael@0: result[code] = glyphID; michael@0: } michael@0: return result; michael@0: }, michael@0: michael@0: extractWidths: function PartialEvaluator_extractWidths(dict, xref, michael@0: descriptor, michael@0: properties) { michael@0: var glyphsWidths = []; michael@0: var defaultWidth = 0; michael@0: var glyphsVMetrics = []; michael@0: var defaultVMetrics; michael@0: var i, ii, j, jj, start, code, widths; michael@0: if (properties.composite) { michael@0: defaultWidth = dict.get('DW') || 1000; michael@0: michael@0: widths = dict.get('W'); michael@0: if (widths) { michael@0: for (i = 0, ii = widths.length; i < ii; i++) { michael@0: start = widths[i++]; michael@0: code = xref.fetchIfRef(widths[i]); michael@0: if (isArray(code)) { michael@0: for (j = 0, jj = code.length; j < jj; j++) { michael@0: glyphsWidths[start++] = code[j]; michael@0: } michael@0: } else { michael@0: var width = widths[++i]; michael@0: for (j = start; j <= code; j++) { michael@0: glyphsWidths[j] = width; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: if (properties.vertical) { michael@0: var vmetrics = (dict.get('DW2') || [880, -1000]); michael@0: defaultVMetrics = [vmetrics[1], defaultWidth * 0.5, vmetrics[0]]; michael@0: vmetrics = dict.get('W2'); michael@0: if (vmetrics) { michael@0: for (i = 0, ii = vmetrics.length; i < ii; i++) { michael@0: start = vmetrics[i++]; michael@0: code = xref.fetchIfRef(vmetrics[i]); michael@0: if (isArray(code)) { michael@0: for (j = 0, jj = code.length; j < jj; j++) { michael@0: glyphsVMetrics[start++] = [code[j++], code[j++], code[j]]; michael@0: } michael@0: } else { michael@0: var vmetric = [vmetrics[++i], vmetrics[++i], vmetrics[++i]]; michael@0: for (j = start; j <= code; j++) { michael@0: glyphsVMetrics[j] = vmetric; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } else { michael@0: var firstChar = properties.firstChar; michael@0: widths = dict.get('Widths'); michael@0: if (widths) { michael@0: j = firstChar; michael@0: for (i = 0, ii = widths.length; i < ii; i++) { michael@0: glyphsWidths[j++] = widths[i]; michael@0: } michael@0: defaultWidth = (parseFloat(descriptor.get('MissingWidth')) || 0); michael@0: } else { michael@0: // Trying get the BaseFont metrics (see comment above). michael@0: var baseFontName = dict.get('BaseFont'); michael@0: if (isName(baseFontName)) { michael@0: var metrics = this.getBaseFontMetrics(baseFontName.name); michael@0: michael@0: glyphsWidths = this.buildCharCodeToWidth(metrics.widths, michael@0: properties); michael@0: defaultWidth = metrics.defaultWidth; michael@0: } michael@0: } michael@0: } michael@0: michael@0: // Heuristic: detection of monospace font by checking all non-zero widths michael@0: var isMonospace = true; michael@0: var firstWidth = defaultWidth; michael@0: for (var glyph in glyphsWidths) { michael@0: var glyphWidth = glyphsWidths[glyph]; michael@0: if (!glyphWidth) { michael@0: continue; michael@0: } michael@0: if (!firstWidth) { michael@0: firstWidth = glyphWidth; michael@0: continue; michael@0: } michael@0: if (firstWidth != glyphWidth) { michael@0: isMonospace = false; michael@0: break; michael@0: } michael@0: } michael@0: if (isMonospace) { michael@0: properties.flags |= FontFlags.FixedPitch; michael@0: } michael@0: michael@0: properties.defaultWidth = defaultWidth; michael@0: properties.widths = glyphsWidths; michael@0: properties.defaultVMetrics = defaultVMetrics; michael@0: properties.vmetrics = glyphsVMetrics; michael@0: }, michael@0: michael@0: isSerifFont: function PartialEvaluator_isSerifFont(baseFontName) { michael@0: // Simulating descriptor flags attribute michael@0: var fontNameWoStyle = baseFontName.split('-')[0]; michael@0: return (fontNameWoStyle in serifFonts) || michael@0: (fontNameWoStyle.search(/serif/gi) !== -1); michael@0: }, michael@0: michael@0: getBaseFontMetrics: function PartialEvaluator_getBaseFontMetrics(name) { michael@0: var defaultWidth = 0; michael@0: var widths = []; michael@0: var monospace = false; michael@0: var lookupName = (stdFontMap[name] || name); michael@0: michael@0: if (!(lookupName in Metrics)) { michael@0: // Use default fonts for looking up font metrics if the passed michael@0: // font is not a base font michael@0: if (this.isSerifFont(name)) { michael@0: lookupName = 'Times-Roman'; michael@0: } else { michael@0: lookupName = 'Helvetica'; michael@0: } michael@0: } michael@0: var glyphWidths = Metrics[lookupName]; michael@0: michael@0: if (isNum(glyphWidths)) { michael@0: defaultWidth = glyphWidths; michael@0: monospace = true; michael@0: } else { michael@0: widths = glyphWidths; michael@0: } michael@0: michael@0: return { michael@0: defaultWidth: defaultWidth, michael@0: monospace: monospace, michael@0: widths: widths michael@0: }; michael@0: }, michael@0: michael@0: buildCharCodeToWidth: michael@0: function PartialEvaluator_bulildCharCodeToWidth(widthsByGlyphName, michael@0: properties) { michael@0: var widths = Object.create(null); michael@0: var differences = properties.differences; michael@0: var encoding = properties.defaultEncoding; michael@0: for (var charCode = 0; charCode < 256; charCode++) { michael@0: if (charCode in differences && michael@0: widthsByGlyphName[differences[charCode]]) { michael@0: widths[charCode] = widthsByGlyphName[differences[charCode]]; michael@0: continue; michael@0: } michael@0: if (charCode in encoding && widthsByGlyphName[encoding[charCode]]) { michael@0: widths[charCode] = widthsByGlyphName[encoding[charCode]]; michael@0: continue; michael@0: } michael@0: } michael@0: return widths; michael@0: }, michael@0: michael@0: preEvaluateFont: function PartialEvaluator_preEvaluateFont(dict, xref) { michael@0: var baseDict = dict; michael@0: var type = dict.get('Subtype'); michael@0: assert(isName(type), 'invalid font Subtype'); michael@0: michael@0: var composite = false; michael@0: var uint8array; michael@0: if (type.name == 'Type0') { michael@0: // If font is a composite michael@0: // - get the descendant font michael@0: // - set the type according to the descendant font michael@0: // - get the FontDescriptor from the descendant font michael@0: var df = dict.get('DescendantFonts'); michael@0: if (!df) { michael@0: error('Descendant fonts are not specified'); michael@0: } michael@0: dict = (isArray(df) ? xref.fetchIfRef(df[0]) : df); michael@0: michael@0: type = dict.get('Subtype'); michael@0: assert(isName(type), 'invalid font Subtype'); michael@0: composite = true; michael@0: } michael@0: michael@0: var descriptor = dict.get('FontDescriptor'); michael@0: if (descriptor) { michael@0: var hash = new MurmurHash3_64(); michael@0: var encoding = baseDict.getRaw('Encoding'); michael@0: if (isName(encoding)) { michael@0: hash.update(encoding.name); michael@0: } else if (isRef(encoding)) { michael@0: hash.update(encoding.num + '_' + encoding.gen); michael@0: } michael@0: michael@0: var toUnicode = dict.get('ToUnicode') || baseDict.get('ToUnicode'); michael@0: if (isStream(toUnicode)) { michael@0: var stream = toUnicode.str || toUnicode; michael@0: uint8array = stream.buffer ? michael@0: new Uint8Array(stream.buffer.buffer, 0, stream.bufferLength) : michael@0: new Uint8Array(stream.bytes.buffer, michael@0: stream.start, stream.end - stream.start); michael@0: hash.update(uint8array); michael@0: michael@0: } else if (isName(toUnicode)) { michael@0: hash.update(toUnicode.name); michael@0: } michael@0: michael@0: var widths = dict.get('Widths') || baseDict.get('Widths'); michael@0: if (widths) { michael@0: uint8array = new Uint8Array(new Uint32Array(widths).buffer); michael@0: hash.update(uint8array); michael@0: } michael@0: } michael@0: michael@0: return { michael@0: descriptor: descriptor, michael@0: dict: dict, michael@0: baseDict: baseDict, michael@0: composite: composite, michael@0: hash: hash ? hash.hexdigest() : '' michael@0: }; michael@0: }, michael@0: michael@0: translateFont: function PartialEvaluator_translateFont(preEvaluatedFont, michael@0: xref) { michael@0: var baseDict = preEvaluatedFont.baseDict; michael@0: var dict = preEvaluatedFont.dict; michael@0: var composite = preEvaluatedFont.composite; michael@0: var descriptor = preEvaluatedFont.descriptor; michael@0: var type = dict.get('Subtype'); michael@0: var maxCharIndex = (composite ? 0xFFFF : 0xFF); michael@0: var properties; michael@0: michael@0: if (!descriptor) { michael@0: if (type.name == 'Type3') { michael@0: // FontDescriptor is only required for Type3 fonts when the document michael@0: // is a tagged pdf. Create a barbebones one to get by. michael@0: descriptor = new Dict(null); michael@0: descriptor.set('FontName', Name.get(type.name)); michael@0: } else { michael@0: // Before PDF 1.5 if the font was one of the base 14 fonts, having a michael@0: // FontDescriptor was not required. michael@0: // This case is here for compatibility. michael@0: var baseFontName = dict.get('BaseFont'); michael@0: if (!isName(baseFontName)) { michael@0: error('Base font is not specified'); michael@0: } michael@0: michael@0: // Using base font name as a font name. michael@0: baseFontName = baseFontName.name.replace(/[,_]/g, '-'); michael@0: var metrics = this.getBaseFontMetrics(baseFontName); michael@0: michael@0: // Simulating descriptor flags attribute michael@0: var fontNameWoStyle = baseFontName.split('-')[0]; michael@0: var flags = michael@0: (this.isSerifFont(fontNameWoStyle) ? FontFlags.Serif : 0) | michael@0: (metrics.monospace ? FontFlags.FixedPitch : 0) | michael@0: (symbolsFonts[fontNameWoStyle] ? FontFlags.Symbolic : michael@0: FontFlags.Nonsymbolic); michael@0: michael@0: properties = { michael@0: type: type.name, michael@0: name: baseFontName, michael@0: widths: metrics.widths, michael@0: defaultWidth: metrics.defaultWidth, michael@0: flags: flags, michael@0: firstChar: 0, michael@0: lastChar: maxCharIndex michael@0: }; michael@0: this.extractDataStructures(dict, dict, xref, properties); michael@0: properties.widths = this.buildCharCodeToWidth(metrics.widths, michael@0: properties); michael@0: return new Font(baseFontName, null, properties); michael@0: } michael@0: } michael@0: michael@0: // According to the spec if 'FontDescriptor' is declared, 'FirstChar', michael@0: // 'LastChar' and 'Widths' should exist too, but some PDF encoders seem michael@0: // to ignore this rule when a variant of a standart font is used. michael@0: // TODO Fill the width array depending on which of the base font this is michael@0: // a variant. michael@0: var firstChar = (dict.get('FirstChar') || 0); michael@0: var lastChar = (dict.get('LastChar') || maxCharIndex); michael@0: michael@0: var fontName = descriptor.get('FontName'); michael@0: var baseFont = dict.get('BaseFont'); michael@0: // Some bad PDFs have a string as the font name. michael@0: if (isString(fontName)) { michael@0: fontName = Name.get(fontName); michael@0: } michael@0: if (isString(baseFont)) { michael@0: baseFont = Name.get(baseFont); michael@0: } michael@0: michael@0: if (type.name !== 'Type3') { michael@0: var fontNameStr = fontName && fontName.name; michael@0: var baseFontStr = baseFont && baseFont.name; michael@0: if (fontNameStr !== baseFontStr) { michael@0: info('The FontDescriptor\'s FontName is "' + fontNameStr + michael@0: '" but should be the same as the Font\'s BaseFont "' + michael@0: baseFontStr + '"'); michael@0: // Workaround for cases where e.g. fontNameStr = 'Arial' and michael@0: // baseFontStr = 'Arial,Bold' (needed when no font file is embedded). michael@0: if (fontNameStr && baseFontStr && michael@0: baseFontStr.search(fontNameStr) === 0) { michael@0: fontName = baseFont; michael@0: } michael@0: } michael@0: } michael@0: fontName = (fontName || baseFont); michael@0: michael@0: assert(isName(fontName), 'invalid font name'); michael@0: michael@0: var fontFile = descriptor.get('FontFile', 'FontFile2', 'FontFile3'); michael@0: if (fontFile) { michael@0: if (fontFile.dict) { michael@0: var subtype = fontFile.dict.get('Subtype'); michael@0: if (subtype) { michael@0: subtype = subtype.name; michael@0: } michael@0: var length1 = fontFile.dict.get('Length1'); michael@0: var length2 = fontFile.dict.get('Length2'); michael@0: } michael@0: } michael@0: michael@0: properties = { michael@0: type: type.name, michael@0: name: fontName.name, michael@0: subtype: subtype, michael@0: file: fontFile, michael@0: length1: length1, michael@0: length2: length2, michael@0: loadedName: baseDict.loadedName, michael@0: composite: composite, michael@0: wideChars: composite, michael@0: fixedPitch: false, michael@0: fontMatrix: (dict.get('FontMatrix') || FONT_IDENTITY_MATRIX), michael@0: firstChar: firstChar || 0, michael@0: lastChar: (lastChar || maxCharIndex), michael@0: bbox: descriptor.get('FontBBox'), michael@0: ascent: descriptor.get('Ascent'), michael@0: descent: descriptor.get('Descent'), michael@0: xHeight: descriptor.get('XHeight'), michael@0: capHeight: descriptor.get('CapHeight'), michael@0: flags: descriptor.get('Flags'), michael@0: italicAngle: descriptor.get('ItalicAngle'), michael@0: coded: false michael@0: }; michael@0: michael@0: if (composite) { michael@0: var cidEncoding = baseDict.get('Encoding'); michael@0: if (isName(cidEncoding)) { michael@0: properties.cidEncoding = cidEncoding.name; michael@0: } michael@0: properties.cMap = CMapFactory.create(cidEncoding, michael@0: { url: PDFJS.cMapUrl, packed: PDFJS.cMapPacked }, null); michael@0: properties.vertical = properties.cMap.vertical; michael@0: } michael@0: this.extractDataStructures(dict, baseDict, xref, properties); michael@0: this.extractWidths(dict, xref, descriptor, properties); michael@0: michael@0: if (type.name === 'Type3') { michael@0: properties.coded = true; michael@0: } michael@0: michael@0: return new Font(fontName.name, fontFile, properties); michael@0: } michael@0: }; michael@0: michael@0: return PartialEvaluator; michael@0: })(); michael@0: michael@0: var OperatorList = (function OperatorListClosure() { michael@0: var CHUNK_SIZE = 1000; michael@0: var CHUNK_SIZE_ABOUT = CHUNK_SIZE - 5; // close to chunk size michael@0: michael@0: function getTransfers(queue) { michael@0: var transfers = []; michael@0: var fnArray = queue.fnArray, argsArray = queue.argsArray; michael@0: for (var i = 0, ii = queue.length; i < ii; i++) { michael@0: switch (fnArray[i]) { michael@0: case OPS.paintInlineImageXObject: michael@0: case OPS.paintInlineImageXObjectGroup: michael@0: case OPS.paintImageMaskXObject: michael@0: var arg = argsArray[i][0]; // first param in imgData michael@0: if (!arg.cached) { michael@0: transfers.push(arg.data.buffer); michael@0: } michael@0: break; michael@0: } michael@0: } michael@0: return transfers; michael@0: } michael@0: michael@0: function OperatorList(intent, messageHandler, pageIndex) { michael@0: this.messageHandler = messageHandler; michael@0: this.fnArray = []; michael@0: this.argsArray = []; michael@0: this.dependencies = {}; michael@0: this.pageIndex = pageIndex; michael@0: this.intent = intent; michael@0: } michael@0: michael@0: OperatorList.prototype = { michael@0: get length() { michael@0: return this.argsArray.length; michael@0: }, michael@0: michael@0: addOp: function(fn, args) { michael@0: this.fnArray.push(fn); michael@0: this.argsArray.push(args); michael@0: if (this.messageHandler) { michael@0: if (this.fnArray.length >= CHUNK_SIZE) { michael@0: this.flush(); michael@0: } else if (this.fnArray.length >= CHUNK_SIZE_ABOUT && michael@0: (fn === OPS.restore || fn === OPS.endText)) { michael@0: // heuristic to flush on boundary of restore or endText michael@0: this.flush(); michael@0: } michael@0: } michael@0: }, michael@0: michael@0: addDependency: function(dependency) { michael@0: if (dependency in this.dependencies) { michael@0: return; michael@0: } michael@0: this.dependencies[dependency] = true; michael@0: this.addOp(OPS.dependency, [dependency]); michael@0: }, michael@0: michael@0: addDependencies: function(dependencies) { michael@0: for (var key in dependencies) { michael@0: this.addDependency(key); michael@0: } michael@0: }, michael@0: michael@0: addOpList: function(opList) { michael@0: Util.extendObj(this.dependencies, opList.dependencies); michael@0: for (var i = 0, ii = opList.length; i < ii; i++) { michael@0: this.addOp(opList.fnArray[i], opList.argsArray[i]); michael@0: } michael@0: }, michael@0: michael@0: getIR: function() { michael@0: return { michael@0: fnArray: this.fnArray, michael@0: argsArray: this.argsArray, michael@0: length: this.length michael@0: }; michael@0: }, michael@0: michael@0: flush: function(lastChunk) { michael@0: new QueueOptimizer().optimize(this); michael@0: var transfers = getTransfers(this); michael@0: this.messageHandler.send('RenderPageChunk', { michael@0: operatorList: { michael@0: fnArray: this.fnArray, michael@0: argsArray: this.argsArray, michael@0: lastChunk: lastChunk, michael@0: length: this.length michael@0: }, michael@0: pageIndex: this.pageIndex, michael@0: intent: this.intent michael@0: }, null, transfers); michael@0: this.dependencies = {}; michael@0: this.fnArray.length = 0; michael@0: this.argsArray.length = 0; michael@0: } michael@0: }; michael@0: michael@0: return OperatorList; michael@0: })(); michael@0: michael@0: var StateManager = (function StateManagerClosure() { michael@0: function StateManager(initialState) { michael@0: this.state = initialState; michael@0: this.stateStack = []; michael@0: } michael@0: StateManager.prototype = { michael@0: save: function () { michael@0: var old = this.state; michael@0: this.stateStack.push(this.state); michael@0: this.state = old.clone(); michael@0: }, michael@0: restore: function () { michael@0: var prev = this.stateStack.pop(); michael@0: if (prev) { michael@0: this.state = prev; michael@0: } michael@0: }, michael@0: transform: function (args) { michael@0: this.state.ctm = Util.transform(this.state.ctm, args); michael@0: } michael@0: }; michael@0: return StateManager; michael@0: })(); michael@0: michael@0: var TextState = (function TextStateClosure() { michael@0: function TextState() { michael@0: this.ctm = new Float32Array(IDENTITY_MATRIX); michael@0: this.fontSize = 0; michael@0: this.font = null; michael@0: this.fontMatrix = FONT_IDENTITY_MATRIX; michael@0: this.textMatrix = IDENTITY_MATRIX.slice(); michael@0: this.textLineMatrix = IDENTITY_MATRIX.slice(); michael@0: this.charSpacing = 0; michael@0: this.wordSpacing = 0; michael@0: this.leading = 0; michael@0: this.textHScale = 1; michael@0: this.textRise = 0; michael@0: } michael@0: michael@0: TextState.prototype = { michael@0: setTextMatrix: function TextState_setTextMatrix(a, b, c, d, e, f) { michael@0: var m = this.textMatrix; michael@0: m[0] = a; m[1] = b; m[2] = c; m[3] = d; m[4] = e; m[5] = f; michael@0: }, michael@0: setTextLineMatrix: function TextState_setTextMatrix(a, b, c, d, e, f) { michael@0: var m = this.textLineMatrix; michael@0: m[0] = a; m[1] = b; m[2] = c; m[3] = d; m[4] = e; m[5] = f; michael@0: }, michael@0: translateTextMatrix: function TextState_translateTextMatrix(x, y) { michael@0: var m = this.textMatrix; michael@0: m[4] = m[0] * x + m[2] * y + m[4]; michael@0: m[5] = m[1] * x + m[3] * y + m[5]; michael@0: }, michael@0: translateTextLineMatrix: function TextState_translateTextMatrix(x, y) { michael@0: var m = this.textLineMatrix; michael@0: m[4] = m[0] * x + m[2] * y + m[4]; michael@0: m[5] = m[1] * x + m[3] * y + m[5]; michael@0: }, michael@0: calcRenderMatrix: function TextState_calcRendeMatrix(ctm) { michael@0: // 9.4.4 Text Space Details michael@0: var tsm = [this.fontSize * this.textHScale, 0, michael@0: 0, this.fontSize, michael@0: 0, this.textRise]; michael@0: return Util.transform(ctm, Util.transform(this.textMatrix, tsm)); michael@0: }, michael@0: carriageReturn: function TextState_carriageReturn() { michael@0: this.translateTextLineMatrix(0, -this.leading); michael@0: this.textMatrix = this.textLineMatrix.slice(); michael@0: }, michael@0: clone: function TextState_clone() { michael@0: var clone = Object.create(this); michael@0: clone.textMatrix = this.textMatrix.slice(); michael@0: clone.textLineMatrix = this.textLineMatrix.slice(); michael@0: clone.fontMatrix = this.fontMatrix.slice(); michael@0: return clone; michael@0: } michael@0: }; michael@0: return TextState; michael@0: })(); michael@0: michael@0: var EvalState = (function EvalStateClosure() { michael@0: function EvalState() { michael@0: this.ctm = new Float32Array(IDENTITY_MATRIX); michael@0: this.font = null; michael@0: this.textRenderingMode = TextRenderingMode.FILL; michael@0: } michael@0: EvalState.prototype = { michael@0: clone: function CanvasExtraState_clone() { michael@0: return Object.create(this); michael@0: }, michael@0: }; michael@0: return EvalState; michael@0: })(); michael@0: michael@0: var EvaluatorPreprocessor = (function EvaluatorPreprocessorClosure() { michael@0: // Specifies properties for each command michael@0: // michael@0: // If variableArgs === true: [0, `numArgs`] expected michael@0: // If variableArgs === false: exactly `numArgs` expected michael@0: var OP_MAP = { michael@0: // Graphic state michael@0: w: { id: OPS.setLineWidth, numArgs: 1, variableArgs: false }, michael@0: J: { id: OPS.setLineCap, numArgs: 1, variableArgs: false }, michael@0: j: { id: OPS.setLineJoin, numArgs: 1, variableArgs: false }, michael@0: M: { id: OPS.setMiterLimit, numArgs: 1, variableArgs: false }, michael@0: d: { id: OPS.setDash, numArgs: 2, variableArgs: false }, michael@0: ri: { id: OPS.setRenderingIntent, numArgs: 1, variableArgs: false }, michael@0: i: { id: OPS.setFlatness, numArgs: 1, variableArgs: false }, michael@0: gs: { id: OPS.setGState, numArgs: 1, variableArgs: false }, michael@0: q: { id: OPS.save, numArgs: 0, variableArgs: false }, michael@0: Q: { id: OPS.restore, numArgs: 0, variableArgs: false }, michael@0: cm: { id: OPS.transform, numArgs: 6, variableArgs: false }, michael@0: michael@0: // Path michael@0: m: { id: OPS.moveTo, numArgs: 2, variableArgs: false }, michael@0: l: { id: OPS.lineTo, numArgs: 2, variableArgs: false }, michael@0: c: { id: OPS.curveTo, numArgs: 6, variableArgs: false }, michael@0: v: { id: OPS.curveTo2, numArgs: 4, variableArgs: false }, michael@0: y: { id: OPS.curveTo3, numArgs: 4, variableArgs: false }, michael@0: h: { id: OPS.closePath, numArgs: 0, variableArgs: false }, michael@0: re: { id: OPS.rectangle, numArgs: 4, variableArgs: false }, michael@0: S: { id: OPS.stroke, numArgs: 0, variableArgs: false }, michael@0: s: { id: OPS.closeStroke, numArgs: 0, variableArgs: false }, michael@0: f: { id: OPS.fill, numArgs: 0, variableArgs: false }, michael@0: F: { id: OPS.fill, numArgs: 0, variableArgs: false }, michael@0: 'f*': { id: OPS.eoFill, numArgs: 0, variableArgs: false }, michael@0: B: { id: OPS.fillStroke, numArgs: 0, variableArgs: false }, michael@0: 'B*': { id: OPS.eoFillStroke, numArgs: 0, variableArgs: false }, michael@0: b: { id: OPS.closeFillStroke, numArgs: 0, variableArgs: false }, michael@0: 'b*': { id: OPS.closeEOFillStroke, numArgs: 0, variableArgs: false }, michael@0: n: { id: OPS.endPath, numArgs: 0, variableArgs: false }, michael@0: michael@0: // Clipping michael@0: W: { id: OPS.clip, numArgs: 0, variableArgs: false }, michael@0: 'W*': { id: OPS.eoClip, numArgs: 0, variableArgs: false }, michael@0: michael@0: // Text michael@0: BT: { id: OPS.beginText, numArgs: 0, variableArgs: false }, michael@0: ET: { id: OPS.endText, numArgs: 0, variableArgs: false }, michael@0: Tc: { id: OPS.setCharSpacing, numArgs: 1, variableArgs: false }, michael@0: Tw: { id: OPS.setWordSpacing, numArgs: 1, variableArgs: false }, michael@0: Tz: { id: OPS.setHScale, numArgs: 1, variableArgs: false }, michael@0: TL: { id: OPS.setLeading, numArgs: 1, variableArgs: false }, michael@0: Tf: { id: OPS.setFont, numArgs: 2, variableArgs: false }, michael@0: Tr: { id: OPS.setTextRenderingMode, numArgs: 1, variableArgs: false }, michael@0: Ts: { id: OPS.setTextRise, numArgs: 1, variableArgs: false }, michael@0: Td: { id: OPS.moveText, numArgs: 2, variableArgs: false }, michael@0: TD: { id: OPS.setLeadingMoveText, numArgs: 2, variableArgs: false }, michael@0: Tm: { id: OPS.setTextMatrix, numArgs: 6, variableArgs: false }, michael@0: 'T*': { id: OPS.nextLine, numArgs: 0, variableArgs: false }, michael@0: Tj: { id: OPS.showText, numArgs: 1, variableArgs: false }, michael@0: TJ: { id: OPS.showSpacedText, numArgs: 1, variableArgs: false }, michael@0: '\'': { id: OPS.nextLineShowText, numArgs: 1, variableArgs: false }, michael@0: '"': { id: OPS.nextLineSetSpacingShowText, numArgs: 3, michael@0: variableArgs: false }, michael@0: michael@0: // Type3 fonts michael@0: d0: { id: OPS.setCharWidth, numArgs: 2, variableArgs: false }, michael@0: d1: { id: OPS.setCharWidthAndBounds, numArgs: 6, variableArgs: false }, michael@0: michael@0: // Color michael@0: CS: { id: OPS.setStrokeColorSpace, numArgs: 1, variableArgs: false }, michael@0: cs: { id: OPS.setFillColorSpace, numArgs: 1, variableArgs: false }, michael@0: SC: { id: OPS.setStrokeColor, numArgs: 4, variableArgs: true }, michael@0: SCN: { id: OPS.setStrokeColorN, numArgs: 33, variableArgs: true }, michael@0: sc: { id: OPS.setFillColor, numArgs: 4, variableArgs: true }, michael@0: scn: { id: OPS.setFillColorN, numArgs: 33, variableArgs: true }, michael@0: G: { id: OPS.setStrokeGray, numArgs: 1, variableArgs: false }, michael@0: g: { id: OPS.setFillGray, numArgs: 1, variableArgs: false }, michael@0: RG: { id: OPS.setStrokeRGBColor, numArgs: 3, variableArgs: false }, michael@0: rg: { id: OPS.setFillRGBColor, numArgs: 3, variableArgs: false }, michael@0: K: { id: OPS.setStrokeCMYKColor, numArgs: 4, variableArgs: false }, michael@0: k: { id: OPS.setFillCMYKColor, numArgs: 4, variableArgs: false }, michael@0: michael@0: // Shading michael@0: sh: { id: OPS.shadingFill, numArgs: 1, variableArgs: false }, michael@0: michael@0: // Images michael@0: BI: { id: OPS.beginInlineImage, numArgs: 0, variableArgs: false }, michael@0: ID: { id: OPS.beginImageData, numArgs: 0, variableArgs: false }, michael@0: EI: { id: OPS.endInlineImage, numArgs: 1, variableArgs: false }, michael@0: michael@0: // XObjects michael@0: Do: { id: OPS.paintXObject, numArgs: 1, variableArgs: false }, michael@0: MP: { id: OPS.markPoint, numArgs: 1, variableArgs: false }, michael@0: DP: { id: OPS.markPointProps, numArgs: 2, variableArgs: false }, michael@0: BMC: { id: OPS.beginMarkedContent, numArgs: 1, variableArgs: false }, michael@0: BDC: { id: OPS.beginMarkedContentProps, numArgs: 2, michael@0: variableArgs: false }, michael@0: EMC: { id: OPS.endMarkedContent, numArgs: 0, variableArgs: false }, michael@0: michael@0: // Compatibility michael@0: BX: { id: OPS.beginCompat, numArgs: 0, variableArgs: false }, michael@0: EX: { id: OPS.endCompat, numArgs: 0, variableArgs: false }, michael@0: michael@0: // (reserved partial commands for the lexer) michael@0: BM: null, michael@0: BD: null, michael@0: 'true': null, michael@0: fa: null, michael@0: fal: null, michael@0: fals: null, michael@0: 'false': null, michael@0: nu: null, michael@0: nul: null, michael@0: 'null': null michael@0: }; michael@0: michael@0: function EvaluatorPreprocessor(stream, xref, stateManager) { michael@0: // TODO(mduan): pass array of knownCommands rather than OP_MAP michael@0: // dictionary michael@0: this.parser = new Parser(new Lexer(stream, OP_MAP), false, xref); michael@0: this.stateManager = stateManager; michael@0: } michael@0: michael@0: EvaluatorPreprocessor.prototype = { michael@0: get savedStatesDepth() { michael@0: return this.stateManager.stateStack.length; michael@0: }, michael@0: michael@0: read: function EvaluatorPreprocessor_read() { michael@0: var args = []; michael@0: while (true) { michael@0: var obj = this.parser.getObj(); michael@0: if (isEOF(obj)) { michael@0: return null; // no more commands michael@0: } michael@0: if (!isCmd(obj)) { michael@0: // argument michael@0: if (obj !== null && obj !== undefined) { michael@0: args.push((obj instanceof Dict ? obj.getAll() : obj)); michael@0: assert(args.length <= 33, 'Too many arguments'); michael@0: } michael@0: continue; michael@0: } michael@0: michael@0: var cmd = obj.cmd; michael@0: // Check that the command is valid michael@0: var opSpec = OP_MAP[cmd]; michael@0: if (!opSpec) { michael@0: warn('Unknown command "' + cmd + '"'); michael@0: continue; michael@0: } michael@0: michael@0: var fn = opSpec.id; michael@0: michael@0: // Validate the number of arguments for the command michael@0: if (opSpec.variableArgs) { michael@0: if (args.length > opSpec.numArgs) { michael@0: info('Command ' + fn + ': expected [0,' + opSpec.numArgs + michael@0: '] args, but received ' + args.length + ' args'); michael@0: } michael@0: } else { michael@0: if (args.length < opSpec.numArgs) { michael@0: // If we receive too few args, it's not possible to possible michael@0: // to execute the command, so skip the command michael@0: info('Command ' + fn + ': because expected ' + michael@0: opSpec.numArgs + ' args, but received ' + args.length + michael@0: ' args; skipping'); michael@0: args = []; michael@0: continue; michael@0: } else if (args.length > opSpec.numArgs) { michael@0: info('Command ' + fn + ': expected ' + opSpec.numArgs + michael@0: ' args, but received ' + args.length + ' args'); michael@0: } michael@0: } michael@0: michael@0: // TODO figure out how to type-check vararg functions michael@0: this.preprocessCommand(fn, args); michael@0: michael@0: return { fn: fn, args: args }; michael@0: } michael@0: }, michael@0: michael@0: preprocessCommand: michael@0: function EvaluatorPreprocessor_preprocessCommand(fn, args) { michael@0: switch (fn | 0) { michael@0: case OPS.save: michael@0: this.stateManager.save(); michael@0: break; michael@0: case OPS.restore: michael@0: this.stateManager.restore(); michael@0: break; michael@0: case OPS.transform: michael@0: this.stateManager.transform(args); michael@0: break; michael@0: } michael@0: } michael@0: }; michael@0: return EvaluatorPreprocessor; michael@0: })(); michael@0: michael@0: var QueueOptimizer = (function QueueOptimizerClosure() { michael@0: function addState(parentState, pattern, fn) { michael@0: var state = parentState; michael@0: for (var i = 0, ii = pattern.length - 1; i < ii; i++) { michael@0: var item = pattern[i]; michael@0: state = (state[item] || (state[item] = [])); michael@0: } michael@0: state[pattern[pattern.length - 1]] = fn; michael@0: } michael@0: michael@0: function handlePaintSolidColorImageMask(index, count, fnArray, argsArray) { michael@0: // Handles special case of mainly LaTeX documents which michael@0: // use image masks to draw lines with the current fill style. michael@0: // 'count' groups of (save, transform, paintImageMaskXObject, restore)+ michael@0: // have been found at index. michael@0: for (var i = 0; i < count; i++) { michael@0: var arg = argsArray[index + 4 * i + 2]; michael@0: var imageMask = arg.length == 1 && arg[0]; michael@0: if (imageMask && imageMask.width == 1 && imageMask.height == 1 && michael@0: (!imageMask.data.length || (imageMask.data.length == 1 && michael@0: imageMask.data[0] === 0))) { michael@0: fnArray[index + 4 * i + 2] = OPS.paintSolidColorImageMask; michael@0: continue; michael@0: } michael@0: break; michael@0: } michael@0: return count - i; michael@0: } michael@0: michael@0: var InitialState = []; michael@0: michael@0: addState(InitialState, michael@0: [OPS.save, OPS.transform, OPS.paintInlineImageXObject, OPS.restore], michael@0: function foundInlineImageGroup(context) { michael@0: // grouping paintInlineImageXObject's into paintInlineImageXObjectGroup michael@0: // searching for (save, transform, paintInlineImageXObject, restore)+ michael@0: var MIN_IMAGES_IN_INLINE_IMAGES_BLOCK = 10; michael@0: var MAX_IMAGES_IN_INLINE_IMAGES_BLOCK = 200; michael@0: var MAX_WIDTH = 1000; michael@0: var IMAGE_PADDING = 1; michael@0: michael@0: var fnArray = context.fnArray, argsArray = context.argsArray; michael@0: var j = context.currentOperation - 3, i = j + 4; michael@0: var ii = fnArray.length; michael@0: michael@0: for (; i < ii && fnArray[i - 4] === fnArray[i]; i++) {} michael@0: var count = Math.min((i - j) >> 2, MAX_IMAGES_IN_INLINE_IMAGES_BLOCK); michael@0: if (count < MIN_IMAGES_IN_INLINE_IMAGES_BLOCK) { michael@0: context.currentOperation = i - 1; michael@0: return; michael@0: } michael@0: // assuming that heights of those image is too small (~1 pixel) michael@0: // packing as much as possible by lines michael@0: var maxX = 0; michael@0: var map = [], maxLineHeight = 0; michael@0: var currentX = IMAGE_PADDING, currentY = IMAGE_PADDING; michael@0: var q; michael@0: for (q = 0; q < count; q++) { michael@0: var transform = argsArray[j + (q << 2) + 1]; michael@0: var img = argsArray[j + (q << 2) + 2][0]; michael@0: if (currentX + img.width > MAX_WIDTH) { michael@0: // starting new line michael@0: maxX = Math.max(maxX, currentX); michael@0: currentY += maxLineHeight + 2 * IMAGE_PADDING; michael@0: currentX = 0; michael@0: maxLineHeight = 0; michael@0: } michael@0: map.push({ michael@0: transform: transform, michael@0: x: currentX, y: currentY, michael@0: w: img.width, h: img.height michael@0: }); michael@0: currentX += img.width + 2 * IMAGE_PADDING; michael@0: maxLineHeight = Math.max(maxLineHeight, img.height); michael@0: } michael@0: var imgWidth = Math.max(maxX, currentX) + IMAGE_PADDING; michael@0: var imgHeight = currentY + maxLineHeight + IMAGE_PADDING; michael@0: var imgData = new Uint8Array(imgWidth * imgHeight * 4); michael@0: var imgRowSize = imgWidth << 2; michael@0: for (q = 0; q < count; q++) { michael@0: var data = argsArray[j + (q << 2) + 2][0].data; michael@0: // copy image by lines and extends pixels into padding michael@0: var rowSize = map[q].w << 2; michael@0: var dataOffset = 0; michael@0: var offset = (map[q].x + map[q].y * imgWidth) << 2; michael@0: imgData.set(data.subarray(0, rowSize), offset - imgRowSize); michael@0: for (var k = 0, kk = map[q].h; k < kk; k++) { michael@0: imgData.set(data.subarray(dataOffset, dataOffset + rowSize), offset); michael@0: dataOffset += rowSize; michael@0: offset += imgRowSize; michael@0: } michael@0: imgData.set(data.subarray(dataOffset - rowSize, dataOffset), offset); michael@0: while (offset >= 0) { michael@0: data[offset - 4] = data[offset]; michael@0: data[offset - 3] = data[offset + 1]; michael@0: data[offset - 2] = data[offset + 2]; michael@0: data[offset - 1] = data[offset + 3]; michael@0: data[offset + rowSize] = data[offset + rowSize - 4]; michael@0: data[offset + rowSize + 1] = data[offset + rowSize - 3]; michael@0: data[offset + rowSize + 2] = data[offset + rowSize - 2]; michael@0: data[offset + rowSize + 3] = data[offset + rowSize - 1]; michael@0: offset -= imgRowSize; michael@0: } michael@0: } michael@0: // replacing queue items michael@0: fnArray.splice(j, count * 4, OPS.paintInlineImageXObjectGroup); michael@0: argsArray.splice(j, count * 4, michael@0: [{ width: imgWidth, height: imgHeight, kind: ImageKind.RGBA_32BPP, michael@0: data: imgData }, map]); michael@0: context.currentOperation = j; michael@0: }); michael@0: michael@0: addState(InitialState, michael@0: [OPS.save, OPS.transform, OPS.paintImageMaskXObject, OPS.restore], michael@0: function foundImageMaskGroup(context) { michael@0: // grouping paintImageMaskXObject's into paintImageMaskXObjectGroup michael@0: // searching for (save, transform, paintImageMaskXObject, restore)+ michael@0: var MIN_IMAGES_IN_MASKS_BLOCK = 10; michael@0: var MAX_IMAGES_IN_MASKS_BLOCK = 100; michael@0: var MAX_SAME_IMAGES_IN_MASKS_BLOCK = 1000; michael@0: michael@0: var fnArray = context.fnArray, argsArray = context.argsArray; michael@0: var j = context.currentOperation - 3, i = j + 4; michael@0: var ii = fnArray.length, q; michael@0: michael@0: for (; i < ii && fnArray[i - 4] === fnArray[i]; i++) {} michael@0: var count = (i - j) >> 2; michael@0: count = handlePaintSolidColorImageMask(j, count, fnArray, argsArray); michael@0: if (count < MIN_IMAGES_IN_MASKS_BLOCK) { michael@0: context.currentOperation = i - 1; michael@0: return; michael@0: } michael@0: michael@0: var isSameImage = false; michael@0: var transformArgs; michael@0: if (argsArray[j + 1][1] === 0 && argsArray[j + 1][2] === 0) { michael@0: i = j + 4; michael@0: isSameImage = true; michael@0: for (q = 1; q < count; q++, i += 4) { michael@0: var prevTransformArgs = argsArray[i - 3]; michael@0: transformArgs = argsArray[i + 1]; michael@0: if (argsArray[i - 2][0] !== argsArray[i + 2][0] || michael@0: prevTransformArgs[0] !== transformArgs[0] || michael@0: prevTransformArgs[1] !== transformArgs[1] || michael@0: prevTransformArgs[2] !== transformArgs[2] || michael@0: prevTransformArgs[3] !== transformArgs[3]) { michael@0: if (q < MIN_IMAGES_IN_MASKS_BLOCK) { michael@0: isSameImage = false; michael@0: } else { michael@0: count = q; michael@0: } michael@0: break; // different image or transform michael@0: } michael@0: } michael@0: } michael@0: michael@0: if (isSameImage) { michael@0: count = Math.min(count, MAX_SAME_IMAGES_IN_MASKS_BLOCK); michael@0: var positions = new Float32Array(count * 2); michael@0: i = j + 1; michael@0: for (q = 0; q < count; q++) { michael@0: transformArgs = argsArray[i]; michael@0: positions[(q << 1)] = transformArgs[4]; michael@0: positions[(q << 1) + 1] = transformArgs[5]; michael@0: i += 4; michael@0: } michael@0: michael@0: // replacing queue items michael@0: fnArray.splice(j, count * 4, OPS.paintImageMaskXObjectRepeat); michael@0: argsArray.splice(j, count * 4, [argsArray[j + 2][0], michael@0: argsArray[j + 1][0], argsArray[j + 1][3], positions]); michael@0: michael@0: context.currentOperation = j; michael@0: } else { michael@0: count = Math.min(count, MAX_IMAGES_IN_MASKS_BLOCK); michael@0: var images = []; michael@0: for (q = 0; q < count; q++) { michael@0: transformArgs = argsArray[j + (q << 2) + 1]; michael@0: var maskParams = argsArray[j + (q << 2) + 2][0]; michael@0: images.push({ data: maskParams.data, width: maskParams.width, michael@0: height: maskParams.height, michael@0: transform: transformArgs }); michael@0: } michael@0: michael@0: // replacing queue items michael@0: fnArray.splice(j, count * 4, OPS.paintImageMaskXObjectGroup); michael@0: argsArray.splice(j, count * 4, [images]); michael@0: michael@0: context.currentOperation = j; michael@0: } michael@0: }); michael@0: michael@0: addState(InitialState, michael@0: [OPS.save, OPS.transform, OPS.paintImageXObject, OPS.restore], michael@0: function (context) { michael@0: var MIN_IMAGES_IN_BLOCK = 3; michael@0: var MAX_IMAGES_IN_BLOCK = 1000; michael@0: michael@0: var fnArray = context.fnArray, argsArray = context.argsArray; michael@0: var j = context.currentOperation - 3, i = j + 4; michael@0: if (argsArray[j + 1][1] !== 0 || argsArray[j + 1][2] !== 0) { michael@0: return; michael@0: } michael@0: var ii = fnArray.length; michael@0: var transformArgs; michael@0: for (; i + 3 < ii && fnArray[i - 4] === fnArray[i]; i += 4) { michael@0: if (fnArray[i - 3] !== fnArray[i + 1] || michael@0: fnArray[i - 2] !== fnArray[i + 2] || michael@0: fnArray[i - 1] !== fnArray[i + 3]) { michael@0: break; michael@0: } michael@0: if (argsArray[i - 2][0] !== argsArray[i + 2][0]) { michael@0: break; // different image michael@0: } michael@0: var prevTransformArgs = argsArray[i - 3]; michael@0: transformArgs = argsArray[i + 1]; michael@0: if (prevTransformArgs[0] !== transformArgs[0] || michael@0: prevTransformArgs[1] !== transformArgs[1] || michael@0: prevTransformArgs[2] !== transformArgs[2] || michael@0: prevTransformArgs[3] !== transformArgs[3]) { michael@0: break; // different transform michael@0: } michael@0: } michael@0: var count = Math.min((i - j) >> 2, MAX_IMAGES_IN_BLOCK); michael@0: if (count < MIN_IMAGES_IN_BLOCK) { michael@0: context.currentOperation = i - 1; michael@0: return; michael@0: } michael@0: michael@0: var positions = new Float32Array(count * 2); michael@0: i = j + 1; michael@0: for (var q = 0; q < count; q++) { michael@0: transformArgs = argsArray[i]; michael@0: positions[(q << 1)] = transformArgs[4]; michael@0: positions[(q << 1) + 1] = transformArgs[5]; michael@0: i += 4; michael@0: } michael@0: var args = [argsArray[j + 2][0], argsArray[j + 1][0], michael@0: argsArray[j + 1][3], positions]; michael@0: // replacing queue items michael@0: fnArray.splice(j, count * 4, OPS.paintImageXObjectRepeat); michael@0: argsArray.splice(j, count * 4, args); michael@0: michael@0: context.currentOperation = j; michael@0: }); michael@0: michael@0: addState(InitialState, michael@0: [OPS.beginText, OPS.setFont, OPS.setTextMatrix, OPS.showText, OPS.endText], michael@0: function (context) { michael@0: // moving single chars with same font into beginText/endText groups michael@0: // searching for (beginText, setFont, setTextMatrix, showText, endText)+ michael@0: var MIN_CHARS_IN_BLOCK = 3; michael@0: var MAX_CHARS_IN_BLOCK = 1000; michael@0: michael@0: var fnArray = context.fnArray, argsArray = context.argsArray; michael@0: var j = context.currentOperation - 4, i = j + 5; michael@0: var ii = fnArray.length; michael@0: michael@0: for (; i < ii && fnArray[i - 5] === fnArray[i]; i++) { michael@0: if (fnArray[i] === OPS.setFont) { michael@0: if (argsArray[i - 5][0] !== argsArray[i][0] || michael@0: argsArray[i - 5][1] !== argsArray[i][1]) { michael@0: break; michael@0: } michael@0: } michael@0: } michael@0: var count = Math.min(((i - j) / 5) | 0, MAX_CHARS_IN_BLOCK); michael@0: if (count < MIN_CHARS_IN_BLOCK) { michael@0: context.currentOperation = i - 1; michael@0: return; michael@0: } michael@0: if (j >= 4 && fnArray[j - 4] === fnArray[j + 1] && michael@0: fnArray[j - 3] === fnArray[j + 2] && michael@0: fnArray[j - 2] === fnArray[j + 3] && michael@0: fnArray[j - 1] === fnArray[j + 4] && michael@0: argsArray[j - 4][0] === argsArray[j + 1][0] && michael@0: argsArray[j - 4][1] === argsArray[j + 1][1]) { michael@0: // extending one block ahead (very first block might have 'dependency') michael@0: count++; michael@0: j -= 5; michael@0: } michael@0: var k = j + 7; michael@0: i = j + 4; michael@0: for (var q = 1; q < count; q++) { michael@0: fnArray[i] = fnArray[k]; michael@0: argsArray[i] = argsArray[k]; michael@0: fnArray[i + 1] = fnArray[k + 1]; michael@0: argsArray[i + 1] = argsArray[k + 1]; michael@0: i += 2; michael@0: k += 5; michael@0: } michael@0: var removed = (count - 1) * 3; michael@0: fnArray.splice(i, removed); michael@0: argsArray.splice(i, removed); michael@0: michael@0: context.currentOperation = i; michael@0: }); michael@0: michael@0: function QueueOptimizer() {} michael@0: michael@0: QueueOptimizer.prototype = { michael@0: optimize: function QueueOptimizer_optimize(queue) { michael@0: var fnArray = queue.fnArray, argsArray = queue.argsArray; michael@0: var context = { michael@0: currentOperation: 0, michael@0: fnArray: fnArray, michael@0: argsArray: argsArray michael@0: }; michael@0: var i, ii = argsArray.length; michael@0: var state; michael@0: for (i = 0; i < ii; i++) { michael@0: state = (state || InitialState)[fnArray[i]]; michael@0: if (typeof state === 'function') { // we found some handler michael@0: context.currentOperation = i; michael@0: state = state(context); michael@0: i = context.currentOperation; michael@0: ii = context.fnArray.length; michael@0: } michael@0: } michael@0: } michael@0: }; michael@0: return QueueOptimizer; michael@0: })(); michael@0: michael@0: michael@0: var BUILT_IN_CMAPS = [ michael@0: // << Start unicode maps. michael@0: 'Adobe-GB1-UCS2', michael@0: 'Adobe-CNS1-UCS2', michael@0: 'Adobe-Japan1-UCS2', michael@0: 'Adobe-Korea1-UCS2', michael@0: // >> End unicode maps. michael@0: '78-EUC-H', michael@0: '78-EUC-V', michael@0: '78-H', michael@0: '78-RKSJ-H', michael@0: '78-RKSJ-V', michael@0: '78-V', michael@0: '78ms-RKSJ-H', michael@0: '78ms-RKSJ-V', michael@0: '83pv-RKSJ-H', michael@0: '90ms-RKSJ-H', michael@0: '90ms-RKSJ-V', michael@0: '90msp-RKSJ-H', michael@0: '90msp-RKSJ-V', michael@0: '90pv-RKSJ-H', michael@0: '90pv-RKSJ-V', michael@0: 'Add-H', michael@0: 'Add-RKSJ-H', michael@0: 'Add-RKSJ-V', michael@0: 'Add-V', michael@0: 'Adobe-CNS1-0', michael@0: 'Adobe-CNS1-1', michael@0: 'Adobe-CNS1-2', michael@0: 'Adobe-CNS1-3', michael@0: 'Adobe-CNS1-4', michael@0: 'Adobe-CNS1-5', michael@0: 'Adobe-CNS1-6', michael@0: 'Adobe-GB1-0', michael@0: 'Adobe-GB1-1', michael@0: 'Adobe-GB1-2', michael@0: 'Adobe-GB1-3', michael@0: 'Adobe-GB1-4', michael@0: 'Adobe-GB1-5', michael@0: 'Adobe-Japan1-0', michael@0: 'Adobe-Japan1-1', michael@0: 'Adobe-Japan1-2', michael@0: 'Adobe-Japan1-3', michael@0: 'Adobe-Japan1-4', michael@0: 'Adobe-Japan1-5', michael@0: 'Adobe-Japan1-6', michael@0: 'Adobe-Korea1-0', michael@0: 'Adobe-Korea1-1', michael@0: 'Adobe-Korea1-2', michael@0: 'B5-H', michael@0: 'B5-V', michael@0: 'B5pc-H', michael@0: 'B5pc-V', michael@0: 'CNS-EUC-H', michael@0: 'CNS-EUC-V', michael@0: 'CNS1-H', michael@0: 'CNS1-V', michael@0: 'CNS2-H', michael@0: 'CNS2-V', michael@0: 'ETHK-B5-H', michael@0: 'ETHK-B5-V', michael@0: 'ETen-B5-H', michael@0: 'ETen-B5-V', michael@0: 'ETenms-B5-H', michael@0: 'ETenms-B5-V', michael@0: 'EUC-H', michael@0: 'EUC-V', michael@0: 'Ext-H', michael@0: 'Ext-RKSJ-H', michael@0: 'Ext-RKSJ-V', michael@0: 'Ext-V', michael@0: 'GB-EUC-H', michael@0: 'GB-EUC-V', michael@0: 'GB-H', michael@0: 'GB-V', michael@0: 'GBK-EUC-H', michael@0: 'GBK-EUC-V', michael@0: 'GBK2K-H', michael@0: 'GBK2K-V', michael@0: 'GBKp-EUC-H', michael@0: 'GBKp-EUC-V', michael@0: 'GBT-EUC-H', michael@0: 'GBT-EUC-V', michael@0: 'GBT-H', michael@0: 'GBT-V', michael@0: 'GBTpc-EUC-H', michael@0: 'GBTpc-EUC-V', michael@0: 'GBpc-EUC-H', michael@0: 'GBpc-EUC-V', michael@0: 'H', michael@0: 'HKdla-B5-H', michael@0: 'HKdla-B5-V', michael@0: 'HKdlb-B5-H', michael@0: 'HKdlb-B5-V', michael@0: 'HKgccs-B5-H', michael@0: 'HKgccs-B5-V', michael@0: 'HKm314-B5-H', michael@0: 'HKm314-B5-V', michael@0: 'HKm471-B5-H', michael@0: 'HKm471-B5-V', michael@0: 'HKscs-B5-H', michael@0: 'HKscs-B5-V', michael@0: 'Hankaku', michael@0: 'Hiragana', michael@0: 'KSC-EUC-H', michael@0: 'KSC-EUC-V', michael@0: 'KSC-H', michael@0: 'KSC-Johab-H', michael@0: 'KSC-Johab-V', michael@0: 'KSC-V', michael@0: 'KSCms-UHC-H', michael@0: 'KSCms-UHC-HW-H', michael@0: 'KSCms-UHC-HW-V', michael@0: 'KSCms-UHC-V', michael@0: 'KSCpc-EUC-H', michael@0: 'KSCpc-EUC-V', michael@0: 'Katakana', michael@0: 'NWP-H', michael@0: 'NWP-V', michael@0: 'RKSJ-H', michael@0: 'RKSJ-V', michael@0: 'Roman', michael@0: 'UniCNS-UCS2-H', michael@0: 'UniCNS-UCS2-V', michael@0: 'UniCNS-UTF16-H', michael@0: 'UniCNS-UTF16-V', michael@0: 'UniCNS-UTF32-H', michael@0: 'UniCNS-UTF32-V', michael@0: 'UniCNS-UTF8-H', michael@0: 'UniCNS-UTF8-V', michael@0: 'UniGB-UCS2-H', michael@0: 'UniGB-UCS2-V', michael@0: 'UniGB-UTF16-H', michael@0: 'UniGB-UTF16-V', michael@0: 'UniGB-UTF32-H', michael@0: 'UniGB-UTF32-V', michael@0: 'UniGB-UTF8-H', michael@0: 'UniGB-UTF8-V', michael@0: 'UniJIS-UCS2-H', michael@0: 'UniJIS-UCS2-HW-H', michael@0: 'UniJIS-UCS2-HW-V', michael@0: 'UniJIS-UCS2-V', michael@0: 'UniJIS-UTF16-H', michael@0: 'UniJIS-UTF16-V', michael@0: 'UniJIS-UTF32-H', michael@0: 'UniJIS-UTF32-V', michael@0: 'UniJIS-UTF8-H', michael@0: 'UniJIS-UTF8-V', michael@0: 'UniJIS2004-UTF16-H', michael@0: 'UniJIS2004-UTF16-V', michael@0: 'UniJIS2004-UTF32-H', michael@0: 'UniJIS2004-UTF32-V', michael@0: 'UniJIS2004-UTF8-H', michael@0: 'UniJIS2004-UTF8-V', michael@0: 'UniJISPro-UCS2-HW-V', michael@0: 'UniJISPro-UCS2-V', michael@0: 'UniJISPro-UTF8-V', michael@0: 'UniJISX0213-UTF32-H', michael@0: 'UniJISX0213-UTF32-V', michael@0: 'UniJISX02132004-UTF32-H', michael@0: 'UniJISX02132004-UTF32-V', michael@0: 'UniKS-UCS2-H', michael@0: 'UniKS-UCS2-V', michael@0: 'UniKS-UTF16-H', michael@0: 'UniKS-UTF16-V', michael@0: 'UniKS-UTF32-H', michael@0: 'UniKS-UTF32-V', michael@0: 'UniKS-UTF8-H', michael@0: 'UniKS-UTF8-V', michael@0: 'V', michael@0: 'WP-Symbol']; michael@0: michael@0: // CMap, not to be confused with TrueType's cmap. michael@0: var CMap = (function CMapClosure() { michael@0: function CMap(builtInCMap) { michael@0: // Codespace ranges are stored as follows: michael@0: // [[1BytePairs], [2BytePairs], [3BytePairs], [4BytePairs]] michael@0: // where nBytePairs are ranges e.g. [low1, high1, low2, high2, ...] michael@0: this.codespaceRanges = [[], [], [], []]; michael@0: this.numCodespaceRanges = 0; michael@0: this.map = []; michael@0: this.vertical = false; michael@0: this.useCMap = null; michael@0: this.builtInCMap = builtInCMap; michael@0: } michael@0: CMap.prototype = { michael@0: addCodespaceRange: function(n, low, high) { michael@0: this.codespaceRanges[n - 1].push(low, high); michael@0: this.numCodespaceRanges++; michael@0: }, michael@0: michael@0: mapRange: function(low, high, dstLow) { michael@0: var lastByte = dstLow.length - 1; michael@0: while (low <= high) { michael@0: this.map[low] = dstLow; michael@0: // Only the last byte has to be incremented. michael@0: dstLow = dstLow.substr(0, lastByte) + michael@0: String.fromCharCode(dstLow.charCodeAt(lastByte) + 1); michael@0: ++low; michael@0: } michael@0: }, michael@0: michael@0: mapRangeToArray: function(low, high, array) { michael@0: var i = 0; michael@0: while (low <= high) { michael@0: this.map[low] = array[i++]; michael@0: ++low; michael@0: } michael@0: }, michael@0: michael@0: mapOne: function(src, dst) { michael@0: this.map[src] = dst; michael@0: }, michael@0: michael@0: lookup: function(code) { michael@0: return this.map[code]; michael@0: }, michael@0: michael@0: readCharCode: function(str, offset) { michael@0: var c = 0; michael@0: var codespaceRanges = this.codespaceRanges; michael@0: var codespaceRangesLen = this.codespaceRanges.length; michael@0: // 9.7.6.2 CMap Mapping michael@0: // The code length is at most 4. michael@0: for (var n = 0; n < codespaceRangesLen; n++) { michael@0: c = ((c << 8) | str.charCodeAt(offset + n)) >>> 0; michael@0: // Check each codespace range to see if it falls within. michael@0: var codespaceRange = codespaceRanges[n]; michael@0: for (var k = 0, kk = codespaceRange.length; k < kk;) { michael@0: var low = codespaceRange[k++]; michael@0: var high = codespaceRange[k++]; michael@0: if (c >= low && c <= high) { michael@0: return [c, n + 1]; michael@0: } michael@0: } michael@0: } michael@0: michael@0: return [0, 1]; michael@0: } michael@0: michael@0: }; michael@0: return CMap; michael@0: })(); michael@0: michael@0: var IdentityCMap = (function IdentityCMapClosure() { michael@0: function IdentityCMap(vertical, n) { michael@0: CMap.call(this); michael@0: this.vertical = vertical; michael@0: this.addCodespaceRange(n, 0, 0xffff); michael@0: this.mapRange(0, 0xffff, '\u0000'); michael@0: } michael@0: Util.inherit(IdentityCMap, CMap, {}); michael@0: michael@0: return IdentityCMap; michael@0: })(); michael@0: michael@0: var BinaryCMapReader = (function BinaryCMapReaderClosure() { michael@0: function fetchBinaryData(url) { michael@0: var nonBinaryRequest = PDFJS.disableWorker; michael@0: var request = new XMLHttpRequest(); michael@0: request.open('GET', url, false); michael@0: if (!nonBinaryRequest) { michael@0: try { michael@0: request.responseType = 'arraybuffer'; michael@0: nonBinaryRequest = request.responseType !== 'arraybuffer'; michael@0: } catch (e) { michael@0: nonBinaryRequest = true; michael@0: } michael@0: } michael@0: if (nonBinaryRequest && request.overrideMimeType) { michael@0: request.overrideMimeType('text/plain; charset=x-user-defined'); michael@0: } michael@0: request.send(null); michael@0: if (request.status === 0 && /^https?:/i.test(url)) { michael@0: error('Unable to get binary cMap at: ' + url); michael@0: } michael@0: if (nonBinaryRequest) { michael@0: var data = Array.prototype.map.call(request.responseText, function (ch) { michael@0: return ch.charCodeAt(0) & 255; michael@0: }); michael@0: return new Uint8Array(data); michael@0: } michael@0: return new Uint8Array(request.response); michael@0: } michael@0: michael@0: function hexToInt(a, size) { michael@0: var n = 0; michael@0: for (var i = 0; i <= size; i++) { michael@0: n = (n << 8) | a[i]; michael@0: } michael@0: return n >>> 0; michael@0: } michael@0: michael@0: function hexToStr(a, size) { michael@0: return String.fromCharCode.apply(null, a.subarray(0, size + 1)); michael@0: } michael@0: michael@0: function addHex(a, b, size) { michael@0: var c = 0; michael@0: for (var i = size; i >= 0; i--) { michael@0: c += a[i] + b[i]; michael@0: a[i] = c & 255; michael@0: c >>= 8; michael@0: } michael@0: } michael@0: michael@0: function incHex(a, size) { michael@0: var c = 1; michael@0: for (var i = size; i >= 0 && c > 0; i--) { michael@0: c += a[i]; michael@0: a[i] = c & 255; michael@0: c >>= 8; michael@0: } michael@0: } michael@0: michael@0: var MAX_NUM_SIZE = 16; michael@0: var MAX_ENCODED_NUM_SIZE = 19; // ceil(MAX_NUM_SIZE * 7 / 8) michael@0: michael@0: function BinaryCMapStream(data) { michael@0: this.buffer = data; michael@0: this.pos = 0; michael@0: this.end = data.length; michael@0: this.tmpBuf = new Uint8Array(MAX_ENCODED_NUM_SIZE); michael@0: } michael@0: michael@0: BinaryCMapStream.prototype = { michael@0: readByte: function () { michael@0: if (this.pos >= this.end) { michael@0: return -1; michael@0: } michael@0: return this.buffer[this.pos++]; michael@0: }, michael@0: readNumber: function () { michael@0: var n = 0; michael@0: var last; michael@0: do { michael@0: var b = this.readByte(); michael@0: if (b < 0) { michael@0: error('unexpected EOF in bcmap'); michael@0: } michael@0: last = !(b & 0x80); michael@0: n = (n << 7) | (b & 0x7F); michael@0: } while (!last); michael@0: return n; michael@0: }, michael@0: readSigned: function () { michael@0: var n = this.readNumber(); michael@0: return (n & 1) ? ~(n >>> 1) : n >>> 1; michael@0: }, michael@0: readHex: function (num, size) { michael@0: num.set(this.buffer.subarray(this.pos, michael@0: this.pos + size + 1)); michael@0: this.pos += size + 1; michael@0: }, michael@0: readHexNumber: function (num, size) { michael@0: var last; michael@0: var stack = this.tmpBuf, sp = 0; michael@0: do { michael@0: var b = this.readByte(); michael@0: if (b < 0) { michael@0: error('unexpected EOF in bcmap'); michael@0: } michael@0: last = !(b & 0x80); michael@0: stack[sp++] = b & 0x7F; michael@0: } while (!last); michael@0: var i = size, buffer = 0, bufferSize = 0; michael@0: while (i >= 0) { michael@0: while (bufferSize < 8 && stack.length > 0) { michael@0: buffer = (stack[--sp] << bufferSize) | buffer; michael@0: bufferSize += 7; michael@0: } michael@0: num[i] = buffer & 255; michael@0: i--; michael@0: buffer >>= 8; michael@0: bufferSize -= 8; michael@0: } michael@0: }, michael@0: readHexSigned: function (num, size) { michael@0: this.readHexNumber(num, size); michael@0: var sign = num[size] & 1 ? 255 : 0; michael@0: var c = 0; michael@0: for (var i = 0; i <= size; i++) { michael@0: c = ((c & 1) << 8) | num[i]; michael@0: num[i] = (c >> 1) ^ sign; michael@0: } michael@0: }, michael@0: readString: function () { michael@0: var len = this.readNumber(); michael@0: var s = ''; michael@0: for (var i = 0; i < len; i++) { michael@0: s += String.fromCharCode(this.readNumber()); michael@0: } michael@0: return s; michael@0: } michael@0: }; michael@0: michael@0: function processBinaryCMap(url, cMap, extend) { michael@0: var data = fetchBinaryData(url); michael@0: var stream = new BinaryCMapStream(data); michael@0: michael@0: var header = stream.readByte(); michael@0: cMap.vertical = !!(header & 1); michael@0: michael@0: var useCMap = null; michael@0: var start = new Uint8Array(MAX_NUM_SIZE); michael@0: var end = new Uint8Array(MAX_NUM_SIZE); michael@0: var char = new Uint8Array(MAX_NUM_SIZE); michael@0: var charCode = new Uint8Array(MAX_NUM_SIZE); michael@0: var tmp = new Uint8Array(MAX_NUM_SIZE); michael@0: var code; michael@0: michael@0: var b; michael@0: while ((b = stream.readByte()) >= 0) { michael@0: var type = b >> 5; michael@0: if (type === 7) { // metadata, e.g. comment or usecmap michael@0: switch (b & 0x1F) { michael@0: case 0: michael@0: stream.readString(); // skipping comment michael@0: break; michael@0: case 1: michael@0: useCMap = stream.readString(); michael@0: break; michael@0: } michael@0: continue; michael@0: } michael@0: var sequence = !!(b & 0x10); michael@0: var dataSize = b & 15; michael@0: michael@0: assert(dataSize + 1 <= MAX_NUM_SIZE); michael@0: michael@0: var ucs2DataSize = 1; michael@0: var subitemsCount = stream.readNumber(); michael@0: var i; michael@0: switch (type) { michael@0: case 0: // codespacerange michael@0: stream.readHex(start, dataSize); michael@0: stream.readHexNumber(end, dataSize); michael@0: addHex(end, start, dataSize); michael@0: cMap.addCodespaceRange(dataSize + 1, hexToInt(start, dataSize), michael@0: hexToInt(end, dataSize)); michael@0: for (i = 1; i < subitemsCount; i++) { michael@0: incHex(end, dataSize); michael@0: stream.readHexNumber(start, dataSize); michael@0: addHex(start, end, dataSize); michael@0: stream.readHexNumber(end, dataSize); michael@0: addHex(end, start, dataSize); michael@0: cMap.addCodespaceRange(dataSize + 1, hexToInt(start, dataSize), michael@0: hexToInt(end, dataSize)); michael@0: } michael@0: break; michael@0: case 1: // notdefrange michael@0: stream.readHex(start, dataSize); michael@0: stream.readHexNumber(end, dataSize); michael@0: addHex(end, start, dataSize); michael@0: code = stream.readNumber(); michael@0: // undefined range, skipping michael@0: for (i = 1; i < subitemsCount; i++) { michael@0: incHex(end, dataSize); michael@0: stream.readHexNumber(start, dataSize); michael@0: addHex(start, end, dataSize); michael@0: stream.readHexNumber(end, dataSize); michael@0: addHex(end, start, dataSize); michael@0: code = stream.readNumber(); michael@0: // nop michael@0: } michael@0: break; michael@0: case 2: // cidchar michael@0: stream.readHex(char, dataSize); michael@0: code = stream.readNumber(); michael@0: cMap.mapOne(hexToInt(char, dataSize), String.fromCharCode(code)); michael@0: for (i = 1; i < subitemsCount; i++) { michael@0: incHex(char, dataSize); michael@0: if (!sequence) { michael@0: stream.readHexNumber(tmp, dataSize); michael@0: addHex(char, tmp, dataSize); michael@0: } michael@0: code = stream.readSigned() + (code + 1); michael@0: cMap.mapOne(hexToInt(char, dataSize), String.fromCharCode(code)); michael@0: } michael@0: break; michael@0: case 3: // cidrange michael@0: stream.readHex(start, dataSize); michael@0: stream.readHexNumber(end, dataSize); michael@0: addHex(end, start, dataSize); michael@0: code = stream.readNumber(); michael@0: cMap.mapRange(hexToInt(start, dataSize), hexToInt(end, dataSize), michael@0: String.fromCharCode(code)); michael@0: for (i = 1; i < subitemsCount; i++) { michael@0: incHex(end, dataSize); michael@0: if (!sequence) { michael@0: stream.readHexNumber(start, dataSize); michael@0: addHex(start, end, dataSize); michael@0: } else { michael@0: start.set(end); michael@0: } michael@0: stream.readHexNumber(end, dataSize); michael@0: addHex(end, start, dataSize); michael@0: code = stream.readNumber(); michael@0: cMap.mapRange(hexToInt(start, dataSize), hexToInt(end, dataSize), michael@0: String.fromCharCode(code)); michael@0: } michael@0: break; michael@0: case 4: // bfchar michael@0: stream.readHex(char, ucs2DataSize); michael@0: stream.readHex(charCode, dataSize); michael@0: cMap.mapOne(hexToInt(char, ucs2DataSize), michael@0: hexToStr(charCode, dataSize)); michael@0: for (i = 1; i < subitemsCount; i++) { michael@0: incHex(char, ucs2DataSize); michael@0: if (!sequence) { michael@0: stream.readHexNumber(tmp, ucs2DataSize); michael@0: addHex(char, tmp, ucs2DataSize); michael@0: } michael@0: incHex(charCode, dataSize); michael@0: stream.readHexSigned(tmp, dataSize); michael@0: addHex(charCode, tmp, dataSize); michael@0: cMap.mapOne(hexToInt(char, ucs2DataSize), michael@0: hexToStr(charCode, dataSize)); michael@0: } michael@0: break; michael@0: case 5: // bfrange michael@0: stream.readHex(start, ucs2DataSize); michael@0: stream.readHexNumber(end, ucs2DataSize); michael@0: addHex(end, start, ucs2DataSize); michael@0: stream.readHex(charCode, dataSize); michael@0: cMap.mapRange(hexToInt(start, ucs2DataSize), michael@0: hexToInt(end, ucs2DataSize), michael@0: hexToStr(charCode, dataSize)); michael@0: for (i = 1; i < subitemsCount; i++) { michael@0: incHex(end, ucs2DataSize); michael@0: if (!sequence) { michael@0: stream.readHexNumber(start, ucs2DataSize); michael@0: addHex(start, end, ucs2DataSize); michael@0: } else { michael@0: start.set(end); michael@0: } michael@0: stream.readHexNumber(end, ucs2DataSize); michael@0: addHex(end, start, ucs2DataSize); michael@0: stream.readHex(charCode, dataSize); michael@0: cMap.mapRange(hexToInt(start, ucs2DataSize), michael@0: hexToInt(end, ucs2DataSize), michael@0: hexToStr(charCode, dataSize)); michael@0: } michael@0: break; michael@0: default: michael@0: error('Unknown type: ' + type); michael@0: break; michael@0: } michael@0: } michael@0: michael@0: if (useCMap) { michael@0: extend(useCMap); michael@0: } michael@0: return cMap; michael@0: } michael@0: michael@0: function BinaryCMapReader() {} michael@0: michael@0: BinaryCMapReader.prototype = { michael@0: read: processBinaryCMap michael@0: }; michael@0: michael@0: return BinaryCMapReader; michael@0: })(); michael@0: michael@0: var CMapFactory = (function CMapFactoryClosure() { michael@0: function strToInt(str) { michael@0: var a = 0; michael@0: for (var i = 0; i < str.length; i++) { michael@0: a = (a << 8) | str.charCodeAt(i); michael@0: } michael@0: return a >>> 0; michael@0: } michael@0: michael@0: function expectString(obj) { michael@0: if (!isString(obj)) { michael@0: error('Malformed CMap: expected string.'); michael@0: } michael@0: } michael@0: michael@0: function expectInt(obj) { michael@0: if (!isInt(obj)) { michael@0: error('Malformed CMap: expected int.'); michael@0: } michael@0: } michael@0: michael@0: function parseBfChar(cMap, lexer) { michael@0: while (true) { michael@0: var obj = lexer.getObj(); michael@0: if (isEOF(obj)) { michael@0: break; michael@0: } michael@0: if (isCmd(obj, 'endbfchar')) { michael@0: return; michael@0: } michael@0: expectString(obj); michael@0: var src = strToInt(obj); michael@0: obj = lexer.getObj(); michael@0: // TODO are /dstName used? michael@0: expectString(obj); michael@0: var dst = obj; michael@0: cMap.mapOne(src, dst); michael@0: } michael@0: } michael@0: michael@0: function parseBfRange(cMap, lexer) { michael@0: while (true) { michael@0: var obj = lexer.getObj(); michael@0: if (isEOF(obj)) { michael@0: break; michael@0: } michael@0: if (isCmd(obj, 'endbfrange')) { michael@0: return; michael@0: } michael@0: expectString(obj); michael@0: var low = strToInt(obj); michael@0: obj = lexer.getObj(); michael@0: expectString(obj); michael@0: var high = strToInt(obj); michael@0: obj = lexer.getObj(); michael@0: if (isInt(obj) || isString(obj)) { michael@0: var dstLow = isInt(obj) ? String.fromCharCode(obj) : obj; michael@0: cMap.mapRange(low, high, dstLow); michael@0: } else if (isCmd(obj, '[')) { michael@0: obj = lexer.getObj(); michael@0: var array = []; michael@0: while (!isCmd(obj, ']') && !isEOF(obj)) { michael@0: array.push(obj); michael@0: obj = lexer.getObj(); michael@0: } michael@0: cMap.mapRangeToArray(low, high, array); michael@0: } else { michael@0: break; michael@0: } michael@0: } michael@0: error('Invalid bf range.'); michael@0: } michael@0: michael@0: function parseCidChar(cMap, lexer) { michael@0: while (true) { michael@0: var obj = lexer.getObj(); michael@0: if (isEOF(obj)) { michael@0: break; michael@0: } michael@0: if (isCmd(obj, 'endcidchar')) { michael@0: return; michael@0: } michael@0: expectString(obj); michael@0: var src = strToInt(obj); michael@0: obj = lexer.getObj(); michael@0: expectInt(obj); michael@0: var dst = String.fromCharCode(obj); michael@0: cMap.mapOne(src, dst); michael@0: } michael@0: } michael@0: michael@0: function parseCidRange(cMap, lexer) { michael@0: while (true) { michael@0: var obj = lexer.getObj(); michael@0: if (isEOF(obj)) { michael@0: break; michael@0: } michael@0: if (isCmd(obj, 'endcidrange')) { michael@0: return; michael@0: } michael@0: expectString(obj); michael@0: var low = strToInt(obj); michael@0: obj = lexer.getObj(); michael@0: expectString(obj); michael@0: var high = strToInt(obj); michael@0: obj = lexer.getObj(); michael@0: expectInt(obj); michael@0: var dstLow = String.fromCharCode(obj); michael@0: cMap.mapRange(low, high, dstLow); michael@0: } michael@0: } michael@0: michael@0: function parseCodespaceRange(cMap, lexer) { michael@0: while (true) { michael@0: var obj = lexer.getObj(); michael@0: if (isEOF(obj)) { michael@0: break; michael@0: } michael@0: if (isCmd(obj, 'endcodespacerange')) { michael@0: return; michael@0: } michael@0: if (!isString(obj)) { michael@0: break; michael@0: } michael@0: var low = strToInt(obj); michael@0: obj = lexer.getObj(); michael@0: if (!isString(obj)) { michael@0: break; michael@0: } michael@0: var high = strToInt(obj); michael@0: cMap.addCodespaceRange(obj.length, low, high); michael@0: } michael@0: error('Invalid codespace range.'); michael@0: } michael@0: michael@0: function parseWMode(cMap, lexer) { michael@0: var obj = lexer.getObj(); michael@0: if (isInt(obj)) { michael@0: cMap.vertical = !!obj; michael@0: } michael@0: } michael@0: michael@0: function parseCMap(cMap, lexer, builtInCMapParams, useCMap) { michael@0: var previous; michael@0: var embededUseCMap; michael@0: objLoop: while (true) { michael@0: var obj = lexer.getObj(); michael@0: if (isEOF(obj)) { michael@0: break; michael@0: } else if (isName(obj)) { michael@0: if (obj.name === 'WMode') { michael@0: parseWMode(cMap, lexer); michael@0: } michael@0: previous = obj; michael@0: } else if (isCmd(obj)) { michael@0: switch (obj.cmd) { michael@0: case 'endcmap': michael@0: break objLoop; michael@0: case 'usecmap': michael@0: if (isName(previous)) { michael@0: embededUseCMap = previous.name; michael@0: } michael@0: break; michael@0: case 'begincodespacerange': michael@0: parseCodespaceRange(cMap, lexer); michael@0: break; michael@0: case 'beginbfchar': michael@0: parseBfChar(cMap, lexer); michael@0: break; michael@0: case 'begincidchar': michael@0: parseCidChar(cMap, lexer); michael@0: break; michael@0: case 'beginbfrange': michael@0: parseBfRange(cMap, lexer); michael@0: break; michael@0: case 'begincidrange': michael@0: parseCidRange(cMap, lexer); michael@0: break; michael@0: } michael@0: } michael@0: } michael@0: michael@0: if (!useCMap && embededUseCMap) { michael@0: // Load the usecmap definition from the file only if there wasn't one michael@0: // specified. michael@0: useCMap = embededUseCMap; michael@0: } michael@0: if (useCMap) { michael@0: extendCMap(cMap, builtInCMapParams, useCMap); michael@0: } michael@0: } michael@0: michael@0: function extendCMap(cMap, builtInCMapParams, useCMap) { michael@0: cMap.useCMap = createBuiltInCMap(useCMap, builtInCMapParams); michael@0: // If there aren't any code space ranges defined clone all the parent ones michael@0: // into this cMap. michael@0: if (cMap.numCodespaceRanges === 0) { michael@0: var useCodespaceRanges = cMap.useCMap.codespaceRanges; michael@0: for (var i = 0; i < useCodespaceRanges.length; i++) { michael@0: cMap.codespaceRanges[i] = useCodespaceRanges[i].slice(); michael@0: } michael@0: cMap.numCodespaceRanges = cMap.useCMap.numCodespaceRanges; michael@0: } michael@0: // Merge the map into the current one, making sure not to override michael@0: // any previously defined entries. michael@0: for (var key in cMap.useCMap.map) { michael@0: if (key in cMap.map) { michael@0: continue; michael@0: } michael@0: cMap.map[key] = cMap.useCMap.map[key]; michael@0: } michael@0: } michael@0: michael@0: function parseBinaryCMap(name, builtInCMapParams) { michael@0: var url = builtInCMapParams.url + name + '.bcmap'; michael@0: var cMap = new CMap(true); michael@0: new BinaryCMapReader().read(url, cMap, function (useCMap) { michael@0: extendCMap(cMap, builtInCMapParams, useCMap); michael@0: }); michael@0: return cMap; michael@0: } michael@0: michael@0: function createBuiltInCMap(name, builtInCMapParams) { michael@0: if (name === 'Identity-H') { michael@0: return new IdentityCMap(false, 2); michael@0: } else if (name === 'Identity-V') { michael@0: return new IdentityCMap(true, 2); michael@0: } michael@0: if (BUILT_IN_CMAPS.indexOf(name) === -1) { michael@0: error('Unknown cMap name: ' + name); michael@0: } michael@0: assert (builtInCMapParams, 'buildin cmap parameters are not provided'); michael@0: michael@0: if (builtInCMapParams.packed) { michael@0: return parseBinaryCMap(name, builtInCMapParams); michael@0: } michael@0: michael@0: var request = new XMLHttpRequest(); michael@0: var url = builtInCMapParams.url + name; michael@0: request.open('GET', url, false); michael@0: request.send(null); michael@0: if (request.status === 0 && /^https?:/i.test(url)) { michael@0: error('Unable to get cMap at: ' + url); michael@0: } michael@0: var cMap = new CMap(true); michael@0: var lexer = new Lexer(new StringStream(request.responseText)); michael@0: parseCMap(cMap, lexer, builtInCMapParams, null); michael@0: return cMap; michael@0: } michael@0: michael@0: return { michael@0: create: function (encoding, builtInCMapParams, useCMap) { michael@0: if (isName(encoding)) { michael@0: return createBuiltInCMap(encoding.name, builtInCMapParams); michael@0: } else if (isStream(encoding)) { michael@0: var cMap = new CMap(); michael@0: var lexer = new Lexer(encoding); michael@0: try { michael@0: parseCMap(cMap, lexer, builtInCMapParams, useCMap); michael@0: } catch (e) { michael@0: warn('Invalid CMap data. ' + e); michael@0: } michael@0: return cMap; michael@0: } michael@0: error('Encoding required.'); michael@0: } michael@0: }; michael@0: })(); michael@0: michael@0: michael@0: // Unicode Private Use Area michael@0: var PRIVATE_USE_OFFSET_START = 0xE000; michael@0: var PRIVATE_USE_OFFSET_END = 0xF8FF; michael@0: var SKIP_PRIVATE_USE_RANGE_F000_TO_F01F = false; michael@0: michael@0: // PDF Glyph Space Units are one Thousandth of a TextSpace Unit michael@0: // except for Type 3 fonts michael@0: var PDF_GLYPH_SPACE_UNITS = 1000; michael@0: michael@0: // Hinting is currently disabled due to unknown problems on windows michael@0: // in tracemonkey and various other pdfs with type1 fonts. michael@0: var HINTING_ENABLED = false; michael@0: michael@0: // Accented charactars are not displayed properly on windows, using this flag michael@0: // to control analysis of seac charstrings. michael@0: var SEAC_ANALYSIS_ENABLED = false; michael@0: michael@0: var FontFlags = { michael@0: FixedPitch: 1, michael@0: Serif: 2, michael@0: Symbolic: 4, michael@0: Script: 8, michael@0: Nonsymbolic: 32, michael@0: Italic: 64, michael@0: AllCap: 65536, michael@0: SmallCap: 131072, michael@0: ForceBold: 262144 michael@0: }; michael@0: michael@0: var Encodings = { michael@0: ExpertEncoding: ['', '', '', '', '', '', '', '', '', '', '', '', '', '', '', michael@0: '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', michael@0: 'space', 'exclamsmall', 'Hungarumlautsmall', '', 'dollaroldstyle', michael@0: 'dollarsuperior', 'ampersandsmall', 'Acutesmall', 'parenleftsuperior', michael@0: 'parenrightsuperior', 'twodotenleader', 'onedotenleader', 'comma', michael@0: 'hyphen', 'period', 'fraction', 'zerooldstyle', 'oneoldstyle', michael@0: 'twooldstyle', 'threeoldstyle', 'fouroldstyle', 'fiveoldstyle', michael@0: 'sixoldstyle', 'sevenoldstyle', 'eightoldstyle', 'nineoldstyle', 'colon', michael@0: 'semicolon', 'commasuperior', 'threequartersemdash', 'periodsuperior', michael@0: 'questionsmall', '', 'asuperior', 'bsuperior', 'centsuperior', 'dsuperior', michael@0: 'esuperior', '', '', 'isuperior', '', '', 'lsuperior', 'msuperior', michael@0: 'nsuperior', 'osuperior', '', '', 'rsuperior', 'ssuperior', 'tsuperior', michael@0: '', 'ff', 'fi', 'fl', 'ffi', 'ffl', 'parenleftinferior', '', michael@0: 'parenrightinferior', 'Circumflexsmall', 'hyphensuperior', 'Gravesmall', michael@0: 'Asmall', 'Bsmall', 'Csmall', 'Dsmall', 'Esmall', 'Fsmall', 'Gsmall', michael@0: 'Hsmall', 'Ismall', 'Jsmall', 'Ksmall', 'Lsmall', 'Msmall', 'Nsmall', michael@0: 'Osmall', 'Psmall', 'Qsmall', 'Rsmall', 'Ssmall', 'Tsmall', 'Usmall', michael@0: 'Vsmall', 'Wsmall', 'Xsmall', 'Ysmall', 'Zsmall', 'colonmonetary', michael@0: 'onefitted', 'rupiah', 'Tildesmall', '', '', '', '', '', '', '', '', '', michael@0: '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', michael@0: '', '', '', '', '', '', 'exclamdownsmall', 'centoldstyle', 'Lslashsmall', michael@0: '', '', 'Scaronsmall', 'Zcaronsmall', 'Dieresissmall', 'Brevesmall', michael@0: 'Caronsmall', '', 'Dotaccentsmall', '', '', 'Macronsmall', '', '', michael@0: 'figuredash', 'hypheninferior', '', '', 'Ogoneksmall', 'Ringsmall', michael@0: 'Cedillasmall', '', '', '', 'onequarter', 'onehalf', 'threequarters', michael@0: 'questiondownsmall', 'oneeighth', 'threeeighths', 'fiveeighths', michael@0: 'seveneighths', 'onethird', 'twothirds', '', '', 'zerosuperior', michael@0: 'onesuperior', 'twosuperior', 'threesuperior', 'foursuperior', michael@0: 'fivesuperior', 'sixsuperior', 'sevensuperior', 'eightsuperior', michael@0: 'ninesuperior', 'zeroinferior', 'oneinferior', 'twoinferior', michael@0: 'threeinferior', 'fourinferior', 'fiveinferior', 'sixinferior', michael@0: 'seveninferior', 'eightinferior', 'nineinferior', 'centinferior', michael@0: 'dollarinferior', 'periodinferior', 'commainferior', 'Agravesmall', michael@0: 'Aacutesmall', 'Acircumflexsmall', 'Atildesmall', 'Adieresissmall', michael@0: 'Aringsmall', 'AEsmall', 'Ccedillasmall', 'Egravesmall', 'Eacutesmall', michael@0: 'Ecircumflexsmall', 'Edieresissmall', 'Igravesmall', 'Iacutesmall', michael@0: 'Icircumflexsmall', 'Idieresissmall', 'Ethsmall', 'Ntildesmall', michael@0: 'Ogravesmall', 'Oacutesmall', 'Ocircumflexsmall', 'Otildesmall', michael@0: 'Odieresissmall', 'OEsmall', 'Oslashsmall', 'Ugravesmall', 'Uacutesmall', michael@0: 'Ucircumflexsmall', 'Udieresissmall', 'Yacutesmall', 'Thornsmall', michael@0: 'Ydieresissmall'], michael@0: MacExpertEncoding: ['', '', '', '', '', '', '', '', '', '', '', '', '', '', michael@0: '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', michael@0: 'space', 'exclamsmall', 'Hungarumlautsmall', 'centoldstyle', michael@0: 'dollaroldstyle', 'dollarsuperior', 'ampersandsmall', 'Acutesmall', michael@0: 'parenleftsuperior', 'parenrightsuperior', 'twodotenleader', michael@0: 'onedotenleader', 'comma', 'hyphen', 'period', 'fraction', 'zerooldstyle', michael@0: 'oneoldstyle', 'twooldstyle', 'threeoldstyle', 'fouroldstyle', michael@0: 'fiveoldstyle', 'sixoldstyle', 'sevenoldstyle', 'eightoldstyle', michael@0: 'nineoldstyle', 'colon', 'semicolon', '', 'threequartersemdash', '', michael@0: 'questionsmall', '', '', '', '', 'Ethsmall', '', '', 'onequarter', michael@0: 'onehalf', 'threequarters', 'oneeighth', 'threeeighths', 'fiveeighths', michael@0: 'seveneighths', 'onethird', 'twothirds', '', '', '', '', '', '', 'ff', michael@0: 'fi', 'fl', 'ffi', 'ffl', 'parenleftinferior', '', 'parenrightinferior', michael@0: 'Circumflexsmall', 'hypheninferior', 'Gravesmall', 'Asmall', 'Bsmall', michael@0: 'Csmall', 'Dsmall', 'Esmall', 'Fsmall', 'Gsmall', 'Hsmall', 'Ismall', michael@0: 'Jsmall', 'Ksmall', 'Lsmall', 'Msmall', 'Nsmall', 'Osmall', 'Psmall', michael@0: 'Qsmall', 'Rsmall', 'Ssmall', 'Tsmall', 'Usmall', 'Vsmall', 'Wsmall', michael@0: 'Xsmall', 'Ysmall', 'Zsmall', 'colonmonetary', 'onefitted', 'rupiah', michael@0: 'Tildesmall', '', '', 'asuperior', 'centsuperior', '', '', '', '', michael@0: 'Aacutesmall', 'Agravesmall', 'Acircumflexsmall', 'Adieresissmall', michael@0: 'Atildesmall', 'Aringsmall', 'Ccedillasmall', 'Eacutesmall', 'Egravesmall', michael@0: 'Ecircumflexsmall', 'Edieresissmall', 'Iacutesmall', 'Igravesmall', michael@0: 'Icircumflexsmall', 'Idieresissmall', 'Ntildesmall', 'Oacutesmall', michael@0: 'Ogravesmall', 'Ocircumflexsmall', 'Odieresissmall', 'Otildesmall', michael@0: 'Uacutesmall', 'Ugravesmall', 'Ucircumflexsmall', 'Udieresissmall', '', michael@0: 'eightsuperior', 'fourinferior', 'threeinferior', 'sixinferior', michael@0: 'eightinferior', 'seveninferior', 'Scaronsmall', '', 'centinferior', michael@0: 'twoinferior', '', 'Dieresissmall', '', 'Caronsmall', 'osuperior', michael@0: 'fiveinferior', '', 'commainferior', 'periodinferior', 'Yacutesmall', '', michael@0: 'dollarinferior', '', 'Thornsmall', '', 'nineinferior', 'zeroinferior', michael@0: 'Zcaronsmall', 'AEsmall', 'Oslashsmall', 'questiondownsmall', michael@0: 'oneinferior', 'Lslashsmall', '', '', '', '', '', '', 'Cedillasmall', '', michael@0: '', '', '', '', 'OEsmall', 'figuredash', 'hyphensuperior', '', '', '', '', michael@0: 'exclamdownsmall', '', 'Ydieresissmall', '', 'onesuperior', 'twosuperior', michael@0: 'threesuperior', 'foursuperior', 'fivesuperior', 'sixsuperior', michael@0: 'sevensuperior', 'ninesuperior', 'zerosuperior', '', 'esuperior', michael@0: 'rsuperior', 'tsuperior', '', '', 'isuperior', 'ssuperior', 'dsuperior', michael@0: '', '', '', '', '', 'lsuperior', 'Ogoneksmall', 'Brevesmall', michael@0: 'Macronsmall', 'bsuperior', 'nsuperior', 'msuperior', 'commasuperior', michael@0: 'periodsuperior', 'Dotaccentsmall', 'Ringsmall'], michael@0: MacRomanEncoding: ['', '', '', '', '', '', '', '', '', '', '', '', '', '', '', michael@0: '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', michael@0: 'space', 'exclam', 'quotedbl', 'numbersign', 'dollar', 'percent', michael@0: 'ampersand', 'quotesingle', 'parenleft', 'parenright', 'asterisk', 'plus', michael@0: 'comma', 'hyphen', 'period', 'slash', 'zero', 'one', 'two', 'three', michael@0: 'four', 'five', 'six', 'seven', 'eight', 'nine', 'colon', 'semicolon', michael@0: 'less', 'equal', 'greater', 'question', 'at', 'A', 'B', 'C', 'D', 'E', 'F', michael@0: 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', michael@0: 'V', 'W', 'X', 'Y', 'Z', 'bracketleft', 'backslash', 'bracketright', michael@0: 'asciicircum', 'underscore', 'grave', 'a', 'b', 'c', 'd', 'e', 'f', 'g', michael@0: 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', michael@0: 'w', 'x', 'y', 'z', 'braceleft', 'bar', 'braceright', 'asciitilde', '', michael@0: 'Adieresis', 'Aring', 'Ccedilla', 'Eacute', 'Ntilde', 'Odieresis', michael@0: 'Udieresis', 'aacute', 'agrave', 'acircumflex', 'adieresis', 'atilde', michael@0: 'aring', 'ccedilla', 'eacute', 'egrave', 'ecircumflex', 'edieresis', michael@0: 'iacute', 'igrave', 'icircumflex', 'idieresis', 'ntilde', 'oacute', michael@0: 'ograve', 'ocircumflex', 'odieresis', 'otilde', 'uacute', 'ugrave', michael@0: 'ucircumflex', 'udieresis', 'dagger', 'degree', 'cent', 'sterling', michael@0: 'section', 'bullet', 'paragraph', 'germandbls', 'registered', 'copyright', michael@0: 'trademark', 'acute', 'dieresis', 'notequal', 'AE', 'Oslash', 'infinity', michael@0: 'plusminus', 'lessequal', 'greaterequal', 'yen', 'mu', 'partialdiff', michael@0: 'summation', 'product', 'pi', 'integral', 'ordfeminine', 'ordmasculine', michael@0: 'Omega', 'ae', 'oslash', 'questiondown', 'exclamdown', 'logicalnot', michael@0: 'radical', 'florin', 'approxequal', 'Delta', 'guillemotleft', michael@0: 'guillemotright', 'ellipsis', 'space', 'Agrave', 'Atilde', 'Otilde', 'OE', michael@0: 'oe', 'endash', 'emdash', 'quotedblleft', 'quotedblright', 'quoteleft', michael@0: 'quoteright', 'divide', 'lozenge', 'ydieresis', 'Ydieresis', 'fraction', michael@0: 'currency', 'guilsinglleft', 'guilsinglright', 'fi', 'fl', 'daggerdbl', michael@0: 'periodcentered', 'quotesinglbase', 'quotedblbase', 'perthousand', michael@0: 'Acircumflex', 'Ecircumflex', 'Aacute', 'Edieresis', 'Egrave', 'Iacute', michael@0: 'Icircumflex', 'Idieresis', 'Igrave', 'Oacute', 'Ocircumflex', 'apple', michael@0: 'Ograve', 'Uacute', 'Ucircumflex', 'Ugrave', 'dotlessi', 'circumflex', michael@0: 'tilde', 'macron', 'breve', 'dotaccent', 'ring', 'cedilla', 'hungarumlaut', michael@0: 'ogonek', 'caron'], michael@0: StandardEncoding: ['', '', '', '', '', '', '', '', '', '', '', '', '', '', '', michael@0: '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', michael@0: 'space', 'exclam', 'quotedbl', 'numbersign', 'dollar', 'percent', michael@0: 'ampersand', 'quoteright', 'parenleft', 'parenright', 'asterisk', 'plus', michael@0: 'comma', 'hyphen', 'period', 'slash', 'zero', 'one', 'two', 'three', michael@0: 'four', 'five', 'six', 'seven', 'eight', 'nine', 'colon', 'semicolon', michael@0: 'less', 'equal', 'greater', 'question', 'at', 'A', 'B', 'C', 'D', 'E', 'F', michael@0: 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', michael@0: 'V', 'W', 'X', 'Y', 'Z', 'bracketleft', 'backslash', 'bracketright', michael@0: 'asciicircum', 'underscore', 'quoteleft', 'a', 'b', 'c', 'd', 'e', 'f', michael@0: 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', michael@0: 'v', 'w', 'x', 'y', 'z', 'braceleft', 'bar', 'braceright', 'asciitilde', michael@0: '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', michael@0: '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', 'exclamdown', michael@0: 'cent', 'sterling', 'fraction', 'yen', 'florin', 'section', 'currency', michael@0: 'quotesingle', 'quotedblleft', 'guillemotleft', 'guilsinglleft', michael@0: 'guilsinglright', 'fi', 'fl', '', 'endash', 'dagger', 'daggerdbl', michael@0: 'periodcentered', '', 'paragraph', 'bullet', 'quotesinglbase', michael@0: 'quotedblbase', 'quotedblright', 'guillemotright', 'ellipsis', michael@0: 'perthousand', '', 'questiondown', '', 'grave', 'acute', 'circumflex', michael@0: 'tilde', 'macron', 'breve', 'dotaccent', 'dieresis', '', 'ring', 'cedilla', michael@0: '', 'hungarumlaut', 'ogonek', 'caron', 'emdash', '', '', '', '', '', '', michael@0: '', '', '', '', '', '', '', '', '', '', 'AE', '', 'ordfeminine', '', '', michael@0: '', '', 'Lslash', 'Oslash', 'OE', 'ordmasculine', '', '', '', '', '', 'ae', michael@0: '', '', '', 'dotlessi', '', '', 'lslash', 'oslash', 'oe', 'germandbls'], michael@0: WinAnsiEncoding: ['', '', '', '', '', '', '', '', '', '', '', '', '', '', '', michael@0: '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', michael@0: 'space', 'exclam', 'quotedbl', 'numbersign', 'dollar', 'percent', michael@0: 'ampersand', 'quotesingle', 'parenleft', 'parenright', 'asterisk', 'plus', michael@0: 'comma', 'hyphen', 'period', 'slash', 'zero', 'one', 'two', 'three', michael@0: 'four', 'five', 'six', 'seven', 'eight', 'nine', 'colon', 'semicolon', michael@0: 'less', 'equal', 'greater', 'question', 'at', 'A', 'B', 'C', 'D', 'E', 'F', michael@0: 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', michael@0: 'V', 'W', 'X', 'Y', 'Z', 'bracketleft', 'backslash', 'bracketright', michael@0: 'asciicircum', 'underscore', 'grave', 'a', 'b', 'c', 'd', 'e', 'f', 'g', michael@0: 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', michael@0: 'w', 'x', 'y', 'z', 'braceleft', 'bar', 'braceright', 'asciitilde', michael@0: 'bullet', 'Euro', 'bullet', 'quotesinglbase', 'florin', 'quotedblbase', michael@0: 'ellipsis', 'dagger', 'daggerdbl', 'circumflex', 'perthousand', 'Scaron', michael@0: 'guilsinglleft', 'OE', 'bullet', 'Zcaron', 'bullet', 'bullet', 'quoteleft', michael@0: 'quoteright', 'quotedblleft', 'quotedblright', 'bullet', 'endash', michael@0: 'emdash', 'tilde', 'trademark', 'scaron', 'guilsinglright', 'oe', 'bullet', michael@0: 'zcaron', 'Ydieresis', 'space', 'exclamdown', 'cent', 'sterling', michael@0: 'currency', 'yen', 'brokenbar', 'section', 'dieresis', 'copyright', michael@0: 'ordfeminine', 'guillemotleft', 'logicalnot', 'hyphen', 'registered', michael@0: 'macron', 'degree', 'plusminus', 'twosuperior', 'threesuperior', 'acute', michael@0: 'mu', 'paragraph', 'periodcentered', 'cedilla', 'onesuperior', michael@0: 'ordmasculine', 'guillemotright', 'onequarter', 'onehalf', 'threequarters', michael@0: 'questiondown', 'Agrave', 'Aacute', 'Acircumflex', 'Atilde', 'Adieresis', michael@0: 'Aring', 'AE', 'Ccedilla', 'Egrave', 'Eacute', 'Ecircumflex', 'Edieresis', michael@0: 'Igrave', 'Iacute', 'Icircumflex', 'Idieresis', 'Eth', 'Ntilde', 'Ograve', michael@0: 'Oacute', 'Ocircumflex', 'Otilde', 'Odieresis', 'multiply', 'Oslash', michael@0: 'Ugrave', 'Uacute', 'Ucircumflex', 'Udieresis', 'Yacute', 'Thorn', michael@0: 'germandbls', 'agrave', 'aacute', 'acircumflex', 'atilde', 'adieresis', michael@0: 'aring', 'ae', 'ccedilla', 'egrave', 'eacute', 'ecircumflex', 'edieresis', michael@0: 'igrave', 'iacute', 'icircumflex', 'idieresis', 'eth', 'ntilde', 'ograve', michael@0: 'oacute', 'ocircumflex', 'otilde', 'odieresis', 'divide', 'oslash', michael@0: 'ugrave', 'uacute', 'ucircumflex', 'udieresis', 'yacute', 'thorn', michael@0: 'ydieresis'], michael@0: SymbolSetEncoding: ['', '', '', '', '', '', '', '', '', '', '', '', '', '', michael@0: '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', michael@0: 'space', 'exclam', 'universal', 'numbersign', 'existential', 'percent', michael@0: 'ampersand', 'suchthat', 'parenleft', 'parenright', 'asteriskmath', 'plus', michael@0: 'comma', 'minus', 'period', 'slash', 'zero', 'one', 'two', 'three', 'four', michael@0: 'five', 'six', 'seven', 'eight', 'nine', 'colon', 'semicolon', 'less', michael@0: 'equal', 'greater', 'question', 'congruent', 'Alpha', 'Beta', 'Chi', michael@0: 'Delta', 'Epsilon', 'Phi', 'Gamma', 'Eta', 'Iota', 'theta1', 'Kappa', michael@0: 'Lambda', 'Mu', 'Nu', 'Omicron', 'Pi', 'Theta', 'Rho', 'Sigma', 'Tau', michael@0: 'Upsilon', 'sigma1', 'Omega', 'Xi', 'Psi', 'Zeta', 'bracketleft', michael@0: 'therefore', 'bracketright', 'perpendicular', 'underscore', 'radicalex', michael@0: 'alpha', 'beta', 'chi', 'delta', 'epsilon', 'phi', 'gamma', 'eta', 'iota', michael@0: 'phi1', 'kappa', 'lambda', 'mu', 'nu', 'omicron', 'pi', 'theta', 'rho', michael@0: 'sigma', 'tau', 'upsilon', 'omega1', 'omega', 'xi', 'psi', 'zeta', michael@0: 'braceleft', 'bar', 'braceright', 'similar', '', '', '', '', '', '', '', michael@0: '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', michael@0: '', '', '', '', '', '', '', 'Euro', 'Upsilon1', 'minute', 'lessequal', michael@0: 'fraction', 'infinity', 'florin', 'club', 'diamond', 'heart', 'spade', michael@0: 'arrowboth', 'arrowleft', 'arrowup', 'arrowright', 'arrowdown', 'degree', michael@0: 'plusminus', 'second', 'greaterequal', 'multiply', 'proportional', michael@0: 'partialdiff', 'bullet', 'divide', 'notequal', 'equivalence', michael@0: 'approxequal', 'ellipsis', 'arrowvertex', 'arrowhorizex', 'carriagereturn', michael@0: 'aleph', 'Ifraktur', 'Rfraktur', 'weierstrass', 'circlemultiply', michael@0: 'circleplus', 'emptyset', 'intersection', 'union', 'propersuperset', michael@0: 'reflexsuperset', 'notsubset', 'propersubset', 'reflexsubset', 'element', michael@0: 'notelement', 'angle', 'gradient', 'registerserif', 'copyrightserif', michael@0: 'trademarkserif', 'product', 'radical', 'dotmath', 'logicalnot', michael@0: 'logicaland', 'logicalor', 'arrowdblboth', 'arrowdblleft', 'arrowdblup', michael@0: 'arrowdblright', 'arrowdbldown', 'lozenge', 'angleleft', 'registersans', michael@0: 'copyrightsans', 'trademarksans', 'summation', 'parenlefttp', michael@0: 'parenleftex', 'parenleftbt', 'bracketlefttp', 'bracketleftex', michael@0: 'bracketleftbt', 'bracelefttp', 'braceleftmid', 'braceleftbt', 'braceex', michael@0: '', 'angleright', 'integral', 'integraltp', 'integralex', 'integralbt', michael@0: 'parenrighttp', 'parenrightex', 'parenrightbt', 'bracketrighttp', michael@0: 'bracketrightex', 'bracketrightbt', 'bracerighttp', 'bracerightmid', michael@0: 'bracerightbt'], michael@0: zapfDingbatsEncoding: ['', '', '', '', '', '', '', '', '', '', '', '', '', '', michael@0: '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', michael@0: 'space', 'a1', 'a2', 'a202', 'a3', 'a4', 'a5', 'a119', 'a118', 'a117', michael@0: 'a11', 'a12', 'a13', 'a14', 'a15', 'a16', 'a105', 'a17', 'a18', 'a19', michael@0: 'a20', 'a21', 'a22', 'a23', 'a24', 'a25', 'a26', 'a27', 'a28', 'a6', 'a7', michael@0: 'a8', 'a9', 'a10', 'a29', 'a30', 'a31', 'a32', 'a33', 'a34', 'a35', 'a36', michael@0: 'a37', 'a38', 'a39', 'a40', 'a41', 'a42', 'a43', 'a44', 'a45', 'a46', michael@0: 'a47', 'a48', 'a49', 'a50', 'a51', 'a52', 'a53', 'a54', 'a55', 'a56', michael@0: 'a57', 'a58', 'a59', 'a60', 'a61', 'a62', 'a63', 'a64', 'a65', 'a66', michael@0: 'a67', 'a68', 'a69', 'a70', 'a71', 'a72', 'a73', 'a74', 'a203', 'a75', michael@0: 'a204', 'a76', 'a77', 'a78', 'a79', 'a81', 'a82', 'a83', 'a84', 'a97', michael@0: 'a98', 'a99', 'a100', '', '', '', '', '', '', '', '', '', '', '', '', '', michael@0: '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', michael@0: '', '', 'a101', 'a102', 'a103', 'a104', 'a106', 'a107', 'a108', 'a112', michael@0: 'a111', 'a110', 'a109', 'a120', 'a121', 'a122', 'a123', 'a124', 'a125', michael@0: 'a126', 'a127', 'a128', 'a129', 'a130', 'a131', 'a132', 'a133', 'a134', michael@0: 'a135', 'a136', 'a137', 'a138', 'a139', 'a140', 'a141', 'a142', 'a143', michael@0: 'a144', 'a145', 'a146', 'a147', 'a148', 'a149', 'a150', 'a151', 'a152', michael@0: 'a153', 'a154', 'a155', 'a156', 'a157', 'a158', 'a159', 'a160', 'a161', michael@0: 'a163', 'a164', 'a196', 'a165', 'a192', 'a166', 'a167', 'a168', 'a169', michael@0: 'a170', 'a171', 'a172', 'a173', 'a162', 'a174', 'a175', 'a176', 'a177', michael@0: 'a178', 'a179', 'a193', 'a180', 'a199', 'a181', 'a200', 'a182', '', 'a201', michael@0: 'a183', 'a184', 'a197', 'a185', 'a194', 'a198', 'a186', 'a195', 'a187', michael@0: 'a188', 'a189', 'a190', 'a191'] michael@0: }; michael@0: michael@0: /** michael@0: * Hold a map of decoded fonts and of the standard fourteen Type1 michael@0: * fonts and their acronyms. michael@0: */ michael@0: var stdFontMap = { michael@0: 'ArialNarrow': 'Helvetica', michael@0: 'ArialNarrow-Bold': 'Helvetica-Bold', michael@0: 'ArialNarrow-BoldItalic': 'Helvetica-BoldOblique', michael@0: 'ArialNarrow-Italic': 'Helvetica-Oblique', michael@0: 'ArialBlack': 'Helvetica', michael@0: 'ArialBlack-Bold': 'Helvetica-Bold', michael@0: 'ArialBlack-BoldItalic': 'Helvetica-BoldOblique', michael@0: 'ArialBlack-Italic': 'Helvetica-Oblique', michael@0: 'Arial': 'Helvetica', michael@0: 'Arial-Bold': 'Helvetica-Bold', michael@0: 'Arial-BoldItalic': 'Helvetica-BoldOblique', michael@0: 'Arial-Italic': 'Helvetica-Oblique', michael@0: 'Arial-BoldItalicMT': 'Helvetica-BoldOblique', michael@0: 'Arial-BoldMT': 'Helvetica-Bold', michael@0: 'Arial-ItalicMT': 'Helvetica-Oblique', michael@0: 'ArialMT': 'Helvetica', michael@0: 'Courier-Bold': 'Courier-Bold', michael@0: 'Courier-BoldItalic': 'Courier-BoldOblique', michael@0: 'Courier-Italic': 'Courier-Oblique', michael@0: 'CourierNew': 'Courier', michael@0: 'CourierNew-Bold': 'Courier-Bold', michael@0: 'CourierNew-BoldItalic': 'Courier-BoldOblique', michael@0: 'CourierNew-Italic': 'Courier-Oblique', michael@0: 'CourierNewPS-BoldItalicMT': 'Courier-BoldOblique', michael@0: 'CourierNewPS-BoldMT': 'Courier-Bold', michael@0: 'CourierNewPS-ItalicMT': 'Courier-Oblique', michael@0: 'CourierNewPSMT': 'Courier', michael@0: 'Helvetica-Bold': 'Helvetica-Bold', michael@0: 'Helvetica-BoldItalic': 'Helvetica-BoldOblique', michael@0: 'Helvetica-Italic': 'Helvetica-Oblique', michael@0: 'Symbol-Bold': 'Symbol', michael@0: 'Symbol-BoldItalic': 'Symbol', michael@0: 'Symbol-Italic': 'Symbol', michael@0: 'TimesNewRoman': 'Times-Roman', michael@0: 'TimesNewRoman-Bold': 'Times-Bold', michael@0: 'TimesNewRoman-BoldItalic': 'Times-BoldItalic', michael@0: 'TimesNewRoman-Italic': 'Times-Italic', michael@0: 'TimesNewRomanPS': 'Times-Roman', michael@0: 'TimesNewRomanPS-Bold': 'Times-Bold', michael@0: 'TimesNewRomanPS-BoldItalic': 'Times-BoldItalic', michael@0: 'TimesNewRomanPS-BoldItalicMT': 'Times-BoldItalic', michael@0: 'TimesNewRomanPS-BoldMT': 'Times-Bold', michael@0: 'TimesNewRomanPS-Italic': 'Times-Italic', michael@0: 'TimesNewRomanPS-ItalicMT': 'Times-Italic', michael@0: 'TimesNewRomanPSMT': 'Times-Roman', michael@0: 'TimesNewRomanPSMT-Bold': 'Times-Bold', michael@0: 'TimesNewRomanPSMT-BoldItalic': 'Times-BoldItalic', michael@0: 'TimesNewRomanPSMT-Italic': 'Times-Italic' michael@0: }; michael@0: michael@0: /** michael@0: * Holds the map of the non-standard fonts that might be included as a standard michael@0: * fonts without glyph data. michael@0: */ michael@0: var nonStdFontMap = { michael@0: 'ComicSansMS': 'Comic Sans MS', michael@0: 'ComicSansMS-Bold': 'Comic Sans MS-Bold', michael@0: 'ComicSansMS-BoldItalic': 'Comic Sans MS-BoldItalic', michael@0: 'ComicSansMS-Italic': 'Comic Sans MS-Italic', michael@0: 'LucidaConsole': 'Courier', michael@0: 'LucidaConsole-Bold': 'Courier-Bold', michael@0: 'LucidaConsole-BoldItalic': 'Courier-BoldOblique', michael@0: 'LucidaConsole-Italic': 'Courier-Oblique', michael@0: 'MS-Gothic': 'MS Gothic', michael@0: 'MS-Gothic-Bold': 'MS Gothic-Bold', michael@0: 'MS-Gothic-BoldItalic': 'MS Gothic-BoldItalic', michael@0: 'MS-Gothic-Italic': 'MS Gothic-Italic', michael@0: 'MS-Mincho': 'MS Mincho', michael@0: 'MS-Mincho-Bold': 'MS Mincho-Bold', michael@0: 'MS-Mincho-BoldItalic': 'MS Mincho-BoldItalic', michael@0: 'MS-Mincho-Italic': 'MS Mincho-Italic', michael@0: 'MS-PGothic': 'MS PGothic', michael@0: 'MS-PGothic-Bold': 'MS PGothic-Bold', michael@0: 'MS-PGothic-BoldItalic': 'MS PGothic-BoldItalic', michael@0: 'MS-PGothic-Italic': 'MS PGothic-Italic', michael@0: 'MS-PMincho': 'MS PMincho', michael@0: 'MS-PMincho-Bold': 'MS PMincho-Bold', michael@0: 'MS-PMincho-BoldItalic': 'MS PMincho-BoldItalic', michael@0: 'MS-PMincho-Italic': 'MS PMincho-Italic' michael@0: }; michael@0: michael@0: var serifFonts = { michael@0: 'Adobe Jenson': true, 'Adobe Text': true, 'Albertus': true, michael@0: 'Aldus': true, 'Alexandria': true, 'Algerian': true, michael@0: 'American Typewriter': true, 'Antiqua': true, 'Apex': true, michael@0: 'Arno': true, 'Aster': true, 'Aurora': true, michael@0: 'Baskerville': true, 'Bell': true, 'Bembo': true, michael@0: 'Bembo Schoolbook': true, 'Benguiat': true, 'Berkeley Old Style': true, michael@0: 'Bernhard Modern': true, 'Berthold City': true, 'Bodoni': true, michael@0: 'Bauer Bodoni': true, 'Book Antiqua': true, 'Bookman': true, michael@0: 'Bordeaux Roman': true, 'Californian FB': true, 'Calisto': true, michael@0: 'Calvert': true, 'Capitals': true, 'Cambria': true, michael@0: 'Cartier': true, 'Caslon': true, 'Catull': true, michael@0: 'Centaur': true, 'Century Old Style': true, 'Century Schoolbook': true, michael@0: 'Chaparral': true, 'Charis SIL': true, 'Cheltenham': true, michael@0: 'Cholla Slab': true, 'Clarendon': true, 'Clearface': true, michael@0: 'Cochin': true, 'Colonna': true, 'Computer Modern': true, michael@0: 'Concrete Roman': true, 'Constantia': true, 'Cooper Black': true, michael@0: 'Corona': true, 'Ecotype': true, 'Egyptienne': true, michael@0: 'Elephant': true, 'Excelsior': true, 'Fairfield': true, michael@0: 'FF Scala': true, 'Folkard': true, 'Footlight': true, michael@0: 'FreeSerif': true, 'Friz Quadrata': true, 'Garamond': true, michael@0: 'Gentium': true, 'Georgia': true, 'Gloucester': true, michael@0: 'Goudy Old Style': true, 'Goudy Schoolbook': true, 'Goudy Pro Font': true, michael@0: 'Granjon': true, 'Guardian Egyptian': true, 'Heather': true, michael@0: 'Hercules': true, 'High Tower Text': true, 'Hiroshige': true, michael@0: 'Hoefler Text': true, 'Humana Serif': true, 'Imprint': true, michael@0: 'Ionic No. 5': true, 'Janson': true, 'Joanna': true, michael@0: 'Korinna': true, 'Lexicon': true, 'Liberation Serif': true, michael@0: 'Linux Libertine': true, 'Literaturnaya': true, 'Lucida': true, michael@0: 'Lucida Bright': true, 'Melior': true, 'Memphis': true, michael@0: 'Miller': true, 'Minion': true, 'Modern': true, michael@0: 'Mona Lisa': true, 'Mrs Eaves': true, 'MS Serif': true, michael@0: 'Museo Slab': true, 'New York': true, 'Nimbus Roman': true, michael@0: 'NPS Rawlinson Roadway': true, 'Palatino': true, 'Perpetua': true, michael@0: 'Plantin': true, 'Plantin Schoolbook': true, 'Playbill': true, michael@0: 'Poor Richard': true, 'Rawlinson Roadway': true, 'Renault': true, michael@0: 'Requiem': true, 'Rockwell': true, 'Roman': true, michael@0: 'Rotis Serif': true, 'Sabon': true, 'Scala': true, michael@0: 'Seagull': true, 'Sistina': true, 'Souvenir': true, michael@0: 'STIX': true, 'Stone Informal': true, 'Stone Serif': true, michael@0: 'Sylfaen': true, 'Times': true, 'Trajan': true, michael@0: 'Trinité': true, 'Trump Mediaeval': true, 'Utopia': true, michael@0: 'Vale Type': true, 'Bitstream Vera': true, 'Vera Serif': true, michael@0: 'Versailles': true, 'Wanted': true, 'Weiss': true, michael@0: 'Wide Latin': true, 'Windsor': true, 'XITS': true michael@0: }; michael@0: michael@0: var symbolsFonts = { michael@0: 'Dingbats': true, 'Symbol': true, 'ZapfDingbats': true michael@0: }; michael@0: michael@0: // Glyph map for well-known standard fonts. Sometimes Ghostscript uses CID fonts michael@0: // but does not embed the CID to GID mapping. The mapping is incomplete for all michael@0: // glyphs, but common for some set of the standard fonts. michael@0: var GlyphMapForStandardFonts = { michael@0: '2': 10, '3': 32, '4': 33, '5': 34, '6': 35, '7': 36, '8': 37, '9': 38, michael@0: '10': 39, '11': 40, '12': 41, '13': 42, '14': 43, '15': 44, '16': 173, michael@0: '17': 46, '18': 47, '19': 48, '20': 49, '21': 50, '22': 51, '23': 52, michael@0: '24': 53, '25': 54, '26': 55, '27': 56, '28': 57, '29': 58, '30': 894, michael@0: '31': 60, '32': 61, '33': 62, '34': 63, '35': 64, '36': 65, '37': 66, michael@0: '38': 67, '39': 68, '40': 69, '41': 70, '42': 71, '43': 72, '44': 73, michael@0: '45': 74, '46': 75, '47': 76, '48': 77, '49': 78, '50': 79, '51': 80, michael@0: '52': 81, '53': 82, '54': 83, '55': 84, '56': 85, '57': 86, '58': 87, michael@0: '59': 88, '60': 89, '61': 90, '62': 91, '63': 92, '64': 93, '65': 94, michael@0: '66': 95, '67': 96, '68': 97, '69': 98, '70': 99, '71': 100, '72': 101, michael@0: '73': 102, '74': 103, '75': 104, '76': 105, '77': 106, '78': 107, '79': 108, michael@0: '80': 109, '81': 110, '82': 111, '83': 112, '84': 113, '85': 114, '86': 115, michael@0: '87': 116, '88': 117, '89': 118, '90': 119, '91': 120, '92': 121, '93': 122, michael@0: '94': 123, '95': 124, '96': 125, '97': 126, '98': 196, '99': 197, '100': 199, michael@0: '101': 201, '102': 209, '103': 214, '104': 220, '105': 225, '106': 224, michael@0: '107': 226, '108': 228, '109': 227, '110': 229, '111': 231, '112': 233, michael@0: '113': 232, '114': 234, '115': 235, '116': 237, '117': 236, '118': 238, michael@0: '119': 239, '120': 241, '121': 243, '122': 242, '123': 244, '124': 246, michael@0: '125': 245, '126': 250, '127': 249, '128': 251, '129': 252, '130': 8224, michael@0: '131': 176, '132': 162, '133': 163, '134': 167, '135': 8226, '136': 182, michael@0: '137': 223, '138': 174, '139': 169, '140': 8482, '141': 180, '142': 168, michael@0: '143': 8800, '144': 198, '145': 216, '146': 8734, '147': 177, '148': 8804, michael@0: '149': 8805, '150': 165, '151': 181, '152': 8706, '153': 8721, '154': 8719, michael@0: '156': 8747, '157': 170, '158': 186, '159': 8486, '160': 230, '161': 248, michael@0: '162': 191, '163': 161, '164': 172, '165': 8730, '166': 402, '167': 8776, michael@0: '168': 8710, '169': 171, '170': 187, '171': 8230, '210': 218, '305': 963, michael@0: '306': 964, '307': 966, '308': 8215, '309': 8252, '310': 8319, '311': 8359, michael@0: '312': 8592, '313': 8593, '337': 9552, '493': 1039, '494': 1040, '705': 1524, michael@0: '706': 8362, '710': 64288, '711': 64298, '759': 1617, '761': 1776, michael@0: '763': 1778, '775': 1652, '777': 1764, '778': 1780, '779': 1781, '780': 1782, michael@0: '782': 771, '783': 64726, '786': 8363, '788': 8532, '790': 768, '791': 769, michael@0: '792': 768, '795': 803, '797': 64336, '798': 64337, '799': 64342, michael@0: '800': 64343, '801': 64344, '802': 64345, '803': 64362, '804': 64363, michael@0: '805': 64364, '2424': 7821, '2425': 7822, '2426': 7823, '2427': 7824, michael@0: '2428': 7825, '2429': 7826, '2430': 7827, '2433': 7682, '2678': 8045, michael@0: '2679': 8046, '2830': 1552, '2838': 686, '2840': 751, '2842': 753, michael@0: '2843': 754, '2844': 755, '2846': 757, '2856': 767, '2857': 848, '2858': 849, michael@0: '2862': 853, '2863': 854, '2864': 855, '2865': 861, '2866': 862, '2906': 7460, michael@0: '2908': 7462, '2909': 7463, '2910': 7464, '2912': 7466, '2913': 7467, michael@0: '2914': 7468, '2916': 7470, '2917': 7471, '2918': 7472, '2920': 7474, michael@0: '2921': 7475, '2922': 7476, '2924': 7478, '2925': 7479, '2926': 7480, michael@0: '2928': 7482, '2929': 7483, '2930': 7484, '2932': 7486, '2933': 7487, michael@0: '2934': 7488, '2936': 7490, '2937': 7491, '2938': 7492, '2940': 7494, michael@0: '2941': 7495, '2942': 7496, '2944': 7498, '2946': 7500, '2948': 7502, michael@0: '2950': 7504, '2951': 7505, '2952': 7506, '2954': 7508, '2955': 7509, michael@0: '2956': 7510, '2958': 7512, '2959': 7513, '2960': 7514, '2962': 7516, michael@0: '2963': 7517, '2964': 7518, '2966': 7520, '2967': 7521, '2968': 7522, michael@0: '2970': 7524, '2971': 7525, '2972': 7526, '2974': 7528, '2975': 7529, michael@0: '2976': 7530, '2978': 1537, '2979': 1538, '2980': 1539, '2982': 1549, michael@0: '2983': 1551, '2984': 1552, '2986': 1554, '2987': 1555, '2988': 1556, michael@0: '2990': 1623, '2991': 1624, '2995': 1775, '2999': 1791, '3002': 64290, michael@0: '3003': 64291, '3004': 64292, '3006': 64294, '3007': 64295, '3008': 64296, michael@0: '3011': 1900, '3014': 8223, '3015': 8244, '3017': 7532, '3018': 7533, michael@0: '3019': 7534, '3075': 7590, '3076': 7591, '3079': 7594, '3080': 7595, michael@0: '3083': 7598, '3084': 7599, '3087': 7602, '3088': 7603, '3091': 7606, michael@0: '3092': 7607, '3095': 7610, '3096': 7611, '3099': 7614, '3100': 7615, michael@0: '3103': 7618, '3104': 7619, '3107': 8337, '3108': 8338, '3116': 1884, michael@0: '3119': 1885, '3120': 1885, '3123': 1886, '3124': 1886, '3127': 1887, michael@0: '3128': 1887, '3131': 1888, '3132': 1888, '3135': 1889, '3136': 1889, michael@0: '3139': 1890, '3140': 1890, '3143': 1891, '3144': 1891, '3147': 1892, michael@0: '3148': 1892, '3153': 580, '3154': 581, '3157': 584, '3158': 585, '3161': 588, michael@0: '3162': 589, '3165': 891, '3166': 892, '3169': 1274, '3170': 1275, michael@0: '3173': 1278, '3174': 1279, '3181': 7622, '3182': 7623, '3282': 11799, michael@0: '3316': 578, '3379': 42785, '3393': 1159, '3416': 8377 michael@0: }; michael@0: michael@0: // Some characters, e.g. copyrightserif, mapped to the private use area and michael@0: // might not be displayed using standard fonts. Mapping/hacking well-known chars michael@0: // to the similar equivalents in the normal characters range. michael@0: function mapSpecialUnicodeValues(code) { michael@0: if (code >= 0xFFF0 && code <= 0xFFFF) { // Specials unicode block. michael@0: return 0; michael@0: } michael@0: switch (code) { michael@0: case 0xF8E9: // copyrightsans michael@0: case 0xF6D9: // copyrightserif michael@0: return 0x00A9; // copyright michael@0: michael@0: case 0xF8E8: // registersans michael@0: case 0xF6DA: // registerserif michael@0: return 0x00AE; // registered michael@0: michael@0: case 0xF8EA: // trademarksans michael@0: case 0xF6DB: // trademarkserif michael@0: return 0x2122; // trademark michael@0: michael@0: default: michael@0: return code; michael@0: } michael@0: } michael@0: michael@0: var UnicodeRanges = [ michael@0: { 'begin': 0x0000, 'end': 0x007F }, // Basic Latin michael@0: { 'begin': 0x0080, 'end': 0x00FF }, // Latin-1 Supplement michael@0: { 'begin': 0x0100, 'end': 0x017F }, // Latin Extended-A michael@0: { 'begin': 0x0180, 'end': 0x024F }, // Latin Extended-B michael@0: { 'begin': 0x0250, 'end': 0x02AF }, // IPA Extensions michael@0: { 'begin': 0x02B0, 'end': 0x02FF }, // Spacing Modifier Letters michael@0: { 'begin': 0x0300, 'end': 0x036F }, // Combining Diacritical Marks michael@0: { 'begin': 0x0370, 'end': 0x03FF }, // Greek and Coptic michael@0: { 'begin': 0x2C80, 'end': 0x2CFF }, // Coptic michael@0: { 'begin': 0x0400, 'end': 0x04FF }, // Cyrillic michael@0: { 'begin': 0x0530, 'end': 0x058F }, // Armenian michael@0: { 'begin': 0x0590, 'end': 0x05FF }, // Hebrew michael@0: { 'begin': 0xA500, 'end': 0xA63F }, // Vai michael@0: { 'begin': 0x0600, 'end': 0x06FF }, // Arabic michael@0: { 'begin': 0x07C0, 'end': 0x07FF }, // NKo michael@0: { 'begin': 0x0900, 'end': 0x097F }, // Devanagari michael@0: { 'begin': 0x0980, 'end': 0x09FF }, // Bengali michael@0: { 'begin': 0x0A00, 'end': 0x0A7F }, // Gurmukhi michael@0: { 'begin': 0x0A80, 'end': 0x0AFF }, // Gujarati michael@0: { 'begin': 0x0B00, 'end': 0x0B7F }, // Oriya michael@0: { 'begin': 0x0B80, 'end': 0x0BFF }, // Tamil michael@0: { 'begin': 0x0C00, 'end': 0x0C7F }, // Telugu michael@0: { 'begin': 0x0C80, 'end': 0x0CFF }, // Kannada michael@0: { 'begin': 0x0D00, 'end': 0x0D7F }, // Malayalam michael@0: { 'begin': 0x0E00, 'end': 0x0E7F }, // Thai michael@0: { 'begin': 0x0E80, 'end': 0x0EFF }, // Lao michael@0: { 'begin': 0x10A0, 'end': 0x10FF }, // Georgian michael@0: { 'begin': 0x1B00, 'end': 0x1B7F }, // Balinese michael@0: { 'begin': 0x1100, 'end': 0x11FF }, // Hangul Jamo michael@0: { 'begin': 0x1E00, 'end': 0x1EFF }, // Latin Extended Additional michael@0: { 'begin': 0x1F00, 'end': 0x1FFF }, // Greek Extended michael@0: { 'begin': 0x2000, 'end': 0x206F }, // General Punctuation michael@0: { 'begin': 0x2070, 'end': 0x209F }, // Superscripts And Subscripts michael@0: { 'begin': 0x20A0, 'end': 0x20CF }, // Currency Symbol michael@0: { 'begin': 0x20D0, 'end': 0x20FF }, // Combining Diacritical Marks For Symbols michael@0: { 'begin': 0x2100, 'end': 0x214F }, // Letterlike Symbols michael@0: { 'begin': 0x2150, 'end': 0x218F }, // Number Forms michael@0: { 'begin': 0x2190, 'end': 0x21FF }, // Arrows michael@0: { 'begin': 0x2200, 'end': 0x22FF }, // Mathematical Operators michael@0: { 'begin': 0x2300, 'end': 0x23FF }, // Miscellaneous Technical michael@0: { 'begin': 0x2400, 'end': 0x243F }, // Control Pictures michael@0: { 'begin': 0x2440, 'end': 0x245F }, // Optical Character Recognition michael@0: { 'begin': 0x2460, 'end': 0x24FF }, // Enclosed Alphanumerics michael@0: { 'begin': 0x2500, 'end': 0x257F }, // Box Drawing michael@0: { 'begin': 0x2580, 'end': 0x259F }, // Block Elements michael@0: { 'begin': 0x25A0, 'end': 0x25FF }, // Geometric Shapes michael@0: { 'begin': 0x2600, 'end': 0x26FF }, // Miscellaneous Symbols michael@0: { 'begin': 0x2700, 'end': 0x27BF }, // Dingbats michael@0: { 'begin': 0x3000, 'end': 0x303F }, // CJK Symbols And Punctuation michael@0: { 'begin': 0x3040, 'end': 0x309F }, // Hiragana michael@0: { 'begin': 0x30A0, 'end': 0x30FF }, // Katakana michael@0: { 'begin': 0x3100, 'end': 0x312F }, // Bopomofo michael@0: { 'begin': 0x3130, 'end': 0x318F }, // Hangul Compatibility Jamo michael@0: { 'begin': 0xA840, 'end': 0xA87F }, // Phags-pa michael@0: { 'begin': 0x3200, 'end': 0x32FF }, // Enclosed CJK Letters And Months michael@0: { 'begin': 0x3300, 'end': 0x33FF }, // CJK Compatibility michael@0: { 'begin': 0xAC00, 'end': 0xD7AF }, // Hangul Syllables michael@0: { 'begin': 0xD800, 'end': 0xDFFF }, // Non-Plane 0 * michael@0: { 'begin': 0x10900, 'end': 0x1091F }, // Phoenicia michael@0: { 'begin': 0x4E00, 'end': 0x9FFF }, // CJK Unified Ideographs michael@0: { 'begin': 0xE000, 'end': 0xF8FF }, // Private Use Area (plane 0) michael@0: { 'begin': 0x31C0, 'end': 0x31EF }, // CJK Strokes michael@0: { 'begin': 0xFB00, 'end': 0xFB4F }, // Alphabetic Presentation Forms michael@0: { 'begin': 0xFB50, 'end': 0xFDFF }, // Arabic Presentation Forms-A michael@0: { 'begin': 0xFE20, 'end': 0xFE2F }, // Combining Half Marks michael@0: { 'begin': 0xFE10, 'end': 0xFE1F }, // Vertical Forms michael@0: { 'begin': 0xFE50, 'end': 0xFE6F }, // Small Form Variants michael@0: { 'begin': 0xFE70, 'end': 0xFEFF }, // Arabic Presentation Forms-B michael@0: { 'begin': 0xFF00, 'end': 0xFFEF }, // Halfwidth And Fullwidth Forms michael@0: { 'begin': 0xFFF0, 'end': 0xFFFF }, // Specials michael@0: { 'begin': 0x0F00, 'end': 0x0FFF }, // Tibetan michael@0: { 'begin': 0x0700, 'end': 0x074F }, // Syriac michael@0: { 'begin': 0x0780, 'end': 0x07BF }, // Thaana michael@0: { 'begin': 0x0D80, 'end': 0x0DFF }, // Sinhala michael@0: { 'begin': 0x1000, 'end': 0x109F }, // Myanmar michael@0: { 'begin': 0x1200, 'end': 0x137F }, // Ethiopic michael@0: { 'begin': 0x13A0, 'end': 0x13FF }, // Cherokee michael@0: { 'begin': 0x1400, 'end': 0x167F }, // Unified Canadian Aboriginal Syllabics michael@0: { 'begin': 0x1680, 'end': 0x169F }, // Ogham michael@0: { 'begin': 0x16A0, 'end': 0x16FF }, // Runic michael@0: { 'begin': 0x1780, 'end': 0x17FF }, // Khmer michael@0: { 'begin': 0x1800, 'end': 0x18AF }, // Mongolian michael@0: { 'begin': 0x2800, 'end': 0x28FF }, // Braille Patterns michael@0: { 'begin': 0xA000, 'end': 0xA48F }, // Yi Syllables michael@0: { 'begin': 0x1700, 'end': 0x171F }, // Tagalog michael@0: { 'begin': 0x10300, 'end': 0x1032F }, // Old Italic michael@0: { 'begin': 0x10330, 'end': 0x1034F }, // Gothic michael@0: { 'begin': 0x10400, 'end': 0x1044F }, // Deseret michael@0: { 'begin': 0x1D000, 'end': 0x1D0FF }, // Byzantine Musical Symbols michael@0: { 'begin': 0x1D400, 'end': 0x1D7FF }, // Mathematical Alphanumeric Symbols michael@0: { 'begin': 0xFF000, 'end': 0xFFFFD }, // Private Use (plane 15) michael@0: { 'begin': 0xFE00, 'end': 0xFE0F }, // Variation Selectors michael@0: { 'begin': 0xE0000, 'end': 0xE007F }, // Tags michael@0: { 'begin': 0x1900, 'end': 0x194F }, // Limbu michael@0: { 'begin': 0x1950, 'end': 0x197F }, // Tai Le michael@0: { 'begin': 0x1980, 'end': 0x19DF }, // New Tai Lue michael@0: { 'begin': 0x1A00, 'end': 0x1A1F }, // Buginese michael@0: { 'begin': 0x2C00, 'end': 0x2C5F }, // Glagolitic michael@0: { 'begin': 0x2D30, 'end': 0x2D7F }, // Tifinagh michael@0: { 'begin': 0x4DC0, 'end': 0x4DFF }, // Yijing Hexagram Symbols michael@0: { 'begin': 0xA800, 'end': 0xA82F }, // Syloti Nagri michael@0: { 'begin': 0x10000, 'end': 0x1007F }, // Linear B Syllabary michael@0: { 'begin': 0x10140, 'end': 0x1018F }, // Ancient Greek Numbers michael@0: { 'begin': 0x10380, 'end': 0x1039F }, // Ugaritic michael@0: { 'begin': 0x103A0, 'end': 0x103DF }, // Old Persian michael@0: { 'begin': 0x10450, 'end': 0x1047F }, // Shavian michael@0: { 'begin': 0x10480, 'end': 0x104AF }, // Osmanya michael@0: { 'begin': 0x10800, 'end': 0x1083F }, // Cypriot Syllabary michael@0: { 'begin': 0x10A00, 'end': 0x10A5F }, // Kharoshthi michael@0: { 'begin': 0x1D300, 'end': 0x1D35F }, // Tai Xuan Jing Symbols michael@0: { 'begin': 0x12000, 'end': 0x123FF }, // Cuneiform michael@0: { 'begin': 0x1D360, 'end': 0x1D37F }, // Counting Rod Numerals michael@0: { 'begin': 0x1B80, 'end': 0x1BBF }, // Sundanese michael@0: { 'begin': 0x1C00, 'end': 0x1C4F }, // Lepcha michael@0: { 'begin': 0x1C50, 'end': 0x1C7F }, // Ol Chiki michael@0: { 'begin': 0xA880, 'end': 0xA8DF }, // Saurashtra michael@0: { 'begin': 0xA900, 'end': 0xA92F }, // Kayah Li michael@0: { 'begin': 0xA930, 'end': 0xA95F }, // Rejang michael@0: { 'begin': 0xAA00, 'end': 0xAA5F }, // Cham michael@0: { 'begin': 0x10190, 'end': 0x101CF }, // Ancient Symbols michael@0: { 'begin': 0x101D0, 'end': 0x101FF }, // Phaistos Disc michael@0: { 'begin': 0x102A0, 'end': 0x102DF }, // Carian michael@0: { 'begin': 0x1F030, 'end': 0x1F09F } // Domino Tiles michael@0: ]; michael@0: michael@0: var MacStandardGlyphOrdering = [ michael@0: '.notdef', '.null', 'nonmarkingreturn', 'space', 'exclam', 'quotedbl', michael@0: 'numbersign', 'dollar', 'percent', 'ampersand', 'quotesingle', 'parenleft', michael@0: 'parenright', 'asterisk', 'plus', 'comma', 'hyphen', 'period', 'slash', michael@0: 'zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', michael@0: 'nine', 'colon', 'semicolon', 'less', 'equal', 'greater', 'question', 'at', michael@0: 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', michael@0: 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'bracketleft', michael@0: 'backslash', 'bracketright', 'asciicircum', 'underscore', 'grave', 'a', 'b', michael@0: 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', michael@0: 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'braceleft', 'bar', 'braceright', michael@0: 'asciitilde', 'Adieresis', 'Aring', 'Ccedilla', 'Eacute', 'Ntilde', michael@0: 'Odieresis', 'Udieresis', 'aacute', 'agrave', 'acircumflex', 'adieresis', michael@0: 'atilde', 'aring', 'ccedilla', 'eacute', 'egrave', 'ecircumflex', 'edieresis', michael@0: 'iacute', 'igrave', 'icircumflex', 'idieresis', 'ntilde', 'oacute', 'ograve', michael@0: 'ocircumflex', 'odieresis', 'otilde', 'uacute', 'ugrave', 'ucircumflex', michael@0: 'udieresis', 'dagger', 'degree', 'cent', 'sterling', 'section', 'bullet', michael@0: 'paragraph', 'germandbls', 'registered', 'copyright', 'trademark', 'acute', michael@0: 'dieresis', 'notequal', 'AE', 'Oslash', 'infinity', 'plusminus', 'lessequal', michael@0: 'greaterequal', 'yen', 'mu', 'partialdiff', 'summation', 'product', 'pi', michael@0: 'integral', 'ordfeminine', 'ordmasculine', 'Omega', 'ae', 'oslash', michael@0: 'questiondown', 'exclamdown', 'logicalnot', 'radical', 'florin', michael@0: 'approxequal', 'Delta', 'guillemotleft', 'guillemotright', 'ellipsis', michael@0: 'nonbreakingspace', 'Agrave', 'Atilde', 'Otilde', 'OE', 'oe', 'endash', michael@0: 'emdash', 'quotedblleft', 'quotedblright', 'quoteleft', 'quoteright', michael@0: 'divide', 'lozenge', 'ydieresis', 'Ydieresis', 'fraction', 'currency', michael@0: 'guilsinglleft', 'guilsinglright', 'fi', 'fl', 'daggerdbl', 'periodcentered', michael@0: 'quotesinglbase', 'quotedblbase', 'perthousand', 'Acircumflex', michael@0: 'Ecircumflex', 'Aacute', 'Edieresis', 'Egrave', 'Iacute', 'Icircumflex', michael@0: 'Idieresis', 'Igrave', 'Oacute', 'Ocircumflex', 'apple', 'Ograve', 'Uacute', michael@0: 'Ucircumflex', 'Ugrave', 'dotlessi', 'circumflex', 'tilde', 'macron', michael@0: 'breve', 'dotaccent', 'ring', 'cedilla', 'hungarumlaut', 'ogonek', 'caron', michael@0: 'Lslash', 'lslash', 'Scaron', 'scaron', 'Zcaron', 'zcaron', 'brokenbar', michael@0: 'Eth', 'eth', 'Yacute', 'yacute', 'Thorn', 'thorn', 'minus', 'multiply', michael@0: 'onesuperior', 'twosuperior', 'threesuperior', 'onehalf', 'onequarter', michael@0: 'threequarters', 'franc', 'Gbreve', 'gbreve', 'Idotaccent', 'Scedilla', michael@0: 'scedilla', 'Cacute', 'cacute', 'Ccaron', 'ccaron', 'dcroat']; michael@0: michael@0: function getUnicodeRangeFor(value) { michael@0: for (var i = 0, ii = UnicodeRanges.length; i < ii; i++) { michael@0: var range = UnicodeRanges[i]; michael@0: if (value >= range.begin && value < range.end) { michael@0: return i; michael@0: } michael@0: } michael@0: return -1; michael@0: } michael@0: michael@0: function isRTLRangeFor(value) { michael@0: var range = UnicodeRanges[13]; michael@0: if (value >= range.begin && value < range.end) { michael@0: return true; michael@0: } michael@0: range = UnicodeRanges[11]; michael@0: if (value >= range.begin && value < range.end) { michael@0: return true; michael@0: } michael@0: return false; michael@0: } michael@0: michael@0: // The normalization table is obtained by filtering the Unicode characters michael@0: // database with entries. michael@0: var NormalizedUnicodes = { michael@0: '\u00A8': '\u0020\u0308', michael@0: '\u00AF': '\u0020\u0304', michael@0: '\u00B4': '\u0020\u0301', michael@0: '\u00B5': '\u03BC', michael@0: '\u00B8': '\u0020\u0327', michael@0: '\u0132': '\u0049\u004A', michael@0: '\u0133': '\u0069\u006A', michael@0: '\u013F': '\u004C\u00B7', michael@0: '\u0140': '\u006C\u00B7', michael@0: '\u0149': '\u02BC\u006E', michael@0: '\u017F': '\u0073', michael@0: '\u01C4': '\u0044\u017D', michael@0: '\u01C5': '\u0044\u017E', michael@0: '\u01C6': '\u0064\u017E', michael@0: '\u01C7': '\u004C\u004A', michael@0: '\u01C8': '\u004C\u006A', michael@0: '\u01C9': '\u006C\u006A', michael@0: '\u01CA': '\u004E\u004A', michael@0: '\u01CB': '\u004E\u006A', michael@0: '\u01CC': '\u006E\u006A', michael@0: '\u01F1': '\u0044\u005A', michael@0: '\u01F2': '\u0044\u007A', michael@0: '\u01F3': '\u0064\u007A', michael@0: '\u02D8': '\u0020\u0306', michael@0: '\u02D9': '\u0020\u0307', michael@0: '\u02DA': '\u0020\u030A', michael@0: '\u02DB': '\u0020\u0328', michael@0: '\u02DC': '\u0020\u0303', michael@0: '\u02DD': '\u0020\u030B', michael@0: '\u037A': '\u0020\u0345', michael@0: '\u0384': '\u0020\u0301', michael@0: '\u03D0': '\u03B2', michael@0: '\u03D1': '\u03B8', michael@0: '\u03D2': '\u03A5', michael@0: '\u03D5': '\u03C6', michael@0: '\u03D6': '\u03C0', michael@0: '\u03F0': '\u03BA', michael@0: '\u03F1': '\u03C1', michael@0: '\u03F2': '\u03C2', michael@0: '\u03F4': '\u0398', michael@0: '\u03F5': '\u03B5', michael@0: '\u03F9': '\u03A3', michael@0: '\u0587': '\u0565\u0582', michael@0: '\u0675': '\u0627\u0674', michael@0: '\u0676': '\u0648\u0674', michael@0: '\u0677': '\u06C7\u0674', michael@0: '\u0678': '\u064A\u0674', michael@0: '\u0E33': '\u0E4D\u0E32', michael@0: '\u0EB3': '\u0ECD\u0EB2', michael@0: '\u0EDC': '\u0EAB\u0E99', michael@0: '\u0EDD': '\u0EAB\u0EA1', michael@0: '\u0F77': '\u0FB2\u0F81', michael@0: '\u0F79': '\u0FB3\u0F81', michael@0: '\u1E9A': '\u0061\u02BE', michael@0: '\u1FBD': '\u0020\u0313', michael@0: '\u1FBF': '\u0020\u0313', michael@0: '\u1FC0': '\u0020\u0342', michael@0: '\u1FFE': '\u0020\u0314', michael@0: '\u2002': '\u0020', michael@0: '\u2003': '\u0020', michael@0: '\u2004': '\u0020', michael@0: '\u2005': '\u0020', michael@0: '\u2006': '\u0020', michael@0: '\u2008': '\u0020', michael@0: '\u2009': '\u0020', michael@0: '\u200A': '\u0020', michael@0: '\u2017': '\u0020\u0333', michael@0: '\u2024': '\u002E', michael@0: '\u2025': '\u002E\u002E', michael@0: '\u2026': '\u002E\u002E\u002E', michael@0: '\u2033': '\u2032\u2032', michael@0: '\u2034': '\u2032\u2032\u2032', michael@0: '\u2036': '\u2035\u2035', michael@0: '\u2037': '\u2035\u2035\u2035', michael@0: '\u203C': '\u0021\u0021', michael@0: '\u203E': '\u0020\u0305', michael@0: '\u2047': '\u003F\u003F', michael@0: '\u2048': '\u003F\u0021', michael@0: '\u2049': '\u0021\u003F', michael@0: '\u2057': '\u2032\u2032\u2032\u2032', michael@0: '\u205F': '\u0020', michael@0: '\u20A8': '\u0052\u0073', michael@0: '\u2100': '\u0061\u002F\u0063', michael@0: '\u2101': '\u0061\u002F\u0073', michael@0: '\u2103': '\u00B0\u0043', michael@0: '\u2105': '\u0063\u002F\u006F', michael@0: '\u2106': '\u0063\u002F\u0075', michael@0: '\u2107': '\u0190', michael@0: '\u2109': '\u00B0\u0046', michael@0: '\u2116': '\u004E\u006F', michael@0: '\u2121': '\u0054\u0045\u004C', michael@0: '\u2135': '\u05D0', michael@0: '\u2136': '\u05D1', michael@0: '\u2137': '\u05D2', michael@0: '\u2138': '\u05D3', michael@0: '\u213B': '\u0046\u0041\u0058', michael@0: '\u2160': '\u0049', michael@0: '\u2161': '\u0049\u0049', michael@0: '\u2162': '\u0049\u0049\u0049', michael@0: '\u2163': '\u0049\u0056', michael@0: '\u2164': '\u0056', michael@0: '\u2165': '\u0056\u0049', michael@0: '\u2166': '\u0056\u0049\u0049', michael@0: '\u2167': '\u0056\u0049\u0049\u0049', michael@0: '\u2168': '\u0049\u0058', michael@0: '\u2169': '\u0058', michael@0: '\u216A': '\u0058\u0049', michael@0: '\u216B': '\u0058\u0049\u0049', michael@0: '\u216C': '\u004C', michael@0: '\u216D': '\u0043', michael@0: '\u216E': '\u0044', michael@0: '\u216F': '\u004D', michael@0: '\u2170': '\u0069', michael@0: '\u2171': '\u0069\u0069', michael@0: '\u2172': '\u0069\u0069\u0069', michael@0: '\u2173': '\u0069\u0076', michael@0: '\u2174': '\u0076', michael@0: '\u2175': '\u0076\u0069', michael@0: '\u2176': '\u0076\u0069\u0069', michael@0: '\u2177': '\u0076\u0069\u0069\u0069', michael@0: '\u2178': '\u0069\u0078', michael@0: '\u2179': '\u0078', michael@0: '\u217A': '\u0078\u0069', michael@0: '\u217B': '\u0078\u0069\u0069', michael@0: '\u217C': '\u006C', michael@0: '\u217D': '\u0063', michael@0: '\u217E': '\u0064', michael@0: '\u217F': '\u006D', michael@0: '\u222C': '\u222B\u222B', michael@0: '\u222D': '\u222B\u222B\u222B', michael@0: '\u222F': '\u222E\u222E', michael@0: '\u2230': '\u222E\u222E\u222E', michael@0: '\u2474': '\u0028\u0031\u0029', michael@0: '\u2475': '\u0028\u0032\u0029', michael@0: '\u2476': '\u0028\u0033\u0029', michael@0: '\u2477': '\u0028\u0034\u0029', michael@0: '\u2478': '\u0028\u0035\u0029', michael@0: '\u2479': '\u0028\u0036\u0029', michael@0: '\u247A': '\u0028\u0037\u0029', michael@0: '\u247B': '\u0028\u0038\u0029', michael@0: '\u247C': '\u0028\u0039\u0029', michael@0: '\u247D': '\u0028\u0031\u0030\u0029', michael@0: '\u247E': '\u0028\u0031\u0031\u0029', michael@0: '\u247F': '\u0028\u0031\u0032\u0029', michael@0: '\u2480': '\u0028\u0031\u0033\u0029', michael@0: '\u2481': '\u0028\u0031\u0034\u0029', michael@0: '\u2482': '\u0028\u0031\u0035\u0029', michael@0: '\u2483': '\u0028\u0031\u0036\u0029', michael@0: '\u2484': '\u0028\u0031\u0037\u0029', michael@0: '\u2485': '\u0028\u0031\u0038\u0029', michael@0: '\u2486': '\u0028\u0031\u0039\u0029', michael@0: '\u2487': '\u0028\u0032\u0030\u0029', michael@0: '\u2488': '\u0031\u002E', michael@0: '\u2489': '\u0032\u002E', michael@0: '\u248A': '\u0033\u002E', michael@0: '\u248B': '\u0034\u002E', michael@0: '\u248C': '\u0035\u002E', michael@0: '\u248D': '\u0036\u002E', michael@0: '\u248E': '\u0037\u002E', michael@0: '\u248F': '\u0038\u002E', michael@0: '\u2490': '\u0039\u002E', michael@0: '\u2491': '\u0031\u0030\u002E', michael@0: '\u2492': '\u0031\u0031\u002E', michael@0: '\u2493': '\u0031\u0032\u002E', michael@0: '\u2494': '\u0031\u0033\u002E', michael@0: '\u2495': '\u0031\u0034\u002E', michael@0: '\u2496': '\u0031\u0035\u002E', michael@0: '\u2497': '\u0031\u0036\u002E', michael@0: '\u2498': '\u0031\u0037\u002E', michael@0: '\u2499': '\u0031\u0038\u002E', michael@0: '\u249A': '\u0031\u0039\u002E', michael@0: '\u249B': '\u0032\u0030\u002E', michael@0: '\u249C': '\u0028\u0061\u0029', michael@0: '\u249D': '\u0028\u0062\u0029', michael@0: '\u249E': '\u0028\u0063\u0029', michael@0: '\u249F': '\u0028\u0064\u0029', michael@0: '\u24A0': '\u0028\u0065\u0029', michael@0: '\u24A1': '\u0028\u0066\u0029', michael@0: '\u24A2': '\u0028\u0067\u0029', michael@0: '\u24A3': '\u0028\u0068\u0029', michael@0: '\u24A4': '\u0028\u0069\u0029', michael@0: '\u24A5': '\u0028\u006A\u0029', michael@0: '\u24A6': '\u0028\u006B\u0029', michael@0: '\u24A7': '\u0028\u006C\u0029', michael@0: '\u24A8': '\u0028\u006D\u0029', michael@0: '\u24A9': '\u0028\u006E\u0029', michael@0: '\u24AA': '\u0028\u006F\u0029', michael@0: '\u24AB': '\u0028\u0070\u0029', michael@0: '\u24AC': '\u0028\u0071\u0029', michael@0: '\u24AD': '\u0028\u0072\u0029', michael@0: '\u24AE': '\u0028\u0073\u0029', michael@0: '\u24AF': '\u0028\u0074\u0029', michael@0: '\u24B0': '\u0028\u0075\u0029', michael@0: '\u24B1': '\u0028\u0076\u0029', michael@0: '\u24B2': '\u0028\u0077\u0029', michael@0: '\u24B3': '\u0028\u0078\u0029', michael@0: '\u24B4': '\u0028\u0079\u0029', michael@0: '\u24B5': '\u0028\u007A\u0029', michael@0: '\u2A0C': '\u222B\u222B\u222B\u222B', michael@0: '\u2A74': '\u003A\u003A\u003D', michael@0: '\u2A75': '\u003D\u003D', michael@0: '\u2A76': '\u003D\u003D\u003D', michael@0: '\u2E9F': '\u6BCD', michael@0: '\u2EF3': '\u9F9F', michael@0: '\u2F00': '\u4E00', michael@0: '\u2F01': '\u4E28', michael@0: '\u2F02': '\u4E36', michael@0: '\u2F03': '\u4E3F', michael@0: '\u2F04': '\u4E59', michael@0: '\u2F05': '\u4E85', michael@0: '\u2F06': '\u4E8C', michael@0: '\u2F07': '\u4EA0', michael@0: '\u2F08': '\u4EBA', michael@0: '\u2F09': '\u513F', michael@0: '\u2F0A': '\u5165', michael@0: '\u2F0B': '\u516B', michael@0: '\u2F0C': '\u5182', michael@0: '\u2F0D': '\u5196', michael@0: '\u2F0E': '\u51AB', michael@0: '\u2F0F': '\u51E0', michael@0: '\u2F10': '\u51F5', michael@0: '\u2F11': '\u5200', michael@0: '\u2F12': '\u529B', michael@0: '\u2F13': '\u52F9', michael@0: '\u2F14': '\u5315', michael@0: '\u2F15': '\u531A', michael@0: '\u2F16': '\u5338', michael@0: '\u2F17': '\u5341', michael@0: '\u2F18': '\u535C', michael@0: '\u2F19': '\u5369', michael@0: '\u2F1A': '\u5382', michael@0: '\u2F1B': '\u53B6', michael@0: '\u2F1C': '\u53C8', michael@0: '\u2F1D': '\u53E3', michael@0: '\u2F1E': '\u56D7', michael@0: '\u2F1F': '\u571F', michael@0: '\u2F20': '\u58EB', michael@0: '\u2F21': '\u5902', michael@0: '\u2F22': '\u590A', michael@0: '\u2F23': '\u5915', michael@0: '\u2F24': '\u5927', michael@0: '\u2F25': '\u5973', michael@0: '\u2F26': '\u5B50', michael@0: '\u2F27': '\u5B80', michael@0: '\u2F28': '\u5BF8', michael@0: '\u2F29': '\u5C0F', michael@0: '\u2F2A': '\u5C22', michael@0: '\u2F2B': '\u5C38', michael@0: '\u2F2C': '\u5C6E', michael@0: '\u2F2D': '\u5C71', michael@0: '\u2F2E': '\u5DDB', michael@0: '\u2F2F': '\u5DE5', michael@0: '\u2F30': '\u5DF1', michael@0: '\u2F31': '\u5DFE', michael@0: '\u2F32': '\u5E72', michael@0: '\u2F33': '\u5E7A', michael@0: '\u2F34': '\u5E7F', michael@0: '\u2F35': '\u5EF4', michael@0: '\u2F36': '\u5EFE', michael@0: '\u2F37': '\u5F0B', michael@0: '\u2F38': '\u5F13', michael@0: '\u2F39': '\u5F50', michael@0: '\u2F3A': '\u5F61', michael@0: '\u2F3B': '\u5F73', michael@0: '\u2F3C': '\u5FC3', michael@0: '\u2F3D': '\u6208', michael@0: '\u2F3E': '\u6236', michael@0: '\u2F3F': '\u624B', michael@0: '\u2F40': '\u652F', michael@0: '\u2F41': '\u6534', michael@0: '\u2F42': '\u6587', michael@0: '\u2F43': '\u6597', michael@0: '\u2F44': '\u65A4', michael@0: '\u2F45': '\u65B9', michael@0: '\u2F46': '\u65E0', michael@0: '\u2F47': '\u65E5', michael@0: '\u2F48': '\u66F0', michael@0: '\u2F49': '\u6708', michael@0: '\u2F4A': '\u6728', michael@0: '\u2F4B': '\u6B20', michael@0: '\u2F4C': '\u6B62', michael@0: '\u2F4D': '\u6B79', michael@0: '\u2F4E': '\u6BB3', michael@0: '\u2F4F': '\u6BCB', michael@0: '\u2F50': '\u6BD4', michael@0: '\u2F51': '\u6BDB', michael@0: '\u2F52': '\u6C0F', michael@0: '\u2F53': '\u6C14', michael@0: '\u2F54': '\u6C34', michael@0: '\u2F55': '\u706B', michael@0: '\u2F56': '\u722A', michael@0: '\u2F57': '\u7236', michael@0: '\u2F58': '\u723B', michael@0: '\u2F59': '\u723F', michael@0: '\u2F5A': '\u7247', michael@0: '\u2F5B': '\u7259', michael@0: '\u2F5C': '\u725B', michael@0: '\u2F5D': '\u72AC', michael@0: '\u2F5E': '\u7384', michael@0: '\u2F5F': '\u7389', michael@0: '\u2F60': '\u74DC', michael@0: '\u2F61': '\u74E6', michael@0: '\u2F62': '\u7518', michael@0: '\u2F63': '\u751F', michael@0: '\u2F64': '\u7528', michael@0: '\u2F65': '\u7530', michael@0: '\u2F66': '\u758B', michael@0: '\u2F67': '\u7592', michael@0: '\u2F68': '\u7676', michael@0: '\u2F69': '\u767D', michael@0: '\u2F6A': '\u76AE', michael@0: '\u2F6B': '\u76BF', michael@0: '\u2F6C': '\u76EE', michael@0: '\u2F6D': '\u77DB', michael@0: '\u2F6E': '\u77E2', michael@0: '\u2F6F': '\u77F3', michael@0: '\u2F70': '\u793A', michael@0: '\u2F71': '\u79B8', michael@0: '\u2F72': '\u79BE', michael@0: '\u2F73': '\u7A74', michael@0: '\u2F74': '\u7ACB', michael@0: '\u2F75': '\u7AF9', michael@0: '\u2F76': '\u7C73', michael@0: '\u2F77': '\u7CF8', michael@0: '\u2F78': '\u7F36', michael@0: '\u2F79': '\u7F51', michael@0: '\u2F7A': '\u7F8A', michael@0: '\u2F7B': '\u7FBD', michael@0: '\u2F7C': '\u8001', michael@0: '\u2F7D': '\u800C', michael@0: '\u2F7E': '\u8012', michael@0: '\u2F7F': '\u8033', michael@0: '\u2F80': '\u807F', michael@0: '\u2F81': '\u8089', michael@0: '\u2F82': '\u81E3', michael@0: '\u2F83': '\u81EA', michael@0: '\u2F84': '\u81F3', michael@0: '\u2F85': '\u81FC', michael@0: '\u2F86': '\u820C', michael@0: '\u2F87': '\u821B', michael@0: '\u2F88': '\u821F', michael@0: '\u2F89': '\u826E', michael@0: '\u2F8A': '\u8272', michael@0: '\u2F8B': '\u8278', michael@0: '\u2F8C': '\u864D', michael@0: '\u2F8D': '\u866B', michael@0: '\u2F8E': '\u8840', michael@0: '\u2F8F': '\u884C', michael@0: '\u2F90': '\u8863', michael@0: '\u2F91': '\u897E', michael@0: '\u2F92': '\u898B', michael@0: '\u2F93': '\u89D2', michael@0: '\u2F94': '\u8A00', michael@0: '\u2F95': '\u8C37', michael@0: '\u2F96': '\u8C46', michael@0: '\u2F97': '\u8C55', michael@0: '\u2F98': '\u8C78', michael@0: '\u2F99': '\u8C9D', michael@0: '\u2F9A': '\u8D64', michael@0: '\u2F9B': '\u8D70', michael@0: '\u2F9C': '\u8DB3', michael@0: '\u2F9D': '\u8EAB', michael@0: '\u2F9E': '\u8ECA', michael@0: '\u2F9F': '\u8F9B', michael@0: '\u2FA0': '\u8FB0', michael@0: '\u2FA1': '\u8FB5', michael@0: '\u2FA2': '\u9091', michael@0: '\u2FA3': '\u9149', michael@0: '\u2FA4': '\u91C6', michael@0: '\u2FA5': '\u91CC', michael@0: '\u2FA6': '\u91D1', michael@0: '\u2FA7': '\u9577', michael@0: '\u2FA8': '\u9580', michael@0: '\u2FA9': '\u961C', michael@0: '\u2FAA': '\u96B6', michael@0: '\u2FAB': '\u96B9', michael@0: '\u2FAC': '\u96E8', michael@0: '\u2FAD': '\u9751', michael@0: '\u2FAE': '\u975E', michael@0: '\u2FAF': '\u9762', michael@0: '\u2FB0': '\u9769', michael@0: '\u2FB1': '\u97CB', michael@0: '\u2FB2': '\u97ED', michael@0: '\u2FB3': '\u97F3', michael@0: '\u2FB4': '\u9801', michael@0: '\u2FB5': '\u98A8', michael@0: '\u2FB6': '\u98DB', michael@0: '\u2FB7': '\u98DF', michael@0: '\u2FB8': '\u9996', michael@0: '\u2FB9': '\u9999', michael@0: '\u2FBA': '\u99AC', michael@0: '\u2FBB': '\u9AA8', michael@0: '\u2FBC': '\u9AD8', michael@0: '\u2FBD': '\u9ADF', michael@0: '\u2FBE': '\u9B25', michael@0: '\u2FBF': '\u9B2F', michael@0: '\u2FC0': '\u9B32', michael@0: '\u2FC1': '\u9B3C', michael@0: '\u2FC2': '\u9B5A', michael@0: '\u2FC3': '\u9CE5', michael@0: '\u2FC4': '\u9E75', michael@0: '\u2FC5': '\u9E7F', michael@0: '\u2FC6': '\u9EA5', michael@0: '\u2FC7': '\u9EBB', michael@0: '\u2FC8': '\u9EC3', michael@0: '\u2FC9': '\u9ECD', michael@0: '\u2FCA': '\u9ED1', michael@0: '\u2FCB': '\u9EF9', michael@0: '\u2FCC': '\u9EFD', michael@0: '\u2FCD': '\u9F0E', michael@0: '\u2FCE': '\u9F13', michael@0: '\u2FCF': '\u9F20', michael@0: '\u2FD0': '\u9F3B', michael@0: '\u2FD1': '\u9F4A', michael@0: '\u2FD2': '\u9F52', michael@0: '\u2FD3': '\u9F8D', michael@0: '\u2FD4': '\u9F9C', michael@0: '\u2FD5': '\u9FA0', michael@0: '\u3036': '\u3012', michael@0: '\u3038': '\u5341', michael@0: '\u3039': '\u5344', michael@0: '\u303A': '\u5345', michael@0: '\u309B': '\u0020\u3099', michael@0: '\u309C': '\u0020\u309A', michael@0: '\u3131': '\u1100', michael@0: '\u3132': '\u1101', michael@0: '\u3133': '\u11AA', michael@0: '\u3134': '\u1102', michael@0: '\u3135': '\u11AC', michael@0: '\u3136': '\u11AD', michael@0: '\u3137': '\u1103', michael@0: '\u3138': '\u1104', michael@0: '\u3139': '\u1105', michael@0: '\u313A': '\u11B0', michael@0: '\u313B': '\u11B1', michael@0: '\u313C': '\u11B2', michael@0: '\u313D': '\u11B3', michael@0: '\u313E': '\u11B4', michael@0: '\u313F': '\u11B5', michael@0: '\u3140': '\u111A', michael@0: '\u3141': '\u1106', michael@0: '\u3142': '\u1107', michael@0: '\u3143': '\u1108', michael@0: '\u3144': '\u1121', michael@0: '\u3145': '\u1109', michael@0: '\u3146': '\u110A', michael@0: '\u3147': '\u110B', michael@0: '\u3148': '\u110C', michael@0: '\u3149': '\u110D', michael@0: '\u314A': '\u110E', michael@0: '\u314B': '\u110F', michael@0: '\u314C': '\u1110', michael@0: '\u314D': '\u1111', michael@0: '\u314E': '\u1112', michael@0: '\u314F': '\u1161', michael@0: '\u3150': '\u1162', michael@0: '\u3151': '\u1163', michael@0: '\u3152': '\u1164', michael@0: '\u3153': '\u1165', michael@0: '\u3154': '\u1166', michael@0: '\u3155': '\u1167', michael@0: '\u3156': '\u1168', michael@0: '\u3157': '\u1169', michael@0: '\u3158': '\u116A', michael@0: '\u3159': '\u116B', michael@0: '\u315A': '\u116C', michael@0: '\u315B': '\u116D', michael@0: '\u315C': '\u116E', michael@0: '\u315D': '\u116F', michael@0: '\u315E': '\u1170', michael@0: '\u315F': '\u1171', michael@0: '\u3160': '\u1172', michael@0: '\u3161': '\u1173', michael@0: '\u3162': '\u1174', michael@0: '\u3163': '\u1175', michael@0: '\u3164': '\u1160', michael@0: '\u3165': '\u1114', michael@0: '\u3166': '\u1115', michael@0: '\u3167': '\u11C7', michael@0: '\u3168': '\u11C8', michael@0: '\u3169': '\u11CC', michael@0: '\u316A': '\u11CE', michael@0: '\u316B': '\u11D3', michael@0: '\u316C': '\u11D7', michael@0: '\u316D': '\u11D9', michael@0: '\u316E': '\u111C', michael@0: '\u316F': '\u11DD', michael@0: '\u3170': '\u11DF', michael@0: '\u3171': '\u111D', michael@0: '\u3172': '\u111E', michael@0: '\u3173': '\u1120', michael@0: '\u3174': '\u1122', michael@0: '\u3175': '\u1123', michael@0: '\u3176': '\u1127', michael@0: '\u3177': '\u1129', michael@0: '\u3178': '\u112B', michael@0: '\u3179': '\u112C', michael@0: '\u317A': '\u112D', michael@0: '\u317B': '\u112E', michael@0: '\u317C': '\u112F', michael@0: '\u317D': '\u1132', michael@0: '\u317E': '\u1136', michael@0: '\u317F': '\u1140', michael@0: '\u3180': '\u1147', michael@0: '\u3181': '\u114C', michael@0: '\u3182': '\u11F1', michael@0: '\u3183': '\u11F2', michael@0: '\u3184': '\u1157', michael@0: '\u3185': '\u1158', michael@0: '\u3186': '\u1159', michael@0: '\u3187': '\u1184', michael@0: '\u3188': '\u1185', michael@0: '\u3189': '\u1188', michael@0: '\u318A': '\u1191', michael@0: '\u318B': '\u1192', michael@0: '\u318C': '\u1194', michael@0: '\u318D': '\u119E', michael@0: '\u318E': '\u11A1', michael@0: '\u3200': '\u0028\u1100\u0029', michael@0: '\u3201': '\u0028\u1102\u0029', michael@0: '\u3202': '\u0028\u1103\u0029', michael@0: '\u3203': '\u0028\u1105\u0029', michael@0: '\u3204': '\u0028\u1106\u0029', michael@0: '\u3205': '\u0028\u1107\u0029', michael@0: '\u3206': '\u0028\u1109\u0029', michael@0: '\u3207': '\u0028\u110B\u0029', michael@0: '\u3208': '\u0028\u110C\u0029', michael@0: '\u3209': '\u0028\u110E\u0029', michael@0: '\u320A': '\u0028\u110F\u0029', michael@0: '\u320B': '\u0028\u1110\u0029', michael@0: '\u320C': '\u0028\u1111\u0029', michael@0: '\u320D': '\u0028\u1112\u0029', michael@0: '\u320E': '\u0028\u1100\u1161\u0029', michael@0: '\u320F': '\u0028\u1102\u1161\u0029', michael@0: '\u3210': '\u0028\u1103\u1161\u0029', michael@0: '\u3211': '\u0028\u1105\u1161\u0029', michael@0: '\u3212': '\u0028\u1106\u1161\u0029', michael@0: '\u3213': '\u0028\u1107\u1161\u0029', michael@0: '\u3214': '\u0028\u1109\u1161\u0029', michael@0: '\u3215': '\u0028\u110B\u1161\u0029', michael@0: '\u3216': '\u0028\u110C\u1161\u0029', michael@0: '\u3217': '\u0028\u110E\u1161\u0029', michael@0: '\u3218': '\u0028\u110F\u1161\u0029', michael@0: '\u3219': '\u0028\u1110\u1161\u0029', michael@0: '\u321A': '\u0028\u1111\u1161\u0029', michael@0: '\u321B': '\u0028\u1112\u1161\u0029', michael@0: '\u321C': '\u0028\u110C\u116E\u0029', michael@0: '\u321D': '\u0028\u110B\u1169\u110C\u1165\u11AB\u0029', michael@0: '\u321E': '\u0028\u110B\u1169\u1112\u116E\u0029', michael@0: '\u3220': '\u0028\u4E00\u0029', michael@0: '\u3221': '\u0028\u4E8C\u0029', michael@0: '\u3222': '\u0028\u4E09\u0029', michael@0: '\u3223': '\u0028\u56DB\u0029', michael@0: '\u3224': '\u0028\u4E94\u0029', michael@0: '\u3225': '\u0028\u516D\u0029', michael@0: '\u3226': '\u0028\u4E03\u0029', michael@0: '\u3227': '\u0028\u516B\u0029', michael@0: '\u3228': '\u0028\u4E5D\u0029', michael@0: '\u3229': '\u0028\u5341\u0029', michael@0: '\u322A': '\u0028\u6708\u0029', michael@0: '\u322B': '\u0028\u706B\u0029', michael@0: '\u322C': '\u0028\u6C34\u0029', michael@0: '\u322D': '\u0028\u6728\u0029', michael@0: '\u322E': '\u0028\u91D1\u0029', michael@0: '\u322F': '\u0028\u571F\u0029', michael@0: '\u3230': '\u0028\u65E5\u0029', michael@0: '\u3231': '\u0028\u682A\u0029', michael@0: '\u3232': '\u0028\u6709\u0029', michael@0: '\u3233': '\u0028\u793E\u0029', michael@0: '\u3234': '\u0028\u540D\u0029', michael@0: '\u3235': '\u0028\u7279\u0029', michael@0: '\u3236': '\u0028\u8CA1\u0029', michael@0: '\u3237': '\u0028\u795D\u0029', michael@0: '\u3238': '\u0028\u52B4\u0029', michael@0: '\u3239': '\u0028\u4EE3\u0029', michael@0: '\u323A': '\u0028\u547C\u0029', michael@0: '\u323B': '\u0028\u5B66\u0029', michael@0: '\u323C': '\u0028\u76E3\u0029', michael@0: '\u323D': '\u0028\u4F01\u0029', michael@0: '\u323E': '\u0028\u8CC7\u0029', michael@0: '\u323F': '\u0028\u5354\u0029', michael@0: '\u3240': '\u0028\u796D\u0029', michael@0: '\u3241': '\u0028\u4F11\u0029', michael@0: '\u3242': '\u0028\u81EA\u0029', michael@0: '\u3243': '\u0028\u81F3\u0029', michael@0: '\u32C0': '\u0031\u6708', michael@0: '\u32C1': '\u0032\u6708', michael@0: '\u32C2': '\u0033\u6708', michael@0: '\u32C3': '\u0034\u6708', michael@0: '\u32C4': '\u0035\u6708', michael@0: '\u32C5': '\u0036\u6708', michael@0: '\u32C6': '\u0037\u6708', michael@0: '\u32C7': '\u0038\u6708', michael@0: '\u32C8': '\u0039\u6708', michael@0: '\u32C9': '\u0031\u0030\u6708', michael@0: '\u32CA': '\u0031\u0031\u6708', michael@0: '\u32CB': '\u0031\u0032\u6708', michael@0: '\u3358': '\u0030\u70B9', michael@0: '\u3359': '\u0031\u70B9', michael@0: '\u335A': '\u0032\u70B9', michael@0: '\u335B': '\u0033\u70B9', michael@0: '\u335C': '\u0034\u70B9', michael@0: '\u335D': '\u0035\u70B9', michael@0: '\u335E': '\u0036\u70B9', michael@0: '\u335F': '\u0037\u70B9', michael@0: '\u3360': '\u0038\u70B9', michael@0: '\u3361': '\u0039\u70B9', michael@0: '\u3362': '\u0031\u0030\u70B9', michael@0: '\u3363': '\u0031\u0031\u70B9', michael@0: '\u3364': '\u0031\u0032\u70B9', michael@0: '\u3365': '\u0031\u0033\u70B9', michael@0: '\u3366': '\u0031\u0034\u70B9', michael@0: '\u3367': '\u0031\u0035\u70B9', michael@0: '\u3368': '\u0031\u0036\u70B9', michael@0: '\u3369': '\u0031\u0037\u70B9', michael@0: '\u336A': '\u0031\u0038\u70B9', michael@0: '\u336B': '\u0031\u0039\u70B9', michael@0: '\u336C': '\u0032\u0030\u70B9', michael@0: '\u336D': '\u0032\u0031\u70B9', michael@0: '\u336E': '\u0032\u0032\u70B9', michael@0: '\u336F': '\u0032\u0033\u70B9', michael@0: '\u3370': '\u0032\u0034\u70B9', michael@0: '\u33E0': '\u0031\u65E5', michael@0: '\u33E1': '\u0032\u65E5', michael@0: '\u33E2': '\u0033\u65E5', michael@0: '\u33E3': '\u0034\u65E5', michael@0: '\u33E4': '\u0035\u65E5', michael@0: '\u33E5': '\u0036\u65E5', michael@0: '\u33E6': '\u0037\u65E5', michael@0: '\u33E7': '\u0038\u65E5', michael@0: '\u33E8': '\u0039\u65E5', michael@0: '\u33E9': '\u0031\u0030\u65E5', michael@0: '\u33EA': '\u0031\u0031\u65E5', michael@0: '\u33EB': '\u0031\u0032\u65E5', michael@0: '\u33EC': '\u0031\u0033\u65E5', michael@0: '\u33ED': '\u0031\u0034\u65E5', michael@0: '\u33EE': '\u0031\u0035\u65E5', michael@0: '\u33EF': '\u0031\u0036\u65E5', michael@0: '\u33F0': '\u0031\u0037\u65E5', michael@0: '\u33F1': '\u0031\u0038\u65E5', michael@0: '\u33F2': '\u0031\u0039\u65E5', michael@0: '\u33F3': '\u0032\u0030\u65E5', michael@0: '\u33F4': '\u0032\u0031\u65E5', michael@0: '\u33F5': '\u0032\u0032\u65E5', michael@0: '\u33F6': '\u0032\u0033\u65E5', michael@0: '\u33F7': '\u0032\u0034\u65E5', michael@0: '\u33F8': '\u0032\u0035\u65E5', michael@0: '\u33F9': '\u0032\u0036\u65E5', michael@0: '\u33FA': '\u0032\u0037\u65E5', michael@0: '\u33FB': '\u0032\u0038\u65E5', michael@0: '\u33FC': '\u0032\u0039\u65E5', michael@0: '\u33FD': '\u0033\u0030\u65E5', michael@0: '\u33FE': '\u0033\u0031\u65E5', michael@0: '\uFB00': '\u0066\u0066', michael@0: '\uFB01': '\u0066\u0069', michael@0: '\uFB02': '\u0066\u006C', michael@0: '\uFB03': '\u0066\u0066\u0069', michael@0: '\uFB04': '\u0066\u0066\u006C', michael@0: '\uFB05': '\u017F\u0074', michael@0: '\uFB06': '\u0073\u0074', michael@0: '\uFB13': '\u0574\u0576', michael@0: '\uFB14': '\u0574\u0565', michael@0: '\uFB15': '\u0574\u056B', michael@0: '\uFB16': '\u057E\u0576', michael@0: '\uFB17': '\u0574\u056D', michael@0: '\uFB4F': '\u05D0\u05DC', michael@0: '\uFB50': '\u0671', michael@0: '\uFB51': '\u0671', michael@0: '\uFB52': '\u067B', michael@0: '\uFB53': '\u067B', michael@0: '\uFB54': '\u067B', michael@0: '\uFB55': '\u067B', michael@0: '\uFB56': '\u067E', michael@0: '\uFB57': '\u067E', michael@0: '\uFB58': '\u067E', michael@0: '\uFB59': '\u067E', michael@0: '\uFB5A': '\u0680', michael@0: '\uFB5B': '\u0680', michael@0: '\uFB5C': '\u0680', michael@0: '\uFB5D': '\u0680', michael@0: '\uFB5E': '\u067A', michael@0: '\uFB5F': '\u067A', michael@0: '\uFB60': '\u067A', michael@0: '\uFB61': '\u067A', michael@0: '\uFB62': '\u067F', michael@0: '\uFB63': '\u067F', michael@0: '\uFB64': '\u067F', michael@0: '\uFB65': '\u067F', michael@0: '\uFB66': '\u0679', michael@0: '\uFB67': '\u0679', michael@0: '\uFB68': '\u0679', michael@0: '\uFB69': '\u0679', michael@0: '\uFB6A': '\u06A4', michael@0: '\uFB6B': '\u06A4', michael@0: '\uFB6C': '\u06A4', michael@0: '\uFB6D': '\u06A4', michael@0: '\uFB6E': '\u06A6', michael@0: '\uFB6F': '\u06A6', michael@0: '\uFB70': '\u06A6', michael@0: '\uFB71': '\u06A6', michael@0: '\uFB72': '\u0684', michael@0: '\uFB73': '\u0684', michael@0: '\uFB74': '\u0684', michael@0: '\uFB75': '\u0684', michael@0: '\uFB76': '\u0683', michael@0: '\uFB77': '\u0683', michael@0: '\uFB78': '\u0683', michael@0: '\uFB79': '\u0683', michael@0: '\uFB7A': '\u0686', michael@0: '\uFB7B': '\u0686', michael@0: '\uFB7C': '\u0686', michael@0: '\uFB7D': '\u0686', michael@0: '\uFB7E': '\u0687', michael@0: '\uFB7F': '\u0687', michael@0: '\uFB80': '\u0687', michael@0: '\uFB81': '\u0687', michael@0: '\uFB82': '\u068D', michael@0: '\uFB83': '\u068D', michael@0: '\uFB84': '\u068C', michael@0: '\uFB85': '\u068C', michael@0: '\uFB86': '\u068E', michael@0: '\uFB87': '\u068E', michael@0: '\uFB88': '\u0688', michael@0: '\uFB89': '\u0688', michael@0: '\uFB8A': '\u0698', michael@0: '\uFB8B': '\u0698', michael@0: '\uFB8C': '\u0691', michael@0: '\uFB8D': '\u0691', michael@0: '\uFB8E': '\u06A9', michael@0: '\uFB8F': '\u06A9', michael@0: '\uFB90': '\u06A9', michael@0: '\uFB91': '\u06A9', michael@0: '\uFB92': '\u06AF', michael@0: '\uFB93': '\u06AF', michael@0: '\uFB94': '\u06AF', michael@0: '\uFB95': '\u06AF', michael@0: '\uFB96': '\u06B3', michael@0: '\uFB97': '\u06B3', michael@0: '\uFB98': '\u06B3', michael@0: '\uFB99': '\u06B3', michael@0: '\uFB9A': '\u06B1', michael@0: '\uFB9B': '\u06B1', michael@0: '\uFB9C': '\u06B1', michael@0: '\uFB9D': '\u06B1', michael@0: '\uFB9E': '\u06BA', michael@0: '\uFB9F': '\u06BA', michael@0: '\uFBA0': '\u06BB', michael@0: '\uFBA1': '\u06BB', michael@0: '\uFBA2': '\u06BB', michael@0: '\uFBA3': '\u06BB', michael@0: '\uFBA4': '\u06C0', michael@0: '\uFBA5': '\u06C0', michael@0: '\uFBA6': '\u06C1', michael@0: '\uFBA7': '\u06C1', michael@0: '\uFBA8': '\u06C1', michael@0: '\uFBA9': '\u06C1', michael@0: '\uFBAA': '\u06BE', michael@0: '\uFBAB': '\u06BE', michael@0: '\uFBAC': '\u06BE', michael@0: '\uFBAD': '\u06BE', michael@0: '\uFBAE': '\u06D2', michael@0: '\uFBAF': '\u06D2', michael@0: '\uFBB0': '\u06D3', michael@0: '\uFBB1': '\u06D3', michael@0: '\uFBD3': '\u06AD', michael@0: '\uFBD4': '\u06AD', michael@0: '\uFBD5': '\u06AD', michael@0: '\uFBD6': '\u06AD', michael@0: '\uFBD7': '\u06C7', michael@0: '\uFBD8': '\u06C7', michael@0: '\uFBD9': '\u06C6', michael@0: '\uFBDA': '\u06C6', michael@0: '\uFBDB': '\u06C8', michael@0: '\uFBDC': '\u06C8', michael@0: '\uFBDD': '\u0677', michael@0: '\uFBDE': '\u06CB', michael@0: '\uFBDF': '\u06CB', michael@0: '\uFBE0': '\u06C5', michael@0: '\uFBE1': '\u06C5', michael@0: '\uFBE2': '\u06C9', michael@0: '\uFBE3': '\u06C9', michael@0: '\uFBE4': '\u06D0', michael@0: '\uFBE5': '\u06D0', michael@0: '\uFBE6': '\u06D0', michael@0: '\uFBE7': '\u06D0', michael@0: '\uFBE8': '\u0649', michael@0: '\uFBE9': '\u0649', michael@0: '\uFBEA': '\u0626\u0627', michael@0: '\uFBEB': '\u0626\u0627', michael@0: '\uFBEC': '\u0626\u06D5', michael@0: '\uFBED': '\u0626\u06D5', michael@0: '\uFBEE': '\u0626\u0648', michael@0: '\uFBEF': '\u0626\u0648', michael@0: '\uFBF0': '\u0626\u06C7', michael@0: '\uFBF1': '\u0626\u06C7', michael@0: '\uFBF2': '\u0626\u06C6', michael@0: '\uFBF3': '\u0626\u06C6', michael@0: '\uFBF4': '\u0626\u06C8', michael@0: '\uFBF5': '\u0626\u06C8', michael@0: '\uFBF6': '\u0626\u06D0', michael@0: '\uFBF7': '\u0626\u06D0', michael@0: '\uFBF8': '\u0626\u06D0', michael@0: '\uFBF9': '\u0626\u0649', michael@0: '\uFBFA': '\u0626\u0649', michael@0: '\uFBFB': '\u0626\u0649', michael@0: '\uFBFC': '\u06CC', michael@0: '\uFBFD': '\u06CC', michael@0: '\uFBFE': '\u06CC', michael@0: '\uFBFF': '\u06CC', michael@0: '\uFC00': '\u0626\u062C', michael@0: '\uFC01': '\u0626\u062D', michael@0: '\uFC02': '\u0626\u0645', michael@0: '\uFC03': '\u0626\u0649', michael@0: '\uFC04': '\u0626\u064A', michael@0: '\uFC05': '\u0628\u062C', michael@0: '\uFC06': '\u0628\u062D', michael@0: '\uFC07': '\u0628\u062E', michael@0: '\uFC08': '\u0628\u0645', michael@0: '\uFC09': '\u0628\u0649', michael@0: '\uFC0A': '\u0628\u064A', michael@0: '\uFC0B': '\u062A\u062C', michael@0: '\uFC0C': '\u062A\u062D', michael@0: '\uFC0D': '\u062A\u062E', michael@0: '\uFC0E': '\u062A\u0645', michael@0: '\uFC0F': '\u062A\u0649', michael@0: '\uFC10': '\u062A\u064A', michael@0: '\uFC11': '\u062B\u062C', michael@0: '\uFC12': '\u062B\u0645', michael@0: '\uFC13': '\u062B\u0649', michael@0: '\uFC14': '\u062B\u064A', michael@0: '\uFC15': '\u062C\u062D', michael@0: '\uFC16': '\u062C\u0645', michael@0: '\uFC17': '\u062D\u062C', michael@0: '\uFC18': '\u062D\u0645', michael@0: '\uFC19': '\u062E\u062C', michael@0: '\uFC1A': '\u062E\u062D', michael@0: '\uFC1B': '\u062E\u0645', michael@0: '\uFC1C': '\u0633\u062C', michael@0: '\uFC1D': '\u0633\u062D', michael@0: '\uFC1E': '\u0633\u062E', michael@0: '\uFC1F': '\u0633\u0645', michael@0: '\uFC20': '\u0635\u062D', michael@0: '\uFC21': '\u0635\u0645', michael@0: '\uFC22': '\u0636\u062C', michael@0: '\uFC23': '\u0636\u062D', michael@0: '\uFC24': '\u0636\u062E', michael@0: '\uFC25': '\u0636\u0645', michael@0: '\uFC26': '\u0637\u062D', michael@0: '\uFC27': '\u0637\u0645', michael@0: '\uFC28': '\u0638\u0645', michael@0: '\uFC29': '\u0639\u062C', michael@0: '\uFC2A': '\u0639\u0645', michael@0: '\uFC2B': '\u063A\u062C', michael@0: '\uFC2C': '\u063A\u0645', michael@0: '\uFC2D': '\u0641\u062C', michael@0: '\uFC2E': '\u0641\u062D', michael@0: '\uFC2F': '\u0641\u062E', michael@0: '\uFC30': '\u0641\u0645', michael@0: '\uFC31': '\u0641\u0649', michael@0: '\uFC32': '\u0641\u064A', michael@0: '\uFC33': '\u0642\u062D', michael@0: '\uFC34': '\u0642\u0645', michael@0: '\uFC35': '\u0642\u0649', michael@0: '\uFC36': '\u0642\u064A', michael@0: '\uFC37': '\u0643\u0627', michael@0: '\uFC38': '\u0643\u062C', michael@0: '\uFC39': '\u0643\u062D', michael@0: '\uFC3A': '\u0643\u062E', michael@0: '\uFC3B': '\u0643\u0644', michael@0: '\uFC3C': '\u0643\u0645', michael@0: '\uFC3D': '\u0643\u0649', michael@0: '\uFC3E': '\u0643\u064A', michael@0: '\uFC3F': '\u0644\u062C', michael@0: '\uFC40': '\u0644\u062D', michael@0: '\uFC41': '\u0644\u062E', michael@0: '\uFC42': '\u0644\u0645', michael@0: '\uFC43': '\u0644\u0649', michael@0: '\uFC44': '\u0644\u064A', michael@0: '\uFC45': '\u0645\u062C', michael@0: '\uFC46': '\u0645\u062D', michael@0: '\uFC47': '\u0645\u062E', michael@0: '\uFC48': '\u0645\u0645', michael@0: '\uFC49': '\u0645\u0649', michael@0: '\uFC4A': '\u0645\u064A', michael@0: '\uFC4B': '\u0646\u062C', michael@0: '\uFC4C': '\u0646\u062D', michael@0: '\uFC4D': '\u0646\u062E', michael@0: '\uFC4E': '\u0646\u0645', michael@0: '\uFC4F': '\u0646\u0649', michael@0: '\uFC50': '\u0646\u064A', michael@0: '\uFC51': '\u0647\u062C', michael@0: '\uFC52': '\u0647\u0645', michael@0: '\uFC53': '\u0647\u0649', michael@0: '\uFC54': '\u0647\u064A', michael@0: '\uFC55': '\u064A\u062C', michael@0: '\uFC56': '\u064A\u062D', michael@0: '\uFC57': '\u064A\u062E', michael@0: '\uFC58': '\u064A\u0645', michael@0: '\uFC59': '\u064A\u0649', michael@0: '\uFC5A': '\u064A\u064A', michael@0: '\uFC5B': '\u0630\u0670', michael@0: '\uFC5C': '\u0631\u0670', michael@0: '\uFC5D': '\u0649\u0670', michael@0: '\uFC5E': '\u0020\u064C\u0651', michael@0: '\uFC5F': '\u0020\u064D\u0651', michael@0: '\uFC60': '\u0020\u064E\u0651', michael@0: '\uFC61': '\u0020\u064F\u0651', michael@0: '\uFC62': '\u0020\u0650\u0651', michael@0: '\uFC63': '\u0020\u0651\u0670', michael@0: '\uFC64': '\u0626\u0631', michael@0: '\uFC65': '\u0626\u0632', michael@0: '\uFC66': '\u0626\u0645', michael@0: '\uFC67': '\u0626\u0646', michael@0: '\uFC68': '\u0626\u0649', michael@0: '\uFC69': '\u0626\u064A', michael@0: '\uFC6A': '\u0628\u0631', michael@0: '\uFC6B': '\u0628\u0632', michael@0: '\uFC6C': '\u0628\u0645', michael@0: '\uFC6D': '\u0628\u0646', michael@0: '\uFC6E': '\u0628\u0649', michael@0: '\uFC6F': '\u0628\u064A', michael@0: '\uFC70': '\u062A\u0631', michael@0: '\uFC71': '\u062A\u0632', michael@0: '\uFC72': '\u062A\u0645', michael@0: '\uFC73': '\u062A\u0646', michael@0: '\uFC74': '\u062A\u0649', michael@0: '\uFC75': '\u062A\u064A', michael@0: '\uFC76': '\u062B\u0631', michael@0: '\uFC77': '\u062B\u0632', michael@0: '\uFC78': '\u062B\u0645', michael@0: '\uFC79': '\u062B\u0646', michael@0: '\uFC7A': '\u062B\u0649', michael@0: '\uFC7B': '\u062B\u064A', michael@0: '\uFC7C': '\u0641\u0649', michael@0: '\uFC7D': '\u0641\u064A', michael@0: '\uFC7E': '\u0642\u0649', michael@0: '\uFC7F': '\u0642\u064A', michael@0: '\uFC80': '\u0643\u0627', michael@0: '\uFC81': '\u0643\u0644', michael@0: '\uFC82': '\u0643\u0645', michael@0: '\uFC83': '\u0643\u0649', michael@0: '\uFC84': '\u0643\u064A', michael@0: '\uFC85': '\u0644\u0645', michael@0: '\uFC86': '\u0644\u0649', michael@0: '\uFC87': '\u0644\u064A', michael@0: '\uFC88': '\u0645\u0627', michael@0: '\uFC89': '\u0645\u0645', michael@0: '\uFC8A': '\u0646\u0631', michael@0: '\uFC8B': '\u0646\u0632', michael@0: '\uFC8C': '\u0646\u0645', michael@0: '\uFC8D': '\u0646\u0646', michael@0: '\uFC8E': '\u0646\u0649', michael@0: '\uFC8F': '\u0646\u064A', michael@0: '\uFC90': '\u0649\u0670', michael@0: '\uFC91': '\u064A\u0631', michael@0: '\uFC92': '\u064A\u0632', michael@0: '\uFC93': '\u064A\u0645', michael@0: '\uFC94': '\u064A\u0646', michael@0: '\uFC95': '\u064A\u0649', michael@0: '\uFC96': '\u064A\u064A', michael@0: '\uFC97': '\u0626\u062C', michael@0: '\uFC98': '\u0626\u062D', michael@0: '\uFC99': '\u0626\u062E', michael@0: '\uFC9A': '\u0626\u0645', michael@0: '\uFC9B': '\u0626\u0647', michael@0: '\uFC9C': '\u0628\u062C', michael@0: '\uFC9D': '\u0628\u062D', michael@0: '\uFC9E': '\u0628\u062E', michael@0: '\uFC9F': '\u0628\u0645', michael@0: '\uFCA0': '\u0628\u0647', michael@0: '\uFCA1': '\u062A\u062C', michael@0: '\uFCA2': '\u062A\u062D', michael@0: '\uFCA3': '\u062A\u062E', michael@0: '\uFCA4': '\u062A\u0645', michael@0: '\uFCA5': '\u062A\u0647', michael@0: '\uFCA6': '\u062B\u0645', michael@0: '\uFCA7': '\u062C\u062D', michael@0: '\uFCA8': '\u062C\u0645', michael@0: '\uFCA9': '\u062D\u062C', michael@0: '\uFCAA': '\u062D\u0645', michael@0: '\uFCAB': '\u062E\u062C', michael@0: '\uFCAC': '\u062E\u0645', michael@0: '\uFCAD': '\u0633\u062C', michael@0: '\uFCAE': '\u0633\u062D', michael@0: '\uFCAF': '\u0633\u062E', michael@0: '\uFCB0': '\u0633\u0645', michael@0: '\uFCB1': '\u0635\u062D', michael@0: '\uFCB2': '\u0635\u062E', michael@0: '\uFCB3': '\u0635\u0645', michael@0: '\uFCB4': '\u0636\u062C', michael@0: '\uFCB5': '\u0636\u062D', michael@0: '\uFCB6': '\u0636\u062E', michael@0: '\uFCB7': '\u0636\u0645', michael@0: '\uFCB8': '\u0637\u062D', michael@0: '\uFCB9': '\u0638\u0645', michael@0: '\uFCBA': '\u0639\u062C', michael@0: '\uFCBB': '\u0639\u0645', michael@0: '\uFCBC': '\u063A\u062C', michael@0: '\uFCBD': '\u063A\u0645', michael@0: '\uFCBE': '\u0641\u062C', michael@0: '\uFCBF': '\u0641\u062D', michael@0: '\uFCC0': '\u0641\u062E', michael@0: '\uFCC1': '\u0641\u0645', michael@0: '\uFCC2': '\u0642\u062D', michael@0: '\uFCC3': '\u0642\u0645', michael@0: '\uFCC4': '\u0643\u062C', michael@0: '\uFCC5': '\u0643\u062D', michael@0: '\uFCC6': '\u0643\u062E', michael@0: '\uFCC7': '\u0643\u0644', michael@0: '\uFCC8': '\u0643\u0645', michael@0: '\uFCC9': '\u0644\u062C', michael@0: '\uFCCA': '\u0644\u062D', michael@0: '\uFCCB': '\u0644\u062E', michael@0: '\uFCCC': '\u0644\u0645', michael@0: '\uFCCD': '\u0644\u0647', michael@0: '\uFCCE': '\u0645\u062C', michael@0: '\uFCCF': '\u0645\u062D', michael@0: '\uFCD0': '\u0645\u062E', michael@0: '\uFCD1': '\u0645\u0645', michael@0: '\uFCD2': '\u0646\u062C', michael@0: '\uFCD3': '\u0646\u062D', michael@0: '\uFCD4': '\u0646\u062E', michael@0: '\uFCD5': '\u0646\u0645', michael@0: '\uFCD6': '\u0646\u0647', michael@0: '\uFCD7': '\u0647\u062C', michael@0: '\uFCD8': '\u0647\u0645', michael@0: '\uFCD9': '\u0647\u0670', michael@0: '\uFCDA': '\u064A\u062C', michael@0: '\uFCDB': '\u064A\u062D', michael@0: '\uFCDC': '\u064A\u062E', michael@0: '\uFCDD': '\u064A\u0645', michael@0: '\uFCDE': '\u064A\u0647', michael@0: '\uFCDF': '\u0626\u0645', michael@0: '\uFCE0': '\u0626\u0647', michael@0: '\uFCE1': '\u0628\u0645', michael@0: '\uFCE2': '\u0628\u0647', michael@0: '\uFCE3': '\u062A\u0645', michael@0: '\uFCE4': '\u062A\u0647', michael@0: '\uFCE5': '\u062B\u0645', michael@0: '\uFCE6': '\u062B\u0647', michael@0: '\uFCE7': '\u0633\u0645', michael@0: '\uFCE8': '\u0633\u0647', michael@0: '\uFCE9': '\u0634\u0645', michael@0: '\uFCEA': '\u0634\u0647', michael@0: '\uFCEB': '\u0643\u0644', michael@0: '\uFCEC': '\u0643\u0645', michael@0: '\uFCED': '\u0644\u0645', michael@0: '\uFCEE': '\u0646\u0645', michael@0: '\uFCEF': '\u0646\u0647', michael@0: '\uFCF0': '\u064A\u0645', michael@0: '\uFCF1': '\u064A\u0647', michael@0: '\uFCF2': '\u0640\u064E\u0651', michael@0: '\uFCF3': '\u0640\u064F\u0651', michael@0: '\uFCF4': '\u0640\u0650\u0651', michael@0: '\uFCF5': '\u0637\u0649', michael@0: '\uFCF6': '\u0637\u064A', michael@0: '\uFCF7': '\u0639\u0649', michael@0: '\uFCF8': '\u0639\u064A', michael@0: '\uFCF9': '\u063A\u0649', michael@0: '\uFCFA': '\u063A\u064A', michael@0: '\uFCFB': '\u0633\u0649', michael@0: '\uFCFC': '\u0633\u064A', michael@0: '\uFCFD': '\u0634\u0649', michael@0: '\uFCFE': '\u0634\u064A', michael@0: '\uFCFF': '\u062D\u0649', michael@0: '\uFD00': '\u062D\u064A', michael@0: '\uFD01': '\u062C\u0649', michael@0: '\uFD02': '\u062C\u064A', michael@0: '\uFD03': '\u062E\u0649', michael@0: '\uFD04': '\u062E\u064A', michael@0: '\uFD05': '\u0635\u0649', michael@0: '\uFD06': '\u0635\u064A', michael@0: '\uFD07': '\u0636\u0649', michael@0: '\uFD08': '\u0636\u064A', michael@0: '\uFD09': '\u0634\u062C', michael@0: '\uFD0A': '\u0634\u062D', michael@0: '\uFD0B': '\u0634\u062E', michael@0: '\uFD0C': '\u0634\u0645', michael@0: '\uFD0D': '\u0634\u0631', michael@0: '\uFD0E': '\u0633\u0631', michael@0: '\uFD0F': '\u0635\u0631', michael@0: '\uFD10': '\u0636\u0631', michael@0: '\uFD11': '\u0637\u0649', michael@0: '\uFD12': '\u0637\u064A', michael@0: '\uFD13': '\u0639\u0649', michael@0: '\uFD14': '\u0639\u064A', michael@0: '\uFD15': '\u063A\u0649', michael@0: '\uFD16': '\u063A\u064A', michael@0: '\uFD17': '\u0633\u0649', michael@0: '\uFD18': '\u0633\u064A', michael@0: '\uFD19': '\u0634\u0649', michael@0: '\uFD1A': '\u0634\u064A', michael@0: '\uFD1B': '\u062D\u0649', michael@0: '\uFD1C': '\u062D\u064A', michael@0: '\uFD1D': '\u062C\u0649', michael@0: '\uFD1E': '\u062C\u064A', michael@0: '\uFD1F': '\u062E\u0649', michael@0: '\uFD20': '\u062E\u064A', michael@0: '\uFD21': '\u0635\u0649', michael@0: '\uFD22': '\u0635\u064A', michael@0: '\uFD23': '\u0636\u0649', michael@0: '\uFD24': '\u0636\u064A', michael@0: '\uFD25': '\u0634\u062C', michael@0: '\uFD26': '\u0634\u062D', michael@0: '\uFD27': '\u0634\u062E', michael@0: '\uFD28': '\u0634\u0645', michael@0: '\uFD29': '\u0634\u0631', michael@0: '\uFD2A': '\u0633\u0631', michael@0: '\uFD2B': '\u0635\u0631', michael@0: '\uFD2C': '\u0636\u0631', michael@0: '\uFD2D': '\u0634\u062C', michael@0: '\uFD2E': '\u0634\u062D', michael@0: '\uFD2F': '\u0634\u062E', michael@0: '\uFD30': '\u0634\u0645', michael@0: '\uFD31': '\u0633\u0647', michael@0: '\uFD32': '\u0634\u0647', michael@0: '\uFD33': '\u0637\u0645', michael@0: '\uFD34': '\u0633\u062C', michael@0: '\uFD35': '\u0633\u062D', michael@0: '\uFD36': '\u0633\u062E', michael@0: '\uFD37': '\u0634\u062C', michael@0: '\uFD38': '\u0634\u062D', michael@0: '\uFD39': '\u0634\u062E', michael@0: '\uFD3A': '\u0637\u0645', michael@0: '\uFD3B': '\u0638\u0645', michael@0: '\uFD3C': '\u0627\u064B', michael@0: '\uFD3D': '\u0627\u064B', michael@0: '\uFD50': '\u062A\u062C\u0645', michael@0: '\uFD51': '\u062A\u062D\u062C', michael@0: '\uFD52': '\u062A\u062D\u062C', michael@0: '\uFD53': '\u062A\u062D\u0645', michael@0: '\uFD54': '\u062A\u062E\u0645', michael@0: '\uFD55': '\u062A\u0645\u062C', michael@0: '\uFD56': '\u062A\u0645\u062D', michael@0: '\uFD57': '\u062A\u0645\u062E', michael@0: '\uFD58': '\u062C\u0645\u062D', michael@0: '\uFD59': '\u062C\u0645\u062D', michael@0: '\uFD5A': '\u062D\u0645\u064A', michael@0: '\uFD5B': '\u062D\u0645\u0649', michael@0: '\uFD5C': '\u0633\u062D\u062C', michael@0: '\uFD5D': '\u0633\u062C\u062D', michael@0: '\uFD5E': '\u0633\u062C\u0649', michael@0: '\uFD5F': '\u0633\u0645\u062D', michael@0: '\uFD60': '\u0633\u0645\u062D', michael@0: '\uFD61': '\u0633\u0645\u062C', michael@0: '\uFD62': '\u0633\u0645\u0645', michael@0: '\uFD63': '\u0633\u0645\u0645', michael@0: '\uFD64': '\u0635\u062D\u062D', michael@0: '\uFD65': '\u0635\u062D\u062D', michael@0: '\uFD66': '\u0635\u0645\u0645', michael@0: '\uFD67': '\u0634\u062D\u0645', michael@0: '\uFD68': '\u0634\u062D\u0645', michael@0: '\uFD69': '\u0634\u062C\u064A', michael@0: '\uFD6A': '\u0634\u0645\u062E', michael@0: '\uFD6B': '\u0634\u0645\u062E', michael@0: '\uFD6C': '\u0634\u0645\u0645', michael@0: '\uFD6D': '\u0634\u0645\u0645', michael@0: '\uFD6E': '\u0636\u062D\u0649', michael@0: '\uFD6F': '\u0636\u062E\u0645', michael@0: '\uFD70': '\u0636\u062E\u0645', michael@0: '\uFD71': '\u0637\u0645\u062D', michael@0: '\uFD72': '\u0637\u0645\u062D', michael@0: '\uFD73': '\u0637\u0645\u0645', michael@0: '\uFD74': '\u0637\u0645\u064A', michael@0: '\uFD75': '\u0639\u062C\u0645', michael@0: '\uFD76': '\u0639\u0645\u0645', michael@0: '\uFD77': '\u0639\u0645\u0645', michael@0: '\uFD78': '\u0639\u0645\u0649', michael@0: '\uFD79': '\u063A\u0645\u0645', michael@0: '\uFD7A': '\u063A\u0645\u064A', michael@0: '\uFD7B': '\u063A\u0645\u0649', michael@0: '\uFD7C': '\u0641\u062E\u0645', michael@0: '\uFD7D': '\u0641\u062E\u0645', michael@0: '\uFD7E': '\u0642\u0645\u062D', michael@0: '\uFD7F': '\u0642\u0645\u0645', michael@0: '\uFD80': '\u0644\u062D\u0645', michael@0: '\uFD81': '\u0644\u062D\u064A', michael@0: '\uFD82': '\u0644\u062D\u0649', michael@0: '\uFD83': '\u0644\u062C\u062C', michael@0: '\uFD84': '\u0644\u062C\u062C', michael@0: '\uFD85': '\u0644\u062E\u0645', michael@0: '\uFD86': '\u0644\u062E\u0645', michael@0: '\uFD87': '\u0644\u0645\u062D', michael@0: '\uFD88': '\u0644\u0645\u062D', michael@0: '\uFD89': '\u0645\u062D\u062C', michael@0: '\uFD8A': '\u0645\u062D\u0645', michael@0: '\uFD8B': '\u0645\u062D\u064A', michael@0: '\uFD8C': '\u0645\u062C\u062D', michael@0: '\uFD8D': '\u0645\u062C\u0645', michael@0: '\uFD8E': '\u0645\u062E\u062C', michael@0: '\uFD8F': '\u0645\u062E\u0645', michael@0: '\uFD92': '\u0645\u062C\u062E', michael@0: '\uFD93': '\u0647\u0645\u062C', michael@0: '\uFD94': '\u0647\u0645\u0645', michael@0: '\uFD95': '\u0646\u062D\u0645', michael@0: '\uFD96': '\u0646\u062D\u0649', michael@0: '\uFD97': '\u0646\u062C\u0645', michael@0: '\uFD98': '\u0646\u062C\u0645', michael@0: '\uFD99': '\u0646\u062C\u0649', michael@0: '\uFD9A': '\u0646\u0645\u064A', michael@0: '\uFD9B': '\u0646\u0645\u0649', michael@0: '\uFD9C': '\u064A\u0645\u0645', michael@0: '\uFD9D': '\u064A\u0645\u0645', michael@0: '\uFD9E': '\u0628\u062E\u064A', michael@0: '\uFD9F': '\u062A\u062C\u064A', michael@0: '\uFDA0': '\u062A\u062C\u0649', michael@0: '\uFDA1': '\u062A\u062E\u064A', michael@0: '\uFDA2': '\u062A\u062E\u0649', michael@0: '\uFDA3': '\u062A\u0645\u064A', michael@0: '\uFDA4': '\u062A\u0645\u0649', michael@0: '\uFDA5': '\u062C\u0645\u064A', michael@0: '\uFDA6': '\u062C\u062D\u0649', michael@0: '\uFDA7': '\u062C\u0645\u0649', michael@0: '\uFDA8': '\u0633\u062E\u0649', michael@0: '\uFDA9': '\u0635\u062D\u064A', michael@0: '\uFDAA': '\u0634\u062D\u064A', michael@0: '\uFDAB': '\u0636\u062D\u064A', michael@0: '\uFDAC': '\u0644\u062C\u064A', michael@0: '\uFDAD': '\u0644\u0645\u064A', michael@0: '\uFDAE': '\u064A\u062D\u064A', michael@0: '\uFDAF': '\u064A\u062C\u064A', michael@0: '\uFDB0': '\u064A\u0645\u064A', michael@0: '\uFDB1': '\u0645\u0645\u064A', michael@0: '\uFDB2': '\u0642\u0645\u064A', michael@0: '\uFDB3': '\u0646\u062D\u064A', michael@0: '\uFDB4': '\u0642\u0645\u062D', michael@0: '\uFDB5': '\u0644\u062D\u0645', michael@0: '\uFDB6': '\u0639\u0645\u064A', michael@0: '\uFDB7': '\u0643\u0645\u064A', michael@0: '\uFDB8': '\u0646\u062C\u062D', michael@0: '\uFDB9': '\u0645\u062E\u064A', michael@0: '\uFDBA': '\u0644\u062C\u0645', michael@0: '\uFDBB': '\u0643\u0645\u0645', michael@0: '\uFDBC': '\u0644\u062C\u0645', michael@0: '\uFDBD': '\u0646\u062C\u062D', michael@0: '\uFDBE': '\u062C\u062D\u064A', michael@0: '\uFDBF': '\u062D\u062C\u064A', michael@0: '\uFDC0': '\u0645\u062C\u064A', michael@0: '\uFDC1': '\u0641\u0645\u064A', michael@0: '\uFDC2': '\u0628\u062D\u064A', michael@0: '\uFDC3': '\u0643\u0645\u0645', michael@0: '\uFDC4': '\u0639\u062C\u0645', michael@0: '\uFDC5': '\u0635\u0645\u0645', michael@0: '\uFDC6': '\u0633\u062E\u064A', michael@0: '\uFDC7': '\u0646\u062C\u064A', michael@0: '\uFE49': '\u203E', michael@0: '\uFE4A': '\u203E', michael@0: '\uFE4B': '\u203E', michael@0: '\uFE4C': '\u203E', michael@0: '\uFE4D': '\u005F', michael@0: '\uFE4E': '\u005F', michael@0: '\uFE4F': '\u005F', michael@0: '\uFE80': '\u0621', michael@0: '\uFE81': '\u0622', michael@0: '\uFE82': '\u0622', michael@0: '\uFE83': '\u0623', michael@0: '\uFE84': '\u0623', michael@0: '\uFE85': '\u0624', michael@0: '\uFE86': '\u0624', michael@0: '\uFE87': '\u0625', michael@0: '\uFE88': '\u0625', michael@0: '\uFE89': '\u0626', michael@0: '\uFE8A': '\u0626', michael@0: '\uFE8B': '\u0626', michael@0: '\uFE8C': '\u0626', michael@0: '\uFE8D': '\u0627', michael@0: '\uFE8E': '\u0627', michael@0: '\uFE8F': '\u0628', michael@0: '\uFE90': '\u0628', michael@0: '\uFE91': '\u0628', michael@0: '\uFE92': '\u0628', michael@0: '\uFE93': '\u0629', michael@0: '\uFE94': '\u0629', michael@0: '\uFE95': '\u062A', michael@0: '\uFE96': '\u062A', michael@0: '\uFE97': '\u062A', michael@0: '\uFE98': '\u062A', michael@0: '\uFE99': '\u062B', michael@0: '\uFE9A': '\u062B', michael@0: '\uFE9B': '\u062B', michael@0: '\uFE9C': '\u062B', michael@0: '\uFE9D': '\u062C', michael@0: '\uFE9E': '\u062C', michael@0: '\uFE9F': '\u062C', michael@0: '\uFEA0': '\u062C', michael@0: '\uFEA1': '\u062D', michael@0: '\uFEA2': '\u062D', michael@0: '\uFEA3': '\u062D', michael@0: '\uFEA4': '\u062D', michael@0: '\uFEA5': '\u062E', michael@0: '\uFEA6': '\u062E', michael@0: '\uFEA7': '\u062E', michael@0: '\uFEA8': '\u062E', michael@0: '\uFEA9': '\u062F', michael@0: '\uFEAA': '\u062F', michael@0: '\uFEAB': '\u0630', michael@0: '\uFEAC': '\u0630', michael@0: '\uFEAD': '\u0631', michael@0: '\uFEAE': '\u0631', michael@0: '\uFEAF': '\u0632', michael@0: '\uFEB0': '\u0632', michael@0: '\uFEB1': '\u0633', michael@0: '\uFEB2': '\u0633', michael@0: '\uFEB3': '\u0633', michael@0: '\uFEB4': '\u0633', michael@0: '\uFEB5': '\u0634', michael@0: '\uFEB6': '\u0634', michael@0: '\uFEB7': '\u0634', michael@0: '\uFEB8': '\u0634', michael@0: '\uFEB9': '\u0635', michael@0: '\uFEBA': '\u0635', michael@0: '\uFEBB': '\u0635', michael@0: '\uFEBC': '\u0635', michael@0: '\uFEBD': '\u0636', michael@0: '\uFEBE': '\u0636', michael@0: '\uFEBF': '\u0636', michael@0: '\uFEC0': '\u0636', michael@0: '\uFEC1': '\u0637', michael@0: '\uFEC2': '\u0637', michael@0: '\uFEC3': '\u0637', michael@0: '\uFEC4': '\u0637', michael@0: '\uFEC5': '\u0638', michael@0: '\uFEC6': '\u0638', michael@0: '\uFEC7': '\u0638', michael@0: '\uFEC8': '\u0638', michael@0: '\uFEC9': '\u0639', michael@0: '\uFECA': '\u0639', michael@0: '\uFECB': '\u0639', michael@0: '\uFECC': '\u0639', michael@0: '\uFECD': '\u063A', michael@0: '\uFECE': '\u063A', michael@0: '\uFECF': '\u063A', michael@0: '\uFED0': '\u063A', michael@0: '\uFED1': '\u0641', michael@0: '\uFED2': '\u0641', michael@0: '\uFED3': '\u0641', michael@0: '\uFED4': '\u0641', michael@0: '\uFED5': '\u0642', michael@0: '\uFED6': '\u0642', michael@0: '\uFED7': '\u0642', michael@0: '\uFED8': '\u0642', michael@0: '\uFED9': '\u0643', michael@0: '\uFEDA': '\u0643', michael@0: '\uFEDB': '\u0643', michael@0: '\uFEDC': '\u0643', michael@0: '\uFEDD': '\u0644', michael@0: '\uFEDE': '\u0644', michael@0: '\uFEDF': '\u0644', michael@0: '\uFEE0': '\u0644', michael@0: '\uFEE1': '\u0645', michael@0: '\uFEE2': '\u0645', michael@0: '\uFEE3': '\u0645', michael@0: '\uFEE4': '\u0645', michael@0: '\uFEE5': '\u0646', michael@0: '\uFEE6': '\u0646', michael@0: '\uFEE7': '\u0646', michael@0: '\uFEE8': '\u0646', michael@0: '\uFEE9': '\u0647', michael@0: '\uFEEA': '\u0647', michael@0: '\uFEEB': '\u0647', michael@0: '\uFEEC': '\u0647', michael@0: '\uFEED': '\u0648', michael@0: '\uFEEE': '\u0648', michael@0: '\uFEEF': '\u0649', michael@0: '\uFEF0': '\u0649', michael@0: '\uFEF1': '\u064A', michael@0: '\uFEF2': '\u064A', michael@0: '\uFEF3': '\u064A', michael@0: '\uFEF4': '\u064A', michael@0: '\uFEF5': '\u0644\u0622', michael@0: '\uFEF6': '\u0644\u0622', michael@0: '\uFEF7': '\u0644\u0623', michael@0: '\uFEF8': '\u0644\u0623', michael@0: '\uFEF9': '\u0644\u0625', michael@0: '\uFEFA': '\u0644\u0625', michael@0: '\uFEFB': '\u0644\u0627', michael@0: '\uFEFC': '\u0644\u0627' michael@0: }; michael@0: michael@0: function reverseIfRtl(chars) { michael@0: var charsLength = chars.length; michael@0: //reverse an arabic ligature michael@0: if (charsLength <= 1 || !isRTLRangeFor(chars.charCodeAt(0))) { michael@0: return chars; michael@0: } michael@0: var s = ''; michael@0: for (var ii = charsLength - 1; ii >= 0; ii--) { michael@0: s += chars[ii]; michael@0: } michael@0: return s; michael@0: } michael@0: michael@0: function adjustWidths(properties) { michael@0: if (properties.fontMatrix[0] === FONT_IDENTITY_MATRIX[0]) { michael@0: return; michael@0: } michael@0: // adjusting width to fontMatrix scale michael@0: var scale = 0.001 / properties.fontMatrix[0]; michael@0: var glyphsWidths = properties.widths; michael@0: for (var glyph in glyphsWidths) { michael@0: glyphsWidths[glyph] *= scale; michael@0: } michael@0: properties.defaultWidth *= scale; michael@0: } michael@0: michael@0: var Glyph = (function GlyphClosure() { michael@0: function Glyph(fontChar, unicode, accent, width, vmetric, operatorList) { michael@0: this.fontChar = fontChar; michael@0: this.unicode = unicode; michael@0: this.accent = accent; michael@0: this.width = width; michael@0: this.vmetric = vmetric; michael@0: this.operatorList = operatorList; michael@0: } michael@0: michael@0: Glyph.prototype.matchesForCache = michael@0: function(fontChar, unicode, accent, width, vmetric, operatorList) { michael@0: return this.fontChar === fontChar && michael@0: this.unicode === unicode && michael@0: this.accent === accent && michael@0: this.width === width && michael@0: this.vmetric === vmetric && michael@0: this.operatorList === operatorList; michael@0: }; michael@0: michael@0: return Glyph; michael@0: })(); michael@0: michael@0: /** michael@0: * 'Font' is the class the outside world should use, it encapsulate all the font michael@0: * decoding logics whatever type it is (assuming the font type is supported). michael@0: * michael@0: * For example to read a Type1 font and to attach it to the document: michael@0: * var type1Font = new Font("MyFontName", binaryFile, propertiesObject); michael@0: * type1Font.bind(); michael@0: */ michael@0: var Font = (function FontClosure() { michael@0: function Font(name, file, properties) { michael@0: var charCode; michael@0: michael@0: this.name = name; michael@0: this.loadedName = properties.loadedName; michael@0: this.coded = properties.coded; michael@0: this.loadCharProcs = properties.coded; michael@0: this.sizes = []; michael@0: michael@0: this.glyphCache = {}; michael@0: michael@0: var names = name.split('+'); michael@0: names = names.length > 1 ? names[1] : names[0]; michael@0: names = names.split(/[-,_]/g)[0]; michael@0: this.isSerifFont = !!(properties.flags & FontFlags.Serif); michael@0: this.isSymbolicFont = !!(properties.flags & FontFlags.Symbolic); michael@0: this.isMonospace = !!(properties.flags & FontFlags.FixedPitch); michael@0: michael@0: var type = properties.type; michael@0: this.type = type; michael@0: michael@0: this.fallbackName = (this.isMonospace ? 'monospace' : michael@0: (this.isSerifFont ? 'serif' : 'sans-serif')); michael@0: michael@0: this.differences = properties.differences; michael@0: this.widths = properties.widths; michael@0: this.defaultWidth = properties.defaultWidth; michael@0: this.composite = properties.composite; michael@0: this.wideChars = properties.wideChars; michael@0: this.cMap = properties.cMap; michael@0: this.ascent = properties.ascent / PDF_GLYPH_SPACE_UNITS; michael@0: this.descent = properties.descent / PDF_GLYPH_SPACE_UNITS; michael@0: this.fontMatrix = properties.fontMatrix; michael@0: michael@0: var unicode = this.buildToUnicode(properties); michael@0: this.toUnicode = properties.toUnicode = unicode.toUnicode; michael@0: this.isIdentityUnicode = properties.isIdentityUnicode = unicode.isIdentity; michael@0: michael@0: this.toFontChar = []; michael@0: michael@0: if (properties.type == 'Type3') { michael@0: for (charCode = 0; charCode < 256; charCode++) { michael@0: this.toFontChar[charCode] = (this.differences[charCode] || michael@0: properties.defaultEncoding[charCode]); michael@0: } michael@0: return; michael@0: } michael@0: michael@0: this.cidEncoding = properties.cidEncoding; michael@0: this.vertical = properties.vertical; michael@0: if (this.vertical) { michael@0: this.vmetrics = properties.vmetrics; michael@0: this.defaultVMetrics = properties.defaultVMetrics; michael@0: } michael@0: michael@0: if (!file) { michael@0: this.missingFile = true; michael@0: // The file data is not specified. Trying to fix the font name michael@0: // to be used with the canvas.font. michael@0: var fontName = name.replace(/[,_]/g, '-'); michael@0: var isStandardFont = fontName in stdFontMap; michael@0: fontName = stdFontMap[fontName] || nonStdFontMap[fontName] || fontName; michael@0: michael@0: this.bold = (fontName.search(/bold/gi) != -1); michael@0: this.italic = ((fontName.search(/oblique/gi) != -1) || michael@0: (fontName.search(/italic/gi) != -1)); michael@0: michael@0: // Use 'name' instead of 'fontName' here because the original michael@0: // name ArialBlack for example will be replaced by Helvetica. michael@0: this.black = (name.search(/Black/g) != -1); michael@0: michael@0: // if at least one width is present, remeasure all chars when exists michael@0: this.remeasure = Object.keys(this.widths).length > 0; michael@0: if (isStandardFont && type === 'CIDFontType2' && michael@0: properties.cidEncoding.indexOf('Identity-') === 0) { michael@0: // Standard fonts might be embedded as CID font without glyph mapping. michael@0: // Building one based on GlyphMapForStandardFonts. michael@0: var map = []; michael@0: for (var code in GlyphMapForStandardFonts) { michael@0: map[+code] = GlyphMapForStandardFonts[code]; michael@0: } michael@0: this.toFontChar = map; michael@0: this.toUnicode = map; michael@0: } else if (/Symbol/i.test(fontName)) { michael@0: var symbols = Encodings.SymbolSetEncoding; michael@0: for (charCode in symbols) { michael@0: var fontChar = GlyphsUnicode[symbols[charCode]]; michael@0: if (!fontChar) { michael@0: continue; michael@0: } michael@0: this.toFontChar[charCode] = fontChar; michael@0: } michael@0: } else if (isStandardFont) { michael@0: this.toFontChar = []; michael@0: for (charCode in properties.defaultEncoding) { michael@0: var glyphName = properties.differences[charCode] || michael@0: properties.defaultEncoding[charCode]; michael@0: this.toFontChar[charCode] = GlyphsUnicode[glyphName]; michael@0: } michael@0: } else { michael@0: for (charCode in this.toUnicode) { michael@0: this.toFontChar[charCode] = this.toUnicode[charCode].charCodeAt(0); michael@0: } michael@0: } michael@0: this.loadedName = fontName.split('-')[0]; michael@0: this.loading = false; michael@0: return; michael@0: } michael@0: michael@0: // Some fonts might use wrong font types for Type1C or CIDFontType0C michael@0: var subtype = properties.subtype; michael@0: if (subtype == 'Type1C' && (type != 'Type1' && type != 'MMType1')) { michael@0: type = 'Type1'; michael@0: } michael@0: if (subtype == 'CIDFontType0C' && type != 'CIDFontType0') { michael@0: type = 'CIDFontType0'; michael@0: } michael@0: // XXX: Temporarily change the type for open type so we trigger a warning. michael@0: // This should be removed when we add support for open type. michael@0: if (subtype === 'OpenType') { michael@0: type = 'OpenType'; michael@0: } michael@0: michael@0: var data; michael@0: switch (type) { michael@0: case 'Type1': michael@0: case 'CIDFontType0': michael@0: this.mimetype = 'font/opentype'; michael@0: michael@0: var cff = (subtype == 'Type1C' || subtype == 'CIDFontType0C') ? michael@0: new CFFFont(file, properties) : new Type1Font(name, file, properties); michael@0: michael@0: adjustWidths(properties); michael@0: michael@0: // Wrap the CFF data inside an OTF font file michael@0: data = this.convert(name, cff, properties); michael@0: break; michael@0: michael@0: case 'OpenType': michael@0: case 'TrueType': michael@0: case 'CIDFontType2': michael@0: this.mimetype = 'font/opentype'; michael@0: michael@0: // Repair the TrueType file. It is can be damaged in the point of michael@0: // view of the sanitizer michael@0: data = this.checkAndRepair(name, file, properties); michael@0: break; michael@0: michael@0: default: michael@0: error('Font ' + type + ' is not supported'); michael@0: break; michael@0: } michael@0: michael@0: this.data = data; michael@0: michael@0: // Transfer some properties again that could change during font conversion michael@0: this.fontMatrix = properties.fontMatrix; michael@0: this.widths = properties.widths; michael@0: this.defaultWidth = properties.defaultWidth; michael@0: this.encoding = properties.baseEncoding; michael@0: this.seacMap = properties.seacMap; michael@0: michael@0: this.loading = true; michael@0: } michael@0: michael@0: Font.getFontID = (function () { michael@0: var ID = 1; michael@0: return function Font_getFontID() { michael@0: return String(ID++); michael@0: }; michael@0: })(); michael@0: michael@0: function int16(b0, b1) { michael@0: return (b0 << 8) + b1; michael@0: } michael@0: michael@0: function int32(b0, b1, b2, b3) { michael@0: return (b0 << 24) + (b1 << 16) + (b2 << 8) + b3; michael@0: } michael@0: michael@0: function getMaxPower2(number) { michael@0: var maxPower = 0; michael@0: var value = number; michael@0: while (value >= 2) { michael@0: value /= 2; michael@0: maxPower++; michael@0: } michael@0: michael@0: value = 2; michael@0: for (var i = 1; i < maxPower; i++) { michael@0: value *= 2; michael@0: } michael@0: return value; michael@0: } michael@0: michael@0: function string16(value) { michael@0: return String.fromCharCode((value >> 8) & 0xff, value & 0xff); michael@0: } michael@0: michael@0: function safeString16(value) { michael@0: // clamp value to the 16-bit int range michael@0: value = (value > 0x7FFF ? 0x7FFF : (value < -0x8000 ? -0x8000 : value)); michael@0: return String.fromCharCode((value >> 8) & 0xff, value & 0xff); michael@0: } michael@0: michael@0: function createOpenTypeHeader(sfnt, file, numTables) { michael@0: // Windows hates the Mac TrueType sfnt version number michael@0: if (sfnt == 'true') { michael@0: sfnt = string32(0x00010000); michael@0: } michael@0: michael@0: // sfnt version (4 bytes) michael@0: var header = sfnt; michael@0: michael@0: // numTables (2 bytes) michael@0: header += string16(numTables); michael@0: michael@0: // searchRange (2 bytes) michael@0: var tablesMaxPower2 = getMaxPower2(numTables); michael@0: var searchRange = tablesMaxPower2 * 16; michael@0: header += string16(searchRange); michael@0: michael@0: // entrySelector (2 bytes) michael@0: header += string16(Math.log(tablesMaxPower2) / Math.log(2)); michael@0: michael@0: // rangeShift (2 bytes) michael@0: header += string16(numTables * 16 - searchRange); michael@0: michael@0: file.file += header; michael@0: file.virtualOffset += header.length; michael@0: } michael@0: michael@0: function createTableEntry(file, tag, data) { michael@0: // offset michael@0: var offset = file.virtualOffset; michael@0: michael@0: // length michael@0: var length = data.length; michael@0: michael@0: // Per spec tables must be 4-bytes align so add padding as needed michael@0: while (data.length & 3) { michael@0: data.push(0x00); michael@0: } michael@0: while (file.virtualOffset & 3) { michael@0: file.virtualOffset++; michael@0: } michael@0: michael@0: // checksum michael@0: var checksum = 0, n = data.length; michael@0: for (var i = 0; i < n; i += 4) { michael@0: checksum = (checksum + int32(data[i], data[i + 1], data[i + 2], michael@0: data[i + 3])) | 0; michael@0: } michael@0: michael@0: var tableEntry = (tag + string32(checksum) + michael@0: string32(offset) + string32(length)); michael@0: file.file += tableEntry; michael@0: file.virtualOffset += data.length; michael@0: } michael@0: michael@0: /** michael@0: * Rebuilds the char code to glyph ID map by trying to replace the char codes michael@0: * with their unicode value. It also moves char codes that are in known michael@0: * problematic locations. michael@0: * @return {Object} Two properties: michael@0: * 'toFontChar' - maps original char codes(the value that will be read michael@0: * from commands such as show text) to the char codes that will be used in the michael@0: * font that we build michael@0: * 'charCodeToGlyphId' - maps the new font char codes to glyph ids michael@0: */ michael@0: function adjustMapping(charCodeToGlyphId, properties) { michael@0: var toUnicode = properties.toUnicode; michael@0: var isSymbolic = !!(properties.flags & FontFlags.Symbolic); michael@0: var isIdentityUnicode = properties.isIdentityUnicode; michael@0: var newMap = Object.create(null); michael@0: var toFontChar = []; michael@0: var usedFontCharCodes = []; michael@0: var nextAvailableFontCharCode = PRIVATE_USE_OFFSET_START; michael@0: for (var originalCharCode in charCodeToGlyphId) { michael@0: originalCharCode |= 0; michael@0: var glyphId = charCodeToGlyphId[originalCharCode]; michael@0: var fontCharCode = originalCharCode; michael@0: // First try to map the value to a unicode position if a non identity map michael@0: // was created. michael@0: if (!isIdentityUnicode && originalCharCode in toUnicode) { michael@0: var unicode = toUnicode[fontCharCode]; michael@0: // TODO: Try to map ligatures to the correct spot. michael@0: if (unicode.length === 1) { michael@0: fontCharCode = unicode.charCodeAt(0); michael@0: } michael@0: } michael@0: // Try to move control characters, special characters and already mapped michael@0: // characters to the private use area since they will not be drawn by michael@0: // canvas if left in their current position. Also, move characters if the michael@0: // font was symbolic and there is only an identity unicode map since the michael@0: // characters probably aren't in the correct position (fixes an issue michael@0: // with firefox and thuluthfont). michael@0: if ((fontCharCode in usedFontCharCodes || michael@0: fontCharCode <= 0x1f || // Control chars michael@0: fontCharCode === 0x7F || // Control char michael@0: fontCharCode === 0xAD || // Soft hyphen michael@0: (fontCharCode >= 0x80 && fontCharCode <= 0x9F) || // Control chars michael@0: (isSymbolic && isIdentityUnicode)) && michael@0: nextAvailableFontCharCode <= PRIVATE_USE_OFFSET_END) { // Room left. michael@0: // Loop to try and find a free spot in the private use area. michael@0: do { michael@0: fontCharCode = nextAvailableFontCharCode++; michael@0: michael@0: if (SKIP_PRIVATE_USE_RANGE_F000_TO_F01F && fontCharCode === 0xF000) { michael@0: fontCharCode = 0xF020; michael@0: nextAvailableFontCharCode = fontCharCode + 1; michael@0: } michael@0: michael@0: } while (fontCharCode in usedFontCharCodes && michael@0: nextAvailableFontCharCode <= PRIVATE_USE_OFFSET_END); michael@0: } michael@0: michael@0: newMap[fontCharCode] = glyphId; michael@0: toFontChar[originalCharCode] = fontCharCode; michael@0: usedFontCharCodes[fontCharCode] = true; michael@0: } michael@0: return { michael@0: toFontChar: toFontChar, michael@0: charCodeToGlyphId: newMap, michael@0: nextAvailableFontCharCode: nextAvailableFontCharCode michael@0: }; michael@0: } michael@0: michael@0: function getRanges(glyphs) { michael@0: // Array.sort() sorts by characters, not numerically, so convert to an michael@0: // array of characters. michael@0: var codes = []; michael@0: for (var charCode in glyphs) { michael@0: codes.push({ fontCharCode: charCode | 0, glyphId: glyphs[charCode] }); michael@0: } michael@0: codes.sort(function fontGetRangesSort(a, b) { michael@0: return a.fontCharCode - b.fontCharCode; michael@0: }); michael@0: michael@0: // Split the sorted codes into ranges. michael@0: var ranges = []; michael@0: var length = codes.length; michael@0: for (var n = 0; n < length; ) { michael@0: var start = codes[n].fontCharCode; michael@0: var codeIndices = [codes[n].glyphId]; michael@0: ++n; michael@0: var end = start; michael@0: while (n < length && end + 1 == codes[n].fontCharCode) { michael@0: codeIndices.push(codes[n].glyphId); michael@0: ++end; michael@0: ++n; michael@0: if (end === 0xFFFF) { michael@0: break; michael@0: } michael@0: } michael@0: ranges.push([start, end, codeIndices]); michael@0: } michael@0: michael@0: return ranges; michael@0: } michael@0: michael@0: function createCmapTable(glyphs) { michael@0: var ranges = getRanges(glyphs); michael@0: var numTables = ranges[ranges.length - 1][1] > 0xFFFF ? 2 : 1; michael@0: var cmap = '\x00\x00' + // version michael@0: string16(numTables) + // numTables michael@0: '\x00\x03' + // platformID michael@0: '\x00\x01' + // encodingID michael@0: string32(4 + numTables * 8); // start of the table record michael@0: michael@0: var i, ii, j, jj; michael@0: for (i = ranges.length - 1; i >= 0; --i) { michael@0: if (ranges[i][0] <= 0xFFFF) { break; } michael@0: } michael@0: var bmpLength = i + 1; michael@0: michael@0: if (ranges[i][0] < 0xFFFF && ranges[i][1] === 0xFFFF) { michael@0: ranges[i][1] = 0xFFFE; michael@0: } michael@0: var trailingRangesCount = ranges[i][1] < 0xFFFF ? 1 : 0; michael@0: var segCount = bmpLength + trailingRangesCount; michael@0: var segCount2 = segCount * 2; michael@0: var searchRange = getMaxPower2(segCount) * 2; michael@0: var searchEntry = Math.log(segCount) / Math.log(2); michael@0: var rangeShift = 2 * segCount - searchRange; michael@0: michael@0: // Fill up the 4 parallel arrays describing the segments. michael@0: var startCount = ''; michael@0: var endCount = ''; michael@0: var idDeltas = ''; michael@0: var idRangeOffsets = ''; michael@0: var glyphsIds = ''; michael@0: var bias = 0; michael@0: michael@0: var range, start, end, codes; michael@0: for (i = 0, ii = bmpLength; i < ii; i++) { michael@0: range = ranges[i]; michael@0: start = range[0]; michael@0: end = range[1]; michael@0: startCount += string16(start); michael@0: endCount += string16(end); michael@0: codes = range[2]; michael@0: var contiguous = true; michael@0: for (j = 1, jj = codes.length; j < jj; ++j) { michael@0: if (codes[j] !== codes[j - 1] + 1) { michael@0: contiguous = false; michael@0: break; michael@0: } michael@0: } michael@0: if (!contiguous) { michael@0: var offset = (segCount - i) * 2 + bias * 2; michael@0: bias += (end - start + 1); michael@0: michael@0: idDeltas += string16(0); michael@0: idRangeOffsets += string16(offset); michael@0: michael@0: for (j = 0, jj = codes.length; j < jj; ++j) { michael@0: glyphsIds += string16(codes[j]); michael@0: } michael@0: } else { michael@0: var startCode = codes[0]; michael@0: michael@0: idDeltas += string16((startCode - start) & 0xFFFF); michael@0: idRangeOffsets += string16(0); michael@0: } michael@0: } michael@0: michael@0: if (trailingRangesCount > 0) { michael@0: endCount += '\xFF\xFF'; michael@0: startCount += '\xFF\xFF'; michael@0: idDeltas += '\x00\x01'; michael@0: idRangeOffsets += '\x00\x00'; michael@0: } michael@0: michael@0: var format314 = '\x00\x00' + // language michael@0: string16(segCount2) + michael@0: string16(searchRange) + michael@0: string16(searchEntry) + michael@0: string16(rangeShift) + michael@0: endCount + '\x00\x00' + startCount + michael@0: idDeltas + idRangeOffsets + glyphsIds; michael@0: michael@0: var format31012 = ''; michael@0: var header31012 = ''; michael@0: if (numTables > 1) { michael@0: cmap += '\x00\x03' + // platformID michael@0: '\x00\x0A' + // encodingID michael@0: string32(4 + numTables * 8 + michael@0: 4 + format314.length); // start of the table record michael@0: format31012 = ''; michael@0: for (i = 0, ii = ranges.length; i < ii; i++) { michael@0: range = ranges[i]; michael@0: start = range[0]; michael@0: codes = range[2]; michael@0: var code = codes[0]; michael@0: for (j = 1, jj = codes.length; j < jj; ++j) { michael@0: if (codes[j] !== codes[j - 1] + 1) { michael@0: end = range[0] + j - 1; michael@0: format31012 += string32(start) + // startCharCode michael@0: string32(end) + // endCharCode michael@0: string32(code); // startGlyphID michael@0: start = end + 1; michael@0: code = codes[j]; michael@0: } michael@0: } michael@0: format31012 += string32(start) + // startCharCode michael@0: string32(range[1]) + // endCharCode michael@0: string32(code); // startGlyphID michael@0: } michael@0: header31012 = '\x00\x0C' + // format michael@0: '\x00\x00' + // reserved michael@0: string32(format31012.length + 16) + // length michael@0: '\x00\x00\x00\x00' + // language michael@0: string32(format31012.length / 12); // nGroups michael@0: } michael@0: michael@0: return stringToArray(cmap + michael@0: '\x00\x04' + // format michael@0: string16(format314.length + 4) + // length michael@0: format314 + header31012 + format31012); michael@0: } michael@0: michael@0: function validateOS2Table(os2) { michael@0: var stream = new Stream(os2.data); michael@0: var version = stream.getUint16(); michael@0: // TODO verify all OS/2 tables fields, but currently we validate only those michael@0: // that give us issues michael@0: stream.getBytes(60); // skipping type, misc sizes, panose, unicode ranges michael@0: var selection = stream.getUint16(); michael@0: if (version < 4 && (selection & 0x0300)) { michael@0: return false; michael@0: } michael@0: var firstChar = stream.getUint16(); michael@0: var lastChar = stream.getUint16(); michael@0: if (firstChar > lastChar) { michael@0: return false; michael@0: } michael@0: stream.getBytes(6); // skipping sTypoAscender/Descender/LineGap michael@0: var usWinAscent = stream.getUint16(); michael@0: if (usWinAscent === 0) { // makes font unreadable by windows michael@0: return false; michael@0: } michael@0: michael@0: // OS/2 appears to be valid, resetting some fields michael@0: os2.data[8] = os2.data[9] = 0; // IE rejects fonts if fsType != 0 michael@0: return true; michael@0: } michael@0: michael@0: function createOS2Table(properties, charstrings, override) { michael@0: override = override || { michael@0: unitsPerEm: 0, michael@0: yMax: 0, michael@0: yMin: 0, michael@0: ascent: 0, michael@0: descent: 0 michael@0: }; michael@0: michael@0: var ulUnicodeRange1 = 0; michael@0: var ulUnicodeRange2 = 0; michael@0: var ulUnicodeRange3 = 0; michael@0: var ulUnicodeRange4 = 0; michael@0: michael@0: var firstCharIndex = null; michael@0: var lastCharIndex = 0; michael@0: michael@0: if (charstrings) { michael@0: for (var code in charstrings) { michael@0: code |= 0; michael@0: if (firstCharIndex > code || !firstCharIndex) { michael@0: firstCharIndex = code; michael@0: } michael@0: if (lastCharIndex < code) { michael@0: lastCharIndex = code; michael@0: } michael@0: michael@0: var position = getUnicodeRangeFor(code); michael@0: if (position < 32) { michael@0: ulUnicodeRange1 |= 1 << position; michael@0: } else if (position < 64) { michael@0: ulUnicodeRange2 |= 1 << position - 32; michael@0: } else if (position < 96) { michael@0: ulUnicodeRange3 |= 1 << position - 64; michael@0: } else if (position < 123) { michael@0: ulUnicodeRange4 |= 1 << position - 96; michael@0: } else { michael@0: error('Unicode ranges Bits > 123 are reserved for internal usage'); michael@0: } michael@0: } michael@0: } else { michael@0: // TODO michael@0: firstCharIndex = 0; michael@0: lastCharIndex = 255; michael@0: } michael@0: michael@0: var bbox = properties.bbox || [0, 0, 0, 0]; michael@0: var unitsPerEm = (override.unitsPerEm || michael@0: 1 / (properties.fontMatrix || FONT_IDENTITY_MATRIX)[0]); michael@0: michael@0: // if the font units differ to the PDF glyph space units michael@0: // then scale up the values michael@0: var scale = (properties.ascentScaled ? 1.0 : michael@0: unitsPerEm / PDF_GLYPH_SPACE_UNITS); michael@0: michael@0: var typoAscent = (override.ascent || michael@0: Math.round(scale * (properties.ascent || bbox[3]))); michael@0: var typoDescent = (override.descent || michael@0: Math.round(scale * (properties.descent || bbox[1]))); michael@0: if (typoDescent > 0 && properties.descent > 0 && bbox[1] < 0) { michael@0: typoDescent = -typoDescent; // fixing incorrect descent michael@0: } michael@0: var winAscent = override.yMax || typoAscent; michael@0: var winDescent = -override.yMin || -typoDescent; michael@0: michael@0: return '\x00\x03' + // version michael@0: '\x02\x24' + // xAvgCharWidth michael@0: '\x01\xF4' + // usWeightClass michael@0: '\x00\x05' + // usWidthClass michael@0: '\x00\x00' + // fstype (0 to let the font loads via font-face on IE) michael@0: '\x02\x8A' + // ySubscriptXSize michael@0: '\x02\xBB' + // ySubscriptYSize michael@0: '\x00\x00' + // ySubscriptXOffset michael@0: '\x00\x8C' + // ySubscriptYOffset michael@0: '\x02\x8A' + // ySuperScriptXSize michael@0: '\x02\xBB' + // ySuperScriptYSize michael@0: '\x00\x00' + // ySuperScriptXOffset michael@0: '\x01\xDF' + // ySuperScriptYOffset michael@0: '\x00\x31' + // yStrikeOutSize michael@0: '\x01\x02' + // yStrikeOutPosition michael@0: '\x00\x00' + // sFamilyClass michael@0: '\x00\x00\x06' + michael@0: String.fromCharCode(properties.fixedPitch ? 0x09 : 0x00) + michael@0: '\x00\x00\x00\x00\x00\x00' + // Panose michael@0: string32(ulUnicodeRange1) + // ulUnicodeRange1 (Bits 0-31) michael@0: string32(ulUnicodeRange2) + // ulUnicodeRange2 (Bits 32-63) michael@0: string32(ulUnicodeRange3) + // ulUnicodeRange3 (Bits 64-95) michael@0: string32(ulUnicodeRange4) + // ulUnicodeRange4 (Bits 96-127) michael@0: '\x2A\x32\x31\x2A' + // achVendID michael@0: string16(properties.italicAngle ? 1 : 0) + // fsSelection michael@0: string16(firstCharIndex || michael@0: properties.firstChar) + // usFirstCharIndex michael@0: string16(lastCharIndex || properties.lastChar) + // usLastCharIndex michael@0: string16(typoAscent) + // sTypoAscender michael@0: string16(typoDescent) + // sTypoDescender michael@0: '\x00\x64' + // sTypoLineGap (7%-10% of the unitsPerEM value) michael@0: string16(winAscent) + // usWinAscent michael@0: string16(winDescent) + // usWinDescent michael@0: '\x00\x00\x00\x00' + // ulCodePageRange1 (Bits 0-31) michael@0: '\x00\x00\x00\x00' + // ulCodePageRange2 (Bits 32-63) michael@0: string16(properties.xHeight) + // sxHeight michael@0: string16(properties.capHeight) + // sCapHeight michael@0: string16(0) + // usDefaultChar michael@0: string16(firstCharIndex || properties.firstChar) + // usBreakChar michael@0: '\x00\x03'; // usMaxContext michael@0: } michael@0: michael@0: function createPostTable(properties) { michael@0: var angle = Math.floor(properties.italicAngle * (Math.pow(2, 16))); michael@0: return ('\x00\x03\x00\x00' + // Version number michael@0: string32(angle) + // italicAngle michael@0: '\x00\x00' + // underlinePosition michael@0: '\x00\x00' + // underlineThickness michael@0: string32(properties.fixedPitch) + // isFixedPitch michael@0: '\x00\x00\x00\x00' + // minMemType42 michael@0: '\x00\x00\x00\x00' + // maxMemType42 michael@0: '\x00\x00\x00\x00' + // minMemType1 michael@0: '\x00\x00\x00\x00'); // maxMemType1 michael@0: } michael@0: michael@0: function createNameTable(name, proto) { michael@0: if (!proto) { michael@0: proto = [[], []]; // no strings and unicode strings michael@0: } michael@0: michael@0: var strings = [ michael@0: proto[0][0] || 'Original licence', // 0.Copyright michael@0: proto[0][1] || name, // 1.Font family michael@0: proto[0][2] || 'Unknown', // 2.Font subfamily (font weight) michael@0: proto[0][3] || 'uniqueID', // 3.Unique ID michael@0: proto[0][4] || name, // 4.Full font name michael@0: proto[0][5] || 'Version 0.11', // 5.Version michael@0: proto[0][6] || '', // 6.Postscript name michael@0: proto[0][7] || 'Unknown', // 7.Trademark michael@0: proto[0][8] || 'Unknown', // 8.Manufacturer michael@0: proto[0][9] || 'Unknown' // 9.Designer michael@0: ]; michael@0: michael@0: // Mac want 1-byte per character strings while Windows want michael@0: // 2-bytes per character, so duplicate the names table michael@0: var stringsUnicode = []; michael@0: var i, ii, j, jj, str; michael@0: for (i = 0, ii = strings.length; i < ii; i++) { michael@0: str = proto[1][i] || strings[i]; michael@0: michael@0: var strBufUnicode = []; michael@0: for (j = 0, jj = str.length; j < jj; j++) { michael@0: strBufUnicode.push(string16(str.charCodeAt(j))); michael@0: } michael@0: stringsUnicode.push(strBufUnicode.join('')); michael@0: } michael@0: michael@0: var names = [strings, stringsUnicode]; michael@0: var platforms = ['\x00\x01', '\x00\x03']; michael@0: var encodings = ['\x00\x00', '\x00\x01']; michael@0: var languages = ['\x00\x00', '\x04\x09']; michael@0: michael@0: var namesRecordCount = strings.length * platforms.length; michael@0: var nameTable = michael@0: '\x00\x00' + // format michael@0: string16(namesRecordCount) + // Number of names Record michael@0: string16(namesRecordCount * 12 + 6); // Storage michael@0: michael@0: // Build the name records field michael@0: var strOffset = 0; michael@0: for (i = 0, ii = platforms.length; i < ii; i++) { michael@0: var strs = names[i]; michael@0: for (j = 0, jj = strs.length; j < jj; j++) { michael@0: str = strs[j]; michael@0: var nameRecord = michael@0: platforms[i] + // platform ID michael@0: encodings[i] + // encoding ID michael@0: languages[i] + // language ID michael@0: string16(j) + // name ID michael@0: string16(str.length) + michael@0: string16(strOffset); michael@0: nameTable += nameRecord; michael@0: strOffset += str.length; michael@0: } michael@0: } michael@0: michael@0: nameTable += strings.join('') + stringsUnicode.join(''); michael@0: return nameTable; michael@0: } michael@0: michael@0: Font.prototype = { michael@0: name: null, michael@0: font: null, michael@0: mimetype: null, michael@0: encoding: null, michael@0: get renderer() { michael@0: var renderer = FontRendererFactory.create(this); michael@0: return shadow(this, 'renderer', renderer); michael@0: }, michael@0: michael@0: exportData: function Font_exportData() { michael@0: var data = {}; michael@0: for (var i in this) { michael@0: if (this.hasOwnProperty(i)) { michael@0: data[i] = this[i]; michael@0: } michael@0: } michael@0: return data; michael@0: }, michael@0: michael@0: checkAndRepair: function Font_checkAndRepair(name, font, properties) { michael@0: function readTableEntry(file) { michael@0: var tag = bytesToString(file.getBytes(4)); michael@0: michael@0: var checksum = file.getInt32(); michael@0: var offset = file.getInt32() >>> 0; michael@0: var length = file.getInt32() >>> 0; michael@0: michael@0: // Read the table associated data michael@0: var previousPosition = file.pos; michael@0: file.pos = file.start ? file.start : 0; michael@0: file.skip(offset); michael@0: var data = file.getBytes(length); michael@0: file.pos = previousPosition; michael@0: michael@0: if (tag == 'head') { michael@0: // clearing checksum adjustment michael@0: data[8] = data[9] = data[10] = data[11] = 0; michael@0: data[17] |= 0x20; //Set font optimized for cleartype flag michael@0: } michael@0: michael@0: return { michael@0: tag: tag, michael@0: checksum: checksum, michael@0: length: length, michael@0: offset: offset, michael@0: data: data michael@0: }; michael@0: } michael@0: michael@0: function readOpenTypeHeader(ttf) { michael@0: return { michael@0: version: bytesToString(ttf.getBytes(4)), michael@0: numTables: ttf.getUint16(), michael@0: searchRange: ttf.getUint16(), michael@0: entrySelector: ttf.getUint16(), michael@0: rangeShift: ttf.getUint16() michael@0: }; michael@0: } michael@0: michael@0: /** michael@0: * Read the appropriate subtable from the cmap according to 9.6.6.4 from michael@0: * PDF spec michael@0: */ michael@0: function readCmapTable(cmap, font, isSymbolicFont) { michael@0: var segment; michael@0: var start = (font.start ? font.start : 0) + cmap.offset; michael@0: font.pos = start; michael@0: michael@0: var version = font.getUint16(); michael@0: var numTables = font.getUint16(); michael@0: michael@0: var potentialTable; michael@0: var canBreak = false; michael@0: // There's an order of preference in terms of which cmap subtable to michael@0: // use: michael@0: // - non-symbolic fonts the preference is a 3,1 table then a 1,0 table michael@0: // - symbolic fonts the preference is a 3,0 table then a 1,0 table michael@0: // The following takes advantage of the fact that the tables are sorted michael@0: // to work. michael@0: for (var i = 0; i < numTables; i++) { michael@0: var platformId = font.getUint16(); michael@0: var encodingId = font.getUint16(); michael@0: var offset = font.getInt32() >>> 0; michael@0: var useTable = false; michael@0: michael@0: if (platformId == 1 && encodingId === 0) { michael@0: useTable = true; michael@0: // Continue the loop since there still may be a higher priority michael@0: // table. michael@0: } else if (!isSymbolicFont && platformId === 3 && encodingId === 1) { michael@0: useTable = true; michael@0: canBreak = true; michael@0: } else if (isSymbolicFont && platformId === 3 && encodingId === 0) { michael@0: useTable = true; michael@0: canBreak = true; michael@0: } michael@0: michael@0: if (useTable) { michael@0: potentialTable = { michael@0: platformId: platformId, michael@0: encodingId: encodingId, michael@0: offset: offset michael@0: }; michael@0: } michael@0: if (canBreak) { michael@0: break; michael@0: } michael@0: } michael@0: michael@0: if (!potentialTable) { michael@0: warn('Could not find a preferred cmap table.'); michael@0: return { michael@0: platformId: -1, michael@0: encodingId: -1, michael@0: mappings: [], michael@0: hasShortCmap: false michael@0: }; michael@0: } michael@0: michael@0: font.pos = start + potentialTable.offset; michael@0: var format = font.getUint16(); michael@0: var length = font.getUint16(); michael@0: var language = font.getUint16(); michael@0: michael@0: var hasShortCmap = false; michael@0: var mappings = []; michael@0: var j, glyphId; michael@0: michael@0: // TODO(mack): refactor this cmap subtable reading logic out michael@0: if (format === 0) { michael@0: for (j = 0; j < 256; j++) { michael@0: var index = font.getByte(); michael@0: if (!index) { michael@0: continue; michael@0: } michael@0: mappings.push({ michael@0: charCode: j, michael@0: glyphId: index michael@0: }); michael@0: } michael@0: hasShortCmap = true; michael@0: } else if (format === 4) { michael@0: // re-creating the table in format 4 since the encoding michael@0: // might be changed michael@0: var segCount = (font.getUint16() >> 1); michael@0: font.getBytes(6); // skipping range fields michael@0: var segIndex, segments = []; michael@0: for (segIndex = 0; segIndex < segCount; segIndex++) { michael@0: segments.push({ end: font.getUint16() }); michael@0: } michael@0: font.getUint16(); michael@0: for (segIndex = 0; segIndex < segCount; segIndex++) { michael@0: segments[segIndex].start = font.getUint16(); michael@0: } michael@0: michael@0: for (segIndex = 0; segIndex < segCount; segIndex++) { michael@0: segments[segIndex].delta = font.getUint16(); michael@0: } michael@0: michael@0: var offsetsCount = 0; michael@0: for (segIndex = 0; segIndex < segCount; segIndex++) { michael@0: segment = segments[segIndex]; michael@0: var rangeOffset = font.getUint16(); michael@0: if (!rangeOffset) { michael@0: segment.offsetIndex = -1; michael@0: continue; michael@0: } michael@0: michael@0: var offsetIndex = (rangeOffset >> 1) - (segCount - segIndex); michael@0: segment.offsetIndex = offsetIndex; michael@0: offsetsCount = Math.max(offsetsCount, offsetIndex + michael@0: segment.end - segment.start + 1); michael@0: } michael@0: michael@0: var offsets = []; michael@0: for (j = 0; j < offsetsCount; j++) { michael@0: offsets.push(font.getUint16()); michael@0: } michael@0: michael@0: for (segIndex = 0; segIndex < segCount; segIndex++) { michael@0: segment = segments[segIndex]; michael@0: start = segment.start; michael@0: var end = segment.end; michael@0: var delta = segment.delta; michael@0: offsetIndex = segment.offsetIndex; michael@0: michael@0: for (j = start; j <= end; j++) { michael@0: if (j == 0xFFFF) { michael@0: continue; michael@0: } michael@0: michael@0: glyphId = (offsetIndex < 0 ? michael@0: j : offsets[offsetIndex + j - start]); michael@0: glyphId = (glyphId + delta) & 0xFFFF; michael@0: if (glyphId === 0) { michael@0: continue; michael@0: } michael@0: mappings.push({ michael@0: charCode: j, michael@0: glyphId: glyphId michael@0: }); michael@0: } michael@0: } michael@0: } else if (format == 6) { michael@0: // Format 6 is a 2-bytes dense mapping, which means the font data michael@0: // lives glue together even if they are pretty far in the unicode michael@0: // table. (This looks weird, so I can have missed something), this michael@0: // works on Linux but seems to fails on Mac so let's rewrite the michael@0: // cmap table to a 3-1-4 style michael@0: var firstCode = font.getUint16(); michael@0: var entryCount = font.getUint16(); michael@0: michael@0: for (j = 0; j < entryCount; j++) { michael@0: glyphId = font.getUint16(); michael@0: var charCode = firstCode + j; michael@0: michael@0: mappings.push({ michael@0: charCode: charCode, michael@0: glyphId: glyphId michael@0: }); michael@0: } michael@0: } else { michael@0: error('cmap table has unsupported format: ' + format); michael@0: } michael@0: michael@0: // removing duplicate entries michael@0: mappings.sort(function (a, b) { michael@0: return a.charCode - b.charCode; michael@0: }); michael@0: for (i = 1; i < mappings.length; i++) { michael@0: if (mappings[i - 1].charCode === mappings[i].charCode) { michael@0: mappings.splice(i, 1); michael@0: i--; michael@0: } michael@0: } michael@0: michael@0: return { michael@0: platformId: potentialTable.platformId, michael@0: encodingId: potentialTable.encodingId, michael@0: mappings: mappings, michael@0: hasShortCmap: hasShortCmap michael@0: }; michael@0: } michael@0: michael@0: function sanitizeMetrics(font, header, metrics, numGlyphs) { michael@0: if (!header) { michael@0: if (metrics) { michael@0: metrics.data = null; michael@0: } michael@0: return; michael@0: } michael@0: michael@0: font.pos = (font.start ? font.start : 0) + header.offset; michael@0: font.pos += header.length - 2; michael@0: var numOfMetrics = font.getUint16(); michael@0: michael@0: if (numOfMetrics > numGlyphs) { michael@0: info('The numOfMetrics (' + numOfMetrics + ') should not be ' + michael@0: 'greater than the numGlyphs (' + numGlyphs + ')'); michael@0: // Reduce numOfMetrics if it is greater than numGlyphs michael@0: numOfMetrics = numGlyphs; michael@0: header.data[34] = (numOfMetrics & 0xff00) >> 8; michael@0: header.data[35] = numOfMetrics & 0x00ff; michael@0: } michael@0: michael@0: var numOfSidebearings = numGlyphs - numOfMetrics; michael@0: var numMissing = numOfSidebearings - michael@0: ((metrics.length - numOfMetrics * 4) >> 1); michael@0: michael@0: var i, ii; michael@0: if (numMissing > 0) { michael@0: font.pos = (font.start ? font.start : 0) + metrics.offset; michael@0: var entries = ''; michael@0: for (i = 0, ii = metrics.length; i < ii; i++) { michael@0: entries += String.fromCharCode(font.getByte()); michael@0: } michael@0: for (i = 0; i < numMissing; i++) { michael@0: entries += '\x00\x00'; michael@0: } michael@0: metrics.data = stringToArray(entries); michael@0: } michael@0: } michael@0: michael@0: function sanitizeGlyph(source, sourceStart, sourceEnd, dest, destStart, michael@0: hintsValid) { michael@0: if (sourceEnd - sourceStart <= 12) { michael@0: // glyph with data less than 12 is invalid one michael@0: return 0; michael@0: } michael@0: var glyf = source.subarray(sourceStart, sourceEnd); michael@0: var contoursCount = (glyf[0] << 8) | glyf[1]; michael@0: if (contoursCount & 0x8000) { michael@0: // complex glyph, writing as is michael@0: dest.set(glyf, destStart); michael@0: return glyf.length; michael@0: } michael@0: michael@0: var i, j = 10, flagsCount = 0; michael@0: for (i = 0; i < contoursCount; i++) { michael@0: var endPoint = (glyf[j] << 8) | glyf[j + 1]; michael@0: flagsCount = endPoint + 1; michael@0: j += 2; michael@0: } michael@0: // skipping instructions michael@0: var instructionsStart = j; michael@0: var instructionsLength = (glyf[j] << 8) | glyf[j + 1]; michael@0: j += 2 + instructionsLength; michael@0: var instructionsEnd = j; michael@0: // validating flags michael@0: var coordinatesLength = 0; michael@0: for (i = 0; i < flagsCount; i++) { michael@0: var flag = glyf[j++]; michael@0: if (flag & 0xC0) { michael@0: // reserved flags must be zero, cleaning up michael@0: glyf[j - 1] = flag & 0x3F; michael@0: } michael@0: var xyLength = ((flag & 2) ? 1 : (flag & 16) ? 0 : 2) + michael@0: ((flag & 4) ? 1 : (flag & 32) ? 0 : 2); michael@0: coordinatesLength += xyLength; michael@0: if (flag & 8) { michael@0: var repeat = glyf[j++]; michael@0: i += repeat; michael@0: coordinatesLength += repeat * xyLength; michael@0: } michael@0: } michael@0: // glyph without coordinates will be rejected michael@0: if (coordinatesLength === 0) { michael@0: return 0; michael@0: } michael@0: var glyphDataLength = j + coordinatesLength; michael@0: if (glyphDataLength > glyf.length) { michael@0: // not enough data for coordinates michael@0: return 0; michael@0: } michael@0: if (!hintsValid && instructionsLength > 0) { michael@0: dest.set(glyf.subarray(0, instructionsStart), destStart); michael@0: dest.set([0, 0], destStart + instructionsStart); michael@0: dest.set(glyf.subarray(instructionsEnd, glyphDataLength), michael@0: destStart + instructionsStart + 2); michael@0: glyphDataLength -= instructionsLength; michael@0: if (glyf.length - glyphDataLength > 3) { michael@0: glyphDataLength = (glyphDataLength + 3) & ~3; michael@0: } michael@0: return glyphDataLength; michael@0: } michael@0: if (glyf.length - glyphDataLength > 3) { michael@0: // truncating and aligning to 4 bytes the long glyph data michael@0: glyphDataLength = (glyphDataLength + 3) & ~3; michael@0: dest.set(glyf.subarray(0, glyphDataLength), destStart); michael@0: return glyphDataLength; michael@0: } michael@0: // glyph data is fine michael@0: dest.set(glyf, destStart); michael@0: return glyf.length; michael@0: } michael@0: michael@0: function sanitizeHead(head, numGlyphs, locaLength) { michael@0: var data = head.data; michael@0: michael@0: // Validate version: michael@0: // Should always be 0x00010000 michael@0: var version = int32(data[0], data[1], data[2], data[3]); michael@0: if (version >> 16 !== 1) { michael@0: info('Attempting to fix invalid version in head table: ' + version); michael@0: data[0] = 0; michael@0: data[1] = 1; michael@0: data[2] = 0; michael@0: data[3] = 0; michael@0: } michael@0: michael@0: var indexToLocFormat = int16(data[50], data[51]); michael@0: if (indexToLocFormat < 0 || indexToLocFormat > 1) { michael@0: info('Attempting to fix invalid indexToLocFormat in head table: ' + michael@0: indexToLocFormat); michael@0: michael@0: // The value of indexToLocFormat should be 0 if the loca table michael@0: // consists of short offsets, and should be 1 if the loca table michael@0: // consists of long offsets. michael@0: // michael@0: // The number of entries in the loca table should be numGlyphs + 1. michael@0: // michael@0: // Using this information, we can work backwards to deduce if the michael@0: // size of each offset in the loca table, and thus figure out the michael@0: // appropriate value for indexToLocFormat. michael@0: michael@0: var numGlyphsPlusOne = numGlyphs + 1; michael@0: if (locaLength === numGlyphsPlusOne << 1) { michael@0: // 0x0000 indicates the loca table consists of short offsets michael@0: data[50] = 0; michael@0: data[51] = 0; michael@0: } else if (locaLength === numGlyphsPlusOne << 2) { michael@0: // 0x0001 indicates the loca table consists of long offsets michael@0: data[50] = 0; michael@0: data[51] = 1; michael@0: } else { michael@0: warn('Could not fix indexToLocFormat: ' + indexToLocFormat); michael@0: } michael@0: } michael@0: } michael@0: michael@0: function sanitizeGlyphLocations(loca, glyf, numGlyphs, michael@0: isGlyphLocationsLong, hintsValid, michael@0: dupFirstEntry) { michael@0: var itemSize, itemDecode, itemEncode; michael@0: if (isGlyphLocationsLong) { michael@0: itemSize = 4; michael@0: itemDecode = function fontItemDecodeLong(data, offset) { michael@0: return (data[offset] << 24) | (data[offset + 1] << 16) | michael@0: (data[offset + 2] << 8) | data[offset + 3]; michael@0: }; michael@0: itemEncode = function fontItemEncodeLong(data, offset, value) { michael@0: data[offset] = (value >>> 24) & 0xFF; michael@0: data[offset + 1] = (value >> 16) & 0xFF; michael@0: data[offset + 2] = (value >> 8) & 0xFF; michael@0: data[offset + 3] = value & 0xFF; michael@0: }; michael@0: } else { michael@0: itemSize = 2; michael@0: itemDecode = function fontItemDecode(data, offset) { michael@0: return (data[offset] << 9) | (data[offset + 1] << 1); michael@0: }; michael@0: itemEncode = function fontItemEncode(data, offset, value) { michael@0: data[offset] = (value >> 9) & 0xFF; michael@0: data[offset + 1] = (value >> 1) & 0xFF; michael@0: }; michael@0: } michael@0: var locaData = loca.data; michael@0: var locaDataSize = itemSize * (1 + numGlyphs); michael@0: // is loca.data too short or long? michael@0: if (locaData.length !== locaDataSize) { michael@0: locaData = new Uint8Array(locaDataSize); michael@0: locaData.set(loca.data.subarray(0, locaDataSize)); michael@0: loca.data = locaData; michael@0: } michael@0: // removing the invalid glyphs michael@0: var oldGlyfData = glyf.data; michael@0: var oldGlyfDataLength = oldGlyfData.length; michael@0: var newGlyfData = new Uint8Array(oldGlyfDataLength); michael@0: var startOffset = itemDecode(locaData, 0); michael@0: var writeOffset = 0; michael@0: itemEncode(locaData, 0, writeOffset); michael@0: var i, j; michael@0: for (i = 0, j = itemSize; i < numGlyphs; i++, j += itemSize) { michael@0: var endOffset = itemDecode(locaData, j); michael@0: if (endOffset > oldGlyfDataLength && michael@0: ((oldGlyfDataLength + 3) & ~3) === endOffset) { michael@0: // Aspose breaks fonts by aligning the glyphs to the qword, but not michael@0: // the glyf table size, which makes last glyph out of range. michael@0: endOffset = oldGlyfDataLength; michael@0: } michael@0: if (endOffset > oldGlyfDataLength) { michael@0: // glyph end offset points outside glyf data, rejecting the glyph michael@0: itemEncode(locaData, j, writeOffset); michael@0: startOffset = endOffset; michael@0: continue; michael@0: } michael@0: michael@0: var newLength = sanitizeGlyph(oldGlyfData, startOffset, endOffset, michael@0: newGlyfData, writeOffset, hintsValid); michael@0: writeOffset += newLength; michael@0: itemEncode(locaData, j, writeOffset); michael@0: startOffset = endOffset; michael@0: } michael@0: michael@0: if (writeOffset === 0) { michael@0: // glyf table cannot be empty -- redoing the glyf and loca tables michael@0: // to have single glyph with one point michael@0: var simpleGlyph = new Uint8Array( michael@0: [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 49, 0]); michael@0: for (i = 0, j = itemSize; i < numGlyphs; i++, j += itemSize) { michael@0: itemEncode(locaData, j, simpleGlyph.length); michael@0: } michael@0: glyf.data = simpleGlyph; michael@0: return; michael@0: } michael@0: michael@0: if (dupFirstEntry) { michael@0: var firstEntryLength = itemDecode(locaData, itemSize); michael@0: if (newGlyfData.length > firstEntryLength + writeOffset) { michael@0: glyf.data = newGlyfData.subarray(0, firstEntryLength + writeOffset); michael@0: } else { michael@0: glyf.data = new Uint8Array(firstEntryLength + writeOffset); michael@0: glyf.data.set(newGlyfData.subarray(0, writeOffset)); michael@0: } michael@0: glyf.data.set(newGlyfData.subarray(0, firstEntryLength), writeOffset); michael@0: itemEncode(loca.data, locaData.length - itemSize, michael@0: writeOffset + firstEntryLength); michael@0: } else { michael@0: glyf.data = newGlyfData.subarray(0, writeOffset); michael@0: } michael@0: } michael@0: michael@0: function readPostScriptTable(post, properties, maxpNumGlyphs) { michael@0: var start = (font.start ? font.start : 0) + post.offset; michael@0: font.pos = start; michael@0: michael@0: var length = post.length, end = start + length; michael@0: var version = font.getInt32(); michael@0: // skip rest to the tables michael@0: font.getBytes(28); michael@0: michael@0: var glyphNames; michael@0: var valid = true; michael@0: var i; michael@0: michael@0: switch (version) { michael@0: case 0x00010000: michael@0: glyphNames = MacStandardGlyphOrdering; michael@0: break; michael@0: case 0x00020000: michael@0: var numGlyphs = font.getUint16(); michael@0: if (numGlyphs != maxpNumGlyphs) { michael@0: valid = false; michael@0: break; michael@0: } michael@0: var glyphNameIndexes = []; michael@0: for (i = 0; i < numGlyphs; ++i) { michael@0: var index = font.getUint16(); michael@0: if (index >= 32768) { michael@0: valid = false; michael@0: break; michael@0: } michael@0: glyphNameIndexes.push(index); michael@0: } michael@0: if (!valid) { michael@0: break; michael@0: } michael@0: var customNames = []; michael@0: while (font.pos < end) { michael@0: var stringLength = font.getByte(); michael@0: var string = ''; michael@0: for (i = 0; i < stringLength; ++i) { michael@0: string += String.fromCharCode(font.getByte()); michael@0: } michael@0: customNames.push(string); michael@0: } michael@0: glyphNames = []; michael@0: for (i = 0; i < numGlyphs; ++i) { michael@0: var j = glyphNameIndexes[i]; michael@0: if (j < 258) { michael@0: glyphNames.push(MacStandardGlyphOrdering[j]); michael@0: continue; michael@0: } michael@0: glyphNames.push(customNames[j - 258]); michael@0: } michael@0: break; michael@0: case 0x00030000: michael@0: break; michael@0: default: michael@0: warn('Unknown/unsupported post table version ' + version); michael@0: valid = false; michael@0: break; michael@0: } michael@0: properties.glyphNames = glyphNames; michael@0: return valid; michael@0: } michael@0: michael@0: function readNameTable(nameTable) { michael@0: var start = (font.start ? font.start : 0) + nameTable.offset; michael@0: font.pos = start; michael@0: michael@0: var names = [[], []]; michael@0: var length = nameTable.length, end = start + length; michael@0: var format = font.getUint16(); michael@0: var FORMAT_0_HEADER_LENGTH = 6; michael@0: if (format !== 0 || length < FORMAT_0_HEADER_LENGTH) { michael@0: // unsupported name table format or table "too" small michael@0: return names; michael@0: } michael@0: var numRecords = font.getUint16(); michael@0: var stringsStart = font.getUint16(); michael@0: var records = []; michael@0: var NAME_RECORD_LENGTH = 12; michael@0: var i, ii; michael@0: michael@0: for (i = 0; i < numRecords && michael@0: font.pos + NAME_RECORD_LENGTH <= end; i++) { michael@0: var r = { michael@0: platform: font.getUint16(), michael@0: encoding: font.getUint16(), michael@0: language: font.getUint16(), michael@0: name: font.getUint16(), michael@0: length: font.getUint16(), michael@0: offset: font.getUint16() michael@0: }; michael@0: // using only Macintosh and Windows platform/encoding names michael@0: if ((r.platform == 1 && r.encoding === 0 && r.language === 0) || michael@0: (r.platform == 3 && r.encoding == 1 && r.language == 0x409)) { michael@0: records.push(r); michael@0: } michael@0: } michael@0: for (i = 0, ii = records.length; i < ii; i++) { michael@0: var record = records[i]; michael@0: var pos = start + stringsStart + record.offset; michael@0: if (pos + record.length > end) { michael@0: continue; // outside of name table, ignoring michael@0: } michael@0: font.pos = pos; michael@0: var nameIndex = record.name; michael@0: if (record.encoding) { michael@0: // unicode michael@0: var str = ''; michael@0: for (var j = 0, jj = record.length; j < jj; j += 2) { michael@0: str += String.fromCharCode(font.getUint16()); michael@0: } michael@0: names[1][nameIndex] = str; michael@0: } else { michael@0: names[0][nameIndex] = bytesToString(font.getBytes(record.length)); michael@0: } michael@0: } michael@0: return names; michael@0: } michael@0: michael@0: var TTOpsStackDeltas = [ michael@0: 0, 0, 0, 0, 0, 0, 0, 0, -2, -2, -2, -2, 0, 0, -2, -5, michael@0: -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, -1, 0, -1, -1, -1, -1, michael@0: 1, -1, -999, 0, 1, 0, -1, -2, 0, -1, -2, -1, -1, 0, -1, -1, michael@0: 0, 0, -999, -999, -1, -1, -1, -1, -2, -999, -2, -2, -999, 0, -2, -2, michael@0: 0, 0, -2, 0, -2, 0, 0, 0, -2, -1, -1, 1, 1, 0, 0, -1, michael@0: -1, -1, -1, -1, -1, -1, 0, 0, -1, 0, -1, -1, 0, -999, -1, -1, michael@0: -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, michael@0: -2, -999, -999, -999, -999, -999, -1, -1, -2, -2, 0, 0, 0, 0, -1, -1, michael@0: -999, -2, -2, 0, 0, -1, -2, -2, 0, 0, 0, -1, -1, -1, -2]; michael@0: // 0xC0-DF == -1 and 0xE0-FF == -2 michael@0: michael@0: function sanitizeTTProgram(table, ttContext) { michael@0: var data = table.data; michael@0: var i = 0, j, n, b, funcId, pc, lastEndf = 0, lastDeff = 0; michael@0: var stack = []; michael@0: var callstack = []; michael@0: var functionsCalled = []; michael@0: var tooComplexToFollowFunctions = michael@0: ttContext.tooComplexToFollowFunctions; michael@0: var inFDEF = false, ifLevel = 0, inELSE = 0; michael@0: for (var ii = data.length; i < ii;) { michael@0: var op = data[i++]; michael@0: // The TrueType instruction set docs can be found at michael@0: // https://developer.apple.com/fonts/TTRefMan/RM05/Chap5.html michael@0: if (op === 0x40) { // NPUSHB - pushes n bytes michael@0: n = data[i++]; michael@0: if (inFDEF || inELSE) { michael@0: i += n; michael@0: } else { michael@0: for (j = 0; j < n; j++) { michael@0: stack.push(data[i++]); michael@0: } michael@0: } michael@0: } else if (op === 0x41) { // NPUSHW - pushes n words michael@0: n = data[i++]; michael@0: if (inFDEF || inELSE) { michael@0: i += n * 2; michael@0: } else { michael@0: for (j = 0; j < n; j++) { michael@0: b = data[i++]; michael@0: stack.push((b << 8) | data[i++]); michael@0: } michael@0: } michael@0: } else if ((op & 0xF8) === 0xB0) { // PUSHB - pushes bytes michael@0: n = op - 0xB0 + 1; michael@0: if (inFDEF || inELSE) { michael@0: i += n; michael@0: } else { michael@0: for (j = 0; j < n; j++) { michael@0: stack.push(data[i++]); michael@0: } michael@0: } michael@0: } else if ((op & 0xF8) === 0xB8) { // PUSHW - pushes words michael@0: n = op - 0xB8 + 1; michael@0: if (inFDEF || inELSE) { michael@0: i += n * 2; michael@0: } else { michael@0: for (j = 0; j < n; j++) { michael@0: b = data[i++]; michael@0: stack.push((b << 8) | data[i++]); michael@0: } michael@0: } michael@0: } else if (op === 0x2B && !tooComplexToFollowFunctions) { // CALL michael@0: if (!inFDEF && !inELSE) { michael@0: // collecting inforamtion about which functions are used michael@0: funcId = stack[stack.length - 1]; michael@0: ttContext.functionsUsed[funcId] = true; michael@0: if (funcId in ttContext.functionsStackDeltas) { michael@0: stack.length += ttContext.functionsStackDeltas[funcId]; michael@0: } else if (funcId in ttContext.functionsDefined && michael@0: functionsCalled.indexOf(funcId) < 0) { michael@0: callstack.push({data: data, i: i, stackTop: stack.length - 1}); michael@0: functionsCalled.push(funcId); michael@0: pc = ttContext.functionsDefined[funcId]; michael@0: if (!pc) { michael@0: warn('TT: CALL non-existent function'); michael@0: ttContext.hintsValid = false; michael@0: return; michael@0: } michael@0: data = pc.data; michael@0: i = pc.i; michael@0: } michael@0: } michael@0: } else if (op === 0x2C && !tooComplexToFollowFunctions) { // FDEF michael@0: if (inFDEF || inELSE) { michael@0: warn('TT: nested FDEFs not allowed'); michael@0: tooComplexToFollowFunctions = true; michael@0: } michael@0: inFDEF = true; michael@0: // collecting inforamtion about which functions are defined michael@0: lastDeff = i; michael@0: funcId = stack.pop(); michael@0: ttContext.functionsDefined[funcId] = {data: data, i: i}; michael@0: } else if (op === 0x2D) { // ENDF - end of function michael@0: if (inFDEF) { michael@0: inFDEF = false; michael@0: lastEndf = i; michael@0: } else { michael@0: pc = callstack.pop(); michael@0: if (!pc) { michael@0: warn('TT: ENDF bad stack'); michael@0: ttContext.hintsValid = false; michael@0: return; michael@0: } michael@0: funcId = functionsCalled.pop(); michael@0: data = pc.data; michael@0: i = pc.i; michael@0: ttContext.functionsStackDeltas[funcId] = michael@0: stack.length - pc.stackTop; michael@0: } michael@0: } else if (op === 0x89) { // IDEF - instruction definition michael@0: if (inFDEF || inELSE) { michael@0: warn('TT: nested IDEFs not allowed'); michael@0: tooComplexToFollowFunctions = true; michael@0: } michael@0: inFDEF = true; michael@0: // recording it as a function to track ENDF michael@0: lastDeff = i; michael@0: } else if (op === 0x58) { // IF michael@0: ++ifLevel; michael@0: } else if (op === 0x1B) { // ELSE michael@0: inELSE = ifLevel; michael@0: } else if (op === 0x59) { // EIF michael@0: if (inELSE === ifLevel) { michael@0: inELSE = 0; michael@0: } michael@0: --ifLevel; michael@0: } else if (op === 0x1C) { // JMPR michael@0: if (!inFDEF && !inELSE) { michael@0: var offset = stack[stack.length - 1]; michael@0: // only jumping forward to prevent infinite loop michael@0: if (offset > 0) { michael@0: i += offset - 1; michael@0: } michael@0: } michael@0: } michael@0: // Adjusting stack not extactly, but just enough to get function id michael@0: if (!inFDEF && !inELSE) { michael@0: var stackDelta = op <= 0x8E ? TTOpsStackDeltas[op] : michael@0: op >= 0xC0 && op <= 0xDF ? -1 : op >= 0xE0 ? -2 : 0; michael@0: if (op >= 0x71 && op <= 0x75) { michael@0: n = stack.pop(); michael@0: if (n === n) { michael@0: stackDelta = -n * 2; michael@0: } michael@0: } michael@0: while (stackDelta < 0 && stack.length > 0) { michael@0: stack.pop(); michael@0: stackDelta++; michael@0: } michael@0: while (stackDelta > 0) { michael@0: stack.push(NaN); // pushing any number into stack michael@0: stackDelta--; michael@0: } michael@0: } michael@0: } michael@0: ttContext.tooComplexToFollowFunctions = tooComplexToFollowFunctions; michael@0: var content = [data]; michael@0: if (i > data.length) { michael@0: content.push(new Uint8Array(i - data.length)); michael@0: } michael@0: if (lastDeff > lastEndf) { michael@0: warn('TT: complementing a missing function tail'); michael@0: // new function definition started, but not finished michael@0: // complete function by [CLEAR, ENDF] michael@0: content.push(new Uint8Array([0x22, 0x2D])); michael@0: } michael@0: foldTTTable(table, content); michael@0: } michael@0: michael@0: function checkInvalidFunctions(ttContext, maxFunctionDefs) { michael@0: if (ttContext.tooComplexToFollowFunctions) { michael@0: return; michael@0: } michael@0: if (ttContext.functionsDefined.length > maxFunctionDefs) { michael@0: warn('TT: more functions defined than expected'); michael@0: ttContext.hintsValid = false; michael@0: return; michael@0: } michael@0: for (var j = 0, jj = ttContext.functionsUsed.length; j < jj; j++) { michael@0: if (j > maxFunctionDefs) { michael@0: warn('TT: invalid function id: ' + j); michael@0: ttContext.hintsValid = false; michael@0: return; michael@0: } michael@0: if (ttContext.functionsUsed[j] && !ttContext.functionsDefined[j]) { michael@0: warn('TT: undefined function: ' + j); michael@0: ttContext.hintsValid = false; michael@0: return; michael@0: } michael@0: } michael@0: } michael@0: michael@0: function foldTTTable(table, content) { michael@0: if (content.length > 1) { michael@0: // concatenating the content items michael@0: var newLength = 0; michael@0: var j, jj; michael@0: for (j = 0, jj = content.length; j < jj; j++) { michael@0: newLength += content[j].length; michael@0: } michael@0: newLength = (newLength + 3) & ~3; michael@0: var result = new Uint8Array(newLength); michael@0: var pos = 0; michael@0: for (j = 0, jj = content.length; j < jj; j++) { michael@0: result.set(content[j], pos); michael@0: pos += content[j].length; michael@0: } michael@0: table.data = result; michael@0: table.length = newLength; michael@0: } michael@0: } michael@0: michael@0: function sanitizeTTPrograms(fpgm, prep, cvt) { michael@0: var ttContext = { michael@0: functionsDefined: [], michael@0: functionsUsed: [], michael@0: functionsStackDeltas: [], michael@0: tooComplexToFollowFunctions: false, michael@0: hintsValid: true michael@0: }; michael@0: if (fpgm) { michael@0: sanitizeTTProgram(fpgm, ttContext); michael@0: } michael@0: if (prep) { michael@0: sanitizeTTProgram(prep, ttContext); michael@0: } michael@0: if (fpgm) { michael@0: checkInvalidFunctions(ttContext, maxFunctionDefs); michael@0: } michael@0: if (cvt && (cvt.length & 1)) { michael@0: var cvtData = new Uint8Array(cvt.length + 1); michael@0: cvtData.set(cvt.data); michael@0: cvt.data = cvtData; michael@0: } michael@0: return ttContext.hintsValid; michael@0: } michael@0: michael@0: // The following steps modify the original font data, making copy michael@0: font = new Stream(new Uint8Array(font.getBytes())); michael@0: michael@0: var VALID_TABLES = ['OS/2', 'cmap', 'head', 'hhea', 'hmtx', 'maxp', michael@0: 'name', 'post', 'loca', 'glyf', 'fpgm', 'prep', 'cvt ', 'CFF ']; michael@0: michael@0: var header = readOpenTypeHeader(font); michael@0: var numTables = header.numTables; michael@0: var cff, cffFile; michael@0: michael@0: var tables = { 'OS/2': null, cmap: null, head: null, hhea: null, michael@0: hmtx: null, maxp: null, name: null, post: null }; michael@0: var table, tableData; michael@0: for (var i = 0; i < numTables; i++) { michael@0: table = readTableEntry(font); michael@0: if (VALID_TABLES.indexOf(table.tag) < 0) { michael@0: continue; // skipping table if it's not a required or optional table michael@0: } michael@0: if (table.length === 0) { michael@0: continue; // skipping empty tables michael@0: } michael@0: tables[table.tag] = table; michael@0: } michael@0: michael@0: var isTrueType = !tables['CFF ']; michael@0: if (!isTrueType) { michael@0: // OpenType font michael@0: if (!tables.head || !tables.hhea || !tables.maxp || !tables.post) { michael@0: // no major tables: throwing everything at CFFFont michael@0: cffFile = new Stream(tables['CFF '].data); michael@0: cff = new CFFFont(cffFile, properties); michael@0: michael@0: return this.convert(name, cff, properties); michael@0: } michael@0: michael@0: delete tables.glyf; michael@0: delete tables.loca; michael@0: delete tables.fpgm; michael@0: delete tables.prep; michael@0: delete tables['cvt ']; michael@0: } else { michael@0: if (!tables.glyf || !tables.loca) { michael@0: error('Required "glyf" or "loca" tables are not found'); michael@0: } michael@0: } michael@0: michael@0: if (!tables.maxp) { michael@0: error('Required "maxp" table is not found'); michael@0: } michael@0: michael@0: font.pos = (font.start || 0) + tables.maxp.offset; michael@0: var version = font.getInt32(); michael@0: var numGlyphs = font.getUint16(); michael@0: var maxFunctionDefs = 0; michael@0: if (version >= 0x00010000 && tables.maxp.length >= 22) { michael@0: // maxZones can be invalid michael@0: font.pos += 8; michael@0: var maxZones = font.getUint16(); michael@0: if (maxZones > 2) { // reset to 2 if font has invalid maxZones michael@0: tables.maxp.data[14] = 0; michael@0: tables.maxp.data[15] = 2; michael@0: } michael@0: font.pos += 4; michael@0: maxFunctionDefs = font.getUint16(); michael@0: } michael@0: michael@0: var dupFirstEntry = false; michael@0: if (properties.type == 'CIDFontType2' && properties.toUnicode && michael@0: properties.toUnicode[0] > '\u0000') { michael@0: // oracle's defect (see 3427), duplicating first entry michael@0: dupFirstEntry = true; michael@0: numGlyphs++; michael@0: tables.maxp.data[4] = numGlyphs >> 8; michael@0: tables.maxp.data[5] = numGlyphs & 255; michael@0: } michael@0: michael@0: var hintsValid = sanitizeTTPrograms(tables.fpgm, tables.prep, michael@0: tables['cvt '], maxFunctionDefs); michael@0: if (!hintsValid) { michael@0: delete tables.fpgm; michael@0: delete tables.prep; michael@0: delete tables['cvt ']; michael@0: } michael@0: michael@0: // Tables needs to be written by ascendant alphabetic order michael@0: var tablesNames = Object.keys(tables); michael@0: tablesNames.sort(); michael@0: michael@0: numTables = tablesNames.length; michael@0: michael@0: // header and new offsets. Table entry information is appended to the michael@0: // end of file. The virtualOffset represents where to put the actual michael@0: // data of a particular table; michael@0: var ttf = { michael@0: file: '', michael@0: virtualOffset: numTables * (4 * 4) michael@0: }; michael@0: michael@0: // The new numbers of tables will be the last one plus the num michael@0: // of missing tables michael@0: createOpenTypeHeader(header.version, ttf, numTables); michael@0: michael@0: // Ensure the hmtx table contains the advance width and michael@0: // sidebearings information for numGlyphs in the maxp table michael@0: sanitizeMetrics(font, tables.hhea, tables.hmtx, numGlyphs); michael@0: michael@0: if (!tables.head) { michael@0: error('Required "head" table is not found'); michael@0: } michael@0: michael@0: sanitizeHead(tables.head, numGlyphs, isTrueType ? tables.loca.length : 0); michael@0: michael@0: if (isTrueType) { michael@0: var isGlyphLocationsLong = int16(tables.head.data[50], michael@0: tables.head.data[51]); michael@0: sanitizeGlyphLocations(tables.loca, tables.glyf, numGlyphs, michael@0: isGlyphLocationsLong, hintsValid, dupFirstEntry); michael@0: } michael@0: michael@0: if (!tables.hhea) { michael@0: error('Required "hhea" table is not found'); michael@0: } michael@0: michael@0: // Sanitizer reduces the glyph advanceWidth to the maxAdvanceWidth michael@0: // Sometimes it's 0. That needs to be fixed michael@0: if (tables.hhea.data[10] === 0 && tables.hhea.data[11] === 0) { michael@0: tables.hhea.data[10] = 0xFF; michael@0: tables.hhea.data[11] = 0xFF; michael@0: } michael@0: michael@0: // The 'post' table has glyphs names. michael@0: if (tables.post) { michael@0: var valid = readPostScriptTable(tables.post, properties, numGlyphs); michael@0: if (!valid) { michael@0: tables.post = null; michael@0: } michael@0: } michael@0: michael@0: var charCodeToGlyphId = [], charCode; michael@0: if (properties.type == 'CIDFontType2') { michael@0: var cidToGidMap = properties.cidToGidMap || []; michael@0: var cMap = properties.cMap.map; michael@0: for (charCode in cMap) { michael@0: charCode |= 0; michael@0: var cid = cMap[charCode]; michael@0: assert(cid.length === 1, 'Max size of CID is 65,535'); michael@0: cid = cid.charCodeAt(0); michael@0: var glyphId = -1; michael@0: if (cidToGidMap.length === 0) { michael@0: glyphId = charCode; michael@0: } else if (cid in cidToGidMap) { michael@0: glyphId = cidToGidMap[cid]; michael@0: } michael@0: if (glyphId >= 0 && glyphId < numGlyphs) { michael@0: charCodeToGlyphId[charCode] = glyphId; michael@0: } michael@0: } michael@0: if (dupFirstEntry) { michael@0: charCodeToGlyphId[0] = numGlyphs - 1; michael@0: } michael@0: } else { michael@0: // Most of the following logic in this code branch is based on the michael@0: // 9.6.6.4 of the PDF spec. michael@0: var cmapTable = readCmapTable(tables.cmap, font, this.isSymbolicFont); michael@0: var cmapPlatformId = cmapTable.platformId; michael@0: var cmapEncodingId = cmapTable.encodingId; michael@0: var cmapMappings = cmapTable.mappings; michael@0: var cmapMappingsLength = cmapMappings.length; michael@0: var hasEncoding = properties.differences.length || michael@0: !!properties.baseEncodingName; michael@0: michael@0: // The spec seems to imply that if the font is symbolic the encoding michael@0: // should be ignored, this doesn't appear to work for 'preistabelle.pdf' michael@0: // where the the font is symbolic and it has an encoding. michael@0: if (hasEncoding && michael@0: (cmapPlatformId === 3 && cmapEncodingId === 1 || michael@0: cmapPlatformId === 1 && cmapEncodingId === 0)) { michael@0: var baseEncoding = []; michael@0: if (properties.baseEncodingName === 'MacRomanEncoding' || michael@0: properties.baseEncodingName === 'WinAnsiEncoding') { michael@0: baseEncoding = Encodings[properties.baseEncodingName]; michael@0: } michael@0: for (charCode = 0; charCode < 256; charCode++) { michael@0: var glyphName; michael@0: if (this.differences && charCode in this.differences) { michael@0: glyphName = this.differences[charCode]; michael@0: } else if (charCode in baseEncoding && michael@0: baseEncoding[charCode] !== '') { michael@0: glyphName = baseEncoding[charCode]; michael@0: } else { michael@0: glyphName = Encodings.StandardEncoding[charCode]; michael@0: } michael@0: if (!glyphName) { michael@0: continue; michael@0: } michael@0: var unicodeOrCharCode; michael@0: if (cmapPlatformId === 3 && cmapEncodingId === 1) { michael@0: unicodeOrCharCode = GlyphsUnicode[glyphName]; michael@0: } else if (cmapPlatformId === 1 && cmapEncodingId === 0) { michael@0: // TODO: the encoding needs to be updated with mac os table. michael@0: unicodeOrCharCode = Encodings.MacRomanEncoding.indexOf(glyphName); michael@0: } michael@0: michael@0: var found = false; michael@0: for (i = 0; i < cmapMappingsLength; ++i) { michael@0: if (cmapMappings[i].charCode === unicodeOrCharCode) { michael@0: charCodeToGlyphId[charCode] = cmapMappings[i].glyphId; michael@0: found = true; michael@0: break; michael@0: } michael@0: } michael@0: if (!found && properties.glyphNames) { michael@0: // Try to map using the post table. There are currently no known michael@0: // pdfs that this fixes. michael@0: glyphId = properties.glyphNames.indexOf(glyphName); michael@0: if (glyphId > 0) { michael@0: charCodeToGlyphId[charCode] = glyphId; michael@0: } michael@0: } michael@0: } michael@0: } else { michael@0: // For (3, 0) cmap tables: michael@0: // The charcode key being stored in charCodeToGlyphId is the lower michael@0: // byte of the two-byte charcodes of the cmap table since according to michael@0: // the spec: 'each byte from the string shall be prepended with the michael@0: // high byte of the range [of charcodes in the cmap table], to form michael@0: // a two-byte character, which shall be used to select the michael@0: // associated glyph description from the subtable'. michael@0: // michael@0: // For (1, 0) cmap tables: michael@0: // 'single bytes from the string shall be used to look up the michael@0: // associated glyph descriptions from the subtable'. This means michael@0: // charcodes in the cmap will be single bytes, so no-op since michael@0: // glyph.charCode & 0xFF === glyph.charCode michael@0: for (i = 0; i < cmapMappingsLength; ++i) { michael@0: charCode = cmapMappings[i].charCode & 0xFF; michael@0: charCodeToGlyphId[charCode] = cmapMappings[i].glyphId; michael@0: } michael@0: } michael@0: } michael@0: michael@0: if (charCodeToGlyphId.length === 0) { michael@0: // defines at least one glyph michael@0: charCodeToGlyphId[0] = 0; michael@0: } michael@0: michael@0: // Converting glyphs and ids into font's cmap table michael@0: var newMapping = adjustMapping(charCodeToGlyphId, properties); michael@0: this.toFontChar = newMapping.toFontChar; michael@0: tables.cmap = { michael@0: tag: 'cmap', michael@0: data: createCmapTable(newMapping.charCodeToGlyphId) michael@0: }; michael@0: michael@0: if (!tables['OS/2'] || !validateOS2Table(tables['OS/2'])) { michael@0: // extract some more font properties from the OpenType head and michael@0: // hhea tables; yMin and descent value are always negative michael@0: var override = { michael@0: unitsPerEm: int16(tables.head.data[18], tables.head.data[19]), michael@0: yMax: int16(tables.head.data[42], tables.head.data[43]), michael@0: yMin: int16(tables.head.data[38], tables.head.data[39]) - 0x10000, michael@0: ascent: int16(tables.hhea.data[4], tables.hhea.data[5]), michael@0: descent: int16(tables.hhea.data[6], tables.hhea.data[7]) - 0x10000 michael@0: }; michael@0: michael@0: tables['OS/2'] = { michael@0: tag: 'OS/2', michael@0: data: stringToArray(createOS2Table(properties, michael@0: newMapping.charCodeToGlyphId, michael@0: override)) michael@0: }; michael@0: } michael@0: michael@0: // Rewrite the 'post' table if needed michael@0: if (!tables.post) { michael@0: tables.post = { michael@0: tag: 'post', michael@0: data: stringToArray(createPostTable(properties)) michael@0: }; michael@0: } michael@0: michael@0: if (!isTrueType) { michael@0: try { michael@0: // Trying to repair CFF file michael@0: cffFile = new Stream(tables['CFF '].data); michael@0: var parser = new CFFParser(cffFile, properties); michael@0: cff = parser.parse(); michael@0: var compiler = new CFFCompiler(cff); michael@0: tables['CFF '].data = compiler.compile(); michael@0: } catch (e) { michael@0: warn('Failed to compile font ' + properties.loadedName); michael@0: } michael@0: } michael@0: michael@0: // Re-creating 'name' table michael@0: if (!tables.name) { michael@0: tables.name = { michael@0: tag: 'name', michael@0: data: stringToArray(createNameTable(this.name)) michael@0: }; michael@0: } else { michael@0: // ... using existing 'name' table as prototype michael@0: var namePrototype = readNameTable(tables.name); michael@0: tables.name.data = stringToArray(createNameTable(name, namePrototype)); michael@0: } michael@0: michael@0: // rewrite the tables but tweak offsets michael@0: for (i = 0; i < numTables; i++) { michael@0: table = tables[tablesNames[i]]; michael@0: var data = []; michael@0: michael@0: tableData = table.data; michael@0: for (var j = 0, jj = tableData.length; j < jj; j++) { michael@0: data.push(tableData[j]); michael@0: } michael@0: createTableEntry(ttf, table.tag, data); michael@0: } michael@0: michael@0: // Add the table datas michael@0: for (i = 0; i < numTables; i++) { michael@0: table = tables[tablesNames[i]]; michael@0: tableData = table.data; michael@0: ttf.file += bytesToString(new Uint8Array(tableData)); michael@0: michael@0: // 4-byte aligned data michael@0: while (ttf.file.length & 3) { michael@0: ttf.file += String.fromCharCode(0); michael@0: } michael@0: } michael@0: michael@0: return stringToArray(ttf.file); michael@0: }, michael@0: michael@0: convert: function Font_convert(fontName, font, properties) { michael@0: // The offsets object holds at the same time a representation of where michael@0: // to write the table entry information about a table and another offset michael@0: // representing the offset where to draw the actual data of a particular michael@0: // table michael@0: var otf = { michael@0: file: '', michael@0: virtualOffset: 9 * (4 * 4) michael@0: }; michael@0: michael@0: createOpenTypeHeader('\x4F\x54\x54\x4F', otf, 9); michael@0: michael@0: // TODO: Check the charstring widths to determine this. michael@0: properties.fixedPitch = false; michael@0: michael@0: var mapping = font.getGlyphMapping(properties); michael@0: var newMapping = adjustMapping(mapping, properties); michael@0: this.toFontChar = newMapping.toFontChar; michael@0: var numGlyphs = font.numGlyphs; michael@0: michael@0: function getCharCode(charCodeToGlyphId, glyphId, addMap) { michael@0: for (var charCode in charCodeToGlyphId) { michael@0: if (glyphId === charCodeToGlyphId[charCode]) { michael@0: return charCode | 0; michael@0: } michael@0: } michael@0: if (addMap) { michael@0: newMapping.charCodeToGlyphId[newMapping.nextAvailableFontCharCode] = michael@0: glyphId; michael@0: return newMapping.nextAvailableFontCharCode++; michael@0: } michael@0: return null; michael@0: } michael@0: michael@0: var seacs = font.seacs; michael@0: if (SEAC_ANALYSIS_ENABLED && seacs && seacs.length) { michael@0: var matrix = properties.fontMatrix || FONT_IDENTITY_MATRIX; michael@0: var charset = font.getCharset(); michael@0: var seacMap = Object.create(null); michael@0: for (var glyphId in seacs) { michael@0: glyphId |= 0; michael@0: var seac = seacs[glyphId]; michael@0: var baseGlyphName = Encodings.StandardEncoding[seac[2]]; michael@0: var accentGlyphName = Encodings.StandardEncoding[seac[3]]; michael@0: var baseGlyphId = charset.indexOf(baseGlyphName); michael@0: var accentGlyphId = charset.indexOf(accentGlyphName); michael@0: if (baseGlyphId < 0 || accentGlyphId < 0) { michael@0: continue; michael@0: } michael@0: var accentOffset = { michael@0: x: seac[0] * matrix[0] + seac[1] * matrix[2] + matrix[4], michael@0: y: seac[0] * matrix[1] + seac[1] * matrix[3] + matrix[5] michael@0: }; michael@0: michael@0: var charCode = getCharCode(mapping, glyphId); michael@0: if (charCode === null) { michael@0: // There's no point in mapping it if the char code was never mapped michael@0: // to begin with. michael@0: continue; michael@0: } michael@0: // Find a fontCharCode that maps to the base and accent glyphs. If one michael@0: // doesn't exists, create it. michael@0: var charCodeToGlyphId = newMapping.charCodeToGlyphId; michael@0: var baseFontCharCode = getCharCode(charCodeToGlyphId, baseGlyphId, michael@0: true); michael@0: var accentFontCharCode = getCharCode(charCodeToGlyphId, accentGlyphId, michael@0: true); michael@0: seacMap[charCode] = { michael@0: baseFontCharCode: baseFontCharCode, michael@0: accentFontCharCode: accentFontCharCode, michael@0: accentOffset: accentOffset michael@0: }; michael@0: } michael@0: properties.seacMap = seacMap; michael@0: } michael@0: michael@0: var unitsPerEm = 1 / (properties.fontMatrix || FONT_IDENTITY_MATRIX)[0]; michael@0: michael@0: var fields = { michael@0: // PostScript Font Program michael@0: 'CFF ': font.data, michael@0: michael@0: // OS/2 and Windows Specific metrics michael@0: 'OS/2': stringToArray(createOS2Table(properties, michael@0: newMapping.charCodeToGlyphId)), michael@0: michael@0: // Character to glyphs mapping michael@0: 'cmap': createCmapTable(newMapping.charCodeToGlyphId), michael@0: michael@0: // Font header michael@0: 'head': (function fontFieldsHead() { michael@0: return stringToArray( michael@0: '\x00\x01\x00\x00' + // Version number michael@0: '\x00\x00\x10\x00' + // fontRevision michael@0: '\x00\x00\x00\x00' + // checksumAdjustement michael@0: '\x5F\x0F\x3C\xF5' + // magicNumber michael@0: '\x00\x00' + // Flags michael@0: safeString16(unitsPerEm) + // unitsPerEM michael@0: '\x00\x00\x00\x00\x9e\x0b\x7e\x27' + // creation date michael@0: '\x00\x00\x00\x00\x9e\x0b\x7e\x27' + // modifification date michael@0: '\x00\x00' + // xMin michael@0: safeString16(properties.descent) + // yMin michael@0: '\x0F\xFF' + // xMax michael@0: safeString16(properties.ascent) + // yMax michael@0: string16(properties.italicAngle ? 2 : 0) + // macStyle michael@0: '\x00\x11' + // lowestRecPPEM michael@0: '\x00\x00' + // fontDirectionHint michael@0: '\x00\x00' + // indexToLocFormat michael@0: '\x00\x00'); // glyphDataFormat michael@0: })(), michael@0: michael@0: // Horizontal header michael@0: 'hhea': (function fontFieldsHhea() { michael@0: return stringToArray( michael@0: '\x00\x01\x00\x00' + // Version number michael@0: safeString16(properties.ascent) + // Typographic Ascent michael@0: safeString16(properties.descent) + // Typographic Descent michael@0: '\x00\x00' + // Line Gap michael@0: '\xFF\xFF' + // advanceWidthMax michael@0: '\x00\x00' + // minLeftSidebearing michael@0: '\x00\x00' + // minRightSidebearing michael@0: '\x00\x00' + // xMaxExtent michael@0: safeString16(properties.capHeight) + // caretSlopeRise michael@0: safeString16(Math.tan(properties.italicAngle) * michael@0: properties.xHeight) + // caretSlopeRun michael@0: '\x00\x00' + // caretOffset michael@0: '\x00\x00' + // -reserved- michael@0: '\x00\x00' + // -reserved- michael@0: '\x00\x00' + // -reserved- michael@0: '\x00\x00' + // -reserved- michael@0: '\x00\x00' + // metricDataFormat michael@0: string16(numGlyphs)); // Number of HMetrics michael@0: })(), michael@0: michael@0: // Horizontal metrics michael@0: 'hmtx': (function fontFieldsHmtx() { michael@0: var charstrings = font.charstrings; michael@0: var hmtx = '\x00\x00\x00\x00'; // Fake .notdef michael@0: for (var i = 1, ii = numGlyphs; i < ii; i++) { michael@0: // TODO: For CFF fonts the width should technically match th x in michael@0: // the glyph, but it doesn't seem to matter. michael@0: var charstring = charstrings ? charstrings[i - 1] : {}; michael@0: var width = 'width' in charstring ? charstring.width : 0; michael@0: hmtx += string16(width) + string16(0); michael@0: } michael@0: return stringToArray(hmtx); michael@0: })(), michael@0: michael@0: // Maximum profile michael@0: 'maxp': (function fontFieldsMaxp() { michael@0: return stringToArray( michael@0: '\x00\x00\x50\x00' + // Version number michael@0: string16(numGlyphs)); // Num of glyphs michael@0: })(), michael@0: michael@0: // Naming tables michael@0: 'name': stringToArray(createNameTable(fontName)), michael@0: michael@0: // PostScript informations michael@0: 'post': stringToArray(createPostTable(properties)) michael@0: }; michael@0: michael@0: var field; michael@0: for (field in fields) { michael@0: createTableEntry(otf, field, fields[field]); michael@0: } michael@0: for (field in fields) { michael@0: var table = fields[field]; michael@0: otf.file += bytesToString(new Uint8Array(table)); michael@0: } michael@0: michael@0: return stringToArray(otf.file); michael@0: }, michael@0: michael@0: /** michael@0: * Builds a char code to unicode map based on section 9.10 of the spec. michael@0: * @param {Object} properties Font properties object. michael@0: * @return {Object} Has two properties: 'toUnicode' which maps char codes to michael@0: * unicode (string) values and 'isIdentity' which is true if an identity map michael@0: * is used. michael@0: */ michael@0: buildToUnicode: function Font_buildToUnicode(properties) { michael@0: var map = { michael@0: isIdentity: false, michael@0: toUnicode: null michael@0: }; michael@0: // Section 9.10.2 Mapping Character Codes to Unicode Values michael@0: if (properties.toUnicode && properties.toUnicode.length !== 0) { michael@0: map.toUnicode = properties.toUnicode; michael@0: return map; michael@0: } michael@0: // According to the spec if the font is a simple font we should only map michael@0: // to unicode if the base encoding is MacRoman, MacExpert, or WinAnsi or michael@0: // the differences array only contains adobe standard or symbol set names, michael@0: // in pratice it seems better to always try to create a toUnicode michael@0: // map based of the default encoding. michael@0: var toUnicode, charcode; michael@0: if (!properties.composite /* is simple font */) { michael@0: toUnicode = []; michael@0: var encoding = properties.defaultEncoding.slice(); michael@0: // Merge in the differences array. michael@0: var differences = properties.differences; michael@0: for (charcode in differences) { michael@0: encoding[charcode] = differences[charcode]; michael@0: } michael@0: for (charcode in encoding) { michael@0: // a) Map the character code to a character name. michael@0: var glyphName = encoding[charcode]; michael@0: // b) Look up the character name in the Adobe Glyph List (see the michael@0: // Bibliography) to obtain the corresponding Unicode value. michael@0: if (glyphName === '' || !(glyphName in GlyphsUnicode)) { michael@0: // (undocumented) c) Few heuristics to recognize unknown glyphs michael@0: // NOTE: Adobe Reader does not do this step, but OSX Preview does michael@0: var code; michael@0: // Gxx glyph michael@0: if (glyphName.length === 3 && michael@0: glyphName[0] === 'G' && michael@0: (code = parseInt(glyphName.substr(1), 16))) { michael@0: toUnicode[charcode] = String.fromCharCode(code); michael@0: } michael@0: // Cddd glyph michael@0: if (glyphName.length >= 3 && michael@0: glyphName[0] === 'C' && michael@0: (code = +glyphName.substr(1))) { michael@0: toUnicode[charcode] = String.fromCharCode(code); michael@0: } michael@0: continue; michael@0: } michael@0: toUnicode[charcode] = String.fromCharCode(GlyphsUnicode[glyphName]); michael@0: } michael@0: map.toUnicode = toUnicode; michael@0: return map; michael@0: } michael@0: // If the font is a composite font that uses one of the predefined CMaps michael@0: // listed in Table 118 (except Identity–H and Identity–V) or whose michael@0: // descendant CIDFont uses the Adobe-GB1, Adobe-CNS1, Adobe-Japan1, or michael@0: // Adobe-Korea1 character collection: michael@0: if (properties.composite && ( michael@0: (properties.cMap.builtInCMap && michael@0: !(properties.cMap instanceof IdentityCMap)) || michael@0: (properties.cidSystemInfo.registry === 'Adobe' && michael@0: (properties.cidSystemInfo.ordering === 'GB1' || michael@0: properties.cidSystemInfo.ordering === 'CNS1' || michael@0: properties.cidSystemInfo.ordering === 'Japan1' || michael@0: properties.cidSystemInfo.ordering === 'Korea1')))) { michael@0: // Then: michael@0: // a) Map the character code to a character identifier (CID) according michael@0: // to the font’s CMap. michael@0: // b) Obtain the registry and ordering of the character collection used michael@0: // by the font’s CMap (for example, Adobe and Japan1) from its michael@0: // CIDSystemInfo dictionary. michael@0: var registry = properties.cidSystemInfo.registry; michael@0: var ordering = properties.cidSystemInfo.ordering; michael@0: // c) Construct a second CMap name by concatenating the registry and michael@0: // ordering obtained in step (b) in the format registry–ordering–UCS2 michael@0: // (for example, Adobe–Japan1–UCS2). michael@0: var ucs2CMapName = new Name(registry + '-' + ordering + '-UCS2'); michael@0: // d) Obtain the CMap with the name constructed in step (c) (available michael@0: // from the ASN Web site; see the Bibliography). michael@0: var ucs2CMap = CMapFactory.create(ucs2CMapName, michael@0: { url: PDFJS.cMapUrl, packed: PDFJS.cMapPacked }, null); michael@0: var cMap = properties.cMap; michael@0: toUnicode = []; michael@0: for (charcode in cMap.map) { michael@0: var cid = cMap.map[charcode]; michael@0: assert(cid.length === 1, 'Max size of CID is 65,535'); michael@0: // e) Map the CID obtained in step (a) according to the CMap obtained michael@0: // in step (d), producing a Unicode value. michael@0: var ucs2 = ucs2CMap.map[cid.charCodeAt(0)]; michael@0: if (!ucs2) { michael@0: continue; michael@0: } michael@0: toUnicode[charcode] = String.fromCharCode((ucs2.charCodeAt(0) << 8) + michael@0: ucs2.charCodeAt(1)); michael@0: } michael@0: map.toUnicode = toUnicode; michael@0: return map; michael@0: } michael@0: michael@0: // The viewer's choice, just use an identity map. michael@0: toUnicode = []; michael@0: var firstChar = properties.firstChar, lastChar = properties.lastChar; michael@0: for (var i = firstChar; i <= lastChar; i++) { michael@0: toUnicode[i] = String.fromCharCode(i); michael@0: } michael@0: map.isIdentity = true; michael@0: map.toUnicode = toUnicode; michael@0: return map; michael@0: }, michael@0: michael@0: get spaceWidth() { michael@0: if ('_shadowWidth' in this) { michael@0: return this._shadowWidth; michael@0: } michael@0: michael@0: // trying to estimate space character width michael@0: var possibleSpaceReplacements = ['space', 'minus', 'one', 'i']; michael@0: var width; michael@0: for (var i = 0, ii = possibleSpaceReplacements.length; i < ii; i++) { michael@0: var glyphName = possibleSpaceReplacements[i]; michael@0: // if possible, getting width by glyph name michael@0: if (glyphName in this.widths) { michael@0: width = this.widths[glyphName]; michael@0: break; michael@0: } michael@0: var glyphUnicode = GlyphsUnicode[glyphName]; michael@0: // finding the charcode via unicodeToCID map michael@0: var charcode = 0; michael@0: if (this.composite) { michael@0: if (glyphUnicode in this.cMap.map) { michael@0: charcode = this.cMap.lookup(glyphUnicode).charCodeAt(0); michael@0: } michael@0: } michael@0: // ... via toUnicode map michael@0: if (!charcode && 'toUnicode' in this) { michael@0: charcode = this.toUnicode.indexOf(glyphUnicode); michael@0: } michael@0: // setting it to unicode if negative or undefined michael@0: if (charcode <= 0) { michael@0: charcode = glyphUnicode; michael@0: } michael@0: // trying to get width via charcode michael@0: width = this.widths[charcode]; michael@0: if (width) { michael@0: break; // the non-zero width found michael@0: } michael@0: } michael@0: width = width || this.defaultWidth; michael@0: // Do not shadow the property here. See discussion: michael@0: // https://github.com/mozilla/pdf.js/pull/2127#discussion_r1662280 michael@0: this._shadowWidth = width; michael@0: return width; michael@0: }, michael@0: michael@0: charToGlyph: function Font_charToGlyph(charcode) { michael@0: var fontCharCode, width, operatorList; michael@0: michael@0: var widthCode = charcode; michael@0: if (this.cMap && charcode in this.cMap.map) { michael@0: widthCode = this.cMap.map[charcode].charCodeAt(0); michael@0: } michael@0: width = this.widths[widthCode]; michael@0: width = isNum(width) ? width : this.defaultWidth; michael@0: var vmetric = this.vmetrics && this.vmetrics[widthCode]; michael@0: michael@0: var unicode = this.toUnicode[charcode] || charcode; michael@0: if (typeof unicode === 'number') { michael@0: unicode = String.fromCharCode(unicode); michael@0: } michael@0: michael@0: // First try the toFontChar map, if it's not there then try falling michael@0: // back to the char code. michael@0: fontCharCode = this.toFontChar[charcode] || charcode; michael@0: if (this.missingFile) { michael@0: fontCharCode = mapSpecialUnicodeValues(fontCharCode); michael@0: } michael@0: michael@0: if (this.type === 'Type3') { michael@0: // Font char code in this case is actually a glyph name. michael@0: operatorList = this.charProcOperatorList[fontCharCode]; michael@0: } michael@0: michael@0: var accent = null; michael@0: if (this.seacMap && this.seacMap[charcode]) { michael@0: var seac = this.seacMap[charcode]; michael@0: fontCharCode = seac.baseFontCharCode; michael@0: accent = { michael@0: fontChar: String.fromCharCode(seac.accentFontCharCode), michael@0: offset: seac.accentOffset michael@0: }; michael@0: } michael@0: michael@0: var fontChar = String.fromCharCode(fontCharCode); michael@0: michael@0: var glyph = this.glyphCache[charcode]; michael@0: if (!glyph || michael@0: !glyph.matchesForCache(fontChar, unicode, accent, width, vmetric, michael@0: operatorList)) { michael@0: glyph = new Glyph(fontChar, unicode, accent, width, vmetric, michael@0: operatorList); michael@0: this.glyphCache[charcode] = glyph; michael@0: } michael@0: return glyph; michael@0: }, michael@0: michael@0: charsToGlyphs: function Font_charsToGlyphs(chars) { michael@0: var charsCache = this.charsCache; michael@0: var glyphs, glyph, charcode; michael@0: michael@0: // if we translated this string before, just grab it from the cache michael@0: if (charsCache) { michael@0: glyphs = charsCache[chars]; michael@0: if (glyphs) { michael@0: return glyphs; michael@0: } michael@0: } michael@0: michael@0: // lazily create the translation cache michael@0: if (!charsCache) { michael@0: charsCache = this.charsCache = Object.create(null); michael@0: } michael@0: michael@0: glyphs = []; michael@0: var charsCacheKey = chars; michael@0: var i = 0, ii; michael@0: michael@0: if (this.cMap) { michael@0: // composite fonts have multi-byte strings convert the string from michael@0: // single-byte to multi-byte michael@0: while (i < chars.length) { michael@0: var c = this.cMap.readCharCode(chars, i); michael@0: charcode = c[0]; michael@0: var length = c[1]; michael@0: i += length; michael@0: glyph = this.charToGlyph(charcode); michael@0: glyphs.push(glyph); michael@0: // placing null after each word break charcode (ASCII SPACE) michael@0: // Ignore occurences of 0x20 in multiple-byte codes. michael@0: if (length === 1 && chars.charCodeAt(i - 1) === 0x20) { michael@0: glyphs.push(null); michael@0: } michael@0: } michael@0: } else { michael@0: for (i = 0, ii = chars.length; i < ii; ++i) { michael@0: charcode = chars.charCodeAt(i); michael@0: glyph = this.charToGlyph(charcode); michael@0: glyphs.push(glyph); michael@0: if (charcode == 0x20) { michael@0: glyphs.push(null); michael@0: } michael@0: } michael@0: } michael@0: michael@0: // Enter the translated string into the cache michael@0: return (charsCache[charsCacheKey] = glyphs); michael@0: } michael@0: }; michael@0: michael@0: return Font; michael@0: })(); michael@0: michael@0: var ErrorFont = (function ErrorFontClosure() { michael@0: function ErrorFont(error) { michael@0: this.error = error; michael@0: } michael@0: michael@0: ErrorFont.prototype = { michael@0: charsToGlyphs: function ErrorFont_charsToGlyphs() { michael@0: return []; michael@0: }, michael@0: exportData: function ErrorFont_exportData() { michael@0: return {error: this.error}; michael@0: } michael@0: }; michael@0: michael@0: return ErrorFont; michael@0: })(); michael@0: michael@0: /** michael@0: * Shared logic for building a char code to glyph id mapping for Type1 and michael@0: * simple CFF fonts. See section 9.6.6.2 of the spec. michael@0: * @param {Object} properties Font properties object. michael@0: * @param {Object} builtInEncoding The encoding contained within the actual font michael@0: * data. michael@0: * @param {Array} Array of glyph names where the index is the glyph ID. michael@0: * @returns {Object} A char code to glyph ID map. michael@0: */ michael@0: function type1FontGlyphMapping(properties, builtInEncoding, glyphNames) { michael@0: var charCodeToGlyphId = Object.create(null); michael@0: var glyphId, charCode, baseEncoding; michael@0: michael@0: if (properties.baseEncodingName) { michael@0: // If a valid base encoding name was used, the mapping is initialized with michael@0: // that. michael@0: baseEncoding = Encodings[properties.baseEncodingName]; michael@0: for (charCode = 0; charCode < baseEncoding.length; charCode++) { michael@0: glyphId = glyphNames.indexOf(baseEncoding[charCode]); michael@0: if (glyphId >= 0) { michael@0: charCodeToGlyphId[charCode] = glyphId; michael@0: } michael@0: } michael@0: } else if (!!(properties.flags & FontFlags.Symbolic)) { michael@0: // For a symbolic font the encoding should be the fonts built-in michael@0: // encoding. michael@0: for (charCode in builtInEncoding) { michael@0: charCodeToGlyphId[charCode] = builtInEncoding[charCode]; michael@0: } michael@0: } else { michael@0: // For non-symbolic fonts that don't have a base encoding the standard michael@0: // encoding should be used. michael@0: baseEncoding = Encodings.StandardEncoding; michael@0: for (charCode = 0; charCode < baseEncoding.length; charCode++) { michael@0: glyphId = glyphNames.indexOf(baseEncoding[charCode]); michael@0: if (glyphId >= 0) { michael@0: charCodeToGlyphId[charCode] = glyphId; michael@0: } michael@0: } michael@0: } michael@0: michael@0: // Lastly, merge in the differences. michael@0: var differences = properties.differences; michael@0: if (differences) { michael@0: for (charCode in differences) { michael@0: var glyphName = differences[charCode]; michael@0: glyphId = glyphNames.indexOf(glyphName); michael@0: if (glyphId >= 0) { michael@0: charCodeToGlyphId[charCode] = glyphId; michael@0: } michael@0: } michael@0: } michael@0: return charCodeToGlyphId; michael@0: } michael@0: michael@0: /* michael@0: * CharStrings are encoded following the the CharString Encoding sequence michael@0: * describe in Chapter 6 of the "Adobe Type1 Font Format" specification. michael@0: * The value in a byte indicates a command, a number, or subsequent bytes michael@0: * that are to be interpreted in a special way. michael@0: * michael@0: * CharString Number Encoding: michael@0: * A CharString byte containing the values from 32 through 255 inclusive michael@0: * indicate an integer. These values are decoded in four ranges. michael@0: * michael@0: * 1. A CharString byte containing a value, v, between 32 and 246 inclusive, michael@0: * indicate the integer v - 139. Thus, the integer values from -107 through michael@0: * 107 inclusive may be encoded in single byte. michael@0: * michael@0: * 2. A CharString byte containing a value, v, between 247 and 250 inclusive, michael@0: * indicates an integer involving the next byte, w, according to the formula: michael@0: * [(v - 247) x 256] + w + 108 michael@0: * michael@0: * 3. A CharString byte containing a value, v, between 251 and 254 inclusive, michael@0: * indicates an integer involving the next byte, w, according to the formula: michael@0: * -[(v - 251) * 256] - w - 108 michael@0: * michael@0: * 4. A CharString containing the value 255 indicates that the next 4 bytes michael@0: * are a two complement signed integer. The first of these bytes contains the michael@0: * highest order bits, the second byte contains the next higher order bits michael@0: * and the fourth byte contain the lowest order bits. michael@0: * michael@0: * michael@0: * CharString Command Encoding: michael@0: * CharStrings commands are encoded in 1 or 2 bytes. michael@0: * michael@0: * Single byte commands are encoded in 1 byte that contains a value between michael@0: * 0 and 31 inclusive. michael@0: * If a command byte contains the value 12, then the value in the next byte michael@0: * indicates a command. This "escape" mechanism allows many extra commands michael@0: * to be encoded and this encoding technique helps to minimize the length of michael@0: * the charStrings. michael@0: */ michael@0: var Type1CharString = (function Type1CharStringClosure() { michael@0: var COMMAND_MAP = { michael@0: 'hstem': [1], michael@0: 'vstem': [3], michael@0: 'vmoveto': [4], michael@0: 'rlineto': [5], michael@0: 'hlineto': [6], michael@0: 'vlineto': [7], michael@0: 'rrcurveto': [8], michael@0: 'callsubr': [10], michael@0: 'flex': [12, 35], michael@0: 'drop' : [12, 18], michael@0: 'endchar': [14], michael@0: 'rmoveto': [21], michael@0: 'hmoveto': [22], michael@0: 'vhcurveto': [30], michael@0: 'hvcurveto': [31] michael@0: }; michael@0: michael@0: function Type1CharString() { michael@0: this.width = 0; michael@0: this.lsb = 0; michael@0: this.flexing = false; michael@0: this.output = []; michael@0: this.stack = []; michael@0: } michael@0: michael@0: Type1CharString.prototype = { michael@0: convert: function Type1CharString_convert(encoded, subrs) { michael@0: var count = encoded.length; michael@0: var error = false; michael@0: var wx, sbx, subrNumber; michael@0: for (var i = 0; i < count; i++) { michael@0: var value = encoded[i]; michael@0: if (value < 32) { michael@0: if (value === 12) { michael@0: value = (value << 8) + encoded[++i]; michael@0: } michael@0: switch (value) { michael@0: case 1: // hstem michael@0: if (!HINTING_ENABLED) { michael@0: this.stack = []; michael@0: break; michael@0: } michael@0: error = this.executeCommand(2, COMMAND_MAP.hstem); michael@0: break; michael@0: case 3: // vstem michael@0: if (!HINTING_ENABLED) { michael@0: this.stack = []; michael@0: break; michael@0: } michael@0: error = this.executeCommand(2, COMMAND_MAP.vstem); michael@0: break; michael@0: case 4: // vmoveto michael@0: if (this.flexing) { michael@0: if (this.stack.length < 1) { michael@0: error = true; michael@0: break; michael@0: } michael@0: // Add the dx for flex and but also swap the values so they are michael@0: // the right order. michael@0: var dy = this.stack.pop(); michael@0: this.stack.push(0, dy); michael@0: break; michael@0: } michael@0: error = this.executeCommand(1, COMMAND_MAP.vmoveto); michael@0: break; michael@0: case 5: // rlineto michael@0: error = this.executeCommand(2, COMMAND_MAP.rlineto); michael@0: break; michael@0: case 6: // hlineto michael@0: error = this.executeCommand(1, COMMAND_MAP.hlineto); michael@0: break; michael@0: case 7: // vlineto michael@0: error = this.executeCommand(1, COMMAND_MAP.vlineto); michael@0: break; michael@0: case 8: // rrcurveto michael@0: error = this.executeCommand(6, COMMAND_MAP.rrcurveto); michael@0: break; michael@0: case 9: // closepath michael@0: // closepath is a Type1 command that does not take argument and is michael@0: // useless in Type2 and it can simply be ignored. michael@0: this.stack = []; michael@0: break; michael@0: case 10: // callsubr michael@0: if (this.stack.length < 1) { michael@0: error = true; michael@0: break; michael@0: } michael@0: subrNumber = this.stack.pop(); michael@0: error = this.convert(subrs[subrNumber], subrs); michael@0: break; michael@0: case 11: // return michael@0: return error; michael@0: case 13: // hsbw michael@0: if (this.stack.length < 2) { michael@0: error = true; michael@0: break; michael@0: } michael@0: // To convert to type2 we have to move the width value to the michael@0: // first part of the charstring and then use hmoveto with lsb. michael@0: wx = this.stack.pop(); michael@0: sbx = this.stack.pop(); michael@0: this.lsb = sbx; michael@0: this.width = wx; michael@0: this.stack.push(sbx); michael@0: error = this.executeCommand(1, COMMAND_MAP.hmoveto); michael@0: break; michael@0: case 14: // endchar michael@0: this.output.push(COMMAND_MAP.endchar[0]); michael@0: break; michael@0: case 21: // rmoveto michael@0: if (this.flexing) { michael@0: break; michael@0: } michael@0: error = this.executeCommand(2, COMMAND_MAP.rmoveto); michael@0: break; michael@0: case 22: // hmoveto michael@0: if (this.flexing) { michael@0: // Add the dy for flex. michael@0: this.stack.push(0); michael@0: break; michael@0: } michael@0: error = this.executeCommand(1, COMMAND_MAP.hmoveto); michael@0: break; michael@0: case 30: // vhcurveto michael@0: error = this.executeCommand(4, COMMAND_MAP.vhcurveto); michael@0: break; michael@0: case 31: // hvcurveto michael@0: error = this.executeCommand(4, COMMAND_MAP.hvcurveto); michael@0: break; michael@0: case (12 << 8) + 0: // dotsection michael@0: // dotsection is a Type1 command to specify some hinting feature michael@0: // for dots that do not take a parameter and it can safely be michael@0: // ignored for Type2. michael@0: this.stack = []; michael@0: break; michael@0: case (12 << 8) + 1: // vstem3 michael@0: if (!HINTING_ENABLED) { michael@0: this.stack = []; michael@0: break; michael@0: } michael@0: // [vh]stem3 are Type1 only and Type2 supports [vh]stem with michael@0: // multiple parameters, so instead of returning [vh]stem3 take a michael@0: // shortcut and return [vhstem] instead. michael@0: error = this.executeCommand(2, COMMAND_MAP.vstem); michael@0: break; michael@0: case (12 << 8) + 2: // hstem3 michael@0: if (!HINTING_ENABLED) { michael@0: this.stack = []; michael@0: break; michael@0: } michael@0: // See vstem3. michael@0: error = this.executeCommand(2, COMMAND_MAP.hstem); michael@0: break; michael@0: case (12 << 8) + 6: // seac michael@0: // seac is like type 2's special endchar but it doesn't use the michael@0: // first argument asb, so remove it. michael@0: if (SEAC_ANALYSIS_ENABLED) { michael@0: this.seac = this.stack.splice(-4, 4); michael@0: error = this.executeCommand(0, COMMAND_MAP.endchar); michael@0: } else { michael@0: error = this.executeCommand(4, COMMAND_MAP.endchar); michael@0: } michael@0: break; michael@0: case (12 << 8) + 7: // sbw michael@0: if (this.stack.length < 4) { michael@0: error = true; michael@0: break; michael@0: } michael@0: // To convert to type2 we have to move the width value to the michael@0: // first part of the charstring and then use rmoveto with michael@0: // (dx, dy). The height argument will not be used for vmtx and michael@0: // vhea tables reconstruction -- ignoring it. michael@0: var wy = this.stack.pop(); michael@0: wx = this.stack.pop(); michael@0: var sby = this.stack.pop(); michael@0: sbx = this.stack.pop(); michael@0: this.lsb = sbx; michael@0: this.width = wx; michael@0: this.stack.push(sbx, sby); michael@0: error = this.executeCommand(2, COMMAND_MAP.rmoveto); michael@0: break; michael@0: case (12 << 8) + 12: // div michael@0: if (this.stack.length < 2) { michael@0: error = true; michael@0: break; michael@0: } michael@0: var num2 = this.stack.pop(); michael@0: var num1 = this.stack.pop(); michael@0: this.stack.push(num1 / num2); michael@0: break; michael@0: case (12 << 8) + 16: // callothersubr michael@0: if (this.stack.length < 2) { michael@0: error = true; michael@0: break; michael@0: } michael@0: subrNumber = this.stack.pop(); michael@0: var numArgs = this.stack.pop(); michael@0: if (subrNumber === 0 && numArgs === 3) { michael@0: var flexArgs = this.stack.splice(this.stack.length - 17, 17); michael@0: this.stack.push( michael@0: flexArgs[2] + flexArgs[0], // bcp1x + rpx michael@0: flexArgs[3] + flexArgs[1], // bcp1y + rpy michael@0: flexArgs[4], // bcp2x michael@0: flexArgs[5], // bcp2y michael@0: flexArgs[6], // p2x michael@0: flexArgs[7], // p2y michael@0: flexArgs[8], // bcp3x michael@0: flexArgs[9], // bcp3y michael@0: flexArgs[10], // bcp4x michael@0: flexArgs[11], // bcp4y michael@0: flexArgs[12], // p3x michael@0: flexArgs[13], // p3y michael@0: flexArgs[14] // flexDepth michael@0: // 15 = finalx unused by flex michael@0: // 16 = finaly unused by flex michael@0: ); michael@0: error = this.executeCommand(13, COMMAND_MAP.flex, true); michael@0: this.flexing = false; michael@0: this.stack.push(flexArgs[15], flexArgs[16]); michael@0: } else if (subrNumber === 1 && numArgs === 0) { michael@0: this.flexing = true; michael@0: } michael@0: break; michael@0: case (12 << 8) + 17: // pop michael@0: // Ignore this since it is only used with othersubr. michael@0: break; michael@0: case (12 << 8) + 33: // setcurrentpoint michael@0: // Ignore for now. michael@0: this.stack = []; michael@0: break; michael@0: default: michael@0: warn('Unknown type 1 charstring command of "' + value + '"'); michael@0: break; michael@0: } michael@0: if (error) { michael@0: break; michael@0: } michael@0: continue; michael@0: } else if (value <= 246) { michael@0: value = value - 139; michael@0: } else if (value <= 250) { michael@0: value = ((value - 247) * 256) + encoded[++i] + 108; michael@0: } else if (value <= 254) { michael@0: value = -((value - 251) * 256) - encoded[++i] - 108; michael@0: } else { michael@0: value = (encoded[++i] & 0xff) << 24 | (encoded[++i] & 0xff) << 16 | michael@0: (encoded[++i] & 0xff) << 8 | (encoded[++i] & 0xff) << 0; michael@0: } michael@0: this.stack.push(value); michael@0: } michael@0: return error; michael@0: }, michael@0: michael@0: executeCommand: function(howManyArgs, command, keepStack) { michael@0: var stackLength = this.stack.length; michael@0: if (howManyArgs > stackLength) { michael@0: return true; michael@0: } michael@0: var start = stackLength - howManyArgs; michael@0: for (var i = start; i < stackLength; i++) { michael@0: var value = this.stack[i]; michael@0: if (value === (value | 0)) { // int michael@0: this.output.push(28, (value >> 8) & 0xff, value & 0xff); michael@0: } else { // fixed point michael@0: value = (65536 * value) | 0; michael@0: this.output.push(255, michael@0: (value >> 24) & 0xFF, michael@0: (value >> 16) & 0xFF, michael@0: (value >> 8) & 0xFF, michael@0: value & 0xFF); michael@0: } michael@0: } michael@0: this.output.push.apply(this.output, command); michael@0: if (keepStack) { michael@0: this.stack.splice(start, howManyArgs); michael@0: } else { michael@0: this.stack.length = 0; michael@0: } michael@0: return false; michael@0: } michael@0: }; michael@0: michael@0: return Type1CharString; michael@0: })(); michael@0: michael@0: /* michael@0: * Type1Parser encapsulate the needed code for parsing a Type1 font michael@0: * program. Some of its logic depends on the Type2 charstrings michael@0: * structure. michael@0: * Note: this doesn't really parse the font since that would require evaluation michael@0: * of PostScript, but it is possible in most cases to extract what we need michael@0: * without a full parse. michael@0: */ michael@0: var Type1Parser = (function Type1ParserClosure() { michael@0: /* michael@0: * Decrypt a Sequence of Ciphertext Bytes to Produce the Original Sequence michael@0: * of Plaintext Bytes. The function took a key as a parameter which can be michael@0: * for decrypting the eexec block of for decoding charStrings. michael@0: */ michael@0: var EEXEC_ENCRYPT_KEY = 55665; michael@0: var CHAR_STRS_ENCRYPT_KEY = 4330; michael@0: michael@0: function isHexDigit(code) { michael@0: return code >= 48 && code <= 57 || // '0'-'9' michael@0: code >= 65 && code <= 70 || // 'A'-'F' michael@0: code >= 97 && code <= 102; // 'a'-'f' michael@0: } michael@0: michael@0: function decrypt(data, key, discardNumber) { michael@0: var r = key | 0, c1 = 52845, c2 = 22719; michael@0: var count = data.length; michael@0: var decrypted = new Uint8Array(count); michael@0: for (var i = 0; i < count; i++) { michael@0: var value = data[i]; michael@0: decrypted[i] = value ^ (r >> 8); michael@0: r = ((value + r) * c1 + c2) & ((1 << 16) - 1); michael@0: } michael@0: return Array.prototype.slice.call(decrypted, discardNumber); michael@0: } michael@0: michael@0: function decryptAscii(data, key, discardNumber) { michael@0: var r = key | 0, c1 = 52845, c2 = 22719; michael@0: var count = data.length, maybeLength = count >>> 1; michael@0: var decrypted = new Uint8Array(maybeLength); michael@0: var i, j; michael@0: for (i = 0, j = 0; i < count; i++) { michael@0: var digit1 = data[i]; michael@0: if (!isHexDigit(digit1)) { michael@0: continue; michael@0: } michael@0: i++; michael@0: var digit2; michael@0: while (i < count && !isHexDigit(digit2 = data[i])) { michael@0: i++; michael@0: } michael@0: if (i < count) { michael@0: var value = parseInt(String.fromCharCode(digit1, digit2), 16); michael@0: decrypted[j++] = value ^ (r >> 8); michael@0: r = ((value + r) * c1 + c2) & ((1 << 16) - 1); michael@0: } michael@0: } michael@0: return Array.prototype.slice.call(decrypted, discardNumber, j); michael@0: } michael@0: michael@0: function isSpecial(c) { michael@0: return c === 0x2F || // '/' michael@0: c === 0x5B || c === 0x5D || // '[', ']' michael@0: c === 0x7B || c === 0x7D || // '{', '}' michael@0: c === 0x28 || c === 0x29; // '(', ')' michael@0: } michael@0: michael@0: function Type1Parser(stream, encrypted) { michael@0: if (encrypted) { michael@0: var data = stream.getBytes(); michael@0: var isBinary = !(isHexDigit(data[0]) && isHexDigit(data[1]) && michael@0: isHexDigit(data[2]) && isHexDigit(data[3])); michael@0: stream = new Stream(isBinary ? decrypt(data, EEXEC_ENCRYPT_KEY, 4) : michael@0: decryptAscii(data, EEXEC_ENCRYPT_KEY, 4)); michael@0: } michael@0: this.stream = stream; michael@0: this.nextChar(); michael@0: } michael@0: michael@0: Type1Parser.prototype = { michael@0: readNumberArray: function Type1Parser_readNumberArray() { michael@0: this.getToken(); // read '[' or '{' (arrays can start with either) michael@0: var array = []; michael@0: while (true) { michael@0: var token = this.getToken(); michael@0: if (token === null || token === ']' || token === '}') { michael@0: break; michael@0: } michael@0: array.push(parseFloat(token || 0)); michael@0: } michael@0: return array; michael@0: }, michael@0: michael@0: readNumber: function Type1Parser_readNumber() { michael@0: var token = this.getToken(); michael@0: return parseFloat(token || 0); michael@0: }, michael@0: michael@0: readInt: function Type1Parser_readInt() { michael@0: // Use '| 0' to prevent setting a double into length such as the double michael@0: // does not flow into the loop variable. michael@0: var token = this.getToken(); michael@0: return parseInt(token || 0, 10) | 0; michael@0: }, michael@0: michael@0: readBoolean: function Type1Parser_readBoolean() { michael@0: var token = this.getToken(); michael@0: michael@0: // Use 1 and 0 since that's what type2 charstrings use. michael@0: return token === 'true' ? 1 : 0; michael@0: }, michael@0: michael@0: nextChar : function Type1_nextChar() { michael@0: return (this.currentChar = this.stream.getByte()); michael@0: }, michael@0: michael@0: getToken: function Type1Parser_getToken() { michael@0: // Eat whitespace and comments. michael@0: var comment = false; michael@0: var ch = this.currentChar; michael@0: while (true) { michael@0: if (ch === -1) { michael@0: return null; michael@0: } michael@0: michael@0: if (comment) { michael@0: if (ch === 0x0A || ch === 0x0D) { michael@0: comment = false; michael@0: } michael@0: } else if (ch === 0x25) { // '%' michael@0: comment = true; michael@0: } else if (!Lexer.isSpace(ch)) { michael@0: break; michael@0: } michael@0: ch = this.nextChar(); michael@0: } michael@0: if (isSpecial(ch)) { michael@0: this.nextChar(); michael@0: return String.fromCharCode(ch); michael@0: } michael@0: var token = ''; michael@0: do { michael@0: token += String.fromCharCode(ch); michael@0: ch = this.nextChar(); michael@0: } while (ch >= 0 && !Lexer.isSpace(ch) && !isSpecial(ch)); michael@0: return token; michael@0: }, michael@0: michael@0: /* michael@0: * Returns an object containing a Subrs array and a CharStrings michael@0: * array extracted from and eexec encrypted block of data michael@0: */ michael@0: extractFontProgram: function Type1Parser_extractFontProgram() { michael@0: var stream = this.stream; michael@0: michael@0: var subrs = [], charstrings = []; michael@0: var program = { michael@0: subrs: [], michael@0: charstrings: [], michael@0: properties: { michael@0: 'privateData': { michael@0: 'lenIV': 4 michael@0: } michael@0: } michael@0: }; michael@0: var token, length, data, lenIV, encoded; michael@0: while ((token = this.getToken()) !== null) { michael@0: if (token !== '/') { michael@0: continue; michael@0: } michael@0: token = this.getToken(); michael@0: switch (token) { michael@0: case 'CharStrings': michael@0: // The number immediately following CharStrings must be greater or michael@0: // equal to the number of CharStrings. michael@0: this.getToken(); michael@0: this.getToken(); // read in 'dict' michael@0: this.getToken(); // read in 'dup' michael@0: this.getToken(); // read in 'begin' michael@0: while(true) { michael@0: token = this.getToken(); michael@0: if (token === null || token === 'end') { michael@0: break; michael@0: } michael@0: michael@0: if (token !== '/') { michael@0: continue; michael@0: } michael@0: var glyph = this.getToken(); michael@0: length = this.readInt(); michael@0: this.getToken(); // read in 'RD' or '-|' michael@0: data = stream.makeSubStream(stream.pos, length); michael@0: lenIV = program.properties.privateData['lenIV']; michael@0: encoded = decrypt(data.getBytes(), CHAR_STRS_ENCRYPT_KEY, lenIV); michael@0: // Skip past the required space and binary data. michael@0: stream.skip(length); michael@0: this.nextChar(); michael@0: token = this.getToken(); // read in 'ND' or '|-' michael@0: if (token === 'noaccess') { michael@0: this.getToken(); // read in 'def' michael@0: } michael@0: charstrings.push({ michael@0: glyph: glyph, michael@0: encoded: encoded michael@0: }); michael@0: } michael@0: break; michael@0: case 'Subrs': michael@0: var num = this.readInt(); michael@0: this.getToken(); // read in 'array' michael@0: while ((token = this.getToken()) === 'dup') { michael@0: var index = this.readInt(); michael@0: length = this.readInt(); michael@0: this.getToken(); // read in 'RD' or '-|' michael@0: data = stream.makeSubStream(stream.pos, length); michael@0: lenIV = program.properties.privateData['lenIV']; michael@0: encoded = decrypt(data.getBytes(), CHAR_STRS_ENCRYPT_KEY, lenIV); michael@0: // Skip past the required space and binary data. michael@0: stream.skip(length); michael@0: this.nextChar(); michael@0: token = this.getToken(); // read in 'NP' or '|' michael@0: if (token === 'noaccess') { michael@0: this.getToken(); // read in 'put' michael@0: } michael@0: subrs[index] = encoded; michael@0: } michael@0: break; michael@0: case 'BlueValues': michael@0: case 'OtherBlues': michael@0: case 'FamilyBlues': michael@0: case 'FamilyOtherBlues': michael@0: var blueArray = this.readNumberArray(); michael@0: // *Blue* values may contain invalid data: disables reading of michael@0: // those values when hinting is disabled. michael@0: if (blueArray.length > 0 && (blueArray.length % 2) === 0 && michael@0: HINTING_ENABLED) { michael@0: program.properties.privateData[token] = blueArray; michael@0: } michael@0: break; michael@0: case 'StemSnapH': michael@0: case 'StemSnapV': michael@0: program.properties.privateData[token] = this.readNumberArray(); michael@0: break; michael@0: case 'StdHW': michael@0: case 'StdVW': michael@0: program.properties.privateData[token] = michael@0: this.readNumberArray()[0]; michael@0: break; michael@0: case 'BlueShift': michael@0: case 'lenIV': michael@0: case 'BlueFuzz': michael@0: case 'BlueScale': michael@0: case 'LanguageGroup': michael@0: case 'ExpansionFactor': michael@0: program.properties.privateData[token] = this.readNumber(); michael@0: break; michael@0: case 'ForceBold': michael@0: program.properties.privateData[token] = this.readBoolean(); michael@0: break; michael@0: } michael@0: } michael@0: michael@0: for (var i = 0; i < charstrings.length; i++) { michael@0: glyph = charstrings[i].glyph; michael@0: encoded = charstrings[i].encoded; michael@0: var charString = new Type1CharString(); michael@0: var error = charString.convert(encoded, subrs); michael@0: var output = charString.output; michael@0: if (error) { michael@0: // It seems when FreeType encounters an error while evaluating a glyph michael@0: // that it completely ignores the glyph so we'll mimic that behaviour michael@0: // here and put an endchar to make the validator happy. michael@0: output = [14]; michael@0: } michael@0: program.charstrings.push({ michael@0: glyphName: glyph, michael@0: charstring: output, michael@0: width: charString.width, michael@0: lsb: charString.lsb, michael@0: seac: charString.seac michael@0: }); michael@0: } michael@0: michael@0: return program; michael@0: }, michael@0: michael@0: extractFontHeader: function Type1Parser_extractFontHeader(properties) { michael@0: var token; michael@0: while ((token = this.getToken()) !== null) { michael@0: if (token !== '/') { michael@0: continue; michael@0: } michael@0: token = this.getToken(); michael@0: switch (token) { michael@0: case 'FontMatrix': michael@0: var matrix = this.readNumberArray(); michael@0: properties.fontMatrix = matrix; michael@0: break; michael@0: case 'Encoding': michael@0: var encodingArg = this.getToken(); michael@0: var encoding; michael@0: if (!/^\d+$/.test(encodingArg)) { michael@0: // encoding name is specified michael@0: encoding = Encodings[encodingArg]; michael@0: } else { michael@0: encoding = []; michael@0: var size = parseInt(encodingArg, 10) | 0; michael@0: this.getToken(); // read in 'array' michael@0: michael@0: for (var j = 0; j < size; j++) { michael@0: token = this.getToken(); michael@0: // skipping till first dup or def (e.g. ignoring for statement) michael@0: while (token !== 'dup' && token !== 'def') { michael@0: token = this.getToken(); michael@0: if (token === null) { michael@0: return; // invalid header michael@0: } michael@0: } michael@0: if (token === 'def') { michael@0: break; // read all array data michael@0: } michael@0: var index = this.readInt(); michael@0: this.getToken(); // read in '/' michael@0: var glyph = this.getToken(); michael@0: encoding[index] = glyph; michael@0: this.getToken(); // read the in 'put' michael@0: } michael@0: } michael@0: properties.builtInEncoding = encoding; michael@0: break; michael@0: case 'FontBBox': michael@0: var fontBBox = this.readNumberArray(); michael@0: // adjusting ascent/descent michael@0: properties.ascent = fontBBox[3]; michael@0: properties.descent = fontBBox[1]; michael@0: properties.ascentScaled = true; michael@0: break; michael@0: } michael@0: } michael@0: } michael@0: }; michael@0: michael@0: return Type1Parser; michael@0: })(); michael@0: michael@0: /** michael@0: * The CFF class takes a Type1 file and wrap it into a michael@0: * 'Compact Font Format' which itself embed Type2 charstrings. michael@0: */ michael@0: var CFFStandardStrings = [ michael@0: '.notdef', 'space', 'exclam', 'quotedbl', 'numbersign', 'dollar', 'percent', michael@0: 'ampersand', 'quoteright', 'parenleft', 'parenright', 'asterisk', 'plus', michael@0: 'comma', 'hyphen', 'period', 'slash', 'zero', 'one', 'two', 'three', 'four', michael@0: 'five', 'six', 'seven', 'eight', 'nine', 'colon', 'semicolon', 'less', michael@0: 'equal', 'greater', 'question', 'at', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', michael@0: 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', michael@0: 'X', 'Y', 'Z', 'bracketleft', 'backslash', 'bracketright', 'asciicircum', michael@0: 'underscore', 'quoteleft', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', michael@0: 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', michael@0: 'z', 'braceleft', 'bar', 'braceright', 'asciitilde', 'exclamdown', 'cent', michael@0: 'sterling', 'fraction', 'yen', 'florin', 'section', 'currency', michael@0: 'quotesingle', 'quotedblleft', 'guillemotleft', 'guilsinglleft', michael@0: 'guilsinglright', 'fi', 'fl', 'endash', 'dagger', 'daggerdbl', michael@0: 'periodcentered', 'paragraph', 'bullet', 'quotesinglbase', 'quotedblbase', michael@0: 'quotedblright', 'guillemotright', 'ellipsis', 'perthousand', 'questiondown', michael@0: 'grave', 'acute', 'circumflex', 'tilde', 'macron', 'breve', 'dotaccent', michael@0: 'dieresis', 'ring', 'cedilla', 'hungarumlaut', 'ogonek', 'caron', 'emdash', michael@0: 'AE', 'ordfeminine', 'Lslash', 'Oslash', 'OE', 'ordmasculine', 'ae', michael@0: 'dotlessi', 'lslash', 'oslash', 'oe', 'germandbls', 'onesuperior', michael@0: 'logicalnot', 'mu', 'trademark', 'Eth', 'onehalf', 'plusminus', 'Thorn', michael@0: 'onequarter', 'divide', 'brokenbar', 'degree', 'thorn', 'threequarters', michael@0: 'twosuperior', 'registered', 'minus', 'eth', 'multiply', 'threesuperior', michael@0: 'copyright', 'Aacute', 'Acircumflex', 'Adieresis', 'Agrave', 'Aring', michael@0: 'Atilde', 'Ccedilla', 'Eacute', 'Ecircumflex', 'Edieresis', 'Egrave', michael@0: 'Iacute', 'Icircumflex', 'Idieresis', 'Igrave', 'Ntilde', 'Oacute', michael@0: 'Ocircumflex', 'Odieresis', 'Ograve', 'Otilde', 'Scaron', 'Uacute', michael@0: 'Ucircumflex', 'Udieresis', 'Ugrave', 'Yacute', 'Ydieresis', 'Zcaron', michael@0: 'aacute', 'acircumflex', 'adieresis', 'agrave', 'aring', 'atilde', michael@0: 'ccedilla', 'eacute', 'ecircumflex', 'edieresis', 'egrave', 'iacute', michael@0: 'icircumflex', 'idieresis', 'igrave', 'ntilde', 'oacute', 'ocircumflex', michael@0: 'odieresis', 'ograve', 'otilde', 'scaron', 'uacute', 'ucircumflex', michael@0: 'udieresis', 'ugrave', 'yacute', 'ydieresis', 'zcaron', 'exclamsmall', michael@0: 'Hungarumlautsmall', 'dollaroldstyle', 'dollarsuperior', 'ampersandsmall', michael@0: 'Acutesmall', 'parenleftsuperior', 'parenrightsuperior', 'twodotenleader', michael@0: 'onedotenleader', 'zerooldstyle', 'oneoldstyle', 'twooldstyle', michael@0: 'threeoldstyle', 'fouroldstyle', 'fiveoldstyle', 'sixoldstyle', michael@0: 'sevenoldstyle', 'eightoldstyle', 'nineoldstyle', 'commasuperior', michael@0: 'threequartersemdash', 'periodsuperior', 'questionsmall', 'asuperior', michael@0: 'bsuperior', 'centsuperior', 'dsuperior', 'esuperior', 'isuperior', michael@0: 'lsuperior', 'msuperior', 'nsuperior', 'osuperior', 'rsuperior', 'ssuperior', michael@0: 'tsuperior', 'ff', 'ffi', 'ffl', 'parenleftinferior', 'parenrightinferior', michael@0: 'Circumflexsmall', 'hyphensuperior', 'Gravesmall', 'Asmall', 'Bsmall', michael@0: 'Csmall', 'Dsmall', 'Esmall', 'Fsmall', 'Gsmall', 'Hsmall', 'Ismall', michael@0: 'Jsmall', 'Ksmall', 'Lsmall', 'Msmall', 'Nsmall', 'Osmall', 'Psmall', michael@0: 'Qsmall', 'Rsmall', 'Ssmall', 'Tsmall', 'Usmall', 'Vsmall', 'Wsmall', michael@0: 'Xsmall', 'Ysmall', 'Zsmall', 'colonmonetary', 'onefitted', 'rupiah', michael@0: 'Tildesmall', 'exclamdownsmall', 'centoldstyle', 'Lslashsmall', michael@0: 'Scaronsmall', 'Zcaronsmall', 'Dieresissmall', 'Brevesmall', 'Caronsmall', michael@0: 'Dotaccentsmall', 'Macronsmall', 'figuredash', 'hypheninferior', michael@0: 'Ogoneksmall', 'Ringsmall', 'Cedillasmall', 'questiondownsmall', 'oneeighth', michael@0: 'threeeighths', 'fiveeighths', 'seveneighths', 'onethird', 'twothirds', michael@0: 'zerosuperior', 'foursuperior', 'fivesuperior', 'sixsuperior', michael@0: 'sevensuperior', 'eightsuperior', 'ninesuperior', 'zeroinferior', michael@0: 'oneinferior', 'twoinferior', 'threeinferior', 'fourinferior', michael@0: 'fiveinferior', 'sixinferior', 'seveninferior', 'eightinferior', michael@0: 'nineinferior', 'centinferior', 'dollarinferior', 'periodinferior', michael@0: 'commainferior', 'Agravesmall', 'Aacutesmall', 'Acircumflexsmall', michael@0: 'Atildesmall', 'Adieresissmall', 'Aringsmall', 'AEsmall', 'Ccedillasmall', michael@0: 'Egravesmall', 'Eacutesmall', 'Ecircumflexsmall', 'Edieresissmall', michael@0: 'Igravesmall', 'Iacutesmall', 'Icircumflexsmall', 'Idieresissmall', michael@0: 'Ethsmall', 'Ntildesmall', 'Ogravesmall', 'Oacutesmall', 'Ocircumflexsmall', michael@0: 'Otildesmall', 'Odieresissmall', 'OEsmall', 'Oslashsmall', 'Ugravesmall', michael@0: 'Uacutesmall', 'Ucircumflexsmall', 'Udieresissmall', 'Yacutesmall', michael@0: 'Thornsmall', 'Ydieresissmall', '001.000', '001.001', '001.002', '001.003', michael@0: 'Black', 'Bold', 'Book', 'Light', 'Medium', 'Regular', 'Roman', 'Semibold' michael@0: ]; michael@0: michael@0: // Type1Font is also a CIDFontType0. michael@0: var Type1Font = function Type1Font(name, file, properties) { michael@0: // Some bad generators embed pfb file as is, we have to strip 6-byte headers. michael@0: // Also, length1 and length2 might be off by 6 bytes as well. michael@0: // http://www.math.ubc.ca/~cass/piscript/type1.pdf michael@0: var PFB_HEADER_SIZE = 6; michael@0: var headerBlockLength = properties.length1; michael@0: var eexecBlockLength = properties.length2; michael@0: var pfbHeader = file.peekBytes(PFB_HEADER_SIZE); michael@0: var pfbHeaderPresent = pfbHeader[0] == 0x80 && pfbHeader[1] == 0x01; michael@0: if (pfbHeaderPresent) { michael@0: file.skip(PFB_HEADER_SIZE); michael@0: headerBlockLength = (pfbHeader[5] << 24) | (pfbHeader[4] << 16) | michael@0: (pfbHeader[3] << 8) | pfbHeader[2]; michael@0: } michael@0: michael@0: // Get the data block containing glyphs and subrs informations michael@0: var headerBlock = new Stream(file.getBytes(headerBlockLength)); michael@0: var headerBlockParser = new Type1Parser(headerBlock); michael@0: headerBlockParser.extractFontHeader(properties); michael@0: michael@0: if (pfbHeaderPresent) { michael@0: pfbHeader = file.getBytes(PFB_HEADER_SIZE); michael@0: eexecBlockLength = (pfbHeader[5] << 24) | (pfbHeader[4] << 16) | michael@0: (pfbHeader[3] << 8) | pfbHeader[2]; michael@0: } michael@0: michael@0: // Decrypt the data blocks and retrieve it's content michael@0: var eexecBlock = new Stream(file.getBytes(eexecBlockLength)); michael@0: var eexecBlockParser = new Type1Parser(eexecBlock, true); michael@0: var data = eexecBlockParser.extractFontProgram(); michael@0: for (var info in data.properties) { michael@0: properties[info] = data.properties[info]; michael@0: } michael@0: michael@0: var charstrings = data.charstrings; michael@0: var type2Charstrings = this.getType2Charstrings(charstrings); michael@0: var subrs = this.getType2Subrs(data.subrs); michael@0: michael@0: this.charstrings = charstrings; michael@0: this.data = this.wrap(name, type2Charstrings, this.charstrings, michael@0: subrs, properties); michael@0: this.seacs = this.getSeacs(data.charstrings); michael@0: }; michael@0: michael@0: Type1Font.prototype = { michael@0: get numGlyphs() { michael@0: return this.charstrings.length + 1; michael@0: }, michael@0: michael@0: getCharset: function Type1Font_getCharset() { michael@0: var charset = ['.notdef']; michael@0: var charstrings = this.charstrings; michael@0: for (var glyphId = 0; glyphId < charstrings.length; glyphId++) { michael@0: charset.push(charstrings[glyphId].glyphName); michael@0: } michael@0: return charset; michael@0: }, michael@0: michael@0: getGlyphMapping: function Type1Font_getGlyphMapping(properties) { michael@0: var charstrings = this.charstrings; michael@0: var glyphNames = ['.notdef'], glyphId; michael@0: for (glyphId = 0; glyphId < charstrings.length; glyphId++) { michael@0: glyphNames.push(charstrings[glyphId].glyphName); michael@0: } michael@0: var encoding = properties.builtInEncoding; michael@0: if (encoding) { michael@0: var builtInEncoding = {}; michael@0: for (var charCode in encoding) { michael@0: glyphId = glyphNames.indexOf(encoding[charCode]); michael@0: if (glyphId >= 0) { michael@0: builtInEncoding[charCode] = glyphId; michael@0: } michael@0: } michael@0: } michael@0: michael@0: return type1FontGlyphMapping(properties, builtInEncoding, glyphNames); michael@0: }, michael@0: michael@0: getSeacs: function Type1Font_getSeacs(charstrings) { michael@0: var i, ii; michael@0: var seacMap = []; michael@0: for (i = 0, ii = charstrings.length; i < ii; i++) { michael@0: var charstring = charstrings[i]; michael@0: if (charstring.seac) { michael@0: // Offset by 1 for .notdef michael@0: seacMap[i + 1] = charstring.seac; michael@0: } michael@0: } michael@0: return seacMap; michael@0: }, michael@0: michael@0: getType2Charstrings: function Type1Font_getType2Charstrings( michael@0: type1Charstrings) { michael@0: var type2Charstrings = []; michael@0: for (var i = 0, ii = type1Charstrings.length; i < ii; i++) { michael@0: type2Charstrings.push(type1Charstrings[i].charstring); michael@0: } michael@0: return type2Charstrings; michael@0: }, michael@0: michael@0: getType2Subrs: function Type1Font_getType2Subrs(type1Subrs) { michael@0: var bias = 0; michael@0: var count = type1Subrs.length; michael@0: if (count < 1133) { michael@0: bias = 107; michael@0: } else if (count < 33769) { michael@0: bias = 1131; michael@0: } else { michael@0: bias = 32768; michael@0: } michael@0: michael@0: // Add a bunch of empty subrs to deal with the Type2 bias michael@0: var type2Subrs = []; michael@0: var i; michael@0: for (i = 0; i < bias; i++) { michael@0: type2Subrs.push([0x0B]); michael@0: } michael@0: michael@0: for (i = 0; i < count; i++) { michael@0: type2Subrs.push(type1Subrs[i]); michael@0: } michael@0: michael@0: return type2Subrs; michael@0: }, michael@0: michael@0: wrap: function Type1Font_wrap(name, glyphs, charstrings, subrs, properties) { michael@0: var cff = new CFF(); michael@0: cff.header = new CFFHeader(1, 0, 4, 4); michael@0: michael@0: cff.names = [name]; michael@0: michael@0: var topDict = new CFFTopDict(); michael@0: // CFF strings IDs 0...390 are predefined names, so refering michael@0: // to entries in our own String INDEX starts at SID 391. michael@0: topDict.setByName('version', 391); michael@0: topDict.setByName('Notice', 392); michael@0: topDict.setByName('FullName', 393); michael@0: topDict.setByName('FamilyName', 394); michael@0: topDict.setByName('Weight', 395); michael@0: topDict.setByName('Encoding', null); // placeholder michael@0: topDict.setByName('FontMatrix', properties.fontMatrix); michael@0: topDict.setByName('FontBBox', properties.bbox); michael@0: topDict.setByName('charset', null); // placeholder michael@0: topDict.setByName('CharStrings', null); // placeholder michael@0: topDict.setByName('Private', null); // placeholder michael@0: cff.topDict = topDict; michael@0: michael@0: var strings = new CFFStrings(); michael@0: strings.add('Version 0.11'); // Version michael@0: strings.add('See original notice'); // Notice michael@0: strings.add(name); // FullName michael@0: strings.add(name); // FamilyName michael@0: strings.add('Medium'); // Weight michael@0: cff.strings = strings; michael@0: michael@0: cff.globalSubrIndex = new CFFIndex(); michael@0: michael@0: var count = glyphs.length; michael@0: var charsetArray = [0]; michael@0: var i, ii; michael@0: for (i = 0; i < count; i++) { michael@0: var index = CFFStandardStrings.indexOf(charstrings[i].glyphName); michael@0: // TODO: Insert the string and correctly map it. Previously it was michael@0: // thought mapping names that aren't in the standard strings to .notdef michael@0: // was fine, however in issue818 when mapping them all to .notdef the michael@0: // adieresis glyph no longer worked. michael@0: if (index == -1) { michael@0: index = 0; michael@0: } michael@0: charsetArray.push((index >> 8) & 0xff, index & 0xff); michael@0: } michael@0: cff.charset = new CFFCharset(false, 0, [], charsetArray); michael@0: michael@0: var charStringsIndex = new CFFIndex(); michael@0: charStringsIndex.add([0x8B, 0x0E]); // .notdef michael@0: for (i = 0; i < count; i++) { michael@0: charStringsIndex.add(glyphs[i]); michael@0: } michael@0: cff.charStrings = charStringsIndex; michael@0: michael@0: var privateDict = new CFFPrivateDict(); michael@0: privateDict.setByName('Subrs', null); // placeholder michael@0: var fields = [ michael@0: 'BlueValues', michael@0: 'OtherBlues', michael@0: 'FamilyBlues', michael@0: 'FamilyOtherBlues', michael@0: 'StemSnapH', michael@0: 'StemSnapV', michael@0: 'BlueShift', michael@0: 'BlueFuzz', michael@0: 'BlueScale', michael@0: 'LanguageGroup', michael@0: 'ExpansionFactor', michael@0: 'ForceBold', michael@0: 'StdHW', michael@0: 'StdVW' michael@0: ]; michael@0: for (i = 0, ii = fields.length; i < ii; i++) { michael@0: var field = fields[i]; michael@0: if (!properties.privateData.hasOwnProperty(field)) { michael@0: continue; michael@0: } michael@0: var value = properties.privateData[field]; michael@0: if (isArray(value)) { michael@0: // All of the private dictionary array data in CFF must be stored as michael@0: // "delta-encoded" numbers. michael@0: for (var j = value.length - 1; j > 0; j--) { michael@0: value[j] -= value[j - 1]; // ... difference from previous value michael@0: } michael@0: } michael@0: privateDict.setByName(field, value); michael@0: } michael@0: cff.topDict.privateDict = privateDict; michael@0: michael@0: var subrIndex = new CFFIndex(); michael@0: for (i = 0, ii = subrs.length; i < ii; i++) { michael@0: subrIndex.add(subrs[i]); michael@0: } michael@0: privateDict.subrsIndex = subrIndex; michael@0: michael@0: var compiler = new CFFCompiler(cff); michael@0: return compiler.compile(); michael@0: } michael@0: }; michael@0: michael@0: var CFFFont = (function CFFFontClosure() { michael@0: function CFFFont(file, properties) { michael@0: this.properties = properties; michael@0: michael@0: var parser = new CFFParser(file, properties); michael@0: this.cff = parser.parse(); michael@0: var compiler = new CFFCompiler(this.cff); michael@0: this.seacs = this.cff.seacs; michael@0: try { michael@0: this.data = compiler.compile(); michael@0: } catch (e) { michael@0: warn('Failed to compile font ' + properties.loadedName); michael@0: // There may have just been an issue with the compiler, set the data michael@0: // anyway and hope the font loaded. michael@0: this.data = file; michael@0: } michael@0: } michael@0: michael@0: CFFFont.prototype = { michael@0: get numGlyphs() { michael@0: return this.cff.charStrings.count; michael@0: }, michael@0: getCharset: function CFFFont_getCharset() { michael@0: return this.cff.charset.charset; michael@0: }, michael@0: getGlyphMapping: function CFFFont_getGlyphMapping() { michael@0: var cff = this.cff; michael@0: var properties = this.properties; michael@0: var charsets = cff.charset.charset; michael@0: var charCodeToGlyphId; michael@0: var glyphId; michael@0: michael@0: if (properties.composite) { michael@0: charCodeToGlyphId = Object.create(null); michael@0: if (cff.isCIDFont) { michael@0: // If the font is actually a CID font then we should use the charset michael@0: // to map CIDs to GIDs. michael@0: for (glyphId = 0; glyphId < charsets.length; glyphId++) { michael@0: var cidString = String.fromCharCode(charsets[glyphId]); michael@0: var charCode = properties.cMap.map.indexOf(cidString); michael@0: charCodeToGlyphId[charCode] = glyphId; michael@0: } michael@0: } else { michael@0: // If it is NOT actually a CID font then CIDs should be mapped michael@0: // directly to GIDs. michael@0: for (glyphId = 0; glyphId < cff.charStrings.count; glyphId++) { michael@0: charCodeToGlyphId[glyphId] = glyphId; michael@0: } michael@0: } michael@0: return charCodeToGlyphId; michael@0: } michael@0: michael@0: var encoding = cff.encoding ? cff.encoding.encoding : null; michael@0: charCodeToGlyphId = type1FontGlyphMapping(properties, encoding, charsets); michael@0: return charCodeToGlyphId; michael@0: } michael@0: }; michael@0: michael@0: return CFFFont; michael@0: })(); michael@0: michael@0: var CFFParser = (function CFFParserClosure() { michael@0: var CharstringValidationData = [ michael@0: null, michael@0: { id: 'hstem', min: 2, resetStack: true, stem: true }, michael@0: null, michael@0: { id: 'vstem', min: 2, resetStack: true, stem: true }, michael@0: { id: 'vmoveto', min: 1, resetStack: true }, michael@0: { id: 'rlineto', min: 2, resetStack: true }, michael@0: { id: 'hlineto', min: 1, resetStack: true }, michael@0: { id: 'vlineto', min: 1, resetStack: true }, michael@0: { id: 'rrcurveto', min: 6, resetStack: true }, michael@0: null, michael@0: { id: 'callsubr', min: 1, undefStack: true }, michael@0: { id: 'return', min: 0, undefStack: true }, michael@0: null, // 12 michael@0: null, michael@0: null, // endchar michael@0: null, michael@0: null, michael@0: null, michael@0: { id: 'hstemhm', min: 2, resetStack: true, stem: true }, michael@0: null, // hintmask michael@0: null, // cntrmask michael@0: { id: 'rmoveto', min: 2, resetStack: true }, michael@0: { id: 'hmoveto', min: 1, resetStack: true }, michael@0: { id: 'vstemhm', min: 2, resetStack: true, stem: true }, michael@0: { id: 'rcurveline', min: 8, resetStack: true }, michael@0: { id: 'rlinecurve', min: 8, resetStack: true }, michael@0: { id: 'vvcurveto', min: 4, resetStack: true }, michael@0: { id: 'hhcurveto', min: 4, resetStack: true }, michael@0: null, // shortint michael@0: { id: 'callgsubr', min: 1, undefStack: true }, michael@0: { id: 'vhcurveto', min: 4, resetStack: true }, michael@0: { id: 'hvcurveto', min: 4, resetStack: true } michael@0: ]; michael@0: var CharstringValidationData12 = [ michael@0: null, michael@0: null, michael@0: null, michael@0: { id: 'and', min: 2, stackDelta: -1 }, michael@0: { id: 'or', min: 2, stackDelta: -1 }, michael@0: { id: 'not', min: 1, stackDelta: 0 }, michael@0: null, michael@0: null, michael@0: null, michael@0: { id: 'abs', min: 1, stackDelta: 0 }, michael@0: { id: 'add', min: 2, stackDelta: -1, michael@0: stackFn: function stack_div(stack, index) { michael@0: stack[index - 2] = stack[index - 2] + stack[index - 1]; michael@0: } michael@0: }, michael@0: { id: 'sub', min: 2, stackDelta: -1, michael@0: stackFn: function stack_div(stack, index) { michael@0: stack[index - 2] = stack[index - 2] - stack[index - 1]; michael@0: } michael@0: }, michael@0: { id: 'div', min: 2, stackDelta: -1, michael@0: stackFn: function stack_div(stack, index) { michael@0: stack[index - 2] = stack[index - 2] / stack[index - 1]; michael@0: } michael@0: }, michael@0: null, michael@0: { id: 'neg', min: 1, stackDelta: 0, michael@0: stackFn: function stack_div(stack, index) { michael@0: stack[index - 1] = -stack[index - 1]; michael@0: } michael@0: }, michael@0: { id: 'eq', min: 2, stackDelta: -1 }, michael@0: null, michael@0: null, michael@0: { id: 'drop', min: 1, stackDelta: -1 }, michael@0: null, michael@0: { id: 'put', min: 2, stackDelta: -2 }, michael@0: { id: 'get', min: 1, stackDelta: 0 }, michael@0: { id: 'ifelse', min: 4, stackDelta: -3 }, michael@0: { id: 'random', min: 0, stackDelta: 1 }, michael@0: { id: 'mul', min: 2, stackDelta: -1, michael@0: stackFn: function stack_div(stack, index) { michael@0: stack[index - 2] = stack[index - 2] * stack[index - 1]; michael@0: } michael@0: }, michael@0: null, michael@0: { id: 'sqrt', min: 1, stackDelta: 0 }, michael@0: { id: 'dup', min: 1, stackDelta: 1 }, michael@0: { id: 'exch', min: 2, stackDelta: 0 }, michael@0: { id: 'index', min: 2, stackDelta: 0 }, michael@0: { id: 'roll', min: 3, stackDelta: -2 }, michael@0: null, michael@0: null, michael@0: null, michael@0: { id: 'hflex', min: 7, resetStack: true }, michael@0: { id: 'flex', min: 13, resetStack: true }, michael@0: { id: 'hflex1', min: 9, resetStack: true }, michael@0: { id: 'flex1', min: 11, resetStack: true } michael@0: ]; michael@0: michael@0: function CFFParser(file, properties) { michael@0: this.bytes = file.getBytes(); michael@0: this.properties = properties; michael@0: } michael@0: CFFParser.prototype = { michael@0: parse: function CFFParser_parse() { michael@0: var properties = this.properties; michael@0: var cff = new CFF(); michael@0: this.cff = cff; michael@0: michael@0: // The first five sections must be in order, all the others are reached michael@0: // via offsets contained in one of the below. michael@0: var header = this.parseHeader(); michael@0: var nameIndex = this.parseIndex(header.endPos); michael@0: var topDictIndex = this.parseIndex(nameIndex.endPos); michael@0: var stringIndex = this.parseIndex(topDictIndex.endPos); michael@0: var globalSubrIndex = this.parseIndex(stringIndex.endPos); michael@0: michael@0: var topDictParsed = this.parseDict(topDictIndex.obj.get(0)); michael@0: var topDict = this.createDict(CFFTopDict, topDictParsed, cff.strings); michael@0: michael@0: cff.header = header.obj; michael@0: cff.names = this.parseNameIndex(nameIndex.obj); michael@0: cff.strings = this.parseStringIndex(stringIndex.obj); michael@0: cff.topDict = topDict; michael@0: cff.globalSubrIndex = globalSubrIndex.obj; michael@0: michael@0: this.parsePrivateDict(cff.topDict); michael@0: michael@0: cff.isCIDFont = topDict.hasName('ROS'); michael@0: michael@0: var charStringOffset = topDict.getByName('CharStrings'); michael@0: var charStringsAndSeacs = this.parseCharStrings(charStringOffset); michael@0: cff.charStrings = charStringsAndSeacs.charStrings; michael@0: cff.seacs = charStringsAndSeacs.seacs; michael@0: michael@0: var fontMatrix = topDict.getByName('FontMatrix'); michael@0: if (fontMatrix) { michael@0: properties.fontMatrix = fontMatrix; michael@0: } michael@0: michael@0: var fontBBox = topDict.getByName('FontBBox'); michael@0: if (fontBBox) { michael@0: // adjusting ascent/descent michael@0: properties.ascent = fontBBox[3]; michael@0: properties.descent = fontBBox[1]; michael@0: properties.ascentScaled = true; michael@0: } michael@0: michael@0: var charset, encoding; michael@0: if (cff.isCIDFont) { michael@0: var fdArrayIndex = this.parseIndex(topDict.getByName('FDArray')).obj; michael@0: for (var i = 0, ii = fdArrayIndex.count; i < ii; ++i) { michael@0: var dictRaw = fdArrayIndex.get(i); michael@0: var fontDict = this.createDict(CFFTopDict, this.parseDict(dictRaw), michael@0: cff.strings); michael@0: this.parsePrivateDict(fontDict); michael@0: cff.fdArray.push(fontDict); michael@0: } michael@0: // cid fonts don't have an encoding michael@0: encoding = null; michael@0: charset = this.parseCharsets(topDict.getByName('charset'), michael@0: cff.charStrings.count, cff.strings, true); michael@0: cff.fdSelect = this.parseFDSelect(topDict.getByName('FDSelect'), michael@0: cff.charStrings.count); michael@0: } else { michael@0: charset = this.parseCharsets(topDict.getByName('charset'), michael@0: cff.charStrings.count, cff.strings, false); michael@0: encoding = this.parseEncoding(topDict.getByName('Encoding'), michael@0: properties, michael@0: cff.strings, charset.charset); michael@0: } michael@0: cff.charset = charset; michael@0: cff.encoding = encoding; michael@0: michael@0: return cff; michael@0: }, michael@0: parseHeader: function CFFParser_parseHeader() { michael@0: var bytes = this.bytes; michael@0: var bytesLength = bytes.length; michael@0: var offset = 0; michael@0: michael@0: // Prevent an infinite loop, by checking that the offset is within the michael@0: // bounds of the bytes array. Necessary in empty, or invalid, font files. michael@0: while (offset < bytesLength && bytes[offset] !== 1) { michael@0: ++offset; michael@0: } michael@0: if (offset >= bytesLength) { michael@0: error('Invalid CFF header'); michael@0: } else if (offset !== 0) { michael@0: info('cff data is shifted'); michael@0: bytes = bytes.subarray(offset); michael@0: this.bytes = bytes; michael@0: } michael@0: var major = bytes[0]; michael@0: var minor = bytes[1]; michael@0: var hdrSize = bytes[2]; michael@0: var offSize = bytes[3]; michael@0: var header = new CFFHeader(major, minor, hdrSize, offSize); michael@0: return { obj: header, endPos: hdrSize }; michael@0: }, michael@0: parseDict: function CFFParser_parseDict(dict) { michael@0: var pos = 0; michael@0: michael@0: function parseOperand() { michael@0: var value = dict[pos++]; michael@0: if (value === 30) { michael@0: return parseFloatOperand(pos); michael@0: } else if (value === 28) { michael@0: value = dict[pos++]; michael@0: value = ((value << 24) | (dict[pos++] << 16)) >> 16; michael@0: return value; michael@0: } else if (value === 29) { michael@0: value = dict[pos++]; michael@0: value = (value << 8) | dict[pos++]; michael@0: value = (value << 8) | dict[pos++]; michael@0: value = (value << 8) | dict[pos++]; michael@0: return value; michael@0: } else if (value >= 32 && value <= 246) { michael@0: return value - 139; michael@0: } else if (value >= 247 && value <= 250) { michael@0: return ((value - 247) * 256) + dict[pos++] + 108; michael@0: } else if (value >= 251 && value <= 254) { michael@0: return -((value - 251) * 256) - dict[pos++] - 108; michael@0: } else { michael@0: error('255 is not a valid DICT command'); michael@0: } michael@0: return -1; michael@0: } michael@0: michael@0: function parseFloatOperand() { michael@0: var str = ''; michael@0: var eof = 15; michael@0: var lookup = ['0', '1', '2', '3', '4', '5', '6', '7', '8', michael@0: '9', '.', 'E', 'E-', null, '-']; michael@0: var length = dict.length; michael@0: while (pos < length) { michael@0: var b = dict[pos++]; michael@0: var b1 = b >> 4; michael@0: var b2 = b & 15; michael@0: michael@0: if (b1 == eof) { michael@0: break; michael@0: } michael@0: str += lookup[b1]; michael@0: michael@0: if (b2 == eof) { michael@0: break; michael@0: } michael@0: str += lookup[b2]; michael@0: } michael@0: return parseFloat(str); michael@0: } michael@0: michael@0: var operands = []; michael@0: var entries = []; michael@0: michael@0: pos = 0; michael@0: var end = dict.length; michael@0: while (pos < end) { michael@0: var b = dict[pos]; michael@0: if (b <= 21) { michael@0: if (b === 12) { michael@0: b = (b << 8) | dict[++pos]; michael@0: } michael@0: entries.push([b, operands]); michael@0: operands = []; michael@0: ++pos; michael@0: } else { michael@0: operands.push(parseOperand()); michael@0: } michael@0: } michael@0: return entries; michael@0: }, michael@0: parseIndex: function CFFParser_parseIndex(pos) { michael@0: var cffIndex = new CFFIndex(); michael@0: var bytes = this.bytes; michael@0: var count = (bytes[pos++] << 8) | bytes[pos++]; michael@0: var offsets = []; michael@0: var end = pos; michael@0: var i, ii; michael@0: michael@0: if (count !== 0) { michael@0: var offsetSize = bytes[pos++]; michael@0: // add 1 for offset to determine size of last object michael@0: var startPos = pos + ((count + 1) * offsetSize) - 1; michael@0: michael@0: for (i = 0, ii = count + 1; i < ii; ++i) { michael@0: var offset = 0; michael@0: for (var j = 0; j < offsetSize; ++j) { michael@0: offset <<= 8; michael@0: offset += bytes[pos++]; michael@0: } michael@0: offsets.push(startPos + offset); michael@0: } michael@0: end = offsets[count]; michael@0: } michael@0: for (i = 0, ii = offsets.length - 1; i < ii; ++i) { michael@0: var offsetStart = offsets[i]; michael@0: var offsetEnd = offsets[i + 1]; michael@0: cffIndex.add(bytes.subarray(offsetStart, offsetEnd)); michael@0: } michael@0: return {obj: cffIndex, endPos: end}; michael@0: }, michael@0: parseNameIndex: function CFFParser_parseNameIndex(index) { michael@0: var names = []; michael@0: for (var i = 0, ii = index.count; i < ii; ++i) { michael@0: var name = index.get(i); michael@0: // OTS doesn't allow names to be over 127 characters. michael@0: var length = Math.min(name.length, 127); michael@0: var data = []; michael@0: // OTS also only permits certain characters in the name. michael@0: for (var j = 0; j < length; ++j) { michael@0: var c = name[j]; michael@0: if (j === 0 && c === 0) { michael@0: data[j] = c; michael@0: continue; michael@0: } michael@0: if ((c < 33 || c > 126) || c === 91 /* [ */ || c === 93 /* ] */ || michael@0: c === 40 /* ( */ || c === 41 /* ) */ || c === 123 /* { */ || michael@0: c === 125 /* } */ || c === 60 /* < */ || c === 62 /* > */ || michael@0: c === 47 /* / */ || c === 37 /* % */ || c === 35 /* # */) { michael@0: data[j] = 95; michael@0: continue; michael@0: } michael@0: data[j] = c; michael@0: } michael@0: names.push(bytesToString(data)); michael@0: } michael@0: return names; michael@0: }, michael@0: parseStringIndex: function CFFParser_parseStringIndex(index) { michael@0: var strings = new CFFStrings(); michael@0: for (var i = 0, ii = index.count; i < ii; ++i) { michael@0: var data = index.get(i); michael@0: strings.add(bytesToString(data)); michael@0: } michael@0: return strings; michael@0: }, michael@0: createDict: function CFFParser_createDict(Type, dict, strings) { michael@0: var cffDict = new Type(strings); michael@0: for (var i = 0, ii = dict.length; i < ii; ++i) { michael@0: var pair = dict[i]; michael@0: var key = pair[0]; michael@0: var value = pair[1]; michael@0: cffDict.setByKey(key, value); michael@0: } michael@0: return cffDict; michael@0: }, michael@0: parseCharStrings: function CFFParser_parseCharStrings(charStringOffset) { michael@0: var charStrings = this.parseIndex(charStringOffset).obj; michael@0: var seacs = []; michael@0: var count = charStrings.count; michael@0: for (var i = 0; i < count; i++) { michael@0: var charstring = charStrings.get(i); michael@0: michael@0: var stackSize = 0; michael@0: var stack = []; michael@0: var undefStack = true; michael@0: var hints = 0; michael@0: var valid = true; michael@0: var data = charstring; michael@0: var length = data.length; michael@0: for (var j = 0; j < length;) { michael@0: var value = data[j++]; michael@0: var validationCommand = null; michael@0: if (value == 12) { michael@0: var q = data[j++]; michael@0: if (q === 0) { michael@0: // The CFF specification state that the 'dotsection' command michael@0: // (12, 0) is deprecated and treated as a no-op, but all Type2 michael@0: // charstrings processors should support them. Unfortunately michael@0: // the font sanitizer don't. As a workaround the sequence (12, 0) michael@0: // is replaced by a useless (0, hmoveto). michael@0: data[j - 2] = 139; michael@0: data[j - 1] = 22; michael@0: stackSize = 0; michael@0: } else { michael@0: validationCommand = CharstringValidationData12[q]; michael@0: } michael@0: } else if (value === 28) { // number (16 bit) michael@0: stack[stackSize] = ((data[j] << 24) | (data[j + 1] << 16)) >> 16; michael@0: j += 2; michael@0: stackSize++; michael@0: } else if (value == 14) { michael@0: if (stackSize >= 4) { michael@0: stackSize -= 4; michael@0: if (SEAC_ANALYSIS_ENABLED) { michael@0: seacs[i] = stack.slice(stackSize, stackSize + 4); michael@0: valid = false; michael@0: } michael@0: } michael@0: } else if (value >= 32 && value <= 246) { // number michael@0: stack[stackSize] = value - 139; michael@0: stackSize++; michael@0: } else if (value >= 247 && value <= 254) { // number (+1 bytes) michael@0: stack[stackSize] = (value < 251 ? michael@0: ((value - 247) << 8) + data[j] + 108 : michael@0: -((value - 251) << 8) - data[j] - 108); michael@0: j++; michael@0: stackSize++; michael@0: } else if (value == 255) { // number (32 bit) michael@0: stack[stackSize] = ((data[j] << 24) | (data[j + 1] << 16) | michael@0: (data[j + 2] << 8) | data[j + 3]) / 65536; michael@0: j += 4; michael@0: stackSize++; michael@0: } else if (value == 19 || value == 20) { michael@0: hints += stackSize >> 1; michael@0: j += (hints + 7) >> 3; // skipping right amount of hints flag data michael@0: stackSize = 0; michael@0: } else { michael@0: validationCommand = CharstringValidationData[value]; michael@0: } michael@0: if (validationCommand) { michael@0: if (validationCommand.stem) { michael@0: hints += stackSize >> 1; michael@0: } michael@0: if ('min' in validationCommand) { michael@0: if (!undefStack && stackSize < validationCommand.min) { michael@0: warn('Not enough parameters for ' + validationCommand.id + michael@0: '; actual: ' + stackSize + michael@0: ', expected: ' + validationCommand.min); michael@0: valid = false; michael@0: break; michael@0: } michael@0: } michael@0: if ('stackDelta' in validationCommand) { michael@0: if ('stackFn' in validationCommand) { michael@0: validationCommand.stackFn(stack, stackSize); michael@0: } michael@0: stackSize += validationCommand.stackDelta; michael@0: } else if (validationCommand.resetStack) { michael@0: stackSize = 0; michael@0: undefStack = false; michael@0: } else if (validationCommand.undefStack) { michael@0: stackSize = 0; michael@0: undefStack = true; michael@0: } michael@0: } michael@0: } michael@0: if (!valid) { michael@0: // resetting invalid charstring to single 'endchar' michael@0: charStrings.set(i, new Uint8Array([14])); michael@0: } michael@0: } michael@0: return { charStrings: charStrings, seacs: seacs }; michael@0: }, michael@0: emptyPrivateDictionary: michael@0: function CFFParser_emptyPrivateDictionary(parentDict) { michael@0: var privateDict = this.createDict(CFFPrivateDict, [], michael@0: parentDict.strings); michael@0: parentDict.setByKey(18, [0, 0]); michael@0: parentDict.privateDict = privateDict; michael@0: }, michael@0: parsePrivateDict: function CFFParser_parsePrivateDict(parentDict) { michael@0: // no private dict, do nothing michael@0: if (!parentDict.hasName('Private')) { michael@0: this.emptyPrivateDictionary(parentDict); michael@0: return; michael@0: } michael@0: var privateOffset = parentDict.getByName('Private'); michael@0: // make sure the params are formatted correctly michael@0: if (!isArray(privateOffset) || privateOffset.length !== 2) { michael@0: parentDict.removeByName('Private'); michael@0: return; michael@0: } michael@0: var size = privateOffset[0]; michael@0: var offset = privateOffset[1]; michael@0: // remove empty dicts or ones that refer to invalid location michael@0: if (size === 0 || offset >= this.bytes.length) { michael@0: this.emptyPrivateDictionary(parentDict); michael@0: return; michael@0: } michael@0: michael@0: var privateDictEnd = offset + size; michael@0: var dictData = this.bytes.subarray(offset, privateDictEnd); michael@0: var dict = this.parseDict(dictData); michael@0: var privateDict = this.createDict(CFFPrivateDict, dict, michael@0: parentDict.strings); michael@0: parentDict.privateDict = privateDict; michael@0: michael@0: // Parse the Subrs index also since it's relative to the private dict. michael@0: if (!privateDict.getByName('Subrs')) { michael@0: return; michael@0: } michael@0: var subrsOffset = privateDict.getByName('Subrs'); michael@0: var relativeOffset = offset + subrsOffset; michael@0: // Validate the offset. michael@0: if (subrsOffset === 0 || relativeOffset >= this.bytes.length) { michael@0: this.emptyPrivateDictionary(parentDict); michael@0: return; michael@0: } michael@0: var subrsIndex = this.parseIndex(relativeOffset); michael@0: privateDict.subrsIndex = subrsIndex.obj; michael@0: }, michael@0: parseCharsets: function CFFParser_parseCharsets(pos, length, strings, cid) { michael@0: if (pos === 0) { michael@0: return new CFFCharset(true, CFFCharsetPredefinedTypes.ISO_ADOBE, michael@0: ISOAdobeCharset); michael@0: } else if (pos == 1) { michael@0: return new CFFCharset(true, CFFCharsetPredefinedTypes.EXPERT, michael@0: ExpertCharset); michael@0: } else if (pos == 2) { michael@0: return new CFFCharset(true, CFFCharsetPredefinedTypes.EXPERT_SUBSET, michael@0: ExpertSubsetCharset); michael@0: } michael@0: michael@0: var bytes = this.bytes; michael@0: var start = pos; michael@0: var format = bytes[pos++]; michael@0: var charset = ['.notdef']; michael@0: var id, count, i; michael@0: michael@0: // subtract 1 for the .notdef glyph michael@0: length -= 1; michael@0: michael@0: switch (format) { michael@0: case 0: michael@0: for (i = 0; i < length; i++) { michael@0: id = (bytes[pos++] << 8) | bytes[pos++]; michael@0: charset.push(cid ? id : strings.get(id)); michael@0: } michael@0: break; michael@0: case 1: michael@0: while (charset.length <= length) { michael@0: id = (bytes[pos++] << 8) | bytes[pos++]; michael@0: count = bytes[pos++]; michael@0: for (i = 0; i <= count; i++) { michael@0: charset.push(cid ? id++ : strings.get(id++)); michael@0: } michael@0: } michael@0: break; michael@0: case 2: michael@0: while (charset.length <= length) { michael@0: id = (bytes[pos++] << 8) | bytes[pos++]; michael@0: count = (bytes[pos++] << 8) | bytes[pos++]; michael@0: for (i = 0; i <= count; i++) { michael@0: charset.push(cid ? id++ : strings.get(id++)); michael@0: } michael@0: } michael@0: break; michael@0: default: michael@0: error('Unknown charset format'); michael@0: } michael@0: // Raw won't be needed if we actually compile the charset. michael@0: var end = pos; michael@0: var raw = bytes.subarray(start, end); michael@0: michael@0: return new CFFCharset(false, format, charset, raw); michael@0: }, michael@0: parseEncoding: function CFFParser_parseEncoding(pos, michael@0: properties, michael@0: strings, michael@0: charset) { michael@0: var encoding = {}; michael@0: var bytes = this.bytes; michael@0: var predefined = false; michael@0: var hasSupplement = false; michael@0: var format, i, ii; michael@0: var raw = null; michael@0: michael@0: function readSupplement() { michael@0: var supplementsCount = bytes[pos++]; michael@0: for (i = 0; i < supplementsCount; i++) { michael@0: var code = bytes[pos++]; michael@0: var sid = (bytes[pos++] << 8) + (bytes[pos++] & 0xff); michael@0: encoding[code] = charset.indexOf(strings.get(sid)); michael@0: } michael@0: } michael@0: michael@0: if (pos === 0 || pos == 1) { michael@0: predefined = true; michael@0: format = pos; michael@0: var baseEncoding = pos ? Encodings.ExpertEncoding : michael@0: Encodings.StandardEncoding; michael@0: for (i = 0, ii = charset.length; i < ii; i++) { michael@0: var index = baseEncoding.indexOf(charset[i]); michael@0: if (index != -1) { michael@0: encoding[index] = i; michael@0: } michael@0: } michael@0: } else { michael@0: var dataStart = pos; michael@0: format = bytes[pos++]; michael@0: switch (format & 0x7f) { michael@0: case 0: michael@0: var glyphsCount = bytes[pos++]; michael@0: for (i = 1; i <= glyphsCount; i++) { michael@0: encoding[bytes[pos++]] = i; michael@0: } michael@0: break; michael@0: michael@0: case 1: michael@0: var rangesCount = bytes[pos++]; michael@0: var gid = 1; michael@0: for (i = 0; i < rangesCount; i++) { michael@0: var start = bytes[pos++]; michael@0: var left = bytes[pos++]; michael@0: for (var j = start; j <= start + left; j++) { michael@0: encoding[j] = gid++; michael@0: } michael@0: } michael@0: break; michael@0: michael@0: default: michael@0: error('Unknow encoding format: ' + format + ' in CFF'); michael@0: break; michael@0: } michael@0: var dataEnd = pos; michael@0: if (format & 0x80) { michael@0: // The font sanitizer does not support CFF encoding with a michael@0: // supplement, since the encoding is not really used to map michael@0: // between gid to glyph, let's overwrite what is declared in michael@0: // the top dictionary to let the sanitizer think the font use michael@0: // StandardEncoding, that's a lie but that's ok. michael@0: bytes[dataStart] &= 0x7f; michael@0: readSupplement(); michael@0: hasSupplement = true; michael@0: } michael@0: raw = bytes.subarray(dataStart, dataEnd); michael@0: } michael@0: format = format & 0x7f; michael@0: return new CFFEncoding(predefined, format, encoding, raw); michael@0: }, michael@0: parseFDSelect: function CFFParser_parseFDSelect(pos, length) { michael@0: var start = pos; michael@0: var bytes = this.bytes; michael@0: var format = bytes[pos++]; michael@0: var fdSelect = []; michael@0: var i; michael@0: michael@0: switch (format) { michael@0: case 0: michael@0: for (i = 0; i < length; ++i) { michael@0: var id = bytes[pos++]; michael@0: fdSelect.push(id); michael@0: } michael@0: break; michael@0: case 3: michael@0: var rangesCount = (bytes[pos++] << 8) | bytes[pos++]; michael@0: for (i = 0; i < rangesCount; ++i) { michael@0: var first = (bytes[pos++] << 8) | bytes[pos++]; michael@0: var fdIndex = bytes[pos++]; michael@0: var next = (bytes[pos] << 8) | bytes[pos + 1]; michael@0: for (var j = first; j < next; ++j) { michael@0: fdSelect.push(fdIndex); michael@0: } michael@0: } michael@0: // Advance past the sentinel(next). michael@0: pos += 2; michael@0: break; michael@0: default: michael@0: error('Unknown fdselect format ' + format); michael@0: break; michael@0: } michael@0: var end = pos; michael@0: return new CFFFDSelect(fdSelect, bytes.subarray(start, end)); michael@0: } michael@0: }; michael@0: return CFFParser; michael@0: })(); michael@0: michael@0: // Compact Font Format michael@0: var CFF = (function CFFClosure() { michael@0: function CFF() { michael@0: this.header = null; michael@0: this.names = []; michael@0: this.topDict = null; michael@0: this.strings = new CFFStrings(); michael@0: this.globalSubrIndex = null; michael@0: michael@0: // The following could really be per font, but since we only have one font michael@0: // store them here. michael@0: this.encoding = null; michael@0: this.charset = null; michael@0: this.charStrings = null; michael@0: this.fdArray = []; michael@0: this.fdSelect = null; michael@0: michael@0: this.isCIDFont = false; michael@0: } michael@0: return CFF; michael@0: })(); michael@0: michael@0: var CFFHeader = (function CFFHeaderClosure() { michael@0: function CFFHeader(major, minor, hdrSize, offSize) { michael@0: this.major = major; michael@0: this.minor = minor; michael@0: this.hdrSize = hdrSize; michael@0: this.offSize = offSize; michael@0: } michael@0: return CFFHeader; michael@0: })(); michael@0: michael@0: var CFFStrings = (function CFFStringsClosure() { michael@0: function CFFStrings() { michael@0: this.strings = []; michael@0: } michael@0: CFFStrings.prototype = { michael@0: get: function CFFStrings_get(index) { michael@0: if (index >= 0 && index <= 390) { michael@0: return CFFStandardStrings[index]; michael@0: } michael@0: if (index - 391 <= this.strings.length) { michael@0: return this.strings[index - 391]; michael@0: } michael@0: return CFFStandardStrings[0]; michael@0: }, michael@0: add: function CFFStrings_add(value) { michael@0: this.strings.push(value); michael@0: }, michael@0: get count() { michael@0: return this.strings.length; michael@0: } michael@0: }; michael@0: return CFFStrings; michael@0: })(); michael@0: michael@0: var CFFIndex = (function CFFIndexClosure() { michael@0: function CFFIndex() { michael@0: this.objects = []; michael@0: this.length = 0; michael@0: } michael@0: CFFIndex.prototype = { michael@0: add: function CFFIndex_add(data) { michael@0: this.length += data.length; michael@0: this.objects.push(data); michael@0: }, michael@0: set: function CFFIndex_set(index, data) { michael@0: this.length += data.length - this.objects[index].length; michael@0: this.objects[index] = data; michael@0: }, michael@0: get: function CFFIndex_get(index) { michael@0: return this.objects[index]; michael@0: }, michael@0: get count() { michael@0: return this.objects.length; michael@0: } michael@0: }; michael@0: return CFFIndex; michael@0: })(); michael@0: michael@0: var CFFDict = (function CFFDictClosure() { michael@0: function CFFDict(tables, strings) { michael@0: this.keyToNameMap = tables.keyToNameMap; michael@0: this.nameToKeyMap = tables.nameToKeyMap; michael@0: this.defaults = tables.defaults; michael@0: this.types = tables.types; michael@0: this.opcodes = tables.opcodes; michael@0: this.order = tables.order; michael@0: this.strings = strings; michael@0: this.values = {}; michael@0: } michael@0: CFFDict.prototype = { michael@0: // value should always be an array michael@0: setByKey: function CFFDict_setByKey(key, value) { michael@0: if (!(key in this.keyToNameMap)) { michael@0: return false; michael@0: } michael@0: // ignore empty values michael@0: if (value.length === 0) { michael@0: return true; michael@0: } michael@0: var type = this.types[key]; michael@0: // remove the array wrapping these types of values michael@0: if (type === 'num' || type === 'sid' || type === 'offset') { michael@0: value = value[0]; michael@0: } michael@0: this.values[key] = value; michael@0: return true; michael@0: }, michael@0: setByName: function CFFDict_setByName(name, value) { michael@0: if (!(name in this.nameToKeyMap)) { michael@0: error('Invalid dictionary name "' + name + '"'); michael@0: } michael@0: this.values[this.nameToKeyMap[name]] = value; michael@0: }, michael@0: hasName: function CFFDict_hasName(name) { michael@0: return this.nameToKeyMap[name] in this.values; michael@0: }, michael@0: getByName: function CFFDict_getByName(name) { michael@0: if (!(name in this.nameToKeyMap)) { michael@0: error('Invalid dictionary name "' + name + '"'); michael@0: } michael@0: var key = this.nameToKeyMap[name]; michael@0: if (!(key in this.values)) { michael@0: return this.defaults[key]; michael@0: } michael@0: return this.values[key]; michael@0: }, michael@0: removeByName: function CFFDict_removeByName(name) { michael@0: delete this.values[this.nameToKeyMap[name]]; michael@0: } michael@0: }; michael@0: CFFDict.createTables = function CFFDict_createTables(layout) { michael@0: var tables = { michael@0: keyToNameMap: {}, michael@0: nameToKeyMap: {}, michael@0: defaults: {}, michael@0: types: {}, michael@0: opcodes: {}, michael@0: order: [] michael@0: }; michael@0: for (var i = 0, ii = layout.length; i < ii; ++i) { michael@0: var entry = layout[i]; michael@0: var key = isArray(entry[0]) ? (entry[0][0] << 8) + entry[0][1] : entry[0]; michael@0: tables.keyToNameMap[key] = entry[1]; michael@0: tables.nameToKeyMap[entry[1]] = key; michael@0: tables.types[key] = entry[2]; michael@0: tables.defaults[key] = entry[3]; michael@0: tables.opcodes[key] = isArray(entry[0]) ? entry[0] : [entry[0]]; michael@0: tables.order.push(key); michael@0: } michael@0: return tables; michael@0: }; michael@0: return CFFDict; michael@0: })(); michael@0: michael@0: var CFFTopDict = (function CFFTopDictClosure() { michael@0: var layout = [ michael@0: [[12, 30], 'ROS', ['sid', 'sid', 'num'], null], michael@0: [[12, 20], 'SyntheticBase', 'num', null], michael@0: [0, 'version', 'sid', null], michael@0: [1, 'Notice', 'sid', null], michael@0: [[12, 0], 'Copyright', 'sid', null], michael@0: [2, 'FullName', 'sid', null], michael@0: [3, 'FamilyName', 'sid', null], michael@0: [4, 'Weight', 'sid', null], michael@0: [[12, 1], 'isFixedPitch', 'num', 0], michael@0: [[12, 2], 'ItalicAngle', 'num', 0], michael@0: [[12, 3], 'UnderlinePosition', 'num', -100], michael@0: [[12, 4], 'UnderlineThickness', 'num', 50], michael@0: [[12, 5], 'PaintType', 'num', 0], michael@0: [[12, 6], 'CharstringType', 'num', 2], michael@0: [[12, 7], 'FontMatrix', ['num', 'num', 'num', 'num', 'num', 'num'], michael@0: [0.001, 0, 0, 0.001, 0, 0]], michael@0: [13, 'UniqueID', 'num', null], michael@0: [5, 'FontBBox', ['num', 'num', 'num', 'num'], [0, 0, 0, 0]], michael@0: [[12, 8], 'StrokeWidth', 'num', 0], michael@0: [14, 'XUID', 'array', null], michael@0: [15, 'charset', 'offset', 0], michael@0: [16, 'Encoding', 'offset', 0], michael@0: [17, 'CharStrings', 'offset', 0], michael@0: [18, 'Private', ['offset', 'offset'], null], michael@0: [[12, 21], 'PostScript', 'sid', null], michael@0: [[12, 22], 'BaseFontName', 'sid', null], michael@0: [[12, 23], 'BaseFontBlend', 'delta', null], michael@0: [[12, 31], 'CIDFontVersion', 'num', 0], michael@0: [[12, 32], 'CIDFontRevision', 'num', 0], michael@0: [[12, 33], 'CIDFontType', 'num', 0], michael@0: [[12, 34], 'CIDCount', 'num', 8720], michael@0: [[12, 35], 'UIDBase', 'num', null], michael@0: // XXX: CID Fonts on DirectWrite 6.1 only seem to work if FDSelect comes michael@0: // before FDArray. michael@0: [[12, 37], 'FDSelect', 'offset', null], michael@0: [[12, 36], 'FDArray', 'offset', null], michael@0: [[12, 38], 'FontName', 'sid', null] michael@0: ]; michael@0: var tables = null; michael@0: function CFFTopDict(strings) { michael@0: if (tables === null) { michael@0: tables = CFFDict.createTables(layout); michael@0: } michael@0: CFFDict.call(this, tables, strings); michael@0: this.privateDict = null; michael@0: } michael@0: CFFTopDict.prototype = Object.create(CFFDict.prototype); michael@0: return CFFTopDict; michael@0: })(); michael@0: michael@0: var CFFPrivateDict = (function CFFPrivateDictClosure() { michael@0: var layout = [ michael@0: [6, 'BlueValues', 'delta', null], michael@0: [7, 'OtherBlues', 'delta', null], michael@0: [8, 'FamilyBlues', 'delta', null], michael@0: [9, 'FamilyOtherBlues', 'delta', null], michael@0: [[12, 9], 'BlueScale', 'num', 0.039625], michael@0: [[12, 10], 'BlueShift', 'num', 7], michael@0: [[12, 11], 'BlueFuzz', 'num', 1], michael@0: [10, 'StdHW', 'num', null], michael@0: [11, 'StdVW', 'num', null], michael@0: [[12, 12], 'StemSnapH', 'delta', null], michael@0: [[12, 13], 'StemSnapV', 'delta', null], michael@0: [[12, 14], 'ForceBold', 'num', 0], michael@0: [[12, 17], 'LanguageGroup', 'num', 0], michael@0: [[12, 18], 'ExpansionFactor', 'num', 0.06], michael@0: [[12, 19], 'initialRandomSeed', 'num', 0], michael@0: [20, 'defaultWidthX', 'num', 0], michael@0: [21, 'nominalWidthX', 'num', 0], michael@0: [19, 'Subrs', 'offset', null] michael@0: ]; michael@0: var tables = null; michael@0: function CFFPrivateDict(strings) { michael@0: if (tables === null) { michael@0: tables = CFFDict.createTables(layout); michael@0: } michael@0: CFFDict.call(this, tables, strings); michael@0: this.subrsIndex = null; michael@0: } michael@0: CFFPrivateDict.prototype = Object.create(CFFDict.prototype); michael@0: return CFFPrivateDict; michael@0: })(); michael@0: michael@0: var CFFCharsetPredefinedTypes = { michael@0: ISO_ADOBE: 0, michael@0: EXPERT: 1, michael@0: EXPERT_SUBSET: 2 michael@0: }; michael@0: var CFFCharset = (function CFFCharsetClosure() { michael@0: function CFFCharset(predefined, format, charset, raw) { michael@0: this.predefined = predefined; michael@0: this.format = format; michael@0: this.charset = charset; michael@0: this.raw = raw; michael@0: } michael@0: return CFFCharset; michael@0: })(); michael@0: michael@0: var CFFEncoding = (function CFFEncodingClosure() { michael@0: function CFFEncoding(predefined, format, encoding, raw) { michael@0: this.predefined = predefined; michael@0: this.format = format; michael@0: this.encoding = encoding; michael@0: this.raw = raw; michael@0: } michael@0: return CFFEncoding; michael@0: })(); michael@0: michael@0: var CFFFDSelect = (function CFFFDSelectClosure() { michael@0: function CFFFDSelect(fdSelect, raw) { michael@0: this.fdSelect = fdSelect; michael@0: this.raw = raw; michael@0: } michael@0: return CFFFDSelect; michael@0: })(); michael@0: michael@0: // Helper class to keep track of where an offset is within the data and helps michael@0: // filling in that offset once it's known. michael@0: var CFFOffsetTracker = (function CFFOffsetTrackerClosure() { michael@0: function CFFOffsetTracker() { michael@0: this.offsets = {}; michael@0: } michael@0: CFFOffsetTracker.prototype = { michael@0: isTracking: function CFFOffsetTracker_isTracking(key) { michael@0: return key in this.offsets; michael@0: }, michael@0: track: function CFFOffsetTracker_track(key, location) { michael@0: if (key in this.offsets) { michael@0: error('Already tracking location of ' + key); michael@0: } michael@0: this.offsets[key] = location; michael@0: }, michael@0: offset: function CFFOffsetTracker_offset(value) { michael@0: for (var key in this.offsets) { michael@0: this.offsets[key] += value; michael@0: } michael@0: }, michael@0: setEntryLocation: function CFFOffsetTracker_setEntryLocation(key, michael@0: values, michael@0: output) { michael@0: if (!(key in this.offsets)) { michael@0: error('Not tracking location of ' + key); michael@0: } michael@0: var data = output.data; michael@0: var dataOffset = this.offsets[key]; michael@0: var size = 5; michael@0: for (var i = 0, ii = values.length; i < ii; ++i) { michael@0: var offset0 = i * size + dataOffset; michael@0: var offset1 = offset0 + 1; michael@0: var offset2 = offset0 + 2; michael@0: var offset3 = offset0 + 3; michael@0: var offset4 = offset0 + 4; michael@0: // It's easy to screw up offsets so perform this sanity check. michael@0: if (data[offset0] !== 0x1d || data[offset1] !== 0 || michael@0: data[offset2] !== 0 || data[offset3] !== 0 || data[offset4] !== 0) { michael@0: error('writing to an offset that is not empty'); michael@0: } michael@0: var value = values[i]; michael@0: data[offset0] = 0x1d; michael@0: data[offset1] = (value >> 24) & 0xFF; michael@0: data[offset2] = (value >> 16) & 0xFF; michael@0: data[offset3] = (value >> 8) & 0xFF; michael@0: data[offset4] = value & 0xFF; michael@0: } michael@0: } michael@0: }; michael@0: return CFFOffsetTracker; michael@0: })(); michael@0: michael@0: // Takes a CFF and converts it to the binary representation. michael@0: var CFFCompiler = (function CFFCompilerClosure() { michael@0: function CFFCompiler(cff) { michael@0: this.cff = cff; michael@0: } michael@0: CFFCompiler.prototype = { michael@0: compile: function CFFCompiler_compile() { michael@0: var cff = this.cff; michael@0: var output = { michael@0: data: [], michael@0: length: 0, michael@0: add: function CFFCompiler_add(data) { michael@0: this.data = this.data.concat(data); michael@0: this.length = this.data.length; michael@0: } michael@0: }; michael@0: michael@0: // Compile the five entries that must be in order. michael@0: var header = this.compileHeader(cff.header); michael@0: output.add(header); michael@0: michael@0: var nameIndex = this.compileNameIndex(cff.names); michael@0: output.add(nameIndex); michael@0: michael@0: if (cff.isCIDFont) { michael@0: // The spec is unclear on how font matrices should relate to each other michael@0: // when there is one in the main top dict and the sub top dicts. michael@0: // Windows handles this differently than linux and osx so we have to michael@0: // normalize to work on all. michael@0: // Rules based off of some mailing list discussions: michael@0: // - If main font has a matrix and subfont doesn't, use the main matrix. michael@0: // - If no main font matrix and there is a subfont matrix, use the michael@0: // subfont matrix. michael@0: // - If both have matrices, concat together. michael@0: // - If neither have matrices, use default. michael@0: // To make this work on all platforms we move the top matrix into each michael@0: // sub top dict and concat if necessary. michael@0: if (cff.topDict.hasName('FontMatrix')) { michael@0: var base = cff.topDict.getByName('FontMatrix'); michael@0: cff.topDict.removeByName('FontMatrix'); michael@0: for (var i = 0, ii = cff.fdArray.length; i < ii; i++) { michael@0: var subDict = cff.fdArray[i]; michael@0: var matrix = base.slice(0); michael@0: if (subDict.hasName('FontMatrix')) { michael@0: matrix = Util.transform(matrix, subDict.getByName('FontMatrix')); michael@0: } michael@0: subDict.setByName('FontMatrix', matrix); michael@0: } michael@0: } michael@0: } michael@0: michael@0: var compiled = this.compileTopDicts([cff.topDict], michael@0: output.length, michael@0: cff.isCIDFont); michael@0: output.add(compiled.output); michael@0: var topDictTracker = compiled.trackers[0]; michael@0: michael@0: var stringIndex = this.compileStringIndex(cff.strings.strings); michael@0: output.add(stringIndex); michael@0: michael@0: var globalSubrIndex = this.compileIndex(cff.globalSubrIndex); michael@0: output.add(globalSubrIndex); michael@0: michael@0: // Now start on the other entries that have no specfic order. michael@0: if (cff.encoding && cff.topDict.hasName('Encoding')) { michael@0: if (cff.encoding.predefined) { michael@0: topDictTracker.setEntryLocation('Encoding', [cff.encoding.format], michael@0: output); michael@0: } else { michael@0: var encoding = this.compileEncoding(cff.encoding); michael@0: topDictTracker.setEntryLocation('Encoding', [output.length], output); michael@0: output.add(encoding); michael@0: } michael@0: } michael@0: michael@0: if (cff.charset && cff.topDict.hasName('charset')) { michael@0: if (cff.charset.predefined) { michael@0: topDictTracker.setEntryLocation('charset', [cff.charset.format], michael@0: output); michael@0: } else { michael@0: var charset = this.compileCharset(cff.charset); michael@0: topDictTracker.setEntryLocation('charset', [output.length], output); michael@0: output.add(charset); michael@0: } michael@0: } michael@0: michael@0: var charStrings = this.compileCharStrings(cff.charStrings); michael@0: topDictTracker.setEntryLocation('CharStrings', [output.length], output); michael@0: output.add(charStrings); michael@0: michael@0: if (cff.isCIDFont) { michael@0: // For some reason FDSelect must be in front of FDArray on windows. OSX michael@0: // and linux don't seem to care. michael@0: topDictTracker.setEntryLocation('FDSelect', [output.length], output); michael@0: var fdSelect = this.compileFDSelect(cff.fdSelect.raw); michael@0: output.add(fdSelect); michael@0: // It is unclear if the sub font dictionary can have CID related michael@0: // dictionary keys, but the sanitizer doesn't like them so remove them. michael@0: compiled = this.compileTopDicts(cff.fdArray, output.length, true); michael@0: topDictTracker.setEntryLocation('FDArray', [output.length], output); michael@0: output.add(compiled.output); michael@0: var fontDictTrackers = compiled.trackers; michael@0: michael@0: this.compilePrivateDicts(cff.fdArray, fontDictTrackers, output); michael@0: } michael@0: michael@0: this.compilePrivateDicts([cff.topDict], [topDictTracker], output); michael@0: michael@0: // If the font data ends with INDEX whose object data is zero-length, michael@0: // the sanitizer will bail out. Add a dummy byte to avoid that. michael@0: output.add([0]); michael@0: michael@0: return output.data; michael@0: }, michael@0: encodeNumber: function CFFCompiler_encodeNumber(value) { michael@0: if (parseFloat(value) == parseInt(value, 10) && !isNaN(value)) { // isInt michael@0: return this.encodeInteger(value); michael@0: } else { michael@0: return this.encodeFloat(value); michael@0: } michael@0: }, michael@0: encodeFloat: function CFFCompiler_encodeFloat(num) { michael@0: var value = num.toString(); michael@0: michael@0: // rounding inaccurate doubles michael@0: var m = /\.(\d*?)(?:9{5,20}|0{5,20})\d{0,2}(?:e(.+)|$)/.exec(value); michael@0: if (m) { michael@0: var epsilon = parseFloat('1e' + ((m[2] ? +m[2] : 0) + m[1].length)); michael@0: value = (Math.round(num * epsilon) / epsilon).toString(); michael@0: } michael@0: michael@0: var nibbles = ''; michael@0: var i, ii; michael@0: for (i = 0, ii = value.length; i < ii; ++i) { michael@0: var a = value[i]; michael@0: if (a === 'e') { michael@0: nibbles += value[++i] === '-' ? 'c' : 'b'; michael@0: } else if (a === '.') { michael@0: nibbles += 'a'; michael@0: } else if (a === '-') { michael@0: nibbles += 'e'; michael@0: } else { michael@0: nibbles += a; michael@0: } michael@0: } michael@0: nibbles += (nibbles.length & 1) ? 'f' : 'ff'; michael@0: var out = [30]; michael@0: for (i = 0, ii = nibbles.length; i < ii; i += 2) { michael@0: out.push(parseInt(nibbles.substr(i, 2), 16)); michael@0: } michael@0: return out; michael@0: }, michael@0: encodeInteger: function CFFCompiler_encodeInteger(value) { michael@0: var code; michael@0: if (value >= -107 && value <= 107) { michael@0: code = [value + 139]; michael@0: } else if (value >= 108 && value <= 1131) { michael@0: value = [value - 108]; michael@0: code = [(value >> 8) + 247, value & 0xFF]; michael@0: } else if (value >= -1131 && value <= -108) { michael@0: value = -value - 108; michael@0: code = [(value >> 8) + 251, value & 0xFF]; michael@0: } else if (value >= -32768 && value <= 32767) { michael@0: code = [0x1c, (value >> 8) & 0xFF, value & 0xFF]; michael@0: } else { michael@0: code = [0x1d, michael@0: (value >> 24) & 0xFF, michael@0: (value >> 16) & 0xFF, michael@0: (value >> 8) & 0xFF, michael@0: value & 0xFF]; michael@0: } michael@0: return code; michael@0: }, michael@0: compileHeader: function CFFCompiler_compileHeader(header) { michael@0: return [ michael@0: header.major, michael@0: header.minor, michael@0: header.hdrSize, michael@0: header.offSize michael@0: ]; michael@0: }, michael@0: compileNameIndex: function CFFCompiler_compileNameIndex(names) { michael@0: var nameIndex = new CFFIndex(); michael@0: for (var i = 0, ii = names.length; i < ii; ++i) { michael@0: nameIndex.add(stringToArray(names[i])); michael@0: } michael@0: return this.compileIndex(nameIndex); michael@0: }, michael@0: compileTopDicts: function CFFCompiler_compileTopDicts(dicts, michael@0: length, michael@0: removeCidKeys) { michael@0: var fontDictTrackers = []; michael@0: var fdArrayIndex = new CFFIndex(); michael@0: for (var i = 0, ii = dicts.length; i < ii; ++i) { michael@0: var fontDict = dicts[i]; michael@0: if (removeCidKeys) { michael@0: fontDict.removeByName('CIDFontVersion'); michael@0: fontDict.removeByName('CIDFontRevision'); michael@0: fontDict.removeByName('CIDFontType'); michael@0: fontDict.removeByName('CIDCount'); michael@0: fontDict.removeByName('UIDBase'); michael@0: } michael@0: var fontDictTracker = new CFFOffsetTracker(); michael@0: var fontDictData = this.compileDict(fontDict, fontDictTracker); michael@0: fontDictTrackers.push(fontDictTracker); michael@0: fdArrayIndex.add(fontDictData); michael@0: fontDictTracker.offset(length); michael@0: } michael@0: fdArrayIndex = this.compileIndex(fdArrayIndex, fontDictTrackers); michael@0: return { michael@0: trackers: fontDictTrackers, michael@0: output: fdArrayIndex michael@0: }; michael@0: }, michael@0: compilePrivateDicts: function CFFCompiler_compilePrivateDicts(dicts, michael@0: trackers, michael@0: output) { michael@0: for (var i = 0, ii = dicts.length; i < ii; ++i) { michael@0: var fontDict = dicts[i]; michael@0: assert(fontDict.privateDict && fontDict.hasName('Private'), michael@0: 'There must be an private dictionary.'); michael@0: var privateDict = fontDict.privateDict; michael@0: var privateDictTracker = new CFFOffsetTracker(); michael@0: var privateDictData = this.compileDict(privateDict, privateDictTracker); michael@0: michael@0: var outputLength = output.length; michael@0: privateDictTracker.offset(outputLength); michael@0: if (!privateDictData.length) { michael@0: // The private dictionary was empty, set the output length to zero to michael@0: // ensure the offset length isn't out of bounds in the eyes of the michael@0: // sanitizer. michael@0: outputLength = 0; michael@0: } michael@0: michael@0: trackers[i].setEntryLocation('Private', michael@0: [privateDictData.length, outputLength], michael@0: output); michael@0: output.add(privateDictData); michael@0: michael@0: if (privateDict.subrsIndex && privateDict.hasName('Subrs')) { michael@0: var subrs = this.compileIndex(privateDict.subrsIndex); michael@0: privateDictTracker.setEntryLocation('Subrs', [privateDictData.length], michael@0: output); michael@0: output.add(subrs); michael@0: } michael@0: } michael@0: }, michael@0: compileDict: function CFFCompiler_compileDict(dict, offsetTracker) { michael@0: var out = []; michael@0: // The dictionary keys must be in a certain order. michael@0: var order = dict.order; michael@0: for (var i = 0; i < order.length; ++i) { michael@0: var key = order[i]; michael@0: if (!(key in dict.values)) { michael@0: continue; michael@0: } michael@0: var values = dict.values[key]; michael@0: var types = dict.types[key]; michael@0: if (!isArray(types)) { michael@0: types = [types]; michael@0: } michael@0: if (!isArray(values)) { michael@0: values = [values]; michael@0: } michael@0: michael@0: // Remove any empty dict values. michael@0: if (values.length === 0) { michael@0: continue; michael@0: } michael@0: michael@0: for (var j = 0, jj = types.length; j < jj; ++j) { michael@0: var type = types[j]; michael@0: var value = values[j]; michael@0: switch (type) { michael@0: case 'num': michael@0: case 'sid': michael@0: out = out.concat(this.encodeNumber(value)); michael@0: break; michael@0: case 'offset': michael@0: // For offsets we just insert a 32bit integer so we don't have to michael@0: // deal with figuring out the length of the offset when it gets michael@0: // replaced later on by the compiler. michael@0: var name = dict.keyToNameMap[key]; michael@0: // Some offsets have the offset and the length, so just record the michael@0: // position of the first one. michael@0: if (!offsetTracker.isTracking(name)) { michael@0: offsetTracker.track(name, out.length); michael@0: } michael@0: out = out.concat([0x1d, 0, 0, 0, 0]); michael@0: break; michael@0: case 'array': michael@0: case 'delta': michael@0: out = out.concat(this.encodeNumber(value)); michael@0: for (var k = 1, kk = values.length; k < kk; ++k) { michael@0: out = out.concat(this.encodeNumber(values[k])); michael@0: } michael@0: break; michael@0: default: michael@0: error('Unknown data type of ' + type); michael@0: break; michael@0: } michael@0: } michael@0: out = out.concat(dict.opcodes[key]); michael@0: } michael@0: return out; michael@0: }, michael@0: compileStringIndex: function CFFCompiler_compileStringIndex(strings) { michael@0: var stringIndex = new CFFIndex(); michael@0: for (var i = 0, ii = strings.length; i < ii; ++i) { michael@0: stringIndex.add(stringToArray(strings[i])); michael@0: } michael@0: return this.compileIndex(stringIndex); michael@0: }, michael@0: compileGlobalSubrIndex: function CFFCompiler_compileGlobalSubrIndex() { michael@0: var globalSubrIndex = this.cff.globalSubrIndex; michael@0: this.out.writeByteArray(this.compileIndex(globalSubrIndex)); michael@0: }, michael@0: compileCharStrings: function CFFCompiler_compileCharStrings(charStrings) { michael@0: return this.compileIndex(charStrings); michael@0: }, michael@0: compileCharset: function CFFCompiler_compileCharset(charset) { michael@0: return this.compileTypedArray(charset.raw); michael@0: }, michael@0: compileEncoding: function CFFCompiler_compileEncoding(encoding) { michael@0: return this.compileTypedArray(encoding.raw); michael@0: }, michael@0: compileFDSelect: function CFFCompiler_compileFDSelect(fdSelect) { michael@0: return this.compileTypedArray(fdSelect); michael@0: }, michael@0: compileTypedArray: function CFFCompiler_compileTypedArray(data) { michael@0: var out = []; michael@0: for (var i = 0, ii = data.length; i < ii; ++i) { michael@0: out[i] = data[i]; michael@0: } michael@0: return out; michael@0: }, michael@0: compileIndex: function CFFCompiler_compileIndex(index, trackers) { michael@0: trackers = trackers || []; michael@0: var objects = index.objects; michael@0: // First 2 bytes contains the number of objects contained into this index michael@0: var count = objects.length; michael@0: michael@0: // If there is no object, just create an index. This technically michael@0: // should just be [0, 0] but OTS has an issue with that. michael@0: if (count === 0) { michael@0: return [0, 0, 0]; michael@0: } michael@0: michael@0: var data = [(count >> 8) & 0xFF, count & 0xff]; michael@0: michael@0: var lastOffset = 1, i; michael@0: for (i = 0; i < count; ++i) { michael@0: lastOffset += objects[i].length; michael@0: } michael@0: michael@0: var offsetSize; michael@0: if (lastOffset < 0x100) { michael@0: offsetSize = 1; michael@0: } else if (lastOffset < 0x10000) { michael@0: offsetSize = 2; michael@0: } else if (lastOffset < 0x1000000) { michael@0: offsetSize = 3; michael@0: } else { michael@0: offsetSize = 4; michael@0: } michael@0: michael@0: // Next byte contains the offset size use to reference object in the file michael@0: data.push(offsetSize); michael@0: michael@0: // Add another offset after this one because we need a new offset michael@0: var relativeOffset = 1; michael@0: for (i = 0; i < count + 1; i++) { michael@0: if (offsetSize === 1) { michael@0: data.push(relativeOffset & 0xFF); michael@0: } else if (offsetSize === 2) { michael@0: data.push((relativeOffset >> 8) & 0xFF, michael@0: relativeOffset & 0xFF); michael@0: } else if (offsetSize === 3) { michael@0: data.push((relativeOffset >> 16) & 0xFF, michael@0: (relativeOffset >> 8) & 0xFF, michael@0: relativeOffset & 0xFF); michael@0: } else { michael@0: data.push((relativeOffset >>> 24) & 0xFF, michael@0: (relativeOffset >> 16) & 0xFF, michael@0: (relativeOffset >> 8) & 0xFF, michael@0: relativeOffset & 0xFF); michael@0: } michael@0: michael@0: if (objects[i]) { michael@0: relativeOffset += objects[i].length; michael@0: } michael@0: } michael@0: michael@0: for (i = 0; i < count; i++) { michael@0: // Notify the tracker where the object will be offset in the data. michael@0: if (trackers[i]) { michael@0: trackers[i].offset(data.length); michael@0: } michael@0: for (var j = 0, jj = objects[i].length; j < jj; j++) { michael@0: data.push(objects[i][j]); michael@0: } michael@0: } michael@0: return data; michael@0: } michael@0: }; michael@0: return CFFCompiler; michael@0: })(); michael@0: michael@0: // Workaround for seac on Windows. michael@0: (function checkSeacSupport() { michael@0: if (/Windows/.test(navigator.userAgent)) { michael@0: SEAC_ANALYSIS_ENABLED = true; michael@0: } michael@0: })(); michael@0: michael@0: // Workaround for Private Use Area characters in Chrome on Windows michael@0: // http://code.google.com/p/chromium/issues/detail?id=122465 michael@0: // https://github.com/mozilla/pdf.js/issues/1689 michael@0: (function checkChromeWindows() { michael@0: if (/Windows.*Chrome/.test(navigator.userAgent)) { michael@0: SKIP_PRIVATE_USE_RANGE_F000_TO_F01F = true; michael@0: } michael@0: })(); michael@0: michael@0: michael@0: var FontRendererFactory = (function FontRendererFactoryClosure() { michael@0: function getLong(data, offset) { michael@0: return (data[offset] << 24) | (data[offset + 1] << 16) | michael@0: (data[offset + 2] << 8) | data[offset + 3]; michael@0: } michael@0: michael@0: function getUshort(data, offset) { michael@0: return (data[offset] << 8) | data[offset + 1]; michael@0: } michael@0: michael@0: function parseCmap(data, start, end) { michael@0: var offset = (getUshort(data, start + 2) === 1 ? michael@0: getLong(data, start + 8) : getLong(data, start + 16)); michael@0: var format = getUshort(data, start + offset); michael@0: var length, ranges, p, i; michael@0: if (format === 4) { michael@0: length = getUshort(data, start + offset + 2); michael@0: var segCount = getUshort(data, start + offset + 6) >> 1; michael@0: p = start + offset + 14; michael@0: ranges = []; michael@0: for (i = 0; i < segCount; i++, p += 2) { michael@0: ranges[i] = {end: getUshort(data, p)}; michael@0: } michael@0: p += 2; michael@0: for (i = 0; i < segCount; i++, p += 2) { michael@0: ranges[i].start = getUshort(data, p); michael@0: } michael@0: for (i = 0; i < segCount; i++, p += 2) { michael@0: ranges[i].idDelta = getUshort(data, p); michael@0: } michael@0: for (i = 0; i < segCount; i++, p += 2) { michael@0: var idOffset = getUshort(data, p); michael@0: if (idOffset === 0) { michael@0: continue; michael@0: } michael@0: ranges[i].ids = []; michael@0: for (var j = 0, jj = ranges[i].end - ranges[i].start + 1; j < jj; j++) { michael@0: ranges[i].ids[j] = getUshort(data, p + idOffset); michael@0: idOffset += 2; michael@0: } michael@0: } michael@0: return ranges; michael@0: } else if (format === 12) { michael@0: length = getLong(data, start + offset + 4); michael@0: var groups = getLong(data, start + offset + 12); michael@0: p = start + offset + 16; michael@0: ranges = []; michael@0: for (i = 0; i < groups; i++) { michael@0: ranges.push({ michael@0: start: getLong(data, p), michael@0: end: getLong(data, p + 4), michael@0: idDelta: getLong(data, p + 8) - getLong(data, p) michael@0: }); michael@0: p += 12; michael@0: } michael@0: return ranges; michael@0: } michael@0: error('not supported cmap: ' + format); michael@0: } michael@0: michael@0: function parseCff(data, start, end) { michael@0: var properties = {}; michael@0: var parser = new CFFParser(new Stream(data, start, end - start), michael@0: properties); michael@0: var cff = parser.parse(); michael@0: return { michael@0: glyphs: cff.charStrings.objects, michael@0: subrs: (cff.topDict.privateDict && cff.topDict.privateDict.subrsIndex && michael@0: cff.topDict.privateDict.subrsIndex.objects), michael@0: gsubrs: cff.globalSubrIndex && cff.globalSubrIndex.objects michael@0: }; michael@0: } michael@0: michael@0: function parseGlyfTable(glyf, loca, isGlyphLocationsLong) { michael@0: var itemSize, itemDecode; michael@0: if (isGlyphLocationsLong) { michael@0: itemSize = 4; michael@0: itemDecode = function fontItemDecodeLong(data, offset) { michael@0: return (data[offset] << 24) | (data[offset + 1] << 16) | michael@0: (data[offset + 2] << 8) | data[offset + 3]; michael@0: }; michael@0: } else { michael@0: itemSize = 2; michael@0: itemDecode = function fontItemDecode(data, offset) { michael@0: return (data[offset] << 9) | (data[offset + 1] << 1); michael@0: }; michael@0: } michael@0: var glyphs = []; michael@0: var startOffset = itemDecode(loca, 0); michael@0: for (var j = itemSize; j < loca.length; j += itemSize) { michael@0: var endOffset = itemDecode(loca, j); michael@0: glyphs.push(glyf.subarray(startOffset, endOffset)); michael@0: startOffset = endOffset; michael@0: } michael@0: return glyphs; michael@0: } michael@0: michael@0: function lookupCmap(ranges, unicode) { michael@0: var code = unicode.charCodeAt(0); michael@0: var l = 0, r = ranges.length - 1; michael@0: while (l < r) { michael@0: var c = (l + r + 1) >> 1; michael@0: if (code < ranges[c].start) { michael@0: r = c - 1; michael@0: } else { michael@0: l = c; michael@0: } michael@0: } michael@0: if (ranges[l].start <= code && code <= ranges[l].end) { michael@0: return (ranges[l].idDelta + (ranges[l].ids ? michael@0: ranges[l].ids[code - ranges[l].start] : code)) & 0xFFFF; michael@0: } michael@0: return 0; michael@0: } michael@0: michael@0: function compileGlyf(code, js, font) { michael@0: function moveTo(x, y) { michael@0: js.push('c.moveTo(' + x + ',' + y + ');'); michael@0: } michael@0: function lineTo(x, y) { michael@0: js.push('c.lineTo(' + x + ',' + y + ');'); michael@0: } michael@0: function quadraticCurveTo(xa, ya, x, y) { michael@0: js.push('c.quadraticCurveTo(' + xa + ',' + ya + ',' + michael@0: x + ',' + y + ');'); michael@0: } michael@0: michael@0: var i = 0; michael@0: var numberOfContours = ((code[i] << 24) | (code[i + 1] << 16)) >> 16; michael@0: var flags; michael@0: var x = 0, y = 0; michael@0: i += 10; michael@0: if (numberOfContours < 0) { michael@0: // composite glyph michael@0: do { michael@0: flags = (code[i] << 8) | code[i + 1]; michael@0: var glyphIndex = (code[i + 2] << 8) | code[i + 3]; michael@0: i += 4; michael@0: var arg1, arg2; michael@0: if ((flags & 0x01)) { michael@0: arg1 = ((code[i] << 24) | (code[i + 1] << 16)) >> 16; michael@0: arg2 = ((code[i + 2] << 24) | (code[i + 3] << 16)) >> 16; michael@0: i += 4; michael@0: } else { michael@0: arg1 = code[i++]; arg2 = code[i++]; michael@0: } michael@0: if ((flags & 0x02)) { michael@0: x = arg1; michael@0: y = arg2; michael@0: } else { michael@0: x = 0; y = 0; // TODO "they are points" ? michael@0: } michael@0: var scaleX = 1, scaleY = 1, scale01 = 0, scale10 = 0; michael@0: if ((flags & 0x08)) { michael@0: scaleX = michael@0: scaleY = ((code[i] << 24) | (code[i + 1] << 16)) / 1073741824; michael@0: i += 2; michael@0: } else if ((flags & 0x40)) { michael@0: scaleX = ((code[i] << 24) | (code[i + 1] << 16)) / 1073741824; michael@0: scaleY = ((code[i + 2] << 24) | (code[i + 3] << 16)) / 1073741824; michael@0: i += 4; michael@0: } else if ((flags & 0x80)) { michael@0: scaleX = ((code[i] << 24) | (code[i + 1] << 16)) / 1073741824; michael@0: scale01 = ((code[i + 2] << 24) | (code[i + 3] << 16)) / 1073741824; michael@0: scale10 = ((code[i + 4] << 24) | (code[i + 5] << 16)) / 1073741824; michael@0: scaleY = ((code[i + 6] << 24) | (code[i + 7] << 16)) / 1073741824; michael@0: i += 8; michael@0: } michael@0: var subglyph = font.glyphs[glyphIndex]; michael@0: if (subglyph) { michael@0: js.push('c.save();'); michael@0: js.push('c.transform(' + scaleX + ',' + scale01 + ',' + michael@0: scale10 + ',' + scaleY + ',' + x + ',' + y + ');'); michael@0: compileGlyf(subglyph, js, font); michael@0: js.push('c.restore();'); michael@0: } michael@0: } while ((flags & 0x20)); michael@0: } else { michael@0: // simple glyph michael@0: var endPtsOfContours = []; michael@0: var j, jj; michael@0: for (j = 0; j < numberOfContours; j++) { michael@0: endPtsOfContours.push((code[i] << 8) | code[i + 1]); michael@0: i += 2; michael@0: } michael@0: var instructionLength = (code[i] << 8) | code[i + 1]; michael@0: i += 2 + instructionLength; // skipping the instructions michael@0: var numberOfPoints = endPtsOfContours[endPtsOfContours.length - 1] + 1; michael@0: var points = []; michael@0: while (points.length < numberOfPoints) { michael@0: flags = code[i++]; michael@0: var repeat = 1; michael@0: if ((flags & 0x08)) { michael@0: repeat += code[i++]; michael@0: } michael@0: while (repeat-- > 0) { michael@0: points.push({flags: flags}); michael@0: } michael@0: } michael@0: for (j = 0; j < numberOfPoints; j++) { michael@0: switch (points[j].flags & 0x12) { michael@0: case 0x00: michael@0: x += ((code[i] << 24) | (code[i + 1] << 16)) >> 16; michael@0: i += 2; michael@0: break; michael@0: case 0x02: michael@0: x -= code[i++]; michael@0: break; michael@0: case 0x12: michael@0: x += code[i++]; michael@0: break; michael@0: } michael@0: points[j].x = x; michael@0: } michael@0: for (j = 0; j < numberOfPoints; j++) { michael@0: switch (points[j].flags & 0x24) { michael@0: case 0x00: michael@0: y += ((code[i] << 24) | (code[i + 1] << 16)) >> 16; michael@0: i += 2; michael@0: break; michael@0: case 0x04: michael@0: y -= code[i++]; michael@0: break; michael@0: case 0x24: michael@0: y += code[i++]; michael@0: break; michael@0: } michael@0: points[j].y = y; michael@0: } michael@0: michael@0: var startPoint = 0; michael@0: for (i = 0; i < numberOfContours; i++) { michael@0: var endPoint = endPtsOfContours[i]; michael@0: // contours might have implicit points, which is located in the middle michael@0: // between two neighboring off-curve points michael@0: var contour = points.slice(startPoint, endPoint + 1); michael@0: if ((contour[0].flags & 1)) { michael@0: contour.push(contour[0]); // using start point at the contour end michael@0: } else if ((contour[contour.length - 1].flags & 1)) { michael@0: // first is off-curve point, trying to use one from the end michael@0: contour.unshift(contour[contour.length - 1]); michael@0: } else { michael@0: // start and end are off-curve points, creating implicit one michael@0: var p = { michael@0: flags: 1, michael@0: x: (contour[0].x + contour[contour.length - 1].x) / 2, michael@0: y: (contour[0].y + contour[contour.length - 1].y) / 2 michael@0: }; michael@0: contour.unshift(p); michael@0: contour.push(p); michael@0: } michael@0: moveTo(contour[0].x, contour[0].y); michael@0: for (j = 1, jj = contour.length; j < jj; j++) { michael@0: if ((contour[j].flags & 1)) { michael@0: lineTo(contour[j].x, contour[j].y); michael@0: } else if ((contour[j + 1].flags & 1)){ michael@0: quadraticCurveTo(contour[j].x, contour[j].y, michael@0: contour[j + 1].x, contour[j + 1].y); michael@0: j++; michael@0: } else { michael@0: quadraticCurveTo(contour[j].x, contour[j].y, michael@0: (contour[j].x + contour[j + 1].x) / 2, michael@0: (contour[j].y + contour[j + 1].y) / 2); michael@0: } michael@0: } michael@0: startPoint = endPoint + 1; michael@0: } michael@0: } michael@0: } michael@0: michael@0: function compileCharString(code, js, font) { michael@0: var stack = []; michael@0: var x = 0, y = 0; michael@0: var stems = 0; michael@0: michael@0: function moveTo(x, y) { michael@0: js.push('c.moveTo(' + x + ',' + y + ');'); michael@0: } michael@0: function lineTo(x, y) { michael@0: js.push('c.lineTo(' + x + ',' + y + ');'); michael@0: } michael@0: function bezierCurveTo(x1, y1, x2, y2, x, y) { michael@0: js.push('c.bezierCurveTo(' + x1 + ',' + y1 + ',' + x2 + ',' + y2 + ',' + michael@0: x + ',' + y + ');'); michael@0: } michael@0: michael@0: function parse(code) { michael@0: var i = 0; michael@0: while (i < code.length) { michael@0: var stackClean = false; michael@0: var v = code[i++]; michael@0: var xa, xb, ya, yb, y1, y2, y3, n, subrCode; michael@0: switch (v) { michael@0: case 1: // hstem michael@0: stems += stack.length >> 1; michael@0: stackClean = true; michael@0: break; michael@0: case 3: // vstem michael@0: stems += stack.length >> 1; michael@0: stackClean = true; michael@0: break; michael@0: case 4: // vmoveto michael@0: y += stack.pop(); michael@0: moveTo(x, y); michael@0: stackClean = true; michael@0: break; michael@0: case 5: // rlineto michael@0: while (stack.length > 0) { michael@0: x += stack.shift(); michael@0: y += stack.shift(); michael@0: lineTo(x, y); michael@0: } michael@0: break; michael@0: case 6: // hlineto michael@0: while (stack.length > 0) { michael@0: x += stack.shift(); michael@0: lineTo(x, y); michael@0: if (stack.length === 0) { michael@0: break; michael@0: } michael@0: y += stack.shift(); michael@0: lineTo(x, y); michael@0: } michael@0: break; michael@0: case 7: // vlineto michael@0: while (stack.length > 0) { michael@0: y += stack.shift(); michael@0: lineTo(x, y); michael@0: if (stack.length === 0) { michael@0: break; michael@0: } michael@0: x += stack.shift(); michael@0: lineTo(x, y); michael@0: } michael@0: break; michael@0: case 8: // rrcurveto michael@0: while (stack.length > 0) { michael@0: xa = x + stack.shift(); ya = y + stack.shift(); michael@0: xb = xa + stack.shift(); yb = ya + stack.shift(); michael@0: x = xb + stack.shift(); y = yb + stack.shift(); michael@0: bezierCurveTo(xa, ya, xb, yb, x, y); michael@0: } michael@0: break; michael@0: case 10: // callsubr michael@0: n = stack.pop() + font.subrsBias; michael@0: subrCode = font.subrs[n]; michael@0: if (subrCode) { michael@0: parse(subrCode); michael@0: } michael@0: break; michael@0: case 11: // return michael@0: return; michael@0: case 12: michael@0: v = code[i++]; michael@0: switch (v) { michael@0: case 34: // flex michael@0: xa = x + stack.shift(); michael@0: xb = xa + stack.shift(); y1 = y + stack.shift(); michael@0: x = xb + stack.shift(); michael@0: bezierCurveTo(xa, y, xb, y1, x, y1); michael@0: xa = x + stack.shift(); michael@0: xb = xa + stack.shift(); michael@0: x = xb + stack.shift(); michael@0: bezierCurveTo(xa, y1, xb, y, x, y); michael@0: break; michael@0: case 35: // flex michael@0: xa = x + stack.shift(); ya = y + stack.shift(); michael@0: xb = xa + stack.shift(); yb = ya + stack.shift(); michael@0: x = xb + stack.shift(); y = yb + stack.shift(); michael@0: bezierCurveTo(xa, ya, xb, yb, x, y); michael@0: xa = x + stack.shift(); ya = y + stack.shift(); michael@0: xb = xa + stack.shift(); yb = ya + stack.shift(); michael@0: x = xb + stack.shift(); y = yb + stack.shift(); michael@0: bezierCurveTo(xa, ya, xb, yb, x, y); michael@0: stack.pop(); // fd michael@0: break; michael@0: case 36: // hflex1 michael@0: xa = x + stack.shift(); y1 = y + stack.shift(); michael@0: xb = xa + stack.shift(); y2 = y1 + stack.shift(); michael@0: x = xb + stack.shift(); michael@0: bezierCurveTo(xa, y1, xb, y2, x, y2); michael@0: xa = x + stack.shift(); michael@0: xb = xa + stack.shift(); y3 = y2 + stack.shift(); michael@0: x = xb + stack.shift(); michael@0: bezierCurveTo(xa, y2, xb, y3, x, y); michael@0: break; michael@0: case 37: // flex1 michael@0: var x0 = x, y0 = y; michael@0: xa = x + stack.shift(); ya = y + stack.shift(); michael@0: xb = xa + stack.shift(); yb = ya + stack.shift(); michael@0: x = xb + stack.shift(); y = yb + stack.shift(); michael@0: bezierCurveTo(xa, ya, xb, yb, x, y); michael@0: xa = x + stack.shift(); ya = y + stack.shift(); michael@0: xb = xa + stack.shift(); yb = ya + stack.shift(); michael@0: x = xb; y = yb; michael@0: if (Math.abs(x - x0) > Math.abs(y - y0)) { michael@0: x += stack.shift(); michael@0: } else { michael@0: y += stack.shift(); michael@0: } michael@0: bezierCurveTo(xa, ya, xb, yb, x, y); michael@0: break; michael@0: default: michael@0: error('unknown operator: 12 ' + v); michael@0: } michael@0: break; michael@0: case 14: // endchar michael@0: if (stack.length >= 4) { michael@0: var achar = stack.pop(); michael@0: var bchar = stack.pop(); michael@0: y = stack.pop(); michael@0: x = stack.pop(); michael@0: js.push('c.save();'); michael@0: js.push('c.translate('+ x + ',' + y + ');'); michael@0: var gid = lookupCmap(font.cmap, String.fromCharCode( michael@0: font.glyphNameMap[Encodings.StandardEncoding[achar]])); michael@0: compileCharString(font.glyphs[gid], js, font); michael@0: js.push('c.restore();'); michael@0: michael@0: gid = lookupCmap(font.cmap, String.fromCharCode( michael@0: font.glyphNameMap[Encodings.StandardEncoding[bchar]])); michael@0: compileCharString(font.glyphs[gid], js, font); michael@0: } michael@0: return; michael@0: case 18: // hstemhm michael@0: stems += stack.length >> 1; michael@0: stackClean = true; michael@0: break; michael@0: case 19: // hintmask michael@0: stems += stack.length >> 1; michael@0: i += (stems + 7) >> 3; michael@0: stackClean = true; michael@0: break; michael@0: case 20: // cntrmask michael@0: stems += stack.length >> 1; michael@0: i += (stems + 7) >> 3; michael@0: stackClean = true; michael@0: break; michael@0: case 21: // rmoveto michael@0: y += stack.pop(); michael@0: x += stack.pop(); michael@0: moveTo(x, y); michael@0: stackClean = true; michael@0: break; michael@0: case 22: // hmoveto michael@0: x += stack.pop(); michael@0: moveTo(x, y); michael@0: stackClean = true; michael@0: break; michael@0: case 23: // vstemhm michael@0: stems += stack.length >> 1; michael@0: stackClean = true; michael@0: break; michael@0: case 24: // rcurveline michael@0: while (stack.length > 2) { michael@0: xa = x + stack.shift(); ya = y + stack.shift(); michael@0: xb = xa + stack.shift(); yb = ya + stack.shift(); michael@0: x = xb + stack.shift(); y = yb + stack.shift(); michael@0: bezierCurveTo(xa, ya, xb, yb, x, y); michael@0: } michael@0: x += stack.shift(); michael@0: y += stack.shift(); michael@0: lineTo(x, y); michael@0: break; michael@0: case 25: // rlinecurve michael@0: while (stack.length > 6) { michael@0: x += stack.shift(); michael@0: y += stack.shift(); michael@0: lineTo(x, y); michael@0: } michael@0: xa = x + stack.shift(); ya = y + stack.shift(); michael@0: xb = xa + stack.shift(); yb = ya + stack.shift(); michael@0: x = xb + stack.shift(); y = yb + stack.shift(); michael@0: bezierCurveTo(xa, ya, xb, yb, x, y); michael@0: break; michael@0: case 26: // vvcurveto michael@0: if (stack.length % 2) { michael@0: x += stack.shift(); michael@0: } michael@0: while (stack.length > 0) { michael@0: xa = x; ya = y + stack.shift(); michael@0: xb = xa + stack.shift(); yb = ya + stack.shift(); michael@0: x = xb; y = yb + stack.shift(); michael@0: bezierCurveTo(xa, ya, xb, yb, x, y); michael@0: } michael@0: break; michael@0: case 27: // hhcurveto michael@0: if (stack.length % 2) { michael@0: y += stack.shift(); michael@0: } michael@0: while (stack.length > 0) { michael@0: xa = x + stack.shift(); ya = y; michael@0: xb = xa + stack.shift(); yb = ya + stack.shift(); michael@0: x = xb + stack.shift(); y = yb; michael@0: bezierCurveTo(xa, ya, xb, yb, x, y); michael@0: } michael@0: break; michael@0: case 28: michael@0: stack.push(((code[i] << 24) | (code[i + 1] << 16)) >> 16); michael@0: i += 2; michael@0: break; michael@0: case 29: // callgsubr michael@0: n = stack.pop() + font.gsubrsBias; michael@0: subrCode = font.gsubrs[n]; michael@0: if (subrCode) { michael@0: parse(subrCode); michael@0: } michael@0: break; michael@0: case 30: // vhcurveto michael@0: while (stack.length > 0) { michael@0: xa = x; ya = y + stack.shift(); michael@0: xb = xa + stack.shift(); yb = ya + stack.shift(); michael@0: x = xb + stack.shift(); michael@0: y = yb + (stack.length === 1 ? stack.shift() : 0); michael@0: bezierCurveTo(xa, ya, xb, yb, x, y); michael@0: if (stack.length === 0) { michael@0: break; michael@0: } michael@0: michael@0: xa = x + stack.shift(); ya = y; michael@0: xb = xa + stack.shift(); yb = ya + stack.shift(); michael@0: y = yb + stack.shift(); michael@0: x = xb + (stack.length === 1 ? stack.shift() : 0); michael@0: bezierCurveTo(xa, ya, xb, yb, x, y); michael@0: } michael@0: break; michael@0: case 31: // hvcurveto michael@0: while (stack.length > 0) { michael@0: xa = x + stack.shift(); ya = y; michael@0: xb = xa + stack.shift(); yb = ya + stack.shift(); michael@0: y = yb + stack.shift(); michael@0: x = xb + (stack.length === 1 ? stack.shift() : 0); michael@0: bezierCurveTo(xa, ya, xb, yb, x, y); michael@0: if (stack.length === 0) { michael@0: break; michael@0: } michael@0: michael@0: xa = x; ya = y + stack.shift(); michael@0: xb = xa + stack.shift(); yb = ya + stack.shift(); michael@0: x = xb + stack.shift(); michael@0: y = yb + (stack.length === 1 ? stack.shift() : 0); michael@0: bezierCurveTo(xa, ya, xb, yb, x, y); michael@0: } michael@0: break; michael@0: default: michael@0: if (v < 32) { michael@0: error('unknown operator: ' + v); michael@0: } michael@0: if (v < 247) { michael@0: stack.push(v - 139); michael@0: } else if (v < 251) { michael@0: stack.push((v - 247) * 256 + code[i++] + 108); michael@0: } else if (v < 255) { michael@0: stack.push(-(v - 251) * 256 - code[i++] - 108); michael@0: } else { michael@0: stack.push(((code[i] << 24) | (code[i + 1] << 16) | michael@0: (code[i + 2] << 8) | code[i + 3]) / 65536); michael@0: i += 4; michael@0: } michael@0: break; michael@0: } michael@0: if (stackClean) { michael@0: stack.length = 0; michael@0: } michael@0: } michael@0: } michael@0: parse(code); michael@0: } michael@0: michael@0: var noop = ''; michael@0: michael@0: function CompiledFont(fontMatrix) { michael@0: this.compiledGlyphs = {}; michael@0: this.fontMatrix = fontMatrix; michael@0: } michael@0: CompiledFont.prototype = { michael@0: getPathJs: function (unicode) { michael@0: var gid = lookupCmap(this.cmap, unicode); michael@0: var fn = this.compiledGlyphs[gid]; michael@0: if (!fn) { michael@0: this.compiledGlyphs[gid] = fn = this.compileGlyph(this.glyphs[gid]); michael@0: } michael@0: return fn; michael@0: }, michael@0: michael@0: compileGlyph: function (code) { michael@0: if (!code || code.length === 0 || code[0] === 14) { michael@0: return noop; michael@0: } michael@0: michael@0: var js = []; michael@0: js.push('c.save();'); michael@0: js.push('c.transform(' + this.fontMatrix.join(',') + ');'); michael@0: js.push('c.scale(size, -size);'); michael@0: michael@0: this.compileGlyphImpl(code, js); michael@0: michael@0: js.push('c.restore();'); michael@0: michael@0: return js.join('\n'); michael@0: }, michael@0: michael@0: compileGlyphImpl: function () { michael@0: error('Children classes should implement this.'); michael@0: }, michael@0: michael@0: hasBuiltPath: function (unicode) { michael@0: var gid = lookupCmap(this.cmap, unicode); michael@0: return gid in this.compiledGlyphs; michael@0: } michael@0: }; michael@0: michael@0: function TrueTypeCompiled(glyphs, cmap, fontMatrix) { michael@0: fontMatrix = fontMatrix || [0.000488, 0, 0, 0.000488, 0, 0]; michael@0: CompiledFont.call(this, fontMatrix); michael@0: michael@0: this.glyphs = glyphs; michael@0: this.cmap = cmap; michael@0: michael@0: this.compiledGlyphs = []; michael@0: } michael@0: michael@0: Util.inherit(TrueTypeCompiled, CompiledFont, { michael@0: compileGlyphImpl: function (code, js) { michael@0: compileGlyf(code, js, this); michael@0: } michael@0: }); michael@0: michael@0: function Type2Compiled(cffInfo, cmap, fontMatrix, glyphNameMap) { michael@0: fontMatrix = fontMatrix || [0.001, 0, 0, 0.001, 0, 0]; michael@0: CompiledFont.call(this, fontMatrix); michael@0: this.glyphs = cffInfo.glyphs; michael@0: this.gsubrs = cffInfo.gsubrs || []; michael@0: this.subrs = cffInfo.subrs || []; michael@0: this.cmap = cmap; michael@0: this.glyphNameMap = glyphNameMap || GlyphsUnicode; michael@0: michael@0: this.compiledGlyphs = []; michael@0: this.gsubrsBias = (this.gsubrs.length < 1240 ? michael@0: 107 : (this.gsubrs.length < 33900 ? 1131 : 32768)); michael@0: this.subrsBias = (this.subrs.length < 1240 ? michael@0: 107 : (this.subrs.length < 33900 ? 1131 : 32768)); michael@0: } michael@0: michael@0: Util.inherit(Type2Compiled, CompiledFont, { michael@0: compileGlyphImpl: function (code, js) { michael@0: compileCharString(code, js, this); michael@0: } michael@0: }); michael@0: michael@0: michael@0: return { michael@0: create: function FontRendererFactory_create(font) { michael@0: var data = new Uint8Array(font.data); michael@0: var cmap, glyf, loca, cff, indexToLocFormat, unitsPerEm; michael@0: var numTables = getUshort(data, 4); michael@0: for (var i = 0, p = 12; i < numTables; i++, p += 16) { michael@0: var tag = bytesToString(data.subarray(p, p + 4)); michael@0: var offset = getLong(data, p + 8); michael@0: var length = getLong(data, p + 12); michael@0: switch (tag) { michael@0: case 'cmap': michael@0: cmap = parseCmap(data, offset, offset + length); michael@0: break; michael@0: case 'glyf': michael@0: glyf = data.subarray(offset, offset + length); michael@0: break; michael@0: case 'loca': michael@0: loca = data.subarray(offset, offset + length); michael@0: break; michael@0: case 'head': michael@0: unitsPerEm = getUshort(data, offset + 18); michael@0: indexToLocFormat = getUshort(data, offset + 50); michael@0: break; michael@0: case 'CFF ': michael@0: cff = parseCff(data, offset, offset + length); michael@0: break; michael@0: } michael@0: } michael@0: michael@0: if (glyf) { michael@0: var fontMatrix = (!unitsPerEm ? font.fontMatrix : michael@0: [1 / unitsPerEm, 0, 0, 1 / unitsPerEm, 0, 0]); michael@0: return new TrueTypeCompiled( michael@0: parseGlyfTable(glyf, loca, indexToLocFormat), cmap, fontMatrix); michael@0: } else { michael@0: return new Type2Compiled(cff, cmap, font.fontMatrix, font.glyphNameMap); michael@0: } michael@0: } michael@0: }; michael@0: })(); michael@0: michael@0: michael@0: michael@0: var GlyphsUnicode = { michael@0: A: 0x0041, michael@0: AE: 0x00C6, michael@0: AEacute: 0x01FC, michael@0: AEmacron: 0x01E2, michael@0: AEsmall: 0xF7E6, michael@0: Aacute: 0x00C1, michael@0: Aacutesmall: 0xF7E1, michael@0: Abreve: 0x0102, michael@0: Abreveacute: 0x1EAE, michael@0: Abrevecyrillic: 0x04D0, michael@0: Abrevedotbelow: 0x1EB6, michael@0: Abrevegrave: 0x1EB0, michael@0: Abrevehookabove: 0x1EB2, michael@0: Abrevetilde: 0x1EB4, michael@0: Acaron: 0x01CD, michael@0: Acircle: 0x24B6, michael@0: Acircumflex: 0x00C2, michael@0: Acircumflexacute: 0x1EA4, michael@0: Acircumflexdotbelow: 0x1EAC, michael@0: Acircumflexgrave: 0x1EA6, michael@0: Acircumflexhookabove: 0x1EA8, michael@0: Acircumflexsmall: 0xF7E2, michael@0: Acircumflextilde: 0x1EAA, michael@0: Acute: 0xF6C9, michael@0: Acutesmall: 0xF7B4, michael@0: Acyrillic: 0x0410, michael@0: Adblgrave: 0x0200, michael@0: Adieresis: 0x00C4, michael@0: Adieresiscyrillic: 0x04D2, michael@0: Adieresismacron: 0x01DE, michael@0: Adieresissmall: 0xF7E4, michael@0: Adotbelow: 0x1EA0, michael@0: Adotmacron: 0x01E0, michael@0: Agrave: 0x00C0, michael@0: Agravesmall: 0xF7E0, michael@0: Ahookabove: 0x1EA2, michael@0: Aiecyrillic: 0x04D4, michael@0: Ainvertedbreve: 0x0202, michael@0: Alpha: 0x0391, michael@0: Alphatonos: 0x0386, michael@0: Amacron: 0x0100, michael@0: Amonospace: 0xFF21, michael@0: Aogonek: 0x0104, michael@0: Aring: 0x00C5, michael@0: Aringacute: 0x01FA, michael@0: Aringbelow: 0x1E00, michael@0: Aringsmall: 0xF7E5, michael@0: Asmall: 0xF761, michael@0: Atilde: 0x00C3, michael@0: Atildesmall: 0xF7E3, michael@0: Aybarmenian: 0x0531, michael@0: B: 0x0042, michael@0: Bcircle: 0x24B7, michael@0: Bdotaccent: 0x1E02, michael@0: Bdotbelow: 0x1E04, michael@0: Becyrillic: 0x0411, michael@0: Benarmenian: 0x0532, michael@0: Beta: 0x0392, michael@0: Bhook: 0x0181, michael@0: Blinebelow: 0x1E06, michael@0: Bmonospace: 0xFF22, michael@0: Brevesmall: 0xF6F4, michael@0: Bsmall: 0xF762, michael@0: Btopbar: 0x0182, michael@0: C: 0x0043, michael@0: Caarmenian: 0x053E, michael@0: Cacute: 0x0106, michael@0: Caron: 0xF6CA, michael@0: Caronsmall: 0xF6F5, michael@0: Ccaron: 0x010C, michael@0: Ccedilla: 0x00C7, michael@0: Ccedillaacute: 0x1E08, michael@0: Ccedillasmall: 0xF7E7, michael@0: Ccircle: 0x24B8, michael@0: Ccircumflex: 0x0108, michael@0: Cdot: 0x010A, michael@0: Cdotaccent: 0x010A, michael@0: Cedillasmall: 0xF7B8, michael@0: Chaarmenian: 0x0549, michael@0: Cheabkhasiancyrillic: 0x04BC, michael@0: Checyrillic: 0x0427, michael@0: Chedescenderabkhasiancyrillic: 0x04BE, michael@0: Chedescendercyrillic: 0x04B6, michael@0: Chedieresiscyrillic: 0x04F4, michael@0: Cheharmenian: 0x0543, michael@0: Chekhakassiancyrillic: 0x04CB, michael@0: Cheverticalstrokecyrillic: 0x04B8, michael@0: Chi: 0x03A7, michael@0: Chook: 0x0187, michael@0: Circumflexsmall: 0xF6F6, michael@0: Cmonospace: 0xFF23, michael@0: Coarmenian: 0x0551, michael@0: Csmall: 0xF763, michael@0: D: 0x0044, michael@0: DZ: 0x01F1, michael@0: DZcaron: 0x01C4, michael@0: Daarmenian: 0x0534, michael@0: Dafrican: 0x0189, michael@0: Dcaron: 0x010E, michael@0: Dcedilla: 0x1E10, michael@0: Dcircle: 0x24B9, michael@0: Dcircumflexbelow: 0x1E12, michael@0: Dcroat: 0x0110, michael@0: Ddotaccent: 0x1E0A, michael@0: Ddotbelow: 0x1E0C, michael@0: Decyrillic: 0x0414, michael@0: Deicoptic: 0x03EE, michael@0: Delta: 0x2206, michael@0: Deltagreek: 0x0394, michael@0: Dhook: 0x018A, michael@0: Dieresis: 0xF6CB, michael@0: DieresisAcute: 0xF6CC, michael@0: DieresisGrave: 0xF6CD, michael@0: Dieresissmall: 0xF7A8, michael@0: Digammagreek: 0x03DC, michael@0: Djecyrillic: 0x0402, michael@0: Dlinebelow: 0x1E0E, michael@0: Dmonospace: 0xFF24, michael@0: Dotaccentsmall: 0xF6F7, michael@0: Dslash: 0x0110, michael@0: Dsmall: 0xF764, michael@0: Dtopbar: 0x018B, michael@0: Dz: 0x01F2, michael@0: Dzcaron: 0x01C5, michael@0: Dzeabkhasiancyrillic: 0x04E0, michael@0: Dzecyrillic: 0x0405, michael@0: Dzhecyrillic: 0x040F, michael@0: E: 0x0045, michael@0: Eacute: 0x00C9, michael@0: Eacutesmall: 0xF7E9, michael@0: Ebreve: 0x0114, michael@0: Ecaron: 0x011A, michael@0: Ecedillabreve: 0x1E1C, michael@0: Echarmenian: 0x0535, michael@0: Ecircle: 0x24BA, michael@0: Ecircumflex: 0x00CA, michael@0: Ecircumflexacute: 0x1EBE, michael@0: Ecircumflexbelow: 0x1E18, michael@0: Ecircumflexdotbelow: 0x1EC6, michael@0: Ecircumflexgrave: 0x1EC0, michael@0: Ecircumflexhookabove: 0x1EC2, michael@0: Ecircumflexsmall: 0xF7EA, michael@0: Ecircumflextilde: 0x1EC4, michael@0: Ecyrillic: 0x0404, michael@0: Edblgrave: 0x0204, michael@0: Edieresis: 0x00CB, michael@0: Edieresissmall: 0xF7EB, michael@0: Edot: 0x0116, michael@0: Edotaccent: 0x0116, michael@0: Edotbelow: 0x1EB8, michael@0: Efcyrillic: 0x0424, michael@0: Egrave: 0x00C8, michael@0: Egravesmall: 0xF7E8, michael@0: Eharmenian: 0x0537, michael@0: Ehookabove: 0x1EBA, michael@0: Eightroman: 0x2167, michael@0: Einvertedbreve: 0x0206, michael@0: Eiotifiedcyrillic: 0x0464, michael@0: Elcyrillic: 0x041B, michael@0: Elevenroman: 0x216A, michael@0: Emacron: 0x0112, michael@0: Emacronacute: 0x1E16, michael@0: Emacrongrave: 0x1E14, michael@0: Emcyrillic: 0x041C, michael@0: Emonospace: 0xFF25, michael@0: Encyrillic: 0x041D, michael@0: Endescendercyrillic: 0x04A2, michael@0: Eng: 0x014A, michael@0: Enghecyrillic: 0x04A4, michael@0: Enhookcyrillic: 0x04C7, michael@0: Eogonek: 0x0118, michael@0: Eopen: 0x0190, michael@0: Epsilon: 0x0395, michael@0: Epsilontonos: 0x0388, michael@0: Ercyrillic: 0x0420, michael@0: Ereversed: 0x018E, michael@0: Ereversedcyrillic: 0x042D, michael@0: Escyrillic: 0x0421, michael@0: Esdescendercyrillic: 0x04AA, michael@0: Esh: 0x01A9, michael@0: Esmall: 0xF765, michael@0: Eta: 0x0397, michael@0: Etarmenian: 0x0538, michael@0: Etatonos: 0x0389, michael@0: Eth: 0x00D0, michael@0: Ethsmall: 0xF7F0, michael@0: Etilde: 0x1EBC, michael@0: Etildebelow: 0x1E1A, michael@0: Euro: 0x20AC, michael@0: Ezh: 0x01B7, michael@0: Ezhcaron: 0x01EE, michael@0: Ezhreversed: 0x01B8, michael@0: F: 0x0046, michael@0: Fcircle: 0x24BB, michael@0: Fdotaccent: 0x1E1E, michael@0: Feharmenian: 0x0556, michael@0: Feicoptic: 0x03E4, michael@0: Fhook: 0x0191, michael@0: Fitacyrillic: 0x0472, michael@0: Fiveroman: 0x2164, michael@0: Fmonospace: 0xFF26, michael@0: Fourroman: 0x2163, michael@0: Fsmall: 0xF766, michael@0: G: 0x0047, michael@0: GBsquare: 0x3387, michael@0: Gacute: 0x01F4, michael@0: Gamma: 0x0393, michael@0: Gammaafrican: 0x0194, michael@0: Gangiacoptic: 0x03EA, michael@0: Gbreve: 0x011E, michael@0: Gcaron: 0x01E6, michael@0: Gcedilla: 0x0122, michael@0: Gcircle: 0x24BC, michael@0: Gcircumflex: 0x011C, michael@0: Gcommaaccent: 0x0122, michael@0: Gdot: 0x0120, michael@0: Gdotaccent: 0x0120, michael@0: Gecyrillic: 0x0413, michael@0: Ghadarmenian: 0x0542, michael@0: Ghemiddlehookcyrillic: 0x0494, michael@0: Ghestrokecyrillic: 0x0492, michael@0: Gheupturncyrillic: 0x0490, michael@0: Ghook: 0x0193, michael@0: Gimarmenian: 0x0533, michael@0: Gjecyrillic: 0x0403, michael@0: Gmacron: 0x1E20, michael@0: Gmonospace: 0xFF27, michael@0: Grave: 0xF6CE, michael@0: Gravesmall: 0xF760, michael@0: Gsmall: 0xF767, michael@0: Gsmallhook: 0x029B, michael@0: Gstroke: 0x01E4, michael@0: H: 0x0048, michael@0: H18533: 0x25CF, michael@0: H18543: 0x25AA, michael@0: H18551: 0x25AB, michael@0: H22073: 0x25A1, michael@0: HPsquare: 0x33CB, michael@0: Haabkhasiancyrillic: 0x04A8, michael@0: Hadescendercyrillic: 0x04B2, michael@0: Hardsigncyrillic: 0x042A, michael@0: Hbar: 0x0126, michael@0: Hbrevebelow: 0x1E2A, michael@0: Hcedilla: 0x1E28, michael@0: Hcircle: 0x24BD, michael@0: Hcircumflex: 0x0124, michael@0: Hdieresis: 0x1E26, michael@0: Hdotaccent: 0x1E22, michael@0: Hdotbelow: 0x1E24, michael@0: Hmonospace: 0xFF28, michael@0: Hoarmenian: 0x0540, michael@0: Horicoptic: 0x03E8, michael@0: Hsmall: 0xF768, michael@0: Hungarumlaut: 0xF6CF, michael@0: Hungarumlautsmall: 0xF6F8, michael@0: Hzsquare: 0x3390, michael@0: I: 0x0049, michael@0: IAcyrillic: 0x042F, michael@0: IJ: 0x0132, michael@0: IUcyrillic: 0x042E, michael@0: Iacute: 0x00CD, michael@0: Iacutesmall: 0xF7ED, michael@0: Ibreve: 0x012C, michael@0: Icaron: 0x01CF, michael@0: Icircle: 0x24BE, michael@0: Icircumflex: 0x00CE, michael@0: Icircumflexsmall: 0xF7EE, michael@0: Icyrillic: 0x0406, michael@0: Idblgrave: 0x0208, michael@0: Idieresis: 0x00CF, michael@0: Idieresisacute: 0x1E2E, michael@0: Idieresiscyrillic: 0x04E4, michael@0: Idieresissmall: 0xF7EF, michael@0: Idot: 0x0130, michael@0: Idotaccent: 0x0130, michael@0: Idotbelow: 0x1ECA, michael@0: Iebrevecyrillic: 0x04D6, michael@0: Iecyrillic: 0x0415, michael@0: Ifraktur: 0x2111, michael@0: Igrave: 0x00CC, michael@0: Igravesmall: 0xF7EC, michael@0: Ihookabove: 0x1EC8, michael@0: Iicyrillic: 0x0418, michael@0: Iinvertedbreve: 0x020A, michael@0: Iishortcyrillic: 0x0419, michael@0: Imacron: 0x012A, michael@0: Imacroncyrillic: 0x04E2, michael@0: Imonospace: 0xFF29, michael@0: Iniarmenian: 0x053B, michael@0: Iocyrillic: 0x0401, michael@0: Iogonek: 0x012E, michael@0: Iota: 0x0399, michael@0: Iotaafrican: 0x0196, michael@0: Iotadieresis: 0x03AA, michael@0: Iotatonos: 0x038A, michael@0: Ismall: 0xF769, michael@0: Istroke: 0x0197, michael@0: Itilde: 0x0128, michael@0: Itildebelow: 0x1E2C, michael@0: Izhitsacyrillic: 0x0474, michael@0: Izhitsadblgravecyrillic: 0x0476, michael@0: J: 0x004A, michael@0: Jaarmenian: 0x0541, michael@0: Jcircle: 0x24BF, michael@0: Jcircumflex: 0x0134, michael@0: Jecyrillic: 0x0408, michael@0: Jheharmenian: 0x054B, michael@0: Jmonospace: 0xFF2A, michael@0: Jsmall: 0xF76A, michael@0: K: 0x004B, michael@0: KBsquare: 0x3385, michael@0: KKsquare: 0x33CD, michael@0: Kabashkircyrillic: 0x04A0, michael@0: Kacute: 0x1E30, michael@0: Kacyrillic: 0x041A, michael@0: Kadescendercyrillic: 0x049A, michael@0: Kahookcyrillic: 0x04C3, michael@0: Kappa: 0x039A, michael@0: Kastrokecyrillic: 0x049E, michael@0: Kaverticalstrokecyrillic: 0x049C, michael@0: Kcaron: 0x01E8, michael@0: Kcedilla: 0x0136, michael@0: Kcircle: 0x24C0, michael@0: Kcommaaccent: 0x0136, michael@0: Kdotbelow: 0x1E32, michael@0: Keharmenian: 0x0554, michael@0: Kenarmenian: 0x053F, michael@0: Khacyrillic: 0x0425, michael@0: Kheicoptic: 0x03E6, michael@0: Khook: 0x0198, michael@0: Kjecyrillic: 0x040C, michael@0: Klinebelow: 0x1E34, michael@0: Kmonospace: 0xFF2B, michael@0: Koppacyrillic: 0x0480, michael@0: Koppagreek: 0x03DE, michael@0: Ksicyrillic: 0x046E, michael@0: Ksmall: 0xF76B, michael@0: L: 0x004C, michael@0: LJ: 0x01C7, michael@0: LL: 0xF6BF, michael@0: Lacute: 0x0139, michael@0: Lambda: 0x039B, michael@0: Lcaron: 0x013D, michael@0: Lcedilla: 0x013B, michael@0: Lcircle: 0x24C1, michael@0: Lcircumflexbelow: 0x1E3C, michael@0: Lcommaaccent: 0x013B, michael@0: Ldot: 0x013F, michael@0: Ldotaccent: 0x013F, michael@0: Ldotbelow: 0x1E36, michael@0: Ldotbelowmacron: 0x1E38, michael@0: Liwnarmenian: 0x053C, michael@0: Lj: 0x01C8, michael@0: Ljecyrillic: 0x0409, michael@0: Llinebelow: 0x1E3A, michael@0: Lmonospace: 0xFF2C, michael@0: Lslash: 0x0141, michael@0: Lslashsmall: 0xF6F9, michael@0: Lsmall: 0xF76C, michael@0: M: 0x004D, michael@0: MBsquare: 0x3386, michael@0: Macron: 0xF6D0, michael@0: Macronsmall: 0xF7AF, michael@0: Macute: 0x1E3E, michael@0: Mcircle: 0x24C2, michael@0: Mdotaccent: 0x1E40, michael@0: Mdotbelow: 0x1E42, michael@0: Menarmenian: 0x0544, michael@0: Mmonospace: 0xFF2D, michael@0: Msmall: 0xF76D, michael@0: Mturned: 0x019C, michael@0: Mu: 0x039C, michael@0: N: 0x004E, michael@0: NJ: 0x01CA, michael@0: Nacute: 0x0143, michael@0: Ncaron: 0x0147, michael@0: Ncedilla: 0x0145, michael@0: Ncircle: 0x24C3, michael@0: Ncircumflexbelow: 0x1E4A, michael@0: Ncommaaccent: 0x0145, michael@0: Ndotaccent: 0x1E44, michael@0: Ndotbelow: 0x1E46, michael@0: Nhookleft: 0x019D, michael@0: Nineroman: 0x2168, michael@0: Nj: 0x01CB, michael@0: Njecyrillic: 0x040A, michael@0: Nlinebelow: 0x1E48, michael@0: Nmonospace: 0xFF2E, michael@0: Nowarmenian: 0x0546, michael@0: Nsmall: 0xF76E, michael@0: Ntilde: 0x00D1, michael@0: Ntildesmall: 0xF7F1, michael@0: Nu: 0x039D, michael@0: O: 0x004F, michael@0: OE: 0x0152, michael@0: OEsmall: 0xF6FA, michael@0: Oacute: 0x00D3, michael@0: Oacutesmall: 0xF7F3, michael@0: Obarredcyrillic: 0x04E8, michael@0: Obarreddieresiscyrillic: 0x04EA, michael@0: Obreve: 0x014E, michael@0: Ocaron: 0x01D1, michael@0: Ocenteredtilde: 0x019F, michael@0: Ocircle: 0x24C4, michael@0: Ocircumflex: 0x00D4, michael@0: Ocircumflexacute: 0x1ED0, michael@0: Ocircumflexdotbelow: 0x1ED8, michael@0: Ocircumflexgrave: 0x1ED2, michael@0: Ocircumflexhookabove: 0x1ED4, michael@0: Ocircumflexsmall: 0xF7F4, michael@0: Ocircumflextilde: 0x1ED6, michael@0: Ocyrillic: 0x041E, michael@0: Odblacute: 0x0150, michael@0: Odblgrave: 0x020C, michael@0: Odieresis: 0x00D6, michael@0: Odieresiscyrillic: 0x04E6, michael@0: Odieresissmall: 0xF7F6, michael@0: Odotbelow: 0x1ECC, michael@0: Ogoneksmall: 0xF6FB, michael@0: Ograve: 0x00D2, michael@0: Ogravesmall: 0xF7F2, michael@0: Oharmenian: 0x0555, michael@0: Ohm: 0x2126, michael@0: Ohookabove: 0x1ECE, michael@0: Ohorn: 0x01A0, michael@0: Ohornacute: 0x1EDA, michael@0: Ohorndotbelow: 0x1EE2, michael@0: Ohorngrave: 0x1EDC, michael@0: Ohornhookabove: 0x1EDE, michael@0: Ohorntilde: 0x1EE0, michael@0: Ohungarumlaut: 0x0150, michael@0: Oi: 0x01A2, michael@0: Oinvertedbreve: 0x020E, michael@0: Omacron: 0x014C, michael@0: Omacronacute: 0x1E52, michael@0: Omacrongrave: 0x1E50, michael@0: Omega: 0x2126, michael@0: Omegacyrillic: 0x0460, michael@0: Omegagreek: 0x03A9, michael@0: Omegaroundcyrillic: 0x047A, michael@0: Omegatitlocyrillic: 0x047C, michael@0: Omegatonos: 0x038F, michael@0: Omicron: 0x039F, michael@0: Omicrontonos: 0x038C, michael@0: Omonospace: 0xFF2F, michael@0: Oneroman: 0x2160, michael@0: Oogonek: 0x01EA, michael@0: Oogonekmacron: 0x01EC, michael@0: Oopen: 0x0186, michael@0: Oslash: 0x00D8, michael@0: Oslashacute: 0x01FE, michael@0: Oslashsmall: 0xF7F8, michael@0: Osmall: 0xF76F, michael@0: Ostrokeacute: 0x01FE, michael@0: Otcyrillic: 0x047E, michael@0: Otilde: 0x00D5, michael@0: Otildeacute: 0x1E4C, michael@0: Otildedieresis: 0x1E4E, michael@0: Otildesmall: 0xF7F5, michael@0: P: 0x0050, michael@0: Pacute: 0x1E54, michael@0: Pcircle: 0x24C5, michael@0: Pdotaccent: 0x1E56, michael@0: Pecyrillic: 0x041F, michael@0: Peharmenian: 0x054A, michael@0: Pemiddlehookcyrillic: 0x04A6, michael@0: Phi: 0x03A6, michael@0: Phook: 0x01A4, michael@0: Pi: 0x03A0, michael@0: Piwrarmenian: 0x0553, michael@0: Pmonospace: 0xFF30, michael@0: Psi: 0x03A8, michael@0: Psicyrillic: 0x0470, michael@0: Psmall: 0xF770, michael@0: Q: 0x0051, michael@0: Qcircle: 0x24C6, michael@0: Qmonospace: 0xFF31, michael@0: Qsmall: 0xF771, michael@0: R: 0x0052, michael@0: Raarmenian: 0x054C, michael@0: Racute: 0x0154, michael@0: Rcaron: 0x0158, michael@0: Rcedilla: 0x0156, michael@0: Rcircle: 0x24C7, michael@0: Rcommaaccent: 0x0156, michael@0: Rdblgrave: 0x0210, michael@0: Rdotaccent: 0x1E58, michael@0: Rdotbelow: 0x1E5A, michael@0: Rdotbelowmacron: 0x1E5C, michael@0: Reharmenian: 0x0550, michael@0: Rfraktur: 0x211C, michael@0: Rho: 0x03A1, michael@0: Ringsmall: 0xF6FC, michael@0: Rinvertedbreve: 0x0212, michael@0: Rlinebelow: 0x1E5E, michael@0: Rmonospace: 0xFF32, michael@0: Rsmall: 0xF772, michael@0: Rsmallinverted: 0x0281, michael@0: Rsmallinvertedsuperior: 0x02B6, michael@0: S: 0x0053, michael@0: SF010000: 0x250C, michael@0: SF020000: 0x2514, michael@0: SF030000: 0x2510, michael@0: SF040000: 0x2518, michael@0: SF050000: 0x253C, michael@0: SF060000: 0x252C, michael@0: SF070000: 0x2534, michael@0: SF080000: 0x251C, michael@0: SF090000: 0x2524, michael@0: SF100000: 0x2500, michael@0: SF110000: 0x2502, michael@0: SF190000: 0x2561, michael@0: SF200000: 0x2562, michael@0: SF210000: 0x2556, michael@0: SF220000: 0x2555, michael@0: SF230000: 0x2563, michael@0: SF240000: 0x2551, michael@0: SF250000: 0x2557, michael@0: SF260000: 0x255D, michael@0: SF270000: 0x255C, michael@0: SF280000: 0x255B, michael@0: SF360000: 0x255E, michael@0: SF370000: 0x255F, michael@0: SF380000: 0x255A, michael@0: SF390000: 0x2554, michael@0: SF400000: 0x2569, michael@0: SF410000: 0x2566, michael@0: SF420000: 0x2560, michael@0: SF430000: 0x2550, michael@0: SF440000: 0x256C, michael@0: SF450000: 0x2567, michael@0: SF460000: 0x2568, michael@0: SF470000: 0x2564, michael@0: SF480000: 0x2565, michael@0: SF490000: 0x2559, michael@0: SF500000: 0x2558, michael@0: SF510000: 0x2552, michael@0: SF520000: 0x2553, michael@0: SF530000: 0x256B, michael@0: SF540000: 0x256A, michael@0: Sacute: 0x015A, michael@0: Sacutedotaccent: 0x1E64, michael@0: Sampigreek: 0x03E0, michael@0: Scaron: 0x0160, michael@0: Scarondotaccent: 0x1E66, michael@0: Scaronsmall: 0xF6FD, michael@0: Scedilla: 0x015E, michael@0: Schwa: 0x018F, michael@0: Schwacyrillic: 0x04D8, michael@0: Schwadieresiscyrillic: 0x04DA, michael@0: Scircle: 0x24C8, michael@0: Scircumflex: 0x015C, michael@0: Scommaaccent: 0x0218, michael@0: Sdotaccent: 0x1E60, michael@0: Sdotbelow: 0x1E62, michael@0: Sdotbelowdotaccent: 0x1E68, michael@0: Seharmenian: 0x054D, michael@0: Sevenroman: 0x2166, michael@0: Shaarmenian: 0x0547, michael@0: Shacyrillic: 0x0428, michael@0: Shchacyrillic: 0x0429, michael@0: Sheicoptic: 0x03E2, michael@0: Shhacyrillic: 0x04BA, michael@0: Shimacoptic: 0x03EC, michael@0: Sigma: 0x03A3, michael@0: Sixroman: 0x2165, michael@0: Smonospace: 0xFF33, michael@0: Softsigncyrillic: 0x042C, michael@0: Ssmall: 0xF773, michael@0: Stigmagreek: 0x03DA, michael@0: T: 0x0054, michael@0: Tau: 0x03A4, michael@0: Tbar: 0x0166, michael@0: Tcaron: 0x0164, michael@0: Tcedilla: 0x0162, michael@0: Tcircle: 0x24C9, michael@0: Tcircumflexbelow: 0x1E70, michael@0: Tcommaaccent: 0x0162, michael@0: Tdotaccent: 0x1E6A, michael@0: Tdotbelow: 0x1E6C, michael@0: Tecyrillic: 0x0422, michael@0: Tedescendercyrillic: 0x04AC, michael@0: Tenroman: 0x2169, michael@0: Tetsecyrillic: 0x04B4, michael@0: Theta: 0x0398, michael@0: Thook: 0x01AC, michael@0: Thorn: 0x00DE, michael@0: Thornsmall: 0xF7FE, michael@0: Threeroman: 0x2162, michael@0: Tildesmall: 0xF6FE, michael@0: Tiwnarmenian: 0x054F, michael@0: Tlinebelow: 0x1E6E, michael@0: Tmonospace: 0xFF34, michael@0: Toarmenian: 0x0539, michael@0: Tonefive: 0x01BC, michael@0: Tonesix: 0x0184, michael@0: Tonetwo: 0x01A7, michael@0: Tretroflexhook: 0x01AE, michael@0: Tsecyrillic: 0x0426, michael@0: Tshecyrillic: 0x040B, michael@0: Tsmall: 0xF774, michael@0: Twelveroman: 0x216B, michael@0: Tworoman: 0x2161, michael@0: U: 0x0055, michael@0: Uacute: 0x00DA, michael@0: Uacutesmall: 0xF7FA, michael@0: Ubreve: 0x016C, michael@0: Ucaron: 0x01D3, michael@0: Ucircle: 0x24CA, michael@0: Ucircumflex: 0x00DB, michael@0: Ucircumflexbelow: 0x1E76, michael@0: Ucircumflexsmall: 0xF7FB, michael@0: Ucyrillic: 0x0423, michael@0: Udblacute: 0x0170, michael@0: Udblgrave: 0x0214, michael@0: Udieresis: 0x00DC, michael@0: Udieresisacute: 0x01D7, michael@0: Udieresisbelow: 0x1E72, michael@0: Udieresiscaron: 0x01D9, michael@0: Udieresiscyrillic: 0x04F0, michael@0: Udieresisgrave: 0x01DB, michael@0: Udieresismacron: 0x01D5, michael@0: Udieresissmall: 0xF7FC, michael@0: Udotbelow: 0x1EE4, michael@0: Ugrave: 0x00D9, michael@0: Ugravesmall: 0xF7F9, michael@0: Uhookabove: 0x1EE6, michael@0: Uhorn: 0x01AF, michael@0: Uhornacute: 0x1EE8, michael@0: Uhorndotbelow: 0x1EF0, michael@0: Uhorngrave: 0x1EEA, michael@0: Uhornhookabove: 0x1EEC, michael@0: Uhorntilde: 0x1EEE, michael@0: Uhungarumlaut: 0x0170, michael@0: Uhungarumlautcyrillic: 0x04F2, michael@0: Uinvertedbreve: 0x0216, michael@0: Ukcyrillic: 0x0478, michael@0: Umacron: 0x016A, michael@0: Umacroncyrillic: 0x04EE, michael@0: Umacrondieresis: 0x1E7A, michael@0: Umonospace: 0xFF35, michael@0: Uogonek: 0x0172, michael@0: Upsilon: 0x03A5, michael@0: Upsilon1: 0x03D2, michael@0: Upsilonacutehooksymbolgreek: 0x03D3, michael@0: Upsilonafrican: 0x01B1, michael@0: Upsilondieresis: 0x03AB, michael@0: Upsilondieresishooksymbolgreek: 0x03D4, michael@0: Upsilonhooksymbol: 0x03D2, michael@0: Upsilontonos: 0x038E, michael@0: Uring: 0x016E, michael@0: Ushortcyrillic: 0x040E, michael@0: Usmall: 0xF775, michael@0: Ustraightcyrillic: 0x04AE, michael@0: Ustraightstrokecyrillic: 0x04B0, michael@0: Utilde: 0x0168, michael@0: Utildeacute: 0x1E78, michael@0: Utildebelow: 0x1E74, michael@0: V: 0x0056, michael@0: Vcircle: 0x24CB, michael@0: Vdotbelow: 0x1E7E, michael@0: Vecyrillic: 0x0412, michael@0: Vewarmenian: 0x054E, michael@0: Vhook: 0x01B2, michael@0: Vmonospace: 0xFF36, michael@0: Voarmenian: 0x0548, michael@0: Vsmall: 0xF776, michael@0: Vtilde: 0x1E7C, michael@0: W: 0x0057, michael@0: Wacute: 0x1E82, michael@0: Wcircle: 0x24CC, michael@0: Wcircumflex: 0x0174, michael@0: Wdieresis: 0x1E84, michael@0: Wdotaccent: 0x1E86, michael@0: Wdotbelow: 0x1E88, michael@0: Wgrave: 0x1E80, michael@0: Wmonospace: 0xFF37, michael@0: Wsmall: 0xF777, michael@0: X: 0x0058, michael@0: Xcircle: 0x24CD, michael@0: Xdieresis: 0x1E8C, michael@0: Xdotaccent: 0x1E8A, michael@0: Xeharmenian: 0x053D, michael@0: Xi: 0x039E, michael@0: Xmonospace: 0xFF38, michael@0: Xsmall: 0xF778, michael@0: Y: 0x0059, michael@0: Yacute: 0x00DD, michael@0: Yacutesmall: 0xF7FD, michael@0: Yatcyrillic: 0x0462, michael@0: Ycircle: 0x24CE, michael@0: Ycircumflex: 0x0176, michael@0: Ydieresis: 0x0178, michael@0: Ydieresissmall: 0xF7FF, michael@0: Ydotaccent: 0x1E8E, michael@0: Ydotbelow: 0x1EF4, michael@0: Yericyrillic: 0x042B, michael@0: Yerudieresiscyrillic: 0x04F8, michael@0: Ygrave: 0x1EF2, michael@0: Yhook: 0x01B3, michael@0: Yhookabove: 0x1EF6, michael@0: Yiarmenian: 0x0545, michael@0: Yicyrillic: 0x0407, michael@0: Yiwnarmenian: 0x0552, michael@0: Ymonospace: 0xFF39, michael@0: Ysmall: 0xF779, michael@0: Ytilde: 0x1EF8, michael@0: Yusbigcyrillic: 0x046A, michael@0: Yusbigiotifiedcyrillic: 0x046C, michael@0: Yuslittlecyrillic: 0x0466, michael@0: Yuslittleiotifiedcyrillic: 0x0468, michael@0: Z: 0x005A, michael@0: Zaarmenian: 0x0536, michael@0: Zacute: 0x0179, michael@0: Zcaron: 0x017D, michael@0: Zcaronsmall: 0xF6FF, michael@0: Zcircle: 0x24CF, michael@0: Zcircumflex: 0x1E90, michael@0: Zdot: 0x017B, michael@0: Zdotaccent: 0x017B, michael@0: Zdotbelow: 0x1E92, michael@0: Zecyrillic: 0x0417, michael@0: Zedescendercyrillic: 0x0498, michael@0: Zedieresiscyrillic: 0x04DE, michael@0: Zeta: 0x0396, michael@0: Zhearmenian: 0x053A, michael@0: Zhebrevecyrillic: 0x04C1, michael@0: Zhecyrillic: 0x0416, michael@0: Zhedescendercyrillic: 0x0496, michael@0: Zhedieresiscyrillic: 0x04DC, michael@0: Zlinebelow: 0x1E94, michael@0: Zmonospace: 0xFF3A, michael@0: Zsmall: 0xF77A, michael@0: Zstroke: 0x01B5, michael@0: a: 0x0061, michael@0: aabengali: 0x0986, michael@0: aacute: 0x00E1, michael@0: aadeva: 0x0906, michael@0: aagujarati: 0x0A86, michael@0: aagurmukhi: 0x0A06, michael@0: aamatragurmukhi: 0x0A3E, michael@0: aarusquare: 0x3303, michael@0: aavowelsignbengali: 0x09BE, michael@0: aavowelsigndeva: 0x093E, michael@0: aavowelsigngujarati: 0x0ABE, michael@0: abbreviationmarkarmenian: 0x055F, michael@0: abbreviationsigndeva: 0x0970, michael@0: abengali: 0x0985, michael@0: abopomofo: 0x311A, michael@0: abreve: 0x0103, michael@0: abreveacute: 0x1EAF, michael@0: abrevecyrillic: 0x04D1, michael@0: abrevedotbelow: 0x1EB7, michael@0: abrevegrave: 0x1EB1, michael@0: abrevehookabove: 0x1EB3, michael@0: abrevetilde: 0x1EB5, michael@0: acaron: 0x01CE, michael@0: acircle: 0x24D0, michael@0: acircumflex: 0x00E2, michael@0: acircumflexacute: 0x1EA5, michael@0: acircumflexdotbelow: 0x1EAD, michael@0: acircumflexgrave: 0x1EA7, michael@0: acircumflexhookabove: 0x1EA9, michael@0: acircumflextilde: 0x1EAB, michael@0: acute: 0x00B4, michael@0: acutebelowcmb: 0x0317, michael@0: acutecmb: 0x0301, michael@0: acutecomb: 0x0301, michael@0: acutedeva: 0x0954, michael@0: acutelowmod: 0x02CF, michael@0: acutetonecmb: 0x0341, michael@0: acyrillic: 0x0430, michael@0: adblgrave: 0x0201, michael@0: addakgurmukhi: 0x0A71, michael@0: adeva: 0x0905, michael@0: adieresis: 0x00E4, michael@0: adieresiscyrillic: 0x04D3, michael@0: adieresismacron: 0x01DF, michael@0: adotbelow: 0x1EA1, michael@0: adotmacron: 0x01E1, michael@0: ae: 0x00E6, michael@0: aeacute: 0x01FD, michael@0: aekorean: 0x3150, michael@0: aemacron: 0x01E3, michael@0: afii00208: 0x2015, michael@0: afii08941: 0x20A4, michael@0: afii10017: 0x0410, michael@0: afii10018: 0x0411, michael@0: afii10019: 0x0412, michael@0: afii10020: 0x0413, michael@0: afii10021: 0x0414, michael@0: afii10022: 0x0415, michael@0: afii10023: 0x0401, michael@0: afii10024: 0x0416, michael@0: afii10025: 0x0417, michael@0: afii10026: 0x0418, michael@0: afii10027: 0x0419, michael@0: afii10028: 0x041A, michael@0: afii10029: 0x041B, michael@0: afii10030: 0x041C, michael@0: afii10031: 0x041D, michael@0: afii10032: 0x041E, michael@0: afii10033: 0x041F, michael@0: afii10034: 0x0420, michael@0: afii10035: 0x0421, michael@0: afii10036: 0x0422, michael@0: afii10037: 0x0423, michael@0: afii10038: 0x0424, michael@0: afii10039: 0x0425, michael@0: afii10040: 0x0426, michael@0: afii10041: 0x0427, michael@0: afii10042: 0x0428, michael@0: afii10043: 0x0429, michael@0: afii10044: 0x042A, michael@0: afii10045: 0x042B, michael@0: afii10046: 0x042C, michael@0: afii10047: 0x042D, michael@0: afii10048: 0x042E, michael@0: afii10049: 0x042F, michael@0: afii10050: 0x0490, michael@0: afii10051: 0x0402, michael@0: afii10052: 0x0403, michael@0: afii10053: 0x0404, michael@0: afii10054: 0x0405, michael@0: afii10055: 0x0406, michael@0: afii10056: 0x0407, michael@0: afii10057: 0x0408, michael@0: afii10058: 0x0409, michael@0: afii10059: 0x040A, michael@0: afii10060: 0x040B, michael@0: afii10061: 0x040C, michael@0: afii10062: 0x040E, michael@0: afii10063: 0xF6C4, michael@0: afii10064: 0xF6C5, michael@0: afii10065: 0x0430, michael@0: afii10066: 0x0431, michael@0: afii10067: 0x0432, michael@0: afii10068: 0x0433, michael@0: afii10069: 0x0434, michael@0: afii10070: 0x0435, michael@0: afii10071: 0x0451, michael@0: afii10072: 0x0436, michael@0: afii10073: 0x0437, michael@0: afii10074: 0x0438, michael@0: afii10075: 0x0439, michael@0: afii10076: 0x043A, michael@0: afii10077: 0x043B, michael@0: afii10078: 0x043C, michael@0: afii10079: 0x043D, michael@0: afii10080: 0x043E, michael@0: afii10081: 0x043F, michael@0: afii10082: 0x0440, michael@0: afii10083: 0x0441, michael@0: afii10084: 0x0442, michael@0: afii10085: 0x0443, michael@0: afii10086: 0x0444, michael@0: afii10087: 0x0445, michael@0: afii10088: 0x0446, michael@0: afii10089: 0x0447, michael@0: afii10090: 0x0448, michael@0: afii10091: 0x0449, michael@0: afii10092: 0x044A, michael@0: afii10093: 0x044B, michael@0: afii10094: 0x044C, michael@0: afii10095: 0x044D, michael@0: afii10096: 0x044E, michael@0: afii10097: 0x044F, michael@0: afii10098: 0x0491, michael@0: afii10099: 0x0452, michael@0: afii10100: 0x0453, michael@0: afii10101: 0x0454, michael@0: afii10102: 0x0455, michael@0: afii10103: 0x0456, michael@0: afii10104: 0x0457, michael@0: afii10105: 0x0458, michael@0: afii10106: 0x0459, michael@0: afii10107: 0x045A, michael@0: afii10108: 0x045B, michael@0: afii10109: 0x045C, michael@0: afii10110: 0x045E, michael@0: afii10145: 0x040F, michael@0: afii10146: 0x0462, michael@0: afii10147: 0x0472, michael@0: afii10148: 0x0474, michael@0: afii10192: 0xF6C6, michael@0: afii10193: 0x045F, michael@0: afii10194: 0x0463, michael@0: afii10195: 0x0473, michael@0: afii10196: 0x0475, michael@0: afii10831: 0xF6C7, michael@0: afii10832: 0xF6C8, michael@0: afii10846: 0x04D9, michael@0: afii299: 0x200E, michael@0: afii300: 0x200F, michael@0: afii301: 0x200D, michael@0: afii57381: 0x066A, michael@0: afii57388: 0x060C, michael@0: afii57392: 0x0660, michael@0: afii57393: 0x0661, michael@0: afii57394: 0x0662, michael@0: afii57395: 0x0663, michael@0: afii57396: 0x0664, michael@0: afii57397: 0x0665, michael@0: afii57398: 0x0666, michael@0: afii57399: 0x0667, michael@0: afii57400: 0x0668, michael@0: afii57401: 0x0669, michael@0: afii57403: 0x061B, michael@0: afii57407: 0x061F, michael@0: afii57409: 0x0621, michael@0: afii57410: 0x0622, michael@0: afii57411: 0x0623, michael@0: afii57412: 0x0624, michael@0: afii57413: 0x0625, michael@0: afii57414: 0x0626, michael@0: afii57415: 0x0627, michael@0: afii57416: 0x0628, michael@0: afii57417: 0x0629, michael@0: afii57418: 0x062A, michael@0: afii57419: 0x062B, michael@0: afii57420: 0x062C, michael@0: afii57421: 0x062D, michael@0: afii57422: 0x062E, michael@0: afii57423: 0x062F, michael@0: afii57424: 0x0630, michael@0: afii57425: 0x0631, michael@0: afii57426: 0x0632, michael@0: afii57427: 0x0633, michael@0: afii57428: 0x0634, michael@0: afii57429: 0x0635, michael@0: afii57430: 0x0636, michael@0: afii57431: 0x0637, michael@0: afii57432: 0x0638, michael@0: afii57433: 0x0639, michael@0: afii57434: 0x063A, michael@0: afii57440: 0x0640, michael@0: afii57441: 0x0641, michael@0: afii57442: 0x0642, michael@0: afii57443: 0x0643, michael@0: afii57444: 0x0644, michael@0: afii57445: 0x0645, michael@0: afii57446: 0x0646, michael@0: afii57448: 0x0648, michael@0: afii57449: 0x0649, michael@0: afii57450: 0x064A, michael@0: afii57451: 0x064B, michael@0: afii57452: 0x064C, michael@0: afii57453: 0x064D, michael@0: afii57454: 0x064E, michael@0: afii57455: 0x064F, michael@0: afii57456: 0x0650, michael@0: afii57457: 0x0651, michael@0: afii57458: 0x0652, michael@0: afii57470: 0x0647, michael@0: afii57505: 0x06A4, michael@0: afii57506: 0x067E, michael@0: afii57507: 0x0686, michael@0: afii57508: 0x0698, michael@0: afii57509: 0x06AF, michael@0: afii57511: 0x0679, michael@0: afii57512: 0x0688, michael@0: afii57513: 0x0691, michael@0: afii57514: 0x06BA, michael@0: afii57519: 0x06D2, michael@0: afii57534: 0x06D5, michael@0: afii57636: 0x20AA, michael@0: afii57645: 0x05BE, michael@0: afii57658: 0x05C3, michael@0: afii57664: 0x05D0, michael@0: afii57665: 0x05D1, michael@0: afii57666: 0x05D2, michael@0: afii57667: 0x05D3, michael@0: afii57668: 0x05D4, michael@0: afii57669: 0x05D5, michael@0: afii57670: 0x05D6, michael@0: afii57671: 0x05D7, michael@0: afii57672: 0x05D8, michael@0: afii57673: 0x05D9, michael@0: afii57674: 0x05DA, michael@0: afii57675: 0x05DB, michael@0: afii57676: 0x05DC, michael@0: afii57677: 0x05DD, michael@0: afii57678: 0x05DE, michael@0: afii57679: 0x05DF, michael@0: afii57680: 0x05E0, michael@0: afii57681: 0x05E1, michael@0: afii57682: 0x05E2, michael@0: afii57683: 0x05E3, michael@0: afii57684: 0x05E4, michael@0: afii57685: 0x05E5, michael@0: afii57686: 0x05E6, michael@0: afii57687: 0x05E7, michael@0: afii57688: 0x05E8, michael@0: afii57689: 0x05E9, michael@0: afii57690: 0x05EA, michael@0: afii57694: 0xFB2A, michael@0: afii57695: 0xFB2B, michael@0: afii57700: 0xFB4B, michael@0: afii57705: 0xFB1F, michael@0: afii57716: 0x05F0, michael@0: afii57717: 0x05F1, michael@0: afii57718: 0x05F2, michael@0: afii57723: 0xFB35, michael@0: afii57793: 0x05B4, michael@0: afii57794: 0x05B5, michael@0: afii57795: 0x05B6, michael@0: afii57796: 0x05BB, michael@0: afii57797: 0x05B8, michael@0: afii57798: 0x05B7, michael@0: afii57799: 0x05B0, michael@0: afii57800: 0x05B2, michael@0: afii57801: 0x05B1, michael@0: afii57802: 0x05B3, michael@0: afii57803: 0x05C2, michael@0: afii57804: 0x05C1, michael@0: afii57806: 0x05B9, michael@0: afii57807: 0x05BC, michael@0: afii57839: 0x05BD, michael@0: afii57841: 0x05BF, michael@0: afii57842: 0x05C0, michael@0: afii57929: 0x02BC, michael@0: afii61248: 0x2105, michael@0: afii61289: 0x2113, michael@0: afii61352: 0x2116, michael@0: afii61573: 0x202C, michael@0: afii61574: 0x202D, michael@0: afii61575: 0x202E, michael@0: afii61664: 0x200C, michael@0: afii63167: 0x066D, michael@0: afii64937: 0x02BD, michael@0: agrave: 0x00E0, michael@0: agujarati: 0x0A85, michael@0: agurmukhi: 0x0A05, michael@0: ahiragana: 0x3042, michael@0: ahookabove: 0x1EA3, michael@0: aibengali: 0x0990, michael@0: aibopomofo: 0x311E, michael@0: aideva: 0x0910, michael@0: aiecyrillic: 0x04D5, michael@0: aigujarati: 0x0A90, michael@0: aigurmukhi: 0x0A10, michael@0: aimatragurmukhi: 0x0A48, michael@0: ainarabic: 0x0639, michael@0: ainfinalarabic: 0xFECA, michael@0: aininitialarabic: 0xFECB, michael@0: ainmedialarabic: 0xFECC, michael@0: ainvertedbreve: 0x0203, michael@0: aivowelsignbengali: 0x09C8, michael@0: aivowelsigndeva: 0x0948, michael@0: aivowelsigngujarati: 0x0AC8, michael@0: akatakana: 0x30A2, michael@0: akatakanahalfwidth: 0xFF71, michael@0: akorean: 0x314F, michael@0: alef: 0x05D0, michael@0: alefarabic: 0x0627, michael@0: alefdageshhebrew: 0xFB30, michael@0: aleffinalarabic: 0xFE8E, michael@0: alefhamzaabovearabic: 0x0623, michael@0: alefhamzaabovefinalarabic: 0xFE84, michael@0: alefhamzabelowarabic: 0x0625, michael@0: alefhamzabelowfinalarabic: 0xFE88, michael@0: alefhebrew: 0x05D0, michael@0: aleflamedhebrew: 0xFB4F, michael@0: alefmaddaabovearabic: 0x0622, michael@0: alefmaddaabovefinalarabic: 0xFE82, michael@0: alefmaksuraarabic: 0x0649, michael@0: alefmaksurafinalarabic: 0xFEF0, michael@0: alefmaksurainitialarabic: 0xFEF3, michael@0: alefmaksuramedialarabic: 0xFEF4, michael@0: alefpatahhebrew: 0xFB2E, michael@0: alefqamatshebrew: 0xFB2F, michael@0: aleph: 0x2135, michael@0: allequal: 0x224C, michael@0: alpha: 0x03B1, michael@0: alphatonos: 0x03AC, michael@0: amacron: 0x0101, michael@0: amonospace: 0xFF41, michael@0: ampersand: 0x0026, michael@0: ampersandmonospace: 0xFF06, michael@0: ampersandsmall: 0xF726, michael@0: amsquare: 0x33C2, michael@0: anbopomofo: 0x3122, michael@0: angbopomofo: 0x3124, michael@0: angbracketleft: 0x3008, // This glyph is missing from Adobe's original list. michael@0: angbracketright: 0x3009, // This glyph is missing from Adobe's original list. michael@0: angkhankhuthai: 0x0E5A, michael@0: angle: 0x2220, michael@0: anglebracketleft: 0x3008, michael@0: anglebracketleftvertical: 0xFE3F, michael@0: anglebracketright: 0x3009, michael@0: anglebracketrightvertical: 0xFE40, michael@0: angleleft: 0x2329, michael@0: angleright: 0x232A, michael@0: angstrom: 0x212B, michael@0: anoteleia: 0x0387, michael@0: anudattadeva: 0x0952, michael@0: anusvarabengali: 0x0982, michael@0: anusvaradeva: 0x0902, michael@0: anusvaragujarati: 0x0A82, michael@0: aogonek: 0x0105, michael@0: apaatosquare: 0x3300, michael@0: aparen: 0x249C, michael@0: apostrophearmenian: 0x055A, michael@0: apostrophemod: 0x02BC, michael@0: apple: 0xF8FF, michael@0: approaches: 0x2250, michael@0: approxequal: 0x2248, michael@0: approxequalorimage: 0x2252, michael@0: approximatelyequal: 0x2245, michael@0: araeaekorean: 0x318E, michael@0: araeakorean: 0x318D, michael@0: arc: 0x2312, michael@0: arighthalfring: 0x1E9A, michael@0: aring: 0x00E5, michael@0: aringacute: 0x01FB, michael@0: aringbelow: 0x1E01, michael@0: arrowboth: 0x2194, michael@0: arrowdashdown: 0x21E3, michael@0: arrowdashleft: 0x21E0, michael@0: arrowdashright: 0x21E2, michael@0: arrowdashup: 0x21E1, michael@0: arrowdblboth: 0x21D4, michael@0: arrowdbldown: 0x21D3, michael@0: arrowdblleft: 0x21D0, michael@0: arrowdblright: 0x21D2, michael@0: arrowdblup: 0x21D1, michael@0: arrowdown: 0x2193, michael@0: arrowdownleft: 0x2199, michael@0: arrowdownright: 0x2198, michael@0: arrowdownwhite: 0x21E9, michael@0: arrowheaddownmod: 0x02C5, michael@0: arrowheadleftmod: 0x02C2, michael@0: arrowheadrightmod: 0x02C3, michael@0: arrowheadupmod: 0x02C4, michael@0: arrowhorizex: 0xF8E7, michael@0: arrowleft: 0x2190, michael@0: arrowleftdbl: 0x21D0, michael@0: arrowleftdblstroke: 0x21CD, michael@0: arrowleftoverright: 0x21C6, michael@0: arrowleftwhite: 0x21E6, michael@0: arrowright: 0x2192, michael@0: arrowrightdblstroke: 0x21CF, michael@0: arrowrightheavy: 0x279E, michael@0: arrowrightoverleft: 0x21C4, michael@0: arrowrightwhite: 0x21E8, michael@0: arrowtableft: 0x21E4, michael@0: arrowtabright: 0x21E5, michael@0: arrowup: 0x2191, michael@0: arrowupdn: 0x2195, michael@0: arrowupdnbse: 0x21A8, michael@0: arrowupdownbase: 0x21A8, michael@0: arrowupleft: 0x2196, michael@0: arrowupleftofdown: 0x21C5, michael@0: arrowupright: 0x2197, michael@0: arrowupwhite: 0x21E7, michael@0: arrowvertex: 0xF8E6, michael@0: asciicircum: 0x005E, michael@0: asciicircummonospace: 0xFF3E, michael@0: asciitilde: 0x007E, michael@0: asciitildemonospace: 0xFF5E, michael@0: ascript: 0x0251, michael@0: ascriptturned: 0x0252, michael@0: asmallhiragana: 0x3041, michael@0: asmallkatakana: 0x30A1, michael@0: asmallkatakanahalfwidth: 0xFF67, michael@0: asterisk: 0x002A, michael@0: asteriskaltonearabic: 0x066D, michael@0: asteriskarabic: 0x066D, michael@0: asteriskmath: 0x2217, michael@0: asteriskmonospace: 0xFF0A, michael@0: asterisksmall: 0xFE61, michael@0: asterism: 0x2042, michael@0: asuperior: 0xF6E9, michael@0: asymptoticallyequal: 0x2243, michael@0: at: 0x0040, michael@0: atilde: 0x00E3, michael@0: atmonospace: 0xFF20, michael@0: atsmall: 0xFE6B, michael@0: aturned: 0x0250, michael@0: aubengali: 0x0994, michael@0: aubopomofo: 0x3120, michael@0: audeva: 0x0914, michael@0: augujarati: 0x0A94, michael@0: augurmukhi: 0x0A14, michael@0: aulengthmarkbengali: 0x09D7, michael@0: aumatragurmukhi: 0x0A4C, michael@0: auvowelsignbengali: 0x09CC, michael@0: auvowelsigndeva: 0x094C, michael@0: auvowelsigngujarati: 0x0ACC, michael@0: avagrahadeva: 0x093D, michael@0: aybarmenian: 0x0561, michael@0: ayin: 0x05E2, michael@0: ayinaltonehebrew: 0xFB20, michael@0: ayinhebrew: 0x05E2, michael@0: b: 0x0062, michael@0: babengali: 0x09AC, michael@0: backslash: 0x005C, michael@0: backslashmonospace: 0xFF3C, michael@0: badeva: 0x092C, michael@0: bagujarati: 0x0AAC, michael@0: bagurmukhi: 0x0A2C, michael@0: bahiragana: 0x3070, michael@0: bahtthai: 0x0E3F, michael@0: bakatakana: 0x30D0, michael@0: bar: 0x007C, michael@0: barmonospace: 0xFF5C, michael@0: bbopomofo: 0x3105, michael@0: bcircle: 0x24D1, michael@0: bdotaccent: 0x1E03, michael@0: bdotbelow: 0x1E05, michael@0: beamedsixteenthnotes: 0x266C, michael@0: because: 0x2235, michael@0: becyrillic: 0x0431, michael@0: beharabic: 0x0628, michael@0: behfinalarabic: 0xFE90, michael@0: behinitialarabic: 0xFE91, michael@0: behiragana: 0x3079, michael@0: behmedialarabic: 0xFE92, michael@0: behmeeminitialarabic: 0xFC9F, michael@0: behmeemisolatedarabic: 0xFC08, michael@0: behnoonfinalarabic: 0xFC6D, michael@0: bekatakana: 0x30D9, michael@0: benarmenian: 0x0562, michael@0: bet: 0x05D1, michael@0: beta: 0x03B2, michael@0: betasymbolgreek: 0x03D0, michael@0: betdagesh: 0xFB31, michael@0: betdageshhebrew: 0xFB31, michael@0: bethebrew: 0x05D1, michael@0: betrafehebrew: 0xFB4C, michael@0: bhabengali: 0x09AD, michael@0: bhadeva: 0x092D, michael@0: bhagujarati: 0x0AAD, michael@0: bhagurmukhi: 0x0A2D, michael@0: bhook: 0x0253, michael@0: bihiragana: 0x3073, michael@0: bikatakana: 0x30D3, michael@0: bilabialclick: 0x0298, michael@0: bindigurmukhi: 0x0A02, michael@0: birusquare: 0x3331, michael@0: blackcircle: 0x25CF, michael@0: blackdiamond: 0x25C6, michael@0: blackdownpointingtriangle: 0x25BC, michael@0: blackleftpointingpointer: 0x25C4, michael@0: blackleftpointingtriangle: 0x25C0, michael@0: blacklenticularbracketleft: 0x3010, michael@0: blacklenticularbracketleftvertical: 0xFE3B, michael@0: blacklenticularbracketright: 0x3011, michael@0: blacklenticularbracketrightvertical: 0xFE3C, michael@0: blacklowerlefttriangle: 0x25E3, michael@0: blacklowerrighttriangle: 0x25E2, michael@0: blackrectangle: 0x25AC, michael@0: blackrightpointingpointer: 0x25BA, michael@0: blackrightpointingtriangle: 0x25B6, michael@0: blacksmallsquare: 0x25AA, michael@0: blacksmilingface: 0x263B, michael@0: blacksquare: 0x25A0, michael@0: blackstar: 0x2605, michael@0: blackupperlefttriangle: 0x25E4, michael@0: blackupperrighttriangle: 0x25E5, michael@0: blackuppointingsmalltriangle: 0x25B4, michael@0: blackuppointingtriangle: 0x25B2, michael@0: blank: 0x2423, michael@0: blinebelow: 0x1E07, michael@0: block: 0x2588, michael@0: bmonospace: 0xFF42, michael@0: bobaimaithai: 0x0E1A, michael@0: bohiragana: 0x307C, michael@0: bokatakana: 0x30DC, michael@0: bparen: 0x249D, michael@0: bqsquare: 0x33C3, michael@0: braceex: 0xF8F4, michael@0: braceleft: 0x007B, michael@0: braceleftbt: 0xF8F3, michael@0: braceleftmid: 0xF8F2, michael@0: braceleftmonospace: 0xFF5B, michael@0: braceleftsmall: 0xFE5B, michael@0: bracelefttp: 0xF8F1, michael@0: braceleftvertical: 0xFE37, michael@0: braceright: 0x007D, michael@0: bracerightbt: 0xF8FE, michael@0: bracerightmid: 0xF8FD, michael@0: bracerightmonospace: 0xFF5D, michael@0: bracerightsmall: 0xFE5C, michael@0: bracerighttp: 0xF8FC, michael@0: bracerightvertical: 0xFE38, michael@0: bracketleft: 0x005B, michael@0: bracketleftbt: 0xF8F0, michael@0: bracketleftex: 0xF8EF, michael@0: bracketleftmonospace: 0xFF3B, michael@0: bracketlefttp: 0xF8EE, michael@0: bracketright: 0x005D, michael@0: bracketrightbt: 0xF8FB, michael@0: bracketrightex: 0xF8FA, michael@0: bracketrightmonospace: 0xFF3D, michael@0: bracketrighttp: 0xF8F9, michael@0: breve: 0x02D8, michael@0: brevebelowcmb: 0x032E, michael@0: brevecmb: 0x0306, michael@0: breveinvertedbelowcmb: 0x032F, michael@0: breveinvertedcmb: 0x0311, michael@0: breveinverteddoublecmb: 0x0361, michael@0: bridgebelowcmb: 0x032A, michael@0: bridgeinvertedbelowcmb: 0x033A, michael@0: brokenbar: 0x00A6, michael@0: bstroke: 0x0180, michael@0: bsuperior: 0xF6EA, michael@0: btopbar: 0x0183, michael@0: buhiragana: 0x3076, michael@0: bukatakana: 0x30D6, michael@0: bullet: 0x2022, michael@0: bulletinverse: 0x25D8, michael@0: bulletoperator: 0x2219, michael@0: bullseye: 0x25CE, michael@0: c: 0x0063, michael@0: caarmenian: 0x056E, michael@0: cabengali: 0x099A, michael@0: cacute: 0x0107, michael@0: cadeva: 0x091A, michael@0: cagujarati: 0x0A9A, michael@0: cagurmukhi: 0x0A1A, michael@0: calsquare: 0x3388, michael@0: candrabindubengali: 0x0981, michael@0: candrabinducmb: 0x0310, michael@0: candrabindudeva: 0x0901, michael@0: candrabindugujarati: 0x0A81, michael@0: capslock: 0x21EA, michael@0: careof: 0x2105, michael@0: caron: 0x02C7, michael@0: caronbelowcmb: 0x032C, michael@0: caroncmb: 0x030C, michael@0: carriagereturn: 0x21B5, michael@0: cbopomofo: 0x3118, michael@0: ccaron: 0x010D, michael@0: ccedilla: 0x00E7, michael@0: ccedillaacute: 0x1E09, michael@0: ccircle: 0x24D2, michael@0: ccircumflex: 0x0109, michael@0: ccurl: 0x0255, michael@0: cdot: 0x010B, michael@0: cdotaccent: 0x010B, michael@0: cdsquare: 0x33C5, michael@0: cedilla: 0x00B8, michael@0: cedillacmb: 0x0327, michael@0: cent: 0x00A2, michael@0: centigrade: 0x2103, michael@0: centinferior: 0xF6DF, michael@0: centmonospace: 0xFFE0, michael@0: centoldstyle: 0xF7A2, michael@0: centsuperior: 0xF6E0, michael@0: chaarmenian: 0x0579, michael@0: chabengali: 0x099B, michael@0: chadeva: 0x091B, michael@0: chagujarati: 0x0A9B, michael@0: chagurmukhi: 0x0A1B, michael@0: chbopomofo: 0x3114, michael@0: cheabkhasiancyrillic: 0x04BD, michael@0: checkmark: 0x2713, michael@0: checyrillic: 0x0447, michael@0: chedescenderabkhasiancyrillic: 0x04BF, michael@0: chedescendercyrillic: 0x04B7, michael@0: chedieresiscyrillic: 0x04F5, michael@0: cheharmenian: 0x0573, michael@0: chekhakassiancyrillic: 0x04CC, michael@0: cheverticalstrokecyrillic: 0x04B9, michael@0: chi: 0x03C7, michael@0: chieuchacirclekorean: 0x3277, michael@0: chieuchaparenkorean: 0x3217, michael@0: chieuchcirclekorean: 0x3269, michael@0: chieuchkorean: 0x314A, michael@0: chieuchparenkorean: 0x3209, michael@0: chochangthai: 0x0E0A, michael@0: chochanthai: 0x0E08, michael@0: chochingthai: 0x0E09, michael@0: chochoethai: 0x0E0C, michael@0: chook: 0x0188, michael@0: cieucacirclekorean: 0x3276, michael@0: cieucaparenkorean: 0x3216, michael@0: cieuccirclekorean: 0x3268, michael@0: cieuckorean: 0x3148, michael@0: cieucparenkorean: 0x3208, michael@0: cieucuparenkorean: 0x321C, michael@0: circle: 0x25CB, michael@0: circlecopyrt: 0x00A9, // This glyph is missing from Adobe's original list. michael@0: circlemultiply: 0x2297, michael@0: circleot: 0x2299, michael@0: circleplus: 0x2295, michael@0: circlepostalmark: 0x3036, michael@0: circlewithlefthalfblack: 0x25D0, michael@0: circlewithrighthalfblack: 0x25D1, michael@0: circumflex: 0x02C6, michael@0: circumflexbelowcmb: 0x032D, michael@0: circumflexcmb: 0x0302, michael@0: clear: 0x2327, michael@0: clickalveolar: 0x01C2, michael@0: clickdental: 0x01C0, michael@0: clicklateral: 0x01C1, michael@0: clickretroflex: 0x01C3, michael@0: club: 0x2663, michael@0: clubsuitblack: 0x2663, michael@0: clubsuitwhite: 0x2667, michael@0: cmcubedsquare: 0x33A4, michael@0: cmonospace: 0xFF43, michael@0: cmsquaredsquare: 0x33A0, michael@0: coarmenian: 0x0581, michael@0: colon: 0x003A, michael@0: colonmonetary: 0x20A1, michael@0: colonmonospace: 0xFF1A, michael@0: colonsign: 0x20A1, michael@0: colonsmall: 0xFE55, michael@0: colontriangularhalfmod: 0x02D1, michael@0: colontriangularmod: 0x02D0, michael@0: comma: 0x002C, michael@0: commaabovecmb: 0x0313, michael@0: commaaboverightcmb: 0x0315, michael@0: commaaccent: 0xF6C3, michael@0: commaarabic: 0x060C, michael@0: commaarmenian: 0x055D, michael@0: commainferior: 0xF6E1, michael@0: commamonospace: 0xFF0C, michael@0: commareversedabovecmb: 0x0314, michael@0: commareversedmod: 0x02BD, michael@0: commasmall: 0xFE50, michael@0: commasuperior: 0xF6E2, michael@0: commaturnedabovecmb: 0x0312, michael@0: commaturnedmod: 0x02BB, michael@0: compass: 0x263C, michael@0: congruent: 0x2245, michael@0: contourintegral: 0x222E, michael@0: control: 0x2303, michael@0: controlACK: 0x0006, michael@0: controlBEL: 0x0007, michael@0: controlBS: 0x0008, michael@0: controlCAN: 0x0018, michael@0: controlCR: 0x000D, michael@0: controlDC1: 0x0011, michael@0: controlDC2: 0x0012, michael@0: controlDC3: 0x0013, michael@0: controlDC4: 0x0014, michael@0: controlDEL: 0x007F, michael@0: controlDLE: 0x0010, michael@0: controlEM: 0x0019, michael@0: controlENQ: 0x0005, michael@0: controlEOT: 0x0004, michael@0: controlESC: 0x001B, michael@0: controlETB: 0x0017, michael@0: controlETX: 0x0003, michael@0: controlFF: 0x000C, michael@0: controlFS: 0x001C, michael@0: controlGS: 0x001D, michael@0: controlHT: 0x0009, michael@0: controlLF: 0x000A, michael@0: controlNAK: 0x0015, michael@0: controlRS: 0x001E, michael@0: controlSI: 0x000F, michael@0: controlSO: 0x000E, michael@0: controlSOT: 0x0002, michael@0: controlSTX: 0x0001, michael@0: controlSUB: 0x001A, michael@0: controlSYN: 0x0016, michael@0: controlUS: 0x001F, michael@0: controlVT: 0x000B, michael@0: copyright: 0x00A9, michael@0: copyrightsans: 0xF8E9, michael@0: copyrightserif: 0xF6D9, michael@0: cornerbracketleft: 0x300C, michael@0: cornerbracketlefthalfwidth: 0xFF62, michael@0: cornerbracketleftvertical: 0xFE41, michael@0: cornerbracketright: 0x300D, michael@0: cornerbracketrighthalfwidth: 0xFF63, michael@0: cornerbracketrightvertical: 0xFE42, michael@0: corporationsquare: 0x337F, michael@0: cosquare: 0x33C7, michael@0: coverkgsquare: 0x33C6, michael@0: cparen: 0x249E, michael@0: cruzeiro: 0x20A2, michael@0: cstretched: 0x0297, michael@0: curlyand: 0x22CF, michael@0: curlyor: 0x22CE, michael@0: currency: 0x00A4, michael@0: cyrBreve: 0xF6D1, michael@0: cyrFlex: 0xF6D2, michael@0: cyrbreve: 0xF6D4, michael@0: cyrflex: 0xF6D5, michael@0: d: 0x0064, michael@0: daarmenian: 0x0564, michael@0: dabengali: 0x09A6, michael@0: dadarabic: 0x0636, michael@0: dadeva: 0x0926, michael@0: dadfinalarabic: 0xFEBE, michael@0: dadinitialarabic: 0xFEBF, michael@0: dadmedialarabic: 0xFEC0, michael@0: dagesh: 0x05BC, michael@0: dageshhebrew: 0x05BC, michael@0: dagger: 0x2020, michael@0: daggerdbl: 0x2021, michael@0: dagujarati: 0x0AA6, michael@0: dagurmukhi: 0x0A26, michael@0: dahiragana: 0x3060, michael@0: dakatakana: 0x30C0, michael@0: dalarabic: 0x062F, michael@0: dalet: 0x05D3, michael@0: daletdagesh: 0xFB33, michael@0: daletdageshhebrew: 0xFB33, michael@0: dalethebrew: 0x05D3, michael@0: dalfinalarabic: 0xFEAA, michael@0: dammaarabic: 0x064F, michael@0: dammalowarabic: 0x064F, michael@0: dammatanaltonearabic: 0x064C, michael@0: dammatanarabic: 0x064C, michael@0: danda: 0x0964, michael@0: dargahebrew: 0x05A7, michael@0: dargalefthebrew: 0x05A7, michael@0: dasiapneumatacyrilliccmb: 0x0485, michael@0: dblGrave: 0xF6D3, michael@0: dblanglebracketleft: 0x300A, michael@0: dblanglebracketleftvertical: 0xFE3D, michael@0: dblanglebracketright: 0x300B, michael@0: dblanglebracketrightvertical: 0xFE3E, michael@0: dblarchinvertedbelowcmb: 0x032B, michael@0: dblarrowleft: 0x21D4, michael@0: dblarrowright: 0x21D2, michael@0: dbldanda: 0x0965, michael@0: dblgrave: 0xF6D6, michael@0: dblgravecmb: 0x030F, michael@0: dblintegral: 0x222C, michael@0: dbllowline: 0x2017, michael@0: dbllowlinecmb: 0x0333, michael@0: dbloverlinecmb: 0x033F, michael@0: dblprimemod: 0x02BA, michael@0: dblverticalbar: 0x2016, michael@0: dblverticallineabovecmb: 0x030E, michael@0: dbopomofo: 0x3109, michael@0: dbsquare: 0x33C8, michael@0: dcaron: 0x010F, michael@0: dcedilla: 0x1E11, michael@0: dcircle: 0x24D3, michael@0: dcircumflexbelow: 0x1E13, michael@0: dcroat: 0x0111, michael@0: ddabengali: 0x09A1, michael@0: ddadeva: 0x0921, michael@0: ddagujarati: 0x0AA1, michael@0: ddagurmukhi: 0x0A21, michael@0: ddalarabic: 0x0688, michael@0: ddalfinalarabic: 0xFB89, michael@0: dddhadeva: 0x095C, michael@0: ddhabengali: 0x09A2, michael@0: ddhadeva: 0x0922, michael@0: ddhagujarati: 0x0AA2, michael@0: ddhagurmukhi: 0x0A22, michael@0: ddotaccent: 0x1E0B, michael@0: ddotbelow: 0x1E0D, michael@0: decimalseparatorarabic: 0x066B, michael@0: decimalseparatorpersian: 0x066B, michael@0: decyrillic: 0x0434, michael@0: degree: 0x00B0, michael@0: dehihebrew: 0x05AD, michael@0: dehiragana: 0x3067, michael@0: deicoptic: 0x03EF, michael@0: dekatakana: 0x30C7, michael@0: deleteleft: 0x232B, michael@0: deleteright: 0x2326, michael@0: delta: 0x03B4, michael@0: deltaturned: 0x018D, michael@0: denominatorminusonenumeratorbengali: 0x09F8, michael@0: dezh: 0x02A4, michael@0: dhabengali: 0x09A7, michael@0: dhadeva: 0x0927, michael@0: dhagujarati: 0x0AA7, michael@0: dhagurmukhi: 0x0A27, michael@0: dhook: 0x0257, michael@0: dialytikatonos: 0x0385, michael@0: dialytikatonoscmb: 0x0344, michael@0: diamond: 0x2666, michael@0: diamondsuitwhite: 0x2662, michael@0: dieresis: 0x00A8, michael@0: dieresisacute: 0xF6D7, michael@0: dieresisbelowcmb: 0x0324, michael@0: dieresiscmb: 0x0308, michael@0: dieresisgrave: 0xF6D8, michael@0: dieresistonos: 0x0385, michael@0: dihiragana: 0x3062, michael@0: dikatakana: 0x30C2, michael@0: dittomark: 0x3003, michael@0: divide: 0x00F7, michael@0: divides: 0x2223, michael@0: divisionslash: 0x2215, michael@0: djecyrillic: 0x0452, michael@0: dkshade: 0x2593, michael@0: dlinebelow: 0x1E0F, michael@0: dlsquare: 0x3397, michael@0: dmacron: 0x0111, michael@0: dmonospace: 0xFF44, michael@0: dnblock: 0x2584, michael@0: dochadathai: 0x0E0E, michael@0: dodekthai: 0x0E14, michael@0: dohiragana: 0x3069, michael@0: dokatakana: 0x30C9, michael@0: dollar: 0x0024, michael@0: dollarinferior: 0xF6E3, michael@0: dollarmonospace: 0xFF04, michael@0: dollaroldstyle: 0xF724, michael@0: dollarsmall: 0xFE69, michael@0: dollarsuperior: 0xF6E4, michael@0: dong: 0x20AB, michael@0: dorusquare: 0x3326, michael@0: dotaccent: 0x02D9, michael@0: dotaccentcmb: 0x0307, michael@0: dotbelowcmb: 0x0323, michael@0: dotbelowcomb: 0x0323, michael@0: dotkatakana: 0x30FB, michael@0: dotlessi: 0x0131, michael@0: dotlessj: 0xF6BE, michael@0: dotlessjstrokehook: 0x0284, michael@0: dotmath: 0x22C5, michael@0: dottedcircle: 0x25CC, michael@0: doubleyodpatah: 0xFB1F, michael@0: doubleyodpatahhebrew: 0xFB1F, michael@0: downtackbelowcmb: 0x031E, michael@0: downtackmod: 0x02D5, michael@0: dparen: 0x249F, michael@0: dsuperior: 0xF6EB, michael@0: dtail: 0x0256, michael@0: dtopbar: 0x018C, michael@0: duhiragana: 0x3065, michael@0: dukatakana: 0x30C5, michael@0: dz: 0x01F3, michael@0: dzaltone: 0x02A3, michael@0: dzcaron: 0x01C6, michael@0: dzcurl: 0x02A5, michael@0: dzeabkhasiancyrillic: 0x04E1, michael@0: dzecyrillic: 0x0455, michael@0: dzhecyrillic: 0x045F, michael@0: e: 0x0065, michael@0: eacute: 0x00E9, michael@0: earth: 0x2641, michael@0: ebengali: 0x098F, michael@0: ebopomofo: 0x311C, michael@0: ebreve: 0x0115, michael@0: ecandradeva: 0x090D, michael@0: ecandragujarati: 0x0A8D, michael@0: ecandravowelsigndeva: 0x0945, michael@0: ecandravowelsigngujarati: 0x0AC5, michael@0: ecaron: 0x011B, michael@0: ecedillabreve: 0x1E1D, michael@0: echarmenian: 0x0565, michael@0: echyiwnarmenian: 0x0587, michael@0: ecircle: 0x24D4, michael@0: ecircumflex: 0x00EA, michael@0: ecircumflexacute: 0x1EBF, michael@0: ecircumflexbelow: 0x1E19, michael@0: ecircumflexdotbelow: 0x1EC7, michael@0: ecircumflexgrave: 0x1EC1, michael@0: ecircumflexhookabove: 0x1EC3, michael@0: ecircumflextilde: 0x1EC5, michael@0: ecyrillic: 0x0454, michael@0: edblgrave: 0x0205, michael@0: edeva: 0x090F, michael@0: edieresis: 0x00EB, michael@0: edot: 0x0117, michael@0: edotaccent: 0x0117, michael@0: edotbelow: 0x1EB9, michael@0: eegurmukhi: 0x0A0F, michael@0: eematragurmukhi: 0x0A47, michael@0: efcyrillic: 0x0444, michael@0: egrave: 0x00E8, michael@0: egujarati: 0x0A8F, michael@0: eharmenian: 0x0567, michael@0: ehbopomofo: 0x311D, michael@0: ehiragana: 0x3048, michael@0: ehookabove: 0x1EBB, michael@0: eibopomofo: 0x311F, michael@0: eight: 0x0038, michael@0: eightarabic: 0x0668, michael@0: eightbengali: 0x09EE, michael@0: eightcircle: 0x2467, michael@0: eightcircleinversesansserif: 0x2791, michael@0: eightdeva: 0x096E, michael@0: eighteencircle: 0x2471, michael@0: eighteenparen: 0x2485, michael@0: eighteenperiod: 0x2499, michael@0: eightgujarati: 0x0AEE, michael@0: eightgurmukhi: 0x0A6E, michael@0: eighthackarabic: 0x0668, michael@0: eighthangzhou: 0x3028, michael@0: eighthnotebeamed: 0x266B, michael@0: eightideographicparen: 0x3227, michael@0: eightinferior: 0x2088, michael@0: eightmonospace: 0xFF18, michael@0: eightoldstyle: 0xF738, michael@0: eightparen: 0x247B, michael@0: eightperiod: 0x248F, michael@0: eightpersian: 0x06F8, michael@0: eightroman: 0x2177, michael@0: eightsuperior: 0x2078, michael@0: eightthai: 0x0E58, michael@0: einvertedbreve: 0x0207, michael@0: eiotifiedcyrillic: 0x0465, michael@0: ekatakana: 0x30A8, michael@0: ekatakanahalfwidth: 0xFF74, michael@0: ekonkargurmukhi: 0x0A74, michael@0: ekorean: 0x3154, michael@0: elcyrillic: 0x043B, michael@0: element: 0x2208, michael@0: elevencircle: 0x246A, michael@0: elevenparen: 0x247E, michael@0: elevenperiod: 0x2492, michael@0: elevenroman: 0x217A, michael@0: ellipsis: 0x2026, michael@0: ellipsisvertical: 0x22EE, michael@0: emacron: 0x0113, michael@0: emacronacute: 0x1E17, michael@0: emacrongrave: 0x1E15, michael@0: emcyrillic: 0x043C, michael@0: emdash: 0x2014, michael@0: emdashvertical: 0xFE31, michael@0: emonospace: 0xFF45, michael@0: emphasismarkarmenian: 0x055B, michael@0: emptyset: 0x2205, michael@0: enbopomofo: 0x3123, michael@0: encyrillic: 0x043D, michael@0: endash: 0x2013, michael@0: endashvertical: 0xFE32, michael@0: endescendercyrillic: 0x04A3, michael@0: eng: 0x014B, michael@0: engbopomofo: 0x3125, michael@0: enghecyrillic: 0x04A5, michael@0: enhookcyrillic: 0x04C8, michael@0: enspace: 0x2002, michael@0: eogonek: 0x0119, michael@0: eokorean: 0x3153, michael@0: eopen: 0x025B, michael@0: eopenclosed: 0x029A, michael@0: eopenreversed: 0x025C, michael@0: eopenreversedclosed: 0x025E, michael@0: eopenreversedhook: 0x025D, michael@0: eparen: 0x24A0, michael@0: epsilon: 0x03B5, michael@0: epsilontonos: 0x03AD, michael@0: equal: 0x003D, michael@0: equalmonospace: 0xFF1D, michael@0: equalsmall: 0xFE66, michael@0: equalsuperior: 0x207C, michael@0: equivalence: 0x2261, michael@0: erbopomofo: 0x3126, michael@0: ercyrillic: 0x0440, michael@0: ereversed: 0x0258, michael@0: ereversedcyrillic: 0x044D, michael@0: escyrillic: 0x0441, michael@0: esdescendercyrillic: 0x04AB, michael@0: esh: 0x0283, michael@0: eshcurl: 0x0286, michael@0: eshortdeva: 0x090E, michael@0: eshortvowelsigndeva: 0x0946, michael@0: eshreversedloop: 0x01AA, michael@0: eshsquatreversed: 0x0285, michael@0: esmallhiragana: 0x3047, michael@0: esmallkatakana: 0x30A7, michael@0: esmallkatakanahalfwidth: 0xFF6A, michael@0: estimated: 0x212E, michael@0: esuperior: 0xF6EC, michael@0: eta: 0x03B7, michael@0: etarmenian: 0x0568, michael@0: etatonos: 0x03AE, michael@0: eth: 0x00F0, michael@0: etilde: 0x1EBD, michael@0: etildebelow: 0x1E1B, michael@0: etnahtafoukhhebrew: 0x0591, michael@0: etnahtafoukhlefthebrew: 0x0591, michael@0: etnahtahebrew: 0x0591, michael@0: etnahtalefthebrew: 0x0591, michael@0: eturned: 0x01DD, michael@0: eukorean: 0x3161, michael@0: euro: 0x20AC, michael@0: evowelsignbengali: 0x09C7, michael@0: evowelsigndeva: 0x0947, michael@0: evowelsigngujarati: 0x0AC7, michael@0: exclam: 0x0021, michael@0: exclamarmenian: 0x055C, michael@0: exclamdbl: 0x203C, michael@0: exclamdown: 0x00A1, michael@0: exclamdownsmall: 0xF7A1, michael@0: exclammonospace: 0xFF01, michael@0: exclamsmall: 0xF721, michael@0: existential: 0x2203, michael@0: ezh: 0x0292, michael@0: ezhcaron: 0x01EF, michael@0: ezhcurl: 0x0293, michael@0: ezhreversed: 0x01B9, michael@0: ezhtail: 0x01BA, michael@0: f: 0x0066, michael@0: fadeva: 0x095E, michael@0: fagurmukhi: 0x0A5E, michael@0: fahrenheit: 0x2109, michael@0: fathaarabic: 0x064E, michael@0: fathalowarabic: 0x064E, michael@0: fathatanarabic: 0x064B, michael@0: fbopomofo: 0x3108, michael@0: fcircle: 0x24D5, michael@0: fdotaccent: 0x1E1F, michael@0: feharabic: 0x0641, michael@0: feharmenian: 0x0586, michael@0: fehfinalarabic: 0xFED2, michael@0: fehinitialarabic: 0xFED3, michael@0: fehmedialarabic: 0xFED4, michael@0: feicoptic: 0x03E5, michael@0: female: 0x2640, michael@0: ff: 0xFB00, michael@0: ffi: 0xFB03, michael@0: ffl: 0xFB04, michael@0: fi: 0xFB01, michael@0: fifteencircle: 0x246E, michael@0: fifteenparen: 0x2482, michael@0: fifteenperiod: 0x2496, michael@0: figuredash: 0x2012, michael@0: filledbox: 0x25A0, michael@0: filledrect: 0x25AC, michael@0: finalkaf: 0x05DA, michael@0: finalkafdagesh: 0xFB3A, michael@0: finalkafdageshhebrew: 0xFB3A, michael@0: finalkafhebrew: 0x05DA, michael@0: finalmem: 0x05DD, michael@0: finalmemhebrew: 0x05DD, michael@0: finalnun: 0x05DF, michael@0: finalnunhebrew: 0x05DF, michael@0: finalpe: 0x05E3, michael@0: finalpehebrew: 0x05E3, michael@0: finaltsadi: 0x05E5, michael@0: finaltsadihebrew: 0x05E5, michael@0: firsttonechinese: 0x02C9, michael@0: fisheye: 0x25C9, michael@0: fitacyrillic: 0x0473, michael@0: five: 0x0035, michael@0: fivearabic: 0x0665, michael@0: fivebengali: 0x09EB, michael@0: fivecircle: 0x2464, michael@0: fivecircleinversesansserif: 0x278E, michael@0: fivedeva: 0x096B, michael@0: fiveeighths: 0x215D, michael@0: fivegujarati: 0x0AEB, michael@0: fivegurmukhi: 0x0A6B, michael@0: fivehackarabic: 0x0665, michael@0: fivehangzhou: 0x3025, michael@0: fiveideographicparen: 0x3224, michael@0: fiveinferior: 0x2085, michael@0: fivemonospace: 0xFF15, michael@0: fiveoldstyle: 0xF735, michael@0: fiveparen: 0x2478, michael@0: fiveperiod: 0x248C, michael@0: fivepersian: 0x06F5, michael@0: fiveroman: 0x2174, michael@0: fivesuperior: 0x2075, michael@0: fivethai: 0x0E55, michael@0: fl: 0xFB02, michael@0: florin: 0x0192, michael@0: fmonospace: 0xFF46, michael@0: fmsquare: 0x3399, michael@0: fofanthai: 0x0E1F, michael@0: fofathai: 0x0E1D, michael@0: fongmanthai: 0x0E4F, michael@0: forall: 0x2200, michael@0: four: 0x0034, michael@0: fourarabic: 0x0664, michael@0: fourbengali: 0x09EA, michael@0: fourcircle: 0x2463, michael@0: fourcircleinversesansserif: 0x278D, michael@0: fourdeva: 0x096A, michael@0: fourgujarati: 0x0AEA, michael@0: fourgurmukhi: 0x0A6A, michael@0: fourhackarabic: 0x0664, michael@0: fourhangzhou: 0x3024, michael@0: fourideographicparen: 0x3223, michael@0: fourinferior: 0x2084, michael@0: fourmonospace: 0xFF14, michael@0: fournumeratorbengali: 0x09F7, michael@0: fouroldstyle: 0xF734, michael@0: fourparen: 0x2477, michael@0: fourperiod: 0x248B, michael@0: fourpersian: 0x06F4, michael@0: fourroman: 0x2173, michael@0: foursuperior: 0x2074, michael@0: fourteencircle: 0x246D, michael@0: fourteenparen: 0x2481, michael@0: fourteenperiod: 0x2495, michael@0: fourthai: 0x0E54, michael@0: fourthtonechinese: 0x02CB, michael@0: fparen: 0x24A1, michael@0: fraction: 0x2044, michael@0: franc: 0x20A3, michael@0: g: 0x0067, michael@0: gabengali: 0x0997, michael@0: gacute: 0x01F5, michael@0: gadeva: 0x0917, michael@0: gafarabic: 0x06AF, michael@0: gaffinalarabic: 0xFB93, michael@0: gafinitialarabic: 0xFB94, michael@0: gafmedialarabic: 0xFB95, michael@0: gagujarati: 0x0A97, michael@0: gagurmukhi: 0x0A17, michael@0: gahiragana: 0x304C, michael@0: gakatakana: 0x30AC, michael@0: gamma: 0x03B3, michael@0: gammalatinsmall: 0x0263, michael@0: gammasuperior: 0x02E0, michael@0: gangiacoptic: 0x03EB, michael@0: gbopomofo: 0x310D, michael@0: gbreve: 0x011F, michael@0: gcaron: 0x01E7, michael@0: gcedilla: 0x0123, michael@0: gcircle: 0x24D6, michael@0: gcircumflex: 0x011D, michael@0: gcommaaccent: 0x0123, michael@0: gdot: 0x0121, michael@0: gdotaccent: 0x0121, michael@0: gecyrillic: 0x0433, michael@0: gehiragana: 0x3052, michael@0: gekatakana: 0x30B2, michael@0: geometricallyequal: 0x2251, michael@0: gereshaccenthebrew: 0x059C, michael@0: gereshhebrew: 0x05F3, michael@0: gereshmuqdamhebrew: 0x059D, michael@0: germandbls: 0x00DF, michael@0: gershayimaccenthebrew: 0x059E, michael@0: gershayimhebrew: 0x05F4, michael@0: getamark: 0x3013, michael@0: ghabengali: 0x0998, michael@0: ghadarmenian: 0x0572, michael@0: ghadeva: 0x0918, michael@0: ghagujarati: 0x0A98, michael@0: ghagurmukhi: 0x0A18, michael@0: ghainarabic: 0x063A, michael@0: ghainfinalarabic: 0xFECE, michael@0: ghaininitialarabic: 0xFECF, michael@0: ghainmedialarabic: 0xFED0, michael@0: ghemiddlehookcyrillic: 0x0495, michael@0: ghestrokecyrillic: 0x0493, michael@0: gheupturncyrillic: 0x0491, michael@0: ghhadeva: 0x095A, michael@0: ghhagurmukhi: 0x0A5A, michael@0: ghook: 0x0260, michael@0: ghzsquare: 0x3393, michael@0: gihiragana: 0x304E, michael@0: gikatakana: 0x30AE, michael@0: gimarmenian: 0x0563, michael@0: gimel: 0x05D2, michael@0: gimeldagesh: 0xFB32, michael@0: gimeldageshhebrew: 0xFB32, michael@0: gimelhebrew: 0x05D2, michael@0: gjecyrillic: 0x0453, michael@0: glottalinvertedstroke: 0x01BE, michael@0: glottalstop: 0x0294, michael@0: glottalstopinverted: 0x0296, michael@0: glottalstopmod: 0x02C0, michael@0: glottalstopreversed: 0x0295, michael@0: glottalstopreversedmod: 0x02C1, michael@0: glottalstopreversedsuperior: 0x02E4, michael@0: glottalstopstroke: 0x02A1, michael@0: glottalstopstrokereversed: 0x02A2, michael@0: gmacron: 0x1E21, michael@0: gmonospace: 0xFF47, michael@0: gohiragana: 0x3054, michael@0: gokatakana: 0x30B4, michael@0: gparen: 0x24A2, michael@0: gpasquare: 0x33AC, michael@0: gradient: 0x2207, michael@0: grave: 0x0060, michael@0: gravebelowcmb: 0x0316, michael@0: gravecmb: 0x0300, michael@0: gravecomb: 0x0300, michael@0: gravedeva: 0x0953, michael@0: gravelowmod: 0x02CE, michael@0: gravemonospace: 0xFF40, michael@0: gravetonecmb: 0x0340, michael@0: greater: 0x003E, michael@0: greaterequal: 0x2265, michael@0: greaterequalorless: 0x22DB, michael@0: greatermonospace: 0xFF1E, michael@0: greaterorequivalent: 0x2273, michael@0: greaterorless: 0x2277, michael@0: greateroverequal: 0x2267, michael@0: greatersmall: 0xFE65, michael@0: gscript: 0x0261, michael@0: gstroke: 0x01E5, michael@0: guhiragana: 0x3050, michael@0: guillemotleft: 0x00AB, michael@0: guillemotright: 0x00BB, michael@0: guilsinglleft: 0x2039, michael@0: guilsinglright: 0x203A, michael@0: gukatakana: 0x30B0, michael@0: guramusquare: 0x3318, michael@0: gysquare: 0x33C9, michael@0: h: 0x0068, michael@0: haabkhasiancyrillic: 0x04A9, michael@0: haaltonearabic: 0x06C1, michael@0: habengali: 0x09B9, michael@0: hadescendercyrillic: 0x04B3, michael@0: hadeva: 0x0939, michael@0: hagujarati: 0x0AB9, michael@0: hagurmukhi: 0x0A39, michael@0: haharabic: 0x062D, michael@0: hahfinalarabic: 0xFEA2, michael@0: hahinitialarabic: 0xFEA3, michael@0: hahiragana: 0x306F, michael@0: hahmedialarabic: 0xFEA4, michael@0: haitusquare: 0x332A, michael@0: hakatakana: 0x30CF, michael@0: hakatakanahalfwidth: 0xFF8A, michael@0: halantgurmukhi: 0x0A4D, michael@0: hamzaarabic: 0x0621, michael@0: hamzalowarabic: 0x0621, michael@0: hangulfiller: 0x3164, michael@0: hardsigncyrillic: 0x044A, michael@0: harpoonleftbarbup: 0x21BC, michael@0: harpoonrightbarbup: 0x21C0, michael@0: hasquare: 0x33CA, michael@0: hatafpatah: 0x05B2, michael@0: hatafpatah16: 0x05B2, michael@0: hatafpatah23: 0x05B2, michael@0: hatafpatah2f: 0x05B2, michael@0: hatafpatahhebrew: 0x05B2, michael@0: hatafpatahnarrowhebrew: 0x05B2, michael@0: hatafpatahquarterhebrew: 0x05B2, michael@0: hatafpatahwidehebrew: 0x05B2, michael@0: hatafqamats: 0x05B3, michael@0: hatafqamats1b: 0x05B3, michael@0: hatafqamats28: 0x05B3, michael@0: hatafqamats34: 0x05B3, michael@0: hatafqamatshebrew: 0x05B3, michael@0: hatafqamatsnarrowhebrew: 0x05B3, michael@0: hatafqamatsquarterhebrew: 0x05B3, michael@0: hatafqamatswidehebrew: 0x05B3, michael@0: hatafsegol: 0x05B1, michael@0: hatafsegol17: 0x05B1, michael@0: hatafsegol24: 0x05B1, michael@0: hatafsegol30: 0x05B1, michael@0: hatafsegolhebrew: 0x05B1, michael@0: hatafsegolnarrowhebrew: 0x05B1, michael@0: hatafsegolquarterhebrew: 0x05B1, michael@0: hatafsegolwidehebrew: 0x05B1, michael@0: hbar: 0x0127, michael@0: hbopomofo: 0x310F, michael@0: hbrevebelow: 0x1E2B, michael@0: hcedilla: 0x1E29, michael@0: hcircle: 0x24D7, michael@0: hcircumflex: 0x0125, michael@0: hdieresis: 0x1E27, michael@0: hdotaccent: 0x1E23, michael@0: hdotbelow: 0x1E25, michael@0: he: 0x05D4, michael@0: heart: 0x2665, michael@0: heartsuitblack: 0x2665, michael@0: heartsuitwhite: 0x2661, michael@0: hedagesh: 0xFB34, michael@0: hedageshhebrew: 0xFB34, michael@0: hehaltonearabic: 0x06C1, michael@0: heharabic: 0x0647, michael@0: hehebrew: 0x05D4, michael@0: hehfinalaltonearabic: 0xFBA7, michael@0: hehfinalalttwoarabic: 0xFEEA, michael@0: hehfinalarabic: 0xFEEA, michael@0: hehhamzaabovefinalarabic: 0xFBA5, michael@0: hehhamzaaboveisolatedarabic: 0xFBA4, michael@0: hehinitialaltonearabic: 0xFBA8, michael@0: hehinitialarabic: 0xFEEB, michael@0: hehiragana: 0x3078, michael@0: hehmedialaltonearabic: 0xFBA9, michael@0: hehmedialarabic: 0xFEEC, michael@0: heiseierasquare: 0x337B, michael@0: hekatakana: 0x30D8, michael@0: hekatakanahalfwidth: 0xFF8D, michael@0: hekutaarusquare: 0x3336, michael@0: henghook: 0x0267, michael@0: herutusquare: 0x3339, michael@0: het: 0x05D7, michael@0: hethebrew: 0x05D7, michael@0: hhook: 0x0266, michael@0: hhooksuperior: 0x02B1, michael@0: hieuhacirclekorean: 0x327B, michael@0: hieuhaparenkorean: 0x321B, michael@0: hieuhcirclekorean: 0x326D, michael@0: hieuhkorean: 0x314E, michael@0: hieuhparenkorean: 0x320D, michael@0: hihiragana: 0x3072, michael@0: hikatakana: 0x30D2, michael@0: hikatakanahalfwidth: 0xFF8B, michael@0: hiriq: 0x05B4, michael@0: hiriq14: 0x05B4, michael@0: hiriq21: 0x05B4, michael@0: hiriq2d: 0x05B4, michael@0: hiriqhebrew: 0x05B4, michael@0: hiriqnarrowhebrew: 0x05B4, michael@0: hiriqquarterhebrew: 0x05B4, michael@0: hiriqwidehebrew: 0x05B4, michael@0: hlinebelow: 0x1E96, michael@0: hmonospace: 0xFF48, michael@0: hoarmenian: 0x0570, michael@0: hohipthai: 0x0E2B, michael@0: hohiragana: 0x307B, michael@0: hokatakana: 0x30DB, michael@0: hokatakanahalfwidth: 0xFF8E, michael@0: holam: 0x05B9, michael@0: holam19: 0x05B9, michael@0: holam26: 0x05B9, michael@0: holam32: 0x05B9, michael@0: holamhebrew: 0x05B9, michael@0: holamnarrowhebrew: 0x05B9, michael@0: holamquarterhebrew: 0x05B9, michael@0: holamwidehebrew: 0x05B9, michael@0: honokhukthai: 0x0E2E, michael@0: hookabovecomb: 0x0309, michael@0: hookcmb: 0x0309, michael@0: hookpalatalizedbelowcmb: 0x0321, michael@0: hookretroflexbelowcmb: 0x0322, michael@0: hoonsquare: 0x3342, michael@0: horicoptic: 0x03E9, michael@0: horizontalbar: 0x2015, michael@0: horncmb: 0x031B, michael@0: hotsprings: 0x2668, michael@0: house: 0x2302, michael@0: hparen: 0x24A3, michael@0: hsuperior: 0x02B0, michael@0: hturned: 0x0265, michael@0: huhiragana: 0x3075, michael@0: huiitosquare: 0x3333, michael@0: hukatakana: 0x30D5, michael@0: hukatakanahalfwidth: 0xFF8C, michael@0: hungarumlaut: 0x02DD, michael@0: hungarumlautcmb: 0x030B, michael@0: hv: 0x0195, michael@0: hyphen: 0x002D, michael@0: hypheninferior: 0xF6E5, michael@0: hyphenmonospace: 0xFF0D, michael@0: hyphensmall: 0xFE63, michael@0: hyphensuperior: 0xF6E6, michael@0: hyphentwo: 0x2010, michael@0: i: 0x0069, michael@0: iacute: 0x00ED, michael@0: iacyrillic: 0x044F, michael@0: ibengali: 0x0987, michael@0: ibopomofo: 0x3127, michael@0: ibreve: 0x012D, michael@0: icaron: 0x01D0, michael@0: icircle: 0x24D8, michael@0: icircumflex: 0x00EE, michael@0: icyrillic: 0x0456, michael@0: idblgrave: 0x0209, michael@0: ideographearthcircle: 0x328F, michael@0: ideographfirecircle: 0x328B, michael@0: ideographicallianceparen: 0x323F, michael@0: ideographiccallparen: 0x323A, michael@0: ideographiccentrecircle: 0x32A5, michael@0: ideographicclose: 0x3006, michael@0: ideographiccomma: 0x3001, michael@0: ideographiccommaleft: 0xFF64, michael@0: ideographiccongratulationparen: 0x3237, michael@0: ideographiccorrectcircle: 0x32A3, michael@0: ideographicearthparen: 0x322F, michael@0: ideographicenterpriseparen: 0x323D, michael@0: ideographicexcellentcircle: 0x329D, michael@0: ideographicfestivalparen: 0x3240, michael@0: ideographicfinancialcircle: 0x3296, michael@0: ideographicfinancialparen: 0x3236, michael@0: ideographicfireparen: 0x322B, michael@0: ideographichaveparen: 0x3232, michael@0: ideographichighcircle: 0x32A4, michael@0: ideographiciterationmark: 0x3005, michael@0: ideographiclaborcircle: 0x3298, michael@0: ideographiclaborparen: 0x3238, michael@0: ideographicleftcircle: 0x32A7, michael@0: ideographiclowcircle: 0x32A6, michael@0: ideographicmedicinecircle: 0x32A9, michael@0: ideographicmetalparen: 0x322E, michael@0: ideographicmoonparen: 0x322A, michael@0: ideographicnameparen: 0x3234, michael@0: ideographicperiod: 0x3002, michael@0: ideographicprintcircle: 0x329E, michael@0: ideographicreachparen: 0x3243, michael@0: ideographicrepresentparen: 0x3239, michael@0: ideographicresourceparen: 0x323E, michael@0: ideographicrightcircle: 0x32A8, michael@0: ideographicsecretcircle: 0x3299, michael@0: ideographicselfparen: 0x3242, michael@0: ideographicsocietyparen: 0x3233, michael@0: ideographicspace: 0x3000, michael@0: ideographicspecialparen: 0x3235, michael@0: ideographicstockparen: 0x3231, michael@0: ideographicstudyparen: 0x323B, michael@0: ideographicsunparen: 0x3230, michael@0: ideographicsuperviseparen: 0x323C, michael@0: ideographicwaterparen: 0x322C, michael@0: ideographicwoodparen: 0x322D, michael@0: ideographiczero: 0x3007, michael@0: ideographmetalcircle: 0x328E, michael@0: ideographmooncircle: 0x328A, michael@0: ideographnamecircle: 0x3294, michael@0: ideographsuncircle: 0x3290, michael@0: ideographwatercircle: 0x328C, michael@0: ideographwoodcircle: 0x328D, michael@0: ideva: 0x0907, michael@0: idieresis: 0x00EF, michael@0: idieresisacute: 0x1E2F, michael@0: idieresiscyrillic: 0x04E5, michael@0: idotbelow: 0x1ECB, michael@0: iebrevecyrillic: 0x04D7, michael@0: iecyrillic: 0x0435, michael@0: ieungacirclekorean: 0x3275, michael@0: ieungaparenkorean: 0x3215, michael@0: ieungcirclekorean: 0x3267, michael@0: ieungkorean: 0x3147, michael@0: ieungparenkorean: 0x3207, michael@0: igrave: 0x00EC, michael@0: igujarati: 0x0A87, michael@0: igurmukhi: 0x0A07, michael@0: ihiragana: 0x3044, michael@0: ihookabove: 0x1EC9, michael@0: iibengali: 0x0988, michael@0: iicyrillic: 0x0438, michael@0: iideva: 0x0908, michael@0: iigujarati: 0x0A88, michael@0: iigurmukhi: 0x0A08, michael@0: iimatragurmukhi: 0x0A40, michael@0: iinvertedbreve: 0x020B, michael@0: iishortcyrillic: 0x0439, michael@0: iivowelsignbengali: 0x09C0, michael@0: iivowelsigndeva: 0x0940, michael@0: iivowelsigngujarati: 0x0AC0, michael@0: ij: 0x0133, michael@0: ikatakana: 0x30A4, michael@0: ikatakanahalfwidth: 0xFF72, michael@0: ikorean: 0x3163, michael@0: ilde: 0x02DC, michael@0: iluyhebrew: 0x05AC, michael@0: imacron: 0x012B, michael@0: imacroncyrillic: 0x04E3, michael@0: imageorapproximatelyequal: 0x2253, michael@0: imatragurmukhi: 0x0A3F, michael@0: imonospace: 0xFF49, michael@0: increment: 0x2206, michael@0: infinity: 0x221E, michael@0: iniarmenian: 0x056B, michael@0: integral: 0x222B, michael@0: integralbottom: 0x2321, michael@0: integralbt: 0x2321, michael@0: integralex: 0xF8F5, michael@0: integraltop: 0x2320, michael@0: integraltp: 0x2320, michael@0: intersection: 0x2229, michael@0: intisquare: 0x3305, michael@0: invbullet: 0x25D8, michael@0: invcircle: 0x25D9, michael@0: invsmileface: 0x263B, michael@0: iocyrillic: 0x0451, michael@0: iogonek: 0x012F, michael@0: iota: 0x03B9, michael@0: iotadieresis: 0x03CA, michael@0: iotadieresistonos: 0x0390, michael@0: iotalatin: 0x0269, michael@0: iotatonos: 0x03AF, michael@0: iparen: 0x24A4, michael@0: irigurmukhi: 0x0A72, michael@0: ismallhiragana: 0x3043, michael@0: ismallkatakana: 0x30A3, michael@0: ismallkatakanahalfwidth: 0xFF68, michael@0: issharbengali: 0x09FA, michael@0: istroke: 0x0268, michael@0: isuperior: 0xF6ED, michael@0: iterationhiragana: 0x309D, michael@0: iterationkatakana: 0x30FD, michael@0: itilde: 0x0129, michael@0: itildebelow: 0x1E2D, michael@0: iubopomofo: 0x3129, michael@0: iucyrillic: 0x044E, michael@0: ivowelsignbengali: 0x09BF, michael@0: ivowelsigndeva: 0x093F, michael@0: ivowelsigngujarati: 0x0ABF, michael@0: izhitsacyrillic: 0x0475, michael@0: izhitsadblgravecyrillic: 0x0477, michael@0: j: 0x006A, michael@0: jaarmenian: 0x0571, michael@0: jabengali: 0x099C, michael@0: jadeva: 0x091C, michael@0: jagujarati: 0x0A9C, michael@0: jagurmukhi: 0x0A1C, michael@0: jbopomofo: 0x3110, michael@0: jcaron: 0x01F0, michael@0: jcircle: 0x24D9, michael@0: jcircumflex: 0x0135, michael@0: jcrossedtail: 0x029D, michael@0: jdotlessstroke: 0x025F, michael@0: jecyrillic: 0x0458, michael@0: jeemarabic: 0x062C, michael@0: jeemfinalarabic: 0xFE9E, michael@0: jeeminitialarabic: 0xFE9F, michael@0: jeemmedialarabic: 0xFEA0, michael@0: jeharabic: 0x0698, michael@0: jehfinalarabic: 0xFB8B, michael@0: jhabengali: 0x099D, michael@0: jhadeva: 0x091D, michael@0: jhagujarati: 0x0A9D, michael@0: jhagurmukhi: 0x0A1D, michael@0: jheharmenian: 0x057B, michael@0: jis: 0x3004, michael@0: jmonospace: 0xFF4A, michael@0: jparen: 0x24A5, michael@0: jsuperior: 0x02B2, michael@0: k: 0x006B, michael@0: kabashkircyrillic: 0x04A1, michael@0: kabengali: 0x0995, michael@0: kacute: 0x1E31, michael@0: kacyrillic: 0x043A, michael@0: kadescendercyrillic: 0x049B, michael@0: kadeva: 0x0915, michael@0: kaf: 0x05DB, michael@0: kafarabic: 0x0643, michael@0: kafdagesh: 0xFB3B, michael@0: kafdageshhebrew: 0xFB3B, michael@0: kaffinalarabic: 0xFEDA, michael@0: kafhebrew: 0x05DB, michael@0: kafinitialarabic: 0xFEDB, michael@0: kafmedialarabic: 0xFEDC, michael@0: kafrafehebrew: 0xFB4D, michael@0: kagujarati: 0x0A95, michael@0: kagurmukhi: 0x0A15, michael@0: kahiragana: 0x304B, michael@0: kahookcyrillic: 0x04C4, michael@0: kakatakana: 0x30AB, michael@0: kakatakanahalfwidth: 0xFF76, michael@0: kappa: 0x03BA, michael@0: kappasymbolgreek: 0x03F0, michael@0: kapyeounmieumkorean: 0x3171, michael@0: kapyeounphieuphkorean: 0x3184, michael@0: kapyeounpieupkorean: 0x3178, michael@0: kapyeounssangpieupkorean: 0x3179, michael@0: karoriisquare: 0x330D, michael@0: kashidaautoarabic: 0x0640, michael@0: kashidaautonosidebearingarabic: 0x0640, michael@0: kasmallkatakana: 0x30F5, michael@0: kasquare: 0x3384, michael@0: kasraarabic: 0x0650, michael@0: kasratanarabic: 0x064D, michael@0: kastrokecyrillic: 0x049F, michael@0: katahiraprolongmarkhalfwidth: 0xFF70, michael@0: kaverticalstrokecyrillic: 0x049D, michael@0: kbopomofo: 0x310E, michael@0: kcalsquare: 0x3389, michael@0: kcaron: 0x01E9, michael@0: kcedilla: 0x0137, michael@0: kcircle: 0x24DA, michael@0: kcommaaccent: 0x0137, michael@0: kdotbelow: 0x1E33, michael@0: keharmenian: 0x0584, michael@0: kehiragana: 0x3051, michael@0: kekatakana: 0x30B1, michael@0: kekatakanahalfwidth: 0xFF79, michael@0: kenarmenian: 0x056F, michael@0: kesmallkatakana: 0x30F6, michael@0: kgreenlandic: 0x0138, michael@0: khabengali: 0x0996, michael@0: khacyrillic: 0x0445, michael@0: khadeva: 0x0916, michael@0: khagujarati: 0x0A96, michael@0: khagurmukhi: 0x0A16, michael@0: khaharabic: 0x062E, michael@0: khahfinalarabic: 0xFEA6, michael@0: khahinitialarabic: 0xFEA7, michael@0: khahmedialarabic: 0xFEA8, michael@0: kheicoptic: 0x03E7, michael@0: khhadeva: 0x0959, michael@0: khhagurmukhi: 0x0A59, michael@0: khieukhacirclekorean: 0x3278, michael@0: khieukhaparenkorean: 0x3218, michael@0: khieukhcirclekorean: 0x326A, michael@0: khieukhkorean: 0x314B, michael@0: khieukhparenkorean: 0x320A, michael@0: khokhaithai: 0x0E02, michael@0: khokhonthai: 0x0E05, michael@0: khokhuatthai: 0x0E03, michael@0: khokhwaithai: 0x0E04, michael@0: khomutthai: 0x0E5B, michael@0: khook: 0x0199, michael@0: khorakhangthai: 0x0E06, michael@0: khzsquare: 0x3391, michael@0: kihiragana: 0x304D, michael@0: kikatakana: 0x30AD, michael@0: kikatakanahalfwidth: 0xFF77, michael@0: kiroguramusquare: 0x3315, michael@0: kiromeetorusquare: 0x3316, michael@0: kirosquare: 0x3314, michael@0: kiyeokacirclekorean: 0x326E, michael@0: kiyeokaparenkorean: 0x320E, michael@0: kiyeokcirclekorean: 0x3260, michael@0: kiyeokkorean: 0x3131, michael@0: kiyeokparenkorean: 0x3200, michael@0: kiyeoksioskorean: 0x3133, michael@0: kjecyrillic: 0x045C, michael@0: klinebelow: 0x1E35, michael@0: klsquare: 0x3398, michael@0: kmcubedsquare: 0x33A6, michael@0: kmonospace: 0xFF4B, michael@0: kmsquaredsquare: 0x33A2, michael@0: kohiragana: 0x3053, michael@0: kohmsquare: 0x33C0, michael@0: kokaithai: 0x0E01, michael@0: kokatakana: 0x30B3, michael@0: kokatakanahalfwidth: 0xFF7A, michael@0: kooposquare: 0x331E, michael@0: koppacyrillic: 0x0481, michael@0: koreanstandardsymbol: 0x327F, michael@0: koroniscmb: 0x0343, michael@0: kparen: 0x24A6, michael@0: kpasquare: 0x33AA, michael@0: ksicyrillic: 0x046F, michael@0: ktsquare: 0x33CF, michael@0: kturned: 0x029E, michael@0: kuhiragana: 0x304F, michael@0: kukatakana: 0x30AF, michael@0: kukatakanahalfwidth: 0xFF78, michael@0: kvsquare: 0x33B8, michael@0: kwsquare: 0x33BE, michael@0: l: 0x006C, michael@0: labengali: 0x09B2, michael@0: lacute: 0x013A, michael@0: ladeva: 0x0932, michael@0: lagujarati: 0x0AB2, michael@0: lagurmukhi: 0x0A32, michael@0: lakkhangyaothai: 0x0E45, michael@0: lamaleffinalarabic: 0xFEFC, michael@0: lamalefhamzaabovefinalarabic: 0xFEF8, michael@0: lamalefhamzaaboveisolatedarabic: 0xFEF7, michael@0: lamalefhamzabelowfinalarabic: 0xFEFA, michael@0: lamalefhamzabelowisolatedarabic: 0xFEF9, michael@0: lamalefisolatedarabic: 0xFEFB, michael@0: lamalefmaddaabovefinalarabic: 0xFEF6, michael@0: lamalefmaddaaboveisolatedarabic: 0xFEF5, michael@0: lamarabic: 0x0644, michael@0: lambda: 0x03BB, michael@0: lambdastroke: 0x019B, michael@0: lamed: 0x05DC, michael@0: lameddagesh: 0xFB3C, michael@0: lameddageshhebrew: 0xFB3C, michael@0: lamedhebrew: 0x05DC, michael@0: lamfinalarabic: 0xFEDE, michael@0: lamhahinitialarabic: 0xFCCA, michael@0: laminitialarabic: 0xFEDF, michael@0: lamjeeminitialarabic: 0xFCC9, michael@0: lamkhahinitialarabic: 0xFCCB, michael@0: lamlamhehisolatedarabic: 0xFDF2, michael@0: lammedialarabic: 0xFEE0, michael@0: lammeemhahinitialarabic: 0xFD88, michael@0: lammeeminitialarabic: 0xFCCC, michael@0: largecircle: 0x25EF, michael@0: lbar: 0x019A, michael@0: lbelt: 0x026C, michael@0: lbopomofo: 0x310C, michael@0: lcaron: 0x013E, michael@0: lcedilla: 0x013C, michael@0: lcircle: 0x24DB, michael@0: lcircumflexbelow: 0x1E3D, michael@0: lcommaaccent: 0x013C, michael@0: ldot: 0x0140, michael@0: ldotaccent: 0x0140, michael@0: ldotbelow: 0x1E37, michael@0: ldotbelowmacron: 0x1E39, michael@0: leftangleabovecmb: 0x031A, michael@0: lefttackbelowcmb: 0x0318, michael@0: less: 0x003C, michael@0: lessequal: 0x2264, michael@0: lessequalorgreater: 0x22DA, michael@0: lessmonospace: 0xFF1C, michael@0: lessorequivalent: 0x2272, michael@0: lessorgreater: 0x2276, michael@0: lessoverequal: 0x2266, michael@0: lesssmall: 0xFE64, michael@0: lezh: 0x026E, michael@0: lfblock: 0x258C, michael@0: lhookretroflex: 0x026D, michael@0: lira: 0x20A4, michael@0: liwnarmenian: 0x056C, michael@0: lj: 0x01C9, michael@0: ljecyrillic: 0x0459, michael@0: ll: 0xF6C0, michael@0: lladeva: 0x0933, michael@0: llagujarati: 0x0AB3, michael@0: llinebelow: 0x1E3B, michael@0: llladeva: 0x0934, michael@0: llvocalicbengali: 0x09E1, michael@0: llvocalicdeva: 0x0961, michael@0: llvocalicvowelsignbengali: 0x09E3, michael@0: llvocalicvowelsigndeva: 0x0963, michael@0: lmiddletilde: 0x026B, michael@0: lmonospace: 0xFF4C, michael@0: lmsquare: 0x33D0, michael@0: lochulathai: 0x0E2C, michael@0: logicaland: 0x2227, michael@0: logicalnot: 0x00AC, michael@0: logicalnotreversed: 0x2310, michael@0: logicalor: 0x2228, michael@0: lolingthai: 0x0E25, michael@0: longs: 0x017F, michael@0: lowlinecenterline: 0xFE4E, michael@0: lowlinecmb: 0x0332, michael@0: lowlinedashed: 0xFE4D, michael@0: lozenge: 0x25CA, michael@0: lparen: 0x24A7, michael@0: lslash: 0x0142, michael@0: lsquare: 0x2113, michael@0: lsuperior: 0xF6EE, michael@0: ltshade: 0x2591, michael@0: luthai: 0x0E26, michael@0: lvocalicbengali: 0x098C, michael@0: lvocalicdeva: 0x090C, michael@0: lvocalicvowelsignbengali: 0x09E2, michael@0: lvocalicvowelsigndeva: 0x0962, michael@0: lxsquare: 0x33D3, michael@0: m: 0x006D, michael@0: mabengali: 0x09AE, michael@0: macron: 0x00AF, michael@0: macronbelowcmb: 0x0331, michael@0: macroncmb: 0x0304, michael@0: macronlowmod: 0x02CD, michael@0: macronmonospace: 0xFFE3, michael@0: macute: 0x1E3F, michael@0: madeva: 0x092E, michael@0: magujarati: 0x0AAE, michael@0: magurmukhi: 0x0A2E, michael@0: mahapakhhebrew: 0x05A4, michael@0: mahapakhlefthebrew: 0x05A4, michael@0: mahiragana: 0x307E, michael@0: maichattawalowleftthai: 0xF895, michael@0: maichattawalowrightthai: 0xF894, michael@0: maichattawathai: 0x0E4B, michael@0: maichattawaupperleftthai: 0xF893, michael@0: maieklowleftthai: 0xF88C, michael@0: maieklowrightthai: 0xF88B, michael@0: maiekthai: 0x0E48, michael@0: maiekupperleftthai: 0xF88A, michael@0: maihanakatleftthai: 0xF884, michael@0: maihanakatthai: 0x0E31, michael@0: maitaikhuleftthai: 0xF889, michael@0: maitaikhuthai: 0x0E47, michael@0: maitholowleftthai: 0xF88F, michael@0: maitholowrightthai: 0xF88E, michael@0: maithothai: 0x0E49, michael@0: maithoupperleftthai: 0xF88D, michael@0: maitrilowleftthai: 0xF892, michael@0: maitrilowrightthai: 0xF891, michael@0: maitrithai: 0x0E4A, michael@0: maitriupperleftthai: 0xF890, michael@0: maiyamokthai: 0x0E46, michael@0: makatakana: 0x30DE, michael@0: makatakanahalfwidth: 0xFF8F, michael@0: male: 0x2642, michael@0: mansyonsquare: 0x3347, michael@0: maqafhebrew: 0x05BE, michael@0: mars: 0x2642, michael@0: masoracirclehebrew: 0x05AF, michael@0: masquare: 0x3383, michael@0: mbopomofo: 0x3107, michael@0: mbsquare: 0x33D4, michael@0: mcircle: 0x24DC, michael@0: mcubedsquare: 0x33A5, michael@0: mdotaccent: 0x1E41, michael@0: mdotbelow: 0x1E43, michael@0: meemarabic: 0x0645, michael@0: meemfinalarabic: 0xFEE2, michael@0: meeminitialarabic: 0xFEE3, michael@0: meemmedialarabic: 0xFEE4, michael@0: meemmeeminitialarabic: 0xFCD1, michael@0: meemmeemisolatedarabic: 0xFC48, michael@0: meetorusquare: 0x334D, michael@0: mehiragana: 0x3081, michael@0: meizierasquare: 0x337E, michael@0: mekatakana: 0x30E1, michael@0: mekatakanahalfwidth: 0xFF92, michael@0: mem: 0x05DE, michael@0: memdagesh: 0xFB3E, michael@0: memdageshhebrew: 0xFB3E, michael@0: memhebrew: 0x05DE, michael@0: menarmenian: 0x0574, michael@0: merkhahebrew: 0x05A5, michael@0: merkhakefulahebrew: 0x05A6, michael@0: merkhakefulalefthebrew: 0x05A6, michael@0: merkhalefthebrew: 0x05A5, michael@0: mhook: 0x0271, michael@0: mhzsquare: 0x3392, michael@0: middledotkatakanahalfwidth: 0xFF65, michael@0: middot: 0x00B7, michael@0: mieumacirclekorean: 0x3272, michael@0: mieumaparenkorean: 0x3212, michael@0: mieumcirclekorean: 0x3264, michael@0: mieumkorean: 0x3141, michael@0: mieumpansioskorean: 0x3170, michael@0: mieumparenkorean: 0x3204, michael@0: mieumpieupkorean: 0x316E, michael@0: mieumsioskorean: 0x316F, michael@0: mihiragana: 0x307F, michael@0: mikatakana: 0x30DF, michael@0: mikatakanahalfwidth: 0xFF90, michael@0: minus: 0x2212, michael@0: minusbelowcmb: 0x0320, michael@0: minuscircle: 0x2296, michael@0: minusmod: 0x02D7, michael@0: minusplus: 0x2213, michael@0: minute: 0x2032, michael@0: miribaarusquare: 0x334A, michael@0: mirisquare: 0x3349, michael@0: mlonglegturned: 0x0270, michael@0: mlsquare: 0x3396, michael@0: mmcubedsquare: 0x33A3, michael@0: mmonospace: 0xFF4D, michael@0: mmsquaredsquare: 0x339F, michael@0: mohiragana: 0x3082, michael@0: mohmsquare: 0x33C1, michael@0: mokatakana: 0x30E2, michael@0: mokatakanahalfwidth: 0xFF93, michael@0: molsquare: 0x33D6, michael@0: momathai: 0x0E21, michael@0: moverssquare: 0x33A7, michael@0: moverssquaredsquare: 0x33A8, michael@0: mparen: 0x24A8, michael@0: mpasquare: 0x33AB, michael@0: mssquare: 0x33B3, michael@0: msuperior: 0xF6EF, michael@0: mturned: 0x026F, michael@0: mu: 0x00B5, michael@0: mu1: 0x00B5, michael@0: muasquare: 0x3382, michael@0: muchgreater: 0x226B, michael@0: muchless: 0x226A, michael@0: mufsquare: 0x338C, michael@0: mugreek: 0x03BC, michael@0: mugsquare: 0x338D, michael@0: muhiragana: 0x3080, michael@0: mukatakana: 0x30E0, michael@0: mukatakanahalfwidth: 0xFF91, michael@0: mulsquare: 0x3395, michael@0: multiply: 0x00D7, michael@0: mumsquare: 0x339B, michael@0: munahhebrew: 0x05A3, michael@0: munahlefthebrew: 0x05A3, michael@0: musicalnote: 0x266A, michael@0: musicalnotedbl: 0x266B, michael@0: musicflatsign: 0x266D, michael@0: musicsharpsign: 0x266F, michael@0: mussquare: 0x33B2, michael@0: muvsquare: 0x33B6, michael@0: muwsquare: 0x33BC, michael@0: mvmegasquare: 0x33B9, michael@0: mvsquare: 0x33B7, michael@0: mwmegasquare: 0x33BF, michael@0: mwsquare: 0x33BD, michael@0: n: 0x006E, michael@0: nabengali: 0x09A8, michael@0: nabla: 0x2207, michael@0: nacute: 0x0144, michael@0: nadeva: 0x0928, michael@0: nagujarati: 0x0AA8, michael@0: nagurmukhi: 0x0A28, michael@0: nahiragana: 0x306A, michael@0: nakatakana: 0x30CA, michael@0: nakatakanahalfwidth: 0xFF85, michael@0: napostrophe: 0x0149, michael@0: nasquare: 0x3381, michael@0: nbopomofo: 0x310B, michael@0: nbspace: 0x00A0, michael@0: ncaron: 0x0148, michael@0: ncedilla: 0x0146, michael@0: ncircle: 0x24DD, michael@0: ncircumflexbelow: 0x1E4B, michael@0: ncommaaccent: 0x0146, michael@0: ndotaccent: 0x1E45, michael@0: ndotbelow: 0x1E47, michael@0: nehiragana: 0x306D, michael@0: nekatakana: 0x30CD, michael@0: nekatakanahalfwidth: 0xFF88, michael@0: newsheqelsign: 0x20AA, michael@0: nfsquare: 0x338B, michael@0: ngabengali: 0x0999, michael@0: ngadeva: 0x0919, michael@0: ngagujarati: 0x0A99, michael@0: ngagurmukhi: 0x0A19, michael@0: ngonguthai: 0x0E07, michael@0: nhiragana: 0x3093, michael@0: nhookleft: 0x0272, michael@0: nhookretroflex: 0x0273, michael@0: nieunacirclekorean: 0x326F, michael@0: nieunaparenkorean: 0x320F, michael@0: nieuncieuckorean: 0x3135, michael@0: nieuncirclekorean: 0x3261, michael@0: nieunhieuhkorean: 0x3136, michael@0: nieunkorean: 0x3134, michael@0: nieunpansioskorean: 0x3168, michael@0: nieunparenkorean: 0x3201, michael@0: nieunsioskorean: 0x3167, michael@0: nieuntikeutkorean: 0x3166, michael@0: nihiragana: 0x306B, michael@0: nikatakana: 0x30CB, michael@0: nikatakanahalfwidth: 0xFF86, michael@0: nikhahitleftthai: 0xF899, michael@0: nikhahitthai: 0x0E4D, michael@0: nine: 0x0039, michael@0: ninearabic: 0x0669, michael@0: ninebengali: 0x09EF, michael@0: ninecircle: 0x2468, michael@0: ninecircleinversesansserif: 0x2792, michael@0: ninedeva: 0x096F, michael@0: ninegujarati: 0x0AEF, michael@0: ninegurmukhi: 0x0A6F, michael@0: ninehackarabic: 0x0669, michael@0: ninehangzhou: 0x3029, michael@0: nineideographicparen: 0x3228, michael@0: nineinferior: 0x2089, michael@0: ninemonospace: 0xFF19, michael@0: nineoldstyle: 0xF739, michael@0: nineparen: 0x247C, michael@0: nineperiod: 0x2490, michael@0: ninepersian: 0x06F9, michael@0: nineroman: 0x2178, michael@0: ninesuperior: 0x2079, michael@0: nineteencircle: 0x2472, michael@0: nineteenparen: 0x2486, michael@0: nineteenperiod: 0x249A, michael@0: ninethai: 0x0E59, michael@0: nj: 0x01CC, michael@0: njecyrillic: 0x045A, michael@0: nkatakana: 0x30F3, michael@0: nkatakanahalfwidth: 0xFF9D, michael@0: nlegrightlong: 0x019E, michael@0: nlinebelow: 0x1E49, michael@0: nmonospace: 0xFF4E, michael@0: nmsquare: 0x339A, michael@0: nnabengali: 0x09A3, michael@0: nnadeva: 0x0923, michael@0: nnagujarati: 0x0AA3, michael@0: nnagurmukhi: 0x0A23, michael@0: nnnadeva: 0x0929, michael@0: nohiragana: 0x306E, michael@0: nokatakana: 0x30CE, michael@0: nokatakanahalfwidth: 0xFF89, michael@0: nonbreakingspace: 0x00A0, michael@0: nonenthai: 0x0E13, michael@0: nonuthai: 0x0E19, michael@0: noonarabic: 0x0646, michael@0: noonfinalarabic: 0xFEE6, michael@0: noonghunnaarabic: 0x06BA, michael@0: noonghunnafinalarabic: 0xFB9F, michael@0: nooninitialarabic: 0xFEE7, michael@0: noonjeeminitialarabic: 0xFCD2, michael@0: noonjeemisolatedarabic: 0xFC4B, michael@0: noonmedialarabic: 0xFEE8, michael@0: noonmeeminitialarabic: 0xFCD5, michael@0: noonmeemisolatedarabic: 0xFC4E, michael@0: noonnoonfinalarabic: 0xFC8D, michael@0: notcontains: 0x220C, michael@0: notelement: 0x2209, michael@0: notelementof: 0x2209, michael@0: notequal: 0x2260, michael@0: notgreater: 0x226F, michael@0: notgreaternorequal: 0x2271, michael@0: notgreaternorless: 0x2279, michael@0: notidentical: 0x2262, michael@0: notless: 0x226E, michael@0: notlessnorequal: 0x2270, michael@0: notparallel: 0x2226, michael@0: notprecedes: 0x2280, michael@0: notsubset: 0x2284, michael@0: notsucceeds: 0x2281, michael@0: notsuperset: 0x2285, michael@0: nowarmenian: 0x0576, michael@0: nparen: 0x24A9, michael@0: nssquare: 0x33B1, michael@0: nsuperior: 0x207F, michael@0: ntilde: 0x00F1, michael@0: nu: 0x03BD, michael@0: nuhiragana: 0x306C, michael@0: nukatakana: 0x30CC, michael@0: nukatakanahalfwidth: 0xFF87, michael@0: nuktabengali: 0x09BC, michael@0: nuktadeva: 0x093C, michael@0: nuktagujarati: 0x0ABC, michael@0: nuktagurmukhi: 0x0A3C, michael@0: numbersign: 0x0023, michael@0: numbersignmonospace: 0xFF03, michael@0: numbersignsmall: 0xFE5F, michael@0: numeralsigngreek: 0x0374, michael@0: numeralsignlowergreek: 0x0375, michael@0: numero: 0x2116, michael@0: nun: 0x05E0, michael@0: nundagesh: 0xFB40, michael@0: nundageshhebrew: 0xFB40, michael@0: nunhebrew: 0x05E0, michael@0: nvsquare: 0x33B5, michael@0: nwsquare: 0x33BB, michael@0: nyabengali: 0x099E, michael@0: nyadeva: 0x091E, michael@0: nyagujarati: 0x0A9E, michael@0: nyagurmukhi: 0x0A1E, michael@0: o: 0x006F, michael@0: oacute: 0x00F3, michael@0: oangthai: 0x0E2D, michael@0: obarred: 0x0275, michael@0: obarredcyrillic: 0x04E9, michael@0: obarreddieresiscyrillic: 0x04EB, michael@0: obengali: 0x0993, michael@0: obopomofo: 0x311B, michael@0: obreve: 0x014F, michael@0: ocandradeva: 0x0911, michael@0: ocandragujarati: 0x0A91, michael@0: ocandravowelsigndeva: 0x0949, michael@0: ocandravowelsigngujarati: 0x0AC9, michael@0: ocaron: 0x01D2, michael@0: ocircle: 0x24DE, michael@0: ocircumflex: 0x00F4, michael@0: ocircumflexacute: 0x1ED1, michael@0: ocircumflexdotbelow: 0x1ED9, michael@0: ocircumflexgrave: 0x1ED3, michael@0: ocircumflexhookabove: 0x1ED5, michael@0: ocircumflextilde: 0x1ED7, michael@0: ocyrillic: 0x043E, michael@0: odblacute: 0x0151, michael@0: odblgrave: 0x020D, michael@0: odeva: 0x0913, michael@0: odieresis: 0x00F6, michael@0: odieresiscyrillic: 0x04E7, michael@0: odotbelow: 0x1ECD, michael@0: oe: 0x0153, michael@0: oekorean: 0x315A, michael@0: ogonek: 0x02DB, michael@0: ogonekcmb: 0x0328, michael@0: ograve: 0x00F2, michael@0: ogujarati: 0x0A93, michael@0: oharmenian: 0x0585, michael@0: ohiragana: 0x304A, michael@0: ohookabove: 0x1ECF, michael@0: ohorn: 0x01A1, michael@0: ohornacute: 0x1EDB, michael@0: ohorndotbelow: 0x1EE3, michael@0: ohorngrave: 0x1EDD, michael@0: ohornhookabove: 0x1EDF, michael@0: ohorntilde: 0x1EE1, michael@0: ohungarumlaut: 0x0151, michael@0: oi: 0x01A3, michael@0: oinvertedbreve: 0x020F, michael@0: okatakana: 0x30AA, michael@0: okatakanahalfwidth: 0xFF75, michael@0: okorean: 0x3157, michael@0: olehebrew: 0x05AB, michael@0: omacron: 0x014D, michael@0: omacronacute: 0x1E53, michael@0: omacrongrave: 0x1E51, michael@0: omdeva: 0x0950, michael@0: omega: 0x03C9, michael@0: omega1: 0x03D6, michael@0: omegacyrillic: 0x0461, michael@0: omegalatinclosed: 0x0277, michael@0: omegaroundcyrillic: 0x047B, michael@0: omegatitlocyrillic: 0x047D, michael@0: omegatonos: 0x03CE, michael@0: omgujarati: 0x0AD0, michael@0: omicron: 0x03BF, michael@0: omicrontonos: 0x03CC, michael@0: omonospace: 0xFF4F, michael@0: one: 0x0031, michael@0: onearabic: 0x0661, michael@0: onebengali: 0x09E7, michael@0: onecircle: 0x2460, michael@0: onecircleinversesansserif: 0x278A, michael@0: onedeva: 0x0967, michael@0: onedotenleader: 0x2024, michael@0: oneeighth: 0x215B, michael@0: onefitted: 0xF6DC, michael@0: onegujarati: 0x0AE7, michael@0: onegurmukhi: 0x0A67, michael@0: onehackarabic: 0x0661, michael@0: onehalf: 0x00BD, michael@0: onehangzhou: 0x3021, michael@0: oneideographicparen: 0x3220, michael@0: oneinferior: 0x2081, michael@0: onemonospace: 0xFF11, michael@0: onenumeratorbengali: 0x09F4, michael@0: oneoldstyle: 0xF731, michael@0: oneparen: 0x2474, michael@0: oneperiod: 0x2488, michael@0: onepersian: 0x06F1, michael@0: onequarter: 0x00BC, michael@0: oneroman: 0x2170, michael@0: onesuperior: 0x00B9, michael@0: onethai: 0x0E51, michael@0: onethird: 0x2153, michael@0: oogonek: 0x01EB, michael@0: oogonekmacron: 0x01ED, michael@0: oogurmukhi: 0x0A13, michael@0: oomatragurmukhi: 0x0A4B, michael@0: oopen: 0x0254, michael@0: oparen: 0x24AA, michael@0: openbullet: 0x25E6, michael@0: option: 0x2325, michael@0: ordfeminine: 0x00AA, michael@0: ordmasculine: 0x00BA, michael@0: orthogonal: 0x221F, michael@0: oshortdeva: 0x0912, michael@0: oshortvowelsigndeva: 0x094A, michael@0: oslash: 0x00F8, michael@0: oslashacute: 0x01FF, michael@0: osmallhiragana: 0x3049, michael@0: osmallkatakana: 0x30A9, michael@0: osmallkatakanahalfwidth: 0xFF6B, michael@0: ostrokeacute: 0x01FF, michael@0: osuperior: 0xF6F0, michael@0: otcyrillic: 0x047F, michael@0: otilde: 0x00F5, michael@0: otildeacute: 0x1E4D, michael@0: otildedieresis: 0x1E4F, michael@0: oubopomofo: 0x3121, michael@0: overline: 0x203E, michael@0: overlinecenterline: 0xFE4A, michael@0: overlinecmb: 0x0305, michael@0: overlinedashed: 0xFE49, michael@0: overlinedblwavy: 0xFE4C, michael@0: overlinewavy: 0xFE4B, michael@0: overscore: 0x00AF, michael@0: ovowelsignbengali: 0x09CB, michael@0: ovowelsigndeva: 0x094B, michael@0: ovowelsigngujarati: 0x0ACB, michael@0: p: 0x0070, michael@0: paampssquare: 0x3380, michael@0: paasentosquare: 0x332B, michael@0: pabengali: 0x09AA, michael@0: pacute: 0x1E55, michael@0: padeva: 0x092A, michael@0: pagedown: 0x21DF, michael@0: pageup: 0x21DE, michael@0: pagujarati: 0x0AAA, michael@0: pagurmukhi: 0x0A2A, michael@0: pahiragana: 0x3071, michael@0: paiyannoithai: 0x0E2F, michael@0: pakatakana: 0x30D1, michael@0: palatalizationcyrilliccmb: 0x0484, michael@0: palochkacyrillic: 0x04C0, michael@0: pansioskorean: 0x317F, michael@0: paragraph: 0x00B6, michael@0: parallel: 0x2225, michael@0: parenleft: 0x0028, michael@0: parenleftaltonearabic: 0xFD3E, michael@0: parenleftbt: 0xF8ED, michael@0: parenleftex: 0xF8EC, michael@0: parenleftinferior: 0x208D, michael@0: parenleftmonospace: 0xFF08, michael@0: parenleftsmall: 0xFE59, michael@0: parenleftsuperior: 0x207D, michael@0: parenlefttp: 0xF8EB, michael@0: parenleftvertical: 0xFE35, michael@0: parenright: 0x0029, michael@0: parenrightaltonearabic: 0xFD3F, michael@0: parenrightbt: 0xF8F8, michael@0: parenrightex: 0xF8F7, michael@0: parenrightinferior: 0x208E, michael@0: parenrightmonospace: 0xFF09, michael@0: parenrightsmall: 0xFE5A, michael@0: parenrightsuperior: 0x207E, michael@0: parenrighttp: 0xF8F6, michael@0: parenrightvertical: 0xFE36, michael@0: partialdiff: 0x2202, michael@0: paseqhebrew: 0x05C0, michael@0: pashtahebrew: 0x0599, michael@0: pasquare: 0x33A9, michael@0: patah: 0x05B7, michael@0: patah11: 0x05B7, michael@0: patah1d: 0x05B7, michael@0: patah2a: 0x05B7, michael@0: patahhebrew: 0x05B7, michael@0: patahnarrowhebrew: 0x05B7, michael@0: patahquarterhebrew: 0x05B7, michael@0: patahwidehebrew: 0x05B7, michael@0: pazerhebrew: 0x05A1, michael@0: pbopomofo: 0x3106, michael@0: pcircle: 0x24DF, michael@0: pdotaccent: 0x1E57, michael@0: pe: 0x05E4, michael@0: pecyrillic: 0x043F, michael@0: pedagesh: 0xFB44, michael@0: pedageshhebrew: 0xFB44, michael@0: peezisquare: 0x333B, michael@0: pefinaldageshhebrew: 0xFB43, michael@0: peharabic: 0x067E, michael@0: peharmenian: 0x057A, michael@0: pehebrew: 0x05E4, michael@0: pehfinalarabic: 0xFB57, michael@0: pehinitialarabic: 0xFB58, michael@0: pehiragana: 0x307A, michael@0: pehmedialarabic: 0xFB59, michael@0: pekatakana: 0x30DA, michael@0: pemiddlehookcyrillic: 0x04A7, michael@0: perafehebrew: 0xFB4E, michael@0: percent: 0x0025, michael@0: percentarabic: 0x066A, michael@0: percentmonospace: 0xFF05, michael@0: percentsmall: 0xFE6A, michael@0: period: 0x002E, michael@0: periodarmenian: 0x0589, michael@0: periodcentered: 0x00B7, michael@0: periodhalfwidth: 0xFF61, michael@0: periodinferior: 0xF6E7, michael@0: periodmonospace: 0xFF0E, michael@0: periodsmall: 0xFE52, michael@0: periodsuperior: 0xF6E8, michael@0: perispomenigreekcmb: 0x0342, michael@0: perpendicular: 0x22A5, michael@0: perthousand: 0x2030, michael@0: peseta: 0x20A7, michael@0: pfsquare: 0x338A, michael@0: phabengali: 0x09AB, michael@0: phadeva: 0x092B, michael@0: phagujarati: 0x0AAB, michael@0: phagurmukhi: 0x0A2B, michael@0: phi: 0x03C6, michael@0: phi1: 0x03D5, michael@0: phieuphacirclekorean: 0x327A, michael@0: phieuphaparenkorean: 0x321A, michael@0: phieuphcirclekorean: 0x326C, michael@0: phieuphkorean: 0x314D, michael@0: phieuphparenkorean: 0x320C, michael@0: philatin: 0x0278, michael@0: phinthuthai: 0x0E3A, michael@0: phisymbolgreek: 0x03D5, michael@0: phook: 0x01A5, michael@0: phophanthai: 0x0E1E, michael@0: phophungthai: 0x0E1C, michael@0: phosamphaothai: 0x0E20, michael@0: pi: 0x03C0, michael@0: pieupacirclekorean: 0x3273, michael@0: pieupaparenkorean: 0x3213, michael@0: pieupcieuckorean: 0x3176, michael@0: pieupcirclekorean: 0x3265, michael@0: pieupkiyeokkorean: 0x3172, michael@0: pieupkorean: 0x3142, michael@0: pieupparenkorean: 0x3205, michael@0: pieupsioskiyeokkorean: 0x3174, michael@0: pieupsioskorean: 0x3144, michael@0: pieupsiostikeutkorean: 0x3175, michael@0: pieupthieuthkorean: 0x3177, michael@0: pieuptikeutkorean: 0x3173, michael@0: pihiragana: 0x3074, michael@0: pikatakana: 0x30D4, michael@0: pisymbolgreek: 0x03D6, michael@0: piwrarmenian: 0x0583, michael@0: plus: 0x002B, michael@0: plusbelowcmb: 0x031F, michael@0: pluscircle: 0x2295, michael@0: plusminus: 0x00B1, michael@0: plusmod: 0x02D6, michael@0: plusmonospace: 0xFF0B, michael@0: plussmall: 0xFE62, michael@0: plussuperior: 0x207A, michael@0: pmonospace: 0xFF50, michael@0: pmsquare: 0x33D8, michael@0: pohiragana: 0x307D, michael@0: pointingindexdownwhite: 0x261F, michael@0: pointingindexleftwhite: 0x261C, michael@0: pointingindexrightwhite: 0x261E, michael@0: pointingindexupwhite: 0x261D, michael@0: pokatakana: 0x30DD, michael@0: poplathai: 0x0E1B, michael@0: postalmark: 0x3012, michael@0: postalmarkface: 0x3020, michael@0: pparen: 0x24AB, michael@0: precedes: 0x227A, michael@0: prescription: 0x211E, michael@0: primemod: 0x02B9, michael@0: primereversed: 0x2035, michael@0: product: 0x220F, michael@0: projective: 0x2305, michael@0: prolongedkana: 0x30FC, michael@0: propellor: 0x2318, michael@0: propersubset: 0x2282, michael@0: propersuperset: 0x2283, michael@0: proportion: 0x2237, michael@0: proportional: 0x221D, michael@0: psi: 0x03C8, michael@0: psicyrillic: 0x0471, michael@0: psilipneumatacyrilliccmb: 0x0486, michael@0: pssquare: 0x33B0, michael@0: puhiragana: 0x3077, michael@0: pukatakana: 0x30D7, michael@0: pvsquare: 0x33B4, michael@0: pwsquare: 0x33BA, michael@0: q: 0x0071, michael@0: qadeva: 0x0958, michael@0: qadmahebrew: 0x05A8, michael@0: qafarabic: 0x0642, michael@0: qaffinalarabic: 0xFED6, michael@0: qafinitialarabic: 0xFED7, michael@0: qafmedialarabic: 0xFED8, michael@0: qamats: 0x05B8, michael@0: qamats10: 0x05B8, michael@0: qamats1a: 0x05B8, michael@0: qamats1c: 0x05B8, michael@0: qamats27: 0x05B8, michael@0: qamats29: 0x05B8, michael@0: qamats33: 0x05B8, michael@0: qamatsde: 0x05B8, michael@0: qamatshebrew: 0x05B8, michael@0: qamatsnarrowhebrew: 0x05B8, michael@0: qamatsqatanhebrew: 0x05B8, michael@0: qamatsqatannarrowhebrew: 0x05B8, michael@0: qamatsqatanquarterhebrew: 0x05B8, michael@0: qamatsqatanwidehebrew: 0x05B8, michael@0: qamatsquarterhebrew: 0x05B8, michael@0: qamatswidehebrew: 0x05B8, michael@0: qarneyparahebrew: 0x059F, michael@0: qbopomofo: 0x3111, michael@0: qcircle: 0x24E0, michael@0: qhook: 0x02A0, michael@0: qmonospace: 0xFF51, michael@0: qof: 0x05E7, michael@0: qofdagesh: 0xFB47, michael@0: qofdageshhebrew: 0xFB47, michael@0: qofhebrew: 0x05E7, michael@0: qparen: 0x24AC, michael@0: quarternote: 0x2669, michael@0: qubuts: 0x05BB, michael@0: qubuts18: 0x05BB, michael@0: qubuts25: 0x05BB, michael@0: qubuts31: 0x05BB, michael@0: qubutshebrew: 0x05BB, michael@0: qubutsnarrowhebrew: 0x05BB, michael@0: qubutsquarterhebrew: 0x05BB, michael@0: qubutswidehebrew: 0x05BB, michael@0: question: 0x003F, michael@0: questionarabic: 0x061F, michael@0: questionarmenian: 0x055E, michael@0: questiondown: 0x00BF, michael@0: questiondownsmall: 0xF7BF, michael@0: questiongreek: 0x037E, michael@0: questionmonospace: 0xFF1F, michael@0: questionsmall: 0xF73F, michael@0: quotedbl: 0x0022, michael@0: quotedblbase: 0x201E, michael@0: quotedblleft: 0x201C, michael@0: quotedblmonospace: 0xFF02, michael@0: quotedblprime: 0x301E, michael@0: quotedblprimereversed: 0x301D, michael@0: quotedblright: 0x201D, michael@0: quoteleft: 0x2018, michael@0: quoteleftreversed: 0x201B, michael@0: quotereversed: 0x201B, michael@0: quoteright: 0x2019, michael@0: quoterightn: 0x0149, michael@0: quotesinglbase: 0x201A, michael@0: quotesingle: 0x0027, michael@0: quotesinglemonospace: 0xFF07, michael@0: r: 0x0072, michael@0: raarmenian: 0x057C, michael@0: rabengali: 0x09B0, michael@0: racute: 0x0155, michael@0: radeva: 0x0930, michael@0: radical: 0x221A, michael@0: radicalex: 0xF8E5, michael@0: radoverssquare: 0x33AE, michael@0: radoverssquaredsquare: 0x33AF, michael@0: radsquare: 0x33AD, michael@0: rafe: 0x05BF, michael@0: rafehebrew: 0x05BF, michael@0: ragujarati: 0x0AB0, michael@0: ragurmukhi: 0x0A30, michael@0: rahiragana: 0x3089, michael@0: rakatakana: 0x30E9, michael@0: rakatakanahalfwidth: 0xFF97, michael@0: ralowerdiagonalbengali: 0x09F1, michael@0: ramiddlediagonalbengali: 0x09F0, michael@0: ramshorn: 0x0264, michael@0: ratio: 0x2236, michael@0: rbopomofo: 0x3116, michael@0: rcaron: 0x0159, michael@0: rcedilla: 0x0157, michael@0: rcircle: 0x24E1, michael@0: rcommaaccent: 0x0157, michael@0: rdblgrave: 0x0211, michael@0: rdotaccent: 0x1E59, michael@0: rdotbelow: 0x1E5B, michael@0: rdotbelowmacron: 0x1E5D, michael@0: referencemark: 0x203B, michael@0: reflexsubset: 0x2286, michael@0: reflexsuperset: 0x2287, michael@0: registered: 0x00AE, michael@0: registersans: 0xF8E8, michael@0: registerserif: 0xF6DA, michael@0: reharabic: 0x0631, michael@0: reharmenian: 0x0580, michael@0: rehfinalarabic: 0xFEAE, michael@0: rehiragana: 0x308C, michael@0: rekatakana: 0x30EC, michael@0: rekatakanahalfwidth: 0xFF9A, michael@0: resh: 0x05E8, michael@0: reshdageshhebrew: 0xFB48, michael@0: reshhebrew: 0x05E8, michael@0: reversedtilde: 0x223D, michael@0: reviahebrew: 0x0597, michael@0: reviamugrashhebrew: 0x0597, michael@0: revlogicalnot: 0x2310, michael@0: rfishhook: 0x027E, michael@0: rfishhookreversed: 0x027F, michael@0: rhabengali: 0x09DD, michael@0: rhadeva: 0x095D, michael@0: rho: 0x03C1, michael@0: rhook: 0x027D, michael@0: rhookturned: 0x027B, michael@0: rhookturnedsuperior: 0x02B5, michael@0: rhosymbolgreek: 0x03F1, michael@0: rhotichookmod: 0x02DE, michael@0: rieulacirclekorean: 0x3271, michael@0: rieulaparenkorean: 0x3211, michael@0: rieulcirclekorean: 0x3263, michael@0: rieulhieuhkorean: 0x3140, michael@0: rieulkiyeokkorean: 0x313A, michael@0: rieulkiyeoksioskorean: 0x3169, michael@0: rieulkorean: 0x3139, michael@0: rieulmieumkorean: 0x313B, michael@0: rieulpansioskorean: 0x316C, michael@0: rieulparenkorean: 0x3203, michael@0: rieulphieuphkorean: 0x313F, michael@0: rieulpieupkorean: 0x313C, michael@0: rieulpieupsioskorean: 0x316B, michael@0: rieulsioskorean: 0x313D, michael@0: rieulthieuthkorean: 0x313E, michael@0: rieultikeutkorean: 0x316A, michael@0: rieulyeorinhieuhkorean: 0x316D, michael@0: rightangle: 0x221F, michael@0: righttackbelowcmb: 0x0319, michael@0: righttriangle: 0x22BF, michael@0: rihiragana: 0x308A, michael@0: rikatakana: 0x30EA, michael@0: rikatakanahalfwidth: 0xFF98, michael@0: ring: 0x02DA, michael@0: ringbelowcmb: 0x0325, michael@0: ringcmb: 0x030A, michael@0: ringhalfleft: 0x02BF, michael@0: ringhalfleftarmenian: 0x0559, michael@0: ringhalfleftbelowcmb: 0x031C, michael@0: ringhalfleftcentered: 0x02D3, michael@0: ringhalfright: 0x02BE, michael@0: ringhalfrightbelowcmb: 0x0339, michael@0: ringhalfrightcentered: 0x02D2, michael@0: rinvertedbreve: 0x0213, michael@0: rittorusquare: 0x3351, michael@0: rlinebelow: 0x1E5F, michael@0: rlongleg: 0x027C, michael@0: rlonglegturned: 0x027A, michael@0: rmonospace: 0xFF52, michael@0: rohiragana: 0x308D, michael@0: rokatakana: 0x30ED, michael@0: rokatakanahalfwidth: 0xFF9B, michael@0: roruathai: 0x0E23, michael@0: rparen: 0x24AD, michael@0: rrabengali: 0x09DC, michael@0: rradeva: 0x0931, michael@0: rragurmukhi: 0x0A5C, michael@0: rreharabic: 0x0691, michael@0: rrehfinalarabic: 0xFB8D, michael@0: rrvocalicbengali: 0x09E0, michael@0: rrvocalicdeva: 0x0960, michael@0: rrvocalicgujarati: 0x0AE0, michael@0: rrvocalicvowelsignbengali: 0x09C4, michael@0: rrvocalicvowelsigndeva: 0x0944, michael@0: rrvocalicvowelsigngujarati: 0x0AC4, michael@0: rsuperior: 0xF6F1, michael@0: rtblock: 0x2590, michael@0: rturned: 0x0279, michael@0: rturnedsuperior: 0x02B4, michael@0: ruhiragana: 0x308B, michael@0: rukatakana: 0x30EB, michael@0: rukatakanahalfwidth: 0xFF99, michael@0: rupeemarkbengali: 0x09F2, michael@0: rupeesignbengali: 0x09F3, michael@0: rupiah: 0xF6DD, michael@0: ruthai: 0x0E24, michael@0: rvocalicbengali: 0x098B, michael@0: rvocalicdeva: 0x090B, michael@0: rvocalicgujarati: 0x0A8B, michael@0: rvocalicvowelsignbengali: 0x09C3, michael@0: rvocalicvowelsigndeva: 0x0943, michael@0: rvocalicvowelsigngujarati: 0x0AC3, michael@0: s: 0x0073, michael@0: sabengali: 0x09B8, michael@0: sacute: 0x015B, michael@0: sacutedotaccent: 0x1E65, michael@0: sadarabic: 0x0635, michael@0: sadeva: 0x0938, michael@0: sadfinalarabic: 0xFEBA, michael@0: sadinitialarabic: 0xFEBB, michael@0: sadmedialarabic: 0xFEBC, michael@0: sagujarati: 0x0AB8, michael@0: sagurmukhi: 0x0A38, michael@0: sahiragana: 0x3055, michael@0: sakatakana: 0x30B5, michael@0: sakatakanahalfwidth: 0xFF7B, michael@0: sallallahoualayhewasallamarabic: 0xFDFA, michael@0: samekh: 0x05E1, michael@0: samekhdagesh: 0xFB41, michael@0: samekhdageshhebrew: 0xFB41, michael@0: samekhhebrew: 0x05E1, michael@0: saraaathai: 0x0E32, michael@0: saraaethai: 0x0E41, michael@0: saraaimaimalaithai: 0x0E44, michael@0: saraaimaimuanthai: 0x0E43, michael@0: saraamthai: 0x0E33, michael@0: saraathai: 0x0E30, michael@0: saraethai: 0x0E40, michael@0: saraiileftthai: 0xF886, michael@0: saraiithai: 0x0E35, michael@0: saraileftthai: 0xF885, michael@0: saraithai: 0x0E34, michael@0: saraothai: 0x0E42, michael@0: saraueeleftthai: 0xF888, michael@0: saraueethai: 0x0E37, michael@0: saraueleftthai: 0xF887, michael@0: sarauethai: 0x0E36, michael@0: sarauthai: 0x0E38, michael@0: sarauuthai: 0x0E39, michael@0: sbopomofo: 0x3119, michael@0: scaron: 0x0161, michael@0: scarondotaccent: 0x1E67, michael@0: scedilla: 0x015F, michael@0: schwa: 0x0259, michael@0: schwacyrillic: 0x04D9, michael@0: schwadieresiscyrillic: 0x04DB, michael@0: schwahook: 0x025A, michael@0: scircle: 0x24E2, michael@0: scircumflex: 0x015D, michael@0: scommaaccent: 0x0219, michael@0: sdotaccent: 0x1E61, michael@0: sdotbelow: 0x1E63, michael@0: sdotbelowdotaccent: 0x1E69, michael@0: seagullbelowcmb: 0x033C, michael@0: second: 0x2033, michael@0: secondtonechinese: 0x02CA, michael@0: section: 0x00A7, michael@0: seenarabic: 0x0633, michael@0: seenfinalarabic: 0xFEB2, michael@0: seeninitialarabic: 0xFEB3, michael@0: seenmedialarabic: 0xFEB4, michael@0: segol: 0x05B6, michael@0: segol13: 0x05B6, michael@0: segol1f: 0x05B6, michael@0: segol2c: 0x05B6, michael@0: segolhebrew: 0x05B6, michael@0: segolnarrowhebrew: 0x05B6, michael@0: segolquarterhebrew: 0x05B6, michael@0: segoltahebrew: 0x0592, michael@0: segolwidehebrew: 0x05B6, michael@0: seharmenian: 0x057D, michael@0: sehiragana: 0x305B, michael@0: sekatakana: 0x30BB, michael@0: sekatakanahalfwidth: 0xFF7E, michael@0: semicolon: 0x003B, michael@0: semicolonarabic: 0x061B, michael@0: semicolonmonospace: 0xFF1B, michael@0: semicolonsmall: 0xFE54, michael@0: semivoicedmarkkana: 0x309C, michael@0: semivoicedmarkkanahalfwidth: 0xFF9F, michael@0: sentisquare: 0x3322, michael@0: sentosquare: 0x3323, michael@0: seven: 0x0037, michael@0: sevenarabic: 0x0667, michael@0: sevenbengali: 0x09ED, michael@0: sevencircle: 0x2466, michael@0: sevencircleinversesansserif: 0x2790, michael@0: sevendeva: 0x096D, michael@0: seveneighths: 0x215E, michael@0: sevengujarati: 0x0AED, michael@0: sevengurmukhi: 0x0A6D, michael@0: sevenhackarabic: 0x0667, michael@0: sevenhangzhou: 0x3027, michael@0: sevenideographicparen: 0x3226, michael@0: seveninferior: 0x2087, michael@0: sevenmonospace: 0xFF17, michael@0: sevenoldstyle: 0xF737, michael@0: sevenparen: 0x247A, michael@0: sevenperiod: 0x248E, michael@0: sevenpersian: 0x06F7, michael@0: sevenroman: 0x2176, michael@0: sevensuperior: 0x2077, michael@0: seventeencircle: 0x2470, michael@0: seventeenparen: 0x2484, michael@0: seventeenperiod: 0x2498, michael@0: seventhai: 0x0E57, michael@0: sfthyphen: 0x00AD, michael@0: shaarmenian: 0x0577, michael@0: shabengali: 0x09B6, michael@0: shacyrillic: 0x0448, michael@0: shaddaarabic: 0x0651, michael@0: shaddadammaarabic: 0xFC61, michael@0: shaddadammatanarabic: 0xFC5E, michael@0: shaddafathaarabic: 0xFC60, michael@0: shaddakasraarabic: 0xFC62, michael@0: shaddakasratanarabic: 0xFC5F, michael@0: shade: 0x2592, michael@0: shadedark: 0x2593, michael@0: shadelight: 0x2591, michael@0: shademedium: 0x2592, michael@0: shadeva: 0x0936, michael@0: shagujarati: 0x0AB6, michael@0: shagurmukhi: 0x0A36, michael@0: shalshelethebrew: 0x0593, michael@0: shbopomofo: 0x3115, michael@0: shchacyrillic: 0x0449, michael@0: sheenarabic: 0x0634, michael@0: sheenfinalarabic: 0xFEB6, michael@0: sheeninitialarabic: 0xFEB7, michael@0: sheenmedialarabic: 0xFEB8, michael@0: sheicoptic: 0x03E3, michael@0: sheqel: 0x20AA, michael@0: sheqelhebrew: 0x20AA, michael@0: sheva: 0x05B0, michael@0: sheva115: 0x05B0, michael@0: sheva15: 0x05B0, michael@0: sheva22: 0x05B0, michael@0: sheva2e: 0x05B0, michael@0: shevahebrew: 0x05B0, michael@0: shevanarrowhebrew: 0x05B0, michael@0: shevaquarterhebrew: 0x05B0, michael@0: shevawidehebrew: 0x05B0, michael@0: shhacyrillic: 0x04BB, michael@0: shimacoptic: 0x03ED, michael@0: shin: 0x05E9, michael@0: shindagesh: 0xFB49, michael@0: shindageshhebrew: 0xFB49, michael@0: shindageshshindot: 0xFB2C, michael@0: shindageshshindothebrew: 0xFB2C, michael@0: shindageshsindot: 0xFB2D, michael@0: shindageshsindothebrew: 0xFB2D, michael@0: shindothebrew: 0x05C1, michael@0: shinhebrew: 0x05E9, michael@0: shinshindot: 0xFB2A, michael@0: shinshindothebrew: 0xFB2A, michael@0: shinsindot: 0xFB2B, michael@0: shinsindothebrew: 0xFB2B, michael@0: shook: 0x0282, michael@0: sigma: 0x03C3, michael@0: sigma1: 0x03C2, michael@0: sigmafinal: 0x03C2, michael@0: sigmalunatesymbolgreek: 0x03F2, michael@0: sihiragana: 0x3057, michael@0: sikatakana: 0x30B7, michael@0: sikatakanahalfwidth: 0xFF7C, michael@0: siluqhebrew: 0x05BD, michael@0: siluqlefthebrew: 0x05BD, michael@0: similar: 0x223C, michael@0: sindothebrew: 0x05C2, michael@0: siosacirclekorean: 0x3274, michael@0: siosaparenkorean: 0x3214, michael@0: sioscieuckorean: 0x317E, michael@0: sioscirclekorean: 0x3266, michael@0: sioskiyeokkorean: 0x317A, michael@0: sioskorean: 0x3145, michael@0: siosnieunkorean: 0x317B, michael@0: siosparenkorean: 0x3206, michael@0: siospieupkorean: 0x317D, michael@0: siostikeutkorean: 0x317C, michael@0: six: 0x0036, michael@0: sixarabic: 0x0666, michael@0: sixbengali: 0x09EC, michael@0: sixcircle: 0x2465, michael@0: sixcircleinversesansserif: 0x278F, michael@0: sixdeva: 0x096C, michael@0: sixgujarati: 0x0AEC, michael@0: sixgurmukhi: 0x0A6C, michael@0: sixhackarabic: 0x0666, michael@0: sixhangzhou: 0x3026, michael@0: sixideographicparen: 0x3225, michael@0: sixinferior: 0x2086, michael@0: sixmonospace: 0xFF16, michael@0: sixoldstyle: 0xF736, michael@0: sixparen: 0x2479, michael@0: sixperiod: 0x248D, michael@0: sixpersian: 0x06F6, michael@0: sixroman: 0x2175, michael@0: sixsuperior: 0x2076, michael@0: sixteencircle: 0x246F, michael@0: sixteencurrencydenominatorbengali: 0x09F9, michael@0: sixteenparen: 0x2483, michael@0: sixteenperiod: 0x2497, michael@0: sixthai: 0x0E56, michael@0: slash: 0x002F, michael@0: slashmonospace: 0xFF0F, michael@0: slong: 0x017F, michael@0: slongdotaccent: 0x1E9B, michael@0: smileface: 0x263A, michael@0: smonospace: 0xFF53, michael@0: sofpasuqhebrew: 0x05C3, michael@0: softhyphen: 0x00AD, michael@0: softsigncyrillic: 0x044C, michael@0: sohiragana: 0x305D, michael@0: sokatakana: 0x30BD, michael@0: sokatakanahalfwidth: 0xFF7F, michael@0: soliduslongoverlaycmb: 0x0338, michael@0: solidusshortoverlaycmb: 0x0337, michael@0: sorusithai: 0x0E29, michael@0: sosalathai: 0x0E28, michael@0: sosothai: 0x0E0B, michael@0: sosuathai: 0x0E2A, michael@0: space: 0x0020, michael@0: spacehackarabic: 0x0020, michael@0: spade: 0x2660, michael@0: spadesuitblack: 0x2660, michael@0: spadesuitwhite: 0x2664, michael@0: sparen: 0x24AE, michael@0: squarebelowcmb: 0x033B, michael@0: squarecc: 0x33C4, michael@0: squarecm: 0x339D, michael@0: squarediagonalcrosshatchfill: 0x25A9, michael@0: squarehorizontalfill: 0x25A4, michael@0: squarekg: 0x338F, michael@0: squarekm: 0x339E, michael@0: squarekmcapital: 0x33CE, michael@0: squareln: 0x33D1, michael@0: squarelog: 0x33D2, michael@0: squaremg: 0x338E, michael@0: squaremil: 0x33D5, michael@0: squaremm: 0x339C, michael@0: squaremsquared: 0x33A1, michael@0: squareorthogonalcrosshatchfill: 0x25A6, michael@0: squareupperlefttolowerrightfill: 0x25A7, michael@0: squareupperrighttolowerleftfill: 0x25A8, michael@0: squareverticalfill: 0x25A5, michael@0: squarewhitewithsmallblack: 0x25A3, michael@0: srsquare: 0x33DB, michael@0: ssabengali: 0x09B7, michael@0: ssadeva: 0x0937, michael@0: ssagujarati: 0x0AB7, michael@0: ssangcieuckorean: 0x3149, michael@0: ssanghieuhkorean: 0x3185, michael@0: ssangieungkorean: 0x3180, michael@0: ssangkiyeokkorean: 0x3132, michael@0: ssangnieunkorean: 0x3165, michael@0: ssangpieupkorean: 0x3143, michael@0: ssangsioskorean: 0x3146, michael@0: ssangtikeutkorean: 0x3138, michael@0: ssuperior: 0xF6F2, michael@0: sterling: 0x00A3, michael@0: sterlingmonospace: 0xFFE1, michael@0: strokelongoverlaycmb: 0x0336, michael@0: strokeshortoverlaycmb: 0x0335, michael@0: subset: 0x2282, michael@0: subsetnotequal: 0x228A, michael@0: subsetorequal: 0x2286, michael@0: succeeds: 0x227B, michael@0: suchthat: 0x220B, michael@0: suhiragana: 0x3059, michael@0: sukatakana: 0x30B9, michael@0: sukatakanahalfwidth: 0xFF7D, michael@0: sukunarabic: 0x0652, michael@0: summation: 0x2211, michael@0: sun: 0x263C, michael@0: superset: 0x2283, michael@0: supersetnotequal: 0x228B, michael@0: supersetorequal: 0x2287, michael@0: svsquare: 0x33DC, michael@0: syouwaerasquare: 0x337C, michael@0: t: 0x0074, michael@0: tabengali: 0x09A4, michael@0: tackdown: 0x22A4, michael@0: tackleft: 0x22A3, michael@0: tadeva: 0x0924, michael@0: tagujarati: 0x0AA4, michael@0: tagurmukhi: 0x0A24, michael@0: taharabic: 0x0637, michael@0: tahfinalarabic: 0xFEC2, michael@0: tahinitialarabic: 0xFEC3, michael@0: tahiragana: 0x305F, michael@0: tahmedialarabic: 0xFEC4, michael@0: taisyouerasquare: 0x337D, michael@0: takatakana: 0x30BF, michael@0: takatakanahalfwidth: 0xFF80, michael@0: tatweelarabic: 0x0640, michael@0: tau: 0x03C4, michael@0: tav: 0x05EA, michael@0: tavdages: 0xFB4A, michael@0: tavdagesh: 0xFB4A, michael@0: tavdageshhebrew: 0xFB4A, michael@0: tavhebrew: 0x05EA, michael@0: tbar: 0x0167, michael@0: tbopomofo: 0x310A, michael@0: tcaron: 0x0165, michael@0: tccurl: 0x02A8, michael@0: tcedilla: 0x0163, michael@0: tcheharabic: 0x0686, michael@0: tchehfinalarabic: 0xFB7B, michael@0: tchehinitialarabic: 0xFB7C, michael@0: tchehmedialarabic: 0xFB7D, michael@0: tcircle: 0x24E3, michael@0: tcircumflexbelow: 0x1E71, michael@0: tcommaaccent: 0x0163, michael@0: tdieresis: 0x1E97, michael@0: tdotaccent: 0x1E6B, michael@0: tdotbelow: 0x1E6D, michael@0: tecyrillic: 0x0442, michael@0: tedescendercyrillic: 0x04AD, michael@0: teharabic: 0x062A, michael@0: tehfinalarabic: 0xFE96, michael@0: tehhahinitialarabic: 0xFCA2, michael@0: tehhahisolatedarabic: 0xFC0C, michael@0: tehinitialarabic: 0xFE97, michael@0: tehiragana: 0x3066, michael@0: tehjeeminitialarabic: 0xFCA1, michael@0: tehjeemisolatedarabic: 0xFC0B, michael@0: tehmarbutaarabic: 0x0629, michael@0: tehmarbutafinalarabic: 0xFE94, michael@0: tehmedialarabic: 0xFE98, michael@0: tehmeeminitialarabic: 0xFCA4, michael@0: tehmeemisolatedarabic: 0xFC0E, michael@0: tehnoonfinalarabic: 0xFC73, michael@0: tekatakana: 0x30C6, michael@0: tekatakanahalfwidth: 0xFF83, michael@0: telephone: 0x2121, michael@0: telephoneblack: 0x260E, michael@0: telishagedolahebrew: 0x05A0, michael@0: telishaqetanahebrew: 0x05A9, michael@0: tencircle: 0x2469, michael@0: tenideographicparen: 0x3229, michael@0: tenparen: 0x247D, michael@0: tenperiod: 0x2491, michael@0: tenroman: 0x2179, michael@0: tesh: 0x02A7, michael@0: tet: 0x05D8, michael@0: tetdagesh: 0xFB38, michael@0: tetdageshhebrew: 0xFB38, michael@0: tethebrew: 0x05D8, michael@0: tetsecyrillic: 0x04B5, michael@0: tevirhebrew: 0x059B, michael@0: tevirlefthebrew: 0x059B, michael@0: thabengali: 0x09A5, michael@0: thadeva: 0x0925, michael@0: thagujarati: 0x0AA5, michael@0: thagurmukhi: 0x0A25, michael@0: thalarabic: 0x0630, michael@0: thalfinalarabic: 0xFEAC, michael@0: thanthakhatlowleftthai: 0xF898, michael@0: thanthakhatlowrightthai: 0xF897, michael@0: thanthakhatthai: 0x0E4C, michael@0: thanthakhatupperleftthai: 0xF896, michael@0: theharabic: 0x062B, michael@0: thehfinalarabic: 0xFE9A, michael@0: thehinitialarabic: 0xFE9B, michael@0: thehmedialarabic: 0xFE9C, michael@0: thereexists: 0x2203, michael@0: therefore: 0x2234, michael@0: theta: 0x03B8, michael@0: theta1: 0x03D1, michael@0: thetasymbolgreek: 0x03D1, michael@0: thieuthacirclekorean: 0x3279, michael@0: thieuthaparenkorean: 0x3219, michael@0: thieuthcirclekorean: 0x326B, michael@0: thieuthkorean: 0x314C, michael@0: thieuthparenkorean: 0x320B, michael@0: thirteencircle: 0x246C, michael@0: thirteenparen: 0x2480, michael@0: thirteenperiod: 0x2494, michael@0: thonangmonthothai: 0x0E11, michael@0: thook: 0x01AD, michael@0: thophuthaothai: 0x0E12, michael@0: thorn: 0x00FE, michael@0: thothahanthai: 0x0E17, michael@0: thothanthai: 0x0E10, michael@0: thothongthai: 0x0E18, michael@0: thothungthai: 0x0E16, michael@0: thousandcyrillic: 0x0482, michael@0: thousandsseparatorarabic: 0x066C, michael@0: thousandsseparatorpersian: 0x066C, michael@0: three: 0x0033, michael@0: threearabic: 0x0663, michael@0: threebengali: 0x09E9, michael@0: threecircle: 0x2462, michael@0: threecircleinversesansserif: 0x278C, michael@0: threedeva: 0x0969, michael@0: threeeighths: 0x215C, michael@0: threegujarati: 0x0AE9, michael@0: threegurmukhi: 0x0A69, michael@0: threehackarabic: 0x0663, michael@0: threehangzhou: 0x3023, michael@0: threeideographicparen: 0x3222, michael@0: threeinferior: 0x2083, michael@0: threemonospace: 0xFF13, michael@0: threenumeratorbengali: 0x09F6, michael@0: threeoldstyle: 0xF733, michael@0: threeparen: 0x2476, michael@0: threeperiod: 0x248A, michael@0: threepersian: 0x06F3, michael@0: threequarters: 0x00BE, michael@0: threequartersemdash: 0xF6DE, michael@0: threeroman: 0x2172, michael@0: threesuperior: 0x00B3, michael@0: threethai: 0x0E53, michael@0: thzsquare: 0x3394, michael@0: tihiragana: 0x3061, michael@0: tikatakana: 0x30C1, michael@0: tikatakanahalfwidth: 0xFF81, michael@0: tikeutacirclekorean: 0x3270, michael@0: tikeutaparenkorean: 0x3210, michael@0: tikeutcirclekorean: 0x3262, michael@0: tikeutkorean: 0x3137, michael@0: tikeutparenkorean: 0x3202, michael@0: tilde: 0x02DC, michael@0: tildebelowcmb: 0x0330, michael@0: tildecmb: 0x0303, michael@0: tildecomb: 0x0303, michael@0: tildedoublecmb: 0x0360, michael@0: tildeoperator: 0x223C, michael@0: tildeoverlaycmb: 0x0334, michael@0: tildeverticalcmb: 0x033E, michael@0: timescircle: 0x2297, michael@0: tipehahebrew: 0x0596, michael@0: tipehalefthebrew: 0x0596, michael@0: tippigurmukhi: 0x0A70, michael@0: titlocyrilliccmb: 0x0483, michael@0: tiwnarmenian: 0x057F, michael@0: tlinebelow: 0x1E6F, michael@0: tmonospace: 0xFF54, michael@0: toarmenian: 0x0569, michael@0: tohiragana: 0x3068, michael@0: tokatakana: 0x30C8, michael@0: tokatakanahalfwidth: 0xFF84, michael@0: tonebarextrahighmod: 0x02E5, michael@0: tonebarextralowmod: 0x02E9, michael@0: tonebarhighmod: 0x02E6, michael@0: tonebarlowmod: 0x02E8, michael@0: tonebarmidmod: 0x02E7, michael@0: tonefive: 0x01BD, michael@0: tonesix: 0x0185, michael@0: tonetwo: 0x01A8, michael@0: tonos: 0x0384, michael@0: tonsquare: 0x3327, michael@0: topatakthai: 0x0E0F, michael@0: tortoiseshellbracketleft: 0x3014, michael@0: tortoiseshellbracketleftsmall: 0xFE5D, michael@0: tortoiseshellbracketleftvertical: 0xFE39, michael@0: tortoiseshellbracketright: 0x3015, michael@0: tortoiseshellbracketrightsmall: 0xFE5E, michael@0: tortoiseshellbracketrightvertical: 0xFE3A, michael@0: totaothai: 0x0E15, michael@0: tpalatalhook: 0x01AB, michael@0: tparen: 0x24AF, michael@0: trademark: 0x2122, michael@0: trademarksans: 0xF8EA, michael@0: trademarkserif: 0xF6DB, michael@0: tretroflexhook: 0x0288, michael@0: triagdn: 0x25BC, michael@0: triaglf: 0x25C4, michael@0: triagrt: 0x25BA, michael@0: triagup: 0x25B2, michael@0: ts: 0x02A6, michael@0: tsadi: 0x05E6, michael@0: tsadidagesh: 0xFB46, michael@0: tsadidageshhebrew: 0xFB46, michael@0: tsadihebrew: 0x05E6, michael@0: tsecyrillic: 0x0446, michael@0: tsere: 0x05B5, michael@0: tsere12: 0x05B5, michael@0: tsere1e: 0x05B5, michael@0: tsere2b: 0x05B5, michael@0: tserehebrew: 0x05B5, michael@0: tserenarrowhebrew: 0x05B5, michael@0: tserequarterhebrew: 0x05B5, michael@0: tserewidehebrew: 0x05B5, michael@0: tshecyrillic: 0x045B, michael@0: tsuperior: 0xF6F3, michael@0: ttabengali: 0x099F, michael@0: ttadeva: 0x091F, michael@0: ttagujarati: 0x0A9F, michael@0: ttagurmukhi: 0x0A1F, michael@0: tteharabic: 0x0679, michael@0: ttehfinalarabic: 0xFB67, michael@0: ttehinitialarabic: 0xFB68, michael@0: ttehmedialarabic: 0xFB69, michael@0: tthabengali: 0x09A0, michael@0: tthadeva: 0x0920, michael@0: tthagujarati: 0x0AA0, michael@0: tthagurmukhi: 0x0A20, michael@0: tturned: 0x0287, michael@0: tuhiragana: 0x3064, michael@0: tukatakana: 0x30C4, michael@0: tukatakanahalfwidth: 0xFF82, michael@0: tusmallhiragana: 0x3063, michael@0: tusmallkatakana: 0x30C3, michael@0: tusmallkatakanahalfwidth: 0xFF6F, michael@0: twelvecircle: 0x246B, michael@0: twelveparen: 0x247F, michael@0: twelveperiod: 0x2493, michael@0: twelveroman: 0x217B, michael@0: twentycircle: 0x2473, michael@0: twentyhangzhou: 0x5344, michael@0: twentyparen: 0x2487, michael@0: twentyperiod: 0x249B, michael@0: two: 0x0032, michael@0: twoarabic: 0x0662, michael@0: twobengali: 0x09E8, michael@0: twocircle: 0x2461, michael@0: twocircleinversesansserif: 0x278B, michael@0: twodeva: 0x0968, michael@0: twodotenleader: 0x2025, michael@0: twodotleader: 0x2025, michael@0: twodotleadervertical: 0xFE30, michael@0: twogujarati: 0x0AE8, michael@0: twogurmukhi: 0x0A68, michael@0: twohackarabic: 0x0662, michael@0: twohangzhou: 0x3022, michael@0: twoideographicparen: 0x3221, michael@0: twoinferior: 0x2082, michael@0: twomonospace: 0xFF12, michael@0: twonumeratorbengali: 0x09F5, michael@0: twooldstyle: 0xF732, michael@0: twoparen: 0x2475, michael@0: twoperiod: 0x2489, michael@0: twopersian: 0x06F2, michael@0: tworoman: 0x2171, michael@0: twostroke: 0x01BB, michael@0: twosuperior: 0x00B2, michael@0: twothai: 0x0E52, michael@0: twothirds: 0x2154, michael@0: u: 0x0075, michael@0: uacute: 0x00FA, michael@0: ubar: 0x0289, michael@0: ubengali: 0x0989, michael@0: ubopomofo: 0x3128, michael@0: ubreve: 0x016D, michael@0: ucaron: 0x01D4, michael@0: ucircle: 0x24E4, michael@0: ucircumflex: 0x00FB, michael@0: ucircumflexbelow: 0x1E77, michael@0: ucyrillic: 0x0443, michael@0: udattadeva: 0x0951, michael@0: udblacute: 0x0171, michael@0: udblgrave: 0x0215, michael@0: udeva: 0x0909, michael@0: udieresis: 0x00FC, michael@0: udieresisacute: 0x01D8, michael@0: udieresisbelow: 0x1E73, michael@0: udieresiscaron: 0x01DA, michael@0: udieresiscyrillic: 0x04F1, michael@0: udieresisgrave: 0x01DC, michael@0: udieresismacron: 0x01D6, michael@0: udotbelow: 0x1EE5, michael@0: ugrave: 0x00F9, michael@0: ugujarati: 0x0A89, michael@0: ugurmukhi: 0x0A09, michael@0: uhiragana: 0x3046, michael@0: uhookabove: 0x1EE7, michael@0: uhorn: 0x01B0, michael@0: uhornacute: 0x1EE9, michael@0: uhorndotbelow: 0x1EF1, michael@0: uhorngrave: 0x1EEB, michael@0: uhornhookabove: 0x1EED, michael@0: uhorntilde: 0x1EEF, michael@0: uhungarumlaut: 0x0171, michael@0: uhungarumlautcyrillic: 0x04F3, michael@0: uinvertedbreve: 0x0217, michael@0: ukatakana: 0x30A6, michael@0: ukatakanahalfwidth: 0xFF73, michael@0: ukcyrillic: 0x0479, michael@0: ukorean: 0x315C, michael@0: umacron: 0x016B, michael@0: umacroncyrillic: 0x04EF, michael@0: umacrondieresis: 0x1E7B, michael@0: umatragurmukhi: 0x0A41, michael@0: umonospace: 0xFF55, michael@0: underscore: 0x005F, michael@0: underscoredbl: 0x2017, michael@0: underscoremonospace: 0xFF3F, michael@0: underscorevertical: 0xFE33, michael@0: underscorewavy: 0xFE4F, michael@0: union: 0x222A, michael@0: universal: 0x2200, michael@0: uogonek: 0x0173, michael@0: uparen: 0x24B0, michael@0: upblock: 0x2580, michael@0: upperdothebrew: 0x05C4, michael@0: upsilon: 0x03C5, michael@0: upsilondieresis: 0x03CB, michael@0: upsilondieresistonos: 0x03B0, michael@0: upsilonlatin: 0x028A, michael@0: upsilontonos: 0x03CD, michael@0: uptackbelowcmb: 0x031D, michael@0: uptackmod: 0x02D4, michael@0: uragurmukhi: 0x0A73, michael@0: uring: 0x016F, michael@0: ushortcyrillic: 0x045E, michael@0: usmallhiragana: 0x3045, michael@0: usmallkatakana: 0x30A5, michael@0: usmallkatakanahalfwidth: 0xFF69, michael@0: ustraightcyrillic: 0x04AF, michael@0: ustraightstrokecyrillic: 0x04B1, michael@0: utilde: 0x0169, michael@0: utildeacute: 0x1E79, michael@0: utildebelow: 0x1E75, michael@0: uubengali: 0x098A, michael@0: uudeva: 0x090A, michael@0: uugujarati: 0x0A8A, michael@0: uugurmukhi: 0x0A0A, michael@0: uumatragurmukhi: 0x0A42, michael@0: uuvowelsignbengali: 0x09C2, michael@0: uuvowelsigndeva: 0x0942, michael@0: uuvowelsigngujarati: 0x0AC2, michael@0: uvowelsignbengali: 0x09C1, michael@0: uvowelsigndeva: 0x0941, michael@0: uvowelsigngujarati: 0x0AC1, michael@0: v: 0x0076, michael@0: vadeva: 0x0935, michael@0: vagujarati: 0x0AB5, michael@0: vagurmukhi: 0x0A35, michael@0: vakatakana: 0x30F7, michael@0: vav: 0x05D5, michael@0: vavdagesh: 0xFB35, michael@0: vavdagesh65: 0xFB35, michael@0: vavdageshhebrew: 0xFB35, michael@0: vavhebrew: 0x05D5, michael@0: vavholam: 0xFB4B, michael@0: vavholamhebrew: 0xFB4B, michael@0: vavvavhebrew: 0x05F0, michael@0: vavyodhebrew: 0x05F1, michael@0: vcircle: 0x24E5, michael@0: vdotbelow: 0x1E7F, michael@0: vecyrillic: 0x0432, michael@0: veharabic: 0x06A4, michael@0: vehfinalarabic: 0xFB6B, michael@0: vehinitialarabic: 0xFB6C, michael@0: vehmedialarabic: 0xFB6D, michael@0: vekatakana: 0x30F9, michael@0: venus: 0x2640, michael@0: verticalbar: 0x007C, michael@0: verticallineabovecmb: 0x030D, michael@0: verticallinebelowcmb: 0x0329, michael@0: verticallinelowmod: 0x02CC, michael@0: verticallinemod: 0x02C8, michael@0: vewarmenian: 0x057E, michael@0: vhook: 0x028B, michael@0: vikatakana: 0x30F8, michael@0: viramabengali: 0x09CD, michael@0: viramadeva: 0x094D, michael@0: viramagujarati: 0x0ACD, michael@0: visargabengali: 0x0983, michael@0: visargadeva: 0x0903, michael@0: visargagujarati: 0x0A83, michael@0: vmonospace: 0xFF56, michael@0: voarmenian: 0x0578, michael@0: voicediterationhiragana: 0x309E, michael@0: voicediterationkatakana: 0x30FE, michael@0: voicedmarkkana: 0x309B, michael@0: voicedmarkkanahalfwidth: 0xFF9E, michael@0: vokatakana: 0x30FA, michael@0: vparen: 0x24B1, michael@0: vtilde: 0x1E7D, michael@0: vturned: 0x028C, michael@0: vuhiragana: 0x3094, michael@0: vukatakana: 0x30F4, michael@0: w: 0x0077, michael@0: wacute: 0x1E83, michael@0: waekorean: 0x3159, michael@0: wahiragana: 0x308F, michael@0: wakatakana: 0x30EF, michael@0: wakatakanahalfwidth: 0xFF9C, michael@0: wakorean: 0x3158, michael@0: wasmallhiragana: 0x308E, michael@0: wasmallkatakana: 0x30EE, michael@0: wattosquare: 0x3357, michael@0: wavedash: 0x301C, michael@0: wavyunderscorevertical: 0xFE34, michael@0: wawarabic: 0x0648, michael@0: wawfinalarabic: 0xFEEE, michael@0: wawhamzaabovearabic: 0x0624, michael@0: wawhamzaabovefinalarabic: 0xFE86, michael@0: wbsquare: 0x33DD, michael@0: wcircle: 0x24E6, michael@0: wcircumflex: 0x0175, michael@0: wdieresis: 0x1E85, michael@0: wdotaccent: 0x1E87, michael@0: wdotbelow: 0x1E89, michael@0: wehiragana: 0x3091, michael@0: weierstrass: 0x2118, michael@0: wekatakana: 0x30F1, michael@0: wekorean: 0x315E, michael@0: weokorean: 0x315D, michael@0: wgrave: 0x1E81, michael@0: whitebullet: 0x25E6, michael@0: whitecircle: 0x25CB, michael@0: whitecircleinverse: 0x25D9, michael@0: whitecornerbracketleft: 0x300E, michael@0: whitecornerbracketleftvertical: 0xFE43, michael@0: whitecornerbracketright: 0x300F, michael@0: whitecornerbracketrightvertical: 0xFE44, michael@0: whitediamond: 0x25C7, michael@0: whitediamondcontainingblacksmalldiamond: 0x25C8, michael@0: whitedownpointingsmalltriangle: 0x25BF, michael@0: whitedownpointingtriangle: 0x25BD, michael@0: whiteleftpointingsmalltriangle: 0x25C3, michael@0: whiteleftpointingtriangle: 0x25C1, michael@0: whitelenticularbracketleft: 0x3016, michael@0: whitelenticularbracketright: 0x3017, michael@0: whiterightpointingsmalltriangle: 0x25B9, michael@0: whiterightpointingtriangle: 0x25B7, michael@0: whitesmallsquare: 0x25AB, michael@0: whitesmilingface: 0x263A, michael@0: whitesquare: 0x25A1, michael@0: whitestar: 0x2606, michael@0: whitetelephone: 0x260F, michael@0: whitetortoiseshellbracketleft: 0x3018, michael@0: whitetortoiseshellbracketright: 0x3019, michael@0: whiteuppointingsmalltriangle: 0x25B5, michael@0: whiteuppointingtriangle: 0x25B3, michael@0: wihiragana: 0x3090, michael@0: wikatakana: 0x30F0, michael@0: wikorean: 0x315F, michael@0: wmonospace: 0xFF57, michael@0: wohiragana: 0x3092, michael@0: wokatakana: 0x30F2, michael@0: wokatakanahalfwidth: 0xFF66, michael@0: won: 0x20A9, michael@0: wonmonospace: 0xFFE6, michael@0: wowaenthai: 0x0E27, michael@0: wparen: 0x24B2, michael@0: wring: 0x1E98, michael@0: wsuperior: 0x02B7, michael@0: wturned: 0x028D, michael@0: wynn: 0x01BF, michael@0: x: 0x0078, michael@0: xabovecmb: 0x033D, michael@0: xbopomofo: 0x3112, michael@0: xcircle: 0x24E7, michael@0: xdieresis: 0x1E8D, michael@0: xdotaccent: 0x1E8B, michael@0: xeharmenian: 0x056D, michael@0: xi: 0x03BE, michael@0: xmonospace: 0xFF58, michael@0: xparen: 0x24B3, michael@0: xsuperior: 0x02E3, michael@0: y: 0x0079, michael@0: yaadosquare: 0x334E, michael@0: yabengali: 0x09AF, michael@0: yacute: 0x00FD, michael@0: yadeva: 0x092F, michael@0: yaekorean: 0x3152, michael@0: yagujarati: 0x0AAF, michael@0: yagurmukhi: 0x0A2F, michael@0: yahiragana: 0x3084, michael@0: yakatakana: 0x30E4, michael@0: yakatakanahalfwidth: 0xFF94, michael@0: yakorean: 0x3151, michael@0: yamakkanthai: 0x0E4E, michael@0: yasmallhiragana: 0x3083, michael@0: yasmallkatakana: 0x30E3, michael@0: yasmallkatakanahalfwidth: 0xFF6C, michael@0: yatcyrillic: 0x0463, michael@0: ycircle: 0x24E8, michael@0: ycircumflex: 0x0177, michael@0: ydieresis: 0x00FF, michael@0: ydotaccent: 0x1E8F, michael@0: ydotbelow: 0x1EF5, michael@0: yeharabic: 0x064A, michael@0: yehbarreearabic: 0x06D2, michael@0: yehbarreefinalarabic: 0xFBAF, michael@0: yehfinalarabic: 0xFEF2, michael@0: yehhamzaabovearabic: 0x0626, michael@0: yehhamzaabovefinalarabic: 0xFE8A, michael@0: yehhamzaaboveinitialarabic: 0xFE8B, michael@0: yehhamzaabovemedialarabic: 0xFE8C, michael@0: yehinitialarabic: 0xFEF3, michael@0: yehmedialarabic: 0xFEF4, michael@0: yehmeeminitialarabic: 0xFCDD, michael@0: yehmeemisolatedarabic: 0xFC58, michael@0: yehnoonfinalarabic: 0xFC94, michael@0: yehthreedotsbelowarabic: 0x06D1, michael@0: yekorean: 0x3156, michael@0: yen: 0x00A5, michael@0: yenmonospace: 0xFFE5, michael@0: yeokorean: 0x3155, michael@0: yeorinhieuhkorean: 0x3186, michael@0: yerahbenyomohebrew: 0x05AA, michael@0: yerahbenyomolefthebrew: 0x05AA, michael@0: yericyrillic: 0x044B, michael@0: yerudieresiscyrillic: 0x04F9, michael@0: yesieungkorean: 0x3181, michael@0: yesieungpansioskorean: 0x3183, michael@0: yesieungsioskorean: 0x3182, michael@0: yetivhebrew: 0x059A, michael@0: ygrave: 0x1EF3, michael@0: yhook: 0x01B4, michael@0: yhookabove: 0x1EF7, michael@0: yiarmenian: 0x0575, michael@0: yicyrillic: 0x0457, michael@0: yikorean: 0x3162, michael@0: yinyang: 0x262F, michael@0: yiwnarmenian: 0x0582, michael@0: ymonospace: 0xFF59, michael@0: yod: 0x05D9, michael@0: yoddagesh: 0xFB39, michael@0: yoddageshhebrew: 0xFB39, michael@0: yodhebrew: 0x05D9, michael@0: yodyodhebrew: 0x05F2, michael@0: yodyodpatahhebrew: 0xFB1F, michael@0: yohiragana: 0x3088, michael@0: yoikorean: 0x3189, michael@0: yokatakana: 0x30E8, michael@0: yokatakanahalfwidth: 0xFF96, michael@0: yokorean: 0x315B, michael@0: yosmallhiragana: 0x3087, michael@0: yosmallkatakana: 0x30E7, michael@0: yosmallkatakanahalfwidth: 0xFF6E, michael@0: yotgreek: 0x03F3, michael@0: yoyaekorean: 0x3188, michael@0: yoyakorean: 0x3187, michael@0: yoyakthai: 0x0E22, michael@0: yoyingthai: 0x0E0D, michael@0: yparen: 0x24B4, michael@0: ypogegrammeni: 0x037A, michael@0: ypogegrammenigreekcmb: 0x0345, michael@0: yr: 0x01A6, michael@0: yring: 0x1E99, michael@0: ysuperior: 0x02B8, michael@0: ytilde: 0x1EF9, michael@0: yturned: 0x028E, michael@0: yuhiragana: 0x3086, michael@0: yuikorean: 0x318C, michael@0: yukatakana: 0x30E6, michael@0: yukatakanahalfwidth: 0xFF95, michael@0: yukorean: 0x3160, michael@0: yusbigcyrillic: 0x046B, michael@0: yusbigiotifiedcyrillic: 0x046D, michael@0: yuslittlecyrillic: 0x0467, michael@0: yuslittleiotifiedcyrillic: 0x0469, michael@0: yusmallhiragana: 0x3085, michael@0: yusmallkatakana: 0x30E5, michael@0: yusmallkatakanahalfwidth: 0xFF6D, michael@0: yuyekorean: 0x318B, michael@0: yuyeokorean: 0x318A, michael@0: yyabengali: 0x09DF, michael@0: yyadeva: 0x095F, michael@0: z: 0x007A, michael@0: zaarmenian: 0x0566, michael@0: zacute: 0x017A, michael@0: zadeva: 0x095B, michael@0: zagurmukhi: 0x0A5B, michael@0: zaharabic: 0x0638, michael@0: zahfinalarabic: 0xFEC6, michael@0: zahinitialarabic: 0xFEC7, michael@0: zahiragana: 0x3056, michael@0: zahmedialarabic: 0xFEC8, michael@0: zainarabic: 0x0632, michael@0: zainfinalarabic: 0xFEB0, michael@0: zakatakana: 0x30B6, michael@0: zaqefgadolhebrew: 0x0595, michael@0: zaqefqatanhebrew: 0x0594, michael@0: zarqahebrew: 0x0598, michael@0: zayin: 0x05D6, michael@0: zayindagesh: 0xFB36, michael@0: zayindageshhebrew: 0xFB36, michael@0: zayinhebrew: 0x05D6, michael@0: zbopomofo: 0x3117, michael@0: zcaron: 0x017E, michael@0: zcircle: 0x24E9, michael@0: zcircumflex: 0x1E91, michael@0: zcurl: 0x0291, michael@0: zdot: 0x017C, michael@0: zdotaccent: 0x017C, michael@0: zdotbelow: 0x1E93, michael@0: zecyrillic: 0x0437, michael@0: zedescendercyrillic: 0x0499, michael@0: zedieresiscyrillic: 0x04DF, michael@0: zehiragana: 0x305C, michael@0: zekatakana: 0x30BC, michael@0: zero: 0x0030, michael@0: zeroarabic: 0x0660, michael@0: zerobengali: 0x09E6, michael@0: zerodeva: 0x0966, michael@0: zerogujarati: 0x0AE6, michael@0: zerogurmukhi: 0x0A66, michael@0: zerohackarabic: 0x0660, michael@0: zeroinferior: 0x2080, michael@0: zeromonospace: 0xFF10, michael@0: zerooldstyle: 0xF730, michael@0: zeropersian: 0x06F0, michael@0: zerosuperior: 0x2070, michael@0: zerothai: 0x0E50, michael@0: zerowidthjoiner: 0xFEFF, michael@0: zerowidthnonjoiner: 0x200C, michael@0: zerowidthspace: 0x200B, michael@0: zeta: 0x03B6, michael@0: zhbopomofo: 0x3113, michael@0: zhearmenian: 0x056A, michael@0: zhebrevecyrillic: 0x04C2, michael@0: zhecyrillic: 0x0436, michael@0: zhedescendercyrillic: 0x0497, michael@0: zhedieresiscyrillic: 0x04DD, michael@0: zihiragana: 0x3058, michael@0: zikatakana: 0x30B8, michael@0: zinorhebrew: 0x05AE, michael@0: zlinebelow: 0x1E95, michael@0: zmonospace: 0xFF5A, michael@0: zohiragana: 0x305E, michael@0: zokatakana: 0x30BE, michael@0: zparen: 0x24B5, michael@0: zretroflexhook: 0x0290, michael@0: zstroke: 0x01B6, michael@0: zuhiragana: 0x305A, michael@0: zukatakana: 0x30BA, michael@0: '.notdef': 0x0000 michael@0: }; michael@0: michael@0: michael@0: michael@0: var PDFImage = (function PDFImageClosure() { michael@0: /** michael@0: * Decode the image in the main thread if it supported. Resovles the promise michael@0: * when the image data is ready. michael@0: */ michael@0: function handleImageData(handler, xref, res, image) { michael@0: if (image instanceof JpegStream && image.isNativelyDecodable(xref, res)) { michael@0: // For natively supported jpegs send them to the main thread for decoding. michael@0: var dict = image.dict; michael@0: var colorSpace = dict.get('ColorSpace', 'CS'); michael@0: colorSpace = ColorSpace.parse(colorSpace, xref, res); michael@0: var numComps = colorSpace.numComps; michael@0: var resolvePromise; michael@0: handler.send('JpegDecode', [image.getIR(), numComps], function(message) { michael@0: var data = message.data; michael@0: var stream = new Stream(data, 0, data.length, image.dict); michael@0: resolvePromise(stream); michael@0: }); michael@0: return new Promise(function (resolve) { michael@0: resolvePromise = resolve; michael@0: }); michael@0: } else { michael@0: return Promise.resolve(image); michael@0: } michael@0: } michael@0: /** michael@0: * Decode and clamp a value. The formula is different from the spec because we michael@0: * don't decode to float range [0,1], we decode it in the [0,max] range. michael@0: */ michael@0: function decodeAndClamp(value, addend, coefficient, max) { michael@0: value = addend + value * coefficient; michael@0: // Clamp the value to the range michael@0: return (value < 0 ? 0 : (value > max ? max : value)); michael@0: } michael@0: function PDFImage(xref, res, image, inline, smask, mask, isMask) { michael@0: this.image = image; michael@0: var dict = image.dict; michael@0: if (dict.has('Filter')) { michael@0: var filter = dict.get('Filter').name; michael@0: if (filter === 'JPXDecode') { michael@0: var jpxImage = new JpxImage(); michael@0: jpxImage.parseImageProperties(image.stream); michael@0: image.stream.reset(); michael@0: image.bitsPerComponent = jpxImage.bitsPerComponent; michael@0: image.numComps = jpxImage.componentsCount; michael@0: } else if (filter === 'JBIG2Decode') { michael@0: image.bitsPerComponent = 1; michael@0: image.numComps = 1; michael@0: } michael@0: } michael@0: // TODO cache rendered images? michael@0: michael@0: this.width = dict.get('Width', 'W'); michael@0: this.height = dict.get('Height', 'H'); michael@0: michael@0: if (this.width < 1 || this.height < 1) { michael@0: error('Invalid image width: ' + this.width + ' or height: ' + michael@0: this.height); michael@0: } michael@0: michael@0: this.interpolate = dict.get('Interpolate', 'I') || false; michael@0: this.imageMask = dict.get('ImageMask', 'IM') || false; michael@0: this.matte = dict.get('Matte') || false; michael@0: michael@0: var bitsPerComponent = image.bitsPerComponent; michael@0: if (!bitsPerComponent) { michael@0: bitsPerComponent = dict.get('BitsPerComponent', 'BPC'); michael@0: if (!bitsPerComponent) { michael@0: if (this.imageMask) { michael@0: bitsPerComponent = 1; michael@0: } else { michael@0: error('Bits per component missing in image: ' + this.imageMask); michael@0: } michael@0: } michael@0: } michael@0: this.bpc = bitsPerComponent; michael@0: michael@0: if (!this.imageMask) { michael@0: var colorSpace = dict.get('ColorSpace', 'CS'); michael@0: if (!colorSpace) { michael@0: info('JPX images (which do not require color spaces)'); michael@0: switch (image.numComps) { michael@0: case 1: michael@0: colorSpace = Name.get('DeviceGray'); michael@0: break; michael@0: case 3: michael@0: colorSpace = Name.get('DeviceRGB'); michael@0: break; michael@0: case 4: michael@0: colorSpace = Name.get('DeviceCMYK'); michael@0: break; michael@0: default: michael@0: error('JPX images with ' + this.numComps + michael@0: ' color components not supported.'); michael@0: } michael@0: } michael@0: this.colorSpace = ColorSpace.parse(colorSpace, xref, res); michael@0: this.numComps = this.colorSpace.numComps; michael@0: } michael@0: michael@0: this.decode = dict.get('Decode', 'D'); michael@0: this.needsDecode = false; michael@0: if (this.decode && michael@0: ((this.colorSpace && !this.colorSpace.isDefaultDecode(this.decode)) || michael@0: (isMask && !ColorSpace.isDefaultDecode(this.decode, 1)))) { michael@0: this.needsDecode = true; michael@0: // Do some preprocessing to avoid more math. michael@0: var max = (1 << bitsPerComponent) - 1; michael@0: this.decodeCoefficients = []; michael@0: this.decodeAddends = []; michael@0: for (var i = 0, j = 0; i < this.decode.length; i += 2, ++j) { michael@0: var dmin = this.decode[i]; michael@0: var dmax = this.decode[i + 1]; michael@0: this.decodeCoefficients[j] = dmax - dmin; michael@0: this.decodeAddends[j] = max * dmin; michael@0: } michael@0: } michael@0: michael@0: if (smask) { michael@0: this.smask = new PDFImage(xref, res, smask, false); michael@0: } else if (mask) { michael@0: if (isStream(mask)) { michael@0: this.mask = new PDFImage(xref, res, mask, false, null, null, true); michael@0: } else { michael@0: // Color key mask (just an array). michael@0: this.mask = mask; michael@0: } michael@0: } michael@0: } michael@0: /** michael@0: * Handles processing of image data and returns the Promise that is resolved michael@0: * with a PDFImage when the image is ready to be used. michael@0: */ michael@0: PDFImage.buildImage = function PDFImage_buildImage(handler, xref, michael@0: res, image, inline) { michael@0: var imagePromise = handleImageData(handler, xref, res, image); michael@0: var smaskPromise; michael@0: var maskPromise; michael@0: michael@0: var smask = image.dict.get('SMask'); michael@0: var mask = image.dict.get('Mask'); michael@0: michael@0: if (smask) { michael@0: smaskPromise = handleImageData(handler, xref, res, smask); michael@0: maskPromise = Promise.resolve(null); michael@0: } else { michael@0: smaskPromise = Promise.resolve(null); michael@0: if (mask) { michael@0: if (isStream(mask)) { michael@0: maskPromise = handleImageData(handler, xref, res, mask); michael@0: } else if (isArray(mask)) { michael@0: maskPromise = Promise.resolve(mask); michael@0: } else { michael@0: warn('Unsupported mask format.'); michael@0: maskPromise = Promise.resolve(null); michael@0: } michael@0: } else { michael@0: maskPromise = Promise.resolve(null); michael@0: } michael@0: } michael@0: return Promise.all([imagePromise, smaskPromise, maskPromise]).then( michael@0: function(results) { michael@0: var imageData = results[0]; michael@0: var smaskData = results[1]; michael@0: var maskData = results[2]; michael@0: return new PDFImage(xref, res, imageData, inline, smaskData, maskData); michael@0: }); michael@0: }; michael@0: michael@0: /** michael@0: * Resize an image using the nearest neighbor algorithm. Currently only michael@0: * supports one and three component images. michael@0: * @param {TypedArray} pixels The original image with one component. michael@0: * @param {Number} bpc Number of bits per component. michael@0: * @param {Number} components Number of color components, 1 or 3 is supported. michael@0: * @param {Number} w1 Original width. michael@0: * @param {Number} h1 Original height. michael@0: * @param {Number} w2 New width. michael@0: * @param {Number} h2 New height. michael@0: * @return {TypedArray} Resized image data. michael@0: */ michael@0: PDFImage.resize = function PDFImage_resize(pixels, bpc, components, michael@0: w1, h1, w2, h2) { michael@0: var length = w2 * h2 * components; michael@0: var temp = (bpc <= 8 ? new Uint8Array(length) : michael@0: (bpc <= 16 ? new Uint16Array(length) : new Uint32Array(length))); michael@0: var xRatio = w1 / w2; michael@0: var yRatio = h1 / h2; michael@0: var px, py, newIndex, oldIndex; michael@0: for (var i = 0; i < h2; i++) { michael@0: for (var j = 0; j < w2; j++) { michael@0: px = Math.floor(j * xRatio); michael@0: py = Math.floor(i * yRatio); michael@0: newIndex = (i * w2) + j; michael@0: oldIndex = ((py * w1) + px); michael@0: if (components === 1) { michael@0: temp[newIndex] = pixels[oldIndex]; michael@0: } else if (components === 3) { michael@0: newIndex *= 3; michael@0: oldIndex *= 3; michael@0: temp[newIndex] = pixels[oldIndex]; michael@0: temp[newIndex + 1] = pixels[oldIndex + 1]; michael@0: temp[newIndex + 2] = pixels[oldIndex + 2]; michael@0: } michael@0: } michael@0: } michael@0: return temp; michael@0: }; michael@0: michael@0: PDFImage.createMask = michael@0: function PDFImage_createMask(imgArray, width, height, canTransfer, michael@0: inverseDecode) { michael@0: // If imgArray came from a DecodeStream, we're safe to transfer it. michael@0: // Otherwise, copy it. michael@0: var actualLength = imgArray.byteLength; michael@0: var data; michael@0: if (canTransfer) { michael@0: data = imgArray; michael@0: } else { michael@0: data = new Uint8Array(actualLength); michael@0: data.set(imgArray); michael@0: } michael@0: // Invert if necessary. It's safe to modify the array -- whether it's the michael@0: // original or a copy, we're about to transfer it anyway, so nothing else michael@0: // in this thread can be relying on its contents. michael@0: if (inverseDecode) { michael@0: for (var i = 0; i < actualLength; i++) { michael@0: data[i] = ~data[i]; michael@0: } michael@0: } michael@0: michael@0: return {data: data, width: width, height: height}; michael@0: }; michael@0: michael@0: PDFImage.prototype = { michael@0: get drawWidth() { michael@0: return Math.max(this.width, michael@0: this.smask && this.smask.width || 0, michael@0: this.mask && this.mask.width || 0); michael@0: }, michael@0: get drawHeight() { michael@0: return Math.max(this.height, michael@0: this.smask && this.smask.height || 0, michael@0: this.mask && this.mask.height || 0); michael@0: }, michael@0: decodeBuffer: function PDFImage_decodeBuffer(buffer) { michael@0: var bpc = this.bpc; michael@0: var numComps = this.numComps; michael@0: michael@0: var decodeAddends = this.decodeAddends; michael@0: var decodeCoefficients = this.decodeCoefficients; michael@0: var max = (1 << bpc) - 1; michael@0: var i, ii; michael@0: michael@0: if (bpc === 1) { michael@0: // If the buffer needed decode that means it just needs to be inverted. michael@0: for (i = 0, ii = buffer.length; i < ii; i++) { michael@0: buffer[i] = +!(buffer[i]); michael@0: } michael@0: return; michael@0: } michael@0: var index = 0; michael@0: for (i = 0, ii = this.width * this.height; i < ii; i++) { michael@0: for (var j = 0; j < numComps; j++) { michael@0: buffer[index] = decodeAndClamp(buffer[index], decodeAddends[j], michael@0: decodeCoefficients[j], max); michael@0: index++; michael@0: } michael@0: } michael@0: }, michael@0: getComponents: function PDFImage_getComponents(buffer) { michael@0: var bpc = this.bpc; michael@0: michael@0: // This image doesn't require any extra work. michael@0: if (bpc === 8) { michael@0: return buffer; michael@0: } michael@0: michael@0: var width = this.width; michael@0: var height = this.height; michael@0: var numComps = this.numComps; michael@0: michael@0: var length = width * height * numComps; michael@0: var bufferPos = 0; michael@0: var output = (bpc <= 8 ? new Uint8Array(length) : michael@0: (bpc <= 16 ? new Uint16Array(length) : new Uint32Array(length))); michael@0: var rowComps = width * numComps; michael@0: michael@0: var max = (1 << bpc) - 1; michael@0: var i = 0, ii, buf; michael@0: michael@0: if (bpc === 1) { michael@0: // Optimization for reading 1 bpc images. michael@0: var mask, loop1End, loop2End; michael@0: for (var j = 0; j < height; j++) { michael@0: loop1End = i + (rowComps & ~7); michael@0: loop2End = i + rowComps; michael@0: michael@0: // unroll loop for all full bytes michael@0: while (i < loop1End) { michael@0: buf = buffer[bufferPos++]; michael@0: output[i] = (buf >> 7) & 1; michael@0: output[i + 1] = (buf >> 6) & 1; michael@0: output[i + 2] = (buf >> 5) & 1; michael@0: output[i + 3] = (buf >> 4) & 1; michael@0: output[i + 4] = (buf >> 3) & 1; michael@0: output[i + 5] = (buf >> 2) & 1; michael@0: output[i + 6] = (buf >> 1) & 1; michael@0: output[i + 7] = buf & 1; michael@0: i += 8; michael@0: } michael@0: michael@0: // handle remaing bits michael@0: if (i < loop2End) { michael@0: buf = buffer[bufferPos++]; michael@0: mask = 128; michael@0: while (i < loop2End) { michael@0: output[i++] = +!!(buf & mask); michael@0: mask >>= 1; michael@0: } michael@0: } michael@0: } michael@0: } else { michael@0: // The general case that handles all other bpc values. michael@0: var bits = 0; michael@0: buf = 0; michael@0: for (i = 0, ii = length; i < ii; ++i) { michael@0: if (i % rowComps === 0) { michael@0: buf = 0; michael@0: bits = 0; michael@0: } michael@0: michael@0: while (bits < bpc) { michael@0: buf = (buf << 8) | buffer[bufferPos++]; michael@0: bits += 8; michael@0: } michael@0: michael@0: var remainingBits = bits - bpc; michael@0: var value = buf >> remainingBits; michael@0: output[i] = (value < 0 ? 0 : (value > max ? max : value)); michael@0: buf = buf & ((1 << remainingBits) - 1); michael@0: bits = remainingBits; michael@0: } michael@0: } michael@0: return output; michael@0: }, michael@0: fillOpacity: function PDFImage_fillOpacity(rgbaBuf, width, height, michael@0: actualHeight, image) { michael@0: var smask = this.smask; michael@0: var mask = this.mask; michael@0: var alphaBuf, sw, sh, i, ii, j; michael@0: michael@0: if (smask) { michael@0: sw = smask.width; michael@0: sh = smask.height; michael@0: alphaBuf = new Uint8Array(sw * sh); michael@0: smask.fillGrayBuffer(alphaBuf); michael@0: if (sw != width || sh != height) { michael@0: alphaBuf = PDFImage.resize(alphaBuf, smask.bpc, 1, sw, sh, width, michael@0: height); michael@0: } michael@0: } else if (mask) { michael@0: if (mask instanceof PDFImage) { michael@0: sw = mask.width; michael@0: sh = mask.height; michael@0: alphaBuf = new Uint8Array(sw * sh); michael@0: mask.numComps = 1; michael@0: mask.fillGrayBuffer(alphaBuf); michael@0: michael@0: // Need to invert values in rgbaBuf michael@0: for (i = 0, ii = sw * sh; i < ii; ++i) { michael@0: alphaBuf[i] = 255 - alphaBuf[i]; michael@0: } michael@0: michael@0: if (sw != width || sh != height) { michael@0: alphaBuf = PDFImage.resize(alphaBuf, mask.bpc, 1, sw, sh, width, michael@0: height); michael@0: } michael@0: } else if (isArray(mask)) { michael@0: // Color key mask: if any of the compontents are outside the range michael@0: // then they should be painted. michael@0: alphaBuf = new Uint8Array(width * height); michael@0: var numComps = this.numComps; michael@0: for (i = 0, ii = width * height; i < ii; ++i) { michael@0: var opacity = 0; michael@0: var imageOffset = i * numComps; michael@0: for (j = 0; j < numComps; ++j) { michael@0: var color = image[imageOffset + j]; michael@0: var maskOffset = j * 2; michael@0: if (color < mask[maskOffset] || color > mask[maskOffset + 1]) { michael@0: opacity = 255; michael@0: break; michael@0: } michael@0: } michael@0: alphaBuf[i] = opacity; michael@0: } michael@0: } else { michael@0: error('Unknown mask format.'); michael@0: } michael@0: } michael@0: michael@0: if (alphaBuf) { michael@0: for (i = 0, j = 3, ii = width * actualHeight; i < ii; ++i, j += 4) { michael@0: rgbaBuf[j] = alphaBuf[i]; michael@0: } michael@0: } else { michael@0: // No mask. michael@0: for (i = 0, j = 3, ii = width * actualHeight; i < ii; ++i, j += 4) { michael@0: rgbaBuf[j] = 255; michael@0: } michael@0: } michael@0: }, michael@0: undoPreblend: function PDFImage_undoPreblend(buffer, width, height) { michael@0: var matte = this.smask && this.smask.matte; michael@0: if (!matte) { michael@0: return; michael@0: } michael@0: michael@0: function clamp(value) { michael@0: return (value < 0 ? 0 : (value > 255 ? 255 : value)) | 0; michael@0: } michael@0: michael@0: var matteRgb = this.colorSpace.getRgb(matte, 0); michael@0: var length = width * height * 4; michael@0: for (var i = 0; i < length; i += 4) { michael@0: var alpha = buffer[i + 3]; michael@0: if (alpha === 0) { michael@0: // according formula we have to get Infinity in all components michael@0: // making it as white (tipical paper color) should be okay michael@0: buffer[i] = 255; michael@0: buffer[i + 1] = 255; michael@0: buffer[i + 2] = 255; michael@0: continue; michael@0: } michael@0: var k = 255 / alpha; michael@0: buffer[i] = clamp((buffer[i] - matteRgb[0]) * k + matteRgb[0]); michael@0: buffer[i + 1] = clamp((buffer[i + 1] - matteRgb[1]) * k + matteRgb[1]); michael@0: buffer[i + 2] = clamp((buffer[i + 2] - matteRgb[2]) * k + matteRgb[2]); michael@0: } michael@0: }, michael@0: createImageData: function PDFImage_createImageData(forceRGBA) { michael@0: var drawWidth = this.drawWidth; michael@0: var drawHeight = this.drawHeight; michael@0: var imgData = { // other fields are filled in below michael@0: width: drawWidth, michael@0: height: drawHeight michael@0: }; michael@0: michael@0: var numComps = this.numComps; michael@0: var originalWidth = this.width; michael@0: var originalHeight = this.height; michael@0: var bpc = this.bpc; michael@0: michael@0: // Rows start at byte boundary. michael@0: var rowBytes = (originalWidth * numComps * bpc + 7) >> 3; michael@0: var imgArray = this.getImageBytes(originalHeight * rowBytes); michael@0: michael@0: if (!forceRGBA) { michael@0: // If it is a 1-bit-per-pixel grayscale (i.e. black-and-white) image michael@0: // without any complications, we pass a same-sized copy to the main michael@0: // thread rather than expanding by 32x to RGBA form. This saves *lots* michael@0: // of memory for many scanned documents. It's also much faster. michael@0: // michael@0: // Similarly, if it is a 24-bit-per pixel RGB image without any michael@0: // complications, we avoid expanding by 1.333x to RGBA form. michael@0: var kind; michael@0: if (this.colorSpace.name === 'DeviceGray' && bpc === 1) { michael@0: kind = ImageKind.GRAYSCALE_1BPP; michael@0: } else if (this.colorSpace.name === 'DeviceRGB' && bpc === 8) { michael@0: kind = ImageKind.RGB_24BPP; michael@0: } michael@0: if (kind && !this.smask && !this.mask && !this.needsDecode && michael@0: drawWidth === originalWidth && drawHeight === originalHeight) { michael@0: imgData.kind = kind; michael@0: michael@0: // If imgArray came from a DecodeStream, we're safe to transfer it michael@0: // (and thus neuter it) because it will constitute the entire michael@0: // DecodeStream's data. But if it came from a Stream, we need to michael@0: // copy it because it'll only be a portion of the Stream's data, and michael@0: // the rest will be read later on. michael@0: if (this.image instanceof DecodeStream) { michael@0: imgData.data = imgArray; michael@0: } else { michael@0: var newArray = new Uint8Array(imgArray.length); michael@0: newArray.set(imgArray); michael@0: imgData.data = newArray; michael@0: } michael@0: return imgData; michael@0: } michael@0: } michael@0: michael@0: // imgArray can be incomplete (e.g. after CCITT fax encoding). michael@0: var actualHeight = 0 | (imgArray.length / rowBytes * michael@0: drawHeight / originalHeight); michael@0: michael@0: var comps = this.getComponents(imgArray); michael@0: michael@0: // If opacity data is present, use RGBA_32BPP form. Otherwise, use the michael@0: // more compact RGB_24BPP form if allowable. michael@0: var alpha01, maybeUndoPreblend; michael@0: if (!forceRGBA && !this.smask && !this.mask) { michael@0: imgData.kind = ImageKind.RGB_24BPP; michael@0: imgData.data = new Uint8Array(drawWidth * drawHeight * 3); michael@0: alpha01 = 0; michael@0: maybeUndoPreblend = false; michael@0: } else { michael@0: imgData.kind = ImageKind.RGBA_32BPP; michael@0: imgData.data = new Uint8Array(drawWidth * drawHeight * 4); michael@0: alpha01 = 1; michael@0: maybeUndoPreblend = true; michael@0: michael@0: // Color key masking (opacity) must be performed before decoding. michael@0: this.fillOpacity(imgData.data, drawWidth, drawHeight, actualHeight, michael@0: comps); michael@0: } michael@0: michael@0: if (this.needsDecode) { michael@0: this.decodeBuffer(comps); michael@0: } michael@0: this.colorSpace.fillRgb(imgData.data, originalWidth, originalHeight, michael@0: drawWidth, drawHeight, actualHeight, bpc, comps, michael@0: alpha01); michael@0: if (maybeUndoPreblend) { michael@0: this.undoPreblend(imgData.data, drawWidth, actualHeight); michael@0: } michael@0: michael@0: return imgData; michael@0: }, michael@0: fillGrayBuffer: function PDFImage_fillGrayBuffer(buffer) { michael@0: var numComps = this.numComps; michael@0: if (numComps != 1) { michael@0: error('Reading gray scale from a color image: ' + numComps); michael@0: } michael@0: michael@0: var width = this.width; michael@0: var height = this.height; michael@0: var bpc = this.bpc; michael@0: michael@0: // rows start at byte boundary michael@0: var rowBytes = (width * numComps * bpc + 7) >> 3; michael@0: var imgArray = this.getImageBytes(height * rowBytes); michael@0: michael@0: var comps = this.getComponents(imgArray); michael@0: var i, length; michael@0: michael@0: if (bpc === 1) { michael@0: // inline decoding (= inversion) for 1 bpc images michael@0: length = width * height; michael@0: if (this.needsDecode) { michael@0: // invert and scale to {0, 255} michael@0: for (i = 0; i < length; ++i) { michael@0: buffer[i] = (comps[i] - 1) & 255; michael@0: } michael@0: } else { michael@0: // scale to {0, 255} michael@0: for (i = 0; i < length; ++i) { michael@0: buffer[i] = (-comps[i]) & 255; michael@0: } michael@0: } michael@0: return; michael@0: } michael@0: michael@0: if (this.needsDecode) { michael@0: this.decodeBuffer(comps); michael@0: } michael@0: length = width * height; michael@0: // we aren't using a colorspace so we need to scale the value michael@0: var scale = 255 / ((1 << bpc) - 1); michael@0: for (i = 0; i < length; ++i) { michael@0: buffer[i] = (scale * comps[i]) | 0; michael@0: } michael@0: }, michael@0: getImageBytes: function PDFImage_getImageBytes(length) { michael@0: this.image.reset(); michael@0: return this.image.getBytes(length); michael@0: } michael@0: }; michael@0: return PDFImage; michael@0: })(); michael@0: michael@0: michael@0: // The Metrics object contains glyph widths (in glyph space units). michael@0: // As per PDF spec, for most fonts (Type 3 being an exception) a glyph michael@0: // space unit corresponds to 1/1000th of text space unit. michael@0: var Metrics = { michael@0: 'Courier': 600, michael@0: 'Courier-Bold': 600, michael@0: 'Courier-BoldOblique': 600, michael@0: 'Courier-Oblique': 600, michael@0: 'Helvetica' : { michael@0: 'space': 278, michael@0: 'exclam': 278, michael@0: 'quotedbl': 355, michael@0: 'numbersign': 556, michael@0: 'dollar': 556, michael@0: 'percent': 889, michael@0: 'ampersand': 667, michael@0: 'quoteright': 222, michael@0: 'parenleft': 333, michael@0: 'parenright': 333, michael@0: 'asterisk': 389, michael@0: 'plus': 584, michael@0: 'comma': 278, michael@0: 'hyphen': 333, michael@0: 'period': 278, michael@0: 'slash': 278, michael@0: 'zero': 556, michael@0: 'one': 556, michael@0: 'two': 556, michael@0: 'three': 556, michael@0: 'four': 556, michael@0: 'five': 556, michael@0: 'six': 556, michael@0: 'seven': 556, michael@0: 'eight': 556, michael@0: 'nine': 556, michael@0: 'colon': 278, michael@0: 'semicolon': 278, michael@0: 'less': 584, michael@0: 'equal': 584, michael@0: 'greater': 584, michael@0: 'question': 556, michael@0: 'at': 1015, michael@0: 'A': 667, michael@0: 'B': 667, michael@0: 'C': 722, michael@0: 'D': 722, michael@0: 'E': 667, michael@0: 'F': 611, michael@0: 'G': 778, michael@0: 'H': 722, michael@0: 'I': 278, michael@0: 'J': 500, michael@0: 'K': 667, michael@0: 'L': 556, michael@0: 'M': 833, michael@0: 'N': 722, michael@0: 'O': 778, michael@0: 'P': 667, michael@0: 'Q': 778, michael@0: 'R': 722, michael@0: 'S': 667, michael@0: 'T': 611, michael@0: 'U': 722, michael@0: 'V': 667, michael@0: 'W': 944, michael@0: 'X': 667, michael@0: 'Y': 667, michael@0: 'Z': 611, michael@0: 'bracketleft': 278, michael@0: 'backslash': 278, michael@0: 'bracketright': 278, michael@0: 'asciicircum': 469, michael@0: 'underscore': 556, michael@0: 'quoteleft': 222, michael@0: 'a': 556, michael@0: 'b': 556, michael@0: 'c': 500, michael@0: 'd': 556, michael@0: 'e': 556, michael@0: 'f': 278, michael@0: 'g': 556, michael@0: 'h': 556, michael@0: 'i': 222, michael@0: 'j': 222, michael@0: 'k': 500, michael@0: 'l': 222, michael@0: 'm': 833, michael@0: 'n': 556, michael@0: 'o': 556, michael@0: 'p': 556, michael@0: 'q': 556, michael@0: 'r': 333, michael@0: 's': 500, michael@0: 't': 278, michael@0: 'u': 556, michael@0: 'v': 500, michael@0: 'w': 722, michael@0: 'x': 500, michael@0: 'y': 500, michael@0: 'z': 500, michael@0: 'braceleft': 334, michael@0: 'bar': 260, michael@0: 'braceright': 334, michael@0: 'asciitilde': 584, michael@0: 'exclamdown': 333, michael@0: 'cent': 556, michael@0: 'sterling': 556, michael@0: 'fraction': 167, michael@0: 'yen': 556, michael@0: 'florin': 556, michael@0: 'section': 556, michael@0: 'currency': 556, michael@0: 'quotesingle': 191, michael@0: 'quotedblleft': 333, michael@0: 'guillemotleft': 556, michael@0: 'guilsinglleft': 333, michael@0: 'guilsinglright': 333, michael@0: 'fi': 500, michael@0: 'fl': 500, michael@0: 'endash': 556, michael@0: 'dagger': 556, michael@0: 'daggerdbl': 556, michael@0: 'periodcentered': 278, michael@0: 'paragraph': 537, michael@0: 'bullet': 350, michael@0: 'quotesinglbase': 222, michael@0: 'quotedblbase': 333, michael@0: 'quotedblright': 333, michael@0: 'guillemotright': 556, michael@0: 'ellipsis': 1000, michael@0: 'perthousand': 1000, michael@0: 'questiondown': 611, michael@0: 'grave': 333, michael@0: 'acute': 333, michael@0: 'circumflex': 333, michael@0: 'tilde': 333, michael@0: 'macron': 333, michael@0: 'breve': 333, michael@0: 'dotaccent': 333, michael@0: 'dieresis': 333, michael@0: 'ring': 333, michael@0: 'cedilla': 333, michael@0: 'hungarumlaut': 333, michael@0: 'ogonek': 333, michael@0: 'caron': 333, michael@0: 'emdash': 1000, michael@0: 'AE': 1000, michael@0: 'ordfeminine': 370, michael@0: 'Lslash': 556, michael@0: 'Oslash': 778, michael@0: 'OE': 1000, michael@0: 'ordmasculine': 365, michael@0: 'ae': 889, michael@0: 'dotlessi': 278, michael@0: 'lslash': 222, michael@0: 'oslash': 611, michael@0: 'oe': 944, michael@0: 'germandbls': 611, michael@0: 'Idieresis': 278, michael@0: 'eacute': 556, michael@0: 'abreve': 556, michael@0: 'uhungarumlaut': 556, michael@0: 'ecaron': 556, michael@0: 'Ydieresis': 667, michael@0: 'divide': 584, michael@0: 'Yacute': 667, michael@0: 'Acircumflex': 667, michael@0: 'aacute': 556, michael@0: 'Ucircumflex': 722, michael@0: 'yacute': 500, michael@0: 'scommaaccent': 500, michael@0: 'ecircumflex': 556, michael@0: 'Uring': 722, michael@0: 'Udieresis': 722, michael@0: 'aogonek': 556, michael@0: 'Uacute': 722, michael@0: 'uogonek': 556, michael@0: 'Edieresis': 667, michael@0: 'Dcroat': 722, michael@0: 'commaaccent': 250, michael@0: 'copyright': 737, michael@0: 'Emacron': 667, michael@0: 'ccaron': 500, michael@0: 'aring': 556, michael@0: 'Ncommaaccent': 722, michael@0: 'lacute': 222, michael@0: 'agrave': 556, michael@0: 'Tcommaaccent': 611, michael@0: 'Cacute': 722, michael@0: 'atilde': 556, michael@0: 'Edotaccent': 667, michael@0: 'scaron': 500, michael@0: 'scedilla': 500, michael@0: 'iacute': 278, michael@0: 'lozenge': 471, michael@0: 'Rcaron': 722, michael@0: 'Gcommaaccent': 778, michael@0: 'ucircumflex': 556, michael@0: 'acircumflex': 556, michael@0: 'Amacron': 667, michael@0: 'rcaron': 333, michael@0: 'ccedilla': 500, michael@0: 'Zdotaccent': 611, michael@0: 'Thorn': 667, michael@0: 'Omacron': 778, michael@0: 'Racute': 722, michael@0: 'Sacute': 667, michael@0: 'dcaron': 643, michael@0: 'Umacron': 722, michael@0: 'uring': 556, michael@0: 'threesuperior': 333, michael@0: 'Ograve': 778, michael@0: 'Agrave': 667, michael@0: 'Abreve': 667, michael@0: 'multiply': 584, michael@0: 'uacute': 556, michael@0: 'Tcaron': 611, michael@0: 'partialdiff': 476, michael@0: 'ydieresis': 500, michael@0: 'Nacute': 722, michael@0: 'icircumflex': 278, michael@0: 'Ecircumflex': 667, michael@0: 'adieresis': 556, michael@0: 'edieresis': 556, michael@0: 'cacute': 500, michael@0: 'nacute': 556, michael@0: 'umacron': 556, michael@0: 'Ncaron': 722, michael@0: 'Iacute': 278, michael@0: 'plusminus': 584, michael@0: 'brokenbar': 260, michael@0: 'registered': 737, michael@0: 'Gbreve': 778, michael@0: 'Idotaccent': 278, michael@0: 'summation': 600, michael@0: 'Egrave': 667, michael@0: 'racute': 333, michael@0: 'omacron': 556, michael@0: 'Zacute': 611, michael@0: 'Zcaron': 611, michael@0: 'greaterequal': 549, michael@0: 'Eth': 722, michael@0: 'Ccedilla': 722, michael@0: 'lcommaaccent': 222, michael@0: 'tcaron': 317, michael@0: 'eogonek': 556, michael@0: 'Uogonek': 722, michael@0: 'Aacute': 667, michael@0: 'Adieresis': 667, michael@0: 'egrave': 556, michael@0: 'zacute': 500, michael@0: 'iogonek': 222, michael@0: 'Oacute': 778, michael@0: 'oacute': 556, michael@0: 'amacron': 556, michael@0: 'sacute': 500, michael@0: 'idieresis': 278, michael@0: 'Ocircumflex': 778, michael@0: 'Ugrave': 722, michael@0: 'Delta': 612, michael@0: 'thorn': 556, michael@0: 'twosuperior': 333, michael@0: 'Odieresis': 778, michael@0: 'mu': 556, michael@0: 'igrave': 278, michael@0: 'ohungarumlaut': 556, michael@0: 'Eogonek': 667, michael@0: 'dcroat': 556, michael@0: 'threequarters': 834, michael@0: 'Scedilla': 667, michael@0: 'lcaron': 299, michael@0: 'Kcommaaccent': 667, michael@0: 'Lacute': 556, michael@0: 'trademark': 1000, michael@0: 'edotaccent': 556, michael@0: 'Igrave': 278, michael@0: 'Imacron': 278, michael@0: 'Lcaron': 556, michael@0: 'onehalf': 834, michael@0: 'lessequal': 549, michael@0: 'ocircumflex': 556, michael@0: 'ntilde': 556, michael@0: 'Uhungarumlaut': 722, michael@0: 'Eacute': 667, michael@0: 'emacron': 556, michael@0: 'gbreve': 556, michael@0: 'onequarter': 834, michael@0: 'Scaron': 667, michael@0: 'Scommaaccent': 667, michael@0: 'Ohungarumlaut': 778, michael@0: 'degree': 400, michael@0: 'ograve': 556, michael@0: 'Ccaron': 722, michael@0: 'ugrave': 556, michael@0: 'radical': 453, michael@0: 'Dcaron': 722, michael@0: 'rcommaaccent': 333, michael@0: 'Ntilde': 722, michael@0: 'otilde': 556, michael@0: 'Rcommaaccent': 722, michael@0: 'Lcommaaccent': 556, michael@0: 'Atilde': 667, michael@0: 'Aogonek': 667, michael@0: 'Aring': 667, michael@0: 'Otilde': 778, michael@0: 'zdotaccent': 500, michael@0: 'Ecaron': 667, michael@0: 'Iogonek': 278, michael@0: 'kcommaaccent': 500, michael@0: 'minus': 584, michael@0: 'Icircumflex': 278, michael@0: 'ncaron': 556, michael@0: 'tcommaaccent': 278, michael@0: 'logicalnot': 584, michael@0: 'odieresis': 556, michael@0: 'udieresis': 556, michael@0: 'notequal': 549, michael@0: 'gcommaaccent': 556, michael@0: 'eth': 556, michael@0: 'zcaron': 500, michael@0: 'ncommaaccent': 556, michael@0: 'onesuperior': 333, michael@0: 'imacron': 278, michael@0: 'Euro': 556 michael@0: }, michael@0: 'Helvetica-Bold': { michael@0: 'space': 278, michael@0: 'exclam': 333, michael@0: 'quotedbl': 474, michael@0: 'numbersign': 556, michael@0: 'dollar': 556, michael@0: 'percent': 889, michael@0: 'ampersand': 722, michael@0: 'quoteright': 278, michael@0: 'parenleft': 333, michael@0: 'parenright': 333, michael@0: 'asterisk': 389, michael@0: 'plus': 584, michael@0: 'comma': 278, michael@0: 'hyphen': 333, michael@0: 'period': 278, michael@0: 'slash': 278, michael@0: 'zero': 556, michael@0: 'one': 556, michael@0: 'two': 556, michael@0: 'three': 556, michael@0: 'four': 556, michael@0: 'five': 556, michael@0: 'six': 556, michael@0: 'seven': 556, michael@0: 'eight': 556, michael@0: 'nine': 556, michael@0: 'colon': 333, michael@0: 'semicolon': 333, michael@0: 'less': 584, michael@0: 'equal': 584, michael@0: 'greater': 584, michael@0: 'question': 611, michael@0: 'at': 975, michael@0: 'A': 722, michael@0: 'B': 722, michael@0: 'C': 722, michael@0: 'D': 722, michael@0: 'E': 667, michael@0: 'F': 611, michael@0: 'G': 778, michael@0: 'H': 722, michael@0: 'I': 278, michael@0: 'J': 556, michael@0: 'K': 722, michael@0: 'L': 611, michael@0: 'M': 833, michael@0: 'N': 722, michael@0: 'O': 778, michael@0: 'P': 667, michael@0: 'Q': 778, michael@0: 'R': 722, michael@0: 'S': 667, michael@0: 'T': 611, michael@0: 'U': 722, michael@0: 'V': 667, michael@0: 'W': 944, michael@0: 'X': 667, michael@0: 'Y': 667, michael@0: 'Z': 611, michael@0: 'bracketleft': 333, michael@0: 'backslash': 278, michael@0: 'bracketright': 333, michael@0: 'asciicircum': 584, michael@0: 'underscore': 556, michael@0: 'quoteleft': 278, michael@0: 'a': 556, michael@0: 'b': 611, michael@0: 'c': 556, michael@0: 'd': 611, michael@0: 'e': 556, michael@0: 'f': 333, michael@0: 'g': 611, michael@0: 'h': 611, michael@0: 'i': 278, michael@0: 'j': 278, michael@0: 'k': 556, michael@0: 'l': 278, michael@0: 'm': 889, michael@0: 'n': 611, michael@0: 'o': 611, michael@0: 'p': 611, michael@0: 'q': 611, michael@0: 'r': 389, michael@0: 's': 556, michael@0: 't': 333, michael@0: 'u': 611, michael@0: 'v': 556, michael@0: 'w': 778, michael@0: 'x': 556, michael@0: 'y': 556, michael@0: 'z': 500, michael@0: 'braceleft': 389, michael@0: 'bar': 280, michael@0: 'braceright': 389, michael@0: 'asciitilde': 584, michael@0: 'exclamdown': 333, michael@0: 'cent': 556, michael@0: 'sterling': 556, michael@0: 'fraction': 167, michael@0: 'yen': 556, michael@0: 'florin': 556, michael@0: 'section': 556, michael@0: 'currency': 556, michael@0: 'quotesingle': 238, michael@0: 'quotedblleft': 500, michael@0: 'guillemotleft': 556, michael@0: 'guilsinglleft': 333, michael@0: 'guilsinglright': 333, michael@0: 'fi': 611, michael@0: 'fl': 611, michael@0: 'endash': 556, michael@0: 'dagger': 556, michael@0: 'daggerdbl': 556, michael@0: 'periodcentered': 278, michael@0: 'paragraph': 556, michael@0: 'bullet': 350, michael@0: 'quotesinglbase': 278, michael@0: 'quotedblbase': 500, michael@0: 'quotedblright': 500, michael@0: 'guillemotright': 556, michael@0: 'ellipsis': 1000, michael@0: 'perthousand': 1000, michael@0: 'questiondown': 611, michael@0: 'grave': 333, michael@0: 'acute': 333, michael@0: 'circumflex': 333, michael@0: 'tilde': 333, michael@0: 'macron': 333, michael@0: 'breve': 333, michael@0: 'dotaccent': 333, michael@0: 'dieresis': 333, michael@0: 'ring': 333, michael@0: 'cedilla': 333, michael@0: 'hungarumlaut': 333, michael@0: 'ogonek': 333, michael@0: 'caron': 333, michael@0: 'emdash': 1000, michael@0: 'AE': 1000, michael@0: 'ordfeminine': 370, michael@0: 'Lslash': 611, michael@0: 'Oslash': 778, michael@0: 'OE': 1000, michael@0: 'ordmasculine': 365, michael@0: 'ae': 889, michael@0: 'dotlessi': 278, michael@0: 'lslash': 278, michael@0: 'oslash': 611, michael@0: 'oe': 944, michael@0: 'germandbls': 611, michael@0: 'Idieresis': 278, michael@0: 'eacute': 556, michael@0: 'abreve': 556, michael@0: 'uhungarumlaut': 611, michael@0: 'ecaron': 556, michael@0: 'Ydieresis': 667, michael@0: 'divide': 584, michael@0: 'Yacute': 667, michael@0: 'Acircumflex': 722, michael@0: 'aacute': 556, michael@0: 'Ucircumflex': 722, michael@0: 'yacute': 556, michael@0: 'scommaaccent': 556, michael@0: 'ecircumflex': 556, michael@0: 'Uring': 722, michael@0: 'Udieresis': 722, michael@0: 'aogonek': 556, michael@0: 'Uacute': 722, michael@0: 'uogonek': 611, michael@0: 'Edieresis': 667, michael@0: 'Dcroat': 722, michael@0: 'commaaccent': 250, michael@0: 'copyright': 737, michael@0: 'Emacron': 667, michael@0: 'ccaron': 556, michael@0: 'aring': 556, michael@0: 'Ncommaaccent': 722, michael@0: 'lacute': 278, michael@0: 'agrave': 556, michael@0: 'Tcommaaccent': 611, michael@0: 'Cacute': 722, michael@0: 'atilde': 556, michael@0: 'Edotaccent': 667, michael@0: 'scaron': 556, michael@0: 'scedilla': 556, michael@0: 'iacute': 278, michael@0: 'lozenge': 494, michael@0: 'Rcaron': 722, michael@0: 'Gcommaaccent': 778, michael@0: 'ucircumflex': 611, michael@0: 'acircumflex': 556, michael@0: 'Amacron': 722, michael@0: 'rcaron': 389, michael@0: 'ccedilla': 556, michael@0: 'Zdotaccent': 611, michael@0: 'Thorn': 667, michael@0: 'Omacron': 778, michael@0: 'Racute': 722, michael@0: 'Sacute': 667, michael@0: 'dcaron': 743, michael@0: 'Umacron': 722, michael@0: 'uring': 611, michael@0: 'threesuperior': 333, michael@0: 'Ograve': 778, michael@0: 'Agrave': 722, michael@0: 'Abreve': 722, michael@0: 'multiply': 584, michael@0: 'uacute': 611, michael@0: 'Tcaron': 611, michael@0: 'partialdiff': 494, michael@0: 'ydieresis': 556, michael@0: 'Nacute': 722, michael@0: 'icircumflex': 278, michael@0: 'Ecircumflex': 667, michael@0: 'adieresis': 556, michael@0: 'edieresis': 556, michael@0: 'cacute': 556, michael@0: 'nacute': 611, michael@0: 'umacron': 611, michael@0: 'Ncaron': 722, michael@0: 'Iacute': 278, michael@0: 'plusminus': 584, michael@0: 'brokenbar': 280, michael@0: 'registered': 737, michael@0: 'Gbreve': 778, michael@0: 'Idotaccent': 278, michael@0: 'summation': 600, michael@0: 'Egrave': 667, michael@0: 'racute': 389, michael@0: 'omacron': 611, michael@0: 'Zacute': 611, michael@0: 'Zcaron': 611, michael@0: 'greaterequal': 549, michael@0: 'Eth': 722, michael@0: 'Ccedilla': 722, michael@0: 'lcommaaccent': 278, michael@0: 'tcaron': 389, michael@0: 'eogonek': 556, michael@0: 'Uogonek': 722, michael@0: 'Aacute': 722, michael@0: 'Adieresis': 722, michael@0: 'egrave': 556, michael@0: 'zacute': 500, michael@0: 'iogonek': 278, michael@0: 'Oacute': 778, michael@0: 'oacute': 611, michael@0: 'amacron': 556, michael@0: 'sacute': 556, michael@0: 'idieresis': 278, michael@0: 'Ocircumflex': 778, michael@0: 'Ugrave': 722, michael@0: 'Delta': 612, michael@0: 'thorn': 611, michael@0: 'twosuperior': 333, michael@0: 'Odieresis': 778, michael@0: 'mu': 611, michael@0: 'igrave': 278, michael@0: 'ohungarumlaut': 611, michael@0: 'Eogonek': 667, michael@0: 'dcroat': 611, michael@0: 'threequarters': 834, michael@0: 'Scedilla': 667, michael@0: 'lcaron': 400, michael@0: 'Kcommaaccent': 722, michael@0: 'Lacute': 611, michael@0: 'trademark': 1000, michael@0: 'edotaccent': 556, michael@0: 'Igrave': 278, michael@0: 'Imacron': 278, michael@0: 'Lcaron': 611, michael@0: 'onehalf': 834, michael@0: 'lessequal': 549, michael@0: 'ocircumflex': 611, michael@0: 'ntilde': 611, michael@0: 'Uhungarumlaut': 722, michael@0: 'Eacute': 667, michael@0: 'emacron': 556, michael@0: 'gbreve': 611, michael@0: 'onequarter': 834, michael@0: 'Scaron': 667, michael@0: 'Scommaaccent': 667, michael@0: 'Ohungarumlaut': 778, michael@0: 'degree': 400, michael@0: 'ograve': 611, michael@0: 'Ccaron': 722, michael@0: 'ugrave': 611, michael@0: 'radical': 549, michael@0: 'Dcaron': 722, michael@0: 'rcommaaccent': 389, michael@0: 'Ntilde': 722, michael@0: 'otilde': 611, michael@0: 'Rcommaaccent': 722, michael@0: 'Lcommaaccent': 611, michael@0: 'Atilde': 722, michael@0: 'Aogonek': 722, michael@0: 'Aring': 722, michael@0: 'Otilde': 778, michael@0: 'zdotaccent': 500, michael@0: 'Ecaron': 667, michael@0: 'Iogonek': 278, michael@0: 'kcommaaccent': 556, michael@0: 'minus': 584, michael@0: 'Icircumflex': 278, michael@0: 'ncaron': 611, michael@0: 'tcommaaccent': 333, michael@0: 'logicalnot': 584, michael@0: 'odieresis': 611, michael@0: 'udieresis': 611, michael@0: 'notequal': 549, michael@0: 'gcommaaccent': 611, michael@0: 'eth': 611, michael@0: 'zcaron': 500, michael@0: 'ncommaaccent': 611, michael@0: 'onesuperior': 333, michael@0: 'imacron': 278, michael@0: 'Euro': 556 michael@0: }, michael@0: 'Helvetica-BoldOblique': { michael@0: 'space': 278, michael@0: 'exclam': 333, michael@0: 'quotedbl': 474, michael@0: 'numbersign': 556, michael@0: 'dollar': 556, michael@0: 'percent': 889, michael@0: 'ampersand': 722, michael@0: 'quoteright': 278, michael@0: 'parenleft': 333, michael@0: 'parenright': 333, michael@0: 'asterisk': 389, michael@0: 'plus': 584, michael@0: 'comma': 278, michael@0: 'hyphen': 333, michael@0: 'period': 278, michael@0: 'slash': 278, michael@0: 'zero': 556, michael@0: 'one': 556, michael@0: 'two': 556, michael@0: 'three': 556, michael@0: 'four': 556, michael@0: 'five': 556, michael@0: 'six': 556, michael@0: 'seven': 556, michael@0: 'eight': 556, michael@0: 'nine': 556, michael@0: 'colon': 333, michael@0: 'semicolon': 333, michael@0: 'less': 584, michael@0: 'equal': 584, michael@0: 'greater': 584, michael@0: 'question': 611, michael@0: 'at': 975, michael@0: 'A': 722, michael@0: 'B': 722, michael@0: 'C': 722, michael@0: 'D': 722, michael@0: 'E': 667, michael@0: 'F': 611, michael@0: 'G': 778, michael@0: 'H': 722, michael@0: 'I': 278, michael@0: 'J': 556, michael@0: 'K': 722, michael@0: 'L': 611, michael@0: 'M': 833, michael@0: 'N': 722, michael@0: 'O': 778, michael@0: 'P': 667, michael@0: 'Q': 778, michael@0: 'R': 722, michael@0: 'S': 667, michael@0: 'T': 611, michael@0: 'U': 722, michael@0: 'V': 667, michael@0: 'W': 944, michael@0: 'X': 667, michael@0: 'Y': 667, michael@0: 'Z': 611, michael@0: 'bracketleft': 333, michael@0: 'backslash': 278, michael@0: 'bracketright': 333, michael@0: 'asciicircum': 584, michael@0: 'underscore': 556, michael@0: 'quoteleft': 278, michael@0: 'a': 556, michael@0: 'b': 611, michael@0: 'c': 556, michael@0: 'd': 611, michael@0: 'e': 556, michael@0: 'f': 333, michael@0: 'g': 611, michael@0: 'h': 611, michael@0: 'i': 278, michael@0: 'j': 278, michael@0: 'k': 556, michael@0: 'l': 278, michael@0: 'm': 889, michael@0: 'n': 611, michael@0: 'o': 611, michael@0: 'p': 611, michael@0: 'q': 611, michael@0: 'r': 389, michael@0: 's': 556, michael@0: 't': 333, michael@0: 'u': 611, michael@0: 'v': 556, michael@0: 'w': 778, michael@0: 'x': 556, michael@0: 'y': 556, michael@0: 'z': 500, michael@0: 'braceleft': 389, michael@0: 'bar': 280, michael@0: 'braceright': 389, michael@0: 'asciitilde': 584, michael@0: 'exclamdown': 333, michael@0: 'cent': 556, michael@0: 'sterling': 556, michael@0: 'fraction': 167, michael@0: 'yen': 556, michael@0: 'florin': 556, michael@0: 'section': 556, michael@0: 'currency': 556, michael@0: 'quotesingle': 238, michael@0: 'quotedblleft': 500, michael@0: 'guillemotleft': 556, michael@0: 'guilsinglleft': 333, michael@0: 'guilsinglright': 333, michael@0: 'fi': 611, michael@0: 'fl': 611, michael@0: 'endash': 556, michael@0: 'dagger': 556, michael@0: 'daggerdbl': 556, michael@0: 'periodcentered': 278, michael@0: 'paragraph': 556, michael@0: 'bullet': 350, michael@0: 'quotesinglbase': 278, michael@0: 'quotedblbase': 500, michael@0: 'quotedblright': 500, michael@0: 'guillemotright': 556, michael@0: 'ellipsis': 1000, michael@0: 'perthousand': 1000, michael@0: 'questiondown': 611, michael@0: 'grave': 333, michael@0: 'acute': 333, michael@0: 'circumflex': 333, michael@0: 'tilde': 333, michael@0: 'macron': 333, michael@0: 'breve': 333, michael@0: 'dotaccent': 333, michael@0: 'dieresis': 333, michael@0: 'ring': 333, michael@0: 'cedilla': 333, michael@0: 'hungarumlaut': 333, michael@0: 'ogonek': 333, michael@0: 'caron': 333, michael@0: 'emdash': 1000, michael@0: 'AE': 1000, michael@0: 'ordfeminine': 370, michael@0: 'Lslash': 611, michael@0: 'Oslash': 778, michael@0: 'OE': 1000, michael@0: 'ordmasculine': 365, michael@0: 'ae': 889, michael@0: 'dotlessi': 278, michael@0: 'lslash': 278, michael@0: 'oslash': 611, michael@0: 'oe': 944, michael@0: 'germandbls': 611, michael@0: 'Idieresis': 278, michael@0: 'eacute': 556, michael@0: 'abreve': 556, michael@0: 'uhungarumlaut': 611, michael@0: 'ecaron': 556, michael@0: 'Ydieresis': 667, michael@0: 'divide': 584, michael@0: 'Yacute': 667, michael@0: 'Acircumflex': 722, michael@0: 'aacute': 556, michael@0: 'Ucircumflex': 722, michael@0: 'yacute': 556, michael@0: 'scommaaccent': 556, michael@0: 'ecircumflex': 556, michael@0: 'Uring': 722, michael@0: 'Udieresis': 722, michael@0: 'aogonek': 556, michael@0: 'Uacute': 722, michael@0: 'uogonek': 611, michael@0: 'Edieresis': 667, michael@0: 'Dcroat': 722, michael@0: 'commaaccent': 250, michael@0: 'copyright': 737, michael@0: 'Emacron': 667, michael@0: 'ccaron': 556, michael@0: 'aring': 556, michael@0: 'Ncommaaccent': 722, michael@0: 'lacute': 278, michael@0: 'agrave': 556, michael@0: 'Tcommaaccent': 611, michael@0: 'Cacute': 722, michael@0: 'atilde': 556, michael@0: 'Edotaccent': 667, michael@0: 'scaron': 556, michael@0: 'scedilla': 556, michael@0: 'iacute': 278, michael@0: 'lozenge': 494, michael@0: 'Rcaron': 722, michael@0: 'Gcommaaccent': 778, michael@0: 'ucircumflex': 611, michael@0: 'acircumflex': 556, michael@0: 'Amacron': 722, michael@0: 'rcaron': 389, michael@0: 'ccedilla': 556, michael@0: 'Zdotaccent': 611, michael@0: 'Thorn': 667, michael@0: 'Omacron': 778, michael@0: 'Racute': 722, michael@0: 'Sacute': 667, michael@0: 'dcaron': 743, michael@0: 'Umacron': 722, michael@0: 'uring': 611, michael@0: 'threesuperior': 333, michael@0: 'Ograve': 778, michael@0: 'Agrave': 722, michael@0: 'Abreve': 722, michael@0: 'multiply': 584, michael@0: 'uacute': 611, michael@0: 'Tcaron': 611, michael@0: 'partialdiff': 494, michael@0: 'ydieresis': 556, michael@0: 'Nacute': 722, michael@0: 'icircumflex': 278, michael@0: 'Ecircumflex': 667, michael@0: 'adieresis': 556, michael@0: 'edieresis': 556, michael@0: 'cacute': 556, michael@0: 'nacute': 611, michael@0: 'umacron': 611, michael@0: 'Ncaron': 722, michael@0: 'Iacute': 278, michael@0: 'plusminus': 584, michael@0: 'brokenbar': 280, michael@0: 'registered': 737, michael@0: 'Gbreve': 778, michael@0: 'Idotaccent': 278, michael@0: 'summation': 600, michael@0: 'Egrave': 667, michael@0: 'racute': 389, michael@0: 'omacron': 611, michael@0: 'Zacute': 611, michael@0: 'Zcaron': 611, michael@0: 'greaterequal': 549, michael@0: 'Eth': 722, michael@0: 'Ccedilla': 722, michael@0: 'lcommaaccent': 278, michael@0: 'tcaron': 389, michael@0: 'eogonek': 556, michael@0: 'Uogonek': 722, michael@0: 'Aacute': 722, michael@0: 'Adieresis': 722, michael@0: 'egrave': 556, michael@0: 'zacute': 500, michael@0: 'iogonek': 278, michael@0: 'Oacute': 778, michael@0: 'oacute': 611, michael@0: 'amacron': 556, michael@0: 'sacute': 556, michael@0: 'idieresis': 278, michael@0: 'Ocircumflex': 778, michael@0: 'Ugrave': 722, michael@0: 'Delta': 612, michael@0: 'thorn': 611, michael@0: 'twosuperior': 333, michael@0: 'Odieresis': 778, michael@0: 'mu': 611, michael@0: 'igrave': 278, michael@0: 'ohungarumlaut': 611, michael@0: 'Eogonek': 667, michael@0: 'dcroat': 611, michael@0: 'threequarters': 834, michael@0: 'Scedilla': 667, michael@0: 'lcaron': 400, michael@0: 'Kcommaaccent': 722, michael@0: 'Lacute': 611, michael@0: 'trademark': 1000, michael@0: 'edotaccent': 556, michael@0: 'Igrave': 278, michael@0: 'Imacron': 278, michael@0: 'Lcaron': 611, michael@0: 'onehalf': 834, michael@0: 'lessequal': 549, michael@0: 'ocircumflex': 611, michael@0: 'ntilde': 611, michael@0: 'Uhungarumlaut': 722, michael@0: 'Eacute': 667, michael@0: 'emacron': 556, michael@0: 'gbreve': 611, michael@0: 'onequarter': 834, michael@0: 'Scaron': 667, michael@0: 'Scommaaccent': 667, michael@0: 'Ohungarumlaut': 778, michael@0: 'degree': 400, michael@0: 'ograve': 611, michael@0: 'Ccaron': 722, michael@0: 'ugrave': 611, michael@0: 'radical': 549, michael@0: 'Dcaron': 722, michael@0: 'rcommaaccent': 389, michael@0: 'Ntilde': 722, michael@0: 'otilde': 611, michael@0: 'Rcommaaccent': 722, michael@0: 'Lcommaaccent': 611, michael@0: 'Atilde': 722, michael@0: 'Aogonek': 722, michael@0: 'Aring': 722, michael@0: 'Otilde': 778, michael@0: 'zdotaccent': 500, michael@0: 'Ecaron': 667, michael@0: 'Iogonek': 278, michael@0: 'kcommaaccent': 556, michael@0: 'minus': 584, michael@0: 'Icircumflex': 278, michael@0: 'ncaron': 611, michael@0: 'tcommaaccent': 333, michael@0: 'logicalnot': 584, michael@0: 'odieresis': 611, michael@0: 'udieresis': 611, michael@0: 'notequal': 549, michael@0: 'gcommaaccent': 611, michael@0: 'eth': 611, michael@0: 'zcaron': 500, michael@0: 'ncommaaccent': 611, michael@0: 'onesuperior': 333, michael@0: 'imacron': 278, michael@0: 'Euro': 556 michael@0: }, michael@0: 'Helvetica-Oblique' : { michael@0: 'space': 278, michael@0: 'exclam': 278, michael@0: 'quotedbl': 355, michael@0: 'numbersign': 556, michael@0: 'dollar': 556, michael@0: 'percent': 889, michael@0: 'ampersand': 667, michael@0: 'quoteright': 222, michael@0: 'parenleft': 333, michael@0: 'parenright': 333, michael@0: 'asterisk': 389, michael@0: 'plus': 584, michael@0: 'comma': 278, michael@0: 'hyphen': 333, michael@0: 'period': 278, michael@0: 'slash': 278, michael@0: 'zero': 556, michael@0: 'one': 556, michael@0: 'two': 556, michael@0: 'three': 556, michael@0: 'four': 556, michael@0: 'five': 556, michael@0: 'six': 556, michael@0: 'seven': 556, michael@0: 'eight': 556, michael@0: 'nine': 556, michael@0: 'colon': 278, michael@0: 'semicolon': 278, michael@0: 'less': 584, michael@0: 'equal': 584, michael@0: 'greater': 584, michael@0: 'question': 556, michael@0: 'at': 1015, michael@0: 'A': 667, michael@0: 'B': 667, michael@0: 'C': 722, michael@0: 'D': 722, michael@0: 'E': 667, michael@0: 'F': 611, michael@0: 'G': 778, michael@0: 'H': 722, michael@0: 'I': 278, michael@0: 'J': 500, michael@0: 'K': 667, michael@0: 'L': 556, michael@0: 'M': 833, michael@0: 'N': 722, michael@0: 'O': 778, michael@0: 'P': 667, michael@0: 'Q': 778, michael@0: 'R': 722, michael@0: 'S': 667, michael@0: 'T': 611, michael@0: 'U': 722, michael@0: 'V': 667, michael@0: 'W': 944, michael@0: 'X': 667, michael@0: 'Y': 667, michael@0: 'Z': 611, michael@0: 'bracketleft': 278, michael@0: 'backslash': 278, michael@0: 'bracketright': 278, michael@0: 'asciicircum': 469, michael@0: 'underscore': 556, michael@0: 'quoteleft': 222, michael@0: 'a': 556, michael@0: 'b': 556, michael@0: 'c': 500, michael@0: 'd': 556, michael@0: 'e': 556, michael@0: 'f': 278, michael@0: 'g': 556, michael@0: 'h': 556, michael@0: 'i': 222, michael@0: 'j': 222, michael@0: 'k': 500, michael@0: 'l': 222, michael@0: 'm': 833, michael@0: 'n': 556, michael@0: 'o': 556, michael@0: 'p': 556, michael@0: 'q': 556, michael@0: 'r': 333, michael@0: 's': 500, michael@0: 't': 278, michael@0: 'u': 556, michael@0: 'v': 500, michael@0: 'w': 722, michael@0: 'x': 500, michael@0: 'y': 500, michael@0: 'z': 500, michael@0: 'braceleft': 334, michael@0: 'bar': 260, michael@0: 'braceright': 334, michael@0: 'asciitilde': 584, michael@0: 'exclamdown': 333, michael@0: 'cent': 556, michael@0: 'sterling': 556, michael@0: 'fraction': 167, michael@0: 'yen': 556, michael@0: 'florin': 556, michael@0: 'section': 556, michael@0: 'currency': 556, michael@0: 'quotesingle': 191, michael@0: 'quotedblleft': 333, michael@0: 'guillemotleft': 556, michael@0: 'guilsinglleft': 333, michael@0: 'guilsinglright': 333, michael@0: 'fi': 500, michael@0: 'fl': 500, michael@0: 'endash': 556, michael@0: 'dagger': 556, michael@0: 'daggerdbl': 556, michael@0: 'periodcentered': 278, michael@0: 'paragraph': 537, michael@0: 'bullet': 350, michael@0: 'quotesinglbase': 222, michael@0: 'quotedblbase': 333, michael@0: 'quotedblright': 333, michael@0: 'guillemotright': 556, michael@0: 'ellipsis': 1000, michael@0: 'perthousand': 1000, michael@0: 'questiondown': 611, michael@0: 'grave': 333, michael@0: 'acute': 333, michael@0: 'circumflex': 333, michael@0: 'tilde': 333, michael@0: 'macron': 333, michael@0: 'breve': 333, michael@0: 'dotaccent': 333, michael@0: 'dieresis': 333, michael@0: 'ring': 333, michael@0: 'cedilla': 333, michael@0: 'hungarumlaut': 333, michael@0: 'ogonek': 333, michael@0: 'caron': 333, michael@0: 'emdash': 1000, michael@0: 'AE': 1000, michael@0: 'ordfeminine': 370, michael@0: 'Lslash': 556, michael@0: 'Oslash': 778, michael@0: 'OE': 1000, michael@0: 'ordmasculine': 365, michael@0: 'ae': 889, michael@0: 'dotlessi': 278, michael@0: 'lslash': 222, michael@0: 'oslash': 611, michael@0: 'oe': 944, michael@0: 'germandbls': 611, michael@0: 'Idieresis': 278, michael@0: 'eacute': 556, michael@0: 'abreve': 556, michael@0: 'uhungarumlaut': 556, michael@0: 'ecaron': 556, michael@0: 'Ydieresis': 667, michael@0: 'divide': 584, michael@0: 'Yacute': 667, michael@0: 'Acircumflex': 667, michael@0: 'aacute': 556, michael@0: 'Ucircumflex': 722, michael@0: 'yacute': 500, michael@0: 'scommaaccent': 500, michael@0: 'ecircumflex': 556, michael@0: 'Uring': 722, michael@0: 'Udieresis': 722, michael@0: 'aogonek': 556, michael@0: 'Uacute': 722, michael@0: 'uogonek': 556, michael@0: 'Edieresis': 667, michael@0: 'Dcroat': 722, michael@0: 'commaaccent': 250, michael@0: 'copyright': 737, michael@0: 'Emacron': 667, michael@0: 'ccaron': 500, michael@0: 'aring': 556, michael@0: 'Ncommaaccent': 722, michael@0: 'lacute': 222, michael@0: 'agrave': 556, michael@0: 'Tcommaaccent': 611, michael@0: 'Cacute': 722, michael@0: 'atilde': 556, michael@0: 'Edotaccent': 667, michael@0: 'scaron': 500, michael@0: 'scedilla': 500, michael@0: 'iacute': 278, michael@0: 'lozenge': 471, michael@0: 'Rcaron': 722, michael@0: 'Gcommaaccent': 778, michael@0: 'ucircumflex': 556, michael@0: 'acircumflex': 556, michael@0: 'Amacron': 667, michael@0: 'rcaron': 333, michael@0: 'ccedilla': 500, michael@0: 'Zdotaccent': 611, michael@0: 'Thorn': 667, michael@0: 'Omacron': 778, michael@0: 'Racute': 722, michael@0: 'Sacute': 667, michael@0: 'dcaron': 643, michael@0: 'Umacron': 722, michael@0: 'uring': 556, michael@0: 'threesuperior': 333, michael@0: 'Ograve': 778, michael@0: 'Agrave': 667, michael@0: 'Abreve': 667, michael@0: 'multiply': 584, michael@0: 'uacute': 556, michael@0: 'Tcaron': 611, michael@0: 'partialdiff': 476, michael@0: 'ydieresis': 500, michael@0: 'Nacute': 722, michael@0: 'icircumflex': 278, michael@0: 'Ecircumflex': 667, michael@0: 'adieresis': 556, michael@0: 'edieresis': 556, michael@0: 'cacute': 500, michael@0: 'nacute': 556, michael@0: 'umacron': 556, michael@0: 'Ncaron': 722, michael@0: 'Iacute': 278, michael@0: 'plusminus': 584, michael@0: 'brokenbar': 260, michael@0: 'registered': 737, michael@0: 'Gbreve': 778, michael@0: 'Idotaccent': 278, michael@0: 'summation': 600, michael@0: 'Egrave': 667, michael@0: 'racute': 333, michael@0: 'omacron': 556, michael@0: 'Zacute': 611, michael@0: 'Zcaron': 611, michael@0: 'greaterequal': 549, michael@0: 'Eth': 722, michael@0: 'Ccedilla': 722, michael@0: 'lcommaaccent': 222, michael@0: 'tcaron': 317, michael@0: 'eogonek': 556, michael@0: 'Uogonek': 722, michael@0: 'Aacute': 667, michael@0: 'Adieresis': 667, michael@0: 'egrave': 556, michael@0: 'zacute': 500, michael@0: 'iogonek': 222, michael@0: 'Oacute': 778, michael@0: 'oacute': 556, michael@0: 'amacron': 556, michael@0: 'sacute': 500, michael@0: 'idieresis': 278, michael@0: 'Ocircumflex': 778, michael@0: 'Ugrave': 722, michael@0: 'Delta': 612, michael@0: 'thorn': 556, michael@0: 'twosuperior': 333, michael@0: 'Odieresis': 778, michael@0: 'mu': 556, michael@0: 'igrave': 278, michael@0: 'ohungarumlaut': 556, michael@0: 'Eogonek': 667, michael@0: 'dcroat': 556, michael@0: 'threequarters': 834, michael@0: 'Scedilla': 667, michael@0: 'lcaron': 299, michael@0: 'Kcommaaccent': 667, michael@0: 'Lacute': 556, michael@0: 'trademark': 1000, michael@0: 'edotaccent': 556, michael@0: 'Igrave': 278, michael@0: 'Imacron': 278, michael@0: 'Lcaron': 556, michael@0: 'onehalf': 834, michael@0: 'lessequal': 549, michael@0: 'ocircumflex': 556, michael@0: 'ntilde': 556, michael@0: 'Uhungarumlaut': 722, michael@0: 'Eacute': 667, michael@0: 'emacron': 556, michael@0: 'gbreve': 556, michael@0: 'onequarter': 834, michael@0: 'Scaron': 667, michael@0: 'Scommaaccent': 667, michael@0: 'Ohungarumlaut': 778, michael@0: 'degree': 400, michael@0: 'ograve': 556, michael@0: 'Ccaron': 722, michael@0: 'ugrave': 556, michael@0: 'radical': 453, michael@0: 'Dcaron': 722, michael@0: 'rcommaaccent': 333, michael@0: 'Ntilde': 722, michael@0: 'otilde': 556, michael@0: 'Rcommaaccent': 722, michael@0: 'Lcommaaccent': 556, michael@0: 'Atilde': 667, michael@0: 'Aogonek': 667, michael@0: 'Aring': 667, michael@0: 'Otilde': 778, michael@0: 'zdotaccent': 500, michael@0: 'Ecaron': 667, michael@0: 'Iogonek': 278, michael@0: 'kcommaaccent': 500, michael@0: 'minus': 584, michael@0: 'Icircumflex': 278, michael@0: 'ncaron': 556, michael@0: 'tcommaaccent': 278, michael@0: 'logicalnot': 584, michael@0: 'odieresis': 556, michael@0: 'udieresis': 556, michael@0: 'notequal': 549, michael@0: 'gcommaaccent': 556, michael@0: 'eth': 556, michael@0: 'zcaron': 500, michael@0: 'ncommaaccent': 556, michael@0: 'onesuperior': 333, michael@0: 'imacron': 278, michael@0: 'Euro': 556 michael@0: }, michael@0: 'Symbol': { michael@0: 'space': 250, michael@0: 'exclam': 333, michael@0: 'universal': 713, michael@0: 'numbersign': 500, michael@0: 'existential': 549, michael@0: 'percent': 833, michael@0: 'ampersand': 778, michael@0: 'suchthat': 439, michael@0: 'parenleft': 333, michael@0: 'parenright': 333, michael@0: 'asteriskmath': 500, michael@0: 'plus': 549, michael@0: 'comma': 250, michael@0: 'minus': 549, michael@0: 'period': 250, michael@0: 'slash': 278, michael@0: 'zero': 500, michael@0: 'one': 500, michael@0: 'two': 500, michael@0: 'three': 500, michael@0: 'four': 500, michael@0: 'five': 500, michael@0: 'six': 500, michael@0: 'seven': 500, michael@0: 'eight': 500, michael@0: 'nine': 500, michael@0: 'colon': 278, michael@0: 'semicolon': 278, michael@0: 'less': 549, michael@0: 'equal': 549, michael@0: 'greater': 549, michael@0: 'question': 444, michael@0: 'congruent': 549, michael@0: 'Alpha': 722, michael@0: 'Beta': 667, michael@0: 'Chi': 722, michael@0: 'Delta': 612, michael@0: 'Epsilon': 611, michael@0: 'Phi': 763, michael@0: 'Gamma': 603, michael@0: 'Eta': 722, michael@0: 'Iota': 333, michael@0: 'theta1': 631, michael@0: 'Kappa': 722, michael@0: 'Lambda': 686, michael@0: 'Mu': 889, michael@0: 'Nu': 722, michael@0: 'Omicron': 722, michael@0: 'Pi': 768, michael@0: 'Theta': 741, michael@0: 'Rho': 556, michael@0: 'Sigma': 592, michael@0: 'Tau': 611, michael@0: 'Upsilon': 690, michael@0: 'sigma1': 439, michael@0: 'Omega': 768, michael@0: 'Xi': 645, michael@0: 'Psi': 795, michael@0: 'Zeta': 611, michael@0: 'bracketleft': 333, michael@0: 'therefore': 863, michael@0: 'bracketright': 333, michael@0: 'perpendicular': 658, michael@0: 'underscore': 500, michael@0: 'radicalex': 500, michael@0: 'alpha': 631, michael@0: 'beta': 549, michael@0: 'chi': 549, michael@0: 'delta': 494, michael@0: 'epsilon': 439, michael@0: 'phi': 521, michael@0: 'gamma': 411, michael@0: 'eta': 603, michael@0: 'iota': 329, michael@0: 'phi1': 603, michael@0: 'kappa': 549, michael@0: 'lambda': 549, michael@0: 'mu': 576, michael@0: 'nu': 521, michael@0: 'omicron': 549, michael@0: 'pi': 549, michael@0: 'theta': 521, michael@0: 'rho': 549, michael@0: 'sigma': 603, michael@0: 'tau': 439, michael@0: 'upsilon': 576, michael@0: 'omega1': 713, michael@0: 'omega': 686, michael@0: 'xi': 493, michael@0: 'psi': 686, michael@0: 'zeta': 494, michael@0: 'braceleft': 480, michael@0: 'bar': 200, michael@0: 'braceright': 480, michael@0: 'similar': 549, michael@0: 'Euro': 750, michael@0: 'Upsilon1': 620, michael@0: 'minute': 247, michael@0: 'lessequal': 549, michael@0: 'fraction': 167, michael@0: 'infinity': 713, michael@0: 'florin': 500, michael@0: 'club': 753, michael@0: 'diamond': 753, michael@0: 'heart': 753, michael@0: 'spade': 753, michael@0: 'arrowboth': 1042, michael@0: 'arrowleft': 987, michael@0: 'arrowup': 603, michael@0: 'arrowright': 987, michael@0: 'arrowdown': 603, michael@0: 'degree': 400, michael@0: 'plusminus': 549, michael@0: 'second': 411, michael@0: 'greaterequal': 549, michael@0: 'multiply': 549, michael@0: 'proportional': 713, michael@0: 'partialdiff': 494, michael@0: 'bullet': 460, michael@0: 'divide': 549, michael@0: 'notequal': 549, michael@0: 'equivalence': 549, michael@0: 'approxequal': 549, michael@0: 'ellipsis': 1000, michael@0: 'arrowvertex': 603, michael@0: 'arrowhorizex': 1000, michael@0: 'carriagereturn': 658, michael@0: 'aleph': 823, michael@0: 'Ifraktur': 686, michael@0: 'Rfraktur': 795, michael@0: 'weierstrass': 987, michael@0: 'circlemultiply': 768, michael@0: 'circleplus': 768, michael@0: 'emptyset': 823, michael@0: 'intersection': 768, michael@0: 'union': 768, michael@0: 'propersuperset': 713, michael@0: 'reflexsuperset': 713, michael@0: 'notsubset': 713, michael@0: 'propersubset': 713, michael@0: 'reflexsubset': 713, michael@0: 'element': 713, michael@0: 'notelement': 713, michael@0: 'angle': 768, michael@0: 'gradient': 713, michael@0: 'registerserif': 790, michael@0: 'copyrightserif': 790, michael@0: 'trademarkserif': 890, michael@0: 'product': 823, michael@0: 'radical': 549, michael@0: 'dotmath': 250, michael@0: 'logicalnot': 713, michael@0: 'logicaland': 603, michael@0: 'logicalor': 603, michael@0: 'arrowdblboth': 1042, michael@0: 'arrowdblleft': 987, michael@0: 'arrowdblup': 603, michael@0: 'arrowdblright': 987, michael@0: 'arrowdbldown': 603, michael@0: 'lozenge': 494, michael@0: 'angleleft': 329, michael@0: 'registersans': 790, michael@0: 'copyrightsans': 790, michael@0: 'trademarksans': 786, michael@0: 'summation': 713, michael@0: 'parenlefttp': 384, michael@0: 'parenleftex': 384, michael@0: 'parenleftbt': 384, michael@0: 'bracketlefttp': 384, michael@0: 'bracketleftex': 384, michael@0: 'bracketleftbt': 384, michael@0: 'bracelefttp': 494, michael@0: 'braceleftmid': 494, michael@0: 'braceleftbt': 494, michael@0: 'braceex': 494, michael@0: 'angleright': 329, michael@0: 'integral': 274, michael@0: 'integraltp': 686, michael@0: 'integralex': 686, michael@0: 'integralbt': 686, michael@0: 'parenrighttp': 384, michael@0: 'parenrightex': 384, michael@0: 'parenrightbt': 384, michael@0: 'bracketrighttp': 384, michael@0: 'bracketrightex': 384, michael@0: 'bracketrightbt': 384, michael@0: 'bracerighttp': 494, michael@0: 'bracerightmid': 494, michael@0: 'bracerightbt': 494, michael@0: 'apple': 790 michael@0: }, michael@0: 'Times-Roman': { michael@0: 'space': 250, michael@0: 'exclam': 333, michael@0: 'quotedbl': 408, michael@0: 'numbersign': 500, michael@0: 'dollar': 500, michael@0: 'percent': 833, michael@0: 'ampersand': 778, michael@0: 'quoteright': 333, michael@0: 'parenleft': 333, michael@0: 'parenright': 333, michael@0: 'asterisk': 500, michael@0: 'plus': 564, michael@0: 'comma': 250, michael@0: 'hyphen': 333, michael@0: 'period': 250, michael@0: 'slash': 278, michael@0: 'zero': 500, michael@0: 'one': 500, michael@0: 'two': 500, michael@0: 'three': 500, michael@0: 'four': 500, michael@0: 'five': 500, michael@0: 'six': 500, michael@0: 'seven': 500, michael@0: 'eight': 500, michael@0: 'nine': 500, michael@0: 'colon': 278, michael@0: 'semicolon': 278, michael@0: 'less': 564, michael@0: 'equal': 564, michael@0: 'greater': 564, michael@0: 'question': 444, michael@0: 'at': 921, michael@0: 'A': 722, michael@0: 'B': 667, michael@0: 'C': 667, michael@0: 'D': 722, michael@0: 'E': 611, michael@0: 'F': 556, michael@0: 'G': 722, michael@0: 'H': 722, michael@0: 'I': 333, michael@0: 'J': 389, michael@0: 'K': 722, michael@0: 'L': 611, michael@0: 'M': 889, michael@0: 'N': 722, michael@0: 'O': 722, michael@0: 'P': 556, michael@0: 'Q': 722, michael@0: 'R': 667, michael@0: 'S': 556, michael@0: 'T': 611, michael@0: 'U': 722, michael@0: 'V': 722, michael@0: 'W': 944, michael@0: 'X': 722, michael@0: 'Y': 722, michael@0: 'Z': 611, michael@0: 'bracketleft': 333, michael@0: 'backslash': 278, michael@0: 'bracketright': 333, michael@0: 'asciicircum': 469, michael@0: 'underscore': 500, michael@0: 'quoteleft': 333, michael@0: 'a': 444, michael@0: 'b': 500, michael@0: 'c': 444, michael@0: 'd': 500, michael@0: 'e': 444, michael@0: 'f': 333, michael@0: 'g': 500, michael@0: 'h': 500, michael@0: 'i': 278, michael@0: 'j': 278, michael@0: 'k': 500, michael@0: 'l': 278, michael@0: 'm': 778, michael@0: 'n': 500, michael@0: 'o': 500, michael@0: 'p': 500, michael@0: 'q': 500, michael@0: 'r': 333, michael@0: 's': 389, michael@0: 't': 278, michael@0: 'u': 500, michael@0: 'v': 500, michael@0: 'w': 722, michael@0: 'x': 500, michael@0: 'y': 500, michael@0: 'z': 444, michael@0: 'braceleft': 480, michael@0: 'bar': 200, michael@0: 'braceright': 480, michael@0: 'asciitilde': 541, michael@0: 'exclamdown': 333, michael@0: 'cent': 500, michael@0: 'sterling': 500, michael@0: 'fraction': 167, michael@0: 'yen': 500, michael@0: 'florin': 500, michael@0: 'section': 500, michael@0: 'currency': 500, michael@0: 'quotesingle': 180, michael@0: 'quotedblleft': 444, michael@0: 'guillemotleft': 500, michael@0: 'guilsinglleft': 333, michael@0: 'guilsinglright': 333, michael@0: 'fi': 556, michael@0: 'fl': 556, michael@0: 'endash': 500, michael@0: 'dagger': 500, michael@0: 'daggerdbl': 500, michael@0: 'periodcentered': 250, michael@0: 'paragraph': 453, michael@0: 'bullet': 350, michael@0: 'quotesinglbase': 333, michael@0: 'quotedblbase': 444, michael@0: 'quotedblright': 444, michael@0: 'guillemotright': 500, michael@0: 'ellipsis': 1000, michael@0: 'perthousand': 1000, michael@0: 'questiondown': 444, michael@0: 'grave': 333, michael@0: 'acute': 333, michael@0: 'circumflex': 333, michael@0: 'tilde': 333, michael@0: 'macron': 333, michael@0: 'breve': 333, michael@0: 'dotaccent': 333, michael@0: 'dieresis': 333, michael@0: 'ring': 333, michael@0: 'cedilla': 333, michael@0: 'hungarumlaut': 333, michael@0: 'ogonek': 333, michael@0: 'caron': 333, michael@0: 'emdash': 1000, michael@0: 'AE': 889, michael@0: 'ordfeminine': 276, michael@0: 'Lslash': 611, michael@0: 'Oslash': 722, michael@0: 'OE': 889, michael@0: 'ordmasculine': 310, michael@0: 'ae': 667, michael@0: 'dotlessi': 278, michael@0: 'lslash': 278, michael@0: 'oslash': 500, michael@0: 'oe': 722, michael@0: 'germandbls': 500, michael@0: 'Idieresis': 333, michael@0: 'eacute': 444, michael@0: 'abreve': 444, michael@0: 'uhungarumlaut': 500, michael@0: 'ecaron': 444, michael@0: 'Ydieresis': 722, michael@0: 'divide': 564, michael@0: 'Yacute': 722, michael@0: 'Acircumflex': 722, michael@0: 'aacute': 444, michael@0: 'Ucircumflex': 722, michael@0: 'yacute': 500, michael@0: 'scommaaccent': 389, michael@0: 'ecircumflex': 444, michael@0: 'Uring': 722, michael@0: 'Udieresis': 722, michael@0: 'aogonek': 444, michael@0: 'Uacute': 722, michael@0: 'uogonek': 500, michael@0: 'Edieresis': 611, michael@0: 'Dcroat': 722, michael@0: 'commaaccent': 250, michael@0: 'copyright': 760, michael@0: 'Emacron': 611, michael@0: 'ccaron': 444, michael@0: 'aring': 444, michael@0: 'Ncommaaccent': 722, michael@0: 'lacute': 278, michael@0: 'agrave': 444, michael@0: 'Tcommaaccent': 611, michael@0: 'Cacute': 667, michael@0: 'atilde': 444, michael@0: 'Edotaccent': 611, michael@0: 'scaron': 389, michael@0: 'scedilla': 389, michael@0: 'iacute': 278, michael@0: 'lozenge': 471, michael@0: 'Rcaron': 667, michael@0: 'Gcommaaccent': 722, michael@0: 'ucircumflex': 500, michael@0: 'acircumflex': 444, michael@0: 'Amacron': 722, michael@0: 'rcaron': 333, michael@0: 'ccedilla': 444, michael@0: 'Zdotaccent': 611, michael@0: 'Thorn': 556, michael@0: 'Omacron': 722, michael@0: 'Racute': 667, michael@0: 'Sacute': 556, michael@0: 'dcaron': 588, michael@0: 'Umacron': 722, michael@0: 'uring': 500, michael@0: 'threesuperior': 300, michael@0: 'Ograve': 722, michael@0: 'Agrave': 722, michael@0: 'Abreve': 722, michael@0: 'multiply': 564, michael@0: 'uacute': 500, michael@0: 'Tcaron': 611, michael@0: 'partialdiff': 476, michael@0: 'ydieresis': 500, michael@0: 'Nacute': 722, michael@0: 'icircumflex': 278, michael@0: 'Ecircumflex': 611, michael@0: 'adieresis': 444, michael@0: 'edieresis': 444, michael@0: 'cacute': 444, michael@0: 'nacute': 500, michael@0: 'umacron': 500, michael@0: 'Ncaron': 722, michael@0: 'Iacute': 333, michael@0: 'plusminus': 564, michael@0: 'brokenbar': 200, michael@0: 'registered': 760, michael@0: 'Gbreve': 722, michael@0: 'Idotaccent': 333, michael@0: 'summation': 600, michael@0: 'Egrave': 611, michael@0: 'racute': 333, michael@0: 'omacron': 500, michael@0: 'Zacute': 611, michael@0: 'Zcaron': 611, michael@0: 'greaterequal': 549, michael@0: 'Eth': 722, michael@0: 'Ccedilla': 667, michael@0: 'lcommaaccent': 278, michael@0: 'tcaron': 326, michael@0: 'eogonek': 444, michael@0: 'Uogonek': 722, michael@0: 'Aacute': 722, michael@0: 'Adieresis': 722, michael@0: 'egrave': 444, michael@0: 'zacute': 444, michael@0: 'iogonek': 278, michael@0: 'Oacute': 722, michael@0: 'oacute': 500, michael@0: 'amacron': 444, michael@0: 'sacute': 389, michael@0: 'idieresis': 278, michael@0: 'Ocircumflex': 722, michael@0: 'Ugrave': 722, michael@0: 'Delta': 612, michael@0: 'thorn': 500, michael@0: 'twosuperior': 300, michael@0: 'Odieresis': 722, michael@0: 'mu': 500, michael@0: 'igrave': 278, michael@0: 'ohungarumlaut': 500, michael@0: 'Eogonek': 611, michael@0: 'dcroat': 500, michael@0: 'threequarters': 750, michael@0: 'Scedilla': 556, michael@0: 'lcaron': 344, michael@0: 'Kcommaaccent': 722, michael@0: 'Lacute': 611, michael@0: 'trademark': 980, michael@0: 'edotaccent': 444, michael@0: 'Igrave': 333, michael@0: 'Imacron': 333, michael@0: 'Lcaron': 611, michael@0: 'onehalf': 750, michael@0: 'lessequal': 549, michael@0: 'ocircumflex': 500, michael@0: 'ntilde': 500, michael@0: 'Uhungarumlaut': 722, michael@0: 'Eacute': 611, michael@0: 'emacron': 444, michael@0: 'gbreve': 500, michael@0: 'onequarter': 750, michael@0: 'Scaron': 556, michael@0: 'Scommaaccent': 556, michael@0: 'Ohungarumlaut': 722, michael@0: 'degree': 400, michael@0: 'ograve': 500, michael@0: 'Ccaron': 667, michael@0: 'ugrave': 500, michael@0: 'radical': 453, michael@0: 'Dcaron': 722, michael@0: 'rcommaaccent': 333, michael@0: 'Ntilde': 722, michael@0: 'otilde': 500, michael@0: 'Rcommaaccent': 667, michael@0: 'Lcommaaccent': 611, michael@0: 'Atilde': 722, michael@0: 'Aogonek': 722, michael@0: 'Aring': 722, michael@0: 'Otilde': 722, michael@0: 'zdotaccent': 444, michael@0: 'Ecaron': 611, michael@0: 'Iogonek': 333, michael@0: 'kcommaaccent': 500, michael@0: 'minus': 564, michael@0: 'Icircumflex': 333, michael@0: 'ncaron': 500, michael@0: 'tcommaaccent': 278, michael@0: 'logicalnot': 564, michael@0: 'odieresis': 500, michael@0: 'udieresis': 500, michael@0: 'notequal': 549, michael@0: 'gcommaaccent': 500, michael@0: 'eth': 500, michael@0: 'zcaron': 444, michael@0: 'ncommaaccent': 500, michael@0: 'onesuperior': 300, michael@0: 'imacron': 278, michael@0: 'Euro': 500 michael@0: }, michael@0: 'Times-Bold': { michael@0: 'space': 250, michael@0: 'exclam': 333, michael@0: 'quotedbl': 555, michael@0: 'numbersign': 500, michael@0: 'dollar': 500, michael@0: 'percent': 1000, michael@0: 'ampersand': 833, michael@0: 'quoteright': 333, michael@0: 'parenleft': 333, michael@0: 'parenright': 333, michael@0: 'asterisk': 500, michael@0: 'plus': 570, michael@0: 'comma': 250, michael@0: 'hyphen': 333, michael@0: 'period': 250, michael@0: 'slash': 278, michael@0: 'zero': 500, michael@0: 'one': 500, michael@0: 'two': 500, michael@0: 'three': 500, michael@0: 'four': 500, michael@0: 'five': 500, michael@0: 'six': 500, michael@0: 'seven': 500, michael@0: 'eight': 500, michael@0: 'nine': 500, michael@0: 'colon': 333, michael@0: 'semicolon': 333, michael@0: 'less': 570, michael@0: 'equal': 570, michael@0: 'greater': 570, michael@0: 'question': 500, michael@0: 'at': 930, michael@0: 'A': 722, michael@0: 'B': 667, michael@0: 'C': 722, michael@0: 'D': 722, michael@0: 'E': 667, michael@0: 'F': 611, michael@0: 'G': 778, michael@0: 'H': 778, michael@0: 'I': 389, michael@0: 'J': 500, michael@0: 'K': 778, michael@0: 'L': 667, michael@0: 'M': 944, michael@0: 'N': 722, michael@0: 'O': 778, michael@0: 'P': 611, michael@0: 'Q': 778, michael@0: 'R': 722, michael@0: 'S': 556, michael@0: 'T': 667, michael@0: 'U': 722, michael@0: 'V': 722, michael@0: 'W': 1000, michael@0: 'X': 722, michael@0: 'Y': 722, michael@0: 'Z': 667, michael@0: 'bracketleft': 333, michael@0: 'backslash': 278, michael@0: 'bracketright': 333, michael@0: 'asciicircum': 581, michael@0: 'underscore': 500, michael@0: 'quoteleft': 333, michael@0: 'a': 500, michael@0: 'b': 556, michael@0: 'c': 444, michael@0: 'd': 556, michael@0: 'e': 444, michael@0: 'f': 333, michael@0: 'g': 500, michael@0: 'h': 556, michael@0: 'i': 278, michael@0: 'j': 333, michael@0: 'k': 556, michael@0: 'l': 278, michael@0: 'm': 833, michael@0: 'n': 556, michael@0: 'o': 500, michael@0: 'p': 556, michael@0: 'q': 556, michael@0: 'r': 444, michael@0: 's': 389, michael@0: 't': 333, michael@0: 'u': 556, michael@0: 'v': 500, michael@0: 'w': 722, michael@0: 'x': 500, michael@0: 'y': 500, michael@0: 'z': 444, michael@0: 'braceleft': 394, michael@0: 'bar': 220, michael@0: 'braceright': 394, michael@0: 'asciitilde': 520, michael@0: 'exclamdown': 333, michael@0: 'cent': 500, michael@0: 'sterling': 500, michael@0: 'fraction': 167, michael@0: 'yen': 500, michael@0: 'florin': 500, michael@0: 'section': 500, michael@0: 'currency': 500, michael@0: 'quotesingle': 278, michael@0: 'quotedblleft': 500, michael@0: 'guillemotleft': 500, michael@0: 'guilsinglleft': 333, michael@0: 'guilsinglright': 333, michael@0: 'fi': 556, michael@0: 'fl': 556, michael@0: 'endash': 500, michael@0: 'dagger': 500, michael@0: 'daggerdbl': 500, michael@0: 'periodcentered': 250, michael@0: 'paragraph': 540, michael@0: 'bullet': 350, michael@0: 'quotesinglbase': 333, michael@0: 'quotedblbase': 500, michael@0: 'quotedblright': 500, michael@0: 'guillemotright': 500, michael@0: 'ellipsis': 1000, michael@0: 'perthousand': 1000, michael@0: 'questiondown': 500, michael@0: 'grave': 333, michael@0: 'acute': 333, michael@0: 'circumflex': 333, michael@0: 'tilde': 333, michael@0: 'macron': 333, michael@0: 'breve': 333, michael@0: 'dotaccent': 333, michael@0: 'dieresis': 333, michael@0: 'ring': 333, michael@0: 'cedilla': 333, michael@0: 'hungarumlaut': 333, michael@0: 'ogonek': 333, michael@0: 'caron': 333, michael@0: 'emdash': 1000, michael@0: 'AE': 1000, michael@0: 'ordfeminine': 300, michael@0: 'Lslash': 667, michael@0: 'Oslash': 778, michael@0: 'OE': 1000, michael@0: 'ordmasculine': 330, michael@0: 'ae': 722, michael@0: 'dotlessi': 278, michael@0: 'lslash': 278, michael@0: 'oslash': 500, michael@0: 'oe': 722, michael@0: 'germandbls': 556, michael@0: 'Idieresis': 389, michael@0: 'eacute': 444, michael@0: 'abreve': 500, michael@0: 'uhungarumlaut': 556, michael@0: 'ecaron': 444, michael@0: 'Ydieresis': 722, michael@0: 'divide': 570, michael@0: 'Yacute': 722, michael@0: 'Acircumflex': 722, michael@0: 'aacute': 500, michael@0: 'Ucircumflex': 722, michael@0: 'yacute': 500, michael@0: 'scommaaccent': 389, michael@0: 'ecircumflex': 444, michael@0: 'Uring': 722, michael@0: 'Udieresis': 722, michael@0: 'aogonek': 500, michael@0: 'Uacute': 722, michael@0: 'uogonek': 556, michael@0: 'Edieresis': 667, michael@0: 'Dcroat': 722, michael@0: 'commaaccent': 250, michael@0: 'copyright': 747, michael@0: 'Emacron': 667, michael@0: 'ccaron': 444, michael@0: 'aring': 500, michael@0: 'Ncommaaccent': 722, michael@0: 'lacute': 278, michael@0: 'agrave': 500, michael@0: 'Tcommaaccent': 667, michael@0: 'Cacute': 722, michael@0: 'atilde': 500, michael@0: 'Edotaccent': 667, michael@0: 'scaron': 389, michael@0: 'scedilla': 389, michael@0: 'iacute': 278, michael@0: 'lozenge': 494, michael@0: 'Rcaron': 722, michael@0: 'Gcommaaccent': 778, michael@0: 'ucircumflex': 556, michael@0: 'acircumflex': 500, michael@0: 'Amacron': 722, michael@0: 'rcaron': 444, michael@0: 'ccedilla': 444, michael@0: 'Zdotaccent': 667, michael@0: 'Thorn': 611, michael@0: 'Omacron': 778, michael@0: 'Racute': 722, michael@0: 'Sacute': 556, michael@0: 'dcaron': 672, michael@0: 'Umacron': 722, michael@0: 'uring': 556, michael@0: 'threesuperior': 300, michael@0: 'Ograve': 778, michael@0: 'Agrave': 722, michael@0: 'Abreve': 722, michael@0: 'multiply': 570, michael@0: 'uacute': 556, michael@0: 'Tcaron': 667, michael@0: 'partialdiff': 494, michael@0: 'ydieresis': 500, michael@0: 'Nacute': 722, michael@0: 'icircumflex': 278, michael@0: 'Ecircumflex': 667, michael@0: 'adieresis': 500, michael@0: 'edieresis': 444, michael@0: 'cacute': 444, michael@0: 'nacute': 556, michael@0: 'umacron': 556, michael@0: 'Ncaron': 722, michael@0: 'Iacute': 389, michael@0: 'plusminus': 570, michael@0: 'brokenbar': 220, michael@0: 'registered': 747, michael@0: 'Gbreve': 778, michael@0: 'Idotaccent': 389, michael@0: 'summation': 600, michael@0: 'Egrave': 667, michael@0: 'racute': 444, michael@0: 'omacron': 500, michael@0: 'Zacute': 667, michael@0: 'Zcaron': 667, michael@0: 'greaterequal': 549, michael@0: 'Eth': 722, michael@0: 'Ccedilla': 722, michael@0: 'lcommaaccent': 278, michael@0: 'tcaron': 416, michael@0: 'eogonek': 444, michael@0: 'Uogonek': 722, michael@0: 'Aacute': 722, michael@0: 'Adieresis': 722, michael@0: 'egrave': 444, michael@0: 'zacute': 444, michael@0: 'iogonek': 278, michael@0: 'Oacute': 778, michael@0: 'oacute': 500, michael@0: 'amacron': 500, michael@0: 'sacute': 389, michael@0: 'idieresis': 278, michael@0: 'Ocircumflex': 778, michael@0: 'Ugrave': 722, michael@0: 'Delta': 612, michael@0: 'thorn': 556, michael@0: 'twosuperior': 300, michael@0: 'Odieresis': 778, michael@0: 'mu': 556, michael@0: 'igrave': 278, michael@0: 'ohungarumlaut': 500, michael@0: 'Eogonek': 667, michael@0: 'dcroat': 556, michael@0: 'threequarters': 750, michael@0: 'Scedilla': 556, michael@0: 'lcaron': 394, michael@0: 'Kcommaaccent': 778, michael@0: 'Lacute': 667, michael@0: 'trademark': 1000, michael@0: 'edotaccent': 444, michael@0: 'Igrave': 389, michael@0: 'Imacron': 389, michael@0: 'Lcaron': 667, michael@0: 'onehalf': 750, michael@0: 'lessequal': 549, michael@0: 'ocircumflex': 500, michael@0: 'ntilde': 556, michael@0: 'Uhungarumlaut': 722, michael@0: 'Eacute': 667, michael@0: 'emacron': 444, michael@0: 'gbreve': 500, michael@0: 'onequarter': 750, michael@0: 'Scaron': 556, michael@0: 'Scommaaccent': 556, michael@0: 'Ohungarumlaut': 778, michael@0: 'degree': 400, michael@0: 'ograve': 500, michael@0: 'Ccaron': 722, michael@0: 'ugrave': 556, michael@0: 'radical': 549, michael@0: 'Dcaron': 722, michael@0: 'rcommaaccent': 444, michael@0: 'Ntilde': 722, michael@0: 'otilde': 500, michael@0: 'Rcommaaccent': 722, michael@0: 'Lcommaaccent': 667, michael@0: 'Atilde': 722, michael@0: 'Aogonek': 722, michael@0: 'Aring': 722, michael@0: 'Otilde': 778, michael@0: 'zdotaccent': 444, michael@0: 'Ecaron': 667, michael@0: 'Iogonek': 389, michael@0: 'kcommaaccent': 556, michael@0: 'minus': 570, michael@0: 'Icircumflex': 389, michael@0: 'ncaron': 556, michael@0: 'tcommaaccent': 333, michael@0: 'logicalnot': 570, michael@0: 'odieresis': 500, michael@0: 'udieresis': 556, michael@0: 'notequal': 549, michael@0: 'gcommaaccent': 500, michael@0: 'eth': 500, michael@0: 'zcaron': 444, michael@0: 'ncommaaccent': 556, michael@0: 'onesuperior': 300, michael@0: 'imacron': 278, michael@0: 'Euro': 500 michael@0: }, michael@0: 'Times-BoldItalic': { michael@0: 'space': 250, michael@0: 'exclam': 389, michael@0: 'quotedbl': 555, michael@0: 'numbersign': 500, michael@0: 'dollar': 500, michael@0: 'percent': 833, michael@0: 'ampersand': 778, michael@0: 'quoteright': 333, michael@0: 'parenleft': 333, michael@0: 'parenright': 333, michael@0: 'asterisk': 500, michael@0: 'plus': 570, michael@0: 'comma': 250, michael@0: 'hyphen': 333, michael@0: 'period': 250, michael@0: 'slash': 278, michael@0: 'zero': 500, michael@0: 'one': 500, michael@0: 'two': 500, michael@0: 'three': 500, michael@0: 'four': 500, michael@0: 'five': 500, michael@0: 'six': 500, michael@0: 'seven': 500, michael@0: 'eight': 500, michael@0: 'nine': 500, michael@0: 'colon': 333, michael@0: 'semicolon': 333, michael@0: 'less': 570, michael@0: 'equal': 570, michael@0: 'greater': 570, michael@0: 'question': 500, michael@0: 'at': 832, michael@0: 'A': 667, michael@0: 'B': 667, michael@0: 'C': 667, michael@0: 'D': 722, michael@0: 'E': 667, michael@0: 'F': 667, michael@0: 'G': 722, michael@0: 'H': 778, michael@0: 'I': 389, michael@0: 'J': 500, michael@0: 'K': 667, michael@0: 'L': 611, michael@0: 'M': 889, michael@0: 'N': 722, michael@0: 'O': 722, michael@0: 'P': 611, michael@0: 'Q': 722, michael@0: 'R': 667, michael@0: 'S': 556, michael@0: 'T': 611, michael@0: 'U': 722, michael@0: 'V': 667, michael@0: 'W': 889, michael@0: 'X': 667, michael@0: 'Y': 611, michael@0: 'Z': 611, michael@0: 'bracketleft': 333, michael@0: 'backslash': 278, michael@0: 'bracketright': 333, michael@0: 'asciicircum': 570, michael@0: 'underscore': 500, michael@0: 'quoteleft': 333, michael@0: 'a': 500, michael@0: 'b': 500, michael@0: 'c': 444, michael@0: 'd': 500, michael@0: 'e': 444, michael@0: 'f': 333, michael@0: 'g': 500, michael@0: 'h': 556, michael@0: 'i': 278, michael@0: 'j': 278, michael@0: 'k': 500, michael@0: 'l': 278, michael@0: 'm': 778, michael@0: 'n': 556, michael@0: 'o': 500, michael@0: 'p': 500, michael@0: 'q': 500, michael@0: 'r': 389, michael@0: 's': 389, michael@0: 't': 278, michael@0: 'u': 556, michael@0: 'v': 444, michael@0: 'w': 667, michael@0: 'x': 500, michael@0: 'y': 444, michael@0: 'z': 389, michael@0: 'braceleft': 348, michael@0: 'bar': 220, michael@0: 'braceright': 348, michael@0: 'asciitilde': 570, michael@0: 'exclamdown': 389, michael@0: 'cent': 500, michael@0: 'sterling': 500, michael@0: 'fraction': 167, michael@0: 'yen': 500, michael@0: 'florin': 500, michael@0: 'section': 500, michael@0: 'currency': 500, michael@0: 'quotesingle': 278, michael@0: 'quotedblleft': 500, michael@0: 'guillemotleft': 500, michael@0: 'guilsinglleft': 333, michael@0: 'guilsinglright': 333, michael@0: 'fi': 556, michael@0: 'fl': 556, michael@0: 'endash': 500, michael@0: 'dagger': 500, michael@0: 'daggerdbl': 500, michael@0: 'periodcentered': 250, michael@0: 'paragraph': 500, michael@0: 'bullet': 350, michael@0: 'quotesinglbase': 333, michael@0: 'quotedblbase': 500, michael@0: 'quotedblright': 500, michael@0: 'guillemotright': 500, michael@0: 'ellipsis': 1000, michael@0: 'perthousand': 1000, michael@0: 'questiondown': 500, michael@0: 'grave': 333, michael@0: 'acute': 333, michael@0: 'circumflex': 333, michael@0: 'tilde': 333, michael@0: 'macron': 333, michael@0: 'breve': 333, michael@0: 'dotaccent': 333, michael@0: 'dieresis': 333, michael@0: 'ring': 333, michael@0: 'cedilla': 333, michael@0: 'hungarumlaut': 333, michael@0: 'ogonek': 333, michael@0: 'caron': 333, michael@0: 'emdash': 1000, michael@0: 'AE': 944, michael@0: 'ordfeminine': 266, michael@0: 'Lslash': 611, michael@0: 'Oslash': 722, michael@0: 'OE': 944, michael@0: 'ordmasculine': 300, michael@0: 'ae': 722, michael@0: 'dotlessi': 278, michael@0: 'lslash': 278, michael@0: 'oslash': 500, michael@0: 'oe': 722, michael@0: 'germandbls': 500, michael@0: 'Idieresis': 389, michael@0: 'eacute': 444, michael@0: 'abreve': 500, michael@0: 'uhungarumlaut': 556, michael@0: 'ecaron': 444, michael@0: 'Ydieresis': 611, michael@0: 'divide': 570, michael@0: 'Yacute': 611, michael@0: 'Acircumflex': 667, michael@0: 'aacute': 500, michael@0: 'Ucircumflex': 722, michael@0: 'yacute': 444, michael@0: 'scommaaccent': 389, michael@0: 'ecircumflex': 444, michael@0: 'Uring': 722, michael@0: 'Udieresis': 722, michael@0: 'aogonek': 500, michael@0: 'Uacute': 722, michael@0: 'uogonek': 556, michael@0: 'Edieresis': 667, michael@0: 'Dcroat': 722, michael@0: 'commaaccent': 250, michael@0: 'copyright': 747, michael@0: 'Emacron': 667, michael@0: 'ccaron': 444, michael@0: 'aring': 500, michael@0: 'Ncommaaccent': 722, michael@0: 'lacute': 278, michael@0: 'agrave': 500, michael@0: 'Tcommaaccent': 611, michael@0: 'Cacute': 667, michael@0: 'atilde': 500, michael@0: 'Edotaccent': 667, michael@0: 'scaron': 389, michael@0: 'scedilla': 389, michael@0: 'iacute': 278, michael@0: 'lozenge': 494, michael@0: 'Rcaron': 667, michael@0: 'Gcommaaccent': 722, michael@0: 'ucircumflex': 556, michael@0: 'acircumflex': 500, michael@0: 'Amacron': 667, michael@0: 'rcaron': 389, michael@0: 'ccedilla': 444, michael@0: 'Zdotaccent': 611, michael@0: 'Thorn': 611, michael@0: 'Omacron': 722, michael@0: 'Racute': 667, michael@0: 'Sacute': 556, michael@0: 'dcaron': 608, michael@0: 'Umacron': 722, michael@0: 'uring': 556, michael@0: 'threesuperior': 300, michael@0: 'Ograve': 722, michael@0: 'Agrave': 667, michael@0: 'Abreve': 667, michael@0: 'multiply': 570, michael@0: 'uacute': 556, michael@0: 'Tcaron': 611, michael@0: 'partialdiff': 494, michael@0: 'ydieresis': 444, michael@0: 'Nacute': 722, michael@0: 'icircumflex': 278, michael@0: 'Ecircumflex': 667, michael@0: 'adieresis': 500, michael@0: 'edieresis': 444, michael@0: 'cacute': 444, michael@0: 'nacute': 556, michael@0: 'umacron': 556, michael@0: 'Ncaron': 722, michael@0: 'Iacute': 389, michael@0: 'plusminus': 570, michael@0: 'brokenbar': 220, michael@0: 'registered': 747, michael@0: 'Gbreve': 722, michael@0: 'Idotaccent': 389, michael@0: 'summation': 600, michael@0: 'Egrave': 667, michael@0: 'racute': 389, michael@0: 'omacron': 500, michael@0: 'Zacute': 611, michael@0: 'Zcaron': 611, michael@0: 'greaterequal': 549, michael@0: 'Eth': 722, michael@0: 'Ccedilla': 667, michael@0: 'lcommaaccent': 278, michael@0: 'tcaron': 366, michael@0: 'eogonek': 444, michael@0: 'Uogonek': 722, michael@0: 'Aacute': 667, michael@0: 'Adieresis': 667, michael@0: 'egrave': 444, michael@0: 'zacute': 389, michael@0: 'iogonek': 278, michael@0: 'Oacute': 722, michael@0: 'oacute': 500, michael@0: 'amacron': 500, michael@0: 'sacute': 389, michael@0: 'idieresis': 278, michael@0: 'Ocircumflex': 722, michael@0: 'Ugrave': 722, michael@0: 'Delta': 612, michael@0: 'thorn': 500, michael@0: 'twosuperior': 300, michael@0: 'Odieresis': 722, michael@0: 'mu': 576, michael@0: 'igrave': 278, michael@0: 'ohungarumlaut': 500, michael@0: 'Eogonek': 667, michael@0: 'dcroat': 500, michael@0: 'threequarters': 750, michael@0: 'Scedilla': 556, michael@0: 'lcaron': 382, michael@0: 'Kcommaaccent': 667, michael@0: 'Lacute': 611, michael@0: 'trademark': 1000, michael@0: 'edotaccent': 444, michael@0: 'Igrave': 389, michael@0: 'Imacron': 389, michael@0: 'Lcaron': 611, michael@0: 'onehalf': 750, michael@0: 'lessequal': 549, michael@0: 'ocircumflex': 500, michael@0: 'ntilde': 556, michael@0: 'Uhungarumlaut': 722, michael@0: 'Eacute': 667, michael@0: 'emacron': 444, michael@0: 'gbreve': 500, michael@0: 'onequarter': 750, michael@0: 'Scaron': 556, michael@0: 'Scommaaccent': 556, michael@0: 'Ohungarumlaut': 722, michael@0: 'degree': 400, michael@0: 'ograve': 500, michael@0: 'Ccaron': 667, michael@0: 'ugrave': 556, michael@0: 'radical': 549, michael@0: 'Dcaron': 722, michael@0: 'rcommaaccent': 389, michael@0: 'Ntilde': 722, michael@0: 'otilde': 500, michael@0: 'Rcommaaccent': 667, michael@0: 'Lcommaaccent': 611, michael@0: 'Atilde': 667, michael@0: 'Aogonek': 667, michael@0: 'Aring': 667, michael@0: 'Otilde': 722, michael@0: 'zdotaccent': 389, michael@0: 'Ecaron': 667, michael@0: 'Iogonek': 389, michael@0: 'kcommaaccent': 500, michael@0: 'minus': 606, michael@0: 'Icircumflex': 389, michael@0: 'ncaron': 556, michael@0: 'tcommaaccent': 278, michael@0: 'logicalnot': 606, michael@0: 'odieresis': 500, michael@0: 'udieresis': 556, michael@0: 'notequal': 549, michael@0: 'gcommaaccent': 500, michael@0: 'eth': 500, michael@0: 'zcaron': 389, michael@0: 'ncommaaccent': 556, michael@0: 'onesuperior': 300, michael@0: 'imacron': 278, michael@0: 'Euro': 500 michael@0: }, michael@0: 'Times-Italic': { michael@0: 'space': 250, michael@0: 'exclam': 333, michael@0: 'quotedbl': 420, michael@0: 'numbersign': 500, michael@0: 'dollar': 500, michael@0: 'percent': 833, michael@0: 'ampersand': 778, michael@0: 'quoteright': 333, michael@0: 'parenleft': 333, michael@0: 'parenright': 333, michael@0: 'asterisk': 500, michael@0: 'plus': 675, michael@0: 'comma': 250, michael@0: 'hyphen': 333, michael@0: 'period': 250, michael@0: 'slash': 278, michael@0: 'zero': 500, michael@0: 'one': 500, michael@0: 'two': 500, michael@0: 'three': 500, michael@0: 'four': 500, michael@0: 'five': 500, michael@0: 'six': 500, michael@0: 'seven': 500, michael@0: 'eight': 500, michael@0: 'nine': 500, michael@0: 'colon': 333, michael@0: 'semicolon': 333, michael@0: 'less': 675, michael@0: 'equal': 675, michael@0: 'greater': 675, michael@0: 'question': 500, michael@0: 'at': 920, michael@0: 'A': 611, michael@0: 'B': 611, michael@0: 'C': 667, michael@0: 'D': 722, michael@0: 'E': 611, michael@0: 'F': 611, michael@0: 'G': 722, michael@0: 'H': 722, michael@0: 'I': 333, michael@0: 'J': 444, michael@0: 'K': 667, michael@0: 'L': 556, michael@0: 'M': 833, michael@0: 'N': 667, michael@0: 'O': 722, michael@0: 'P': 611, michael@0: 'Q': 722, michael@0: 'R': 611, michael@0: 'S': 500, michael@0: 'T': 556, michael@0: 'U': 722, michael@0: 'V': 611, michael@0: 'W': 833, michael@0: 'X': 611, michael@0: 'Y': 556, michael@0: 'Z': 556, michael@0: 'bracketleft': 389, michael@0: 'backslash': 278, michael@0: 'bracketright': 389, michael@0: 'asciicircum': 422, michael@0: 'underscore': 500, michael@0: 'quoteleft': 333, michael@0: 'a': 500, michael@0: 'b': 500, michael@0: 'c': 444, michael@0: 'd': 500, michael@0: 'e': 444, michael@0: 'f': 278, michael@0: 'g': 500, michael@0: 'h': 500, michael@0: 'i': 278, michael@0: 'j': 278, michael@0: 'k': 444, michael@0: 'l': 278, michael@0: 'm': 722, michael@0: 'n': 500, michael@0: 'o': 500, michael@0: 'p': 500, michael@0: 'q': 500, michael@0: 'r': 389, michael@0: 's': 389, michael@0: 't': 278, michael@0: 'u': 500, michael@0: 'v': 444, michael@0: 'w': 667, michael@0: 'x': 444, michael@0: 'y': 444, michael@0: 'z': 389, michael@0: 'braceleft': 400, michael@0: 'bar': 275, michael@0: 'braceright': 400, michael@0: 'asciitilde': 541, michael@0: 'exclamdown': 389, michael@0: 'cent': 500, michael@0: 'sterling': 500, michael@0: 'fraction': 167, michael@0: 'yen': 500, michael@0: 'florin': 500, michael@0: 'section': 500, michael@0: 'currency': 500, michael@0: 'quotesingle': 214, michael@0: 'quotedblleft': 556, michael@0: 'guillemotleft': 500, michael@0: 'guilsinglleft': 333, michael@0: 'guilsinglright': 333, michael@0: 'fi': 500, michael@0: 'fl': 500, michael@0: 'endash': 500, michael@0: 'dagger': 500, michael@0: 'daggerdbl': 500, michael@0: 'periodcentered': 250, michael@0: 'paragraph': 523, michael@0: 'bullet': 350, michael@0: 'quotesinglbase': 333, michael@0: 'quotedblbase': 556, michael@0: 'quotedblright': 556, michael@0: 'guillemotright': 500, michael@0: 'ellipsis': 889, michael@0: 'perthousand': 1000, michael@0: 'questiondown': 500, michael@0: 'grave': 333, michael@0: 'acute': 333, michael@0: 'circumflex': 333, michael@0: 'tilde': 333, michael@0: 'macron': 333, michael@0: 'breve': 333, michael@0: 'dotaccent': 333, michael@0: 'dieresis': 333, michael@0: 'ring': 333, michael@0: 'cedilla': 333, michael@0: 'hungarumlaut': 333, michael@0: 'ogonek': 333, michael@0: 'caron': 333, michael@0: 'emdash': 889, michael@0: 'AE': 889, michael@0: 'ordfeminine': 276, michael@0: 'Lslash': 556, michael@0: 'Oslash': 722, michael@0: 'OE': 944, michael@0: 'ordmasculine': 310, michael@0: 'ae': 667, michael@0: 'dotlessi': 278, michael@0: 'lslash': 278, michael@0: 'oslash': 500, michael@0: 'oe': 667, michael@0: 'germandbls': 500, michael@0: 'Idieresis': 333, michael@0: 'eacute': 444, michael@0: 'abreve': 500, michael@0: 'uhungarumlaut': 500, michael@0: 'ecaron': 444, michael@0: 'Ydieresis': 556, michael@0: 'divide': 675, michael@0: 'Yacute': 556, michael@0: 'Acircumflex': 611, michael@0: 'aacute': 500, michael@0: 'Ucircumflex': 722, michael@0: 'yacute': 444, michael@0: 'scommaaccent': 389, michael@0: 'ecircumflex': 444, michael@0: 'Uring': 722, michael@0: 'Udieresis': 722, michael@0: 'aogonek': 500, michael@0: 'Uacute': 722, michael@0: 'uogonek': 500, michael@0: 'Edieresis': 611, michael@0: 'Dcroat': 722, michael@0: 'commaaccent': 250, michael@0: 'copyright': 760, michael@0: 'Emacron': 611, michael@0: 'ccaron': 444, michael@0: 'aring': 500, michael@0: 'Ncommaaccent': 667, michael@0: 'lacute': 278, michael@0: 'agrave': 500, michael@0: 'Tcommaaccent': 556, michael@0: 'Cacute': 667, michael@0: 'atilde': 500, michael@0: 'Edotaccent': 611, michael@0: 'scaron': 389, michael@0: 'scedilla': 389, michael@0: 'iacute': 278, michael@0: 'lozenge': 471, michael@0: 'Rcaron': 611, michael@0: 'Gcommaaccent': 722, michael@0: 'ucircumflex': 500, michael@0: 'acircumflex': 500, michael@0: 'Amacron': 611, michael@0: 'rcaron': 389, michael@0: 'ccedilla': 444, michael@0: 'Zdotaccent': 556, michael@0: 'Thorn': 611, michael@0: 'Omacron': 722, michael@0: 'Racute': 611, michael@0: 'Sacute': 500, michael@0: 'dcaron': 544, michael@0: 'Umacron': 722, michael@0: 'uring': 500, michael@0: 'threesuperior': 300, michael@0: 'Ograve': 722, michael@0: 'Agrave': 611, michael@0: 'Abreve': 611, michael@0: 'multiply': 675, michael@0: 'uacute': 500, michael@0: 'Tcaron': 556, michael@0: 'partialdiff': 476, michael@0: 'ydieresis': 444, michael@0: 'Nacute': 667, michael@0: 'icircumflex': 278, michael@0: 'Ecircumflex': 611, michael@0: 'adieresis': 500, michael@0: 'edieresis': 444, michael@0: 'cacute': 444, michael@0: 'nacute': 500, michael@0: 'umacron': 500, michael@0: 'Ncaron': 667, michael@0: 'Iacute': 333, michael@0: 'plusminus': 675, michael@0: 'brokenbar': 275, michael@0: 'registered': 760, michael@0: 'Gbreve': 722, michael@0: 'Idotaccent': 333, michael@0: 'summation': 600, michael@0: 'Egrave': 611, michael@0: 'racute': 389, michael@0: 'omacron': 500, michael@0: 'Zacute': 556, michael@0: 'Zcaron': 556, michael@0: 'greaterequal': 549, michael@0: 'Eth': 722, michael@0: 'Ccedilla': 667, michael@0: 'lcommaaccent': 278, michael@0: 'tcaron': 300, michael@0: 'eogonek': 444, michael@0: 'Uogonek': 722, michael@0: 'Aacute': 611, michael@0: 'Adieresis': 611, michael@0: 'egrave': 444, michael@0: 'zacute': 389, michael@0: 'iogonek': 278, michael@0: 'Oacute': 722, michael@0: 'oacute': 500, michael@0: 'amacron': 500, michael@0: 'sacute': 389, michael@0: 'idieresis': 278, michael@0: 'Ocircumflex': 722, michael@0: 'Ugrave': 722, michael@0: 'Delta': 612, michael@0: 'thorn': 500, michael@0: 'twosuperior': 300, michael@0: 'Odieresis': 722, michael@0: 'mu': 500, michael@0: 'igrave': 278, michael@0: 'ohungarumlaut': 500, michael@0: 'Eogonek': 611, michael@0: 'dcroat': 500, michael@0: 'threequarters': 750, michael@0: 'Scedilla': 500, michael@0: 'lcaron': 300, michael@0: 'Kcommaaccent': 667, michael@0: 'Lacute': 556, michael@0: 'trademark': 980, michael@0: 'edotaccent': 444, michael@0: 'Igrave': 333, michael@0: 'Imacron': 333, michael@0: 'Lcaron': 611, michael@0: 'onehalf': 750, michael@0: 'lessequal': 549, michael@0: 'ocircumflex': 500, michael@0: 'ntilde': 500, michael@0: 'Uhungarumlaut': 722, michael@0: 'Eacute': 611, michael@0: 'emacron': 444, michael@0: 'gbreve': 500, michael@0: 'onequarter': 750, michael@0: 'Scaron': 500, michael@0: 'Scommaaccent': 500, michael@0: 'Ohungarumlaut': 722, michael@0: 'degree': 400, michael@0: 'ograve': 500, michael@0: 'Ccaron': 667, michael@0: 'ugrave': 500, michael@0: 'radical': 453, michael@0: 'Dcaron': 722, michael@0: 'rcommaaccent': 389, michael@0: 'Ntilde': 667, michael@0: 'otilde': 500, michael@0: 'Rcommaaccent': 611, michael@0: 'Lcommaaccent': 556, michael@0: 'Atilde': 611, michael@0: 'Aogonek': 611, michael@0: 'Aring': 611, michael@0: 'Otilde': 722, michael@0: 'zdotaccent': 389, michael@0: 'Ecaron': 611, michael@0: 'Iogonek': 333, michael@0: 'kcommaaccent': 444, michael@0: 'minus': 675, michael@0: 'Icircumflex': 333, michael@0: 'ncaron': 500, michael@0: 'tcommaaccent': 278, michael@0: 'logicalnot': 675, michael@0: 'odieresis': 500, michael@0: 'udieresis': 500, michael@0: 'notequal': 549, michael@0: 'gcommaaccent': 500, michael@0: 'eth': 500, michael@0: 'zcaron': 389, michael@0: 'ncommaaccent': 500, michael@0: 'onesuperior': 300, michael@0: 'imacron': 278, michael@0: 'Euro': 500 michael@0: }, michael@0: 'ZapfDingbats': { michael@0: 'space': 278, michael@0: 'a1': 974, michael@0: 'a2': 961, michael@0: 'a202': 974, michael@0: 'a3': 980, michael@0: 'a4': 719, michael@0: 'a5': 789, michael@0: 'a119': 790, michael@0: 'a118': 791, michael@0: 'a117': 690, michael@0: 'a11': 960, michael@0: 'a12': 939, michael@0: 'a13': 549, michael@0: 'a14': 855, michael@0: 'a15': 911, michael@0: 'a16': 933, michael@0: 'a105': 911, michael@0: 'a17': 945, michael@0: 'a18': 974, michael@0: 'a19': 755, michael@0: 'a20': 846, michael@0: 'a21': 762, michael@0: 'a22': 761, michael@0: 'a23': 571, michael@0: 'a24': 677, michael@0: 'a25': 763, michael@0: 'a26': 760, michael@0: 'a27': 759, michael@0: 'a28': 754, michael@0: 'a6': 494, michael@0: 'a7': 552, michael@0: 'a8': 537, michael@0: 'a9': 577, michael@0: 'a10': 692, michael@0: 'a29': 786, michael@0: 'a30': 788, michael@0: 'a31': 788, michael@0: 'a32': 790, michael@0: 'a33': 793, michael@0: 'a34': 794, michael@0: 'a35': 816, michael@0: 'a36': 823, michael@0: 'a37': 789, michael@0: 'a38': 841, michael@0: 'a39': 823, michael@0: 'a40': 833, michael@0: 'a41': 816, michael@0: 'a42': 831, michael@0: 'a43': 923, michael@0: 'a44': 744, michael@0: 'a45': 723, michael@0: 'a46': 749, michael@0: 'a47': 790, michael@0: 'a48': 792, michael@0: 'a49': 695, michael@0: 'a50': 776, michael@0: 'a51': 768, michael@0: 'a52': 792, michael@0: 'a53': 759, michael@0: 'a54': 707, michael@0: 'a55': 708, michael@0: 'a56': 682, michael@0: 'a57': 701, michael@0: 'a58': 826, michael@0: 'a59': 815, michael@0: 'a60': 789, michael@0: 'a61': 789, michael@0: 'a62': 707, michael@0: 'a63': 687, michael@0: 'a64': 696, michael@0: 'a65': 689, michael@0: 'a66': 786, michael@0: 'a67': 787, michael@0: 'a68': 713, michael@0: 'a69': 791, michael@0: 'a70': 785, michael@0: 'a71': 791, michael@0: 'a72': 873, michael@0: 'a73': 761, michael@0: 'a74': 762, michael@0: 'a203': 762, michael@0: 'a75': 759, michael@0: 'a204': 759, michael@0: 'a76': 892, michael@0: 'a77': 892, michael@0: 'a78': 788, michael@0: 'a79': 784, michael@0: 'a81': 438, michael@0: 'a82': 138, michael@0: 'a83': 277, michael@0: 'a84': 415, michael@0: 'a97': 392, michael@0: 'a98': 392, michael@0: 'a99': 668, michael@0: 'a100': 668, michael@0: 'a89': 390, michael@0: 'a90': 390, michael@0: 'a93': 317, michael@0: 'a94': 317, michael@0: 'a91': 276, michael@0: 'a92': 276, michael@0: 'a205': 509, michael@0: 'a85': 509, michael@0: 'a206': 410, michael@0: 'a86': 410, michael@0: 'a87': 234, michael@0: 'a88': 234, michael@0: 'a95': 334, michael@0: 'a96': 334, michael@0: 'a101': 732, michael@0: 'a102': 544, michael@0: 'a103': 544, michael@0: 'a104': 910, michael@0: 'a106': 667, michael@0: 'a107': 760, michael@0: 'a108': 760, michael@0: 'a112': 776, michael@0: 'a111': 595, michael@0: 'a110': 694, michael@0: 'a109': 626, michael@0: 'a120': 788, michael@0: 'a121': 788, michael@0: 'a122': 788, michael@0: 'a123': 788, michael@0: 'a124': 788, michael@0: 'a125': 788, michael@0: 'a126': 788, michael@0: 'a127': 788, michael@0: 'a128': 788, michael@0: 'a129': 788, michael@0: 'a130': 788, michael@0: 'a131': 788, michael@0: 'a132': 788, michael@0: 'a133': 788, michael@0: 'a134': 788, michael@0: 'a135': 788, michael@0: 'a136': 788, michael@0: 'a137': 788, michael@0: 'a138': 788, michael@0: 'a139': 788, michael@0: 'a140': 788, michael@0: 'a141': 788, michael@0: 'a142': 788, michael@0: 'a143': 788, michael@0: 'a144': 788, michael@0: 'a145': 788, michael@0: 'a146': 788, michael@0: 'a147': 788, michael@0: 'a148': 788, michael@0: 'a149': 788, michael@0: 'a150': 788, michael@0: 'a151': 788, michael@0: 'a152': 788, michael@0: 'a153': 788, michael@0: 'a154': 788, michael@0: 'a155': 788, michael@0: 'a156': 788, michael@0: 'a157': 788, michael@0: 'a158': 788, michael@0: 'a159': 788, michael@0: 'a160': 894, michael@0: 'a161': 838, michael@0: 'a163': 1016, michael@0: 'a164': 458, michael@0: 'a196': 748, michael@0: 'a165': 924, michael@0: 'a192': 748, michael@0: 'a166': 918, michael@0: 'a167': 927, michael@0: 'a168': 928, michael@0: 'a169': 928, michael@0: 'a170': 834, michael@0: 'a171': 873, michael@0: 'a172': 828, michael@0: 'a173': 924, michael@0: 'a162': 924, michael@0: 'a174': 917, michael@0: 'a175': 930, michael@0: 'a176': 931, michael@0: 'a177': 463, michael@0: 'a178': 883, michael@0: 'a179': 836, michael@0: 'a193': 836, michael@0: 'a180': 867, michael@0: 'a199': 867, michael@0: 'a181': 696, michael@0: 'a200': 696, michael@0: 'a182': 874, michael@0: 'a201': 874, michael@0: 'a183': 760, michael@0: 'a184': 946, michael@0: 'a197': 771, michael@0: 'a185': 865, michael@0: 'a194': 771, michael@0: 'a198': 888, michael@0: 'a186': 967, michael@0: 'a195': 888, michael@0: 'a187': 831, michael@0: 'a188': 873, michael@0: 'a189': 927, michael@0: 'a190': 970, michael@0: 'a191': 918 michael@0: } michael@0: }; michael@0: michael@0: michael@0: michael@0: var EOF = {}; michael@0: michael@0: function isEOF(v) { michael@0: return (v == EOF); michael@0: } michael@0: michael@0: var Parser = (function ParserClosure() { michael@0: function Parser(lexer, allowStreams, xref) { michael@0: this.lexer = lexer; michael@0: this.allowStreams = allowStreams; michael@0: this.xref = xref; michael@0: this.imageCache = { michael@0: length: 0, michael@0: adler32: 0, michael@0: stream: null michael@0: }; michael@0: this.refill(); michael@0: } michael@0: michael@0: Parser.prototype = { michael@0: refill: function Parser_refill() { michael@0: this.buf1 = this.lexer.getObj(); michael@0: this.buf2 = this.lexer.getObj(); michael@0: }, michael@0: shift: function Parser_shift() { michael@0: if (isCmd(this.buf2, 'ID')) { michael@0: this.buf1 = this.buf2; michael@0: this.buf2 = null; michael@0: } else { michael@0: this.buf1 = this.buf2; michael@0: this.buf2 = this.lexer.getObj(); michael@0: } michael@0: }, michael@0: getObj: function Parser_getObj(cipherTransform) { michael@0: if (isCmd(this.buf1, 'BI')) { // inline image michael@0: this.shift(); michael@0: return this.makeInlineImage(cipherTransform); michael@0: } michael@0: if (isCmd(this.buf1, '[')) { // array michael@0: this.shift(); michael@0: var array = []; michael@0: while (!isCmd(this.buf1, ']') && !isEOF(this.buf1)) { michael@0: array.push(this.getObj(cipherTransform)); michael@0: } michael@0: if (isEOF(this.buf1)) { michael@0: error('End of file inside array'); michael@0: } michael@0: this.shift(); michael@0: return array; michael@0: } michael@0: if (isCmd(this.buf1, '<<')) { // dictionary or stream michael@0: this.shift(); michael@0: var dict = new Dict(this.xref); michael@0: while (!isCmd(this.buf1, '>>') && !isEOF(this.buf1)) { michael@0: if (!isName(this.buf1)) { michael@0: info('Malformed dictionary: key must be a name object'); michael@0: this.shift(); michael@0: continue; michael@0: } michael@0: michael@0: var key = this.buf1.name; michael@0: this.shift(); michael@0: if (isEOF(this.buf1)) { michael@0: break; michael@0: } michael@0: dict.set(key, this.getObj(cipherTransform)); michael@0: } michael@0: if (isEOF(this.buf1)) { michael@0: error('End of file inside dictionary'); michael@0: } michael@0: michael@0: // Stream objects are not allowed inside content streams or michael@0: // object streams. michael@0: if (isCmd(this.buf2, 'stream')) { michael@0: return (this.allowStreams ? michael@0: this.makeStream(dict, cipherTransform) : dict); michael@0: } michael@0: this.shift(); michael@0: return dict; michael@0: } michael@0: if (isInt(this.buf1)) { // indirect reference or integer michael@0: var num = this.buf1; michael@0: this.shift(); michael@0: if (isInt(this.buf1) && isCmd(this.buf2, 'R')) { michael@0: var ref = new Ref(num, this.buf1); michael@0: this.shift(); michael@0: this.shift(); michael@0: return ref; michael@0: } michael@0: return num; michael@0: } michael@0: if (isString(this.buf1)) { // string michael@0: var str = this.buf1; michael@0: this.shift(); michael@0: if (cipherTransform) { michael@0: str = cipherTransform.decryptString(str); michael@0: } michael@0: return str; michael@0: } michael@0: michael@0: // simple object michael@0: var obj = this.buf1; michael@0: this.shift(); michael@0: return obj; michael@0: }, michael@0: makeInlineImage: function Parser_makeInlineImage(cipherTransform) { michael@0: var lexer = this.lexer; michael@0: var stream = lexer.stream; michael@0: michael@0: // parse dictionary michael@0: var dict = new Dict(null); michael@0: while (!isCmd(this.buf1, 'ID') && !isEOF(this.buf1)) { michael@0: if (!isName(this.buf1)) { michael@0: error('Dictionary key must be a name object'); michael@0: } michael@0: michael@0: var key = this.buf1.name; michael@0: this.shift(); michael@0: if (isEOF(this.buf1)) { michael@0: break; michael@0: } michael@0: dict.set(key, this.getObj(cipherTransform)); michael@0: } michael@0: michael@0: // parse image stream michael@0: var startPos = stream.pos; michael@0: michael@0: // searching for the /EI\s/ michael@0: var state = 0, ch, i, ii; michael@0: while (state != 4 && (ch = stream.getByte()) !== -1) { michael@0: switch (ch | 0) { michael@0: case 0x20: michael@0: case 0x0D: michael@0: case 0x0A: michael@0: // let's check next five bytes to be ASCII... just be sure michael@0: var followingBytes = stream.peekBytes(5); michael@0: for (i = 0, ii = followingBytes.length; i < ii; i++) { michael@0: ch = followingBytes[i]; michael@0: if (ch !== 0x0A && ch !== 0x0D && (ch < 0x20 || ch > 0x7F)) { michael@0: // not a LF, CR, SPACE or any visible ASCII character michael@0: state = 0; michael@0: break; // some binary stuff found, resetting the state michael@0: } michael@0: } michael@0: state = (state === 3 ? 4 : 0); michael@0: break; michael@0: case 0x45: michael@0: state = 2; michael@0: break; michael@0: case 0x49: michael@0: state = (state === 2 ? 3 : 0); michael@0: break; michael@0: default: michael@0: state = 0; michael@0: break; michael@0: } michael@0: } michael@0: michael@0: var length = (stream.pos - 4) - startPos; michael@0: var imageStream = stream.makeSubStream(startPos, length, dict); michael@0: michael@0: // trying to cache repeat images, first we are trying to "warm up" caching michael@0: // using length, then comparing adler32 michael@0: var MAX_LENGTH_TO_CACHE = 1000; michael@0: var cacheImage = false, adler32; michael@0: if (length < MAX_LENGTH_TO_CACHE && this.imageCache.length === length) { michael@0: var imageBytes = imageStream.getBytes(); michael@0: imageStream.reset(); michael@0: michael@0: var a = 1; michael@0: var b = 0; michael@0: for (i = 0, ii = imageBytes.length; i < ii; ++i) { michael@0: a = (a + (imageBytes[i] & 0xff)) % 65521; michael@0: b = (b + a) % 65521; michael@0: } michael@0: adler32 = (b << 16) | a; michael@0: michael@0: if (this.imageCache.stream && this.imageCache.adler32 === adler32) { michael@0: this.buf2 = Cmd.get('EI'); michael@0: this.shift(); michael@0: michael@0: this.imageCache.stream.reset(); michael@0: return this.imageCache.stream; michael@0: } michael@0: cacheImage = true; michael@0: } michael@0: if (!cacheImage && !this.imageCache.stream) { michael@0: this.imageCache.length = length; michael@0: this.imageCache.stream = null; michael@0: } michael@0: michael@0: if (cipherTransform) { michael@0: imageStream = cipherTransform.createStream(imageStream, length); michael@0: } michael@0: michael@0: imageStream = this.filter(imageStream, dict, length); michael@0: imageStream.dict = dict; michael@0: if (cacheImage) { michael@0: imageStream.cacheKey = 'inline_' + length + '_' + adler32; michael@0: this.imageCache.adler32 = adler32; michael@0: this.imageCache.stream = imageStream; michael@0: } michael@0: michael@0: this.buf2 = Cmd.get('EI'); michael@0: this.shift(); michael@0: michael@0: return imageStream; michael@0: }, michael@0: fetchIfRef: function Parser_fetchIfRef(obj) { michael@0: // not relying on the xref.fetchIfRef -- xref might not be set michael@0: return (isRef(obj) ? this.xref.fetch(obj) : obj); michael@0: }, michael@0: makeStream: function Parser_makeStream(dict, cipherTransform) { michael@0: var lexer = this.lexer; michael@0: var stream = lexer.stream; michael@0: michael@0: // get stream start position michael@0: lexer.skipToNextLine(); michael@0: var pos = stream.pos - 1; michael@0: michael@0: // get length michael@0: var length = this.fetchIfRef(dict.get('Length')); michael@0: if (!isInt(length)) { michael@0: info('Bad ' + length + ' attribute in stream'); michael@0: length = 0; michael@0: } michael@0: michael@0: // skip over the stream data michael@0: stream.pos = pos + length; michael@0: lexer.nextChar(); michael@0: michael@0: this.shift(); // '>>' michael@0: this.shift(); // 'stream' michael@0: if (!isCmd(this.buf1, 'endstream')) { michael@0: // bad stream length, scanning for endstream michael@0: stream.pos = pos; michael@0: var SCAN_BLOCK_SIZE = 2048; michael@0: var ENDSTREAM_SIGNATURE_LENGTH = 9; michael@0: var ENDSTREAM_SIGNATURE = [0x65, 0x6E, 0x64, 0x73, 0x74, 0x72, 0x65, michael@0: 0x61, 0x6D]; michael@0: var skipped = 0, found = false, i, j; michael@0: while (stream.pos < stream.end) { michael@0: var scanBytes = stream.peekBytes(SCAN_BLOCK_SIZE); michael@0: var scanLength = scanBytes.length - ENDSTREAM_SIGNATURE_LENGTH; michael@0: found = false; michael@0: for (i = 0, j = 0; i < scanLength; i++) { michael@0: var b = scanBytes[i]; michael@0: if (b !== ENDSTREAM_SIGNATURE[j]) { michael@0: i -= j; michael@0: j = 0; michael@0: } else { michael@0: j++; michael@0: if (j >= ENDSTREAM_SIGNATURE_LENGTH) { michael@0: i++; michael@0: found = true; michael@0: break; michael@0: } michael@0: } michael@0: } michael@0: if (found) { michael@0: skipped += i - ENDSTREAM_SIGNATURE_LENGTH; michael@0: stream.pos += i - ENDSTREAM_SIGNATURE_LENGTH; michael@0: break; michael@0: } michael@0: skipped += scanLength; michael@0: stream.pos += scanLength; michael@0: } michael@0: if (!found) { michael@0: error('Missing endstream'); michael@0: } michael@0: length = skipped; michael@0: michael@0: lexer.nextChar(); michael@0: this.shift(); michael@0: this.shift(); michael@0: } michael@0: this.shift(); // 'endstream' michael@0: michael@0: stream = stream.makeSubStream(pos, length, dict); michael@0: if (cipherTransform) { michael@0: stream = cipherTransform.createStream(stream, length); michael@0: } michael@0: stream = this.filter(stream, dict, length); michael@0: stream.dict = dict; michael@0: return stream; michael@0: }, michael@0: filter: function Parser_filter(stream, dict, length) { michael@0: var filter = this.fetchIfRef(dict.get('Filter', 'F')); michael@0: var params = this.fetchIfRef(dict.get('DecodeParms', 'DP')); michael@0: if (isName(filter)) { michael@0: return this.makeFilter(stream, filter.name, length, params); michael@0: } michael@0: michael@0: var maybeLength = length; michael@0: if (isArray(filter)) { michael@0: var filterArray = filter; michael@0: var paramsArray = params; michael@0: for (var i = 0, ii = filterArray.length; i < ii; ++i) { michael@0: filter = filterArray[i]; michael@0: if (!isName(filter)) { michael@0: error('Bad filter name: ' + filter); michael@0: } michael@0: michael@0: params = null; michael@0: if (isArray(paramsArray) && (i in paramsArray)) { michael@0: params = paramsArray[i]; michael@0: } michael@0: stream = this.makeFilter(stream, filter.name, maybeLength, params); michael@0: // after the first stream the length variable is invalid michael@0: maybeLength = null; michael@0: } michael@0: } michael@0: return stream; michael@0: }, michael@0: makeFilter: function Parser_makeFilter(stream, name, maybeLength, params) { michael@0: if (stream.dict.get('Length') === 0) { michael@0: return new NullStream(stream); michael@0: } michael@0: if (name == 'FlateDecode' || name == 'Fl') { michael@0: if (params) { michael@0: return new PredictorStream(new FlateStream(stream, maybeLength), michael@0: maybeLength, params); michael@0: } michael@0: return new FlateStream(stream, maybeLength); michael@0: } michael@0: if (name == 'LZWDecode' || name == 'LZW') { michael@0: var earlyChange = 1; michael@0: if (params) { michael@0: if (params.has('EarlyChange')) { michael@0: earlyChange = params.get('EarlyChange'); michael@0: } michael@0: return new PredictorStream( michael@0: new LZWStream(stream, maybeLength, earlyChange), michael@0: maybeLength, params); michael@0: } michael@0: return new LZWStream(stream, maybeLength, earlyChange); michael@0: } michael@0: if (name == 'DCTDecode' || name == 'DCT') { michael@0: return new JpegStream(stream, maybeLength, stream.dict, this.xref); michael@0: } michael@0: if (name == 'JPXDecode' || name == 'JPX') { michael@0: return new JpxStream(stream, maybeLength, stream.dict); michael@0: } michael@0: if (name == 'ASCII85Decode' || name == 'A85') { michael@0: return new Ascii85Stream(stream, maybeLength); michael@0: } michael@0: if (name == 'ASCIIHexDecode' || name == 'AHx') { michael@0: return new AsciiHexStream(stream, maybeLength); michael@0: } michael@0: if (name == 'CCITTFaxDecode' || name == 'CCF') { michael@0: return new CCITTFaxStream(stream, maybeLength, params); michael@0: } michael@0: if (name == 'RunLengthDecode' || name == 'RL') { michael@0: return new RunLengthStream(stream, maybeLength); michael@0: } michael@0: if (name == 'JBIG2Decode') { michael@0: return new Jbig2Stream(stream, maybeLength, stream.dict); michael@0: } michael@0: warn('filter "' + name + '" not supported yet'); michael@0: return stream; michael@0: } michael@0: }; michael@0: michael@0: return Parser; michael@0: })(); michael@0: michael@0: var Lexer = (function LexerClosure() { michael@0: function Lexer(stream, knownCommands) { michael@0: this.stream = stream; michael@0: this.nextChar(); michael@0: michael@0: // While lexing, we build up many strings one char at a time. Using += for michael@0: // this can result in lots of garbage strings. It's better to build an michael@0: // array of single-char strings and then join() them together at the end. michael@0: // And reusing a single array (i.e. |this.strBuf|) over and over for this michael@0: // purpose uses less memory than using a new array for each string. michael@0: this.strBuf = []; michael@0: michael@0: // The PDFs might have "glued" commands with other commands, operands or michael@0: // literals, e.g. "q1". The knownCommands is a dictionary of the valid michael@0: // commands and their prefixes. The prefixes are built the following way: michael@0: // if there a command that is a prefix of the other valid command or michael@0: // literal (e.g. 'f' and 'false') the following prefixes must be included, michael@0: // 'fa', 'fal', 'fals'. The prefixes are not needed, if the command has no michael@0: // other commands or literals as a prefix. The knowCommands is optional. michael@0: this.knownCommands = knownCommands; michael@0: } michael@0: michael@0: Lexer.isSpace = function Lexer_isSpace(ch) { michael@0: // Space is one of the following characters: SPACE, TAB, CR or LF. michael@0: return (ch === 0x20 || ch === 0x09 || ch === 0x0D || ch === 0x0A); michael@0: }; michael@0: michael@0: // A '1' in this array means the character is white space. A '1' or michael@0: // '2' means the character ends a name or command. michael@0: var specialChars = [ michael@0: 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, // 0x michael@0: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x michael@0: 1, 0, 0, 0, 0, 2, 0, 0, 2, 2, 0, 0, 0, 0, 0, 2, // 2x michael@0: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, // 3x michael@0: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4x michael@0: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, // 5x michael@0: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6x michael@0: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, // 7x michael@0: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x michael@0: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x michael@0: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // ax michael@0: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // bx michael@0: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // cx michael@0: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // dx michael@0: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // ex michael@0: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // fx michael@0: ]; michael@0: michael@0: function toHexDigit(ch) { michael@0: if (ch >= 0x30 && ch <= 0x39) { // '0'-'9' michael@0: return ch & 0x0F; michael@0: } michael@0: if ((ch >= 0x41 && ch <= 0x46) || (ch >= 0x61 && ch <= 0x66)) { michael@0: // 'A'-'F', 'a'-'f' michael@0: return (ch & 0x0F) + 9; michael@0: } michael@0: return -1; michael@0: } michael@0: michael@0: Lexer.prototype = { michael@0: nextChar: function Lexer_nextChar() { michael@0: return (this.currentChar = this.stream.getByte()); michael@0: }, michael@0: peekChar: function Lexer_peekChar() { michael@0: return this.stream.peekBytes(1)[0]; michael@0: }, michael@0: getNumber: function Lexer_getNumber() { michael@0: var ch = this.currentChar; michael@0: var eNotation = false; michael@0: var divideBy = 0; // different from 0 if it's a floating point value michael@0: var sign = 1; michael@0: michael@0: if (ch === 0x2D) { // '-' michael@0: sign = -1; michael@0: ch = this.nextChar(); michael@0: } else if (ch === 0x2B) { // '+' michael@0: ch = this.nextChar(); michael@0: } michael@0: if (ch === 0x2E) { // '.' michael@0: divideBy = 10; michael@0: ch = this.nextChar(); michael@0: } michael@0: if (ch < 0x30 || ch > 0x39) { // '0' - '9' michael@0: error('Invalid number: ' + String.fromCharCode(ch)); michael@0: return 0; michael@0: } michael@0: michael@0: var baseValue = ch - 0x30; // '0' michael@0: var powerValue = 0; michael@0: var powerValueSign = 1; michael@0: michael@0: while ((ch = this.nextChar()) >= 0) { michael@0: if (0x30 <= ch && ch <= 0x39) { // '0' - '9' michael@0: var currentDigit = ch - 0x30; // '0' michael@0: if (eNotation) { // We are after an 'e' or 'E' michael@0: powerValue = powerValue * 10 + currentDigit; michael@0: } else { michael@0: if (divideBy !== 0) { // We are after a point michael@0: divideBy *= 10; michael@0: } michael@0: baseValue = baseValue * 10 + currentDigit; michael@0: } michael@0: } else if (ch === 0x2E) { // '.' michael@0: if (divideBy === 0) { michael@0: divideBy = 1; michael@0: } else { michael@0: // A number can have only one '.' michael@0: break; michael@0: } michael@0: } else if (ch === 0x2D) { // '-' michael@0: // ignore minus signs in the middle of numbers to match michael@0: // Adobe's behavior michael@0: warn('Badly formated number'); michael@0: } else if (ch === 0x45 || ch === 0x65) { // 'E', 'e' michael@0: // 'E' can be either a scientific notation or the beginning of a new michael@0: // operator michael@0: ch = this.peekChar(); michael@0: if (ch === 0x2B || ch === 0x2D) { // '+', '-' michael@0: powerValueSign = (ch === 0x2D) ? -1 : 1; michael@0: this.nextChar(); // Consume the sign character michael@0: } else if (ch < 0x30 || ch > 0x39) { // '0' - '9' michael@0: // The 'E' must be the beginning of a new operator michael@0: break; michael@0: } michael@0: eNotation = true; michael@0: } else { michael@0: // the last character doesn't belong to us michael@0: break; michael@0: } michael@0: } michael@0: michael@0: if (divideBy !== 0) { michael@0: baseValue /= divideBy; michael@0: } michael@0: if (eNotation) { michael@0: baseValue *= Math.pow(10, powerValueSign * powerValue); michael@0: } michael@0: return sign * baseValue; michael@0: }, michael@0: getString: function Lexer_getString() { michael@0: var numParen = 1; michael@0: var done = false; michael@0: var strBuf = this.strBuf; michael@0: strBuf.length = 0; michael@0: michael@0: var ch = this.nextChar(); michael@0: while (true) { michael@0: var charBuffered = false; michael@0: switch (ch | 0) { michael@0: case -1: michael@0: warn('Unterminated string'); michael@0: done = true; michael@0: break; michael@0: case 0x28: // '(' michael@0: ++numParen; michael@0: strBuf.push('('); michael@0: break; michael@0: case 0x29: // ')' michael@0: if (--numParen === 0) { michael@0: this.nextChar(); // consume strings ')' michael@0: done = true; michael@0: } else { michael@0: strBuf.push(')'); michael@0: } michael@0: break; michael@0: case 0x5C: // '\\' michael@0: ch = this.nextChar(); michael@0: switch (ch) { michael@0: case -1: michael@0: warn('Unterminated string'); michael@0: done = true; michael@0: break; michael@0: case 0x6E: // 'n' michael@0: strBuf.push('\n'); michael@0: break; michael@0: case 0x72: // 'r' michael@0: strBuf.push('\r'); michael@0: break; michael@0: case 0x74: // 't' michael@0: strBuf.push('\t'); michael@0: break; michael@0: case 0x62: // 'b' michael@0: strBuf.push('\b'); michael@0: break; michael@0: case 0x66: // 'f' michael@0: strBuf.push('\f'); michael@0: break; michael@0: case 0x5C: // '\' michael@0: case 0x28: // '(' michael@0: case 0x29: // ')' michael@0: strBuf.push(String.fromCharCode(ch)); michael@0: break; michael@0: case 0x30: case 0x31: case 0x32: case 0x33: // '0'-'3' michael@0: case 0x34: case 0x35: case 0x36: case 0x37: // '4'-'7' michael@0: var x = ch & 0x0F; michael@0: ch = this.nextChar(); michael@0: charBuffered = true; michael@0: if (ch >= 0x30 && ch <= 0x37) { // '0'-'7' michael@0: x = (x << 3) + (ch & 0x0F); michael@0: ch = this.nextChar(); michael@0: if (ch >= 0x30 && ch <= 0x37) { // '0'-'7' michael@0: charBuffered = false; michael@0: x = (x << 3) + (ch & 0x0F); michael@0: } michael@0: } michael@0: strBuf.push(String.fromCharCode(x)); michael@0: break; michael@0: case 0x0D: // CR michael@0: if (this.peekChar() === 0x0A) { // LF michael@0: this.nextChar(); michael@0: } michael@0: break; michael@0: case 0x0A: // LF michael@0: break; michael@0: default: michael@0: strBuf.push(String.fromCharCode(ch)); michael@0: break; michael@0: } michael@0: break; michael@0: default: michael@0: strBuf.push(String.fromCharCode(ch)); michael@0: break; michael@0: } michael@0: if (done) { michael@0: break; michael@0: } michael@0: if (!charBuffered) { michael@0: ch = this.nextChar(); michael@0: } michael@0: } michael@0: return strBuf.join(''); michael@0: }, michael@0: getName: function Lexer_getName() { michael@0: var ch; michael@0: var strBuf = this.strBuf; michael@0: strBuf.length = 0; michael@0: while ((ch = this.nextChar()) >= 0 && !specialChars[ch]) { michael@0: if (ch === 0x23) { // '#' michael@0: ch = this.nextChar(); michael@0: var x = toHexDigit(ch); michael@0: if (x != -1) { michael@0: var x2 = toHexDigit(this.nextChar()); michael@0: if (x2 == -1) { michael@0: error('Illegal digit in hex char in name: ' + x2); michael@0: } michael@0: strBuf.push(String.fromCharCode((x << 4) | x2)); michael@0: } else { michael@0: strBuf.push('#', String.fromCharCode(ch)); michael@0: } michael@0: } else { michael@0: strBuf.push(String.fromCharCode(ch)); michael@0: } michael@0: } michael@0: if (strBuf.length > 128) { michael@0: error('Warning: name token is longer than allowed by the spec: ' + michael@0: strBuf.length); michael@0: } michael@0: return Name.get(strBuf.join('')); michael@0: }, michael@0: getHexString: function Lexer_getHexString() { michael@0: var strBuf = this.strBuf; michael@0: strBuf.length = 0; michael@0: var ch = this.currentChar; michael@0: var isFirstHex = true; michael@0: var firstDigit; michael@0: var secondDigit; michael@0: while (true) { michael@0: if (ch < 0) { michael@0: warn('Unterminated hex string'); michael@0: break; michael@0: } else if (ch === 0x3E) { // '>' michael@0: this.nextChar(); michael@0: break; michael@0: } else if (specialChars[ch] === 1) { michael@0: ch = this.nextChar(); michael@0: continue; michael@0: } else { michael@0: if (isFirstHex) { michael@0: firstDigit = toHexDigit(ch); michael@0: if (firstDigit === -1) { michael@0: warn('Ignoring invalid character "' + ch + '" in hex string'); michael@0: ch = this.nextChar(); michael@0: continue; michael@0: } michael@0: } else { michael@0: secondDigit = toHexDigit(ch); michael@0: if (secondDigit === -1) { michael@0: warn('Ignoring invalid character "' + ch + '" in hex string'); michael@0: ch = this.nextChar(); michael@0: continue; michael@0: } michael@0: strBuf.push(String.fromCharCode((firstDigit << 4) | secondDigit)); michael@0: } michael@0: isFirstHex = !isFirstHex; michael@0: ch = this.nextChar(); michael@0: } michael@0: } michael@0: return strBuf.join(''); michael@0: }, michael@0: getObj: function Lexer_getObj() { michael@0: // skip whitespace and comments michael@0: var comment = false; michael@0: var ch = this.currentChar; michael@0: while (true) { michael@0: if (ch < 0) { michael@0: return EOF; michael@0: } michael@0: if (comment) { michael@0: if (ch === 0x0A || ch == 0x0D) { // LF, CR michael@0: comment = false; michael@0: } michael@0: } else if (ch === 0x25) { // '%' michael@0: comment = true; michael@0: } else if (specialChars[ch] !== 1) { michael@0: break; michael@0: } michael@0: ch = this.nextChar(); michael@0: } michael@0: michael@0: // start reading token michael@0: switch (ch | 0) { michael@0: case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: // '0'-'4' michael@0: case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: // '5'-'9' michael@0: case 0x2B: case 0x2D: case 0x2E: // '+', '-', '.' michael@0: return this.getNumber(); michael@0: case 0x28: // '(' michael@0: return this.getString(); michael@0: case 0x2F: // '/' michael@0: return this.getName(); michael@0: // array punctuation michael@0: case 0x5B: // '[' michael@0: this.nextChar(); michael@0: return Cmd.get('['); michael@0: case 0x5D: // ']' michael@0: this.nextChar(); michael@0: return Cmd.get(']'); michael@0: // hex string or dict punctuation michael@0: case 0x3C: // '<' michael@0: ch = this.nextChar(); michael@0: if (ch === 0x3C) { michael@0: // dict punctuation michael@0: this.nextChar(); michael@0: return Cmd.get('<<'); michael@0: } michael@0: return this.getHexString(); michael@0: // dict punctuation michael@0: case 0x3E: // '>' michael@0: ch = this.nextChar(); michael@0: if (ch === 0x3E) { michael@0: this.nextChar(); michael@0: return Cmd.get('>>'); michael@0: } michael@0: return Cmd.get('>'); michael@0: case 0x7B: // '{' michael@0: this.nextChar(); michael@0: return Cmd.get('{'); michael@0: case 0x7D: // '}' michael@0: this.nextChar(); michael@0: return Cmd.get('}'); michael@0: case 0x29: // ')' michael@0: error('Illegal character: ' + ch); michael@0: break; michael@0: } michael@0: michael@0: // command michael@0: var str = String.fromCharCode(ch); michael@0: var knownCommands = this.knownCommands; michael@0: var knownCommandFound = knownCommands && (str in knownCommands); michael@0: while ((ch = this.nextChar()) >= 0 && !specialChars[ch]) { michael@0: // stop if known command is found and next character does not make michael@0: // the str a command michael@0: var possibleCommand = str + String.fromCharCode(ch); michael@0: if (knownCommandFound && !(possibleCommand in knownCommands)) { michael@0: break; michael@0: } michael@0: if (str.length == 128) { michael@0: error('Command token too long: ' + str.length); michael@0: } michael@0: str = possibleCommand; michael@0: knownCommandFound = knownCommands && (str in knownCommands); michael@0: } michael@0: if (str == 'true') { michael@0: return true; michael@0: } michael@0: if (str == 'false') { michael@0: return false; michael@0: } michael@0: if (str == 'null') { michael@0: return null; michael@0: } michael@0: return Cmd.get(str); michael@0: }, michael@0: skipToNextLine: function Lexer_skipToNextLine() { michael@0: var ch = this.currentChar; michael@0: while (ch >= 0) { michael@0: if (ch === 0x0D) { // CR michael@0: ch = this.nextChar(); michael@0: if (ch === 0x0A) { // LF michael@0: this.nextChar(); michael@0: } michael@0: break; michael@0: } else if (ch === 0x0A) { // LF michael@0: this.nextChar(); michael@0: break; michael@0: } michael@0: ch = this.nextChar(); michael@0: } michael@0: } michael@0: }; michael@0: michael@0: return Lexer; michael@0: })(); michael@0: michael@0: var Linearization = (function LinearizationClosure() { michael@0: function Linearization(stream) { michael@0: this.parser = new Parser(new Lexer(stream), false, null); michael@0: var obj1 = this.parser.getObj(); michael@0: var obj2 = this.parser.getObj(); michael@0: var obj3 = this.parser.getObj(); michael@0: this.linDict = this.parser.getObj(); michael@0: if (isInt(obj1) && isInt(obj2) && isCmd(obj3, 'obj') && michael@0: isDict(this.linDict)) { michael@0: var obj = this.linDict.get('Linearized'); michael@0: if (!(isNum(obj) && obj > 0)) { michael@0: this.linDict = null; michael@0: } michael@0: } michael@0: } michael@0: michael@0: Linearization.prototype = { michael@0: getInt: function Linearization_getInt(name) { michael@0: var linDict = this.linDict; michael@0: var obj; michael@0: if (isDict(linDict) && isInt(obj = linDict.get(name)) && obj > 0) { michael@0: return obj; michael@0: } michael@0: error('"' + name + '" field in linearization table is invalid'); michael@0: }, michael@0: getHint: function Linearization_getHint(index) { michael@0: var linDict = this.linDict; michael@0: var obj1, obj2; michael@0: if (isDict(linDict) && isArray(obj1 = linDict.get('H')) && michael@0: obj1.length >= 2 && isInt(obj2 = obj1[index]) && obj2 > 0) { michael@0: return obj2; michael@0: } michael@0: error('Hints table in linearization table is invalid: ' + index); michael@0: }, michael@0: get length() { michael@0: if (!isDict(this.linDict)) { michael@0: return 0; michael@0: } michael@0: return this.getInt('L'); michael@0: }, michael@0: get hintsOffset() { michael@0: return this.getHint(0); michael@0: }, michael@0: get hintsLength() { michael@0: return this.getHint(1); michael@0: }, michael@0: get hintsOffset2() { michael@0: return this.getHint(2); michael@0: }, michael@0: get hintsLenth2() { michael@0: return this.getHint(3); michael@0: }, michael@0: get objectNumberFirst() { michael@0: return this.getInt('O'); michael@0: }, michael@0: get endFirst() { michael@0: return this.getInt('E'); michael@0: }, michael@0: get numPages() { michael@0: return this.getInt('N'); michael@0: }, michael@0: get mainXRefEntriesOffset() { michael@0: return this.getInt('T'); michael@0: }, michael@0: get pageFirst() { michael@0: return this.getInt('P'); michael@0: } michael@0: }; michael@0: michael@0: return Linearization; michael@0: })(); michael@0: michael@0: michael@0: michael@0: var PostScriptParser = (function PostScriptParserClosure() { michael@0: function PostScriptParser(lexer) { michael@0: this.lexer = lexer; michael@0: this.operators = []; michael@0: this.token = null; michael@0: this.prev = null; michael@0: } michael@0: PostScriptParser.prototype = { michael@0: nextToken: function PostScriptParser_nextToken() { michael@0: this.prev = this.token; michael@0: this.token = this.lexer.getToken(); michael@0: }, michael@0: accept: function PostScriptParser_accept(type) { michael@0: if (this.token.type == type) { michael@0: this.nextToken(); michael@0: return true; michael@0: } michael@0: return false; michael@0: }, michael@0: expect: function PostScriptParser_expect(type) { michael@0: if (this.accept(type)) { michael@0: return true; michael@0: } michael@0: error('Unexpected symbol: found ' + this.token.type + ' expected ' + michael@0: type + '.'); michael@0: }, michael@0: parse: function PostScriptParser_parse() { michael@0: this.nextToken(); michael@0: this.expect(PostScriptTokenTypes.LBRACE); michael@0: this.parseBlock(); michael@0: this.expect(PostScriptTokenTypes.RBRACE); michael@0: return this.operators; michael@0: }, michael@0: parseBlock: function PostScriptParser_parseBlock() { michael@0: while (true) { michael@0: if (this.accept(PostScriptTokenTypes.NUMBER)) { michael@0: this.operators.push(this.prev.value); michael@0: } else if (this.accept(PostScriptTokenTypes.OPERATOR)) { michael@0: this.operators.push(this.prev.value); michael@0: } else if (this.accept(PostScriptTokenTypes.LBRACE)) { michael@0: this.parseCondition(); michael@0: } else { michael@0: return; michael@0: } michael@0: } michael@0: }, michael@0: parseCondition: function PostScriptParser_parseCondition() { michael@0: // Add two place holders that will be updated later michael@0: var conditionLocation = this.operators.length; michael@0: this.operators.push(null, null); michael@0: michael@0: this.parseBlock(); michael@0: this.expect(PostScriptTokenTypes.RBRACE); michael@0: if (this.accept(PostScriptTokenTypes.IF)) { michael@0: // The true block is right after the 'if' so it just falls through on michael@0: // true else it jumps and skips the true block. michael@0: this.operators[conditionLocation] = this.operators.length; michael@0: this.operators[conditionLocation + 1] = 'jz'; michael@0: } else if (this.accept(PostScriptTokenTypes.LBRACE)) { michael@0: var jumpLocation = this.operators.length; michael@0: this.operators.push(null, null); michael@0: var endOfTrue = this.operators.length; michael@0: this.parseBlock(); michael@0: this.expect(PostScriptTokenTypes.RBRACE); michael@0: this.expect(PostScriptTokenTypes.IFELSE); michael@0: // The jump is added at the end of the true block to skip the false michael@0: // block. michael@0: this.operators[jumpLocation] = this.operators.length; michael@0: this.operators[jumpLocation + 1] = 'j'; michael@0: michael@0: this.operators[conditionLocation] = endOfTrue; michael@0: this.operators[conditionLocation + 1] = 'jz'; michael@0: } else { michael@0: error('PS Function: error parsing conditional.'); michael@0: } michael@0: } michael@0: }; michael@0: return PostScriptParser; michael@0: })(); michael@0: michael@0: var PostScriptTokenTypes = { michael@0: LBRACE: 0, michael@0: RBRACE: 1, michael@0: NUMBER: 2, michael@0: OPERATOR: 3, michael@0: IF: 4, michael@0: IFELSE: 5 michael@0: }; michael@0: michael@0: var PostScriptToken = (function PostScriptTokenClosure() { michael@0: function PostScriptToken(type, value) { michael@0: this.type = type; michael@0: this.value = value; michael@0: } michael@0: michael@0: var opCache = {}; michael@0: michael@0: PostScriptToken.getOperator = function PostScriptToken_getOperator(op) { michael@0: var opValue = opCache[op]; michael@0: if (opValue) { michael@0: return opValue; michael@0: } michael@0: return opCache[op] = new PostScriptToken(PostScriptTokenTypes.OPERATOR, op); michael@0: }; michael@0: michael@0: PostScriptToken.LBRACE = new PostScriptToken(PostScriptTokenTypes.LBRACE, michael@0: '{'); michael@0: PostScriptToken.RBRACE = new PostScriptToken(PostScriptTokenTypes.RBRACE, michael@0: '}'); michael@0: PostScriptToken.IF = new PostScriptToken(PostScriptTokenTypes.IF, 'IF'); michael@0: PostScriptToken.IFELSE = new PostScriptToken(PostScriptTokenTypes.IFELSE, michael@0: 'IFELSE'); michael@0: return PostScriptToken; michael@0: })(); michael@0: michael@0: var PostScriptLexer = (function PostScriptLexerClosure() { michael@0: function PostScriptLexer(stream) { michael@0: this.stream = stream; michael@0: this.nextChar(); michael@0: } michael@0: PostScriptLexer.prototype = { michael@0: nextChar: function PostScriptLexer_nextChar() { michael@0: return (this.currentChar = this.stream.getByte()); michael@0: }, michael@0: getToken: function PostScriptLexer_getToken() { michael@0: var comment = false; michael@0: var ch = this.currentChar; michael@0: michael@0: // skip comments michael@0: while (true) { michael@0: if (ch < 0) { michael@0: return EOF; michael@0: } michael@0: michael@0: if (comment) { michael@0: if (ch === 0x0A || ch === 0x0D) { michael@0: comment = false; michael@0: } michael@0: } else if (ch == 0x25) { // '%' michael@0: comment = true; michael@0: } else if (!Lexer.isSpace(ch)) { michael@0: break; michael@0: } michael@0: ch = this.nextChar(); michael@0: } michael@0: switch (ch | 0) { michael@0: case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: // '0'-'4' michael@0: case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: // '5'-'9' michael@0: case 0x2B: case 0x2D: case 0x2E: // '+', '-', '.' michael@0: return new PostScriptToken(PostScriptTokenTypes.NUMBER, michael@0: this.getNumber()); michael@0: case 0x7B: // '{' michael@0: this.nextChar(); michael@0: return PostScriptToken.LBRACE; michael@0: case 0x7D: // '}' michael@0: this.nextChar(); michael@0: return PostScriptToken.RBRACE; michael@0: } michael@0: // operator michael@0: var str = String.fromCharCode(ch); michael@0: while ((ch = this.nextChar()) >= 0 && // and 'A'-'Z', 'a'-'z' michael@0: ((ch >= 0x41 && ch <= 0x5A) || (ch >= 0x61 && ch <= 0x7A))) { michael@0: str += String.fromCharCode(ch); michael@0: } michael@0: switch (str.toLowerCase()) { michael@0: case 'if': michael@0: return PostScriptToken.IF; michael@0: case 'ifelse': michael@0: return PostScriptToken.IFELSE; michael@0: default: michael@0: return PostScriptToken.getOperator(str); michael@0: } michael@0: }, michael@0: getNumber: function PostScriptLexer_getNumber() { michael@0: var ch = this.currentChar; michael@0: var str = String.fromCharCode(ch); michael@0: while ((ch = this.nextChar()) >= 0) { michael@0: if ((ch >= 0x30 && ch <= 0x39) || // '0'-'9' michael@0: ch === 0x2D || ch === 0x2E) { // '-', '.' michael@0: str += String.fromCharCode(ch); michael@0: } else { michael@0: break; michael@0: } michael@0: } michael@0: var value = parseFloat(str); michael@0: if (isNaN(value)) { michael@0: error('Invalid floating point number: ' + value); michael@0: } michael@0: return value; michael@0: } michael@0: }; michael@0: return PostScriptLexer; michael@0: })(); michael@0: michael@0: michael@0: var Stream = (function StreamClosure() { michael@0: function Stream(arrayBuffer, start, length, dict) { michael@0: this.bytes = (arrayBuffer instanceof Uint8Array ? michael@0: arrayBuffer : new Uint8Array(arrayBuffer)); michael@0: this.start = start || 0; michael@0: this.pos = this.start; michael@0: this.end = (start + length) || this.bytes.length; michael@0: this.dict = dict; michael@0: } michael@0: michael@0: // required methods for a stream. if a particular stream does not michael@0: // implement these, an error should be thrown michael@0: Stream.prototype = { michael@0: get length() { michael@0: return this.end - this.start; michael@0: }, michael@0: getByte: function Stream_getByte() { michael@0: if (this.pos >= this.end) { michael@0: return -1; michael@0: } michael@0: return this.bytes[this.pos++]; michael@0: }, michael@0: getUint16: function Stream_getUint16() { michael@0: var b0 = this.getByte(); michael@0: var b1 = this.getByte(); michael@0: return (b0 << 8) + b1; michael@0: }, michael@0: getInt32: function Stream_getInt32() { michael@0: var b0 = this.getByte(); michael@0: var b1 = this.getByte(); michael@0: var b2 = this.getByte(); michael@0: var b3 = this.getByte(); michael@0: return (b0 << 24) + (b1 << 16) + (b2 << 8) + b3; michael@0: }, michael@0: // returns subarray of original buffer michael@0: // should only be read michael@0: getBytes: function Stream_getBytes(length) { michael@0: var bytes = this.bytes; michael@0: var pos = this.pos; michael@0: var strEnd = this.end; michael@0: michael@0: if (!length) { michael@0: return bytes.subarray(pos, strEnd); michael@0: } michael@0: var end = pos + length; michael@0: if (end > strEnd) { michael@0: end = strEnd; michael@0: } michael@0: this.pos = end; michael@0: return bytes.subarray(pos, end); michael@0: }, michael@0: peekBytes: function Stream_peekBytes(length) { michael@0: var bytes = this.getBytes(length); michael@0: this.pos -= bytes.length; michael@0: return bytes; michael@0: }, michael@0: skip: function Stream_skip(n) { michael@0: if (!n) { michael@0: n = 1; michael@0: } michael@0: this.pos += n; michael@0: }, michael@0: reset: function Stream_reset() { michael@0: this.pos = this.start; michael@0: }, michael@0: moveStart: function Stream_moveStart() { michael@0: this.start = this.pos; michael@0: }, michael@0: makeSubStream: function Stream_makeSubStream(start, length, dict) { michael@0: return new Stream(this.bytes.buffer, start, length, dict); michael@0: }, michael@0: isStream: true michael@0: }; michael@0: michael@0: return Stream; michael@0: })(); michael@0: michael@0: var StringStream = (function StringStreamClosure() { michael@0: function StringStream(str) { michael@0: var length = str.length; michael@0: var bytes = new Uint8Array(length); michael@0: for (var n = 0; n < length; ++n) { michael@0: bytes[n] = str.charCodeAt(n); michael@0: } michael@0: Stream.call(this, bytes); michael@0: } michael@0: michael@0: StringStream.prototype = Stream.prototype; michael@0: michael@0: return StringStream; michael@0: })(); michael@0: michael@0: // super class for the decoding streams michael@0: var DecodeStream = (function DecodeStreamClosure() { michael@0: function DecodeStream(maybeMinBufferLength) { michael@0: this.pos = 0; michael@0: this.bufferLength = 0; michael@0: this.eof = false; michael@0: this.buffer = null; michael@0: this.minBufferLength = 512; michael@0: if (maybeMinBufferLength) { michael@0: // Compute the first power of two that is as big as maybeMinBufferLength. michael@0: while (this.minBufferLength < maybeMinBufferLength) { michael@0: this.minBufferLength *= 2; michael@0: } michael@0: } michael@0: } michael@0: michael@0: DecodeStream.prototype = { michael@0: ensureBuffer: function DecodeStream_ensureBuffer(requested) { michael@0: var buffer = this.buffer; michael@0: var current; michael@0: if (buffer) { michael@0: current = buffer.byteLength; michael@0: if (requested <= current) { michael@0: return buffer; michael@0: } michael@0: } else { michael@0: current = 0; michael@0: } michael@0: var size = this.minBufferLength; michael@0: while (size < requested) { michael@0: size *= 2; michael@0: } michael@0: var buffer2 = new Uint8Array(size); michael@0: for (var i = 0; i < current; ++i) { michael@0: buffer2[i] = buffer[i]; michael@0: } michael@0: return (this.buffer = buffer2); michael@0: }, michael@0: getByte: function DecodeStream_getByte() { michael@0: var pos = this.pos; michael@0: while (this.bufferLength <= pos) { michael@0: if (this.eof) { michael@0: return -1; michael@0: } michael@0: this.readBlock(); michael@0: } michael@0: return this.buffer[this.pos++]; michael@0: }, michael@0: getUint16: function DecodeStream_getUint16() { michael@0: var b0 = this.getByte(); michael@0: var b1 = this.getByte(); michael@0: return (b0 << 8) + b1; michael@0: }, michael@0: getInt32: function DecodeStream_getInt32() { michael@0: var b0 = this.getByte(); michael@0: var b1 = this.getByte(); michael@0: var b2 = this.getByte(); michael@0: var b3 = this.getByte(); michael@0: return (b0 << 24) + (b1 << 16) + (b2 << 8) + b3; michael@0: }, michael@0: getBytes: function DecodeStream_getBytes(length) { michael@0: var end, pos = this.pos; michael@0: michael@0: if (length) { michael@0: this.ensureBuffer(pos + length); michael@0: end = pos + length; michael@0: michael@0: while (!this.eof && this.bufferLength < end) { michael@0: this.readBlock(); michael@0: } michael@0: var bufEnd = this.bufferLength; michael@0: if (end > bufEnd) { michael@0: end = bufEnd; michael@0: } michael@0: } else { michael@0: while (!this.eof) { michael@0: this.readBlock(); michael@0: } michael@0: end = this.bufferLength; michael@0: michael@0: // checking if bufferLength is still 0 then michael@0: // the buffer has to be initialized michael@0: if (!end) { michael@0: this.buffer = new Uint8Array(0); michael@0: } michael@0: } michael@0: michael@0: this.pos = end; michael@0: return this.buffer.subarray(pos, end); michael@0: }, michael@0: peekBytes: function DecodeStream_peekBytes(length) { michael@0: var bytes = this.getBytes(length); michael@0: this.pos -= bytes.length; michael@0: return bytes; michael@0: }, michael@0: makeSubStream: function DecodeStream_makeSubStream(start, length, dict) { michael@0: var end = start + length; michael@0: while (this.bufferLength <= end && !this.eof) { michael@0: this.readBlock(); michael@0: } michael@0: return new Stream(this.buffer, start, length, dict); michael@0: }, michael@0: skip: function Stream_skip(n) { michael@0: if (!n) { michael@0: n = 1; michael@0: } michael@0: this.pos += n; michael@0: }, michael@0: reset: function DecodeStream_reset() { michael@0: this.pos = 0; michael@0: }, michael@0: getBaseStreams: function DecodeStream_getBaseStreams() { michael@0: if (this.str && this.str.getBaseStreams) { michael@0: return this.str.getBaseStreams(); michael@0: } michael@0: return []; michael@0: } michael@0: }; michael@0: michael@0: return DecodeStream; michael@0: })(); michael@0: michael@0: var StreamsSequenceStream = (function StreamsSequenceStreamClosure() { michael@0: function StreamsSequenceStream(streams) { michael@0: this.streams = streams; michael@0: DecodeStream.call(this, /* maybeLength = */ null); michael@0: } michael@0: michael@0: StreamsSequenceStream.prototype = Object.create(DecodeStream.prototype); michael@0: michael@0: StreamsSequenceStream.prototype.readBlock = michael@0: function streamSequenceStreamReadBlock() { michael@0: michael@0: var streams = this.streams; michael@0: if (streams.length === 0) { michael@0: this.eof = true; michael@0: return; michael@0: } michael@0: var stream = streams.shift(); michael@0: var chunk = stream.getBytes(); michael@0: var bufferLength = this.bufferLength; michael@0: var newLength = bufferLength + chunk.length; michael@0: var buffer = this.ensureBuffer(newLength); michael@0: buffer.set(chunk, bufferLength); michael@0: this.bufferLength = newLength; michael@0: }; michael@0: michael@0: StreamsSequenceStream.prototype.getBaseStreams = michael@0: function StreamsSequenceStream_getBaseStreams() { michael@0: michael@0: var baseStreams = []; michael@0: for (var i = 0, ii = this.streams.length; i < ii; i++) { michael@0: var stream = this.streams[i]; michael@0: if (stream.getBaseStreams) { michael@0: Util.concatenateToArray(baseStreams, stream.getBaseStreams()); michael@0: } michael@0: } michael@0: return baseStreams; michael@0: }; michael@0: michael@0: return StreamsSequenceStream; michael@0: })(); michael@0: michael@0: var FlateStream = (function FlateStreamClosure() { michael@0: var codeLenCodeMap = new Uint32Array([ michael@0: 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 michael@0: ]); michael@0: michael@0: var lengthDecode = new Uint32Array([ michael@0: 0x00003, 0x00004, 0x00005, 0x00006, 0x00007, 0x00008, 0x00009, 0x0000a, michael@0: 0x1000b, 0x1000d, 0x1000f, 0x10011, 0x20013, 0x20017, 0x2001b, 0x2001f, michael@0: 0x30023, 0x3002b, 0x30033, 0x3003b, 0x40043, 0x40053, 0x40063, 0x40073, michael@0: 0x50083, 0x500a3, 0x500c3, 0x500e3, 0x00102, 0x00102, 0x00102 michael@0: ]); michael@0: michael@0: var distDecode = new Uint32Array([ michael@0: 0x00001, 0x00002, 0x00003, 0x00004, 0x10005, 0x10007, 0x20009, 0x2000d, michael@0: 0x30011, 0x30019, 0x40021, 0x40031, 0x50041, 0x50061, 0x60081, 0x600c1, michael@0: 0x70101, 0x70181, 0x80201, 0x80301, 0x90401, 0x90601, 0xa0801, 0xa0c01, michael@0: 0xb1001, 0xb1801, 0xc2001, 0xc3001, 0xd4001, 0xd6001 michael@0: ]); michael@0: michael@0: var fixedLitCodeTab = [new Uint32Array([ michael@0: 0x70100, 0x80050, 0x80010, 0x80118, 0x70110, 0x80070, 0x80030, 0x900c0, michael@0: 0x70108, 0x80060, 0x80020, 0x900a0, 0x80000, 0x80080, 0x80040, 0x900e0, michael@0: 0x70104, 0x80058, 0x80018, 0x90090, 0x70114, 0x80078, 0x80038, 0x900d0, michael@0: 0x7010c, 0x80068, 0x80028, 0x900b0, 0x80008, 0x80088, 0x80048, 0x900f0, michael@0: 0x70102, 0x80054, 0x80014, 0x8011c, 0x70112, 0x80074, 0x80034, 0x900c8, michael@0: 0x7010a, 0x80064, 0x80024, 0x900a8, 0x80004, 0x80084, 0x80044, 0x900e8, michael@0: 0x70106, 0x8005c, 0x8001c, 0x90098, 0x70116, 0x8007c, 0x8003c, 0x900d8, michael@0: 0x7010e, 0x8006c, 0x8002c, 0x900b8, 0x8000c, 0x8008c, 0x8004c, 0x900f8, michael@0: 0x70101, 0x80052, 0x80012, 0x8011a, 0x70111, 0x80072, 0x80032, 0x900c4, michael@0: 0x70109, 0x80062, 0x80022, 0x900a4, 0x80002, 0x80082, 0x80042, 0x900e4, michael@0: 0x70105, 0x8005a, 0x8001a, 0x90094, 0x70115, 0x8007a, 0x8003a, 0x900d4, michael@0: 0x7010d, 0x8006a, 0x8002a, 0x900b4, 0x8000a, 0x8008a, 0x8004a, 0x900f4, michael@0: 0x70103, 0x80056, 0x80016, 0x8011e, 0x70113, 0x80076, 0x80036, 0x900cc, michael@0: 0x7010b, 0x80066, 0x80026, 0x900ac, 0x80006, 0x80086, 0x80046, 0x900ec, michael@0: 0x70107, 0x8005e, 0x8001e, 0x9009c, 0x70117, 0x8007e, 0x8003e, 0x900dc, michael@0: 0x7010f, 0x8006e, 0x8002e, 0x900bc, 0x8000e, 0x8008e, 0x8004e, 0x900fc, michael@0: 0x70100, 0x80051, 0x80011, 0x80119, 0x70110, 0x80071, 0x80031, 0x900c2, michael@0: 0x70108, 0x80061, 0x80021, 0x900a2, 0x80001, 0x80081, 0x80041, 0x900e2, michael@0: 0x70104, 0x80059, 0x80019, 0x90092, 0x70114, 0x80079, 0x80039, 0x900d2, michael@0: 0x7010c, 0x80069, 0x80029, 0x900b2, 0x80009, 0x80089, 0x80049, 0x900f2, michael@0: 0x70102, 0x80055, 0x80015, 0x8011d, 0x70112, 0x80075, 0x80035, 0x900ca, michael@0: 0x7010a, 0x80065, 0x80025, 0x900aa, 0x80005, 0x80085, 0x80045, 0x900ea, michael@0: 0x70106, 0x8005d, 0x8001d, 0x9009a, 0x70116, 0x8007d, 0x8003d, 0x900da, michael@0: 0x7010e, 0x8006d, 0x8002d, 0x900ba, 0x8000d, 0x8008d, 0x8004d, 0x900fa, michael@0: 0x70101, 0x80053, 0x80013, 0x8011b, 0x70111, 0x80073, 0x80033, 0x900c6, michael@0: 0x70109, 0x80063, 0x80023, 0x900a6, 0x80003, 0x80083, 0x80043, 0x900e6, michael@0: 0x70105, 0x8005b, 0x8001b, 0x90096, 0x70115, 0x8007b, 0x8003b, 0x900d6, michael@0: 0x7010d, 0x8006b, 0x8002b, 0x900b6, 0x8000b, 0x8008b, 0x8004b, 0x900f6, michael@0: 0x70103, 0x80057, 0x80017, 0x8011f, 0x70113, 0x80077, 0x80037, 0x900ce, michael@0: 0x7010b, 0x80067, 0x80027, 0x900ae, 0x80007, 0x80087, 0x80047, 0x900ee, michael@0: 0x70107, 0x8005f, 0x8001f, 0x9009e, 0x70117, 0x8007f, 0x8003f, 0x900de, michael@0: 0x7010f, 0x8006f, 0x8002f, 0x900be, 0x8000f, 0x8008f, 0x8004f, 0x900fe, michael@0: 0x70100, 0x80050, 0x80010, 0x80118, 0x70110, 0x80070, 0x80030, 0x900c1, michael@0: 0x70108, 0x80060, 0x80020, 0x900a1, 0x80000, 0x80080, 0x80040, 0x900e1, michael@0: 0x70104, 0x80058, 0x80018, 0x90091, 0x70114, 0x80078, 0x80038, 0x900d1, michael@0: 0x7010c, 0x80068, 0x80028, 0x900b1, 0x80008, 0x80088, 0x80048, 0x900f1, michael@0: 0x70102, 0x80054, 0x80014, 0x8011c, 0x70112, 0x80074, 0x80034, 0x900c9, michael@0: 0x7010a, 0x80064, 0x80024, 0x900a9, 0x80004, 0x80084, 0x80044, 0x900e9, michael@0: 0x70106, 0x8005c, 0x8001c, 0x90099, 0x70116, 0x8007c, 0x8003c, 0x900d9, michael@0: 0x7010e, 0x8006c, 0x8002c, 0x900b9, 0x8000c, 0x8008c, 0x8004c, 0x900f9, michael@0: 0x70101, 0x80052, 0x80012, 0x8011a, 0x70111, 0x80072, 0x80032, 0x900c5, michael@0: 0x70109, 0x80062, 0x80022, 0x900a5, 0x80002, 0x80082, 0x80042, 0x900e5, michael@0: 0x70105, 0x8005a, 0x8001a, 0x90095, 0x70115, 0x8007a, 0x8003a, 0x900d5, michael@0: 0x7010d, 0x8006a, 0x8002a, 0x900b5, 0x8000a, 0x8008a, 0x8004a, 0x900f5, michael@0: 0x70103, 0x80056, 0x80016, 0x8011e, 0x70113, 0x80076, 0x80036, 0x900cd, michael@0: 0x7010b, 0x80066, 0x80026, 0x900ad, 0x80006, 0x80086, 0x80046, 0x900ed, michael@0: 0x70107, 0x8005e, 0x8001e, 0x9009d, 0x70117, 0x8007e, 0x8003e, 0x900dd, michael@0: 0x7010f, 0x8006e, 0x8002e, 0x900bd, 0x8000e, 0x8008e, 0x8004e, 0x900fd, michael@0: 0x70100, 0x80051, 0x80011, 0x80119, 0x70110, 0x80071, 0x80031, 0x900c3, michael@0: 0x70108, 0x80061, 0x80021, 0x900a3, 0x80001, 0x80081, 0x80041, 0x900e3, michael@0: 0x70104, 0x80059, 0x80019, 0x90093, 0x70114, 0x80079, 0x80039, 0x900d3, michael@0: 0x7010c, 0x80069, 0x80029, 0x900b3, 0x80009, 0x80089, 0x80049, 0x900f3, michael@0: 0x70102, 0x80055, 0x80015, 0x8011d, 0x70112, 0x80075, 0x80035, 0x900cb, michael@0: 0x7010a, 0x80065, 0x80025, 0x900ab, 0x80005, 0x80085, 0x80045, 0x900eb, michael@0: 0x70106, 0x8005d, 0x8001d, 0x9009b, 0x70116, 0x8007d, 0x8003d, 0x900db, michael@0: 0x7010e, 0x8006d, 0x8002d, 0x900bb, 0x8000d, 0x8008d, 0x8004d, 0x900fb, michael@0: 0x70101, 0x80053, 0x80013, 0x8011b, 0x70111, 0x80073, 0x80033, 0x900c7, michael@0: 0x70109, 0x80063, 0x80023, 0x900a7, 0x80003, 0x80083, 0x80043, 0x900e7, michael@0: 0x70105, 0x8005b, 0x8001b, 0x90097, 0x70115, 0x8007b, 0x8003b, 0x900d7, michael@0: 0x7010d, 0x8006b, 0x8002b, 0x900b7, 0x8000b, 0x8008b, 0x8004b, 0x900f7, michael@0: 0x70103, 0x80057, 0x80017, 0x8011f, 0x70113, 0x80077, 0x80037, 0x900cf, michael@0: 0x7010b, 0x80067, 0x80027, 0x900af, 0x80007, 0x80087, 0x80047, 0x900ef, michael@0: 0x70107, 0x8005f, 0x8001f, 0x9009f, 0x70117, 0x8007f, 0x8003f, 0x900df, michael@0: 0x7010f, 0x8006f, 0x8002f, 0x900bf, 0x8000f, 0x8008f, 0x8004f, 0x900ff michael@0: ]), 9]; michael@0: michael@0: var fixedDistCodeTab = [new Uint32Array([ michael@0: 0x50000, 0x50010, 0x50008, 0x50018, 0x50004, 0x50014, 0x5000c, 0x5001c, michael@0: 0x50002, 0x50012, 0x5000a, 0x5001a, 0x50006, 0x50016, 0x5000e, 0x00000, michael@0: 0x50001, 0x50011, 0x50009, 0x50019, 0x50005, 0x50015, 0x5000d, 0x5001d, michael@0: 0x50003, 0x50013, 0x5000b, 0x5001b, 0x50007, 0x50017, 0x5000f, 0x00000 michael@0: ]), 5]; michael@0: michael@0: function FlateStream(str, maybeLength) { michael@0: this.str = str; michael@0: this.dict = str.dict; michael@0: michael@0: var cmf = str.getByte(); michael@0: var flg = str.getByte(); michael@0: if (cmf == -1 || flg == -1) { michael@0: error('Invalid header in flate stream: ' + cmf + ', ' + flg); michael@0: } michael@0: if ((cmf & 0x0f) != 0x08) { michael@0: error('Unknown compression method in flate stream: ' + cmf + ', ' + flg); michael@0: } michael@0: if ((((cmf << 8) + flg) % 31) !== 0) { michael@0: error('Bad FCHECK in flate stream: ' + cmf + ', ' + flg); michael@0: } michael@0: if (flg & 0x20) { michael@0: error('FDICT bit set in flate stream: ' + cmf + ', ' + flg); michael@0: } michael@0: michael@0: this.codeSize = 0; michael@0: this.codeBuf = 0; michael@0: michael@0: DecodeStream.call(this, maybeLength); michael@0: } michael@0: michael@0: FlateStream.prototype = Object.create(DecodeStream.prototype); michael@0: michael@0: FlateStream.prototype.getBits = function FlateStream_getBits(bits) { michael@0: var str = this.str; michael@0: var codeSize = this.codeSize; michael@0: var codeBuf = this.codeBuf; michael@0: michael@0: var b; michael@0: while (codeSize < bits) { michael@0: if ((b = str.getByte()) === -1) { michael@0: error('Bad encoding in flate stream'); michael@0: } michael@0: codeBuf |= b << codeSize; michael@0: codeSize += 8; michael@0: } michael@0: b = codeBuf & ((1 << bits) - 1); michael@0: this.codeBuf = codeBuf >> bits; michael@0: this.codeSize = codeSize -= bits; michael@0: michael@0: return b; michael@0: }; michael@0: michael@0: FlateStream.prototype.getCode = function FlateStream_getCode(table) { michael@0: var str = this.str; michael@0: var codes = table[0]; michael@0: var maxLen = table[1]; michael@0: var codeSize = this.codeSize; michael@0: var codeBuf = this.codeBuf; michael@0: michael@0: while (codeSize < maxLen) { michael@0: var b; michael@0: if ((b = str.getByte()) === -1) { michael@0: error('Bad encoding in flate stream'); michael@0: } michael@0: codeBuf |= (b << codeSize); michael@0: codeSize += 8; michael@0: } michael@0: var code = codes[codeBuf & ((1 << maxLen) - 1)]; michael@0: var codeLen = code >> 16; michael@0: var codeVal = code & 0xffff; michael@0: if (codeSize === 0 || codeSize < codeLen || codeLen === 0) { michael@0: error('Bad encoding in flate stream'); michael@0: } michael@0: this.codeBuf = (codeBuf >> codeLen); michael@0: this.codeSize = (codeSize - codeLen); michael@0: return codeVal; michael@0: }; michael@0: michael@0: FlateStream.prototype.generateHuffmanTable = michael@0: function flateStreamGenerateHuffmanTable(lengths) { michael@0: var n = lengths.length; michael@0: michael@0: // find max code length michael@0: var maxLen = 0; michael@0: var i; michael@0: for (i = 0; i < n; ++i) { michael@0: if (lengths[i] > maxLen) { michael@0: maxLen = lengths[i]; michael@0: } michael@0: } michael@0: michael@0: // build the table michael@0: var size = 1 << maxLen; michael@0: var codes = new Uint32Array(size); michael@0: for (var len = 1, code = 0, skip = 2; michael@0: len <= maxLen; michael@0: ++len, code <<= 1, skip <<= 1) { michael@0: for (var val = 0; val < n; ++val) { michael@0: if (lengths[val] == len) { michael@0: // bit-reverse the code michael@0: var code2 = 0; michael@0: var t = code; michael@0: for (i = 0; i < len; ++i) { michael@0: code2 = (code2 << 1) | (t & 1); michael@0: t >>= 1; michael@0: } michael@0: michael@0: // fill the table entries michael@0: for (i = code2; i < size; i += skip) { michael@0: codes[i] = (len << 16) | val; michael@0: } michael@0: ++code; michael@0: } michael@0: } michael@0: } michael@0: michael@0: return [codes, maxLen]; michael@0: }; michael@0: michael@0: FlateStream.prototype.readBlock = function FlateStream_readBlock() { michael@0: var buffer, len; michael@0: var str = this.str; michael@0: // read block header michael@0: var hdr = this.getBits(3); michael@0: if (hdr & 1) { michael@0: this.eof = true; michael@0: } michael@0: hdr >>= 1; michael@0: michael@0: if (hdr === 0) { // uncompressed block michael@0: var b; michael@0: michael@0: if ((b = str.getByte()) === -1) { michael@0: error('Bad block header in flate stream'); michael@0: } michael@0: var blockLen = b; michael@0: if ((b = str.getByte()) === -1) { michael@0: error('Bad block header in flate stream'); michael@0: } michael@0: blockLen |= (b << 8); michael@0: if ((b = str.getByte()) === -1) { michael@0: error('Bad block header in flate stream'); michael@0: } michael@0: var check = b; michael@0: if ((b = str.getByte()) === -1) { michael@0: error('Bad block header in flate stream'); michael@0: } michael@0: check |= (b << 8); michael@0: if (check != (~blockLen & 0xffff) && michael@0: (blockLen !== 0 || check !== 0)) { michael@0: // Ignoring error for bad "empty" block (see issue 1277) michael@0: error('Bad uncompressed block length in flate stream'); michael@0: } michael@0: michael@0: this.codeBuf = 0; michael@0: this.codeSize = 0; michael@0: michael@0: var bufferLength = this.bufferLength; michael@0: buffer = this.ensureBuffer(bufferLength + blockLen); michael@0: var end = bufferLength + blockLen; michael@0: this.bufferLength = end; michael@0: if (blockLen === 0) { michael@0: if (str.peekBytes(1).length === 0) { michael@0: this.eof = true; michael@0: } michael@0: } else { michael@0: for (var n = bufferLength; n < end; ++n) { michael@0: if ((b = str.getByte()) === -1) { michael@0: this.eof = true; michael@0: break; michael@0: } michael@0: buffer[n] = b; michael@0: } michael@0: } michael@0: return; michael@0: } michael@0: michael@0: var litCodeTable; michael@0: var distCodeTable; michael@0: if (hdr == 1) { // compressed block, fixed codes michael@0: litCodeTable = fixedLitCodeTab; michael@0: distCodeTable = fixedDistCodeTab; michael@0: } else if (hdr == 2) { // compressed block, dynamic codes michael@0: var numLitCodes = this.getBits(5) + 257; michael@0: var numDistCodes = this.getBits(5) + 1; michael@0: var numCodeLenCodes = this.getBits(4) + 4; michael@0: michael@0: // build the code lengths code table michael@0: var codeLenCodeLengths = new Uint8Array(codeLenCodeMap.length); michael@0: michael@0: var i; michael@0: for (i = 0; i < numCodeLenCodes; ++i) { michael@0: codeLenCodeLengths[codeLenCodeMap[i]] = this.getBits(3); michael@0: } michael@0: var codeLenCodeTab = this.generateHuffmanTable(codeLenCodeLengths); michael@0: michael@0: // build the literal and distance code tables michael@0: len = 0; michael@0: i = 0; michael@0: var codes = numLitCodes + numDistCodes; michael@0: var codeLengths = new Uint8Array(codes); michael@0: var bitsLength, bitsOffset, what; michael@0: while (i < codes) { michael@0: var code = this.getCode(codeLenCodeTab); michael@0: if (code == 16) { michael@0: bitsLength = 2; bitsOffset = 3; what = len; michael@0: } else if (code == 17) { michael@0: bitsLength = 3; bitsOffset = 3; what = (len = 0); michael@0: } else if (code == 18) { michael@0: bitsLength = 7; bitsOffset = 11; what = (len = 0); michael@0: } else { michael@0: codeLengths[i++] = len = code; michael@0: continue; michael@0: } michael@0: michael@0: var repeatLength = this.getBits(bitsLength) + bitsOffset; michael@0: while (repeatLength-- > 0) { michael@0: codeLengths[i++] = what; michael@0: } michael@0: } michael@0: michael@0: litCodeTable = michael@0: this.generateHuffmanTable(codeLengths.subarray(0, numLitCodes)); michael@0: distCodeTable = michael@0: this.generateHuffmanTable(codeLengths.subarray(numLitCodes, codes)); michael@0: } else { michael@0: error('Unknown block type in flate stream'); michael@0: } michael@0: michael@0: buffer = this.buffer; michael@0: var limit = buffer ? buffer.length : 0; michael@0: var pos = this.bufferLength; michael@0: while (true) { michael@0: var code1 = this.getCode(litCodeTable); michael@0: if (code1 < 256) { michael@0: if (pos + 1 >= limit) { michael@0: buffer = this.ensureBuffer(pos + 1); michael@0: limit = buffer.length; michael@0: } michael@0: buffer[pos++] = code1; michael@0: continue; michael@0: } michael@0: if (code1 == 256) { michael@0: this.bufferLength = pos; michael@0: return; michael@0: } michael@0: code1 -= 257; michael@0: code1 = lengthDecode[code1]; michael@0: var code2 = code1 >> 16; michael@0: if (code2 > 0) { michael@0: code2 = this.getBits(code2); michael@0: } michael@0: len = (code1 & 0xffff) + code2; michael@0: code1 = this.getCode(distCodeTable); michael@0: code1 = distDecode[code1]; michael@0: code2 = code1 >> 16; michael@0: if (code2 > 0) { michael@0: code2 = this.getBits(code2); michael@0: } michael@0: var dist = (code1 & 0xffff) + code2; michael@0: if (pos + len >= limit) { michael@0: buffer = this.ensureBuffer(pos + len); michael@0: limit = buffer.length; michael@0: } michael@0: for (var k = 0; k < len; ++k, ++pos) { michael@0: buffer[pos] = buffer[pos - dist]; michael@0: } michael@0: } michael@0: }; michael@0: michael@0: return FlateStream; michael@0: })(); michael@0: michael@0: var PredictorStream = (function PredictorStreamClosure() { michael@0: function PredictorStream(str, maybeLength, params) { michael@0: var predictor = this.predictor = params.get('Predictor') || 1; michael@0: michael@0: if (predictor <= 1) { michael@0: return str; // no prediction michael@0: } michael@0: if (predictor !== 2 && (predictor < 10 || predictor > 15)) { michael@0: error('Unsupported predictor: ' + predictor); michael@0: } michael@0: michael@0: if (predictor === 2) { michael@0: this.readBlock = this.readBlockTiff; michael@0: } else { michael@0: this.readBlock = this.readBlockPng; michael@0: } michael@0: michael@0: this.str = str; michael@0: this.dict = str.dict; michael@0: michael@0: var colors = this.colors = params.get('Colors') || 1; michael@0: var bits = this.bits = params.get('BitsPerComponent') || 8; michael@0: var columns = this.columns = params.get('Columns') || 1; michael@0: michael@0: this.pixBytes = (colors * bits + 7) >> 3; michael@0: this.rowBytes = (columns * colors * bits + 7) >> 3; michael@0: michael@0: DecodeStream.call(this, maybeLength); michael@0: return this; michael@0: } michael@0: michael@0: PredictorStream.prototype = Object.create(DecodeStream.prototype); michael@0: michael@0: PredictorStream.prototype.readBlockTiff = michael@0: function predictorStreamReadBlockTiff() { michael@0: var rowBytes = this.rowBytes; michael@0: michael@0: var bufferLength = this.bufferLength; michael@0: var buffer = this.ensureBuffer(bufferLength + rowBytes); michael@0: michael@0: var bits = this.bits; michael@0: var colors = this.colors; michael@0: michael@0: var rawBytes = this.str.getBytes(rowBytes); michael@0: this.eof = !rawBytes.length; michael@0: if (this.eof) { michael@0: return; michael@0: } michael@0: michael@0: var inbuf = 0, outbuf = 0; michael@0: var inbits = 0, outbits = 0; michael@0: var pos = bufferLength; michael@0: var i; michael@0: michael@0: if (bits === 1) { michael@0: for (i = 0; i < rowBytes; ++i) { michael@0: var c = rawBytes[i]; michael@0: inbuf = (inbuf << 8) | c; michael@0: // bitwise addition is exclusive or michael@0: // first shift inbuf and then add michael@0: buffer[pos++] = (c ^ (inbuf >> colors)) & 0xFF; michael@0: // truncate inbuf (assumes colors < 16) michael@0: inbuf &= 0xFFFF; michael@0: } michael@0: } else if (bits === 8) { michael@0: for (i = 0; i < colors; ++i) { michael@0: buffer[pos++] = rawBytes[i]; michael@0: } michael@0: for (; i < rowBytes; ++i) { michael@0: buffer[pos] = buffer[pos - colors] + rawBytes[i]; michael@0: pos++; michael@0: } michael@0: } else { michael@0: var compArray = new Uint8Array(colors + 1); michael@0: var bitMask = (1 << bits) - 1; michael@0: var j = 0, k = bufferLength; michael@0: var columns = this.columns; michael@0: for (i = 0; i < columns; ++i) { michael@0: for (var kk = 0; kk < colors; ++kk) { michael@0: if (inbits < bits) { michael@0: inbuf = (inbuf << 8) | (rawBytes[j++] & 0xFF); michael@0: inbits += 8; michael@0: } michael@0: compArray[kk] = (compArray[kk] + michael@0: (inbuf >> (inbits - bits))) & bitMask; michael@0: inbits -= bits; michael@0: outbuf = (outbuf << bits) | compArray[kk]; michael@0: outbits += bits; michael@0: if (outbits >= 8) { michael@0: buffer[k++] = (outbuf >> (outbits - 8)) & 0xFF; michael@0: outbits -= 8; michael@0: } michael@0: } michael@0: } michael@0: if (outbits > 0) { michael@0: buffer[k++] = (outbuf << (8 - outbits)) + michael@0: (inbuf & ((1 << (8 - outbits)) - 1)); michael@0: } michael@0: } michael@0: this.bufferLength += rowBytes; michael@0: }; michael@0: michael@0: PredictorStream.prototype.readBlockPng = michael@0: function predictorStreamReadBlockPng() { michael@0: michael@0: var rowBytes = this.rowBytes; michael@0: var pixBytes = this.pixBytes; michael@0: michael@0: var predictor = this.str.getByte(); michael@0: var rawBytes = this.str.getBytes(rowBytes); michael@0: this.eof = !rawBytes.length; michael@0: if (this.eof) { michael@0: return; michael@0: } michael@0: michael@0: var bufferLength = this.bufferLength; michael@0: var buffer = this.ensureBuffer(bufferLength + rowBytes); michael@0: michael@0: var prevRow = buffer.subarray(bufferLength - rowBytes, bufferLength); michael@0: if (prevRow.length === 0) { michael@0: prevRow = new Uint8Array(rowBytes); michael@0: } michael@0: michael@0: var i, j = bufferLength, up, c; michael@0: switch (predictor) { michael@0: case 0: michael@0: for (i = 0; i < rowBytes; ++i) { michael@0: buffer[j++] = rawBytes[i]; michael@0: } michael@0: break; michael@0: case 1: michael@0: for (i = 0; i < pixBytes; ++i) { michael@0: buffer[j++] = rawBytes[i]; michael@0: } michael@0: for (; i < rowBytes; ++i) { michael@0: buffer[j] = (buffer[j - pixBytes] + rawBytes[i]) & 0xFF; michael@0: j++; michael@0: } michael@0: break; michael@0: case 2: michael@0: for (i = 0; i < rowBytes; ++i) { michael@0: buffer[j++] = (prevRow[i] + rawBytes[i]) & 0xFF; michael@0: } michael@0: break; michael@0: case 3: michael@0: for (i = 0; i < pixBytes; ++i) { michael@0: buffer[j++] = (prevRow[i] >> 1) + rawBytes[i]; michael@0: } michael@0: for (; i < rowBytes; ++i) { michael@0: buffer[j] = (((prevRow[i] + buffer[j - pixBytes]) >> 1) + michael@0: rawBytes[i]) & 0xFF; michael@0: j++; michael@0: } michael@0: break; michael@0: case 4: michael@0: // we need to save the up left pixels values. the simplest way michael@0: // is to create a new buffer michael@0: for (i = 0; i < pixBytes; ++i) { michael@0: up = prevRow[i]; michael@0: c = rawBytes[i]; michael@0: buffer[j++] = up + c; michael@0: } michael@0: for (; i < rowBytes; ++i) { michael@0: up = prevRow[i]; michael@0: var upLeft = prevRow[i - pixBytes]; michael@0: var left = buffer[j - pixBytes]; michael@0: var p = left + up - upLeft; michael@0: michael@0: var pa = p - left; michael@0: if (pa < 0) { michael@0: pa = -pa; michael@0: } michael@0: var pb = p - up; michael@0: if (pb < 0) { michael@0: pb = -pb; michael@0: } michael@0: var pc = p - upLeft; michael@0: if (pc < 0) { michael@0: pc = -pc; michael@0: } michael@0: michael@0: c = rawBytes[i]; michael@0: if (pa <= pb && pa <= pc) { michael@0: buffer[j++] = left + c; michael@0: } else if (pb <= pc) { michael@0: buffer[j++] = up + c; michael@0: } else { michael@0: buffer[j++] = upLeft + c; michael@0: } michael@0: } michael@0: break; michael@0: default: michael@0: error('Unsupported predictor: ' + predictor); michael@0: } michael@0: this.bufferLength += rowBytes; michael@0: }; michael@0: michael@0: return PredictorStream; michael@0: })(); michael@0: michael@0: /** michael@0: * Depending on the type of JPEG a JpegStream is handled in different ways. For michael@0: * JPEG's that are supported natively such as DeviceGray and DeviceRGB the image michael@0: * data is stored and then loaded by the browser. For unsupported JPEG's we use michael@0: * a library to decode these images and the stream behaves like all the other michael@0: * DecodeStreams. michael@0: */ michael@0: var JpegStream = (function JpegStreamClosure() { michael@0: function JpegStream(stream, maybeLength, dict, xref) { michael@0: // TODO: per poppler, some images may have 'junk' before that michael@0: // need to be removed michael@0: this.stream = stream; michael@0: this.maybeLength = maybeLength; michael@0: this.dict = dict; michael@0: michael@0: DecodeStream.call(this, maybeLength); michael@0: } michael@0: michael@0: JpegStream.prototype = Object.create(DecodeStream.prototype); michael@0: michael@0: Object.defineProperty(JpegStream.prototype, 'bytes', { michael@0: get: function JpegStream_bytes() { michael@0: // If this.maybeLength is null, we'll get the entire stream. michael@0: return shadow(this, 'bytes', this.stream.getBytes(this.maybeLength)); michael@0: }, michael@0: configurable: true michael@0: }); michael@0: michael@0: JpegStream.prototype.ensureBuffer = function JpegStream_ensureBuffer(req) { michael@0: if (this.bufferLength) { michael@0: return; michael@0: } michael@0: try { michael@0: var jpegImage = new JpegImage(); michael@0: if (this.colorTransform != -1) { michael@0: jpegImage.colorTransform = this.colorTransform; michael@0: } michael@0: jpegImage.parse(this.bytes); michael@0: var width = jpegImage.width; michael@0: var height = jpegImage.height; michael@0: var data = jpegImage.getData(width, height); michael@0: this.buffer = data; michael@0: this.bufferLength = data.length; michael@0: this.eof = true; michael@0: } catch (e) { michael@0: error('JPEG error: ' + e); michael@0: } michael@0: }; michael@0: JpegStream.prototype.getIR = function JpegStream_getIR() { michael@0: return PDFJS.createObjectURL(this.bytes, 'image/jpeg'); michael@0: }; michael@0: /** michael@0: * Checks if the image can be decoded and displayed by the browser without any michael@0: * further processing such as color space conversions. michael@0: */ michael@0: JpegStream.prototype.isNativelySupported = michael@0: function JpegStream_isNativelySupported(xref, res) { michael@0: var cs = ColorSpace.parse(this.dict.get('ColorSpace', 'CS'), xref, res); michael@0: return cs.name === 'DeviceGray' || cs.name === 'DeviceRGB'; michael@0: }; michael@0: /** michael@0: * Checks if the image can be decoded by the browser. michael@0: */ michael@0: JpegStream.prototype.isNativelyDecodable = michael@0: function JpegStream_isNativelyDecodable(xref, res) { michael@0: var cs = ColorSpace.parse(this.dict.get('ColorSpace', 'CS'), xref, res); michael@0: var numComps = cs.numComps; michael@0: return numComps == 1 || numComps == 3; michael@0: }; michael@0: michael@0: return JpegStream; michael@0: })(); michael@0: michael@0: /** michael@0: * For JPEG 2000's we use a library to decode these images and michael@0: * the stream behaves like all the other DecodeStreams. michael@0: */ michael@0: var JpxStream = (function JpxStreamClosure() { michael@0: function JpxStream(stream, maybeLength, dict) { michael@0: this.stream = stream; michael@0: this.maybeLength = maybeLength; michael@0: this.dict = dict; michael@0: michael@0: DecodeStream.call(this, maybeLength); michael@0: } michael@0: michael@0: JpxStream.prototype = Object.create(DecodeStream.prototype); michael@0: michael@0: Object.defineProperty(JpxStream.prototype, 'bytes', { michael@0: get: function JpxStream_bytes() { michael@0: // If this.maybeLength is null, we'll get the entire stream. michael@0: return shadow(this, 'bytes', this.stream.getBytes(this.maybeLength)); michael@0: }, michael@0: configurable: true michael@0: }); michael@0: michael@0: JpxStream.prototype.ensureBuffer = function JpxStream_ensureBuffer(req) { michael@0: if (this.bufferLength) { michael@0: return; michael@0: } michael@0: michael@0: var jpxImage = new JpxImage(); michael@0: jpxImage.parse(this.bytes); michael@0: michael@0: var width = jpxImage.width; michael@0: var height = jpxImage.height; michael@0: var componentsCount = jpxImage.componentsCount; michael@0: var tileCount = jpxImage.tiles.length; michael@0: if (tileCount === 1) { michael@0: this.buffer = jpxImage.tiles[0].items; michael@0: } else { michael@0: var data = new Uint8Array(width * height * componentsCount); michael@0: michael@0: for (var k = 0; k < tileCount; k++) { michael@0: var tileComponents = jpxImage.tiles[k]; michael@0: var tileWidth = tileComponents.width; michael@0: var tileHeight = tileComponents.height; michael@0: var tileLeft = tileComponents.left; michael@0: var tileTop = tileComponents.top; michael@0: michael@0: var src = tileComponents.items; michael@0: var srcPosition = 0; michael@0: var dataPosition = (width * tileTop + tileLeft) * componentsCount; michael@0: var imgRowSize = width * componentsCount; michael@0: var tileRowSize = tileWidth * componentsCount; michael@0: michael@0: for (var j = 0; j < tileHeight; j++) { michael@0: var rowBytes = src.subarray(srcPosition, srcPosition + tileRowSize); michael@0: data.set(rowBytes, dataPosition); michael@0: srcPosition += tileRowSize; michael@0: dataPosition += imgRowSize; michael@0: } michael@0: } michael@0: this.buffer = data; michael@0: } michael@0: this.bufferLength = this.buffer.length; michael@0: this.eof = true; michael@0: }; michael@0: michael@0: return JpxStream; michael@0: })(); michael@0: michael@0: /** michael@0: * For JBIG2's we use a library to decode these images and michael@0: * the stream behaves like all the other DecodeStreams. michael@0: */ michael@0: var Jbig2Stream = (function Jbig2StreamClosure() { michael@0: function Jbig2Stream(stream, maybeLength, dict) { michael@0: this.stream = stream; michael@0: this.maybeLength = maybeLength; michael@0: this.dict = dict; michael@0: michael@0: DecodeStream.call(this, maybeLength); michael@0: } michael@0: michael@0: Jbig2Stream.prototype = Object.create(DecodeStream.prototype); michael@0: michael@0: Object.defineProperty(Jbig2Stream.prototype, 'bytes', { michael@0: get: function Jbig2Stream_bytes() { michael@0: // If this.maybeLength is null, we'll get the entire stream. michael@0: return shadow(this, 'bytes', this.stream.getBytes(this.maybeLength)); michael@0: }, michael@0: configurable: true michael@0: }); michael@0: michael@0: Jbig2Stream.prototype.ensureBuffer = function Jbig2Stream_ensureBuffer(req) { michael@0: if (this.bufferLength) { michael@0: return; michael@0: } michael@0: michael@0: var jbig2Image = new Jbig2Image(); michael@0: michael@0: var chunks = [], decodeParams = this.dict.get('DecodeParms'); michael@0: michael@0: // According to the PDF specification, DecodeParms can be either michael@0: // a dictionary, or an array whose elements are dictionaries. michael@0: if (isArray(decodeParams)) { michael@0: if (decodeParams.length > 1) { michael@0: warn('JBIG2 - \'DecodeParms\' array with multiple elements ' + michael@0: 'not supported.'); michael@0: } michael@0: decodeParams = decodeParams[0]; michael@0: } michael@0: if (decodeParams && decodeParams.has('JBIG2Globals')) { michael@0: var globalsStream = decodeParams.get('JBIG2Globals'); michael@0: var globals = globalsStream.getBytes(); michael@0: chunks.push({data: globals, start: 0, end: globals.length}); michael@0: } michael@0: chunks.push({data: this.bytes, start: 0, end: this.bytes.length}); michael@0: var data = jbig2Image.parseChunks(chunks); michael@0: var dataLength = data.length; michael@0: michael@0: // JBIG2 had black as 1 and white as 0, inverting the colors michael@0: for (var i = 0; i < dataLength; i++) { michael@0: data[i] ^= 0xFF; michael@0: } michael@0: michael@0: this.buffer = data; michael@0: this.bufferLength = dataLength; michael@0: this.eof = true; michael@0: }; michael@0: michael@0: return Jbig2Stream; michael@0: })(); michael@0: michael@0: var DecryptStream = (function DecryptStreamClosure() { michael@0: function DecryptStream(str, maybeLength, decrypt) { michael@0: this.str = str; michael@0: this.dict = str.dict; michael@0: this.decrypt = decrypt; michael@0: this.nextChunk = null; michael@0: this.initialized = false; michael@0: michael@0: DecodeStream.call(this, maybeLength); michael@0: } michael@0: michael@0: var chunkSize = 512; michael@0: michael@0: DecryptStream.prototype = Object.create(DecodeStream.prototype); michael@0: michael@0: DecryptStream.prototype.readBlock = function DecryptStream_readBlock() { michael@0: var chunk; michael@0: if (this.initialized) { michael@0: chunk = this.nextChunk; michael@0: } else { michael@0: chunk = this.str.getBytes(chunkSize); michael@0: this.initialized = true; michael@0: } michael@0: if (!chunk || chunk.length === 0) { michael@0: this.eof = true; michael@0: return; michael@0: } michael@0: this.nextChunk = this.str.getBytes(chunkSize); michael@0: var hasMoreData = this.nextChunk && this.nextChunk.length > 0; michael@0: michael@0: var decrypt = this.decrypt; michael@0: chunk = decrypt(chunk, !hasMoreData); michael@0: michael@0: var bufferLength = this.bufferLength; michael@0: var i, n = chunk.length; michael@0: var buffer = this.ensureBuffer(bufferLength + n); michael@0: for (i = 0; i < n; i++) { michael@0: buffer[bufferLength++] = chunk[i]; michael@0: } michael@0: this.bufferLength = bufferLength; michael@0: }; michael@0: michael@0: return DecryptStream; michael@0: })(); michael@0: michael@0: var Ascii85Stream = (function Ascii85StreamClosure() { michael@0: function Ascii85Stream(str, maybeLength) { michael@0: this.str = str; michael@0: this.dict = str.dict; michael@0: this.input = new Uint8Array(5); michael@0: michael@0: // Most streams increase in size when decoded, but Ascii85 streams michael@0: // typically shrink by ~20%. michael@0: if (maybeLength) { michael@0: maybeLength = 0.8 * maybeLength; michael@0: } michael@0: DecodeStream.call(this, maybeLength); michael@0: } michael@0: michael@0: Ascii85Stream.prototype = Object.create(DecodeStream.prototype); michael@0: michael@0: Ascii85Stream.prototype.readBlock = function Ascii85Stream_readBlock() { michael@0: var TILDA_CHAR = 0x7E; // '~' michael@0: var Z_LOWER_CHAR = 0x7A; // 'z' michael@0: var EOF = -1; michael@0: michael@0: var str = this.str; michael@0: michael@0: var c = str.getByte(); michael@0: while (Lexer.isSpace(c)) { michael@0: c = str.getByte(); michael@0: } michael@0: michael@0: if (c === EOF || c === TILDA_CHAR) { michael@0: this.eof = true; michael@0: return; michael@0: } michael@0: michael@0: var bufferLength = this.bufferLength, buffer; michael@0: var i; michael@0: michael@0: // special code for z michael@0: if (c == Z_LOWER_CHAR) { michael@0: buffer = this.ensureBuffer(bufferLength + 4); michael@0: for (i = 0; i < 4; ++i) { michael@0: buffer[bufferLength + i] = 0; michael@0: } michael@0: this.bufferLength += 4; michael@0: } else { michael@0: var input = this.input; michael@0: input[0] = c; michael@0: for (i = 1; i < 5; ++i) { michael@0: c = str.getByte(); michael@0: while (Lexer.isSpace(c)) { michael@0: c = str.getByte(); michael@0: } michael@0: michael@0: input[i] = c; michael@0: michael@0: if (c === EOF || c == TILDA_CHAR) { michael@0: break; michael@0: } michael@0: } michael@0: buffer = this.ensureBuffer(bufferLength + i - 1); michael@0: this.bufferLength += i - 1; michael@0: michael@0: // partial ending; michael@0: if (i < 5) { michael@0: for (; i < 5; ++i) { michael@0: input[i] = 0x21 + 84; michael@0: } michael@0: this.eof = true; michael@0: } michael@0: var t = 0; michael@0: for (i = 0; i < 5; ++i) { michael@0: t = t * 85 + (input[i] - 0x21); michael@0: } michael@0: michael@0: for (i = 3; i >= 0; --i) { michael@0: buffer[bufferLength + i] = t & 0xFF; michael@0: t >>= 8; michael@0: } michael@0: } michael@0: }; michael@0: michael@0: return Ascii85Stream; michael@0: })(); michael@0: michael@0: var AsciiHexStream = (function AsciiHexStreamClosure() { michael@0: function AsciiHexStream(str, maybeLength) { michael@0: this.str = str; michael@0: this.dict = str.dict; michael@0: michael@0: this.firstDigit = -1; michael@0: michael@0: // Most streams increase in size when decoded, but AsciiHex streams shrink michael@0: // by 50%. michael@0: if (maybeLength) { michael@0: maybeLength = 0.5 * maybeLength; michael@0: } michael@0: DecodeStream.call(this, maybeLength); michael@0: } michael@0: michael@0: AsciiHexStream.prototype = Object.create(DecodeStream.prototype); michael@0: michael@0: AsciiHexStream.prototype.readBlock = function AsciiHexStream_readBlock() { michael@0: var UPSTREAM_BLOCK_SIZE = 8000; michael@0: var bytes = this.str.getBytes(UPSTREAM_BLOCK_SIZE); michael@0: if (!bytes.length) { michael@0: this.eof = true; michael@0: return; michael@0: } michael@0: michael@0: var maxDecodeLength = (bytes.length + 1) >> 1; michael@0: var buffer = this.ensureBuffer(this.bufferLength + maxDecodeLength); michael@0: var bufferLength = this.bufferLength; michael@0: michael@0: var firstDigit = this.firstDigit; michael@0: for (var i = 0, ii = bytes.length; i < ii; i++) { michael@0: var ch = bytes[i], digit; michael@0: if (ch >= 0x30 && ch <= 0x39) { // '0'-'9' michael@0: digit = ch & 0x0F; michael@0: } else if ((ch >= 0x41 && ch <= 0x46) || (ch >= 0x61 && ch <= 0x66)) { michael@0: // 'A'-'Z', 'a'-'z' michael@0: digit = (ch & 0x0F) + 9; michael@0: } else if (ch === 0x3E) { // '>' michael@0: this.eof = true; michael@0: break; michael@0: } else { // probably whitespace michael@0: continue; // ignoring michael@0: } michael@0: if (firstDigit < 0) { michael@0: firstDigit = digit; michael@0: } else { michael@0: buffer[bufferLength++] = (firstDigit << 4) | digit; michael@0: firstDigit = -1; michael@0: } michael@0: } michael@0: if (firstDigit >= 0 && this.eof) { michael@0: // incomplete byte michael@0: buffer[bufferLength++] = (firstDigit << 4); michael@0: firstDigit = -1; michael@0: } michael@0: this.firstDigit = firstDigit; michael@0: this.bufferLength = bufferLength; michael@0: }; michael@0: michael@0: return AsciiHexStream; michael@0: })(); michael@0: michael@0: var RunLengthStream = (function RunLengthStreamClosure() { michael@0: function RunLengthStream(str, maybeLength) { michael@0: this.str = str; michael@0: this.dict = str.dict; michael@0: michael@0: DecodeStream.call(this, maybeLength); michael@0: } michael@0: michael@0: RunLengthStream.prototype = Object.create(DecodeStream.prototype); michael@0: michael@0: RunLengthStream.prototype.readBlock = function RunLengthStream_readBlock() { michael@0: // The repeatHeader has following format. The first byte defines type of run michael@0: // and amount of bytes to repeat/copy: n = 0 through 127 - copy next n bytes michael@0: // (in addition to the second byte from the header), n = 129 through 255 - michael@0: // duplicate the second byte from the header (257 - n) times, n = 128 - end. michael@0: var repeatHeader = this.str.getBytes(2); michael@0: if (!repeatHeader || repeatHeader.length < 2 || repeatHeader[0] == 128) { michael@0: this.eof = true; michael@0: return; michael@0: } michael@0: michael@0: var buffer; michael@0: var bufferLength = this.bufferLength; michael@0: var n = repeatHeader[0]; michael@0: if (n < 128) { michael@0: // copy n bytes michael@0: buffer = this.ensureBuffer(bufferLength + n + 1); michael@0: buffer[bufferLength++] = repeatHeader[1]; michael@0: if (n > 0) { michael@0: var source = this.str.getBytes(n); michael@0: buffer.set(source, bufferLength); michael@0: bufferLength += n; michael@0: } michael@0: } else { michael@0: n = 257 - n; michael@0: var b = repeatHeader[1]; michael@0: buffer = this.ensureBuffer(bufferLength + n + 1); michael@0: for (var i = 0; i < n; i++) { michael@0: buffer[bufferLength++] = b; michael@0: } michael@0: } michael@0: this.bufferLength = bufferLength; michael@0: }; michael@0: michael@0: return RunLengthStream; michael@0: })(); michael@0: michael@0: var CCITTFaxStream = (function CCITTFaxStreamClosure() { michael@0: michael@0: var ccittEOL = -2; michael@0: var twoDimPass = 0; michael@0: var twoDimHoriz = 1; michael@0: var twoDimVert0 = 2; michael@0: var twoDimVertR1 = 3; michael@0: var twoDimVertL1 = 4; michael@0: var twoDimVertR2 = 5; michael@0: var twoDimVertL2 = 6; michael@0: var twoDimVertR3 = 7; michael@0: var twoDimVertL3 = 8; michael@0: michael@0: var twoDimTable = [ michael@0: [-1, -1], [-1, -1], // 000000x michael@0: [7, twoDimVertL3], // 0000010 michael@0: [7, twoDimVertR3], // 0000011 michael@0: [6, twoDimVertL2], [6, twoDimVertL2], // 000010x michael@0: [6, twoDimVertR2], [6, twoDimVertR2], // 000011x michael@0: [4, twoDimPass], [4, twoDimPass], // 0001xxx michael@0: [4, twoDimPass], [4, twoDimPass], michael@0: [4, twoDimPass], [4, twoDimPass], michael@0: [4, twoDimPass], [4, twoDimPass], michael@0: [3, twoDimHoriz], [3, twoDimHoriz], // 001xxxx michael@0: [3, twoDimHoriz], [3, twoDimHoriz], michael@0: [3, twoDimHoriz], [3, twoDimHoriz], michael@0: [3, twoDimHoriz], [3, twoDimHoriz], michael@0: [3, twoDimHoriz], [3, twoDimHoriz], michael@0: [3, twoDimHoriz], [3, twoDimHoriz], michael@0: [3, twoDimHoriz], [3, twoDimHoriz], michael@0: [3, twoDimHoriz], [3, twoDimHoriz], michael@0: [3, twoDimVertL1], [3, twoDimVertL1], // 010xxxx michael@0: [3, twoDimVertL1], [3, twoDimVertL1], michael@0: [3, twoDimVertL1], [3, twoDimVertL1], michael@0: [3, twoDimVertL1], [3, twoDimVertL1], michael@0: [3, twoDimVertL1], [3, twoDimVertL1], michael@0: [3, twoDimVertL1], [3, twoDimVertL1], michael@0: [3, twoDimVertL1], [3, twoDimVertL1], michael@0: [3, twoDimVertL1], [3, twoDimVertL1], michael@0: [3, twoDimVertR1], [3, twoDimVertR1], // 011xxxx michael@0: [3, twoDimVertR1], [3, twoDimVertR1], michael@0: [3, twoDimVertR1], [3, twoDimVertR1], michael@0: [3, twoDimVertR1], [3, twoDimVertR1], michael@0: [3, twoDimVertR1], [3, twoDimVertR1], michael@0: [3, twoDimVertR1], [3, twoDimVertR1], michael@0: [3, twoDimVertR1], [3, twoDimVertR1], michael@0: [3, twoDimVertR1], [3, twoDimVertR1], michael@0: [1, twoDimVert0], [1, twoDimVert0], // 1xxxxxx michael@0: [1, twoDimVert0], [1, twoDimVert0], michael@0: [1, twoDimVert0], [1, twoDimVert0], michael@0: [1, twoDimVert0], [1, twoDimVert0], michael@0: [1, twoDimVert0], [1, twoDimVert0], michael@0: [1, twoDimVert0], [1, twoDimVert0], michael@0: [1, twoDimVert0], [1, twoDimVert0], michael@0: [1, twoDimVert0], [1, twoDimVert0], michael@0: [1, twoDimVert0], [1, twoDimVert0], michael@0: [1, twoDimVert0], [1, twoDimVert0], michael@0: [1, twoDimVert0], [1, twoDimVert0], michael@0: [1, twoDimVert0], [1, twoDimVert0], michael@0: [1, twoDimVert0], [1, twoDimVert0], michael@0: [1, twoDimVert0], [1, twoDimVert0], michael@0: [1, twoDimVert0], [1, twoDimVert0], michael@0: [1, twoDimVert0], [1, twoDimVert0], michael@0: [1, twoDimVert0], [1, twoDimVert0], michael@0: [1, twoDimVert0], [1, twoDimVert0], michael@0: [1, twoDimVert0], [1, twoDimVert0], michael@0: [1, twoDimVert0], [1, twoDimVert0], michael@0: [1, twoDimVert0], [1, twoDimVert0], michael@0: [1, twoDimVert0], [1, twoDimVert0], michael@0: [1, twoDimVert0], [1, twoDimVert0], michael@0: [1, twoDimVert0], [1, twoDimVert0], michael@0: [1, twoDimVert0], [1, twoDimVert0], michael@0: [1, twoDimVert0], [1, twoDimVert0], michael@0: [1, twoDimVert0], [1, twoDimVert0], michael@0: [1, twoDimVert0], [1, twoDimVert0], michael@0: [1, twoDimVert0], [1, twoDimVert0], michael@0: [1, twoDimVert0], [1, twoDimVert0], michael@0: [1, twoDimVert0], [1, twoDimVert0], michael@0: [1, twoDimVert0], [1, twoDimVert0] michael@0: ]; michael@0: michael@0: var whiteTable1 = [ michael@0: [-1, -1], // 00000 michael@0: [12, ccittEOL], // 00001 michael@0: [-1, -1], [-1, -1], // 0001x michael@0: [-1, -1], [-1, -1], [-1, -1], [-1, -1], // 001xx michael@0: [-1, -1], [-1, -1], [-1, -1], [-1, -1], // 010xx michael@0: [-1, -1], [-1, -1], [-1, -1], [-1, -1], // 011xx michael@0: [11, 1792], [11, 1792], // 1000x michael@0: [12, 1984], // 10010 michael@0: [12, 2048], // 10011 michael@0: [12, 2112], // 10100 michael@0: [12, 2176], // 10101 michael@0: [12, 2240], // 10110 michael@0: [12, 2304], // 10111 michael@0: [11, 1856], [11, 1856], // 1100x michael@0: [11, 1920], [11, 1920], // 1101x michael@0: [12, 2368], // 11100 michael@0: [12, 2432], // 11101 michael@0: [12, 2496], // 11110 michael@0: [12, 2560] // 11111 michael@0: ]; michael@0: michael@0: var whiteTable2 = [ michael@0: [-1, -1], [-1, -1], [-1, -1], [-1, -1], // 0000000xx michael@0: [8, 29], [8, 29], // 00000010x michael@0: [8, 30], [8, 30], // 00000011x michael@0: [8, 45], [8, 45], // 00000100x michael@0: [8, 46], [8, 46], // 00000101x michael@0: [7, 22], [7, 22], [7, 22], [7, 22], // 0000011xx michael@0: [7, 23], [7, 23], [7, 23], [7, 23], // 0000100xx michael@0: [8, 47], [8, 47], // 00001010x michael@0: [8, 48], [8, 48], // 00001011x michael@0: [6, 13], [6, 13], [6, 13], [6, 13], // 000011xxx michael@0: [6, 13], [6, 13], [6, 13], [6, 13], michael@0: [7, 20], [7, 20], [7, 20], [7, 20], // 0001000xx michael@0: [8, 33], [8, 33], // 00010010x michael@0: [8, 34], [8, 34], // 00010011x michael@0: [8, 35], [8, 35], // 00010100x michael@0: [8, 36], [8, 36], // 00010101x michael@0: [8, 37], [8, 37], // 00010110x michael@0: [8, 38], [8, 38], // 00010111x michael@0: [7, 19], [7, 19], [7, 19], [7, 19], // 0001100xx michael@0: [8, 31], [8, 31], // 00011010x michael@0: [8, 32], [8, 32], // 00011011x michael@0: [6, 1], [6, 1], [6, 1], [6, 1], // 000111xxx michael@0: [6, 1], [6, 1], [6, 1], [6, 1], michael@0: [6, 12], [6, 12], [6, 12], [6, 12], // 001000xxx michael@0: [6, 12], [6, 12], [6, 12], [6, 12], michael@0: [8, 53], [8, 53], // 00100100x michael@0: [8, 54], [8, 54], // 00100101x michael@0: [7, 26], [7, 26], [7, 26], [7, 26], // 0010011xx michael@0: [8, 39], [8, 39], // 00101000x michael@0: [8, 40], [8, 40], // 00101001x michael@0: [8, 41], [8, 41], // 00101010x michael@0: [8, 42], [8, 42], // 00101011x michael@0: [8, 43], [8, 43], // 00101100x michael@0: [8, 44], [8, 44], // 00101101x michael@0: [7, 21], [7, 21], [7, 21], [7, 21], // 0010111xx michael@0: [7, 28], [7, 28], [7, 28], [7, 28], // 0011000xx michael@0: [8, 61], [8, 61], // 00110010x michael@0: [8, 62], [8, 62], // 00110011x michael@0: [8, 63], [8, 63], // 00110100x michael@0: [8, 0], [8, 0], // 00110101x michael@0: [8, 320], [8, 320], // 00110110x michael@0: [8, 384], [8, 384], // 00110111x michael@0: [5, 10], [5, 10], [5, 10], [5, 10], // 00111xxxx michael@0: [5, 10], [5, 10], [5, 10], [5, 10], michael@0: [5, 10], [5, 10], [5, 10], [5, 10], michael@0: [5, 10], [5, 10], [5, 10], [5, 10], michael@0: [5, 11], [5, 11], [5, 11], [5, 11], // 01000xxxx michael@0: [5, 11], [5, 11], [5, 11], [5, 11], michael@0: [5, 11], [5, 11], [5, 11], [5, 11], michael@0: [5, 11], [5, 11], [5, 11], [5, 11], michael@0: [7, 27], [7, 27], [7, 27], [7, 27], // 0100100xx michael@0: [8, 59], [8, 59], // 01001010x michael@0: [8, 60], [8, 60], // 01001011x michael@0: [9, 1472], // 010011000 michael@0: [9, 1536], // 010011001 michael@0: [9, 1600], // 010011010 michael@0: [9, 1728], // 010011011 michael@0: [7, 18], [7, 18], [7, 18], [7, 18], // 0100111xx michael@0: [7, 24], [7, 24], [7, 24], [7, 24], // 0101000xx michael@0: [8, 49], [8, 49], // 01010010x michael@0: [8, 50], [8, 50], // 01010011x michael@0: [8, 51], [8, 51], // 01010100x michael@0: [8, 52], [8, 52], // 01010101x michael@0: [7, 25], [7, 25], [7, 25], [7, 25], // 0101011xx michael@0: [8, 55], [8, 55], // 01011000x michael@0: [8, 56], [8, 56], // 01011001x michael@0: [8, 57], [8, 57], // 01011010x michael@0: [8, 58], [8, 58], // 01011011x michael@0: [6, 192], [6, 192], [6, 192], [6, 192], // 010111xxx michael@0: [6, 192], [6, 192], [6, 192], [6, 192], michael@0: [6, 1664], [6, 1664], [6, 1664], [6, 1664], // 011000xxx michael@0: [6, 1664], [6, 1664], [6, 1664], [6, 1664], michael@0: [8, 448], [8, 448], // 01100100x michael@0: [8, 512], [8, 512], // 01100101x michael@0: [9, 704], // 011001100 michael@0: [9, 768], // 011001101 michael@0: [8, 640], [8, 640], // 01100111x michael@0: [8, 576], [8, 576], // 01101000x michael@0: [9, 832], // 011010010 michael@0: [9, 896], // 011010011 michael@0: [9, 960], // 011010100 michael@0: [9, 1024], // 011010101 michael@0: [9, 1088], // 011010110 michael@0: [9, 1152], // 011010111 michael@0: [9, 1216], // 011011000 michael@0: [9, 1280], // 011011001 michael@0: [9, 1344], // 011011010 michael@0: [9, 1408], // 011011011 michael@0: [7, 256], [7, 256], [7, 256], [7, 256], // 0110111xx michael@0: [4, 2], [4, 2], [4, 2], [4, 2], // 0111xxxxx michael@0: [4, 2], [4, 2], [4, 2], [4, 2], michael@0: [4, 2], [4, 2], [4, 2], [4, 2], michael@0: [4, 2], [4, 2], [4, 2], [4, 2], michael@0: [4, 2], [4, 2], [4, 2], [4, 2], michael@0: [4, 2], [4, 2], [4, 2], [4, 2], michael@0: [4, 2], [4, 2], [4, 2], [4, 2], michael@0: [4, 2], [4, 2], [4, 2], [4, 2], michael@0: [4, 3], [4, 3], [4, 3], [4, 3], // 1000xxxxx michael@0: [4, 3], [4, 3], [4, 3], [4, 3], michael@0: [4, 3], [4, 3], [4, 3], [4, 3], michael@0: [4, 3], [4, 3], [4, 3], [4, 3], michael@0: [4, 3], [4, 3], [4, 3], [4, 3], michael@0: [4, 3], [4, 3], [4, 3], [4, 3], michael@0: [4, 3], [4, 3], [4, 3], [4, 3], michael@0: [4, 3], [4, 3], [4, 3], [4, 3], michael@0: [5, 128], [5, 128], [5, 128], [5, 128], // 10010xxxx michael@0: [5, 128], [5, 128], [5, 128], [5, 128], michael@0: [5, 128], [5, 128], [5, 128], [5, 128], michael@0: [5, 128], [5, 128], [5, 128], [5, 128], michael@0: [5, 8], [5, 8], [5, 8], [5, 8], // 10011xxxx michael@0: [5, 8], [5, 8], [5, 8], [5, 8], michael@0: [5, 8], [5, 8], [5, 8], [5, 8], michael@0: [5, 8], [5, 8], [5, 8], [5, 8], michael@0: [5, 9], [5, 9], [5, 9], [5, 9], // 10100xxxx michael@0: [5, 9], [5, 9], [5, 9], [5, 9], michael@0: [5, 9], [5, 9], [5, 9], [5, 9], michael@0: [5, 9], [5, 9], [5, 9], [5, 9], michael@0: [6, 16], [6, 16], [6, 16], [6, 16], // 101010xxx michael@0: [6, 16], [6, 16], [6, 16], [6, 16], michael@0: [6, 17], [6, 17], [6, 17], [6, 17], // 101011xxx michael@0: [6, 17], [6, 17], [6, 17], [6, 17], michael@0: [4, 4], [4, 4], [4, 4], [4, 4], // 1011xxxxx michael@0: [4, 4], [4, 4], [4, 4], [4, 4], michael@0: [4, 4], [4, 4], [4, 4], [4, 4], michael@0: [4, 4], [4, 4], [4, 4], [4, 4], michael@0: [4, 4], [4, 4], [4, 4], [4, 4], michael@0: [4, 4], [4, 4], [4, 4], [4, 4], michael@0: [4, 4], [4, 4], [4, 4], [4, 4], michael@0: [4, 4], [4, 4], [4, 4], [4, 4], michael@0: [4, 5], [4, 5], [4, 5], [4, 5], // 1100xxxxx michael@0: [4, 5], [4, 5], [4, 5], [4, 5], michael@0: [4, 5], [4, 5], [4, 5], [4, 5], michael@0: [4, 5], [4, 5], [4, 5], [4, 5], michael@0: [4, 5], [4, 5], [4, 5], [4, 5], michael@0: [4, 5], [4, 5], [4, 5], [4, 5], michael@0: [4, 5], [4, 5], [4, 5], [4, 5], michael@0: [4, 5], [4, 5], [4, 5], [4, 5], michael@0: [6, 14], [6, 14], [6, 14], [6, 14], // 110100xxx michael@0: [6, 14], [6, 14], [6, 14], [6, 14], michael@0: [6, 15], [6, 15], [6, 15], [6, 15], // 110101xxx michael@0: [6, 15], [6, 15], [6, 15], [6, 15], michael@0: [5, 64], [5, 64], [5, 64], [5, 64], // 11011xxxx michael@0: [5, 64], [5, 64], [5, 64], [5, 64], michael@0: [5, 64], [5, 64], [5, 64], [5, 64], michael@0: [5, 64], [5, 64], [5, 64], [5, 64], michael@0: [4, 6], [4, 6], [4, 6], [4, 6], // 1110xxxxx michael@0: [4, 6], [4, 6], [4, 6], [4, 6], michael@0: [4, 6], [4, 6], [4, 6], [4, 6], michael@0: [4, 6], [4, 6], [4, 6], [4, 6], michael@0: [4, 6], [4, 6], [4, 6], [4, 6], michael@0: [4, 6], [4, 6], [4, 6], [4, 6], michael@0: [4, 6], [4, 6], [4, 6], [4, 6], michael@0: [4, 6], [4, 6], [4, 6], [4, 6], michael@0: [4, 7], [4, 7], [4, 7], [4, 7], // 1111xxxxx michael@0: [4, 7], [4, 7], [4, 7], [4, 7], michael@0: [4, 7], [4, 7], [4, 7], [4, 7], michael@0: [4, 7], [4, 7], [4, 7], [4, 7], michael@0: [4, 7], [4, 7], [4, 7], [4, 7], michael@0: [4, 7], [4, 7], [4, 7], [4, 7], michael@0: [4, 7], [4, 7], [4, 7], [4, 7], michael@0: [4, 7], [4, 7], [4, 7], [4, 7] michael@0: ]; michael@0: michael@0: var blackTable1 = [ michael@0: [-1, -1], [-1, -1], // 000000000000x michael@0: [12, ccittEOL], [12, ccittEOL], // 000000000001x michael@0: [-1, -1], [-1, -1], [-1, -1], [-1, -1], // 00000000001xx michael@0: [-1, -1], [-1, -1], [-1, -1], [-1, -1], // 00000000010xx michael@0: [-1, -1], [-1, -1], [-1, -1], [-1, -1], // 00000000011xx michael@0: [-1, -1], [-1, -1], [-1, -1], [-1, -1], // 00000000100xx michael@0: [-1, -1], [-1, -1], [-1, -1], [-1, -1], // 00000000101xx michael@0: [-1, -1], [-1, -1], [-1, -1], [-1, -1], // 00000000110xx michael@0: [-1, -1], [-1, -1], [-1, -1], [-1, -1], // 00000000111xx michael@0: [11, 1792], [11, 1792], [11, 1792], [11, 1792], // 00000001000xx michael@0: [12, 1984], [12, 1984], // 000000010010x michael@0: [12, 2048], [12, 2048], // 000000010011x michael@0: [12, 2112], [12, 2112], // 000000010100x michael@0: [12, 2176], [12, 2176], // 000000010101x michael@0: [12, 2240], [12, 2240], // 000000010110x michael@0: [12, 2304], [12, 2304], // 000000010111x michael@0: [11, 1856], [11, 1856], [11, 1856], [11, 1856], // 00000001100xx michael@0: [11, 1920], [11, 1920], [11, 1920], [11, 1920], // 00000001101xx michael@0: [12, 2368], [12, 2368], // 000000011100x michael@0: [12, 2432], [12, 2432], // 000000011101x michael@0: [12, 2496], [12, 2496], // 000000011110x michael@0: [12, 2560], [12, 2560], // 000000011111x michael@0: [10, 18], [10, 18], [10, 18], [10, 18], // 0000001000xxx michael@0: [10, 18], [10, 18], [10, 18], [10, 18], michael@0: [12, 52], [12, 52], // 000000100100x michael@0: [13, 640], // 0000001001010 michael@0: [13, 704], // 0000001001011 michael@0: [13, 768], // 0000001001100 michael@0: [13, 832], // 0000001001101 michael@0: [12, 55], [12, 55], // 000000100111x michael@0: [12, 56], [12, 56], // 000000101000x michael@0: [13, 1280], // 0000001010010 michael@0: [13, 1344], // 0000001010011 michael@0: [13, 1408], // 0000001010100 michael@0: [13, 1472], // 0000001010101 michael@0: [12, 59], [12, 59], // 000000101011x michael@0: [12, 60], [12, 60], // 000000101100x michael@0: [13, 1536], // 0000001011010 michael@0: [13, 1600], // 0000001011011 michael@0: [11, 24], [11, 24], [11, 24], [11, 24], // 00000010111xx michael@0: [11, 25], [11, 25], [11, 25], [11, 25], // 00000011000xx michael@0: [13, 1664], // 0000001100100 michael@0: [13, 1728], // 0000001100101 michael@0: [12, 320], [12, 320], // 000000110011x michael@0: [12, 384], [12, 384], // 000000110100x michael@0: [12, 448], [12, 448], // 000000110101x michael@0: [13, 512], // 0000001101100 michael@0: [13, 576], // 0000001101101 michael@0: [12, 53], [12, 53], // 000000110111x michael@0: [12, 54], [12, 54], // 000000111000x michael@0: [13, 896], // 0000001110010 michael@0: [13, 960], // 0000001110011 michael@0: [13, 1024], // 0000001110100 michael@0: [13, 1088], // 0000001110101 michael@0: [13, 1152], // 0000001110110 michael@0: [13, 1216], // 0000001110111 michael@0: [10, 64], [10, 64], [10, 64], [10, 64], // 0000001111xxx michael@0: [10, 64], [10, 64], [10, 64], [10, 64] michael@0: ]; michael@0: michael@0: var blackTable2 = [ michael@0: [8, 13], [8, 13], [8, 13], [8, 13], // 00000100xxxx michael@0: [8, 13], [8, 13], [8, 13], [8, 13], michael@0: [8, 13], [8, 13], [8, 13], [8, 13], michael@0: [8, 13], [8, 13], [8, 13], [8, 13], michael@0: [11, 23], [11, 23], // 00000101000x michael@0: [12, 50], // 000001010010 michael@0: [12, 51], // 000001010011 michael@0: [12, 44], // 000001010100 michael@0: [12, 45], // 000001010101 michael@0: [12, 46], // 000001010110 michael@0: [12, 47], // 000001010111 michael@0: [12, 57], // 000001011000 michael@0: [12, 58], // 000001011001 michael@0: [12, 61], // 000001011010 michael@0: [12, 256], // 000001011011 michael@0: [10, 16], [10, 16], [10, 16], [10, 16], // 0000010111xx michael@0: [10, 17], [10, 17], [10, 17], [10, 17], // 0000011000xx michael@0: [12, 48], // 000001100100 michael@0: [12, 49], // 000001100101 michael@0: [12, 62], // 000001100110 michael@0: [12, 63], // 000001100111 michael@0: [12, 30], // 000001101000 michael@0: [12, 31], // 000001101001 michael@0: [12, 32], // 000001101010 michael@0: [12, 33], // 000001101011 michael@0: [12, 40], // 000001101100 michael@0: [12, 41], // 000001101101 michael@0: [11, 22], [11, 22], // 00000110111x michael@0: [8, 14], [8, 14], [8, 14], [8, 14], // 00000111xxxx michael@0: [8, 14], [8, 14], [8, 14], [8, 14], michael@0: [8, 14], [8, 14], [8, 14], [8, 14], michael@0: [8, 14], [8, 14], [8, 14], [8, 14], michael@0: [7, 10], [7, 10], [7, 10], [7, 10], // 0000100xxxxx michael@0: [7, 10], [7, 10], [7, 10], [7, 10], michael@0: [7, 10], [7, 10], [7, 10], [7, 10], michael@0: [7, 10], [7, 10], [7, 10], [7, 10], michael@0: [7, 10], [7, 10], [7, 10], [7, 10], michael@0: [7, 10], [7, 10], [7, 10], [7, 10], michael@0: [7, 10], [7, 10], [7, 10], [7, 10], michael@0: [7, 10], [7, 10], [7, 10], [7, 10], michael@0: [7, 11], [7, 11], [7, 11], [7, 11], // 0000101xxxxx michael@0: [7, 11], [7, 11], [7, 11], [7, 11], michael@0: [7, 11], [7, 11], [7, 11], [7, 11], michael@0: [7, 11], [7, 11], [7, 11], [7, 11], michael@0: [7, 11], [7, 11], [7, 11], [7, 11], michael@0: [7, 11], [7, 11], [7, 11], [7, 11], michael@0: [7, 11], [7, 11], [7, 11], [7, 11], michael@0: [7, 11], [7, 11], [7, 11], [7, 11], michael@0: [9, 15], [9, 15], [9, 15], [9, 15], // 000011000xxx michael@0: [9, 15], [9, 15], [9, 15], [9, 15], michael@0: [12, 128], // 000011001000 michael@0: [12, 192], // 000011001001 michael@0: [12, 26], // 000011001010 michael@0: [12, 27], // 000011001011 michael@0: [12, 28], // 000011001100 michael@0: [12, 29], // 000011001101 michael@0: [11, 19], [11, 19], // 00001100111x michael@0: [11, 20], [11, 20], // 00001101000x michael@0: [12, 34], // 000011010010 michael@0: [12, 35], // 000011010011 michael@0: [12, 36], // 000011010100 michael@0: [12, 37], // 000011010101 michael@0: [12, 38], // 000011010110 michael@0: [12, 39], // 000011010111 michael@0: [11, 21], [11, 21], // 00001101100x michael@0: [12, 42], // 000011011010 michael@0: [12, 43], // 000011011011 michael@0: [10, 0], [10, 0], [10, 0], [10, 0], // 0000110111xx michael@0: [7, 12], [7, 12], [7, 12], [7, 12], // 0000111xxxxx michael@0: [7, 12], [7, 12], [7, 12], [7, 12], michael@0: [7, 12], [7, 12], [7, 12], [7, 12], michael@0: [7, 12], [7, 12], [7, 12], [7, 12], michael@0: [7, 12], [7, 12], [7, 12], [7, 12], michael@0: [7, 12], [7, 12], [7, 12], [7, 12], michael@0: [7, 12], [7, 12], [7, 12], [7, 12], michael@0: [7, 12], [7, 12], [7, 12], [7, 12] michael@0: ]; michael@0: michael@0: var blackTable3 = [ michael@0: [-1, -1], [-1, -1], [-1, -1], [-1, -1], // 0000xx michael@0: [6, 9], // 000100 michael@0: [6, 8], // 000101 michael@0: [5, 7], [5, 7], // 00011x michael@0: [4, 6], [4, 6], [4, 6], [4, 6], // 0010xx michael@0: [4, 5], [4, 5], [4, 5], [4, 5], // 0011xx michael@0: [3, 1], [3, 1], [3, 1], [3, 1], // 010xxx michael@0: [3, 1], [3, 1], [3, 1], [3, 1], michael@0: [3, 4], [3, 4], [3, 4], [3, 4], // 011xxx michael@0: [3, 4], [3, 4], [3, 4], [3, 4], michael@0: [2, 3], [2, 3], [2, 3], [2, 3], // 10xxxx michael@0: [2, 3], [2, 3], [2, 3], [2, 3], michael@0: [2, 3], [2, 3], [2, 3], [2, 3], michael@0: [2, 3], [2, 3], [2, 3], [2, 3], michael@0: [2, 2], [2, 2], [2, 2], [2, 2], // 11xxxx michael@0: [2, 2], [2, 2], [2, 2], [2, 2], michael@0: [2, 2], [2, 2], [2, 2], [2, 2], michael@0: [2, 2], [2, 2], [2, 2], [2, 2] michael@0: ]; michael@0: michael@0: function CCITTFaxStream(str, maybeLength, params) { michael@0: this.str = str; michael@0: this.dict = str.dict; michael@0: michael@0: params = params || Dict.empty; michael@0: michael@0: this.encoding = params.get('K') || 0; michael@0: this.eoline = params.get('EndOfLine') || false; michael@0: this.byteAlign = params.get('EncodedByteAlign') || false; michael@0: this.columns = params.get('Columns') || 1728; michael@0: this.rows = params.get('Rows') || 0; michael@0: var eoblock = params.get('EndOfBlock'); michael@0: if (eoblock === null || eoblock === undefined) { michael@0: eoblock = true; michael@0: } michael@0: this.eoblock = eoblock; michael@0: this.black = params.get('BlackIs1') || false; michael@0: michael@0: this.codingLine = new Uint32Array(this.columns + 1); michael@0: this.refLine = new Uint32Array(this.columns + 2); michael@0: michael@0: this.codingLine[0] = this.columns; michael@0: this.codingPos = 0; michael@0: michael@0: this.row = 0; michael@0: this.nextLine2D = this.encoding < 0; michael@0: this.inputBits = 0; michael@0: this.inputBuf = 0; michael@0: this.outputBits = 0; michael@0: michael@0: var code1; michael@0: while ((code1 = this.lookBits(12)) === 0) { michael@0: this.eatBits(1); michael@0: } michael@0: if (code1 == 1) { michael@0: this.eatBits(12); michael@0: } michael@0: if (this.encoding > 0) { michael@0: this.nextLine2D = !this.lookBits(1); michael@0: this.eatBits(1); michael@0: } michael@0: michael@0: DecodeStream.call(this, maybeLength); michael@0: } michael@0: michael@0: CCITTFaxStream.prototype = Object.create(DecodeStream.prototype); michael@0: michael@0: CCITTFaxStream.prototype.readBlock = function CCITTFaxStream_readBlock() { michael@0: while (!this.eof) { michael@0: var c = this.lookChar(); michael@0: this.ensureBuffer(this.bufferLength + 1); michael@0: this.buffer[this.bufferLength++] = c; michael@0: } michael@0: }; michael@0: michael@0: CCITTFaxStream.prototype.addPixels = michael@0: function ccittFaxStreamAddPixels(a1, blackPixels) { michael@0: var codingLine = this.codingLine; michael@0: var codingPos = this.codingPos; michael@0: michael@0: if (a1 > codingLine[codingPos]) { michael@0: if (a1 > this.columns) { michael@0: info('row is wrong length'); michael@0: this.err = true; michael@0: a1 = this.columns; michael@0: } michael@0: if ((codingPos & 1) ^ blackPixels) { michael@0: ++codingPos; michael@0: } michael@0: michael@0: codingLine[codingPos] = a1; michael@0: } michael@0: this.codingPos = codingPos; michael@0: }; michael@0: michael@0: CCITTFaxStream.prototype.addPixelsNeg = michael@0: function ccittFaxStreamAddPixelsNeg(a1, blackPixels) { michael@0: var codingLine = this.codingLine; michael@0: var codingPos = this.codingPos; michael@0: michael@0: if (a1 > codingLine[codingPos]) { michael@0: if (a1 > this.columns) { michael@0: info('row is wrong length'); michael@0: this.err = true; michael@0: a1 = this.columns; michael@0: } michael@0: if ((codingPos & 1) ^ blackPixels) { michael@0: ++codingPos; michael@0: } michael@0: michael@0: codingLine[codingPos] = a1; michael@0: } else if (a1 < codingLine[codingPos]) { michael@0: if (a1 < 0) { michael@0: info('invalid code'); michael@0: this.err = true; michael@0: a1 = 0; michael@0: } michael@0: while (codingPos > 0 && a1 < codingLine[codingPos - 1]) { michael@0: --codingPos; michael@0: } michael@0: codingLine[codingPos] = a1; michael@0: } michael@0: michael@0: this.codingPos = codingPos; michael@0: }; michael@0: michael@0: CCITTFaxStream.prototype.lookChar = function CCITTFaxStream_lookChar() { michael@0: var refLine = this.refLine; michael@0: var codingLine = this.codingLine; michael@0: var columns = this.columns; michael@0: michael@0: var refPos, blackPixels, bits, i; michael@0: michael@0: if (this.outputBits === 0) { michael@0: if (this.eof) { michael@0: return null; michael@0: } michael@0: this.err = false; michael@0: michael@0: var code1, code2, code3; michael@0: if (this.nextLine2D) { michael@0: for (i = 0; codingLine[i] < columns; ++i) { michael@0: refLine[i] = codingLine[i]; michael@0: } michael@0: refLine[i++] = columns; michael@0: refLine[i] = columns; michael@0: codingLine[0] = 0; michael@0: this.codingPos = 0; michael@0: refPos = 0; michael@0: blackPixels = 0; michael@0: michael@0: while (codingLine[this.codingPos] < columns) { michael@0: code1 = this.getTwoDimCode(); michael@0: switch (code1) { michael@0: case twoDimPass: michael@0: this.addPixels(refLine[refPos + 1], blackPixels); michael@0: if (refLine[refPos + 1] < columns) { michael@0: refPos += 2; michael@0: } michael@0: break; michael@0: case twoDimHoriz: michael@0: code1 = code2 = 0; michael@0: if (blackPixels) { michael@0: do { michael@0: code1 += (code3 = this.getBlackCode()); michael@0: } while (code3 >= 64); michael@0: do { michael@0: code2 += (code3 = this.getWhiteCode()); michael@0: } while (code3 >= 64); michael@0: } else { michael@0: do { michael@0: code1 += (code3 = this.getWhiteCode()); michael@0: } while (code3 >= 64); michael@0: do { michael@0: code2 += (code3 = this.getBlackCode()); michael@0: } while (code3 >= 64); michael@0: } michael@0: this.addPixels(codingLine[this.codingPos] + michael@0: code1, blackPixels); michael@0: if (codingLine[this.codingPos] < columns) { michael@0: this.addPixels(codingLine[this.codingPos] + code2, michael@0: blackPixels ^ 1); michael@0: } michael@0: while (refLine[refPos] <= codingLine[this.codingPos] && michael@0: refLine[refPos] < columns) { michael@0: refPos += 2; michael@0: } michael@0: break; michael@0: case twoDimVertR3: michael@0: this.addPixels(refLine[refPos] + 3, blackPixels); michael@0: blackPixels ^= 1; michael@0: if (codingLine[this.codingPos] < columns) { michael@0: ++refPos; michael@0: while (refLine[refPos] <= codingLine[this.codingPos] && michael@0: refLine[refPos] < columns) { michael@0: refPos += 2; michael@0: } michael@0: } michael@0: break; michael@0: case twoDimVertR2: michael@0: this.addPixels(refLine[refPos] + 2, blackPixels); michael@0: blackPixels ^= 1; michael@0: if (codingLine[this.codingPos] < columns) { michael@0: ++refPos; michael@0: while (refLine[refPos] <= codingLine[this.codingPos] && michael@0: refLine[refPos] < columns) { michael@0: refPos += 2; michael@0: } michael@0: } michael@0: break; michael@0: case twoDimVertR1: michael@0: this.addPixels(refLine[refPos] + 1, blackPixels); michael@0: blackPixels ^= 1; michael@0: if (codingLine[this.codingPos] < columns) { michael@0: ++refPos; michael@0: while (refLine[refPos] <= codingLine[this.codingPos] && michael@0: refLine[refPos] < columns) { michael@0: refPos += 2; michael@0: } michael@0: } michael@0: break; michael@0: case twoDimVert0: michael@0: this.addPixels(refLine[refPos], blackPixels); michael@0: blackPixels ^= 1; michael@0: if (codingLine[this.codingPos] < columns) { michael@0: ++refPos; michael@0: while (refLine[refPos] <= codingLine[this.codingPos] && michael@0: refLine[refPos] < columns) { michael@0: refPos += 2; michael@0: } michael@0: } michael@0: break; michael@0: case twoDimVertL3: michael@0: this.addPixelsNeg(refLine[refPos] - 3, blackPixels); michael@0: blackPixels ^= 1; michael@0: if (codingLine[this.codingPos] < columns) { michael@0: if (refPos > 0) { michael@0: --refPos; michael@0: } else { michael@0: ++refPos; michael@0: } michael@0: while (refLine[refPos] <= codingLine[this.codingPos] && michael@0: refLine[refPos] < columns) { michael@0: refPos += 2; michael@0: } michael@0: } michael@0: break; michael@0: case twoDimVertL2: michael@0: this.addPixelsNeg(refLine[refPos] - 2, blackPixels); michael@0: blackPixels ^= 1; michael@0: if (codingLine[this.codingPos] < columns) { michael@0: if (refPos > 0) { michael@0: --refPos; michael@0: } else { michael@0: ++refPos; michael@0: } michael@0: while (refLine[refPos] <= codingLine[this.codingPos] && michael@0: refLine[refPos] < columns) { michael@0: refPos += 2; michael@0: } michael@0: } michael@0: break; michael@0: case twoDimVertL1: michael@0: this.addPixelsNeg(refLine[refPos] - 1, blackPixels); michael@0: blackPixels ^= 1; michael@0: if (codingLine[this.codingPos] < columns) { michael@0: if (refPos > 0) { michael@0: --refPos; michael@0: } else { michael@0: ++refPos; michael@0: } michael@0: while (refLine[refPos] <= codingLine[this.codingPos] && michael@0: refLine[refPos] < columns) { michael@0: refPos += 2; michael@0: } michael@0: } michael@0: break; michael@0: case EOF: michael@0: this.addPixels(columns, 0); michael@0: this.eof = true; michael@0: break; michael@0: default: michael@0: info('bad 2d code'); michael@0: this.addPixels(columns, 0); michael@0: this.err = true; michael@0: } michael@0: } michael@0: } else { michael@0: codingLine[0] = 0; michael@0: this.codingPos = 0; michael@0: blackPixels = 0; michael@0: while (codingLine[this.codingPos] < columns) { michael@0: code1 = 0; michael@0: if (blackPixels) { michael@0: do { michael@0: code1 += (code3 = this.getBlackCode()); michael@0: } while (code3 >= 64); michael@0: } else { michael@0: do { michael@0: code1 += (code3 = this.getWhiteCode()); michael@0: } while (code3 >= 64); michael@0: } michael@0: this.addPixels(codingLine[this.codingPos] + code1, blackPixels); michael@0: blackPixels ^= 1; michael@0: } michael@0: } michael@0: michael@0: if (this.byteAlign) { michael@0: this.inputBits &= ~7; michael@0: } michael@0: michael@0: var gotEOL = false; michael@0: michael@0: if (!this.eoblock && this.row == this.rows - 1) { michael@0: this.eof = true; michael@0: } else { michael@0: code1 = this.lookBits(12); michael@0: while (code1 === 0) { michael@0: this.eatBits(1); michael@0: code1 = this.lookBits(12); michael@0: } michael@0: if (code1 == 1) { michael@0: this.eatBits(12); michael@0: gotEOL = true; michael@0: } else if (code1 == EOF) { michael@0: this.eof = true; michael@0: } michael@0: } michael@0: michael@0: if (!this.eof && this.encoding > 0) { michael@0: this.nextLine2D = !this.lookBits(1); michael@0: this.eatBits(1); michael@0: } michael@0: michael@0: if (this.eoblock && gotEOL) { michael@0: code1 = this.lookBits(12); michael@0: if (code1 == 1) { michael@0: this.eatBits(12); michael@0: if (this.encoding > 0) { michael@0: this.lookBits(1); michael@0: this.eatBits(1); michael@0: } michael@0: if (this.encoding >= 0) { michael@0: for (i = 0; i < 4; ++i) { michael@0: code1 = this.lookBits(12); michael@0: if (code1 != 1) { michael@0: info('bad rtc code: ' + code1); michael@0: } michael@0: this.eatBits(12); michael@0: if (this.encoding > 0) { michael@0: this.lookBits(1); michael@0: this.eatBits(1); michael@0: } michael@0: } michael@0: } michael@0: this.eof = true; michael@0: } michael@0: } else if (this.err && this.eoline) { michael@0: while (true) { michael@0: code1 = this.lookBits(13); michael@0: if (code1 == EOF) { michael@0: this.eof = true; michael@0: return null; michael@0: } michael@0: if ((code1 >> 1) == 1) { michael@0: break; michael@0: } michael@0: this.eatBits(1); michael@0: } michael@0: this.eatBits(12); michael@0: if (this.encoding > 0) { michael@0: this.eatBits(1); michael@0: this.nextLine2D = !(code1 & 1); michael@0: } michael@0: } michael@0: michael@0: if (codingLine[0] > 0) { michael@0: this.outputBits = codingLine[this.codingPos = 0]; michael@0: } else { michael@0: this.outputBits = codingLine[this.codingPos = 1]; michael@0: } michael@0: this.row++; michael@0: } michael@0: michael@0: var c; michael@0: if (this.outputBits >= 8) { michael@0: c = (this.codingPos & 1) ? 0 : 0xFF; michael@0: this.outputBits -= 8; michael@0: if (this.outputBits === 0 && codingLine[this.codingPos] < columns) { michael@0: this.codingPos++; michael@0: this.outputBits = (codingLine[this.codingPos] - michael@0: codingLine[this.codingPos - 1]); michael@0: } michael@0: } else { michael@0: bits = 8; michael@0: c = 0; michael@0: do { michael@0: if (this.outputBits > bits) { michael@0: c <<= bits; michael@0: if (!(this.codingPos & 1)) { michael@0: c |= 0xFF >> (8 - bits); michael@0: } michael@0: this.outputBits -= bits; michael@0: bits = 0; michael@0: } else { michael@0: c <<= this.outputBits; michael@0: if (!(this.codingPos & 1)) { michael@0: c |= 0xFF >> (8 - this.outputBits); michael@0: } michael@0: bits -= this.outputBits; michael@0: this.outputBits = 0; michael@0: if (codingLine[this.codingPos] < columns) { michael@0: this.codingPos++; michael@0: this.outputBits = (codingLine[this.codingPos] - michael@0: codingLine[this.codingPos - 1]); michael@0: } else if (bits > 0) { michael@0: c <<= bits; michael@0: bits = 0; michael@0: } michael@0: } michael@0: } while (bits); michael@0: } michael@0: if (this.black) { michael@0: c ^= 0xFF; michael@0: } michael@0: return c; michael@0: }; michael@0: michael@0: // This functions returns the code found from the table. michael@0: // The start and end parameters set the boundaries for searching the table. michael@0: // The limit parameter is optional. Function returns an array with three michael@0: // values. The first array element indicates whether a valid code is being michael@0: // returned. The second array element is the actual code. The third array michael@0: // element indicates whether EOF was reached. michael@0: CCITTFaxStream.prototype.findTableCode = michael@0: function ccittFaxStreamFindTableCode(start, end, table, limit) { michael@0: michael@0: var limitValue = limit || 0; michael@0: for (var i = start; i <= end; ++i) { michael@0: var code = this.lookBits(i); michael@0: if (code == EOF) { michael@0: return [true, 1, false]; michael@0: } michael@0: if (i < end) { michael@0: code <<= end - i; michael@0: } michael@0: if (!limitValue || code >= limitValue) { michael@0: var p = table[code - limitValue]; michael@0: if (p[0] == i) { michael@0: this.eatBits(i); michael@0: return [true, p[1], true]; michael@0: } michael@0: } michael@0: } michael@0: return [false, 0, false]; michael@0: }; michael@0: michael@0: CCITTFaxStream.prototype.getTwoDimCode = michael@0: function ccittFaxStreamGetTwoDimCode() { michael@0: michael@0: var code = 0; michael@0: var p; michael@0: if (this.eoblock) { michael@0: code = this.lookBits(7); michael@0: p = twoDimTable[code]; michael@0: if (p && p[0] > 0) { michael@0: this.eatBits(p[0]); michael@0: return p[1]; michael@0: } michael@0: } else { michael@0: var result = this.findTableCode(1, 7, twoDimTable); michael@0: if (result[0] && result[2]) { michael@0: return result[1]; michael@0: } michael@0: } michael@0: info('Bad two dim code'); michael@0: return EOF; michael@0: }; michael@0: michael@0: CCITTFaxStream.prototype.getWhiteCode = michael@0: function ccittFaxStreamGetWhiteCode() { michael@0: michael@0: var code = 0; michael@0: var p; michael@0: if (this.eoblock) { michael@0: code = this.lookBits(12); michael@0: if (code == EOF) { michael@0: return 1; michael@0: } michael@0: michael@0: if ((code >> 5) === 0) { michael@0: p = whiteTable1[code]; michael@0: } else { michael@0: p = whiteTable2[code >> 3]; michael@0: } michael@0: michael@0: if (p[0] > 0) { michael@0: this.eatBits(p[0]); michael@0: return p[1]; michael@0: } michael@0: } else { michael@0: var result = this.findTableCode(1, 9, whiteTable2); michael@0: if (result[0]) { michael@0: return result[1]; michael@0: } michael@0: michael@0: result = this.findTableCode(11, 12, whiteTable1); michael@0: if (result[0]) { michael@0: return result[1]; michael@0: } michael@0: } michael@0: info('bad white code'); michael@0: this.eatBits(1); michael@0: return 1; michael@0: }; michael@0: michael@0: CCITTFaxStream.prototype.getBlackCode = michael@0: function ccittFaxStreamGetBlackCode() { michael@0: michael@0: var code, p; michael@0: if (this.eoblock) { michael@0: code = this.lookBits(13); michael@0: if (code == EOF) { michael@0: return 1; michael@0: } michael@0: if ((code >> 7) === 0) { michael@0: p = blackTable1[code]; michael@0: } else if ((code >> 9) === 0 && (code >> 7) !== 0) { michael@0: p = blackTable2[(code >> 1) - 64]; michael@0: } else { michael@0: p = blackTable3[code >> 7]; michael@0: } michael@0: michael@0: if (p[0] > 0) { michael@0: this.eatBits(p[0]); michael@0: return p[1]; michael@0: } michael@0: } else { michael@0: var result = this.findTableCode(2, 6, blackTable3); michael@0: if (result[0]) { michael@0: return result[1]; michael@0: } michael@0: michael@0: result = this.findTableCode(7, 12, blackTable2, 64); michael@0: if (result[0]) { michael@0: return result[1]; michael@0: } michael@0: michael@0: result = this.findTableCode(10, 13, blackTable1); michael@0: if (result[0]) { michael@0: return result[1]; michael@0: } michael@0: } michael@0: info('bad black code'); michael@0: this.eatBits(1); michael@0: return 1; michael@0: }; michael@0: michael@0: CCITTFaxStream.prototype.lookBits = function CCITTFaxStream_lookBits(n) { michael@0: var c; michael@0: while (this.inputBits < n) { michael@0: if ((c = this.str.getByte()) === -1) { michael@0: if (this.inputBits === 0) { michael@0: return EOF; michael@0: } michael@0: return ((this.inputBuf << (n - this.inputBits)) & michael@0: (0xFFFF >> (16 - n))); michael@0: } michael@0: this.inputBuf = (this.inputBuf << 8) + c; michael@0: this.inputBits += 8; michael@0: } michael@0: return (this.inputBuf >> (this.inputBits - n)) & (0xFFFF >> (16 - n)); michael@0: }; michael@0: michael@0: CCITTFaxStream.prototype.eatBits = function CCITTFaxStream_eatBits(n) { michael@0: if ((this.inputBits -= n) < 0) { michael@0: this.inputBits = 0; michael@0: } michael@0: }; michael@0: michael@0: return CCITTFaxStream; michael@0: })(); michael@0: michael@0: var LZWStream = (function LZWStreamClosure() { michael@0: function LZWStream(str, maybeLength, earlyChange) { michael@0: this.str = str; michael@0: this.dict = str.dict; michael@0: this.cachedData = 0; michael@0: this.bitsCached = 0; michael@0: michael@0: var maxLzwDictionarySize = 4096; michael@0: var lzwState = { michael@0: earlyChange: earlyChange, michael@0: codeLength: 9, michael@0: nextCode: 258, michael@0: dictionaryValues: new Uint8Array(maxLzwDictionarySize), michael@0: dictionaryLengths: new Uint16Array(maxLzwDictionarySize), michael@0: dictionaryPrevCodes: new Uint16Array(maxLzwDictionarySize), michael@0: currentSequence: new Uint8Array(maxLzwDictionarySize), michael@0: currentSequenceLength: 0 michael@0: }; michael@0: for (var i = 0; i < 256; ++i) { michael@0: lzwState.dictionaryValues[i] = i; michael@0: lzwState.dictionaryLengths[i] = 1; michael@0: } michael@0: this.lzwState = lzwState; michael@0: michael@0: DecodeStream.call(this, maybeLength); michael@0: } michael@0: michael@0: LZWStream.prototype = Object.create(DecodeStream.prototype); michael@0: michael@0: LZWStream.prototype.readBits = function LZWStream_readBits(n) { michael@0: var bitsCached = this.bitsCached; michael@0: var cachedData = this.cachedData; michael@0: while (bitsCached < n) { michael@0: var c = this.str.getByte(); michael@0: if (c === -1) { michael@0: this.eof = true; michael@0: return null; michael@0: } michael@0: cachedData = (cachedData << 8) | c; michael@0: bitsCached += 8; michael@0: } michael@0: this.bitsCached = (bitsCached -= n); michael@0: this.cachedData = cachedData; michael@0: this.lastCode = null; michael@0: return (cachedData >>> bitsCached) & ((1 << n) - 1); michael@0: }; michael@0: michael@0: LZWStream.prototype.readBlock = function LZWStream_readBlock() { michael@0: var blockSize = 512; michael@0: var estimatedDecodedSize = blockSize * 2, decodedSizeDelta = blockSize; michael@0: var i, j, q; michael@0: michael@0: var lzwState = this.lzwState; michael@0: if (!lzwState) { michael@0: return; // eof was found michael@0: } michael@0: michael@0: var earlyChange = lzwState.earlyChange; michael@0: var nextCode = lzwState.nextCode; michael@0: var dictionaryValues = lzwState.dictionaryValues; michael@0: var dictionaryLengths = lzwState.dictionaryLengths; michael@0: var dictionaryPrevCodes = lzwState.dictionaryPrevCodes; michael@0: var codeLength = lzwState.codeLength; michael@0: var prevCode = lzwState.prevCode; michael@0: var currentSequence = lzwState.currentSequence; michael@0: var currentSequenceLength = lzwState.currentSequenceLength; michael@0: michael@0: var decodedLength = 0; michael@0: var currentBufferLength = this.bufferLength; michael@0: var buffer = this.ensureBuffer(this.bufferLength + estimatedDecodedSize); michael@0: michael@0: for (i = 0; i < blockSize; i++) { michael@0: var code = this.readBits(codeLength); michael@0: var hasPrev = currentSequenceLength > 0; michael@0: if (code < 256) { michael@0: currentSequence[0] = code; michael@0: currentSequenceLength = 1; michael@0: } else if (code >= 258) { michael@0: if (code < nextCode) { michael@0: currentSequenceLength = dictionaryLengths[code]; michael@0: for (j = currentSequenceLength - 1, q = code; j >= 0; j--) { michael@0: currentSequence[j] = dictionaryValues[q]; michael@0: q = dictionaryPrevCodes[q]; michael@0: } michael@0: } else { michael@0: currentSequence[currentSequenceLength++] = currentSequence[0]; michael@0: } michael@0: } else if (code == 256) { michael@0: codeLength = 9; michael@0: nextCode = 258; michael@0: currentSequenceLength = 0; michael@0: continue; michael@0: } else { michael@0: this.eof = true; michael@0: delete this.lzwState; michael@0: break; michael@0: } michael@0: michael@0: if (hasPrev) { michael@0: dictionaryPrevCodes[nextCode] = prevCode; michael@0: dictionaryLengths[nextCode] = dictionaryLengths[prevCode] + 1; michael@0: dictionaryValues[nextCode] = currentSequence[0]; michael@0: nextCode++; michael@0: codeLength = (nextCode + earlyChange) & (nextCode + earlyChange - 1) ? michael@0: codeLength : Math.min(Math.log(nextCode + earlyChange) / michael@0: 0.6931471805599453 + 1, 12) | 0; michael@0: } michael@0: prevCode = code; michael@0: michael@0: decodedLength += currentSequenceLength; michael@0: if (estimatedDecodedSize < decodedLength) { michael@0: do { michael@0: estimatedDecodedSize += decodedSizeDelta; michael@0: } while (estimatedDecodedSize < decodedLength); michael@0: buffer = this.ensureBuffer(this.bufferLength + estimatedDecodedSize); michael@0: } michael@0: for (j = 0; j < currentSequenceLength; j++) { michael@0: buffer[currentBufferLength++] = currentSequence[j]; michael@0: } michael@0: } michael@0: lzwState.nextCode = nextCode; michael@0: lzwState.codeLength = codeLength; michael@0: lzwState.prevCode = prevCode; michael@0: lzwState.currentSequenceLength = currentSequenceLength; michael@0: michael@0: this.bufferLength = currentBufferLength; michael@0: }; michael@0: michael@0: return LZWStream; michael@0: })(); michael@0: michael@0: var NullStream = (function NullStreamClosure() { michael@0: function NullStream() { michael@0: Stream.call(this, new Uint8Array(0)); michael@0: } michael@0: michael@0: NullStream.prototype = Stream.prototype; michael@0: michael@0: return NullStream; michael@0: })(); michael@0: michael@0: michael@0: var WorkerMessageHandler = PDFJS.WorkerMessageHandler = { michael@0: setup: function wphSetup(handler) { michael@0: var pdfManager; michael@0: michael@0: function loadDocument(recoveryMode) { michael@0: var loadDocumentPromise = new LegacyPromise(); michael@0: michael@0: var parseSuccess = function parseSuccess() { michael@0: var numPagesPromise = pdfManager.ensureDoc('numPages'); michael@0: var fingerprintPromise = pdfManager.ensureDoc('fingerprint'); michael@0: var outlinePromise = pdfManager.ensureCatalog('documentOutline'); michael@0: var infoPromise = pdfManager.ensureDoc('documentInfo'); michael@0: var metadataPromise = pdfManager.ensureCatalog('metadata'); michael@0: var encryptedPromise = pdfManager.ensureXRef('encrypt'); michael@0: var javaScriptPromise = pdfManager.ensureCatalog('javaScript'); michael@0: Promise.all([numPagesPromise, fingerprintPromise, outlinePromise, michael@0: infoPromise, metadataPromise, encryptedPromise, michael@0: javaScriptPromise]).then(function onDocReady(results) { michael@0: michael@0: var doc = { michael@0: numPages: results[0], michael@0: fingerprint: results[1], michael@0: outline: results[2], michael@0: info: results[3], michael@0: metadata: results[4], michael@0: encrypted: !!results[5], michael@0: javaScript: results[6] michael@0: }; michael@0: loadDocumentPromise.resolve(doc); michael@0: }, michael@0: parseFailure); michael@0: }; michael@0: michael@0: var parseFailure = function parseFailure(e) { michael@0: loadDocumentPromise.reject(e); michael@0: }; michael@0: michael@0: pdfManager.ensureDoc('checkHeader', []).then(function() { michael@0: pdfManager.ensureDoc('parseStartXRef', []).then(function() { michael@0: pdfManager.ensureDoc('parse', [recoveryMode]).then( michael@0: parseSuccess, parseFailure); michael@0: }, parseFailure); michael@0: }, parseFailure); michael@0: michael@0: return loadDocumentPromise; michael@0: } michael@0: michael@0: function getPdfManager(data) { michael@0: var pdfManagerPromise = new LegacyPromise(); michael@0: michael@0: var source = data.source; michael@0: var disableRange = data.disableRange; michael@0: if (source.data) { michael@0: try { michael@0: pdfManager = new LocalPdfManager(source.data, source.password); michael@0: pdfManagerPromise.resolve(); michael@0: } catch (ex) { michael@0: pdfManagerPromise.reject(ex); michael@0: } michael@0: return pdfManagerPromise; michael@0: } else if (source.chunkedViewerLoading) { michael@0: try { michael@0: pdfManager = new NetworkPdfManager(source, handler); michael@0: pdfManagerPromise.resolve(); michael@0: } catch (ex) { michael@0: pdfManagerPromise.reject(ex); michael@0: } michael@0: return pdfManagerPromise; michael@0: } michael@0: michael@0: var networkManager = new NetworkManager(source.url, { michael@0: httpHeaders: source.httpHeaders, michael@0: withCredentials: source.withCredentials michael@0: }); michael@0: var fullRequestXhrId = networkManager.requestFull({ michael@0: onHeadersReceived: function onHeadersReceived() { michael@0: if (disableRange) { michael@0: return; michael@0: } michael@0: michael@0: var fullRequestXhr = networkManager.getRequestXhr(fullRequestXhrId); michael@0: if (fullRequestXhr.getResponseHeader('Accept-Ranges') !== 'bytes') { michael@0: return; michael@0: } michael@0: michael@0: var contentEncoding = michael@0: fullRequestXhr.getResponseHeader('Content-Encoding') || 'identity'; michael@0: if (contentEncoding !== 'identity') { michael@0: return; michael@0: } michael@0: michael@0: var length = fullRequestXhr.getResponseHeader('Content-Length'); michael@0: length = parseInt(length, 10); michael@0: if (!isInt(length)) { michael@0: return; michael@0: } michael@0: source.length = length; michael@0: if (length <= 2 * RANGE_CHUNK_SIZE) { michael@0: // The file size is smaller than the size of two chunks, so it does michael@0: // not make any sense to abort the request and retry with a range michael@0: // request. michael@0: return; michael@0: } michael@0: michael@0: // NOTE: by cancelling the full request, and then issuing range michael@0: // requests, there will be an issue for sites where you can only michael@0: // request the pdf once. However, if this is the case, then the michael@0: // server should not be returning that it can support range requests. michael@0: networkManager.abortRequest(fullRequestXhrId); michael@0: michael@0: try { michael@0: pdfManager = new NetworkPdfManager(source, handler); michael@0: pdfManagerPromise.resolve(pdfManager); michael@0: } catch (ex) { michael@0: pdfManagerPromise.reject(ex); michael@0: } michael@0: }, michael@0: michael@0: onDone: function onDone(args) { michael@0: // the data is array, instantiating directly from it michael@0: try { michael@0: pdfManager = new LocalPdfManager(args.chunk, source.password); michael@0: pdfManagerPromise.resolve(); michael@0: } catch (ex) { michael@0: pdfManagerPromise.reject(ex); michael@0: } michael@0: }, michael@0: michael@0: onError: function onError(status) { michael@0: if (status == 404) { michael@0: var exception = new MissingPDFException('Missing PDF "' + michael@0: source.url + '".'); michael@0: handler.send('MissingPDF', { exception: exception }); michael@0: } else { michael@0: handler.send('DocError', 'Unexpected server response (' + michael@0: status + ') while retrieving PDF "' + michael@0: source.url + '".'); michael@0: } michael@0: }, michael@0: michael@0: onProgress: function onProgress(evt) { michael@0: handler.send('DocProgress', { michael@0: loaded: evt.loaded, michael@0: total: evt.lengthComputable ? evt.total : source.length michael@0: }); michael@0: } michael@0: }); michael@0: michael@0: return pdfManagerPromise; michael@0: } michael@0: michael@0: handler.on('test', function wphSetupTest(data) { michael@0: // check if Uint8Array can be sent to worker michael@0: if (!(data instanceof Uint8Array)) { michael@0: handler.send('test', false); michael@0: return; michael@0: } michael@0: // making sure postMessage transfers are working michael@0: var supportTransfers = data[0] === 255; michael@0: handler.postMessageTransfers = supportTransfers; michael@0: // check if the response property is supported by xhr michael@0: var xhr = new XMLHttpRequest(); michael@0: var responseExists = 'response' in xhr; michael@0: // check if the property is actually implemented michael@0: try { michael@0: var dummy = xhr.responseType; michael@0: } catch (e) { michael@0: responseExists = false; michael@0: } michael@0: if (!responseExists) { michael@0: handler.send('test', false); michael@0: return; michael@0: } michael@0: handler.send('test', { michael@0: supportTypedArray: true, michael@0: supportTransfers: supportTransfers michael@0: }); michael@0: }); michael@0: michael@0: handler.on('GetDocRequest', function wphSetupDoc(data) { michael@0: michael@0: var onSuccess = function(doc) { michael@0: handler.send('GetDoc', { pdfInfo: doc }); michael@0: }; michael@0: michael@0: var onFailure = function(e) { michael@0: if (e instanceof PasswordException) { michael@0: if (e.code === PasswordResponses.NEED_PASSWORD) { michael@0: handler.send('NeedPassword', { michael@0: exception: e michael@0: }); michael@0: } else if (e.code === PasswordResponses.INCORRECT_PASSWORD) { michael@0: handler.send('IncorrectPassword', { michael@0: exception: e michael@0: }); michael@0: } michael@0: } else if (e instanceof InvalidPDFException) { michael@0: handler.send('InvalidPDF', { michael@0: exception: e michael@0: }); michael@0: } else if (e instanceof MissingPDFException) { michael@0: handler.send('MissingPDF', { michael@0: exception: e michael@0: }); michael@0: } else { michael@0: handler.send('UnknownError', { michael@0: exception: new UnknownErrorException(e.message, e.toString()) michael@0: }); michael@0: } michael@0: }; michael@0: michael@0: PDFJS.maxImageSize = data.maxImageSize === undefined ? michael@0: -1 : data.maxImageSize; michael@0: PDFJS.disableFontFace = data.disableFontFace; michael@0: PDFJS.disableCreateObjectURL = data.disableCreateObjectURL; michael@0: PDFJS.verbosity = data.verbosity; michael@0: PDFJS.cMapUrl = data.cMapUrl === undefined ? michael@0: null : data.cMapUrl; michael@0: PDFJS.cMapPacked = data.cMapPacked === true; michael@0: michael@0: getPdfManager(data).then(function () { michael@0: pdfManager.onLoadedStream().then(function(stream) { michael@0: handler.send('DataLoaded', { length: stream.bytes.byteLength }); michael@0: }); michael@0: }).then(function pdfManagerReady() { michael@0: loadDocument(false).then(onSuccess, function loadFailure(ex) { michael@0: // Try again with recoveryMode == true michael@0: if (!(ex instanceof XRefParseException)) { michael@0: if (ex instanceof PasswordException) { michael@0: // after password exception prepare to receive a new password michael@0: // to repeat loading michael@0: pdfManager.passwordChangedPromise = new LegacyPromise(); michael@0: pdfManager.passwordChangedPromise.then(pdfManagerReady); michael@0: } michael@0: michael@0: onFailure(ex); michael@0: return; michael@0: } michael@0: michael@0: pdfManager.requestLoadedStream(); michael@0: pdfManager.onLoadedStream().then(function() { michael@0: loadDocument(true).then(onSuccess, onFailure); michael@0: }); michael@0: }, onFailure); michael@0: }, onFailure); michael@0: }); michael@0: michael@0: handler.on('GetPageRequest', function wphSetupGetPage(data) { michael@0: var pageIndex = data.pageIndex; michael@0: pdfManager.getPage(pageIndex).then(function(page) { michael@0: var rotatePromise = pdfManager.ensure(page, 'rotate'); michael@0: var refPromise = pdfManager.ensure(page, 'ref'); michael@0: var viewPromise = pdfManager.ensure(page, 'view'); michael@0: michael@0: Promise.all([rotatePromise, refPromise, viewPromise]).then( michael@0: function(results) { michael@0: var page = { michael@0: pageIndex: data.pageIndex, michael@0: rotate: results[0], michael@0: ref: results[1], michael@0: view: results[2] michael@0: }; michael@0: michael@0: handler.send('GetPage', { pageInfo: page }); michael@0: }); michael@0: }); michael@0: }); michael@0: michael@0: handler.on('GetPageIndex', function wphSetupGetPageIndex(data, deferred) { michael@0: var ref = new Ref(data.ref.num, data.ref.gen); michael@0: var catalog = pdfManager.pdfDocument.catalog; michael@0: catalog.getPageIndex(ref).then(function (pageIndex) { michael@0: deferred.resolve(pageIndex); michael@0: }, deferred.reject); michael@0: }); michael@0: michael@0: handler.on('GetDestinations', michael@0: function wphSetupGetDestinations(data, deferred) { michael@0: pdfManager.ensureCatalog('destinations').then(function(destinations) { michael@0: deferred.resolve(destinations); michael@0: }); michael@0: } michael@0: ); michael@0: michael@0: handler.on('GetAttachments', michael@0: function wphSetupGetAttachments(data, deferred) { michael@0: pdfManager.ensureCatalog('attachments').then(function(attachments) { michael@0: deferred.resolve(attachments); michael@0: }, deferred.reject); michael@0: } michael@0: ); michael@0: michael@0: handler.on('GetData', function wphSetupGetData(data, deferred) { michael@0: pdfManager.requestLoadedStream(); michael@0: pdfManager.onLoadedStream().then(function(stream) { michael@0: deferred.resolve(stream.bytes); michael@0: }); michael@0: }); michael@0: michael@0: handler.on('UpdatePassword', function wphSetupUpdatePassword(data) { michael@0: pdfManager.updatePassword(data); michael@0: }); michael@0: michael@0: handler.on('GetAnnotationsRequest', function wphSetupGetAnnotations(data) { michael@0: pdfManager.getPage(data.pageIndex).then(function(page) { michael@0: pdfManager.ensure(page, 'getAnnotationsData', []).then( michael@0: function(annotationsData) { michael@0: handler.send('GetAnnotations', { michael@0: pageIndex: data.pageIndex, michael@0: annotations: annotationsData michael@0: }); michael@0: } michael@0: ); michael@0: }); michael@0: }); michael@0: michael@0: handler.on('RenderPageRequest', function wphSetupRenderPage(data) { michael@0: pdfManager.getPage(data.pageIndex).then(function(page) { michael@0: michael@0: var pageNum = data.pageIndex + 1; michael@0: var start = Date.now(); michael@0: // Pre compile the pdf page and fetch the fonts/images. michael@0: page.getOperatorList(handler, data.intent).then(function(operatorList) { michael@0: michael@0: info('page=' + pageNum + ' - getOperatorList: time=' + michael@0: (Date.now() - start) + 'ms, len=' + operatorList.fnArray.length); michael@0: michael@0: }, function(e) { michael@0: michael@0: var minimumStackMessage = michael@0: 'worker.js: while trying to getPage() and getOperatorList()'; michael@0: michael@0: var wrappedException; michael@0: michael@0: // Turn the error into an obj that can be serialized michael@0: if (typeof e === 'string') { michael@0: wrappedException = { michael@0: message: e, michael@0: stack: minimumStackMessage michael@0: }; michael@0: } else if (typeof e === 'object') { michael@0: wrappedException = { michael@0: message: e.message || e.toString(), michael@0: stack: e.stack || minimumStackMessage michael@0: }; michael@0: } else { michael@0: wrappedException = { michael@0: message: 'Unknown exception type: ' + (typeof e), michael@0: stack: minimumStackMessage michael@0: }; michael@0: } michael@0: michael@0: handler.send('PageError', { michael@0: pageNum: pageNum, michael@0: error: wrappedException, michael@0: intent: data.intent michael@0: }); michael@0: }); michael@0: }); michael@0: }, this); michael@0: michael@0: handler.on('GetTextContent', function wphExtractText(data, deferred) { michael@0: pdfManager.getPage(data.pageIndex).then(function(page) { michael@0: var pageNum = data.pageIndex + 1; michael@0: var start = Date.now(); michael@0: page.extractTextContent().then(function(textContent) { michael@0: deferred.resolve(textContent); michael@0: info('text indexing: page=' + pageNum + ' - time=' + michael@0: (Date.now() - start) + 'ms'); michael@0: }, function (e) { michael@0: // Skip errored pages michael@0: deferred.reject(e); michael@0: }); michael@0: }); michael@0: }); michael@0: michael@0: handler.on('Cleanup', function wphCleanup(data, deferred) { michael@0: pdfManager.cleanup(); michael@0: deferred.resolve(true); michael@0: }); michael@0: michael@0: handler.on('Terminate', function wphTerminate(data, deferred) { michael@0: pdfManager.terminate(); michael@0: deferred.resolve(); michael@0: }); michael@0: } michael@0: }; michael@0: michael@0: var consoleTimer = {}; michael@0: michael@0: var workerConsole = { michael@0: log: function log() { michael@0: var args = Array.prototype.slice.call(arguments); michael@0: globalScope.postMessage({ michael@0: action: 'console_log', michael@0: data: args michael@0: }); michael@0: }, michael@0: michael@0: error: function error() { michael@0: var args = Array.prototype.slice.call(arguments); michael@0: globalScope.postMessage({ michael@0: action: 'console_error', michael@0: data: args michael@0: }); michael@0: throw 'pdf.js execution error'; michael@0: }, michael@0: michael@0: time: function time(name) { michael@0: consoleTimer[name] = Date.now(); michael@0: }, michael@0: michael@0: timeEnd: function timeEnd(name) { michael@0: var time = consoleTimer[name]; michael@0: if (!time) { michael@0: error('Unknown timer name ' + name); michael@0: } michael@0: this.log('Timer:', name, Date.now() - time); michael@0: } michael@0: }; michael@0: michael@0: michael@0: // Worker thread? michael@0: if (typeof window === 'undefined') { michael@0: if (!('console' in globalScope)) { michael@0: globalScope.console = workerConsole; michael@0: } michael@0: michael@0: // Listen for unsupported features so we can pass them on to the main thread. michael@0: PDFJS.UnsupportedManager.listen(function (msg) { michael@0: globalScope.postMessage({ michael@0: action: '_unsupported_feature', michael@0: data: msg michael@0: }); michael@0: }); michael@0: michael@0: var handler = new MessageHandler('worker_processor', this); michael@0: WorkerMessageHandler.setup(handler); michael@0: } michael@0: michael@0: michael@0: /* This class implements the QM Coder decoding as defined in michael@0: * JPEG 2000 Part I Final Committee Draft Version 1.0 michael@0: * Annex C.3 Arithmetic decoding procedure michael@0: * available at http://www.jpeg.org/public/fcd15444-1.pdf michael@0: * michael@0: * The arithmetic decoder is used in conjunction with context models to decode michael@0: * JPEG2000 and JBIG2 streams. michael@0: */ michael@0: var ArithmeticDecoder = (function ArithmeticDecoderClosure() { michael@0: // Table C-2 michael@0: var QeTable = [ michael@0: {qe: 0x5601, nmps: 1, nlps: 1, switchFlag: 1}, michael@0: {qe: 0x3401, nmps: 2, nlps: 6, switchFlag: 0}, michael@0: {qe: 0x1801, nmps: 3, nlps: 9, switchFlag: 0}, michael@0: {qe: 0x0AC1, nmps: 4, nlps: 12, switchFlag: 0}, michael@0: {qe: 0x0521, nmps: 5, nlps: 29, switchFlag: 0}, michael@0: {qe: 0x0221, nmps: 38, nlps: 33, switchFlag: 0}, michael@0: {qe: 0x5601, nmps: 7, nlps: 6, switchFlag: 1}, michael@0: {qe: 0x5401, nmps: 8, nlps: 14, switchFlag: 0}, michael@0: {qe: 0x4801, nmps: 9, nlps: 14, switchFlag: 0}, michael@0: {qe: 0x3801, nmps: 10, nlps: 14, switchFlag: 0}, michael@0: {qe: 0x3001, nmps: 11, nlps: 17, switchFlag: 0}, michael@0: {qe: 0x2401, nmps: 12, nlps: 18, switchFlag: 0}, michael@0: {qe: 0x1C01, nmps: 13, nlps: 20, switchFlag: 0}, michael@0: {qe: 0x1601, nmps: 29, nlps: 21, switchFlag: 0}, michael@0: {qe: 0x5601, nmps: 15, nlps: 14, switchFlag: 1}, michael@0: {qe: 0x5401, nmps: 16, nlps: 14, switchFlag: 0}, michael@0: {qe: 0x5101, nmps: 17, nlps: 15, switchFlag: 0}, michael@0: {qe: 0x4801, nmps: 18, nlps: 16, switchFlag: 0}, michael@0: {qe: 0x3801, nmps: 19, nlps: 17, switchFlag: 0}, michael@0: {qe: 0x3401, nmps: 20, nlps: 18, switchFlag: 0}, michael@0: {qe: 0x3001, nmps: 21, nlps: 19, switchFlag: 0}, michael@0: {qe: 0x2801, nmps: 22, nlps: 19, switchFlag: 0}, michael@0: {qe: 0x2401, nmps: 23, nlps: 20, switchFlag: 0}, michael@0: {qe: 0x2201, nmps: 24, nlps: 21, switchFlag: 0}, michael@0: {qe: 0x1C01, nmps: 25, nlps: 22, switchFlag: 0}, michael@0: {qe: 0x1801, nmps: 26, nlps: 23, switchFlag: 0}, michael@0: {qe: 0x1601, nmps: 27, nlps: 24, switchFlag: 0}, michael@0: {qe: 0x1401, nmps: 28, nlps: 25, switchFlag: 0}, michael@0: {qe: 0x1201, nmps: 29, nlps: 26, switchFlag: 0}, michael@0: {qe: 0x1101, nmps: 30, nlps: 27, switchFlag: 0}, michael@0: {qe: 0x0AC1, nmps: 31, nlps: 28, switchFlag: 0}, michael@0: {qe: 0x09C1, nmps: 32, nlps: 29, switchFlag: 0}, michael@0: {qe: 0x08A1, nmps: 33, nlps: 30, switchFlag: 0}, michael@0: {qe: 0x0521, nmps: 34, nlps: 31, switchFlag: 0}, michael@0: {qe: 0x0441, nmps: 35, nlps: 32, switchFlag: 0}, michael@0: {qe: 0x02A1, nmps: 36, nlps: 33, switchFlag: 0}, michael@0: {qe: 0x0221, nmps: 37, nlps: 34, switchFlag: 0}, michael@0: {qe: 0x0141, nmps: 38, nlps: 35, switchFlag: 0}, michael@0: {qe: 0x0111, nmps: 39, nlps: 36, switchFlag: 0}, michael@0: {qe: 0x0085, nmps: 40, nlps: 37, switchFlag: 0}, michael@0: {qe: 0x0049, nmps: 41, nlps: 38, switchFlag: 0}, michael@0: {qe: 0x0025, nmps: 42, nlps: 39, switchFlag: 0}, michael@0: {qe: 0x0015, nmps: 43, nlps: 40, switchFlag: 0}, michael@0: {qe: 0x0009, nmps: 44, nlps: 41, switchFlag: 0}, michael@0: {qe: 0x0005, nmps: 45, nlps: 42, switchFlag: 0}, michael@0: {qe: 0x0001, nmps: 45, nlps: 43, switchFlag: 0}, michael@0: {qe: 0x5601, nmps: 46, nlps: 46, switchFlag: 0} michael@0: ]; michael@0: michael@0: // C.3.5 Initialisation of the decoder (INITDEC) michael@0: function ArithmeticDecoder(data, start, end) { michael@0: this.data = data; michael@0: this.bp = start; michael@0: this.dataEnd = end; michael@0: michael@0: this.chigh = data[start]; michael@0: this.clow = 0; michael@0: michael@0: this.byteIn(); michael@0: michael@0: this.chigh = ((this.chigh << 7) & 0xFFFF) | ((this.clow >> 9) & 0x7F); michael@0: this.clow = (this.clow << 7) & 0xFFFF; michael@0: this.ct -= 7; michael@0: this.a = 0x8000; michael@0: } michael@0: michael@0: ArithmeticDecoder.prototype = { michael@0: // C.3.4 Compressed data input (BYTEIN) michael@0: byteIn: function ArithmeticDecoder_byteIn() { michael@0: var data = this.data; michael@0: var bp = this.bp; michael@0: if (data[bp] == 0xFF) { michael@0: var b1 = data[bp + 1]; michael@0: if (b1 > 0x8F) { michael@0: this.clow += 0xFF00; michael@0: this.ct = 8; michael@0: } else { michael@0: bp++; michael@0: this.clow += (data[bp] << 9); michael@0: this.ct = 7; michael@0: this.bp = bp; michael@0: } michael@0: } else { michael@0: bp++; michael@0: this.clow += bp < this.dataEnd ? (data[bp] << 8) : 0xFF00; michael@0: this.ct = 8; michael@0: this.bp = bp; michael@0: } michael@0: if (this.clow > 0xFFFF) { michael@0: this.chigh += (this.clow >> 16); michael@0: this.clow &= 0xFFFF; michael@0: } michael@0: }, michael@0: // C.3.2 Decoding a decision (DECODE) michael@0: readBit: function ArithmeticDecoder_readBit(contexts, pos) { michael@0: // contexts are packed into 1 byte: michael@0: // highest 7 bits carry cx.index, lowest bit carries cx.mps michael@0: var cx_index = contexts[pos] >> 1, cx_mps = contexts[pos] & 1; michael@0: var qeTableIcx = QeTable[cx_index]; michael@0: var qeIcx = qeTableIcx.qe; michael@0: var d; michael@0: var a = this.a - qeIcx; michael@0: michael@0: if (this.chigh < qeIcx) { michael@0: // exchangeLps michael@0: if (a < qeIcx) { michael@0: a = qeIcx; michael@0: d = cx_mps; michael@0: cx_index = qeTableIcx.nmps; michael@0: } else { michael@0: a = qeIcx; michael@0: d = 1 ^ cx_mps; michael@0: if (qeTableIcx.switchFlag === 1) { michael@0: cx_mps = d; michael@0: } michael@0: cx_index = qeTableIcx.nlps; michael@0: } michael@0: } else { michael@0: this.chigh -= qeIcx; michael@0: if ((a & 0x8000) !== 0) { michael@0: this.a = a; michael@0: return cx_mps; michael@0: } michael@0: // exchangeMps michael@0: if (a < qeIcx) { michael@0: d = 1 ^ cx_mps; michael@0: if (qeTableIcx.switchFlag === 1) { michael@0: cx_mps = d; michael@0: } michael@0: cx_index = qeTableIcx.nlps; michael@0: } else { michael@0: d = cx_mps; michael@0: cx_index = qeTableIcx.nmps; michael@0: } michael@0: } michael@0: // C.3.3 renormD; michael@0: do { michael@0: if (this.ct === 0) { michael@0: this.byteIn(); michael@0: } michael@0: michael@0: a <<= 1; michael@0: this.chigh = ((this.chigh << 1) & 0xFFFF) | ((this.clow >> 15) & 1); michael@0: this.clow = (this.clow << 1) & 0xFFFF; michael@0: this.ct--; michael@0: } while ((a & 0x8000) === 0); michael@0: this.a = a; michael@0: michael@0: contexts[pos] = cx_index << 1 | cx_mps; michael@0: return d; michael@0: } michael@0: }; michael@0: michael@0: return ArithmeticDecoder; michael@0: })(); michael@0: michael@0: michael@0: var JpxImage = (function JpxImageClosure() { michael@0: // Table E.1 michael@0: var SubbandsGainLog2 = { michael@0: 'LL': 0, michael@0: 'LH': 1, michael@0: 'HL': 1, michael@0: 'HH': 2 michael@0: }; michael@0: function JpxImage() { michael@0: this.failOnCorruptedImage = false; michael@0: } michael@0: JpxImage.prototype = { michael@0: load: function JpxImage_load(url) { michael@0: var xhr = new XMLHttpRequest(); michael@0: xhr.open('GET', url, true); michael@0: xhr.responseType = 'arraybuffer'; michael@0: xhr.onload = (function() { michael@0: // TODO catch parse error michael@0: var data = new Uint8Array(xhr.response || xhr.mozResponseArrayBuffer); michael@0: this.parse(data); michael@0: if (this.onload) { michael@0: this.onload(); michael@0: } michael@0: }).bind(this); michael@0: xhr.send(null); michael@0: }, michael@0: parse: function JpxImage_parse(data) { michael@0: michael@0: var head = readUint16(data, 0); michael@0: // No box header, immediate start of codestream (SOC) michael@0: if (head === 0xFF4F) { michael@0: this.parseCodestream(data, 0, data.length); michael@0: return; michael@0: } michael@0: michael@0: var position = 0, length = data.length; michael@0: while (position < length) { michael@0: var headerSize = 8; michael@0: var lbox = readUint32(data, position); michael@0: var tbox = readUint32(data, position + 4); michael@0: position += headerSize; michael@0: if (lbox === 1) { michael@0: // XLBox: read UInt64 according to spec. michael@0: // JavaScript's int precision of 53 bit should be sufficient here. michael@0: lbox = readUint32(data, position) * 4294967296 + michael@0: readUint32(data, position + 4); michael@0: position += 8; michael@0: headerSize += 8; michael@0: } michael@0: if (lbox === 0) { michael@0: lbox = length - position + headerSize; michael@0: } michael@0: if (lbox < headerSize) { michael@0: error('JPX error: Invalid box field size'); michael@0: } michael@0: var dataLength = lbox - headerSize; michael@0: var jumpDataLength = true; michael@0: switch (tbox) { michael@0: case 0x6A501A1A: // 'jP\032\032' michael@0: // TODO michael@0: break; michael@0: case 0x6A703268: // 'jp2h' michael@0: jumpDataLength = false; // parsing child boxes michael@0: break; michael@0: case 0x636F6C72: // 'colr' michael@0: // TODO michael@0: break; michael@0: case 0x6A703263: // 'jp2c' michael@0: this.parseCodestream(data, position, position + dataLength); michael@0: break; michael@0: } michael@0: if (jumpDataLength) { michael@0: position += dataLength; michael@0: } michael@0: } michael@0: }, michael@0: parseImageProperties: function JpxImage_parseImageProperties(stream) { michael@0: try { michael@0: var newByte = stream.getByte(); michael@0: while (newByte >= 0) { michael@0: var oldByte = newByte; michael@0: newByte = stream.getByte(); michael@0: var code = (oldByte << 8) | newByte; michael@0: // Image and tile size (SIZ) michael@0: if (code == 0xFF51) { michael@0: stream.skip(4); michael@0: var Xsiz = stream.getInt32() >>> 0; // Byte 4 michael@0: var Ysiz = stream.getInt32() >>> 0; // Byte 8 michael@0: var XOsiz = stream.getInt32() >>> 0; // Byte 12 michael@0: var YOsiz = stream.getInt32() >>> 0; // Byte 16 michael@0: stream.skip(16); michael@0: var Csiz = stream.getUint16(); // Byte 36 michael@0: this.width = Xsiz - XOsiz; michael@0: this.height = Ysiz - YOsiz; michael@0: this.componentsCount = Csiz; michael@0: // Results are always returned as Uint8Arrays michael@0: this.bitsPerComponent = 8; michael@0: return; michael@0: } michael@0: } michael@0: throw 'No size marker found in JPX stream'; michael@0: } catch (e) { michael@0: if (this.failOnCorruptedImage) { michael@0: error('JPX error: ' + e); michael@0: } else { michael@0: warn('JPX error: ' + e + '. Trying to recover'); michael@0: } michael@0: } michael@0: }, michael@0: parseCodestream: function JpxImage_parseCodestream(data, start, end) { michael@0: var context = {}; michael@0: try { michael@0: var position = start; michael@0: while (position + 1 < end) { michael@0: var code = readUint16(data, position); michael@0: position += 2; michael@0: michael@0: var length = 0, j, sqcd, spqcds, spqcdSize, scalarExpounded, tile; michael@0: switch (code) { michael@0: case 0xFF4F: // Start of codestream (SOC) michael@0: context.mainHeader = true; michael@0: break; michael@0: case 0xFFD9: // End of codestream (EOC) michael@0: break; michael@0: case 0xFF51: // Image and tile size (SIZ) michael@0: length = readUint16(data, position); michael@0: var siz = {}; michael@0: siz.Xsiz = readUint32(data, position + 4); michael@0: siz.Ysiz = readUint32(data, position + 8); michael@0: siz.XOsiz = readUint32(data, position + 12); michael@0: siz.YOsiz = readUint32(data, position + 16); michael@0: siz.XTsiz = readUint32(data, position + 20); michael@0: siz.YTsiz = readUint32(data, position + 24); michael@0: siz.XTOsiz = readUint32(data, position + 28); michael@0: siz.YTOsiz = readUint32(data, position + 32); michael@0: var componentsCount = readUint16(data, position + 36); michael@0: siz.Csiz = componentsCount; michael@0: var components = []; michael@0: j = position + 38; michael@0: for (var i = 0; i < componentsCount; i++) { michael@0: var component = { michael@0: precision: (data[j] & 0x7F) + 1, michael@0: isSigned: !!(data[j] & 0x80), michael@0: XRsiz: data[j + 1], michael@0: YRsiz: data[j + 1] michael@0: }; michael@0: calculateComponentDimensions(component, siz); michael@0: components.push(component); michael@0: } michael@0: context.SIZ = siz; michael@0: context.components = components; michael@0: calculateTileGrids(context, components); michael@0: context.QCC = []; michael@0: context.COC = []; michael@0: break; michael@0: case 0xFF5C: // Quantization default (QCD) michael@0: length = readUint16(data, position); michael@0: var qcd = {}; michael@0: j = position + 2; michael@0: sqcd = data[j++]; michael@0: switch (sqcd & 0x1F) { michael@0: case 0: michael@0: spqcdSize = 8; michael@0: scalarExpounded = true; michael@0: break; michael@0: case 1: michael@0: spqcdSize = 16; michael@0: scalarExpounded = false; michael@0: break; michael@0: case 2: michael@0: spqcdSize = 16; michael@0: scalarExpounded = true; michael@0: break; michael@0: default: michael@0: throw 'Invalid SQcd value ' + sqcd; michael@0: } michael@0: qcd.noQuantization = (spqcdSize == 8); michael@0: qcd.scalarExpounded = scalarExpounded; michael@0: qcd.guardBits = sqcd >> 5; michael@0: spqcds = []; michael@0: while (j < length + position) { michael@0: var spqcd = {}; michael@0: if (spqcdSize == 8) { michael@0: spqcd.epsilon = data[j++] >> 3; michael@0: spqcd.mu = 0; michael@0: } else { michael@0: spqcd.epsilon = data[j] >> 3; michael@0: spqcd.mu = ((data[j] & 0x7) << 8) | data[j + 1]; michael@0: j += 2; michael@0: } michael@0: spqcds.push(spqcd); michael@0: } michael@0: qcd.SPqcds = spqcds; michael@0: if (context.mainHeader) { michael@0: context.QCD = qcd; michael@0: } else { michael@0: context.currentTile.QCD = qcd; michael@0: context.currentTile.QCC = []; michael@0: } michael@0: break; michael@0: case 0xFF5D: // Quantization component (QCC) michael@0: length = readUint16(data, position); michael@0: var qcc = {}; michael@0: j = position + 2; michael@0: var cqcc; michael@0: if (context.SIZ.Csiz < 257) { michael@0: cqcc = data[j++]; michael@0: } else { michael@0: cqcc = readUint16(data, j); michael@0: j += 2; michael@0: } michael@0: sqcd = data[j++]; michael@0: switch (sqcd & 0x1F) { michael@0: case 0: michael@0: spqcdSize = 8; michael@0: scalarExpounded = true; michael@0: break; michael@0: case 1: michael@0: spqcdSize = 16; michael@0: scalarExpounded = false; michael@0: break; michael@0: case 2: michael@0: spqcdSize = 16; michael@0: scalarExpounded = true; michael@0: break; michael@0: default: michael@0: throw 'Invalid SQcd value ' + sqcd; michael@0: } michael@0: qcc.noQuantization = (spqcdSize == 8); michael@0: qcc.scalarExpounded = scalarExpounded; michael@0: qcc.guardBits = sqcd >> 5; michael@0: spqcds = []; michael@0: while (j < (length + position)) { michael@0: spqcd = {}; michael@0: if (spqcdSize == 8) { michael@0: spqcd.epsilon = data[j++] >> 3; michael@0: spqcd.mu = 0; michael@0: } else { michael@0: spqcd.epsilon = data[j] >> 3; michael@0: spqcd.mu = ((data[j] & 0x7) << 8) | data[j + 1]; michael@0: j += 2; michael@0: } michael@0: spqcds.push(spqcd); michael@0: } michael@0: qcc.SPqcds = spqcds; michael@0: if (context.mainHeader) { michael@0: context.QCC[cqcc] = qcc; michael@0: } else { michael@0: context.currentTile.QCC[cqcc] = qcc; michael@0: } michael@0: break; michael@0: case 0xFF52: // Coding style default (COD) michael@0: length = readUint16(data, position); michael@0: var cod = {}; michael@0: j = position + 2; michael@0: var scod = data[j++]; michael@0: cod.entropyCoderWithCustomPrecincts = !!(scod & 1); michael@0: cod.sopMarkerUsed = !!(scod & 2); michael@0: cod.ephMarkerUsed = !!(scod & 4); michael@0: cod.progressionOrder = data[j++]; michael@0: cod.layersCount = readUint16(data, j); michael@0: j += 2; michael@0: cod.multipleComponentTransform = data[j++]; michael@0: michael@0: cod.decompositionLevelsCount = data[j++]; michael@0: cod.xcb = (data[j++] & 0xF) + 2; michael@0: cod.ycb = (data[j++] & 0xF) + 2; michael@0: var blockStyle = data[j++]; michael@0: cod.selectiveArithmeticCodingBypass = !!(blockStyle & 1); michael@0: cod.resetContextProbabilities = !!(blockStyle & 2); michael@0: cod.terminationOnEachCodingPass = !!(blockStyle & 4); michael@0: cod.verticalyStripe = !!(blockStyle & 8); michael@0: cod.predictableTermination = !!(blockStyle & 16); michael@0: cod.segmentationSymbolUsed = !!(blockStyle & 32); michael@0: cod.reversibleTransformation = data[j++]; michael@0: if (cod.entropyCoderWithCustomPrecincts) { michael@0: var precinctsSizes = []; michael@0: while (j < length + position) { michael@0: var precinctsSize = data[j++]; michael@0: precinctsSizes.push({ michael@0: PPx: precinctsSize & 0xF, michael@0: PPy: precinctsSize >> 4 michael@0: }); michael@0: } michael@0: cod.precinctsSizes = precinctsSizes; michael@0: } michael@0: michael@0: if (cod.sopMarkerUsed || cod.ephMarkerUsed || michael@0: cod.selectiveArithmeticCodingBypass || michael@0: cod.resetContextProbabilities || michael@0: cod.terminationOnEachCodingPass || michael@0: cod.verticalyStripe || cod.predictableTermination) { michael@0: throw 'Unsupported COD options: ' + michael@0: globalScope.JSON.stringify(cod); michael@0: } michael@0: michael@0: if (context.mainHeader) { michael@0: context.COD = cod; michael@0: } else { michael@0: context.currentTile.COD = cod; michael@0: context.currentTile.COC = []; michael@0: } michael@0: break; michael@0: case 0xFF90: // Start of tile-part (SOT) michael@0: length = readUint16(data, position); michael@0: tile = {}; michael@0: tile.index = readUint16(data, position + 2); michael@0: tile.length = readUint32(data, position + 4); michael@0: tile.dataEnd = tile.length + position - 2; michael@0: tile.partIndex = data[position + 8]; michael@0: tile.partsCount = data[position + 9]; michael@0: michael@0: context.mainHeader = false; michael@0: if (tile.partIndex === 0) { michael@0: // reset component specific settings michael@0: tile.COD = context.COD; michael@0: tile.COC = context.COC.slice(0); // clone of the global COC michael@0: tile.QCD = context.QCD; michael@0: tile.QCC = context.QCC.slice(0); // clone of the global COC michael@0: } michael@0: context.currentTile = tile; michael@0: break; michael@0: case 0xFF93: // Start of data (SOD) michael@0: tile = context.currentTile; michael@0: if (tile.partIndex === 0) { michael@0: initializeTile(context, tile.index); michael@0: buildPackets(context); michael@0: } michael@0: michael@0: // moving to the end of the data michael@0: length = tile.dataEnd - position; michael@0: parseTilePackets(context, data, position, length); michael@0: break; michael@0: case 0xFF64: // Comment (COM) michael@0: length = readUint16(data, position); michael@0: // skipping content michael@0: break; michael@0: case 0xFF53: // Coding style component (COC) michael@0: throw 'Codestream code 0xFF53 (COC) is not implemented'; michael@0: default: michael@0: throw 'Unknown codestream code: ' + code.toString(16); michael@0: } michael@0: position += length; michael@0: } michael@0: } catch (e) { michael@0: if (this.failOnCorruptedImage) { michael@0: error('JPX error: ' + e); michael@0: } else { michael@0: warn('JPX error: ' + e + '. Trying to recover'); michael@0: } michael@0: } michael@0: this.tiles = transformComponents(context); michael@0: this.width = context.SIZ.Xsiz - context.SIZ.XOsiz; michael@0: this.height = context.SIZ.Ysiz - context.SIZ.YOsiz; michael@0: this.componentsCount = context.SIZ.Csiz; michael@0: } michael@0: }; michael@0: function calculateComponentDimensions(component, siz) { michael@0: // Section B.2 Component mapping michael@0: component.x0 = Math.ceil(siz.XOsiz / component.XRsiz); michael@0: component.x1 = Math.ceil(siz.Xsiz / component.XRsiz); michael@0: component.y0 = Math.ceil(siz.YOsiz / component.YRsiz); michael@0: component.y1 = Math.ceil(siz.Ysiz / component.YRsiz); michael@0: component.width = component.x1 - component.x0; michael@0: component.height = component.y1 - component.y0; michael@0: } michael@0: function calculateTileGrids(context, components) { michael@0: var siz = context.SIZ; michael@0: // Section B.3 Division into tile and tile-components michael@0: var tile, tiles = []; michael@0: var numXtiles = Math.ceil((siz.Xsiz - siz.XTOsiz) / siz.XTsiz); michael@0: var numYtiles = Math.ceil((siz.Ysiz - siz.YTOsiz) / siz.YTsiz); michael@0: for (var q = 0; q < numYtiles; q++) { michael@0: for (var p = 0; p < numXtiles; p++) { michael@0: tile = {}; michael@0: tile.tx0 = Math.max(siz.XTOsiz + p * siz.XTsiz, siz.XOsiz); michael@0: tile.ty0 = Math.max(siz.YTOsiz + q * siz.YTsiz, siz.YOsiz); michael@0: tile.tx1 = Math.min(siz.XTOsiz + (p + 1) * siz.XTsiz, siz.Xsiz); michael@0: tile.ty1 = Math.min(siz.YTOsiz + (q + 1) * siz.YTsiz, siz.Ysiz); michael@0: tile.width = tile.tx1 - tile.tx0; michael@0: tile.height = tile.ty1 - tile.ty0; michael@0: tile.components = []; michael@0: tiles.push(tile); michael@0: } michael@0: } michael@0: context.tiles = tiles; michael@0: michael@0: var componentsCount = siz.Csiz; michael@0: for (var i = 0, ii = componentsCount; i < ii; i++) { michael@0: var component = components[i]; michael@0: for (var j = 0, jj = tiles.length; j < jj; j++) { michael@0: var tileComponent = {}; michael@0: tile = tiles[j]; michael@0: tileComponent.tcx0 = Math.ceil(tile.tx0 / component.XRsiz); michael@0: tileComponent.tcy0 = Math.ceil(tile.ty0 / component.YRsiz); michael@0: tileComponent.tcx1 = Math.ceil(tile.tx1 / component.XRsiz); michael@0: tileComponent.tcy1 = Math.ceil(tile.ty1 / component.YRsiz); michael@0: tileComponent.width = tileComponent.tcx1 - tileComponent.tcx0; michael@0: tileComponent.height = tileComponent.tcy1 - tileComponent.tcy0; michael@0: tile.components[i] = tileComponent; michael@0: } michael@0: } michael@0: } michael@0: function getBlocksDimensions(context, component, r) { michael@0: var codOrCoc = component.codingStyleParameters; michael@0: var result = {}; michael@0: if (!codOrCoc.entropyCoderWithCustomPrecincts) { michael@0: result.PPx = 15; michael@0: result.PPy = 15; michael@0: } else { michael@0: result.PPx = codOrCoc.precinctsSizes[r].PPx; michael@0: result.PPy = codOrCoc.precinctsSizes[r].PPy; michael@0: } michael@0: // calculate codeblock size as described in section B.7 michael@0: result.xcb_ = (r > 0 ? Math.min(codOrCoc.xcb, result.PPx - 1) : michael@0: Math.min(codOrCoc.xcb, result.PPx)); michael@0: result.ycb_ = (r > 0 ? Math.min(codOrCoc.ycb, result.PPy - 1) : michael@0: Math.min(codOrCoc.ycb, result.PPy)); michael@0: return result; michael@0: } michael@0: function buildPrecincts(context, resolution, dimensions) { michael@0: // Section B.6 Division resolution to precincts michael@0: var precinctWidth = 1 << dimensions.PPx; michael@0: var precinctHeight = 1 << dimensions.PPy; michael@0: var numprecinctswide = (resolution.trx1 > resolution.trx0 ? michael@0: Math.ceil(resolution.trx1 / precinctWidth) - michael@0: Math.floor(resolution.trx0 / precinctWidth) : 0); michael@0: var numprecinctshigh = (resolution.try1 > resolution.try0 ? michael@0: Math.ceil(resolution.try1 / precinctHeight) - michael@0: Math.floor(resolution.try0 / precinctHeight) : 0); michael@0: var numprecincts = numprecinctswide * numprecinctshigh; michael@0: var precinctXOffset = Math.floor(resolution.trx0 / precinctWidth) * michael@0: precinctWidth; michael@0: var precinctYOffset = Math.floor(resolution.try0 / precinctHeight) * michael@0: precinctHeight; michael@0: resolution.precinctParameters = { michael@0: precinctXOffset: precinctXOffset, michael@0: precinctYOffset: precinctYOffset, michael@0: precinctWidth: precinctWidth, michael@0: precinctHeight: precinctHeight, michael@0: numprecinctswide: numprecinctswide, michael@0: numprecinctshigh: numprecinctshigh, michael@0: numprecincts: numprecincts michael@0: }; michael@0: } michael@0: function buildCodeblocks(context, subband, dimensions) { michael@0: // Section B.7 Division sub-band into code-blocks michael@0: var xcb_ = dimensions.xcb_; michael@0: var ycb_ = dimensions.ycb_; michael@0: var codeblockWidth = 1 << xcb_; michael@0: var codeblockHeight = 1 << ycb_; michael@0: var cbx0 = subband.tbx0 >> xcb_; michael@0: var cby0 = subband.tby0 >> ycb_; michael@0: var cbx1 = (subband.tbx1 + codeblockWidth - 1) >> xcb_; michael@0: var cby1 = (subband.tby1 + codeblockHeight - 1) >> ycb_; michael@0: var precinctParameters = subband.resolution.precinctParameters; michael@0: var codeblocks = []; michael@0: var precincts = []; michael@0: var i, j, codeblock, precinctNumber; michael@0: for (j = cby0; j < cby1; j++) { michael@0: for (i = cbx0; i < cbx1; i++) { michael@0: codeblock = { michael@0: cbx: i, michael@0: cby: j, michael@0: tbx0: codeblockWidth * i, michael@0: tby0: codeblockHeight * j, michael@0: tbx1: codeblockWidth * (i + 1), michael@0: tby1: codeblockHeight * (j + 1) michael@0: }; michael@0: // calculate precinct number michael@0: var pi = Math.floor((codeblock.tbx0 - michael@0: precinctParameters.precinctXOffset) / michael@0: precinctParameters.precinctWidth); michael@0: var pj = Math.floor((codeblock.tby0 - michael@0: precinctParameters.precinctYOffset) / michael@0: precinctParameters.precinctHeight); michael@0: precinctNumber = pj + pi * precinctParameters.numprecinctswide; michael@0: codeblock.tbx0_ = Math.max(subband.tbx0, codeblock.tbx0); michael@0: codeblock.tby0_ = Math.max(subband.tby0, codeblock.tby0); michael@0: codeblock.tbx1_ = Math.min(subband.tbx1, codeblock.tbx1); michael@0: codeblock.tby1_ = Math.min(subband.tby1, codeblock.tby1); michael@0: codeblock.precinctNumber = precinctNumber; michael@0: codeblock.subbandType = subband.type; michael@0: codeblock.Lblock = 3; michael@0: codeblocks.push(codeblock); michael@0: // building precinct for the sub-band michael@0: var precinct = precincts[precinctNumber]; michael@0: if (precinct !== undefined) { michael@0: if (i < precinct.cbxMin) { michael@0: precinct.cbxMin = i; michael@0: } else if (i > precinct.cbxMax) { michael@0: precinct.cbxMax = i; michael@0: } michael@0: if (j < precinct.cbyMin) { michael@0: precinct.cbxMin = j; michael@0: } else if (j > precinct.cbyMax) { michael@0: precinct.cbyMax = j; michael@0: } michael@0: } else { michael@0: precincts[precinctNumber] = precinct = { michael@0: cbxMin: i, michael@0: cbyMin: j, michael@0: cbxMax: i, michael@0: cbyMax: j michael@0: }; michael@0: } michael@0: codeblock.precinct = precinct; michael@0: } michael@0: } michael@0: subband.codeblockParameters = { michael@0: codeblockWidth: xcb_, michael@0: codeblockHeight: ycb_, michael@0: numcodeblockwide: cbx1 - cbx0 + 1, michael@0: numcodeblockhigh: cby1 - cby1 + 1 michael@0: }; michael@0: subband.codeblocks = codeblocks; michael@0: subband.precincts = precincts; michael@0: } michael@0: function createPacket(resolution, precinctNumber, layerNumber) { michael@0: var precinctCodeblocks = []; michael@0: // Section B.10.8 Order of info in packet michael@0: var subbands = resolution.subbands; michael@0: // sub-bands already ordered in 'LL', 'HL', 'LH', and 'HH' sequence michael@0: for (var i = 0, ii = subbands.length; i < ii; i++) { michael@0: var subband = subbands[i]; michael@0: var codeblocks = subband.codeblocks; michael@0: for (var j = 0, jj = codeblocks.length; j < jj; j++) { michael@0: var codeblock = codeblocks[j]; michael@0: if (codeblock.precinctNumber != precinctNumber) { michael@0: continue; michael@0: } michael@0: precinctCodeblocks.push(codeblock); michael@0: } michael@0: } michael@0: return { michael@0: layerNumber: layerNumber, michael@0: codeblocks: precinctCodeblocks michael@0: }; michael@0: } michael@0: function LayerResolutionComponentPositionIterator(context) { michael@0: var siz = context.SIZ; michael@0: var tileIndex = context.currentTile.index; michael@0: var tile = context.tiles[tileIndex]; michael@0: var layersCount = tile.codingStyleDefaultParameters.layersCount; michael@0: var componentsCount = siz.Csiz; michael@0: var maxDecompositionLevelsCount = 0; michael@0: for (var q = 0; q < componentsCount; q++) { michael@0: maxDecompositionLevelsCount = Math.max(maxDecompositionLevelsCount, michael@0: tile.components[q].codingStyleParameters.decompositionLevelsCount); michael@0: } michael@0: michael@0: var l = 0, r = 0, i = 0, k = 0; michael@0: michael@0: this.nextPacket = function JpxImage_nextPacket() { michael@0: // Section B.12.1.1 Layer-resolution-component-position michael@0: for (; l < layersCount; l++) { michael@0: for (; r <= maxDecompositionLevelsCount; r++) { michael@0: for (; i < componentsCount; i++) { michael@0: var component = tile.components[i]; michael@0: if (r > component.codingStyleParameters.decompositionLevelsCount) { michael@0: continue; michael@0: } michael@0: michael@0: var resolution = component.resolutions[r]; michael@0: var numprecincts = resolution.precinctParameters.numprecincts; michael@0: for (; k < numprecincts;) { michael@0: var packet = createPacket(resolution, k, l); michael@0: k++; michael@0: return packet; michael@0: } michael@0: k = 0; michael@0: } michael@0: i = 0; michael@0: } michael@0: r = 0; michael@0: } michael@0: throw 'Out of packets'; michael@0: }; michael@0: } michael@0: function ResolutionLayerComponentPositionIterator(context) { michael@0: var siz = context.SIZ; michael@0: var tileIndex = context.currentTile.index; michael@0: var tile = context.tiles[tileIndex]; michael@0: var layersCount = tile.codingStyleDefaultParameters.layersCount; michael@0: var componentsCount = siz.Csiz; michael@0: var maxDecompositionLevelsCount = 0; michael@0: for (var q = 0; q < componentsCount; q++) { michael@0: maxDecompositionLevelsCount = Math.max(maxDecompositionLevelsCount, michael@0: tile.components[q].codingStyleParameters.decompositionLevelsCount); michael@0: } michael@0: michael@0: var r = 0, l = 0, i = 0, k = 0; michael@0: michael@0: this.nextPacket = function JpxImage_nextPacket() { michael@0: // Section B.12.1.2 Resolution-layer-component-position michael@0: for (; r <= maxDecompositionLevelsCount; r++) { michael@0: for (; l < layersCount; l++) { michael@0: for (; i < componentsCount; i++) { michael@0: var component = tile.components[i]; michael@0: if (r > component.codingStyleParameters.decompositionLevelsCount) { michael@0: continue; michael@0: } michael@0: michael@0: var resolution = component.resolutions[r]; michael@0: var numprecincts = resolution.precinctParameters.numprecincts; michael@0: for (; k < numprecincts;) { michael@0: var packet = createPacket(resolution, k, l); michael@0: k++; michael@0: return packet; michael@0: } michael@0: k = 0; michael@0: } michael@0: i = 0; michael@0: } michael@0: l = 0; michael@0: } michael@0: throw 'Out of packets'; michael@0: }; michael@0: } michael@0: function buildPackets(context) { michael@0: var siz = context.SIZ; michael@0: var tileIndex = context.currentTile.index; michael@0: var tile = context.tiles[tileIndex]; michael@0: var componentsCount = siz.Csiz; michael@0: // Creating resolutions and sub-bands for each component michael@0: for (var c = 0; c < componentsCount; c++) { michael@0: var component = tile.components[c]; michael@0: var decompositionLevelsCount = michael@0: component.codingStyleParameters.decompositionLevelsCount; michael@0: // Section B.5 Resolution levels and sub-bands michael@0: var resolutions = []; michael@0: var subbands = []; michael@0: for (var r = 0; r <= decompositionLevelsCount; r++) { michael@0: var blocksDimensions = getBlocksDimensions(context, component, r); michael@0: var resolution = {}; michael@0: var scale = 1 << (decompositionLevelsCount - r); michael@0: resolution.trx0 = Math.ceil(component.tcx0 / scale); michael@0: resolution.try0 = Math.ceil(component.tcy0 / scale); michael@0: resolution.trx1 = Math.ceil(component.tcx1 / scale); michael@0: resolution.try1 = Math.ceil(component.tcy1 / scale); michael@0: buildPrecincts(context, resolution, blocksDimensions); michael@0: resolutions.push(resolution); michael@0: michael@0: var subband; michael@0: if (r === 0) { michael@0: // one sub-band (LL) with last decomposition michael@0: subband = {}; michael@0: subband.type = 'LL'; michael@0: subband.tbx0 = Math.ceil(component.tcx0 / scale); michael@0: subband.tby0 = Math.ceil(component.tcy0 / scale); michael@0: subband.tbx1 = Math.ceil(component.tcx1 / scale); michael@0: subband.tby1 = Math.ceil(component.tcy1 / scale); michael@0: subband.resolution = resolution; michael@0: buildCodeblocks(context, subband, blocksDimensions); michael@0: subbands.push(subband); michael@0: resolution.subbands = [subband]; michael@0: } else { michael@0: var bscale = 1 << (decompositionLevelsCount - r + 1); michael@0: var resolutionSubbands = []; michael@0: // three sub-bands (HL, LH and HH) with rest of decompositions michael@0: subband = {}; michael@0: subband.type = 'HL'; michael@0: subband.tbx0 = Math.ceil(component.tcx0 / bscale - 0.5); michael@0: subband.tby0 = Math.ceil(component.tcy0 / bscale); michael@0: subband.tbx1 = Math.ceil(component.tcx1 / bscale - 0.5); michael@0: subband.tby1 = Math.ceil(component.tcy1 / bscale); michael@0: subband.resolution = resolution; michael@0: buildCodeblocks(context, subband, blocksDimensions); michael@0: subbands.push(subband); michael@0: resolutionSubbands.push(subband); michael@0: michael@0: subband = {}; michael@0: subband.type = 'LH'; michael@0: subband.tbx0 = Math.ceil(component.tcx0 / bscale); michael@0: subband.tby0 = Math.ceil(component.tcy0 / bscale - 0.5); michael@0: subband.tbx1 = Math.ceil(component.tcx1 / bscale); michael@0: subband.tby1 = Math.ceil(component.tcy1 / bscale - 0.5); michael@0: subband.resolution = resolution; michael@0: buildCodeblocks(context, subband, blocksDimensions); michael@0: subbands.push(subband); michael@0: resolutionSubbands.push(subband); michael@0: michael@0: subband = {}; michael@0: subband.type = 'HH'; michael@0: subband.tbx0 = Math.ceil(component.tcx0 / bscale - 0.5); michael@0: subband.tby0 = Math.ceil(component.tcy0 / bscale - 0.5); michael@0: subband.tbx1 = Math.ceil(component.tcx1 / bscale - 0.5); michael@0: subband.tby1 = Math.ceil(component.tcy1 / bscale - 0.5); michael@0: subband.resolution = resolution; michael@0: buildCodeblocks(context, subband, blocksDimensions); michael@0: subbands.push(subband); michael@0: resolutionSubbands.push(subband); michael@0: michael@0: resolution.subbands = resolutionSubbands; michael@0: } michael@0: } michael@0: component.resolutions = resolutions; michael@0: component.subbands = subbands; michael@0: } michael@0: // Generate the packets sequence michael@0: var progressionOrder = tile.codingStyleDefaultParameters.progressionOrder; michael@0: switch (progressionOrder) { michael@0: case 0: michael@0: tile.packetsIterator = michael@0: new LayerResolutionComponentPositionIterator(context); michael@0: break; michael@0: case 1: michael@0: tile.packetsIterator = michael@0: new ResolutionLayerComponentPositionIterator(context); michael@0: break; michael@0: default: michael@0: throw 'Unsupported progression order ' + progressionOrder; michael@0: } michael@0: } michael@0: function parseTilePackets(context, data, offset, dataLength) { michael@0: var position = 0; michael@0: var buffer, bufferSize = 0, skipNextBit = false; michael@0: function readBits(count) { michael@0: while (bufferSize < count) { michael@0: var b = data[offset + position]; michael@0: position++; michael@0: if (skipNextBit) { michael@0: buffer = (buffer << 7) | b; michael@0: bufferSize += 7; michael@0: skipNextBit = false; michael@0: } else { michael@0: buffer = (buffer << 8) | b; michael@0: bufferSize += 8; michael@0: } michael@0: if (b == 0xFF) { michael@0: skipNextBit = true; michael@0: } michael@0: } michael@0: bufferSize -= count; michael@0: return (buffer >>> bufferSize) & ((1 << count) - 1); michael@0: } michael@0: function alignToByte() { michael@0: bufferSize = 0; michael@0: if (skipNextBit) { michael@0: position++; michael@0: skipNextBit = false; michael@0: } michael@0: } michael@0: function readCodingpasses() { michael@0: if (readBits(1) === 0) { michael@0: return 1; michael@0: } michael@0: if (readBits(1) === 0) { michael@0: return 2; michael@0: } michael@0: var value = readBits(2); michael@0: if (value < 3) { michael@0: return value + 3; michael@0: } michael@0: value = readBits(5); michael@0: if (value < 31) { michael@0: return value + 6; michael@0: } michael@0: value = readBits(7); michael@0: return value + 37; michael@0: } michael@0: var tileIndex = context.currentTile.index; michael@0: var tile = context.tiles[tileIndex]; michael@0: var packetsIterator = tile.packetsIterator; michael@0: while (position < dataLength) { michael@0: var packet = packetsIterator.nextPacket(); michael@0: if (!readBits(1)) { michael@0: alignToByte(); michael@0: continue; michael@0: } michael@0: var layerNumber = packet.layerNumber; michael@0: var queue = [], codeblock; michael@0: for (var i = 0, ii = packet.codeblocks.length; i < ii; i++) { michael@0: codeblock = packet.codeblocks[i]; michael@0: var precinct = codeblock.precinct; michael@0: var codeblockColumn = codeblock.cbx - precinct.cbxMin; michael@0: var codeblockRow = codeblock.cby - precinct.cbyMin; michael@0: var codeblockIncluded = false; michael@0: var firstTimeInclusion = false; michael@0: var valueReady; michael@0: if ('included' in codeblock) { michael@0: codeblockIncluded = !!readBits(1); michael@0: } else { michael@0: // reading inclusion tree michael@0: precinct = codeblock.precinct; michael@0: var inclusionTree, zeroBitPlanesTree; michael@0: if ('inclusionTree' in precinct) { michael@0: inclusionTree = precinct.inclusionTree; michael@0: } else { michael@0: // building inclusion and zero bit-planes trees michael@0: var width = precinct.cbxMax - precinct.cbxMin + 1; michael@0: var height = precinct.cbyMax - precinct.cbyMin + 1; michael@0: inclusionTree = new InclusionTree(width, height, layerNumber); michael@0: zeroBitPlanesTree = new TagTree(width, height); michael@0: precinct.inclusionTree = inclusionTree; michael@0: precinct.zeroBitPlanesTree = zeroBitPlanesTree; michael@0: } michael@0: michael@0: if (inclusionTree.reset(codeblockColumn, codeblockRow, layerNumber)) { michael@0: while (true) { michael@0: if (readBits(1)) { michael@0: valueReady = !inclusionTree.nextLevel(); michael@0: if (valueReady) { michael@0: codeblock.included = true; michael@0: codeblockIncluded = firstTimeInclusion = true; michael@0: break; michael@0: } michael@0: } else { michael@0: inclusionTree.incrementValue(layerNumber); michael@0: break; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: if (!codeblockIncluded) { michael@0: continue; michael@0: } michael@0: if (firstTimeInclusion) { michael@0: zeroBitPlanesTree = precinct.zeroBitPlanesTree; michael@0: zeroBitPlanesTree.reset(codeblockColumn, codeblockRow); michael@0: while (true) { michael@0: if (readBits(1)) { michael@0: valueReady = !zeroBitPlanesTree.nextLevel(); michael@0: if (valueReady) { michael@0: break; michael@0: } michael@0: } else { michael@0: zeroBitPlanesTree.incrementValue(); michael@0: } michael@0: } michael@0: codeblock.zeroBitPlanes = zeroBitPlanesTree.value; michael@0: } michael@0: var codingpasses = readCodingpasses(); michael@0: while (readBits(1)) { michael@0: codeblock.Lblock++; michael@0: } michael@0: var codingpassesLog2 = log2(codingpasses); michael@0: // rounding down log2 michael@0: var bits = ((codingpasses < (1 << codingpassesLog2)) ? michael@0: codingpassesLog2 - 1 : codingpassesLog2) + codeblock.Lblock; michael@0: var codedDataLength = readBits(bits); michael@0: queue.push({ michael@0: codeblock: codeblock, michael@0: codingpasses: codingpasses, michael@0: dataLength: codedDataLength michael@0: }); michael@0: } michael@0: alignToByte(); michael@0: while (queue.length > 0) { michael@0: var packetItem = queue.shift(); michael@0: codeblock = packetItem.codeblock; michael@0: if (!('data' in codeblock)) { michael@0: codeblock.data = []; michael@0: } michael@0: codeblock.data.push({ michael@0: data: data, michael@0: start: offset + position, michael@0: end: offset + position + packetItem.dataLength, michael@0: codingpasses: packetItem.codingpasses michael@0: }); michael@0: position += packetItem.dataLength; michael@0: } michael@0: } michael@0: return position; michael@0: } michael@0: function copyCoefficients(coefficients, levelWidth, levelHeight, subband, michael@0: delta, mb, reversible, segmentationSymbolUsed) { michael@0: var x0 = subband.tbx0; michael@0: var y0 = subband.tby0; michael@0: var width = subband.tbx1 - subband.tbx0; michael@0: var codeblocks = subband.codeblocks; michael@0: var right = subband.type.charAt(0) === 'H' ? 1 : 0; michael@0: var bottom = subband.type.charAt(1) === 'H' ? levelWidth : 0; michael@0: michael@0: for (var i = 0, ii = codeblocks.length; i < ii; ++i) { michael@0: var codeblock = codeblocks[i]; michael@0: var blockWidth = codeblock.tbx1_ - codeblock.tbx0_; michael@0: var blockHeight = codeblock.tby1_ - codeblock.tby0_; michael@0: if (blockWidth === 0 || blockHeight === 0) { michael@0: continue; michael@0: } michael@0: if (!('data' in codeblock)) { michael@0: continue; michael@0: } michael@0: michael@0: var bitModel, currentCodingpassType; michael@0: bitModel = new BitModel(blockWidth, blockHeight, codeblock.subbandType, michael@0: codeblock.zeroBitPlanes, mb); michael@0: currentCodingpassType = 2; // first bit plane starts from cleanup michael@0: michael@0: // collect data michael@0: var data = codeblock.data, totalLength = 0, codingpasses = 0; michael@0: var j, jj, dataItem; michael@0: for (j = 0, jj = data.length; j < jj; j++) { michael@0: dataItem = data[j]; michael@0: totalLength += dataItem.end - dataItem.start; michael@0: codingpasses += dataItem.codingpasses; michael@0: } michael@0: var encodedData = new Uint8Array(totalLength); michael@0: var position = 0; michael@0: for (j = 0, jj = data.length; j < jj; j++) { michael@0: dataItem = data[j]; michael@0: var chunk = dataItem.data.subarray(dataItem.start, dataItem.end); michael@0: encodedData.set(chunk, position); michael@0: position += chunk.length; michael@0: } michael@0: // decoding the item michael@0: var decoder = new ArithmeticDecoder(encodedData, 0, totalLength); michael@0: bitModel.setDecoder(decoder); michael@0: michael@0: for (j = 0; j < codingpasses; j++) { michael@0: switch (currentCodingpassType) { michael@0: case 0: michael@0: bitModel.runSignificancePropogationPass(); michael@0: break; michael@0: case 1: michael@0: bitModel.runMagnitudeRefinementPass(); michael@0: break; michael@0: case 2: michael@0: bitModel.runCleanupPass(); michael@0: if (segmentationSymbolUsed) { michael@0: bitModel.checkSegmentationSymbol(); michael@0: } michael@0: break; michael@0: } michael@0: currentCodingpassType = (currentCodingpassType + 1) % 3; michael@0: } michael@0: michael@0: var offset = (codeblock.tbx0_ - x0) + (codeblock.tby0_ - y0) * width; michael@0: var sign = bitModel.coefficentsSign; michael@0: var magnitude = bitModel.coefficentsMagnitude; michael@0: var bitsDecoded = bitModel.bitsDecoded; michael@0: var magnitudeCorrection = reversible ? 0 : 0.5; michael@0: var k, n, nb; michael@0: position = 0; michael@0: // Do the interleaving of Section F.3.3 here, so we do not need michael@0: // to copy later. LL level is not interleaved, just copied. michael@0: var interleave = (subband.type !== 'LL'); michael@0: for (j = 0; j < blockHeight; j++) { michael@0: var row = (offset / width) | 0; // row in the non-interleaved subband michael@0: var levelOffset = 2 * row * (levelWidth - width) + right + bottom; michael@0: for (k = 0; k < blockWidth; k++) { michael@0: n = magnitude[position]; michael@0: if (n !== 0) { michael@0: n = (n + magnitudeCorrection) * delta; michael@0: if (sign[position] !== 0) { michael@0: n = -n; michael@0: } michael@0: nb = bitsDecoded[position]; michael@0: var pos = interleave ? (levelOffset + (offset << 1)) : offset; michael@0: if (reversible && (nb >= mb)) { michael@0: coefficients[pos] = n; michael@0: } else { michael@0: coefficients[pos] = n * (1 << (mb - nb)); michael@0: } michael@0: } michael@0: offset++; michael@0: position++; michael@0: } michael@0: offset += width - blockWidth; michael@0: } michael@0: } michael@0: } michael@0: function transformTile(context, tile, c) { michael@0: var component = tile.components[c]; michael@0: var codingStyleParameters = component.codingStyleParameters; michael@0: var quantizationParameters = component.quantizationParameters; michael@0: var decompositionLevelsCount = michael@0: codingStyleParameters.decompositionLevelsCount; michael@0: var spqcds = quantizationParameters.SPqcds; michael@0: var scalarExpounded = quantizationParameters.scalarExpounded; michael@0: var guardBits = quantizationParameters.guardBits; michael@0: var segmentationSymbolUsed = codingStyleParameters.segmentationSymbolUsed; michael@0: var precision = context.components[c].precision; michael@0: michael@0: var reversible = codingStyleParameters.reversibleTransformation; michael@0: var transform = (reversible ? new ReversibleTransform() : michael@0: new IrreversibleTransform()); michael@0: michael@0: var subbandCoefficients = []; michael@0: var b = 0; michael@0: for (var i = 0; i <= decompositionLevelsCount; i++) { michael@0: var resolution = component.resolutions[i]; michael@0: michael@0: var width = resolution.trx1 - resolution.trx0; michael@0: var height = resolution.try1 - resolution.try0; michael@0: // Allocate space for the whole sublevel. michael@0: var coefficients = new Float32Array(width * height); michael@0: michael@0: for (var j = 0, jj = resolution.subbands.length; j < jj; j++) { michael@0: var mu, epsilon; michael@0: if (!scalarExpounded) { michael@0: // formula E-5 michael@0: mu = spqcds[0].mu; michael@0: epsilon = spqcds[0].epsilon + (i > 0 ? 1 - i : 0); michael@0: } else { michael@0: mu = spqcds[b].mu; michael@0: epsilon = spqcds[b].epsilon; michael@0: b++; michael@0: } michael@0: michael@0: var subband = resolution.subbands[j]; michael@0: var gainLog2 = SubbandsGainLog2[subband.type]; michael@0: michael@0: // calulate quantization coefficient (Section E.1.1.1) michael@0: var delta = (reversible ? 1 : michael@0: Math.pow(2, precision + gainLog2 - epsilon) * (1 + mu / 2048)); michael@0: var mb = (guardBits + epsilon - 1); michael@0: michael@0: // In the first resolution level, copyCoefficients will fill the michael@0: // whole array with coefficients. In the succeding passes, michael@0: // copyCoefficients will consecutively fill in the values that belong michael@0: // to the interleaved positions of the HL, LH, and HH coefficients. michael@0: // The LL coefficients will then be interleaved in Transform.iterate(). michael@0: copyCoefficients(coefficients, width, height, subband, delta, mb, michael@0: reversible, segmentationSymbolUsed); michael@0: } michael@0: subbandCoefficients.push({ michael@0: width: width, michael@0: height: height, michael@0: items: coefficients michael@0: }); michael@0: } michael@0: michael@0: var result = transform.calculate(subbandCoefficients, michael@0: component.tcx0, component.tcy0); michael@0: return { michael@0: left: component.tcx0, michael@0: top: component.tcy0, michael@0: width: result.width, michael@0: height: result.height, michael@0: items: result.items michael@0: }; michael@0: } michael@0: function transformComponents(context) { michael@0: var siz = context.SIZ; michael@0: var components = context.components; michael@0: var componentsCount = siz.Csiz; michael@0: var resultImages = []; michael@0: for (var i = 0, ii = context.tiles.length; i < ii; i++) { michael@0: var tile = context.tiles[i]; michael@0: var transformedTiles = []; michael@0: var c; michael@0: for (c = 0; c < componentsCount; c++) { michael@0: transformedTiles[c] = transformTile(context, tile, c); michael@0: } michael@0: var tile0 = transformedTiles[0]; michael@0: var out = new Uint8Array(tile0.items.length * componentsCount); michael@0: var result = { michael@0: left: tile0.left, michael@0: top: tile0.top, michael@0: width: tile0.width, michael@0: height: tile0.height, michael@0: items: out michael@0: }; michael@0: michael@0: // Section G.2.2 Inverse multi component transform michael@0: var shift, offset, max, min; michael@0: var pos = 0, j, jj, y0, y1, y2, r, g, b, k, val; michael@0: if (tile.codingStyleDefaultParameters.multipleComponentTransform) { michael@0: var fourComponents = componentsCount === 4; michael@0: var y0items = transformedTiles[0].items; michael@0: var y1items = transformedTiles[1].items; michael@0: var y2items = transformedTiles[2].items; michael@0: var y3items = fourComponents ? transformedTiles[3].items : null; michael@0: michael@0: // HACK: The multiple component transform formulas below assume that michael@0: // all components have the same precision. With this in mind, we michael@0: // compute shift and offset only once. michael@0: shift = components[0].precision - 8; michael@0: offset = (128 << shift) + 0.5; michael@0: max = (127.5 * (1 << shift)); michael@0: min = -max; michael@0: michael@0: var component0 = tile.components[0]; michael@0: if (!component0.codingStyleParameters.reversibleTransformation) { michael@0: // inverse irreversible multiple component transform michael@0: for (j = 0, jj = y0items.length; j < jj; ++j) { michael@0: y0 = y0items[j]; michael@0: y1 = y1items[j]; michael@0: y2 = y2items[j]; michael@0: r = y0 + 1.402 * y2; michael@0: g = y0 - 0.34413 * y1 - 0.71414 * y2; michael@0: b = y0 + 1.772 * y1; michael@0: out[pos++] = r <= min ? 0 : r >= max ? 255 : (r + offset) >> shift; michael@0: out[pos++] = g <= min ? 0 : g >= max ? 255 : (g + offset) >> shift; michael@0: out[pos++] = b <= min ? 0 : b >= max ? 255 : (b + offset) >> shift; michael@0: if (fourComponents) { michael@0: k = y3items[j]; michael@0: out[pos++] = michael@0: k <= min ? 0 : k >= max ? 255 : (k + offset) >> shift; michael@0: } michael@0: } michael@0: } else { michael@0: // inverse reversible multiple component transform michael@0: for (j = 0, jj = y0items.length; j < jj; ++j) { michael@0: y0 = y0items[j]; michael@0: y1 = y1items[j]; michael@0: y2 = y2items[j]; michael@0: g = y0 - ((y2 + y1) >> 2); michael@0: r = g + y2; michael@0: b = g + y1; michael@0: out[pos++] = r <= min ? 0 : r >= max ? 255 : (r + offset) >> shift; michael@0: out[pos++] = g <= min ? 0 : g >= max ? 255 : (g + offset) >> shift; michael@0: out[pos++] = b <= min ? 0 : b >= max ? 255 : (b + offset) >> shift; michael@0: if (fourComponents) { michael@0: k = y3items[j]; michael@0: out[pos++] = michael@0: k <= min ? 0 : k >= max ? 255 : (k + offset) >> shift; michael@0: } michael@0: } michael@0: } michael@0: } else { // no multi-component transform michael@0: for (c = 0; c < componentsCount; c++) { michael@0: var items = transformedTiles[c].items; michael@0: shift = components[c].precision - 8; michael@0: offset = (128 << shift) + 0.5; michael@0: max = (127.5 * (1 << shift)); michael@0: min = -max; michael@0: for (pos = c, j = 0, jj = items.length; j < jj; j++) { michael@0: val = items[j]; michael@0: out[pos] = val <= min ? 0 : michael@0: val >= max ? 255 : (val + offset) >> shift; michael@0: pos += componentsCount; michael@0: } michael@0: } michael@0: } michael@0: resultImages.push(result); michael@0: } michael@0: return resultImages; michael@0: } michael@0: function initializeTile(context, tileIndex) { michael@0: var siz = context.SIZ; michael@0: var componentsCount = siz.Csiz; michael@0: var tile = context.tiles[tileIndex]; michael@0: for (var c = 0; c < componentsCount; c++) { michael@0: var component = tile.components[c]; michael@0: var qcdOrQcc = (c in context.currentTile.QCC ? michael@0: context.currentTile.QCC[c] : context.currentTile.QCD); michael@0: component.quantizationParameters = qcdOrQcc; michael@0: var codOrCoc = (c in context.currentTile.COC ? michael@0: context.currentTile.COC[c] : context.currentTile.COD); michael@0: component.codingStyleParameters = codOrCoc; michael@0: } michael@0: tile.codingStyleDefaultParameters = context.currentTile.COD; michael@0: } michael@0: michael@0: // Section B.10.2 Tag trees michael@0: var TagTree = (function TagTreeClosure() { michael@0: function TagTree(width, height) { michael@0: var levelsLength = log2(Math.max(width, height)) + 1; michael@0: this.levels = []; michael@0: for (var i = 0; i < levelsLength; i++) { michael@0: var level = { michael@0: width: width, michael@0: height: height, michael@0: items: [] michael@0: }; michael@0: this.levels.push(level); michael@0: width = Math.ceil(width / 2); michael@0: height = Math.ceil(height / 2); michael@0: } michael@0: } michael@0: TagTree.prototype = { michael@0: reset: function TagTree_reset(i, j) { michael@0: var currentLevel = 0, value = 0, level; michael@0: while (currentLevel < this.levels.length) { michael@0: level = this.levels[currentLevel]; michael@0: var index = i + j * level.width; michael@0: if (index in level.items) { michael@0: value = level.items[index]; michael@0: break; michael@0: } michael@0: level.index = index; michael@0: i >>= 1; michael@0: j >>= 1; michael@0: currentLevel++; michael@0: } michael@0: currentLevel--; michael@0: level = this.levels[currentLevel]; michael@0: level.items[level.index] = value; michael@0: this.currentLevel = currentLevel; michael@0: delete this.value; michael@0: }, michael@0: incrementValue: function TagTree_incrementValue() { michael@0: var level = this.levels[this.currentLevel]; michael@0: level.items[level.index]++; michael@0: }, michael@0: nextLevel: function TagTree_nextLevel() { michael@0: var currentLevel = this.currentLevel; michael@0: var level = this.levels[currentLevel]; michael@0: var value = level.items[level.index]; michael@0: currentLevel--; michael@0: if (currentLevel < 0) { michael@0: this.value = value; michael@0: return false; michael@0: } michael@0: michael@0: this.currentLevel = currentLevel; michael@0: level = this.levels[currentLevel]; michael@0: level.items[level.index] = value; michael@0: return true; michael@0: } michael@0: }; michael@0: return TagTree; michael@0: })(); michael@0: michael@0: var InclusionTree = (function InclusionTreeClosure() { michael@0: function InclusionTree(width, height, defaultValue) { michael@0: var levelsLength = log2(Math.max(width, height)) + 1; michael@0: this.levels = []; michael@0: for (var i = 0; i < levelsLength; i++) { michael@0: var items = new Uint8Array(width * height); michael@0: for (var j = 0, jj = items.length; j < jj; j++) { michael@0: items[j] = defaultValue; michael@0: } michael@0: michael@0: var level = { michael@0: width: width, michael@0: height: height, michael@0: items: items michael@0: }; michael@0: this.levels.push(level); michael@0: michael@0: width = Math.ceil(width / 2); michael@0: height = Math.ceil(height / 2); michael@0: } michael@0: } michael@0: InclusionTree.prototype = { michael@0: reset: function InclusionTree_reset(i, j, stopValue) { michael@0: var currentLevel = 0; michael@0: while (currentLevel < this.levels.length) { michael@0: var level = this.levels[currentLevel]; michael@0: var index = i + j * level.width; michael@0: level.index = index; michael@0: var value = level.items[index]; michael@0: michael@0: if (value == 0xFF) { michael@0: break; michael@0: } michael@0: michael@0: if (value > stopValue) { michael@0: this.currentLevel = currentLevel; michael@0: // already know about this one, propagating the value to top levels michael@0: this.propagateValues(); michael@0: return false; michael@0: } michael@0: michael@0: i >>= 1; michael@0: j >>= 1; michael@0: currentLevel++; michael@0: } michael@0: this.currentLevel = currentLevel - 1; michael@0: return true; michael@0: }, michael@0: incrementValue: function InclusionTree_incrementValue(stopValue) { michael@0: var level = this.levels[this.currentLevel]; michael@0: level.items[level.index] = stopValue + 1; michael@0: this.propagateValues(); michael@0: }, michael@0: propagateValues: function InclusionTree_propagateValues() { michael@0: var levelIndex = this.currentLevel; michael@0: var level = this.levels[levelIndex]; michael@0: var currentValue = level.items[level.index]; michael@0: while (--levelIndex >= 0) { michael@0: level = this.levels[levelIndex]; michael@0: level.items[level.index] = currentValue; michael@0: } michael@0: }, michael@0: nextLevel: function InclusionTree_nextLevel() { michael@0: var currentLevel = this.currentLevel; michael@0: var level = this.levels[currentLevel]; michael@0: var value = level.items[level.index]; michael@0: level.items[level.index] = 0xFF; michael@0: currentLevel--; michael@0: if (currentLevel < 0) { michael@0: return false; michael@0: } michael@0: michael@0: this.currentLevel = currentLevel; michael@0: level = this.levels[currentLevel]; michael@0: level.items[level.index] = value; michael@0: return true; michael@0: } michael@0: }; michael@0: return InclusionTree; michael@0: })(); michael@0: michael@0: // Section D. Coefficient bit modeling michael@0: var BitModel = (function BitModelClosure() { michael@0: var UNIFORM_CONTEXT = 17; michael@0: var RUNLENGTH_CONTEXT = 18; michael@0: // Table D-1 michael@0: // The index is binary presentation: 0dddvvhh, ddd - sum of Di (0..4), michael@0: // vv - sum of Vi (0..2), and hh - sum of Hi (0..2) michael@0: var LLAndLHContextsLabel = new Uint8Array([ michael@0: 0, 5, 8, 0, 3, 7, 8, 0, 4, 7, 8, 0, 0, 0, 0, 0, 1, 6, 8, 0, 3, 7, 8, 0, 4, michael@0: 7, 8, 0, 0, 0, 0, 0, 2, 6, 8, 0, 3, 7, 8, 0, 4, 7, 8, 0, 0, 0, 0, 0, 2, 6, michael@0: 8, 0, 3, 7, 8, 0, 4, 7, 8, 0, 0, 0, 0, 0, 2, 6, 8, 0, 3, 7, 8, 0, 4, 7, 8 michael@0: ]); michael@0: var HLContextLabel = new Uint8Array([ michael@0: 0, 3, 4, 0, 5, 7, 7, 0, 8, 8, 8, 0, 0, 0, 0, 0, 1, 3, 4, 0, 6, 7, 7, 0, 8, michael@0: 8, 8, 0, 0, 0, 0, 0, 2, 3, 4, 0, 6, 7, 7, 0, 8, 8, 8, 0, 0, 0, 0, 0, 2, 3, michael@0: 4, 0, 6, 7, 7, 0, 8, 8, 8, 0, 0, 0, 0, 0, 2, 3, 4, 0, 6, 7, 7, 0, 8, 8, 8 michael@0: ]); michael@0: var HHContextLabel = new Uint8Array([ michael@0: 0, 1, 2, 0, 1, 2, 2, 0, 2, 2, 2, 0, 0, 0, 0, 0, 3, 4, 5, 0, 4, 5, 5, 0, 5, michael@0: 5, 5, 0, 0, 0, 0, 0, 6, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 0, 0, 0, 0, 8, 8, michael@0: 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 0, 0, 0, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8 michael@0: ]); michael@0: michael@0: function BitModel(width, height, subband, zeroBitPlanes, mb) { michael@0: this.width = width; michael@0: this.height = height; michael@0: michael@0: this.contextLabelTable = (subband == 'HH' ? HHContextLabel : michael@0: (subband == 'HL' ? HLContextLabel : LLAndLHContextsLabel)); michael@0: michael@0: var coefficientCount = width * height; michael@0: michael@0: // coefficients outside the encoding region treated as insignificant michael@0: // add border state cells for significanceState michael@0: this.neighborsSignificance = new Uint8Array(coefficientCount); michael@0: this.coefficentsSign = new Uint8Array(coefficientCount); michael@0: this.coefficentsMagnitude = mb > 14 ? new Uint32Array(coefficientCount) : michael@0: mb > 6 ? new Uint16Array(coefficientCount) : michael@0: new Uint8Array(coefficientCount); michael@0: this.processingFlags = new Uint8Array(coefficientCount); michael@0: michael@0: var bitsDecoded = new Uint8Array(coefficientCount); michael@0: if (zeroBitPlanes !== 0) { michael@0: for (var i = 0; i < coefficientCount; i++) { michael@0: bitsDecoded[i] = zeroBitPlanes; michael@0: } michael@0: } michael@0: this.bitsDecoded = bitsDecoded; michael@0: michael@0: this.reset(); michael@0: } michael@0: michael@0: BitModel.prototype = { michael@0: setDecoder: function BitModel_setDecoder(decoder) { michael@0: this.decoder = decoder; michael@0: }, michael@0: reset: function BitModel_reset() { michael@0: // We have 17 contexts that are accessed via context labels, michael@0: // plus the uniform and runlength context. michael@0: this.contexts = new Int8Array(19); michael@0: michael@0: // Contexts are packed into 1 byte: michael@0: // highest 7 bits carry the index, lowest bit carries mps michael@0: this.contexts[0] = (4 << 1) | 0; michael@0: this.contexts[UNIFORM_CONTEXT] = (46 << 1) | 0; michael@0: this.contexts[RUNLENGTH_CONTEXT] = (3 << 1) | 0; michael@0: }, michael@0: setNeighborsSignificance: michael@0: function BitModel_setNeighborsSignificance(row, column, index) { michael@0: var neighborsSignificance = this.neighborsSignificance; michael@0: var width = this.width, height = this.height; michael@0: var left = (column > 0); michael@0: var right = (column + 1 < width); michael@0: var i; michael@0: michael@0: if (row > 0) { michael@0: i = index - width; michael@0: if (left) { michael@0: neighborsSignificance[i - 1] += 0x10; michael@0: } michael@0: if (right) { michael@0: neighborsSignificance[i + 1] += 0x10; michael@0: } michael@0: neighborsSignificance[i] += 0x04; michael@0: } michael@0: michael@0: if (row + 1 < height) { michael@0: i = index + width; michael@0: if (left) { michael@0: neighborsSignificance[i - 1] += 0x10; michael@0: } michael@0: if (right) { michael@0: neighborsSignificance[i + 1] += 0x10; michael@0: } michael@0: neighborsSignificance[i] += 0x04; michael@0: } michael@0: michael@0: if (left) { michael@0: neighborsSignificance[index - 1] += 0x01; michael@0: } michael@0: if (right) { michael@0: neighborsSignificance[index + 1] += 0x01; michael@0: } michael@0: neighborsSignificance[index] |= 0x80; michael@0: }, michael@0: runSignificancePropogationPass: michael@0: function BitModel_runSignificancePropogationPass() { michael@0: var decoder = this.decoder; michael@0: var width = this.width, height = this.height; michael@0: var coefficentsMagnitude = this.coefficentsMagnitude; michael@0: var coefficentsSign = this.coefficentsSign; michael@0: var neighborsSignificance = this.neighborsSignificance; michael@0: var processingFlags = this.processingFlags; michael@0: var contexts = this.contexts; michael@0: var labels = this.contextLabelTable; michael@0: var bitsDecoded = this.bitsDecoded; michael@0: var processedInverseMask = ~1; michael@0: var processedMask = 1; michael@0: var firstMagnitudeBitMask = 2; michael@0: michael@0: for (var i0 = 0; i0 < height; i0 += 4) { michael@0: for (var j = 0; j < width; j++) { michael@0: var index = i0 * width + j; michael@0: for (var i1 = 0; i1 < 4; i1++, index += width) { michael@0: var i = i0 + i1; michael@0: if (i >= height) { michael@0: break; michael@0: } michael@0: // clear processed flag first michael@0: processingFlags[index] &= processedInverseMask; michael@0: michael@0: if (coefficentsMagnitude[index] || michael@0: !neighborsSignificance[index]) { michael@0: continue; michael@0: } michael@0: michael@0: var contextLabel = labels[neighborsSignificance[index]]; michael@0: var decision = decoder.readBit(contexts, contextLabel); michael@0: if (decision) { michael@0: var sign = this.decodeSignBit(i, j, index); michael@0: coefficentsSign[index] = sign; michael@0: coefficentsMagnitude[index] = 1; michael@0: this.setNeighborsSignificance(i, j, index); michael@0: processingFlags[index] |= firstMagnitudeBitMask; michael@0: } michael@0: bitsDecoded[index]++; michael@0: processingFlags[index] |= processedMask; michael@0: } michael@0: } michael@0: } michael@0: }, michael@0: decodeSignBit: function BitModel_decodeSignBit(row, column, index) { michael@0: var width = this.width, height = this.height; michael@0: var coefficentsMagnitude = this.coefficentsMagnitude; michael@0: var coefficentsSign = this.coefficentsSign; michael@0: var contribution, sign0, sign1, significance1; michael@0: var contextLabel, decoded; michael@0: michael@0: // calculate horizontal contribution michael@0: significance1 = (column > 0 && coefficentsMagnitude[index - 1] !== 0); michael@0: if (column + 1 < width && coefficentsMagnitude[index + 1] !== 0) { michael@0: sign1 = coefficentsSign[index + 1]; michael@0: if (significance1) { michael@0: sign0 = coefficentsSign[index - 1]; michael@0: contribution = 1 - sign1 - sign0; michael@0: } else { michael@0: contribution = 1 - sign1 - sign1; michael@0: } michael@0: } else if (significance1) { michael@0: sign0 = coefficentsSign[index - 1]; michael@0: contribution = 1 - sign0 - sign0; michael@0: } else { michael@0: contribution = 0; michael@0: } michael@0: var horizontalContribution = 3 * contribution; michael@0: michael@0: // calculate vertical contribution and combine with the horizontal michael@0: significance1 = (row > 0 && coefficentsMagnitude[index - width] !== 0); michael@0: if (row + 1 < height && coefficentsMagnitude[index + width] !== 0) { michael@0: sign1 = coefficentsSign[index + width]; michael@0: if (significance1) { michael@0: sign0 = coefficentsSign[index - width]; michael@0: contribution = 1 - sign1 - sign0 + horizontalContribution; michael@0: } else { michael@0: contribution = 1 - sign1 - sign1 + horizontalContribution; michael@0: } michael@0: } else if (significance1) { michael@0: sign0 = coefficentsSign[index - width]; michael@0: contribution = 1 - sign0 - sign0 + horizontalContribution; michael@0: } else { michael@0: contribution = horizontalContribution; michael@0: } michael@0: michael@0: if (contribution >= 0) { michael@0: contextLabel = 9 + contribution; michael@0: decoded = this.decoder.readBit(this.contexts, contextLabel); michael@0: } else { michael@0: contextLabel = 9 - contribution; michael@0: decoded = this.decoder.readBit(this.contexts, contextLabel) ^ 1; michael@0: } michael@0: return decoded; michael@0: }, michael@0: runMagnitudeRefinementPass: michael@0: function BitModel_runMagnitudeRefinementPass() { michael@0: var decoder = this.decoder; michael@0: var width = this.width, height = this.height; michael@0: var coefficentsMagnitude = this.coefficentsMagnitude; michael@0: var neighborsSignificance = this.neighborsSignificance; michael@0: var contexts = this.contexts; michael@0: var bitsDecoded = this.bitsDecoded; michael@0: var processingFlags = this.processingFlags; michael@0: var processedMask = 1; michael@0: var firstMagnitudeBitMask = 2; michael@0: var length = width * height; michael@0: var width4 = width * 4; michael@0: michael@0: for (var index0 = 0, indexNext; index0 < length; index0 = indexNext) { michael@0: indexNext = Math.min(length, index0 + width4); michael@0: for (var j = 0; j < width; j++) { michael@0: for (var index = index0 + j; index < indexNext; index += width) { michael@0: michael@0: // significant but not those that have just become michael@0: if (!coefficentsMagnitude[index] || michael@0: (processingFlags[index] & processedMask) !== 0) { michael@0: continue; michael@0: } michael@0: michael@0: var contextLabel = 16; michael@0: if ((processingFlags[index] & firstMagnitudeBitMask) !== 0) { michael@0: processingFlags[index] ^= firstMagnitudeBitMask; michael@0: // first refinement michael@0: var significance = neighborsSignificance[index] & 127; michael@0: contextLabel = significance === 0 ? 15 : 14; michael@0: } michael@0: michael@0: var bit = decoder.readBit(contexts, contextLabel); michael@0: coefficentsMagnitude[index] = michael@0: (coefficentsMagnitude[index] << 1) | bit; michael@0: bitsDecoded[index]++; michael@0: processingFlags[index] |= processedMask; michael@0: } michael@0: } michael@0: } michael@0: }, michael@0: runCleanupPass: function BitModel_runCleanupPass() { michael@0: var decoder = this.decoder; michael@0: var width = this.width, height = this.height; michael@0: var neighborsSignificance = this.neighborsSignificance; michael@0: var coefficentsMagnitude = this.coefficentsMagnitude; michael@0: var coefficentsSign = this.coefficentsSign; michael@0: var contexts = this.contexts; michael@0: var labels = this.contextLabelTable; michael@0: var bitsDecoded = this.bitsDecoded; michael@0: var processingFlags = this.processingFlags; michael@0: var processedMask = 1; michael@0: var firstMagnitudeBitMask = 2; michael@0: var oneRowDown = width; michael@0: var twoRowsDown = width * 2; michael@0: var threeRowsDown = width * 3; michael@0: var iNext; michael@0: for (var i0 = 0; i0 < height; i0 = iNext) { michael@0: iNext = Math.min(i0 + 4, height); michael@0: var indexBase = i0 * width; michael@0: var checkAllEmpty = i0 + 3 < height; michael@0: for (var j = 0; j < width; j++) { michael@0: var index0 = indexBase + j; michael@0: // using the property: labels[neighborsSignificance[index]] == 0 michael@0: // when neighborsSignificance[index] == 0 michael@0: var allEmpty = (checkAllEmpty && michael@0: processingFlags[index0] === 0 && michael@0: processingFlags[index0 + oneRowDown] === 0 && michael@0: processingFlags[index0 + twoRowsDown] === 0 && michael@0: processingFlags[index0 + threeRowsDown] === 0 && michael@0: neighborsSignificance[index0] === 0 && michael@0: neighborsSignificance[index0 + oneRowDown] === 0 && michael@0: neighborsSignificance[index0 + twoRowsDown] === 0 && michael@0: neighborsSignificance[index0 + threeRowsDown] === 0); michael@0: var i1 = 0, index = index0; michael@0: var i = i0, sign; michael@0: if (allEmpty) { michael@0: var hasSignificantCoefficent = michael@0: decoder.readBit(contexts, RUNLENGTH_CONTEXT); michael@0: if (!hasSignificantCoefficent) { michael@0: bitsDecoded[index0]++; michael@0: bitsDecoded[index0 + oneRowDown]++; michael@0: bitsDecoded[index0 + twoRowsDown]++; michael@0: bitsDecoded[index0 + threeRowsDown]++; michael@0: continue; // next column michael@0: } michael@0: i1 = (decoder.readBit(contexts, UNIFORM_CONTEXT) << 1) | michael@0: decoder.readBit(contexts, UNIFORM_CONTEXT); michael@0: if (i1 !== 0) { michael@0: i = i0 + i1; michael@0: index += i1 * width; michael@0: } michael@0: michael@0: sign = this.decodeSignBit(i, j, index); michael@0: coefficentsSign[index] = sign; michael@0: coefficentsMagnitude[index] = 1; michael@0: this.setNeighborsSignificance(i, j, index); michael@0: processingFlags[index] |= firstMagnitudeBitMask; michael@0: michael@0: index = index0; michael@0: for (var i2 = i0; i2 <= i; i2++, index += width) { michael@0: bitsDecoded[index]++; michael@0: } michael@0: michael@0: i1++; michael@0: } michael@0: for (i = i0 + i1; i < iNext; i++, index += width) { michael@0: if (coefficentsMagnitude[index] || michael@0: (processingFlags[index] & processedMask) !== 0) { michael@0: continue; michael@0: } michael@0: michael@0: var contextLabel = labels[neighborsSignificance[index]]; michael@0: var decision = decoder.readBit(contexts, contextLabel); michael@0: if (decision === 1) { michael@0: sign = this.decodeSignBit(i, j, index); michael@0: coefficentsSign[index] = sign; michael@0: coefficentsMagnitude[index] = 1; michael@0: this.setNeighborsSignificance(i, j, index); michael@0: processingFlags[index] |= firstMagnitudeBitMask; michael@0: } michael@0: bitsDecoded[index]++; michael@0: } michael@0: } michael@0: } michael@0: }, michael@0: checkSegmentationSymbol: function BitModel_checkSegmentationSymbol() { michael@0: var decoder = this.decoder; michael@0: var contexts = this.contexts; michael@0: var symbol = (decoder.readBit(contexts, UNIFORM_CONTEXT) << 3) | michael@0: (decoder.readBit(contexts, UNIFORM_CONTEXT) << 2) | michael@0: (decoder.readBit(contexts, UNIFORM_CONTEXT) << 1) | michael@0: decoder.readBit(contexts, UNIFORM_CONTEXT); michael@0: if (symbol != 0xA) { michael@0: throw 'Invalid segmentation symbol'; michael@0: } michael@0: } michael@0: }; michael@0: michael@0: return BitModel; michael@0: })(); michael@0: michael@0: // Section F, Discrete wavelet transformation michael@0: var Transform = (function TransformClosure() { michael@0: function Transform() {} michael@0: michael@0: Transform.prototype.calculate = michael@0: function transformCalculate(subbands, u0, v0) { michael@0: var ll = subbands[0]; michael@0: for (var i = 1, ii = subbands.length; i < ii; i++) { michael@0: ll = this.iterate(ll, subbands[i], u0, v0); michael@0: } michael@0: return ll; michael@0: }; michael@0: Transform.prototype.extend = function extend(buffer, offset, size) { michael@0: // Section F.3.7 extending... using max extension of 4 michael@0: var i1 = offset - 1, j1 = offset + 1; michael@0: var i2 = offset + size - 2, j2 = offset + size; michael@0: buffer[i1--] = buffer[j1++]; michael@0: buffer[j2++] = buffer[i2--]; michael@0: buffer[i1--] = buffer[j1++]; michael@0: buffer[j2++] = buffer[i2--]; michael@0: buffer[i1--] = buffer[j1++]; michael@0: buffer[j2++] = buffer[i2--]; michael@0: buffer[i1] = buffer[j1]; michael@0: buffer[j2] = buffer[i2]; michael@0: }; michael@0: Transform.prototype.iterate = function Transform_iterate(ll, hl_lh_hh, michael@0: u0, v0) { michael@0: var llWidth = ll.width, llHeight = ll.height, llItems = ll.items; michael@0: var width = hl_lh_hh.width; michael@0: var height = hl_lh_hh.height; michael@0: var items = hl_lh_hh.items; michael@0: var i, j, k, l, u, v; michael@0: michael@0: // Interleave LL according to Section F.3.3 michael@0: for (k = 0, i = 0; i < llHeight; i++) { michael@0: l = i * 2 * width; michael@0: for (j = 0; j < llWidth; j++, k++, l += 2) { michael@0: items[l] = llItems[k]; michael@0: } michael@0: } michael@0: // The LL band is not needed anymore. michael@0: llItems = ll.items = null; michael@0: michael@0: var bufferPadding = 4; michael@0: var rowBuffer = new Float32Array(width + 2 * bufferPadding); michael@0: michael@0: // Section F.3.4 HOR_SR michael@0: if (width === 1) { michael@0: // if width = 1, when u0 even keep items as is, when odd divide by 2 michael@0: if ((u0 & 1) !== 0) { michael@0: for (v = 0, k = 0; v < height; v++, k += width) { michael@0: items[k] *= 0.5; michael@0: } michael@0: } michael@0: } else { michael@0: for (v = 0, k = 0; v < height; v++, k += width) { michael@0: rowBuffer.set(items.subarray(k, k + width), bufferPadding); michael@0: michael@0: this.extend(rowBuffer, bufferPadding, width); michael@0: this.filter(rowBuffer, bufferPadding, width); michael@0: michael@0: items.set( michael@0: rowBuffer.subarray(bufferPadding, bufferPadding + width), michael@0: k); michael@0: } michael@0: } michael@0: michael@0: // Accesses to the items array can take long, because it may not fit into michael@0: // CPU cache and has to be fetched from main memory. Since subsequent michael@0: // accesses to the items array are not local when reading columns, we michael@0: // have a cache miss every time. To reduce cache misses, get up to michael@0: // 'numBuffers' items at a time and store them into the individual michael@0: // buffers. The colBuffers should be small enough to fit into CPU cache. michael@0: var numBuffers = 16; michael@0: var colBuffers = []; michael@0: for (i = 0; i < numBuffers; i++) { michael@0: colBuffers.push(new Float32Array(height + 2 * bufferPadding)); michael@0: } michael@0: var b, currentBuffer = 0; michael@0: ll = bufferPadding + height; michael@0: michael@0: // Section F.3.5 VER_SR michael@0: if (height === 1) { michael@0: // if height = 1, when v0 even keep items as is, when odd divide by 2 michael@0: if ((v0 & 1) !== 0) { michael@0: for (u = 0; u < width; u++) { michael@0: items[u] *= 0.5; michael@0: } michael@0: } michael@0: } else { michael@0: for (u = 0; u < width; u++) { michael@0: // if we ran out of buffers, copy several image columns at once michael@0: if (currentBuffer === 0) { michael@0: numBuffers = Math.min(width - u, numBuffers); michael@0: for (k = u, l = bufferPadding; l < ll; k += width, l++) { michael@0: for (b = 0; b < numBuffers; b++) { michael@0: colBuffers[b][l] = items[k + b]; michael@0: } michael@0: } michael@0: currentBuffer = numBuffers; michael@0: } michael@0: michael@0: currentBuffer--; michael@0: var buffer = colBuffers[currentBuffer]; michael@0: this.extend(buffer, bufferPadding, height); michael@0: this.filter(buffer, bufferPadding, height); michael@0: michael@0: // If this is last buffer in this group of buffers, flush all buffers. michael@0: if (currentBuffer === 0) { michael@0: k = u - numBuffers + 1; michael@0: for (l = bufferPadding; l < ll; k += width, l++) { michael@0: for (b = 0; b < numBuffers; b++) { michael@0: items[k + b] = colBuffers[b][l]; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: return { michael@0: width: width, michael@0: height: height, michael@0: items: items michael@0: }; michael@0: }; michael@0: return Transform; michael@0: })(); michael@0: michael@0: // Section 3.8.2 Irreversible 9-7 filter michael@0: var IrreversibleTransform = (function IrreversibleTransformClosure() { michael@0: function IrreversibleTransform() { michael@0: Transform.call(this); michael@0: } michael@0: michael@0: IrreversibleTransform.prototype = Object.create(Transform.prototype); michael@0: IrreversibleTransform.prototype.filter = michael@0: function irreversibleTransformFilter(x, offset, length) { michael@0: var len = length >> 1; michael@0: offset = offset | 0; michael@0: var j, n, current, next; michael@0: michael@0: var alpha = -1.586134342059924; michael@0: var beta = -0.052980118572961; michael@0: var gamma = 0.882911075530934; michael@0: var delta = 0.443506852043971; michael@0: var K = 1.230174104914001; michael@0: var K_ = 1 / K; michael@0: michael@0: // step 1 is combined with step 3 michael@0: michael@0: // step 2 michael@0: j = offset - 3; michael@0: for (n = len + 4; n--; j += 2) { michael@0: x[j] *= K_; michael@0: } michael@0: michael@0: // step 1 & 3 michael@0: j = offset - 2; michael@0: current = delta * x[j -1]; michael@0: for (n = len + 3; n--; j += 2) { michael@0: next = delta * x[j + 1]; michael@0: x[j] = K * x[j] - current - next; michael@0: if (n--) { michael@0: j += 2; michael@0: current = delta * x[j + 1]; michael@0: x[j] = K * x[j] - current - next; michael@0: } else { michael@0: break; michael@0: } michael@0: } michael@0: michael@0: // step 4 michael@0: j = offset - 1; michael@0: current = gamma * x[j - 1]; michael@0: for (n = len + 2; n--; j += 2) { michael@0: next = gamma * x[j + 1]; michael@0: x[j] -= current + next; michael@0: if (n--) { michael@0: j += 2; michael@0: current = gamma * x[j + 1]; michael@0: x[j] -= current + next; michael@0: } else { michael@0: break; michael@0: } michael@0: } michael@0: michael@0: // step 5 michael@0: j = offset; michael@0: current = beta * x[j - 1]; michael@0: for (n = len + 1; n--; j += 2) { michael@0: next = beta * x[j + 1]; michael@0: x[j] -= current + next; michael@0: if (n--) { michael@0: j += 2; michael@0: current = beta * x[j + 1]; michael@0: x[j] -= current + next; michael@0: } else { michael@0: break; michael@0: } michael@0: } michael@0: michael@0: // step 6 michael@0: if (len !== 0) { michael@0: j = offset + 1; michael@0: current = alpha * x[j - 1]; michael@0: for (n = len; n--; j += 2) { michael@0: next = alpha * x[j + 1]; michael@0: x[j] -= current + next; michael@0: if (n--) { michael@0: j += 2; michael@0: current = alpha * x[j + 1]; michael@0: x[j] -= current + next; michael@0: } else { michael@0: break; michael@0: } michael@0: } michael@0: } michael@0: }; michael@0: michael@0: return IrreversibleTransform; michael@0: })(); michael@0: michael@0: // Section 3.8.1 Reversible 5-3 filter michael@0: var ReversibleTransform = (function ReversibleTransformClosure() { michael@0: function ReversibleTransform() { michael@0: Transform.call(this); michael@0: } michael@0: michael@0: ReversibleTransform.prototype = Object.create(Transform.prototype); michael@0: ReversibleTransform.prototype.filter = michael@0: function reversibleTransformFilter(x, offset, length) { michael@0: var len = length >> 1; michael@0: offset = offset | 0; michael@0: var j, n; michael@0: michael@0: for (j = offset, n = len + 1; n--; j += 2) { michael@0: x[j] -= (x[j - 1] + x[j + 1] + 2) >> 2; michael@0: } michael@0: michael@0: for (j = offset + 1, n = len; n--; j += 2) { michael@0: x[j] += (x[j - 1] + x[j + 1]) >> 1; michael@0: } michael@0: }; michael@0: michael@0: return ReversibleTransform; michael@0: })(); michael@0: michael@0: return JpxImage; michael@0: })(); michael@0: michael@0: michael@0: michael@0: var Jbig2Image = (function Jbig2ImageClosure() { michael@0: // Utility data structures michael@0: function ContextCache() {} michael@0: michael@0: ContextCache.prototype = { michael@0: getContexts: function(id) { michael@0: if (id in this) { michael@0: return this[id]; michael@0: } michael@0: return (this[id] = new Int8Array(1<<16)); michael@0: } michael@0: }; michael@0: michael@0: function DecodingContext(data, start, end) { michael@0: this.data = data; michael@0: this.start = start; michael@0: this.end = end; michael@0: } michael@0: michael@0: DecodingContext.prototype = { michael@0: get decoder() { michael@0: var decoder = new ArithmeticDecoder(this.data, this.start, this.end); michael@0: return shadow(this, 'decoder', decoder); michael@0: }, michael@0: get contextCache() { michael@0: var cache = new ContextCache(); michael@0: return shadow(this, 'contextCache', cache); michael@0: } michael@0: }; michael@0: michael@0: // Annex A. Arithmetic Integer Decoding Procedure michael@0: // A.2 Procedure for decoding values michael@0: function decodeInteger(contextCache, procedure, decoder) { michael@0: var contexts = contextCache.getContexts(procedure); michael@0: michael@0: var prev = 1; michael@0: var state = 1, v = 0, s; michael@0: var toRead = 32, offset = 4436; // defaults for state 7 michael@0: while (state) { michael@0: var bit = decoder.readBit(contexts, prev); michael@0: prev = (prev < 256 ? (prev << 1) | bit : michael@0: (((prev << 1) | bit) & 511) | 256); michael@0: switch (state) { michael@0: case 1: michael@0: s = !!bit; michael@0: break; michael@0: case 2: michael@0: if (bit) { michael@0: break; michael@0: } michael@0: state = 7; michael@0: toRead = 2; michael@0: offset = 0; michael@0: break; michael@0: case 3: michael@0: if (bit) { michael@0: break; michael@0: } michael@0: state = 7; michael@0: toRead = 4; michael@0: offset = 4; michael@0: break; michael@0: case 4: michael@0: if (bit) { michael@0: break; michael@0: } michael@0: state = 7; michael@0: toRead = 6; michael@0: offset = 20; michael@0: break; michael@0: case 5: michael@0: if (bit) { michael@0: break; michael@0: } michael@0: state = 7; michael@0: toRead = 8; michael@0: offset = 84; michael@0: break; michael@0: case 6: michael@0: if (bit) { michael@0: break; michael@0: } michael@0: state = 7; michael@0: toRead = 12; michael@0: offset = 340; michael@0: break; michael@0: default: michael@0: v = ((v << 1) | bit) >>> 0; michael@0: if (--toRead === 0) { michael@0: state = 0; michael@0: } michael@0: continue; michael@0: } michael@0: state++; michael@0: } michael@0: v += offset; michael@0: return (!s ? v : (v > 0 ? -v : null)); michael@0: } michael@0: michael@0: // A.3 The IAID decoding procedure michael@0: function decodeIAID(contextCache, decoder, codeLength) { michael@0: var contexts = contextCache.getContexts('IAID'); michael@0: michael@0: var prev = 1; michael@0: for (var i = 0; i < codeLength; i++) { michael@0: var bit = decoder.readBit(contexts, prev); michael@0: prev = (prev << 1) | bit; michael@0: } michael@0: if (codeLength < 31) { michael@0: return prev & ((1 << codeLength) - 1); michael@0: } michael@0: return prev & 0x7FFFFFFF; michael@0: } michael@0: michael@0: // 7.3 Segment types michael@0: var SegmentTypes = [ michael@0: 'SymbolDictionary', null, null, null, 'IntermediateTextRegion', null, michael@0: 'ImmediateTextRegion', 'ImmediateLosslessTextRegion', null, null, null, michael@0: null, null, null, null, null, 'patternDictionary', null, null, null, michael@0: 'IntermediateHalftoneRegion', null, 'ImmediateHalftoneRegion', michael@0: 'ImmediateLosslessHalftoneRegion', null, null, null, null, null, null, null, michael@0: null, null, null, null, null, 'IntermediateGenericRegion', null, michael@0: 'ImmediateGenericRegion', 'ImmediateLosslessGenericRegion', michael@0: 'IntermediateGenericRefinementRegion', null, michael@0: 'ImmediateGenericRefinementRegion', michael@0: 'ImmediateLosslessGenericRefinementRegion', null, null, null, null, michael@0: 'PageInformation', 'EndOfPage', 'EndOfStripe', 'EndOfFile', 'Profiles', michael@0: 'Tables', null, null, null, null, null, null, null, null, michael@0: 'Extension' michael@0: ]; michael@0: michael@0: var CodingTemplates = [ michael@0: [{x: -1, y: -2}, {x: 0, y: -2}, {x: 1, y: -2}, {x: -2, y: -1}, michael@0: {x: -1, y: -1}, {x: 0, y: -1}, {x: 1, y: -1}, {x: 2, y: -1}, michael@0: {x: -4, y: 0}, {x: -3, y: 0}, {x: -2, y: 0}, {x: -1, y: 0}], michael@0: [{x: -1, y: -2}, {x: 0, y: -2}, {x: 1, y: -2}, {x: 2, y: -2}, michael@0: {x: -2, y: -1}, {x: -1, y: -1}, {x: 0, y: -1}, {x: 1, y: -1}, michael@0: {x: 2, y: -1}, {x: -3, y: 0}, {x: -2, y: 0}, {x: -1, y: 0}], michael@0: [{x: -1, y: -2}, {x: 0, y: -2}, {x: 1, y: -2}, {x: -2, y: -1}, michael@0: {x: -1, y: -1}, {x: 0, y: -1}, {x: 1, y: -1}, {x: -2, y: 0}, michael@0: {x: -1, y: 0}], michael@0: [{x: -3, y: -1}, {x: -2, y: -1}, {x: -1, y: -1}, {x: 0, y: -1}, michael@0: {x: 1, y: -1}, {x: -4, y: 0}, {x: -3, y: 0}, {x: -2, y: 0}, {x: -1, y: 0}] michael@0: ]; michael@0: michael@0: var RefinementTemplates = [ michael@0: { michael@0: coding: [{x: 0, y: -1}, {x: 1, y: -1}, {x: -1, y: 0}], michael@0: reference: [{x: 0, y: -1}, {x: 1, y: -1}, {x: -1, y: 0}, {x: 0, y: 0}, michael@0: {x: 1, y: 0}, {x: -1, y: 1}, {x: 0, y: 1}, {x: 1, y: 1}] michael@0: }, michael@0: { michael@0: coding: [{x: -1, y: -1}, {x: 0, y: -1}, {x: 1, y: -1}, {x: -1, y: 0}], michael@0: reference: [{x: 0, y: -1}, {x: -1, y: 0}, {x: 0, y: 0}, {x: 1, y: 0}, michael@0: {x: 0, y: 1}, {x: 1, y: 1}] michael@0: } michael@0: ]; michael@0: michael@0: var ReusedContexts = [ michael@0: 0x1CD3, // '00111001101' (template) + '0011' (at), michael@0: 0x079A, // '001111001101' + '0', michael@0: 0x00E3, // '001110001' + '1', michael@0: 0x018B // '011000101' + '1' michael@0: ]; michael@0: michael@0: var RefinementReusedContexts = [ michael@0: 0x0020, // '000' + '0' (coding) + '00010000' + '0' (reference) michael@0: 0x0008 // '0000' + '001000' michael@0: ]; michael@0: michael@0: // 6.2 Generic Region Decoding Procedure michael@0: function decodeBitmap(mmr, width, height, templateIndex, prediction, skip, at, michael@0: decodingContext) { michael@0: if (mmr) { michael@0: error('JBIG2 error: MMR encoding is not supported'); michael@0: } michael@0: michael@0: var useskip = !!skip; michael@0: var template = CodingTemplates[templateIndex].concat(at); michael@0: michael@0: // Sorting is non-standard, and it is not required. But sorting increases michael@0: // the number of template bits that can be reused from the previous michael@0: // contextLabel in the main loop. michael@0: template.sort(function (a, b) { michael@0: return (a.y - b.y) || (a.x - b.x); michael@0: }); michael@0: michael@0: var templateLength = template.length; michael@0: var templateX = new Int8Array(templateLength); michael@0: var templateY = new Int8Array(templateLength); michael@0: var changingTemplateEntries = []; michael@0: var reuseMask = 0, minX = 0, maxX = 0, minY = 0; michael@0: var c, k; michael@0: michael@0: for (k = 0; k < templateLength; k++) { michael@0: templateX[k] = template[k].x; michael@0: templateY[k] = template[k].y; michael@0: minX = Math.min(minX, template[k].x); michael@0: maxX = Math.max(maxX, template[k].x); michael@0: minY = Math.min(minY, template[k].y); michael@0: // Check if the template pixel appears in two consecutive context labels, michael@0: // so it can be reused. Otherwise, we add it to the list of changing michael@0: // template entries. michael@0: if (k < templateLength - 1 && michael@0: template[k].y === template[k + 1].y && michael@0: template[k].x === template[k + 1].x - 1) { michael@0: reuseMask |= 1 << (templateLength - 1 - k); michael@0: } else { michael@0: changingTemplateEntries.push(k); michael@0: } michael@0: } michael@0: var changingEntriesLength = changingTemplateEntries.length; michael@0: michael@0: var changingTemplateX = new Int8Array(changingEntriesLength); michael@0: var changingTemplateY = new Int8Array(changingEntriesLength); michael@0: var changingTemplateBit = new Uint16Array(changingEntriesLength); michael@0: for (c = 0; c < changingEntriesLength; c++) { michael@0: k = changingTemplateEntries[c]; michael@0: changingTemplateX[c] = template[k].x; michael@0: changingTemplateY[c] = template[k].y; michael@0: changingTemplateBit[c] = 1 << (templateLength - 1 - k); michael@0: } michael@0: michael@0: // Get the safe bounding box edges from the width, height, minX, maxX, minY michael@0: var sbb_left = -minX; michael@0: var sbb_top = -minY; michael@0: var sbb_right = width - maxX; michael@0: michael@0: var pseudoPixelContext = ReusedContexts[templateIndex]; michael@0: var row = new Uint8Array(width); michael@0: var bitmap = []; michael@0: michael@0: var decoder = decodingContext.decoder; michael@0: var contexts = decodingContext.contextCache.getContexts('GB'); michael@0: michael@0: var ltp = 0, j, i0, j0, contextLabel = 0, bit, shift; michael@0: for (var i = 0; i < height; i++) { michael@0: if (prediction) { michael@0: var sltp = decoder.readBit(contexts, pseudoPixelContext); michael@0: ltp ^= sltp; michael@0: if (ltp) { michael@0: bitmap.push(row); // duplicate previous row michael@0: continue; michael@0: } michael@0: } michael@0: row = new Uint8Array(row); michael@0: bitmap.push(row); michael@0: for (j = 0; j < width; j++) { michael@0: if (useskip && skip[i][j]) { michael@0: row[j] = 0; michael@0: continue; michael@0: } michael@0: // Are we in the middle of a scanline, so we can reuse contextLabel michael@0: // bits? michael@0: if (j >= sbb_left && j < sbb_right && i >= sbb_top) { michael@0: // If yes, we can just shift the bits that are reusable and only michael@0: // fetch the remaining ones. michael@0: contextLabel = (contextLabel << 1) & reuseMask; michael@0: for (k = 0; k < changingEntriesLength; k++) { michael@0: i0 = i + changingTemplateY[k]; michael@0: j0 = j + changingTemplateX[k]; michael@0: bit = bitmap[i0][j0]; michael@0: if (bit) { michael@0: bit = changingTemplateBit[k]; michael@0: contextLabel |= bit; michael@0: } michael@0: } michael@0: } else { michael@0: // compute the contextLabel from scratch michael@0: contextLabel = 0; michael@0: shift = templateLength - 1; michael@0: for (k = 0; k < templateLength; k++, shift--) { michael@0: j0 = j + templateX[k]; michael@0: if (j0 >= 0 && j0 < width) { michael@0: i0 = i + templateY[k]; michael@0: if (i0 >= 0) { michael@0: bit = bitmap[i0][j0]; michael@0: if (bit) { michael@0: contextLabel |= bit << shift; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: var pixel = decoder.readBit(contexts, contextLabel); michael@0: row[j] = pixel; michael@0: } michael@0: } michael@0: return bitmap; michael@0: } michael@0: michael@0: // 6.3.2 Generic Refinement Region Decoding Procedure michael@0: function decodeRefinement(width, height, templateIndex, referenceBitmap, michael@0: offsetX, offsetY, prediction, at, michael@0: decodingContext) { michael@0: var codingTemplate = RefinementTemplates[templateIndex].coding; michael@0: if (templateIndex === 0) { michael@0: codingTemplate = codingTemplate.concat([at[0]]); michael@0: } michael@0: var codingTemplateLength = codingTemplate.length; michael@0: var codingTemplateX = new Int32Array(codingTemplateLength); michael@0: var codingTemplateY = new Int32Array(codingTemplateLength); michael@0: var k; michael@0: for (k = 0; k < codingTemplateLength; k++) { michael@0: codingTemplateX[k] = codingTemplate[k].x; michael@0: codingTemplateY[k] = codingTemplate[k].y; michael@0: } michael@0: michael@0: var referenceTemplate = RefinementTemplates[templateIndex].reference; michael@0: if (templateIndex === 0) { michael@0: referenceTemplate = referenceTemplate.concat([at[1]]); michael@0: } michael@0: var referenceTemplateLength = referenceTemplate.length; michael@0: var referenceTemplateX = new Int32Array(referenceTemplateLength); michael@0: var referenceTemplateY = new Int32Array(referenceTemplateLength); michael@0: for (k = 0; k < referenceTemplateLength; k++) { michael@0: referenceTemplateX[k] = referenceTemplate[k].x; michael@0: referenceTemplateY[k] = referenceTemplate[k].y; michael@0: } michael@0: var referenceWidth = referenceBitmap[0].length; michael@0: var referenceHeight = referenceBitmap.length; michael@0: michael@0: var pseudoPixelContext = RefinementReusedContexts[templateIndex]; michael@0: var bitmap = []; michael@0: michael@0: var decoder = decodingContext.decoder; michael@0: var contexts = decodingContext.contextCache.getContexts('GR'); michael@0: michael@0: var ltp = 0; michael@0: for (var i = 0; i < height; i++) { michael@0: if (prediction) { michael@0: var sltp = decoder.readBit(contexts, pseudoPixelContext); michael@0: ltp ^= sltp; michael@0: if (ltp) { michael@0: error('JBIG2 error: prediction is not supported'); michael@0: } michael@0: } michael@0: var row = new Uint8Array(width); michael@0: bitmap.push(row); michael@0: for (var j = 0; j < width; j++) { michael@0: var i0, j0; michael@0: var contextLabel = 0; michael@0: for (k = 0; k < codingTemplateLength; k++) { michael@0: i0 = i + codingTemplateY[k]; michael@0: j0 = j + codingTemplateX[k]; michael@0: if (i0 < 0 || j0 < 0 || j0 >= width) { michael@0: contextLabel <<= 1; // out of bound pixel michael@0: } else { michael@0: contextLabel = (contextLabel << 1) | bitmap[i0][j0]; michael@0: } michael@0: } michael@0: for (k = 0; k < referenceTemplateLength; k++) { michael@0: i0 = i + referenceTemplateY[k] + offsetY; michael@0: j0 = j + referenceTemplateX[k] + offsetX; michael@0: if (i0 < 0 || i0 >= referenceHeight || j0 < 0 || michael@0: j0 >= referenceWidth) { michael@0: contextLabel <<= 1; // out of bound pixel michael@0: } else { michael@0: contextLabel = (contextLabel << 1) | referenceBitmap[i0][j0]; michael@0: } michael@0: } michael@0: var pixel = decoder.readBit(contexts, contextLabel); michael@0: row[j] = pixel; michael@0: } michael@0: } michael@0: michael@0: return bitmap; michael@0: } michael@0: michael@0: // 6.5.5 Decoding the symbol dictionary michael@0: function decodeSymbolDictionary(huffman, refinement, symbols, michael@0: numberOfNewSymbols, numberOfExportedSymbols, michael@0: huffmanTables, templateIndex, at, michael@0: refinementTemplateIndex, refinementAt, michael@0: decodingContext) { michael@0: if (huffman) { michael@0: error('JBIG2 error: huffman is not supported'); michael@0: } michael@0: michael@0: var newSymbols = []; michael@0: var currentHeight = 0; michael@0: var symbolCodeLength = log2(symbols.length + numberOfNewSymbols); michael@0: michael@0: var decoder = decodingContext.decoder; michael@0: var contextCache = decodingContext.contextCache; michael@0: michael@0: while (newSymbols.length < numberOfNewSymbols) { michael@0: var deltaHeight = decodeInteger(contextCache, 'IADH', decoder); // 6.5.6 michael@0: currentHeight += deltaHeight; michael@0: var currentWidth = 0; michael@0: var totalWidth = 0; michael@0: while (true) { michael@0: var deltaWidth = decodeInteger(contextCache, 'IADW', decoder); // 6.5.7 michael@0: if (deltaWidth === null) { michael@0: break; // OOB michael@0: } michael@0: currentWidth += deltaWidth; michael@0: totalWidth += currentWidth; michael@0: var bitmap; michael@0: if (refinement) { michael@0: // 6.5.8.2 Refinement/aggregate-coded symbol bitmap michael@0: var numberOfInstances = decodeInteger(contextCache, 'IAAI', decoder); michael@0: if (numberOfInstances > 1) { michael@0: bitmap = decodeTextRegion(huffman, refinement, michael@0: currentWidth, currentHeight, 0, michael@0: numberOfInstances, 1, //strip size michael@0: symbols.concat(newSymbols), michael@0: symbolCodeLength, michael@0: 0, //transposed michael@0: 0, //ds offset michael@0: 1, //top left 7.4.3.1.1 michael@0: 0, //OR operator michael@0: huffmanTables, michael@0: refinementTemplateIndex, refinementAt, michael@0: decodingContext); michael@0: } else { michael@0: var symbolId = decodeIAID(contextCache, decoder, symbolCodeLength); michael@0: var rdx = decodeInteger(contextCache, 'IARDX', decoder); // 6.4.11.3 michael@0: var rdy = decodeInteger(contextCache, 'IARDY', decoder); // 6.4.11.4 michael@0: var symbol = (symbolId < symbols.length ? symbols[symbolId] : michael@0: newSymbols[symbolId - symbols.length]); michael@0: bitmap = decodeRefinement(currentWidth, currentHeight, michael@0: refinementTemplateIndex, symbol, rdx, rdy, false, refinementAt, michael@0: decodingContext); michael@0: } michael@0: } else { michael@0: // 6.5.8.1 Direct-coded symbol bitmap michael@0: bitmap = decodeBitmap(false, currentWidth, currentHeight, michael@0: templateIndex, false, null, at, decodingContext); michael@0: } michael@0: newSymbols.push(bitmap); michael@0: } michael@0: } michael@0: // 6.5.10 Exported symbols michael@0: var exportedSymbols = []; michael@0: var flags = [], currentFlag = false; michael@0: var totalSymbolsLength = symbols.length + numberOfNewSymbols; michael@0: while (flags.length < totalSymbolsLength) { michael@0: var runLength = decodeInteger(contextCache, 'IAEX', decoder); michael@0: while (runLength--) { michael@0: flags.push(currentFlag); michael@0: } michael@0: currentFlag = !currentFlag; michael@0: } michael@0: for (var i = 0, ii = symbols.length; i < ii; i++) { michael@0: if (flags[i]) { michael@0: exportedSymbols.push(symbols[i]); michael@0: } michael@0: } michael@0: for (var j = 0; j < numberOfNewSymbols; i++, j++) { michael@0: if (flags[i]) { michael@0: exportedSymbols.push(newSymbols[j]); michael@0: } michael@0: } michael@0: return exportedSymbols; michael@0: } michael@0: michael@0: function decodeTextRegion(huffman, refinement, width, height, michael@0: defaultPixelValue, numberOfSymbolInstances, michael@0: stripSize, inputSymbols, symbolCodeLength, michael@0: transposed, dsOffset, referenceCorner, michael@0: combinationOperator, huffmanTables, michael@0: refinementTemplateIndex, refinementAt, michael@0: decodingContext) { michael@0: if (huffman) { michael@0: error('JBIG2 error: huffman is not supported'); michael@0: } michael@0: michael@0: // Prepare bitmap michael@0: var bitmap = []; michael@0: var i, row; michael@0: for (i = 0; i < height; i++) { michael@0: row = new Uint8Array(width); michael@0: if (defaultPixelValue) { michael@0: for (var j = 0; j < width; j++) { michael@0: row[j] = defaultPixelValue; michael@0: } michael@0: } michael@0: bitmap.push(row); michael@0: } michael@0: michael@0: var decoder = decodingContext.decoder; michael@0: var contextCache = decodingContext.contextCache; michael@0: var stripT = -decodeInteger(contextCache, 'IADT', decoder); // 6.4.6 michael@0: var firstS = 0; michael@0: i = 0; michael@0: while (i < numberOfSymbolInstances) { michael@0: var deltaT = decodeInteger(contextCache, 'IADT', decoder); // 6.4.6 michael@0: stripT += deltaT; michael@0: michael@0: var deltaFirstS = decodeInteger(contextCache, 'IAFS', decoder); // 6.4.7 michael@0: firstS += deltaFirstS; michael@0: var currentS = firstS; michael@0: do { michael@0: var currentT = (stripSize == 1 ? 0 : michael@0: decodeInteger(contextCache, 'IAIT', decoder)); // 6.4.9 michael@0: var t = stripSize * stripT + currentT; michael@0: var symbolId = decodeIAID(contextCache, decoder, symbolCodeLength); michael@0: var applyRefinement = (refinement && michael@0: decodeInteger(contextCache, 'IARI', decoder)); michael@0: var symbolBitmap = inputSymbols[symbolId]; michael@0: var symbolWidth = symbolBitmap[0].length; michael@0: var symbolHeight = symbolBitmap.length; michael@0: if (applyRefinement) { michael@0: var rdw = decodeInteger(contextCache, 'IARDW', decoder); // 6.4.11.1 michael@0: var rdh = decodeInteger(contextCache, 'IARDH', decoder); // 6.4.11.2 michael@0: var rdx = decodeInteger(contextCache, 'IARDX', decoder); // 6.4.11.3 michael@0: var rdy = decodeInteger(contextCache, 'IARDY', decoder); // 6.4.11.4 michael@0: symbolWidth += rdw; michael@0: symbolHeight += rdh; michael@0: symbolBitmap = decodeRefinement(symbolWidth, symbolHeight, michael@0: refinementTemplateIndex, symbolBitmap, (rdw >> 1) + rdx, michael@0: (rdh >> 1) + rdy, false, refinementAt, michael@0: decodingContext); michael@0: } michael@0: var offsetT = t - ((referenceCorner & 1) ? 0 : symbolHeight); michael@0: var offsetS = currentS - ((referenceCorner & 2) ? symbolWidth : 0); michael@0: var s2, t2, symbolRow; michael@0: if (transposed) { michael@0: // Place Symbol Bitmap from T1,S1 michael@0: for (s2 = 0; s2 < symbolHeight; s2++) { michael@0: row = bitmap[offsetS + s2]; michael@0: if (!row) { michael@0: continue; michael@0: } michael@0: symbolRow = symbolBitmap[s2]; michael@0: // To ignore Parts of Symbol bitmap which goes michael@0: // outside bitmap region michael@0: var maxWidth = Math.min(width - offsetT, symbolWidth); michael@0: switch (combinationOperator) { michael@0: case 0: // OR michael@0: for (t2 = 0; t2 < maxWidth; t2++) { michael@0: row[offsetT + t2] |= symbolRow[t2]; michael@0: } michael@0: break; michael@0: case 2: // XOR michael@0: for (t2 = 0; t2 < maxWidth; t2++) { michael@0: row[offsetT + t2] ^= symbolRow[t2]; michael@0: } michael@0: break; michael@0: default: michael@0: error('JBIG2 error: operator ' + combinationOperator + michael@0: ' is not supported'); michael@0: } michael@0: } michael@0: currentS += symbolHeight - 1; michael@0: } else { michael@0: for (t2 = 0; t2 < symbolHeight; t2++) { michael@0: row = bitmap[offsetT + t2]; michael@0: if (!row) { michael@0: continue; michael@0: } michael@0: symbolRow = symbolBitmap[t2]; michael@0: switch (combinationOperator) { michael@0: case 0: // OR michael@0: for (s2 = 0; s2 < symbolWidth; s2++) { michael@0: row[offsetS + s2] |= symbolRow[s2]; michael@0: } michael@0: break; michael@0: case 2: // XOR michael@0: for (s2 = 0; s2 < symbolWidth; s2++) { michael@0: row[offsetS + s2] ^= symbolRow[s2]; michael@0: } michael@0: break; michael@0: default: michael@0: error('JBIG2 error: operator ' + combinationOperator + michael@0: ' is not supported'); michael@0: } michael@0: } michael@0: currentS += symbolWidth - 1; michael@0: } michael@0: i++; michael@0: var deltaS = decodeInteger(contextCache, 'IADS', decoder); // 6.4.8 michael@0: if (deltaS === null) { michael@0: break; // OOB michael@0: } michael@0: currentS += deltaS + dsOffset; michael@0: } while (true); michael@0: } michael@0: return bitmap; michael@0: } michael@0: michael@0: function readSegmentHeader(data, start) { michael@0: var segmentHeader = {}; michael@0: segmentHeader.number = readUint32(data, start); michael@0: var flags = data[start + 4]; michael@0: var segmentType = flags & 0x3F; michael@0: if (!SegmentTypes[segmentType]) { michael@0: error('JBIG2 error: invalid segment type: ' + segmentType); michael@0: } michael@0: segmentHeader.type = segmentType; michael@0: segmentHeader.typeName = SegmentTypes[segmentType]; michael@0: segmentHeader.deferredNonRetain = !!(flags & 0x80); michael@0: michael@0: var pageAssociationFieldSize = !!(flags & 0x40); michael@0: var referredFlags = data[start + 5]; michael@0: var referredToCount = (referredFlags >> 5) & 7; michael@0: var retainBits = [referredFlags & 31]; michael@0: var position = start + 6; michael@0: if (referredFlags == 7) { michael@0: referredToCount = readUint32(data, position - 1) & 0x1FFFFFFF; michael@0: position += 3; michael@0: var bytes = (referredToCount + 7) >> 3; michael@0: retainBits[0] = data[position++]; michael@0: while (--bytes > 0) { michael@0: retainBits.push(data[position++]); michael@0: } michael@0: } else if (referredFlags == 5 || referredFlags == 6) { michael@0: error('JBIG2 error: invalid referred-to flags'); michael@0: } michael@0: michael@0: segmentHeader.retainBits = retainBits; michael@0: var referredToSegmentNumberSize = (segmentHeader.number <= 256 ? 1 : michael@0: (segmentHeader.number <= 65536 ? 2 : 4)); michael@0: var referredTo = []; michael@0: var i, ii; michael@0: for (i = 0; i < referredToCount; i++) { michael@0: var number = (referredToSegmentNumberSize == 1 ? data[position] : michael@0: (referredToSegmentNumberSize == 2 ? readUint16(data, position) : michael@0: readUint32(data, position))); michael@0: referredTo.push(number); michael@0: position += referredToSegmentNumberSize; michael@0: } michael@0: segmentHeader.referredTo = referredTo; michael@0: if (!pageAssociationFieldSize) { michael@0: segmentHeader.pageAssociation = data[position++]; michael@0: } else { michael@0: segmentHeader.pageAssociation = readUint32(data, position); michael@0: position += 4; michael@0: } michael@0: segmentHeader.length = readUint32(data, position); michael@0: position += 4; michael@0: michael@0: if (segmentHeader.length == 0xFFFFFFFF) { michael@0: // 7.2.7 Segment data length, unknown segment length michael@0: if (segmentType === 38) { // ImmediateGenericRegion michael@0: var genericRegionInfo = readRegionSegmentInformation(data, position); michael@0: var genericRegionSegmentFlags = data[position + michael@0: RegionSegmentInformationFieldLength]; michael@0: var genericRegionMmr = !!(genericRegionSegmentFlags & 1); michael@0: // searching for the segment end michael@0: var searchPatternLength = 6; michael@0: var searchPattern = new Uint8Array(searchPatternLength); michael@0: if (!genericRegionMmr) { michael@0: searchPattern[0] = 0xFF; michael@0: searchPattern[1] = 0xAC; michael@0: } michael@0: searchPattern[2] = (genericRegionInfo.height >>> 24) & 0xFF; michael@0: searchPattern[3] = (genericRegionInfo.height >> 16) & 0xFF; michael@0: searchPattern[4] = (genericRegionInfo.height >> 8) & 0xFF; michael@0: searchPattern[5] = genericRegionInfo.height & 0xFF; michael@0: for (i = position, ii = data.length; i < ii; i++) { michael@0: var j = 0; michael@0: while (j < searchPatternLength && searchPattern[j] === data[i + j]) { michael@0: j++; michael@0: } michael@0: if (j == searchPatternLength) { michael@0: segmentHeader.length = i + searchPatternLength; michael@0: break; michael@0: } michael@0: } michael@0: if (segmentHeader.length == 0xFFFFFFFF) { michael@0: error('JBIG2 error: segment end was not found'); michael@0: } michael@0: } else { michael@0: error('JBIG2 error: invalid unknown segment length'); michael@0: } michael@0: } michael@0: segmentHeader.headerEnd = position; michael@0: return segmentHeader; michael@0: } michael@0: michael@0: function readSegments(header, data, start, end) { michael@0: var segments = []; michael@0: var position = start; michael@0: while (position < end) { michael@0: var segmentHeader = readSegmentHeader(data, position); michael@0: position = segmentHeader.headerEnd; michael@0: var segment = { michael@0: header: segmentHeader, michael@0: data: data michael@0: }; michael@0: if (!header.randomAccess) { michael@0: segment.start = position; michael@0: position += segmentHeader.length; michael@0: segment.end = position; michael@0: } michael@0: segments.push(segment); michael@0: if (segmentHeader.type == 51) { michael@0: break; // end of file is found michael@0: } michael@0: } michael@0: if (header.randomAccess) { michael@0: for (var i = 0, ii = segments.length; i < ii; i++) { michael@0: segments[i].start = position; michael@0: position += segments[i].header.length; michael@0: segments[i].end = position; michael@0: } michael@0: } michael@0: return segments; michael@0: } michael@0: michael@0: // 7.4.1 Region segment information field michael@0: function readRegionSegmentInformation(data, start) { michael@0: return { michael@0: width: readUint32(data, start), michael@0: height: readUint32(data, start + 4), michael@0: x: readUint32(data, start + 8), michael@0: y: readUint32(data, start + 12), michael@0: combinationOperator: data[start + 16] & 7 michael@0: }; michael@0: } michael@0: var RegionSegmentInformationFieldLength = 17; michael@0: michael@0: function processSegment(segment, visitor) { michael@0: var header = segment.header; michael@0: michael@0: var data = segment.data, position = segment.start, end = segment.end; michael@0: var args, at, i, atLength; michael@0: switch (header.type) { michael@0: case 0: // SymbolDictionary michael@0: // 7.4.2 Symbol dictionary segment syntax michael@0: var dictionary = {}; michael@0: var dictionaryFlags = readUint16(data, position); // 7.4.2.1.1 michael@0: dictionary.huffman = !!(dictionaryFlags & 1); michael@0: dictionary.refinement = !!(dictionaryFlags & 2); michael@0: dictionary.huffmanDHSelector = (dictionaryFlags >> 2) & 3; michael@0: dictionary.huffmanDWSelector = (dictionaryFlags >> 4) & 3; michael@0: dictionary.bitmapSizeSelector = (dictionaryFlags >> 6) & 1; michael@0: dictionary.aggregationInstancesSelector = (dictionaryFlags >> 7) & 1; michael@0: dictionary.bitmapCodingContextUsed = !!(dictionaryFlags & 256); michael@0: dictionary.bitmapCodingContextRetained = !!(dictionaryFlags & 512); michael@0: dictionary.template = (dictionaryFlags >> 10) & 3; michael@0: dictionary.refinementTemplate = (dictionaryFlags >> 12) & 1; michael@0: position += 2; michael@0: if (!dictionary.huffman) { michael@0: atLength = dictionary.template === 0 ? 4 : 1; michael@0: at = []; michael@0: for (i = 0; i < atLength; i++) { michael@0: at.push({ michael@0: x: readInt8(data, position), michael@0: y: readInt8(data, position + 1) michael@0: }); michael@0: position += 2; michael@0: } michael@0: dictionary.at = at; michael@0: } michael@0: if (dictionary.refinement && !dictionary.refinementTemplate) { michael@0: at = []; michael@0: for (i = 0; i < 2; i++) { michael@0: at.push({ michael@0: x: readInt8(data, position), michael@0: y: readInt8(data, position + 1) michael@0: }); michael@0: position += 2; michael@0: } michael@0: dictionary.refinementAt = at; michael@0: } michael@0: dictionary.numberOfExportedSymbols = readUint32(data, position); michael@0: position += 4; michael@0: dictionary.numberOfNewSymbols = readUint32(data, position); michael@0: position += 4; michael@0: args = [dictionary, header.number, header.referredTo, michael@0: data, position, end]; michael@0: break; michael@0: case 6: // ImmediateTextRegion michael@0: case 7: // ImmediateLosslessTextRegion michael@0: var textRegion = {}; michael@0: textRegion.info = readRegionSegmentInformation(data, position); michael@0: position += RegionSegmentInformationFieldLength; michael@0: var textRegionSegmentFlags = readUint16(data, position); michael@0: position += 2; michael@0: textRegion.huffman = !!(textRegionSegmentFlags & 1); michael@0: textRegion.refinement = !!(textRegionSegmentFlags & 2); michael@0: textRegion.stripSize = 1 << ((textRegionSegmentFlags >> 2) & 3); michael@0: textRegion.referenceCorner = (textRegionSegmentFlags >> 4) & 3; michael@0: textRegion.transposed = !!(textRegionSegmentFlags & 64); michael@0: textRegion.combinationOperator = (textRegionSegmentFlags >> 7) & 3; michael@0: textRegion.defaultPixelValue = (textRegionSegmentFlags >> 9) & 1; michael@0: textRegion.dsOffset = (textRegionSegmentFlags << 17) >> 27; michael@0: textRegion.refinementTemplate = (textRegionSegmentFlags >> 15) & 1; michael@0: if (textRegion.huffman) { michael@0: var textRegionHuffmanFlags = readUint16(data, position); michael@0: position += 2; michael@0: textRegion.huffmanFS = (textRegionHuffmanFlags) & 3; michael@0: textRegion.huffmanDS = (textRegionHuffmanFlags >> 2) & 3; michael@0: textRegion.huffmanDT = (textRegionHuffmanFlags >> 4) & 3; michael@0: textRegion.huffmanRefinementDW = (textRegionHuffmanFlags >> 6) & 3; michael@0: textRegion.huffmanRefinementDH = (textRegionHuffmanFlags >> 8) & 3; michael@0: textRegion.huffmanRefinementDX = (textRegionHuffmanFlags >> 10) & 3; michael@0: textRegion.huffmanRefinementDY = (textRegionHuffmanFlags >> 12) & 3; michael@0: textRegion.huffmanRefinementSizeSelector = michael@0: !!(textRegionHuffmanFlags & 14); michael@0: } michael@0: if (textRegion.refinement && !textRegion.refinementTemplate) { michael@0: at = []; michael@0: for (i = 0; i < 2; i++) { michael@0: at.push({ michael@0: x: readInt8(data, position), michael@0: y: readInt8(data, position + 1) michael@0: }); michael@0: position += 2; michael@0: } michael@0: textRegion.refinementAt = at; michael@0: } michael@0: textRegion.numberOfSymbolInstances = readUint32(data, position); michael@0: position += 4; michael@0: // TODO 7.4.3.1.7 Symbol ID Huffman table decoding michael@0: if (textRegion.huffman) { michael@0: error('JBIG2 error: huffman is not supported'); michael@0: } michael@0: args = [textRegion, header.referredTo, data, position, end]; michael@0: break; michael@0: case 38: // ImmediateGenericRegion michael@0: case 39: // ImmediateLosslessGenericRegion michael@0: var genericRegion = {}; michael@0: genericRegion.info = readRegionSegmentInformation(data, position); michael@0: position += RegionSegmentInformationFieldLength; michael@0: var genericRegionSegmentFlags = data[position++]; michael@0: genericRegion.mmr = !!(genericRegionSegmentFlags & 1); michael@0: genericRegion.template = (genericRegionSegmentFlags >> 1) & 3; michael@0: genericRegion.prediction = !!(genericRegionSegmentFlags & 8); michael@0: if (!genericRegion.mmr) { michael@0: atLength = genericRegion.template === 0 ? 4 : 1; michael@0: at = []; michael@0: for (i = 0; i < atLength; i++) { michael@0: at.push({ michael@0: x: readInt8(data, position), michael@0: y: readInt8(data, position + 1) michael@0: }); michael@0: position += 2; michael@0: } michael@0: genericRegion.at = at; michael@0: } michael@0: args = [genericRegion, data, position, end]; michael@0: break; michael@0: case 48: // PageInformation michael@0: var pageInfo = { michael@0: width: readUint32(data, position), michael@0: height: readUint32(data, position + 4), michael@0: resolutionX: readUint32(data, position + 8), michael@0: resolutionY: readUint32(data, position + 12) michael@0: }; michael@0: if (pageInfo.height == 0xFFFFFFFF) { michael@0: delete pageInfo.height; michael@0: } michael@0: var pageSegmentFlags = data[position + 16]; michael@0: var pageStripingInformatiom = readUint16(data, position + 17); michael@0: pageInfo.lossless = !!(pageSegmentFlags & 1); michael@0: pageInfo.refinement = !!(pageSegmentFlags & 2); michael@0: pageInfo.defaultPixelValue = (pageSegmentFlags >> 2) & 1; michael@0: pageInfo.combinationOperator = (pageSegmentFlags >> 3) & 3; michael@0: pageInfo.requiresBuffer = !!(pageSegmentFlags & 32); michael@0: pageInfo.combinationOperatorOverride = !!(pageSegmentFlags & 64); michael@0: args = [pageInfo]; michael@0: break; michael@0: case 49: // EndOfPage michael@0: break; michael@0: case 50: // EndOfStripe michael@0: break; michael@0: case 51: // EndOfFile michael@0: break; michael@0: case 62: // 7.4.15 defines 2 extension types which michael@0: // are comments and can be ignored. michael@0: break; michael@0: default: michael@0: error('JBIG2 error: segment type ' + header.typeName + '(' + michael@0: header.type + ') is not implemented'); michael@0: } michael@0: var callbackName = 'on' + header.typeName; michael@0: if (callbackName in visitor) { michael@0: visitor[callbackName].apply(visitor, args); michael@0: } michael@0: } michael@0: michael@0: function processSegments(segments, visitor) { michael@0: for (var i = 0, ii = segments.length; i < ii; i++) { michael@0: processSegment(segments[i], visitor); michael@0: } michael@0: } michael@0: michael@0: function parseJbig2(data, start, end) { michael@0: var position = start; michael@0: if (data[position] != 0x97 || data[position + 1] != 0x4A || michael@0: data[position + 2] != 0x42 || data[position + 3] != 0x32 || michael@0: data[position + 4] != 0x0D || data[position + 5] != 0x0A || michael@0: data[position + 6] != 0x1A || data[position + 7] != 0x0A) { michael@0: error('JBIG2 error: invalid header'); michael@0: } michael@0: var header = {}; michael@0: position += 8; michael@0: var flags = data[position++]; michael@0: header.randomAccess = !(flags & 1); michael@0: if (!(flags & 2)) { michael@0: header.numberOfPages = readUint32(data, position); michael@0: position += 4; michael@0: } michael@0: var segments = readSegments(header, data, position, end); michael@0: error('Not implemented'); michael@0: // processSegments(segments, new SimpleSegmentVisitor()); michael@0: } michael@0: michael@0: function parseJbig2Chunks(chunks) { michael@0: var visitor = new SimpleSegmentVisitor(); michael@0: for (var i = 0, ii = chunks.length; i < ii; i++) { michael@0: var chunk = chunks[i]; michael@0: var segments = readSegments({}, chunk.data, chunk.start, chunk.end); michael@0: processSegments(segments, visitor); michael@0: } michael@0: return visitor.buffer; michael@0: } michael@0: michael@0: function SimpleSegmentVisitor() {} michael@0: michael@0: SimpleSegmentVisitor.prototype = { michael@0: onPageInformation: function SimpleSegmentVisitor_onPageInformation(info) { michael@0: this.currentPageInfo = info; michael@0: var rowSize = (info.width + 7) >> 3; michael@0: var buffer = new Uint8Array(rowSize * info.height); michael@0: // The contents of ArrayBuffers are initialized to 0. michael@0: // Fill the buffer with 0xFF only if info.defaultPixelValue is set michael@0: if (info.defaultPixelValue) { michael@0: for (var i = 0, ii = buffer.length; i < ii; i++) { michael@0: buffer[i] = 0xFF; michael@0: } michael@0: } michael@0: this.buffer = buffer; michael@0: }, michael@0: drawBitmap: function SimpleSegmentVisitor_drawBitmap(regionInfo, bitmap) { michael@0: var pageInfo = this.currentPageInfo; michael@0: var width = regionInfo.width, height = regionInfo.height; michael@0: var rowSize = (pageInfo.width + 7) >> 3; michael@0: var combinationOperator = pageInfo.combinationOperatorOverride ? michael@0: regionInfo.combinationOperator : pageInfo.combinationOperator; michael@0: var buffer = this.buffer; michael@0: var mask0 = 128 >> (regionInfo.x & 7); michael@0: var offset0 = regionInfo.y * rowSize + (regionInfo.x >> 3); michael@0: var i, j, mask, offset; michael@0: switch (combinationOperator) { michael@0: case 0: // OR michael@0: for (i = 0; i < height; i++) { michael@0: mask = mask0; michael@0: offset = offset0; michael@0: for (j = 0; j < width; j++) { michael@0: if (bitmap[i][j]) { michael@0: buffer[offset] |= mask; michael@0: } michael@0: mask >>= 1; michael@0: if (!mask) { michael@0: mask = 128; michael@0: offset++; michael@0: } michael@0: } michael@0: offset0 += rowSize; michael@0: } michael@0: break; michael@0: case 2: // XOR michael@0: for (i = 0; i < height; i++) { michael@0: mask = mask0; michael@0: offset = offset0; michael@0: for (j = 0; j < width; j++) { michael@0: if (bitmap[i][j]) { michael@0: buffer[offset] ^= mask; michael@0: } michael@0: mask >>= 1; michael@0: if (!mask) { michael@0: mask = 128; michael@0: offset++; michael@0: } michael@0: } michael@0: offset0 += rowSize; michael@0: } michael@0: break; michael@0: default: michael@0: error('JBIG2 error: operator ' + combinationOperator + michael@0: ' is not supported'); michael@0: } michael@0: }, michael@0: onImmediateGenericRegion: michael@0: function SimpleSegmentVisitor_onImmediateGenericRegion(region, data, michael@0: start, end) { michael@0: var regionInfo = region.info; michael@0: var decodingContext = new DecodingContext(data, start, end); michael@0: var bitmap = decodeBitmap(region.mmr, regionInfo.width, regionInfo.height, michael@0: region.template, region.prediction, null, michael@0: region.at, decodingContext); michael@0: this.drawBitmap(regionInfo, bitmap); michael@0: }, michael@0: onImmediateLosslessGenericRegion: michael@0: function SimpleSegmentVisitor_onImmediateLosslessGenericRegion() { michael@0: this.onImmediateGenericRegion.apply(this, arguments); michael@0: }, michael@0: onSymbolDictionary: michael@0: function SimpleSegmentVisitor_onSymbolDictionary(dictionary, michael@0: currentSegment, michael@0: referredSegments, michael@0: data, start, end) { michael@0: var huffmanTables; michael@0: if (dictionary.huffman) { michael@0: error('JBIG2 error: huffman is not supported'); michael@0: } michael@0: michael@0: // Combines exported symbols from all referred segments michael@0: var symbols = this.symbols; michael@0: if (!symbols) { michael@0: this.symbols = symbols = {}; michael@0: } michael@0: michael@0: var inputSymbols = []; michael@0: for (var i = 0, ii = referredSegments.length; i < ii; i++) { michael@0: inputSymbols = inputSymbols.concat(symbols[referredSegments[i]]); michael@0: } michael@0: michael@0: var decodingContext = new DecodingContext(data, start, end); michael@0: symbols[currentSegment] = decodeSymbolDictionary(dictionary.huffman, michael@0: dictionary.refinement, inputSymbols, dictionary.numberOfNewSymbols, michael@0: dictionary.numberOfExportedSymbols, huffmanTables, michael@0: dictionary.template, dictionary.at, michael@0: dictionary.refinementTemplate, dictionary.refinementAt, michael@0: decodingContext); michael@0: }, michael@0: onImmediateTextRegion: michael@0: function SimpleSegmentVisitor_onImmediateTextRegion(region, michael@0: referredSegments, michael@0: data, start, end) { michael@0: var regionInfo = region.info; michael@0: var huffmanTables; michael@0: michael@0: // Combines exported symbols from all referred segments michael@0: var symbols = this.symbols; michael@0: var inputSymbols = []; michael@0: for (var i = 0, ii = referredSegments.length; i < ii; i++) { michael@0: inputSymbols = inputSymbols.concat(symbols[referredSegments[i]]); michael@0: } michael@0: var symbolCodeLength = log2(inputSymbols.length); michael@0: michael@0: var decodingContext = new DecodingContext(data, start, end); michael@0: var bitmap = decodeTextRegion(region.huffman, region.refinement, michael@0: regionInfo.width, regionInfo.height, region.defaultPixelValue, michael@0: region.numberOfSymbolInstances, region.stripSize, inputSymbols, michael@0: symbolCodeLength, region.transposed, region.dsOffset, michael@0: region.referenceCorner, region.combinationOperator, huffmanTables, michael@0: region.refinementTemplate, region.refinementAt, decodingContext); michael@0: this.drawBitmap(regionInfo, bitmap); michael@0: }, michael@0: onImmediateLosslessTextRegion: michael@0: function SimpleSegmentVisitor_onImmediateLosslessTextRegion() { michael@0: this.onImmediateTextRegion.apply(this, arguments); michael@0: } michael@0: }; michael@0: michael@0: function Jbig2Image() {} michael@0: michael@0: Jbig2Image.prototype = { michael@0: parseChunks: function Jbig2Image_parseChunks(chunks) { michael@0: return parseJbig2Chunks(chunks); michael@0: } michael@0: }; michael@0: michael@0: return Jbig2Image; michael@0: })(); michael@0: michael@0: michael@0: var bidi = PDFJS.bidi = (function bidiClosure() { michael@0: // Character types for symbols from 0000 to 00FF. michael@0: var baseTypes = [ michael@0: 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'S', 'B', 'S', 'WS', michael@0: 'B', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', michael@0: 'BN', 'BN', 'B', 'B', 'B', 'S', 'WS', 'ON', 'ON', 'ET', 'ET', 'ET', 'ON', michael@0: 'ON', 'ON', 'ON', 'ON', 'ON', 'CS', 'ON', 'CS', 'ON', 'EN', 'EN', 'EN', michael@0: 'EN', 'EN', 'EN', 'EN', 'EN', 'EN', 'EN', 'ON', 'ON', 'ON', 'ON', 'ON', michael@0: 'ON', 'ON', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', michael@0: 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'ON', 'ON', michael@0: 'ON', 'ON', 'ON', 'ON', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', michael@0: 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', michael@0: 'L', 'ON', 'ON', 'ON', 'ON', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'B', 'BN', michael@0: 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', michael@0: 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', michael@0: 'BN', 'CS', 'ON', 'ET', 'ET', 'ET', 'ET', 'ON', 'ON', 'ON', 'ON', 'L', 'ON', michael@0: 'ON', 'ON', 'ON', 'ON', 'ET', 'ET', 'EN', 'EN', 'ON', 'L', 'ON', 'ON', 'ON', michael@0: 'EN', 'L', 'ON', 'ON', 'ON', 'ON', 'ON', 'L', 'L', 'L', 'L', 'L', 'L', 'L', michael@0: 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', michael@0: 'L', 'ON', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', michael@0: 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', michael@0: 'L', 'L', 'L', 'ON', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L' michael@0: ]; michael@0: michael@0: // Character types for symbols from 0600 to 06FF michael@0: var arabicTypes = [ michael@0: 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', michael@0: 'CS', 'AL', 'ON', 'ON', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'AL', michael@0: 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', michael@0: 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', michael@0: 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', michael@0: 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', michael@0: 'AL', 'AL', 'AL', 'AL', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', michael@0: 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'AL', 'AL', 'AL', 'AL', michael@0: 'AL', 'AL', 'AL', 'AN', 'AN', 'AN', 'AN', 'AN', 'AN', 'AN', 'AN', 'AN', michael@0: 'AN', 'ET', 'AN', 'AN', 'AL', 'AL', 'AL', 'NSM', 'AL', 'AL', 'AL', 'AL', michael@0: 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', michael@0: 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', michael@0: 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', michael@0: 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', michael@0: 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', michael@0: 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', michael@0: 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', michael@0: 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', michael@0: 'AL', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', michael@0: 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'ON', 'NSM', michael@0: 'NSM', 'NSM', 'NSM', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', michael@0: 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL' michael@0: ]; michael@0: michael@0: function isOdd(i) { michael@0: return (i & 1) !== 0; michael@0: } michael@0: michael@0: function isEven(i) { michael@0: return (i & 1) === 0; michael@0: } michael@0: michael@0: function findUnequal(arr, start, value) { michael@0: for (var j = start, jj = arr.length; j < jj; ++j) { michael@0: if (arr[j] != value) { michael@0: return j; michael@0: } michael@0: } michael@0: return j; michael@0: } michael@0: michael@0: function setValues(arr, start, end, value) { michael@0: for (var j = start; j < end; ++j) { michael@0: arr[j] = value; michael@0: } michael@0: } michael@0: michael@0: function reverseValues(arr, start, end) { michael@0: for (var i = start, j = end - 1; i < j; ++i, --j) { michael@0: var temp = arr[i]; michael@0: arr[i] = arr[j]; michael@0: arr[j] = temp; michael@0: } michael@0: } michael@0: michael@0: function createBidiText(str, isLTR, vertical) { michael@0: return { michael@0: str: str, michael@0: dir: (vertical ? 'ttb' : (isLTR ? 'ltr' : 'rtl')) michael@0: }; michael@0: } michael@0: michael@0: // These are used in bidi(), which is called frequently. We re-use them on michael@0: // each call to avoid unnecessary allocations. michael@0: var chars = []; michael@0: var types = []; michael@0: michael@0: function bidi(str, startLevel, vertical) { michael@0: var isLTR = true; michael@0: var strLength = str.length; michael@0: if (strLength === 0 || vertical) { michael@0: return createBidiText(str, isLTR, vertical); michael@0: } michael@0: michael@0: // Get types and fill arrays michael@0: chars.length = 0; michael@0: types.length = 0; michael@0: var numBidi = 0; michael@0: michael@0: var i, ii; michael@0: for (i = 0; i < strLength; ++i) { michael@0: chars[i] = str.charAt(i); michael@0: michael@0: var charCode = str.charCodeAt(i); michael@0: var charType = 'L'; michael@0: if (charCode <= 0x00ff) { michael@0: charType = baseTypes[charCode]; michael@0: } else if (0x0590 <= charCode && charCode <= 0x05f4) { michael@0: charType = 'R'; michael@0: } else if (0x0600 <= charCode && charCode <= 0x06ff) { michael@0: charType = arabicTypes[charCode & 0xff]; michael@0: } else if (0x0700 <= charCode && charCode <= 0x08AC) { michael@0: charType = 'AL'; michael@0: } michael@0: if (charType == 'R' || charType == 'AL' || charType == 'AN') { michael@0: numBidi++; michael@0: } michael@0: types[i] = charType; michael@0: } michael@0: michael@0: // Detect the bidi method michael@0: // - If there are no rtl characters then no bidi needed michael@0: // - If less than 30% chars are rtl then string is primarily ltr michael@0: // - If more than 30% chars are rtl then string is primarily rtl michael@0: if (numBidi === 0) { michael@0: isLTR = true; michael@0: return createBidiText(str, isLTR); michael@0: } michael@0: michael@0: if (startLevel == -1) { michael@0: if ((strLength / numBidi) < 0.3) { michael@0: isLTR = true; michael@0: startLevel = 0; michael@0: } else { michael@0: isLTR = false; michael@0: startLevel = 1; michael@0: } michael@0: } michael@0: michael@0: var levels = []; michael@0: for (i = 0; i < strLength; ++i) { michael@0: levels[i] = startLevel; michael@0: } michael@0: michael@0: /* michael@0: X1-X10: skip most of this, since we are NOT doing the embeddings. michael@0: */ michael@0: var e = (isOdd(startLevel) ? 'R' : 'L'); michael@0: var sor = e; michael@0: var eor = sor; michael@0: michael@0: /* michael@0: W1. Examine each non-spacing mark (NSM) in the level run, and change the michael@0: type of the NSM to the type of the previous character. If the NSM is at the michael@0: start of the level run, it will get the type of sor. michael@0: */ michael@0: var lastType = sor; michael@0: for (i = 0; i < strLength; ++i) { michael@0: if (types[i] == 'NSM') { michael@0: types[i] = lastType; michael@0: } else { michael@0: lastType = types[i]; michael@0: } michael@0: } michael@0: michael@0: /* michael@0: W2. Search backwards from each instance of a European number until the michael@0: first strong type (R, L, AL, or sor) is found. If an AL is found, change michael@0: the type of the European number to Arabic number. michael@0: */ michael@0: lastType = sor; michael@0: var t; michael@0: for (i = 0; i < strLength; ++i) { michael@0: t = types[i]; michael@0: if (t == 'EN') { michael@0: types[i] = (lastType == 'AL') ? 'AN' : 'EN'; michael@0: } else if (t == 'R' || t == 'L' || t == 'AL') { michael@0: lastType = t; michael@0: } michael@0: } michael@0: michael@0: /* michael@0: W3. Change all ALs to R. michael@0: */ michael@0: for (i = 0; i < strLength; ++i) { michael@0: t = types[i]; michael@0: if (t == 'AL') { michael@0: types[i] = 'R'; michael@0: } michael@0: } michael@0: michael@0: /* michael@0: W4. A single European separator between two European numbers changes to a michael@0: European number. A single common separator between two numbers of the same michael@0: type changes to that type: michael@0: */ michael@0: for (i = 1; i < strLength - 1; ++i) { michael@0: if (types[i] == 'ES' && types[i - 1] == 'EN' && types[i + 1] == 'EN') { michael@0: types[i] = 'EN'; michael@0: } michael@0: if (types[i] == 'CS' && (types[i - 1] == 'EN' || types[i - 1] == 'AN') && michael@0: types[i + 1] == types[i - 1]) { michael@0: types[i] = types[i - 1]; michael@0: } michael@0: } michael@0: michael@0: /* michael@0: W5. A sequence of European terminators adjacent to European numbers changes michael@0: to all European numbers: michael@0: */ michael@0: for (i = 0; i < strLength; ++i) { michael@0: if (types[i] == 'EN') { michael@0: // do before michael@0: var j; michael@0: for (j = i - 1; j >= 0; --j) { michael@0: if (types[j] != 'ET') { michael@0: break; michael@0: } michael@0: types[j] = 'EN'; michael@0: } michael@0: // do after michael@0: for (j = i + 1; j < strLength; --j) { michael@0: if (types[j] != 'ET') { michael@0: break; michael@0: } michael@0: types[j] = 'EN'; michael@0: } michael@0: } michael@0: } michael@0: michael@0: /* michael@0: W6. Otherwise, separators and terminators change to Other Neutral: michael@0: */ michael@0: for (i = 0; i < strLength; ++i) { michael@0: t = types[i]; michael@0: if (t == 'WS' || t == 'ES' || t == 'ET' || t == 'CS') { michael@0: types[i] = 'ON'; michael@0: } michael@0: } michael@0: michael@0: /* michael@0: W7. Search backwards from each instance of a European number until the michael@0: first strong type (R, L, or sor) is found. If an L is found, then change michael@0: the type of the European number to L. michael@0: */ michael@0: lastType = sor; michael@0: for (i = 0; i < strLength; ++i) { michael@0: t = types[i]; michael@0: if (t == 'EN') { michael@0: types[i] = ((lastType == 'L') ? 'L' : 'EN'); michael@0: } else if (t == 'R' || t == 'L') { michael@0: lastType = t; michael@0: } michael@0: } michael@0: michael@0: /* michael@0: N1. A sequence of neutrals takes the direction of the surrounding strong michael@0: text if the text on both sides has the same direction. European and Arabic michael@0: numbers are treated as though they were R. Start-of-level-run (sor) and michael@0: end-of-level-run (eor) are used at level run boundaries. michael@0: */ michael@0: for (i = 0; i < strLength; ++i) { michael@0: if (types[i] == 'ON') { michael@0: var end = findUnequal(types, i + 1, 'ON'); michael@0: var before = sor; michael@0: if (i > 0) { michael@0: before = types[i - 1]; michael@0: } michael@0: michael@0: var after = eor; michael@0: if (end + 1 < strLength) { michael@0: after = types[end + 1]; michael@0: } michael@0: if (before != 'L') { michael@0: before = 'R'; michael@0: } michael@0: if (after != 'L') { michael@0: after = 'R'; michael@0: } michael@0: if (before == after) { michael@0: setValues(types, i, end, before); michael@0: } michael@0: i = end - 1; // reset to end (-1 so next iteration is ok) michael@0: } michael@0: } michael@0: michael@0: /* michael@0: N2. Any remaining neutrals take the embedding direction. michael@0: */ michael@0: for (i = 0; i < strLength; ++i) { michael@0: if (types[i] == 'ON') { michael@0: types[i] = e; michael@0: } michael@0: } michael@0: michael@0: /* michael@0: I1. For all characters with an even (left-to-right) embedding direction, michael@0: those of type R go up one level and those of type AN or EN go up two michael@0: levels. michael@0: I2. For all characters with an odd (right-to-left) embedding direction, michael@0: those of type L, EN or AN go up one level. michael@0: */ michael@0: for (i = 0; i < strLength; ++i) { michael@0: t = types[i]; michael@0: if (isEven(levels[i])) { michael@0: if (t == 'R') { michael@0: levels[i] += 1; michael@0: } else if (t == 'AN' || t == 'EN') { michael@0: levels[i] += 2; michael@0: } michael@0: } else { // isOdd michael@0: if (t == 'L' || t == 'AN' || t == 'EN') { michael@0: levels[i] += 1; michael@0: } michael@0: } michael@0: } michael@0: michael@0: /* michael@0: L1. On each line, reset the embedding level of the following characters to michael@0: the paragraph embedding level: michael@0: michael@0: segment separators, michael@0: paragraph separators, michael@0: any sequence of whitespace characters preceding a segment separator or michael@0: paragraph separator, and any sequence of white space characters at the end michael@0: of the line. michael@0: */ michael@0: michael@0: // don't bother as text is only single line michael@0: michael@0: /* michael@0: L2. From the highest level found in the text to the lowest odd level on michael@0: each line, reverse any contiguous sequence of characters that are at that michael@0: level or higher. michael@0: */ michael@0: michael@0: // find highest level & lowest odd level michael@0: var highestLevel = -1; michael@0: var lowestOddLevel = 99; michael@0: var level; michael@0: for (i = 0, ii = levels.length; i < ii; ++i) { michael@0: level = levels[i]; michael@0: if (highestLevel < level) { michael@0: highestLevel = level; michael@0: } michael@0: if (lowestOddLevel > level && isOdd(level)) { michael@0: lowestOddLevel = level; michael@0: } michael@0: } michael@0: michael@0: // now reverse between those limits michael@0: for (level = highestLevel; level >= lowestOddLevel; --level) { michael@0: // find segments to reverse michael@0: var start = -1; michael@0: for (i = 0, ii = levels.length; i < ii; ++i) { michael@0: if (levels[i] < level) { michael@0: if (start >= 0) { michael@0: reverseValues(chars, start, i); michael@0: start = -1; michael@0: } michael@0: } else if (start < 0) { michael@0: start = i; michael@0: } michael@0: } michael@0: if (start >= 0) { michael@0: reverseValues(chars, start, levels.length); michael@0: } michael@0: } michael@0: michael@0: /* michael@0: L3. Combining marks applied to a right-to-left base character will at this michael@0: point precede their base character. If the rendering engine expects them to michael@0: follow the base characters in the final display process, then the ordering michael@0: of the marks and the base character must be reversed. michael@0: */ michael@0: michael@0: // don't bother for now michael@0: michael@0: /* michael@0: L4. A character that possesses the mirrored property as specified by michael@0: Section 4.7, Mirrored, must be depicted by a mirrored glyph if the resolved michael@0: directionality of that character is R. michael@0: */ michael@0: michael@0: // don't mirror as characters are already mirrored in the pdf michael@0: michael@0: // Finally, return string michael@0: var result = ''; michael@0: for (i = 0, ii = chars.length; i < ii; ++i) { michael@0: var ch = chars[i]; michael@0: if (ch != '<' && ch != '>') { michael@0: result += ch; michael@0: } michael@0: } michael@0: return createBidiText(result, isLTR); michael@0: } michael@0: michael@0: return bidi; michael@0: })(); michael@0: michael@0: michael@0: /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ michael@0: michael@0: /* Copyright 2014 Opera Software ASA michael@0: * michael@0: * Licensed under the Apache License, Version 2.0 (the "License"); michael@0: * you may not use this file except in compliance with the License. michael@0: * You may obtain a copy of the License at michael@0: * michael@0: * http://www.apache.org/licenses/LICENSE-2.0 michael@0: * michael@0: * Unless required by applicable law or agreed to in writing, software michael@0: * distributed under the License is distributed on an "AS IS" BASIS, michael@0: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. michael@0: * See the License for the specific language governing permissions and michael@0: * limitations under the License. michael@0: * michael@0: * michael@0: * Based on https://code.google.com/p/smhasher/wiki/MurmurHash3. michael@0: * Hashes roughly 100 KB per millisecond on i7 3.4 GHz. michael@0: */ michael@0: /* globals Uint32ArrayView */ michael@0: michael@0: 'use strict'; michael@0: michael@0: var MurmurHash3_64 = (function MurmurHash3_64Closure (seed) { michael@0: // Workaround for missing math precison in JS. michael@0: var MASK_HIGH = 0xffff0000; michael@0: var MASK_LOW = 0xffff; michael@0: michael@0: function MurmurHash3_64 (seed) { michael@0: var SEED = 0xc3d2e1f0; michael@0: this.h1 = seed ? seed & 0xffffffff : SEED; michael@0: this.h2 = seed ? seed & 0xffffffff : SEED; michael@0: } michael@0: michael@0: MurmurHash3_64.prototype = { michael@0: update: function MurmurHash3_64_update(input) { michael@0: var useUint32ArrayView = false; michael@0: var i; michael@0: if (typeof input == 'string') { michael@0: var data = new Uint8Array(input.length * 2); michael@0: var length = 0; michael@0: for (i = 0; i < input.length; i++) { michael@0: var code = input.charCodeAt(i); michael@0: if (code <= 0xff) { michael@0: data[length++] = code; michael@0: } michael@0: else { michael@0: data[length++] = code >>> 8; michael@0: data[length++] = code & 0xff; michael@0: } michael@0: } michael@0: } else if (input instanceof Uint8Array) { michael@0: data = input; michael@0: length = data.length; michael@0: } else if (typeof input === 'object' && ('length' in input)) { michael@0: // processing regular arrays as well, e.g. for IE9 michael@0: data = input; michael@0: length = data.length; michael@0: useUint32ArrayView = true; michael@0: } else { michael@0: throw new Error('Wrong data format in MurmurHash3_64_update. ' + michael@0: 'Input must be a string or array.'); michael@0: } michael@0: michael@0: var blockCounts = length >> 2; michael@0: var tailLength = length - blockCounts * 4; michael@0: // we don't care about endianness here michael@0: var dataUint32 = useUint32ArrayView ? michael@0: new Uint32ArrayView(data, blockCounts) : michael@0: new Uint32Array(data.buffer, 0, blockCounts); michael@0: var k1 = 0; michael@0: var k2 = 0; michael@0: var h1 = this.h1; michael@0: var h2 = this.h2; michael@0: var C1 = 0xcc9e2d51; michael@0: var C2 = 0x1b873593; michael@0: var C1_LOW = C1 & MASK_LOW; michael@0: var C2_LOW = C2 & MASK_LOW; michael@0: michael@0: for (i = 0; i < blockCounts; i++) { michael@0: if (i & 1) { michael@0: k1 = dataUint32[i]; michael@0: k1 = (k1 * C1 & MASK_HIGH) | (k1 * C1_LOW & MASK_LOW); michael@0: k1 = k1 << 15 | k1 >>> 17; michael@0: k1 = (k1 * C2 & MASK_HIGH) | (k1 * C2_LOW & MASK_LOW); michael@0: h1 ^= k1; michael@0: h1 = h1 << 13 | h1 >>> 19; michael@0: h1 = h1 * 5 + 0xe6546b64; michael@0: } else { michael@0: k2 = dataUint32[i]; michael@0: k2 = (k2 * C1 & MASK_HIGH) | (k2 * C1_LOW & MASK_LOW); michael@0: k2 = k2 << 15 | k2 >>> 17; michael@0: k2 = (k2 * C2 & MASK_HIGH) | (k2 * C2_LOW & MASK_LOW); michael@0: h2 ^= k2; michael@0: h2 = h2 << 13 | h2 >>> 19; michael@0: h2 = h2 * 5 + 0xe6546b64; michael@0: } michael@0: } michael@0: michael@0: k1 = 0; michael@0: michael@0: switch (tailLength) { michael@0: case 3: michael@0: k1 ^= data[blockCounts * 4 + 2] << 16; michael@0: /* falls through */ michael@0: case 2: michael@0: k1 ^= data[blockCounts * 4 + 1] << 8; michael@0: /* falls through */ michael@0: case 1: michael@0: k1 ^= data[blockCounts * 4]; michael@0: /* falls through */ michael@0: k1 = (k1 * C1 & MASK_HIGH) | (k1 * C1_LOW & MASK_LOW); michael@0: k1 = k1 << 15 | k1 >>> 17; michael@0: k1 = (k1 * C2 & MASK_HIGH) | (k1 * C2_LOW & MASK_LOW); michael@0: if (blockCounts & 1) { michael@0: h1 ^= k1; michael@0: } else { michael@0: h2 ^= k1; michael@0: } michael@0: } michael@0: michael@0: this.h1 = h1; michael@0: this.h2 = h2; michael@0: return this; michael@0: }, michael@0: michael@0: hexdigest: function MurmurHash3_64_hexdigest () { michael@0: var h1 = this.h1; michael@0: var h2 = this.h2; michael@0: michael@0: h1 ^= h2 >>> 1; michael@0: h1 = (h1 * 0xed558ccd & MASK_HIGH) | (h1 * 0x8ccd & MASK_LOW); michael@0: h2 = (h2 * 0xff51afd7 & MASK_HIGH) | michael@0: (((h2 << 16 | h1 >>> 16) * 0xafd7ed55 & MASK_HIGH) >>> 16); michael@0: h1 ^= h2 >>> 1; michael@0: h1 = (h1 * 0x1a85ec53 & MASK_HIGH) | (h1 * 0xec53 & MASK_LOW); michael@0: h2 = (h2 * 0xc4ceb9fe & MASK_HIGH) | michael@0: (((h2 << 16 | h1 >>> 16) * 0xb9fe1a85 & MASK_HIGH) >>> 16); michael@0: h1 ^= h2 >>> 1; michael@0: michael@0: for (var i = 0, arr = [h1, h2], str = ''; i < arr.length; i++) { michael@0: var hex = (arr[i] >>> 0).toString(16); michael@0: while (hex.length < 8) { michael@0: hex = '0' + hex; michael@0: } michael@0: str += hex; michael@0: } michael@0: michael@0: return str; michael@0: } michael@0: }; michael@0: michael@0: return MurmurHash3_64; michael@0: })(); michael@0: /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- / michael@0: /* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ michael@0: /* michael@0: Copyright 2011 notmasteryet michael@0: michael@0: Licensed under the Apache License, Version 2.0 (the "License"); michael@0: you may not use this file except in compliance with the License. michael@0: You may obtain a copy of the License at michael@0: michael@0: http://www.apache.org/licenses/LICENSE-2.0 michael@0: michael@0: Unless required by applicable law or agreed to in writing, software michael@0: distributed under the License is distributed on an "AS IS" BASIS, michael@0: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. michael@0: See the License for the specific language governing permissions and michael@0: limitations under the License. michael@0: */ michael@0: michael@0: // - The JPEG specification can be found in the ITU CCITT Recommendation T.81 michael@0: // (www.w3.org/Graphics/JPEG/itu-t81.pdf) michael@0: // - The JFIF specification can be found in the JPEG File Interchange Format michael@0: // (www.w3.org/Graphics/JPEG/jfif3.pdf) michael@0: // - The Adobe Application-Specific JPEG markers in the Supporting the DCT Filters michael@0: // in PostScript Level 2, Technical Note #5116 michael@0: // (partners.adobe.com/public/developer/en/ps/sdk/5116.DCT_Filter.pdf) michael@0: michael@0: var JpegImage = (function jpegImage() { michael@0: "use strict"; michael@0: var dctZigZag = new Int32Array([ michael@0: 0, michael@0: 1, 8, michael@0: 16, 9, 2, michael@0: 3, 10, 17, 24, michael@0: 32, 25, 18, 11, 4, michael@0: 5, 12, 19, 26, 33, 40, michael@0: 48, 41, 34, 27, 20, 13, 6, michael@0: 7, 14, 21, 28, 35, 42, 49, 56, michael@0: 57, 50, 43, 36, 29, 22, 15, michael@0: 23, 30, 37, 44, 51, 58, michael@0: 59, 52, 45, 38, 31, michael@0: 39, 46, 53, 60, michael@0: 61, 54, 47, michael@0: 55, 62, michael@0: 63 michael@0: ]); michael@0: michael@0: var dctCos1 = 4017 // cos(pi/16) michael@0: var dctSin1 = 799 // sin(pi/16) michael@0: var dctCos3 = 3406 // cos(3*pi/16) michael@0: var dctSin3 = 2276 // sin(3*pi/16) michael@0: var dctCos6 = 1567 // cos(6*pi/16) michael@0: var dctSin6 = 3784 // sin(6*pi/16) michael@0: var dctSqrt2 = 5793 // sqrt(2) michael@0: var dctSqrt1d2 = 2896 // sqrt(2) / 2 michael@0: michael@0: function constructor() { michael@0: } michael@0: michael@0: function buildHuffmanTable(codeLengths, values) { michael@0: var k = 0, code = [], i, j, length = 16; michael@0: while (length > 0 && !codeLengths[length - 1]) michael@0: length--; michael@0: code.push({children: [], index: 0}); michael@0: var p = code[0], q; michael@0: for (i = 0; i < length; i++) { michael@0: for (j = 0; j < codeLengths[i]; j++) { michael@0: p = code.pop(); michael@0: p.children[p.index] = values[k]; michael@0: while (p.index > 0) { michael@0: p = code.pop(); michael@0: } michael@0: p.index++; michael@0: code.push(p); michael@0: while (code.length <= i) { michael@0: code.push(q = {children: [], index: 0}); michael@0: p.children[p.index] = q.children; michael@0: p = q; michael@0: } michael@0: k++; michael@0: } michael@0: if (i + 1 < length) { michael@0: // p here points to last code michael@0: code.push(q = {children: [], index: 0}); michael@0: p.children[p.index] = q.children; michael@0: p = q; michael@0: } michael@0: } michael@0: return code[0].children; michael@0: } michael@0: michael@0: function getBlockBufferOffset(component, row, col) { michael@0: return 64 * ((component.blocksPerLine + 1) * row + col); michael@0: } michael@0: michael@0: function decodeScan(data, offset, michael@0: frame, components, resetInterval, michael@0: spectralStart, spectralEnd, michael@0: successivePrev, successive) { michael@0: var precision = frame.precision; michael@0: var samplesPerLine = frame.samplesPerLine; michael@0: var scanLines = frame.scanLines; michael@0: var mcusPerLine = frame.mcusPerLine; michael@0: var progressive = frame.progressive; michael@0: var maxH = frame.maxH, maxV = frame.maxV; michael@0: michael@0: var startOffset = offset, bitsData = 0, bitsCount = 0; michael@0: michael@0: function readBit() { michael@0: if (bitsCount > 0) { michael@0: bitsCount--; michael@0: return (bitsData >> bitsCount) & 1; michael@0: } michael@0: bitsData = data[offset++]; michael@0: if (bitsData == 0xFF) { michael@0: var nextByte = data[offset++]; michael@0: if (nextByte) { michael@0: throw "unexpected marker: " + ((bitsData << 8) | nextByte).toString(16); michael@0: } michael@0: // unstuff 0 michael@0: } michael@0: bitsCount = 7; michael@0: return bitsData >>> 7; michael@0: } michael@0: michael@0: function decodeHuffman(tree) { michael@0: var node = tree; michael@0: var bit; michael@0: while ((bit = readBit()) !== null) { michael@0: node = node[bit]; michael@0: if (typeof node === 'number') michael@0: return node; michael@0: if (typeof node !== 'object') michael@0: throw "invalid huffman sequence"; michael@0: } michael@0: return null; michael@0: } michael@0: michael@0: function receive(length) { michael@0: var n = 0; michael@0: while (length > 0) { michael@0: var bit = readBit(); michael@0: if (bit === null) return; michael@0: n = (n << 1) | bit; michael@0: length--; michael@0: } michael@0: return n; michael@0: } michael@0: michael@0: function receiveAndExtend(length) { michael@0: var n = receive(length); michael@0: if (n >= 1 << (length - 1)) michael@0: return n; michael@0: return n + (-1 << length) + 1; michael@0: } michael@0: michael@0: function decodeBaseline(component, offset) { michael@0: var t = decodeHuffman(component.huffmanTableDC); michael@0: var diff = t === 0 ? 0 : receiveAndExtend(t); michael@0: component.blockData[offset] = (component.pred += diff); michael@0: var k = 1; michael@0: while (k < 64) { michael@0: var rs = decodeHuffman(component.huffmanTableAC); michael@0: var s = rs & 15, r = rs >> 4; michael@0: if (s === 0) { michael@0: if (r < 15) michael@0: break; michael@0: k += 16; michael@0: continue; michael@0: } michael@0: k += r; michael@0: var z = dctZigZag[k]; michael@0: component.blockData[offset + z] = receiveAndExtend(s); michael@0: k++; michael@0: } michael@0: } michael@0: michael@0: function decodeDCFirst(component, offset) { michael@0: var t = decodeHuffman(component.huffmanTableDC); michael@0: var diff = t === 0 ? 0 : (receiveAndExtend(t) << successive); michael@0: component.blockData[offset] = (component.pred += diff); michael@0: } michael@0: michael@0: function decodeDCSuccessive(component, offset) { michael@0: component.blockData[offset] |= readBit() << successive; michael@0: } michael@0: michael@0: var eobrun = 0; michael@0: function decodeACFirst(component, offset) { michael@0: if (eobrun > 0) { michael@0: eobrun--; michael@0: return; michael@0: } michael@0: var k = spectralStart, e = spectralEnd; michael@0: while (k <= e) { michael@0: var rs = decodeHuffman(component.huffmanTableAC); michael@0: var s = rs & 15, r = rs >> 4; michael@0: if (s === 0) { michael@0: if (r < 15) { michael@0: eobrun = receive(r) + (1 << r) - 1; michael@0: break; michael@0: } michael@0: k += 16; michael@0: continue; michael@0: } michael@0: k += r; michael@0: var z = dctZigZag[k]; michael@0: component.blockData[offset + z] = receiveAndExtend(s) * (1 << successive); michael@0: k++; michael@0: } michael@0: } michael@0: michael@0: var successiveACState = 0, successiveACNextValue; michael@0: function decodeACSuccessive(component, offset) { michael@0: var k = spectralStart, e = spectralEnd, r = 0; michael@0: while (k <= e) { michael@0: var z = dctZigZag[k]; michael@0: switch (successiveACState) { michael@0: case 0: // initial state michael@0: var rs = decodeHuffman(component.huffmanTableAC); michael@0: var s = rs & 15, r = rs >> 4; michael@0: if (s === 0) { michael@0: if (r < 15) { michael@0: eobrun = receive(r) + (1 << r); michael@0: successiveACState = 4; michael@0: } else { michael@0: r = 16; michael@0: successiveACState = 1; michael@0: } michael@0: } else { michael@0: if (s !== 1) michael@0: throw "invalid ACn encoding"; michael@0: successiveACNextValue = receiveAndExtend(s); michael@0: successiveACState = r ? 2 : 3; michael@0: } michael@0: continue; michael@0: case 1: // skipping r zero items michael@0: case 2: michael@0: if (component.blockData[offset + z]) { michael@0: component.blockData[offset + z] += (readBit() << successive); michael@0: } else { michael@0: r--; michael@0: if (r === 0) michael@0: successiveACState = successiveACState == 2 ? 3 : 0; michael@0: } michael@0: break; michael@0: case 3: // set value for a zero item michael@0: if (component.blockData[offset + z]) { michael@0: component.blockData[offset + z] += (readBit() << successive); michael@0: } else { michael@0: component.blockData[offset + z] = successiveACNextValue << successive; michael@0: successiveACState = 0; michael@0: } michael@0: break; michael@0: case 4: // eob michael@0: if (component.blockData[offset + z]) { michael@0: component.blockData[offset + z] += (readBit() << successive); michael@0: } michael@0: break; michael@0: } michael@0: k++; michael@0: } michael@0: if (successiveACState === 4) { michael@0: eobrun--; michael@0: if (eobrun === 0) michael@0: successiveACState = 0; michael@0: } michael@0: } michael@0: michael@0: function decodeMcu(component, decode, mcu, row, col) { michael@0: var mcuRow = (mcu / mcusPerLine) | 0; michael@0: var mcuCol = mcu % mcusPerLine; michael@0: var blockRow = mcuRow * component.v + row; michael@0: var blockCol = mcuCol * component.h + col; michael@0: var offset = getBlockBufferOffset(component, blockRow, blockCol); michael@0: decode(component, offset); michael@0: } michael@0: michael@0: function decodeBlock(component, decode, mcu) { michael@0: var blockRow = (mcu / component.blocksPerLine) | 0; michael@0: var blockCol = mcu % component.blocksPerLine; michael@0: var offset = getBlockBufferOffset(component, blockRow, blockCol); michael@0: decode(component, offset); michael@0: } michael@0: michael@0: var componentsLength = components.length; michael@0: var component, i, j, k, n; michael@0: var decodeFn; michael@0: if (progressive) { michael@0: if (spectralStart === 0) michael@0: decodeFn = successivePrev === 0 ? decodeDCFirst : decodeDCSuccessive; michael@0: else michael@0: decodeFn = successivePrev === 0 ? decodeACFirst : decodeACSuccessive; michael@0: } else { michael@0: decodeFn = decodeBaseline; michael@0: } michael@0: michael@0: var mcu = 0, marker; michael@0: var mcuExpected; michael@0: if (componentsLength == 1) { michael@0: mcuExpected = components[0].blocksPerLine * components[0].blocksPerColumn; michael@0: } else { michael@0: mcuExpected = mcusPerLine * frame.mcusPerColumn; michael@0: } michael@0: if (!resetInterval) { michael@0: resetInterval = mcuExpected; michael@0: } michael@0: michael@0: var h, v; michael@0: while (mcu < mcuExpected) { michael@0: // reset interval stuff michael@0: for (i = 0; i < componentsLength; i++) { michael@0: components[i].pred = 0; michael@0: } michael@0: eobrun = 0; michael@0: michael@0: if (componentsLength == 1) { michael@0: component = components[0]; michael@0: for (n = 0; n < resetInterval; n++) { michael@0: decodeBlock(component, decodeFn, mcu); michael@0: mcu++; michael@0: } michael@0: } else { michael@0: for (n = 0; n < resetInterval; n++) { michael@0: for (i = 0; i < componentsLength; i++) { michael@0: component = components[i]; michael@0: h = component.h; michael@0: v = component.v; michael@0: for (j = 0; j < v; j++) { michael@0: for (k = 0; k < h; k++) { michael@0: decodeMcu(component, decodeFn, mcu, j, k); michael@0: } michael@0: } michael@0: } michael@0: mcu++; michael@0: } michael@0: } michael@0: michael@0: // find marker michael@0: bitsCount = 0; michael@0: marker = (data[offset] << 8) | data[offset + 1]; michael@0: if (marker <= 0xFF00) { michael@0: throw "marker was not found"; michael@0: } michael@0: michael@0: if (marker >= 0xFFD0 && marker <= 0xFFD7) { // RSTx michael@0: offset += 2; michael@0: } else { michael@0: break; michael@0: } michael@0: } michael@0: michael@0: return offset - startOffset; michael@0: } michael@0: michael@0: // A port of poppler's IDCT method which in turn is taken from: michael@0: // Christoph Loeffler, Adriaan Ligtenberg, George S. Moschytz, michael@0: // "Practical Fast 1-D DCT Algorithms with 11 Multiplications", michael@0: // IEEE Intl. Conf. on Acoustics, Speech & Signal Processing, 1989, michael@0: // 988-991. michael@0: function quantizeAndInverse(component, blockBufferOffset, p) { michael@0: var qt = component.quantizationTable; michael@0: var v0, v1, v2, v3, v4, v5, v6, v7, t; michael@0: var i; michael@0: michael@0: // dequant michael@0: for (i = 0; i < 64; i++) { michael@0: p[i] = component.blockData[blockBufferOffset + i] * qt[i]; michael@0: } michael@0: michael@0: // inverse DCT on rows michael@0: for (i = 0; i < 8; ++i) { michael@0: var row = 8 * i; michael@0: michael@0: // check for all-zero AC coefficients michael@0: if (p[1 + row] == 0 && p[2 + row] == 0 && p[3 + row] == 0 && michael@0: p[4 + row] == 0 && p[5 + row] == 0 && p[6 + row] == 0 && michael@0: p[7 + row] == 0) { michael@0: t = (dctSqrt2 * p[0 + row] + 512) >> 10; michael@0: p[0 + row] = t; michael@0: p[1 + row] = t; michael@0: p[2 + row] = t; michael@0: p[3 + row] = t; michael@0: p[4 + row] = t; michael@0: p[5 + row] = t; michael@0: p[6 + row] = t; michael@0: p[7 + row] = t; michael@0: continue; michael@0: } michael@0: michael@0: // stage 4 michael@0: v0 = (dctSqrt2 * p[0 + row] + 128) >> 8; michael@0: v1 = (dctSqrt2 * p[4 + row] + 128) >> 8; michael@0: v2 = p[2 + row]; michael@0: v3 = p[6 + row]; michael@0: v4 = (dctSqrt1d2 * (p[1 + row] - p[7 + row]) + 128) >> 8; michael@0: v7 = (dctSqrt1d2 * (p[1 + row] + p[7 + row]) + 128) >> 8; michael@0: v5 = p[3 + row] << 4; michael@0: v6 = p[5 + row] << 4; michael@0: michael@0: // stage 3 michael@0: t = (v0 - v1+ 1) >> 1; michael@0: v0 = (v0 + v1 + 1) >> 1; michael@0: v1 = t; michael@0: t = (v2 * dctSin6 + v3 * dctCos6 + 128) >> 8; michael@0: v2 = (v2 * dctCos6 - v3 * dctSin6 + 128) >> 8; michael@0: v3 = t; michael@0: t = (v4 - v6 + 1) >> 1; michael@0: v4 = (v4 + v6 + 1) >> 1; michael@0: v6 = t; michael@0: t = (v7 + v5 + 1) >> 1; michael@0: v5 = (v7 - v5 + 1) >> 1; michael@0: v7 = t; michael@0: michael@0: // stage 2 michael@0: t = (v0 - v3 + 1) >> 1; michael@0: v0 = (v0 + v3 + 1) >> 1; michael@0: v3 = t; michael@0: t = (v1 - v2 + 1) >> 1; michael@0: v1 = (v1 + v2 + 1) >> 1; michael@0: v2 = t; michael@0: t = (v4 * dctSin3 + v7 * dctCos3 + 2048) >> 12; michael@0: v4 = (v4 * dctCos3 - v7 * dctSin3 + 2048) >> 12; michael@0: v7 = t; michael@0: t = (v5 * dctSin1 + v6 * dctCos1 + 2048) >> 12; michael@0: v5 = (v5 * dctCos1 - v6 * dctSin1 + 2048) >> 12; michael@0: v6 = t; michael@0: michael@0: // stage 1 michael@0: p[0 + row] = v0 + v7; michael@0: p[7 + row] = v0 - v7; michael@0: p[1 + row] = v1 + v6; michael@0: p[6 + row] = v1 - v6; michael@0: p[2 + row] = v2 + v5; michael@0: p[5 + row] = v2 - v5; michael@0: p[3 + row] = v3 + v4; michael@0: p[4 + row] = v3 - v4; michael@0: } michael@0: michael@0: // inverse DCT on columns michael@0: for (i = 0; i < 8; ++i) { michael@0: var col = i; michael@0: michael@0: // check for all-zero AC coefficients michael@0: if (p[1*8 + col] == 0 && p[2*8 + col] == 0 && p[3*8 + col] == 0 && michael@0: p[4*8 + col] == 0 && p[5*8 + col] == 0 && p[6*8 + col] == 0 && michael@0: p[7*8 + col] == 0) { michael@0: t = (dctSqrt2 * p[i+0] + 8192) >> 14; michael@0: p[0*8 + col] = t; michael@0: p[1*8 + col] = t; michael@0: p[2*8 + col] = t; michael@0: p[3*8 + col] = t; michael@0: p[4*8 + col] = t; michael@0: p[5*8 + col] = t; michael@0: p[6*8 + col] = t; michael@0: p[7*8 + col] = t; michael@0: continue; michael@0: } michael@0: michael@0: // stage 4 michael@0: v0 = (dctSqrt2 * p[0*8 + col] + 2048) >> 12; michael@0: v1 = (dctSqrt2 * p[4*8 + col] + 2048) >> 12; michael@0: v2 = p[2*8 + col]; michael@0: v3 = p[6*8 + col]; michael@0: v4 = (dctSqrt1d2 * (p[1*8 + col] - p[7*8 + col]) + 2048) >> 12; michael@0: v7 = (dctSqrt1d2 * (p[1*8 + col] + p[7*8 + col]) + 2048) >> 12; michael@0: v5 = p[3*8 + col]; michael@0: v6 = p[5*8 + col]; michael@0: michael@0: // stage 3 michael@0: t = (v0 - v1 + 1) >> 1; michael@0: v0 = (v0 + v1 + 1) >> 1; michael@0: v1 = t; michael@0: t = (v2 * dctSin6 + v3 * dctCos6 + 2048) >> 12; michael@0: v2 = (v2 * dctCos6 - v3 * dctSin6 + 2048) >> 12; michael@0: v3 = t; michael@0: t = (v4 - v6 + 1) >> 1; michael@0: v4 = (v4 + v6 + 1) >> 1; michael@0: v6 = t; michael@0: t = (v7 + v5 + 1) >> 1; michael@0: v5 = (v7 - v5 + 1) >> 1; michael@0: v7 = t; michael@0: michael@0: // stage 2 michael@0: t = (v0 - v3 + 1) >> 1; michael@0: v0 = (v0 + v3 + 1) >> 1; michael@0: v3 = t; michael@0: t = (v1 - v2 + 1) >> 1; michael@0: v1 = (v1 + v2 + 1) >> 1; michael@0: v2 = t; michael@0: t = (v4 * dctSin3 + v7 * dctCos3 + 2048) >> 12; michael@0: v4 = (v4 * dctCos3 - v7 * dctSin3 + 2048) >> 12; michael@0: v7 = t; michael@0: t = (v5 * dctSin1 + v6 * dctCos1 + 2048) >> 12; michael@0: v5 = (v5 * dctCos1 - v6 * dctSin1 + 2048) >> 12; michael@0: v6 = t; michael@0: michael@0: // stage 1 michael@0: p[0*8 + col] = v0 + v7; michael@0: p[7*8 + col] = v0 - v7; michael@0: p[1*8 + col] = v1 + v6; michael@0: p[6*8 + col] = v1 - v6; michael@0: p[2*8 + col] = v2 + v5; michael@0: p[5*8 + col] = v2 - v5; michael@0: p[3*8 + col] = v3 + v4; michael@0: p[4*8 + col] = v3 - v4; michael@0: } michael@0: michael@0: // convert to 8-bit integers michael@0: for (i = 0; i < 64; ++i) { michael@0: var index = blockBufferOffset + i; michael@0: component.blockData[index] = clampTo8bitInt((p[i] + 2056) >> 4); michael@0: } michael@0: } michael@0: michael@0: function buildComponentData(frame, component) { michael@0: var lines = []; michael@0: var blocksPerLine = component.blocksPerLine; michael@0: var blocksPerColumn = component.blocksPerColumn; michael@0: var samplesPerLine = blocksPerLine << 3; michael@0: var computationBuffer = new Int32Array(64); michael@0: michael@0: var i, j, ll = 0; michael@0: for (var blockRow = 0; blockRow < blocksPerColumn; blockRow++) { michael@0: for (var blockCol = 0; blockCol < blocksPerLine; blockCol++) { michael@0: var offset = getBlockBufferOffset(component, blockRow, blockCol) michael@0: quantizeAndInverse(component, offset, computationBuffer); michael@0: } michael@0: } michael@0: return component.blockData; michael@0: } michael@0: michael@0: function clampTo8bitInt(a) { michael@0: return a <= 0 ? 0 : a >= 255 ? 255 : a | 0; michael@0: } michael@0: michael@0: function clamp0to255(a) { michael@0: return a <= 0 ? 0 : a >= 255 ? 255 : a; michael@0: } michael@0: michael@0: constructor.prototype = { michael@0: load: function load(path) { michael@0: var xhr = new XMLHttpRequest(); michael@0: xhr.open("GET", path, true); michael@0: xhr.responseType = "arraybuffer"; michael@0: xhr.onload = (function() { michael@0: // TODO catch parse error michael@0: var data = new Uint8Array(xhr.response || xhr.mozResponseArrayBuffer); michael@0: this.parse(data); michael@0: if (this.onload) michael@0: this.onload(); michael@0: }).bind(this); michael@0: xhr.send(null); michael@0: }, michael@0: michael@0: parse: function parse(data) { michael@0: michael@0: function readUint16() { michael@0: var value = (data[offset] << 8) | data[offset + 1]; michael@0: offset += 2; michael@0: return value; michael@0: } michael@0: michael@0: function readDataBlock() { michael@0: var length = readUint16(); michael@0: var array = data.subarray(offset, offset + length - 2); michael@0: offset += array.length; michael@0: return array; michael@0: } michael@0: michael@0: function prepareComponents(frame) { michael@0: var mcusPerLine = Math.ceil(frame.samplesPerLine / 8 / frame.maxH); michael@0: var mcusPerColumn = Math.ceil(frame.scanLines / 8 / frame.maxV); michael@0: for (var i = 0; i < frame.components.length; i++) { michael@0: component = frame.components[i]; michael@0: var blocksPerLine = Math.ceil(Math.ceil(frame.samplesPerLine / 8) * component.h / frame.maxH); michael@0: var blocksPerColumn = Math.ceil(Math.ceil(frame.scanLines / 8) * component.v / frame.maxV); michael@0: var blocksPerLineForMcu = mcusPerLine * component.h; michael@0: var blocksPerColumnForMcu = mcusPerColumn * component.v; michael@0: michael@0: var blocksBufferSize = 64 * blocksPerColumnForMcu michael@0: * (blocksPerLineForMcu + 1); michael@0: component.blockData = new Int16Array(blocksBufferSize); michael@0: component.blocksPerLine = blocksPerLine; michael@0: component.blocksPerColumn = blocksPerColumn; michael@0: } michael@0: frame.mcusPerLine = mcusPerLine; michael@0: frame.mcusPerColumn = mcusPerColumn; michael@0: } michael@0: michael@0: var offset = 0, length = data.length; michael@0: var jfif = null; michael@0: var adobe = null; michael@0: var pixels = null; michael@0: var frame, resetInterval; michael@0: var quantizationTables = []; michael@0: var huffmanTablesAC = [], huffmanTablesDC = []; michael@0: var fileMarker = readUint16(); michael@0: if (fileMarker != 0xFFD8) { // SOI (Start of Image) michael@0: throw "SOI not found"; michael@0: } michael@0: michael@0: fileMarker = readUint16(); michael@0: while (fileMarker != 0xFFD9) { // EOI (End of image) michael@0: var i, j, l; michael@0: switch(fileMarker) { michael@0: case 0xFFE0: // APP0 (Application Specific) michael@0: case 0xFFE1: // APP1 michael@0: case 0xFFE2: // APP2 michael@0: case 0xFFE3: // APP3 michael@0: case 0xFFE4: // APP4 michael@0: case 0xFFE5: // APP5 michael@0: case 0xFFE6: // APP6 michael@0: case 0xFFE7: // APP7 michael@0: case 0xFFE8: // APP8 michael@0: case 0xFFE9: // APP9 michael@0: case 0xFFEA: // APP10 michael@0: case 0xFFEB: // APP11 michael@0: case 0xFFEC: // APP12 michael@0: case 0xFFED: // APP13 michael@0: case 0xFFEE: // APP14 michael@0: case 0xFFEF: // APP15 michael@0: case 0xFFFE: // COM (Comment) michael@0: var appData = readDataBlock(); michael@0: michael@0: if (fileMarker === 0xFFE0) { michael@0: if (appData[0] === 0x4A && appData[1] === 0x46 && appData[2] === 0x49 && michael@0: appData[3] === 0x46 && appData[4] === 0) { // 'JFIF\x00' michael@0: jfif = { michael@0: version: { major: appData[5], minor: appData[6] }, michael@0: densityUnits: appData[7], michael@0: xDensity: (appData[8] << 8) | appData[9], michael@0: yDensity: (appData[10] << 8) | appData[11], michael@0: thumbWidth: appData[12], michael@0: thumbHeight: appData[13], michael@0: thumbData: appData.subarray(14, 14 + 3 * appData[12] * appData[13]) michael@0: }; michael@0: } michael@0: } michael@0: // TODO APP1 - Exif michael@0: if (fileMarker === 0xFFEE) { michael@0: if (appData[0] === 0x41 && appData[1] === 0x64 && appData[2] === 0x6F && michael@0: appData[3] === 0x62 && appData[4] === 0x65 && appData[5] === 0) { // 'Adobe\x00' michael@0: adobe = { michael@0: version: appData[6], michael@0: flags0: (appData[7] << 8) | appData[8], michael@0: flags1: (appData[9] << 8) | appData[10], michael@0: transformCode: appData[11] michael@0: }; michael@0: } michael@0: } michael@0: break; michael@0: michael@0: case 0xFFDB: // DQT (Define Quantization Tables) michael@0: var quantizationTablesLength = readUint16(); michael@0: var quantizationTablesEnd = quantizationTablesLength + offset - 2; michael@0: while (offset < quantizationTablesEnd) { michael@0: var quantizationTableSpec = data[offset++]; michael@0: var tableData = new Int32Array(64); michael@0: if ((quantizationTableSpec >> 4) === 0) { // 8 bit values michael@0: for (j = 0; j < 64; j++) { michael@0: var z = dctZigZag[j]; michael@0: tableData[z] = data[offset++]; michael@0: } michael@0: } else if ((quantizationTableSpec >> 4) === 1) { //16 bit michael@0: for (j = 0; j < 64; j++) { michael@0: var z = dctZigZag[j]; michael@0: tableData[z] = readUint16(); michael@0: } michael@0: } else michael@0: throw "DQT: invalid table spec"; michael@0: quantizationTables[quantizationTableSpec & 15] = tableData; michael@0: } michael@0: break; michael@0: michael@0: case 0xFFC0: // SOF0 (Start of Frame, Baseline DCT) michael@0: case 0xFFC1: // SOF1 (Start of Frame, Extended DCT) michael@0: case 0xFFC2: // SOF2 (Start of Frame, Progressive DCT) michael@0: if (frame) { michael@0: throw "Only single frame JPEGs supported"; michael@0: } michael@0: readUint16(); // skip data length michael@0: frame = {}; michael@0: frame.extended = (fileMarker === 0xFFC1); michael@0: frame.progressive = (fileMarker === 0xFFC2); michael@0: frame.precision = data[offset++]; michael@0: frame.scanLines = readUint16(); michael@0: frame.samplesPerLine = readUint16(); michael@0: frame.components = []; michael@0: frame.componentIds = {}; michael@0: var componentsCount = data[offset++], componentId; michael@0: var maxH = 0, maxV = 0; michael@0: for (i = 0; i < componentsCount; i++) { michael@0: componentId = data[offset]; michael@0: var h = data[offset + 1] >> 4; michael@0: var v = data[offset + 1] & 15; michael@0: if (maxH < h) maxH = h; michael@0: if (maxV < v) maxV = v; michael@0: var qId = data[offset + 2]; michael@0: var l = frame.components.push({ michael@0: h: h, michael@0: v: v, michael@0: quantizationTable: quantizationTables[qId] michael@0: }); michael@0: frame.componentIds[componentId] = l - 1; michael@0: offset += 3; michael@0: } michael@0: frame.maxH = maxH; michael@0: frame.maxV = maxV; michael@0: prepareComponents(frame); michael@0: break; michael@0: michael@0: case 0xFFC4: // DHT (Define Huffman Tables) michael@0: var huffmanLength = readUint16(); michael@0: for (i = 2; i < huffmanLength;) { michael@0: var huffmanTableSpec = data[offset++]; michael@0: var codeLengths = new Uint8Array(16); michael@0: var codeLengthSum = 0; michael@0: for (j = 0; j < 16; j++, offset++) michael@0: codeLengthSum += (codeLengths[j] = data[offset]); michael@0: var huffmanValues = new Uint8Array(codeLengthSum); michael@0: for (j = 0; j < codeLengthSum; j++, offset++) michael@0: huffmanValues[j] = data[offset]; michael@0: i += 17 + codeLengthSum; michael@0: michael@0: ((huffmanTableSpec >> 4) === 0 ? michael@0: huffmanTablesDC : huffmanTablesAC)[huffmanTableSpec & 15] = michael@0: buildHuffmanTable(codeLengths, huffmanValues); michael@0: } michael@0: break; michael@0: michael@0: case 0xFFDD: // DRI (Define Restart Interval) michael@0: readUint16(); // skip data length michael@0: resetInterval = readUint16(); michael@0: break; michael@0: michael@0: case 0xFFDA: // SOS (Start of Scan) michael@0: var scanLength = readUint16(); michael@0: var selectorsCount = data[offset++]; michael@0: var components = [], component; michael@0: for (i = 0; i < selectorsCount; i++) { michael@0: var componentIndex = frame.componentIds[data[offset++]]; michael@0: component = frame.components[componentIndex]; michael@0: var tableSpec = data[offset++]; michael@0: component.huffmanTableDC = huffmanTablesDC[tableSpec >> 4]; michael@0: component.huffmanTableAC = huffmanTablesAC[tableSpec & 15]; michael@0: components.push(component); michael@0: } michael@0: var spectralStart = data[offset++]; michael@0: var spectralEnd = data[offset++]; michael@0: var successiveApproximation = data[offset++]; michael@0: var processed = decodeScan(data, offset, michael@0: frame, components, resetInterval, michael@0: spectralStart, spectralEnd, michael@0: successiveApproximation >> 4, successiveApproximation & 15); michael@0: offset += processed; michael@0: break; michael@0: default: michael@0: if (data[offset - 3] == 0xFF && michael@0: data[offset - 2] >= 0xC0 && data[offset - 2] <= 0xFE) { michael@0: // could be incorrect encoding -- last 0xFF byte of the previous michael@0: // block was eaten by the encoder michael@0: offset -= 3; michael@0: break; michael@0: } michael@0: throw "unknown JPEG marker " + fileMarker.toString(16); michael@0: } michael@0: fileMarker = readUint16(); michael@0: } michael@0: michael@0: this.width = frame.samplesPerLine; michael@0: this.height = frame.scanLines; michael@0: this.jfif = jfif; michael@0: this.adobe = adobe; michael@0: this.components = []; michael@0: for (var i = 0; i < frame.components.length; i++) { michael@0: var component = frame.components[i]; michael@0: this.components.push({ michael@0: output: buildComponentData(frame, component), michael@0: scaleX: component.h / frame.maxH, michael@0: scaleY: component.v / frame.maxV, michael@0: blocksPerLine: component.blocksPerLine, michael@0: blocksPerColumn: component.blocksPerColumn michael@0: }); michael@0: } michael@0: }, michael@0: michael@0: getData: function getData(width, height) { michael@0: var scaleX = this.width / width, scaleY = this.height / height; michael@0: michael@0: var component, componentScaleX, componentScaleY; michael@0: var x, y, i; michael@0: var offset = 0; michael@0: var Y, Cb, Cr, K, C, M, Ye, R, G, B; michael@0: var colorTransform; michael@0: var numComponents = this.components.length; michael@0: var dataLength = width * height * numComponents; michael@0: var data = new Uint8Array(dataLength); michael@0: var componentLine; michael@0: michael@0: // lineData is reused for all components. Assume first component is michael@0: // the biggest michael@0: var lineData = new Uint8Array((this.components[0].blocksPerLine << 3) * michael@0: this.components[0].blocksPerColumn * 8); michael@0: michael@0: // First construct image data ... michael@0: for (i = 0; i < numComponents; i++) { michael@0: component = this.components[i]; michael@0: var blocksPerLine = component.blocksPerLine; michael@0: var blocksPerColumn = component.blocksPerColumn; michael@0: var samplesPerLine = blocksPerLine << 3; michael@0: michael@0: var j, k, ll = 0; michael@0: var lineOffset = 0; michael@0: for (var blockRow = 0; blockRow < blocksPerColumn; blockRow++) { michael@0: var scanLine = blockRow << 3; michael@0: for (var blockCol = 0; blockCol < blocksPerLine; blockCol++) { michael@0: var bufferOffset = getBlockBufferOffset(component, blockRow, blockCol); michael@0: var offset = 0, sample = blockCol << 3; michael@0: for (j = 0; j < 8; j++) { michael@0: var lineOffset = (scanLine + j) * samplesPerLine; michael@0: for (k = 0; k < 8; k++) { michael@0: lineData[lineOffset + sample + k] = michael@0: component.output[bufferOffset + offset++]; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: componentScaleX = component.scaleX * scaleX; michael@0: componentScaleY = component.scaleY * scaleY; michael@0: offset = i; michael@0: michael@0: var cx, cy; michael@0: var index; michael@0: for (y = 0; y < height; y++) { michael@0: for (x = 0; x < width; x++) { michael@0: cy = 0 | (y * componentScaleY); michael@0: cx = 0 | (x * componentScaleX); michael@0: index = cy * samplesPerLine + cx; michael@0: data[offset] = lineData[index]; michael@0: offset += numComponents; michael@0: } michael@0: } michael@0: } michael@0: michael@0: // ... then transform colors, if necessary michael@0: switch (numComponents) { michael@0: case 1: case 2: break; michael@0: // no color conversion for one or two compoenents michael@0: michael@0: case 3: michael@0: // The default transform for three components is true michael@0: colorTransform = true; michael@0: // The adobe transform marker overrides any previous setting michael@0: if (this.adobe && this.adobe.transformCode) michael@0: colorTransform = true; michael@0: else if (typeof this.colorTransform !== 'undefined') michael@0: colorTransform = !!this.colorTransform; michael@0: michael@0: if (colorTransform) { michael@0: for (i = 0; i < dataLength; i += numComponents) { michael@0: Y = data[i ]; michael@0: Cb = data[i + 1]; michael@0: Cr = data[i + 2]; michael@0: michael@0: R = clamp0to255(Y + 1.402 * (Cr - 128)); michael@0: G = clamp0to255(Y - 0.3441363 * (Cb - 128) - 0.71413636 * (Cr - 128)); michael@0: B = clamp0to255(Y + 1.772 * (Cb - 128)); michael@0: michael@0: data[i ] = R; michael@0: data[i + 1] = G; michael@0: data[i + 2] = B; michael@0: } michael@0: } michael@0: break; michael@0: case 4: michael@0: // The default transform for four components is false michael@0: colorTransform = false; michael@0: // The adobe transform marker overrides any previous setting michael@0: if (this.adobe && this.adobe.transformCode) michael@0: colorTransform = true; michael@0: else if (typeof this.colorTransform !== 'undefined') michael@0: colorTransform = !!this.colorTransform; michael@0: michael@0: if (colorTransform) { michael@0: for (i = 0; i < dataLength; i += numComponents) { michael@0: Y = data[i]; michael@0: Cb = data[i + 1]; michael@0: Cr = data[i + 2]; michael@0: michael@0: C = 255 - clamp0to255(Y + 1.402 * (Cr - 128)); michael@0: M = 255 - clamp0to255(Y - 0.3441363 * (Cb - 128) - 0.71413636 * (Cr - 128)); michael@0: Ye = 255 - clamp0to255(Y + 1.772 * (Cb - 128)); michael@0: michael@0: data[i ] = C; michael@0: data[i + 1] = M; michael@0: data[i + 2] = Ye; michael@0: // K is unchanged michael@0: } michael@0: } michael@0: break; michael@0: default: michael@0: throw 'Unsupported color mode'; michael@0: } michael@0: return data; michael@0: }, michael@0: copyToImageData: function copyToImageData(imageData) { michael@0: var width = imageData.width, height = imageData.height; michael@0: var imageDataBytes = width * height * 4; michael@0: var imageDataArray = imageData.data; michael@0: var data = this.getData(width, height); michael@0: var i = 0, j = 0; michael@0: var Y, K, C, M, R, G, B; michael@0: switch (this.components.length) { michael@0: case 1: michael@0: while (j < imageDataBytes) { michael@0: Y = data[i++]; michael@0: michael@0: imageDataArray[j++] = Y; michael@0: imageDataArray[j++] = Y; michael@0: imageDataArray[j++] = Y; michael@0: imageDataArray[j++] = 255; michael@0: } michael@0: break; michael@0: case 3: michael@0: while (j < imageDataBytes) { michael@0: R = data[i++]; michael@0: G = data[i++]; michael@0: B = data[i++]; michael@0: michael@0: imageDataArray[j++] = R; michael@0: imageDataArray[j++] = G; michael@0: imageDataArray[j++] = B; michael@0: imageDataArray[j++] = 255; michael@0: } michael@0: break; michael@0: case 4: michael@0: while (j < imageDataBytes) { michael@0: C = data[i++]; michael@0: M = data[i++]; michael@0: Y = data[i++]; michael@0: K = data[i++]; michael@0: michael@0: R = 255 - clamp0to255(C * (1 - K / 255) + K); michael@0: G = 255 - clamp0to255(M * (1 - K / 255) + K); michael@0: B = 255 - clamp0to255(Y * (1 - K / 255) + K); michael@0: michael@0: imageDataArray[j++] = R; michael@0: imageDataArray[j++] = G; michael@0: imageDataArray[j++] = B; michael@0: imageDataArray[j++] = 255; michael@0: } michael@0: break; michael@0: default: michael@0: throw 'Unsupported color mode'; michael@0: } michael@0: } michael@0: }; michael@0: michael@0: return constructor; michael@0: })(); michael@0: michael@0: michael@0: }).call((typeof window === 'undefined') ? this : window); michael@0: michael@0: michael@0: