PrintColorXFormsImpl.mesa
Copyright Ó 1987 by Xerox Corporation. All rights reserved.
Maureen Stone, July 27, 1989 12:59:11 pm PDT
Color Transformation routines for printing monitor images
DIRECTORY
PrintColorXForms,
PrintColor USING [ColorCorrection, CorrectionProc, ColorCorrectionRep],
ImagerSample USING [PointerToSamples],
ImagerPixel USING [PixelBuffer],
CalibratedColor USING [RGBCalibration, XYZ, XYZFromRGB],
CalibratedColorFns USING [LStarFromLuminance],
Real, RealFns, Basics,
FS USING [StreamOpen],
IO USING [STREAM, GetCard, GetLineRope, Close, GetID],
Rope USING [ROPE];
PrintColorXFormsImpl: CEDAR PROGRAM
IMPORTS Real, RealFns, ImagerSample, FS, IO, CalibratedColor, CalibratedColorFns
EXPORTS PrintColorXForms
~ BEGIN OPEN PrintColorXForms;
ROPE: TYPE ~ Rope.ROPE;
ColorCorrection: TYPE ~ PrintColor.ColorCorrection;
XYZ: TYPE ~ CalibratedColor.XYZ;
SWOP Transformation
SWOP Standard GCR and black
SWOPData: TYPE = REF SWOPDataRec;
SWOPDataRec: TYPE = RECORD[gcTable, cyanTable, magentaTable, yellowTable, blackTable: TRCTable ← NIL, rgbToCMY: RGBToCMYProc, rgbToCMYData: REFNIL];
SWOPLinearDotArea: PUBLIC PROC RETURNS[ColorCorrection] = {
maxSampleOut: NAT = 255;
cc: ColorCorrection ← NEW[PrintColor.ColorCorrectionRep ← [
type: $SWOP,
correctionProc: SWOPColorCorrectionProc,
maxSampleIn: [255, 255, 255],
samplesPerPixelOut: maxSampleOut,
data: NEW[SWOPDataRec ← [
cyanTable: cyanTable,
magentaTable: magentaTable,
yellowTable: yellowTable,
blackTable: blackTable,
gcTable: IdentityTRC[],
rgbToCMY: FlipRGB,
rgbToCMYData: NIL
]]
]];
RETURN[cc];
};
SWOPWithGCLinearLStar: PUBLIC PROC RETURNS[ColorCorrection] = {
maxSampleOut: NAT = 255;
cc: ColorCorrection ← NEW[PrintColor.ColorCorrectionRep ← [
type: $SWOPLinearLStar,
correctionProc: SWOPColorCorrectionProc,
maxSampleIn: [255, 255, 255],
samplesPerPixelOut: maxSampleOut,
data: NEW[SWOPDataRec ← [
cyanTable: cyanTable,
magentaTable: magentaTable,
yellowTable: yellowTable,
blackTable: blackTable,
gcTable: convertToLStar,
rgbToCMY: FlipRGB,
rgbToCMYData: NIL
]]
]];
RETURN[cc];
};
SWOPWithMatrix: PUBLIC PROC[matrixTables: MatrixTables] RETURNS[ColorCorrection] = {
maxSampleOut: NAT = 255;
cc: ColorCorrection ← NEW[PrintColor.ColorCorrectionRep ← [
type: $SWOPWithMatrix,
correctionProc: SWOPColorCorrectionProc,
maxSampleIn: [255, 255, 255],
samplesPerPixelOut: maxSampleOut,
data: NEW[SWOPDataRec ← [
cyanTable: cyanTable,
magentaTable: magentaTable,
yellowTable: yellowTable,
blackTable: blackTable,
gcTable: convertToLStar,
rgbToCMY: MatrixTransform,
rgbToCMYData: matrixTables
]]
]];
RETURN[cc];
};
SWOPColorCorrectionProc: PrintColor.CorrectionProc = {
c,m,y,k, gc: NAT;
data: SWOPData ← NARROW[self.data];
data.rgbToCMY[maxSampleIn: self.maxSampleIn, rgbIn: rgbIn, cmyOut: pixelsOut, data: data.rgbToCMYData];
FOR i: NAT IN [0..pixelsOut.length) DO
c ← pixelsOut[0][i];
m ← pixelsOut[1][i];
y ← pixelsOut[2][i];
gc ← data.gcTable[MIN[c,m,y]];
c ← MAX[0, MIN[255, c-gc+data.cyanTable[gc]]];
m ← MAX[0, MIN[255, m-gc+data.magentaTable[gc]]];
y ← MAX[0, MIN[255, y-gc+data.yellowTable[gc]]];
k ← data.blackTable[gc];
pixelsOut[0][i] ← c;
pixelsOut[1][i] ← m;
pixelsOut[2][i] ← y;
pixelsOut[3][i] ← k;
ENDLOOP;
};
RGB Transformations
Largest24bitNumber: INT ~ 77777777B;
BYTE: TYPE ~ [0..377B];
InitMatrixTables: PUBLIC PROC[rgbToLStar, densityToDotArea: TRCTable, printerDMax, saturation, contrast: REAL, matrix: MatrixN ← NIL] RETURNS[MatrixTables] ~ {
LToDTable: PROC [matrixEl:REAL, trc:TRCTable ← NIL] RETURNS [table: MatrixEltTable] ~ {
-- table values range from -LAST[INT]...LAST[INT]
-- representation for printerDMax = Largest24bitNumber
-- trc=NIL means that no mapping is to be performed. i.e. inputs are density coded
Dens24FromLStarRel : PROC [pixel:NAT] RETURNS [tableValue: INT] ~ {
dens: REAL ← LStarToDens[printerLStarMin + (printerRange * (pixel / 255.0))] * matrixEl;
tableValue ← Real.InlineRound[ (dens / printerDMax) * Largest24bitNumber];
};
table ← NEW[MatrixEltTableRec];
FOR i: NAT IN [0..255] DO
table[i] ← Dens24FromLStarRel[trc[i]];
ENDLOOP
};
blackValue:NAT = 255;
printerLStarMin, printerRange: REAL;
tables: MatrixTables ← NEW[MatrixTablesRec];
IF matrix=NIL THEN matrix ← IdentityMatrix[];
FOR i:NAT IN [0..2] DO -- add required saturation boost
FOR j:NAT IN [0..2] DO
IF i=j THEN
matrix[i][j] ← matrix[i][j] + saturation*2
ELSE
matrix[i][j] ← matrix[i][j] - saturation
ENDLOOP;
ENDLOOP;
FOR i:NAT IN [0..2] DO -- add required contrast boost
matrix[i][i] ← matrix[i][i] + contrast;
ENDLOOP;
printerLStarMin ← DensToLStar[printerDMax];
printerRange ← 100.0 - printerLStarMin;
tables.m00 ← LToDTable[matrix[0][0], rgbToLStar];
tables.m10 ← LToDTable[matrix[1][0], rgbToLStar];
tables.m20 ← LToDTable[matrix[2][0], rgbToLStar];
tables.m01 ← LToDTable[matrix[0][1], rgbToLStar];
tables.m11 ← LToDTable[matrix[1][1], rgbToLStar];
tables.m21 ← LToDTable[matrix[2][1], rgbToLStar];
tables.m02 ← LToDTable[matrix[0][2], rgbToLStar];
tables.m12 ← LToDTable[matrix[1][2], rgbToLStar];
tables.m22 ← LToDTable[matrix[2][2], rgbToLStar];
tables.cyan ← densityToDotArea;
tables.magenta ← densityToDotArea;
tables.yellow ← densityToDotArea;
RETURN [tables]
};
LStarToRef: PROC [lstar: REAL] RETURNS [ref: REAL] ~ {
IF lstar<8.9 THEN ref ← lstar / 903.29
ELSE {
t: REAL ← (lstar+16) / 116.0;
ref ← t * t * t;
}
};
RefToLstar: PROC [ref: REAL] RETURNS [lstar: REAL] ~ {
IF ref<0.01 THEN lstar ← ref * 903.29
ELSE {
lstar ← 116.0 * RealFns.Root[3, ref] - 16;
}
};
RefToDens: PROC [ref: REAL] RETURNS [dens: REAL] ~ {
IF ref=0 THEN RETURN [Real.LargestNumber];
dens ← -RealFns.Log[10, ref]
};
LStarToDens: PROC [lstar: REAL] RETURNS [dens: REAL] ~ {
dens ← RefToDens[LStarToRef[lstar]];
};
DensToLStar: PROC [dens: REAL] RETURNS [lstar: REAL] ~ {
lstar ← RefToLstar[DensToRef[dens]];
};
DensToRef: PROC [dens: REAL] RETURNS [ref: REAL] ~ {
ref ← RealFns.Power[10, -dens];
};
FlipRGB: PUBLIC RGBToCMYProc = { --CMY ← [255,255, 255] -RGB
maxRed: CARDINAL ← maxSampleIn[0];
maxGreen: CARDINAL ← maxSampleIn[1];
maxBlue: CARDINAL ← maxSampleIn[2];
FOR i: NAT IN [0..rgbIn.length) DO
cmyOut[0][i] ← maxRed-rgbIn[0][i];
cmyOut[1][i] ← maxGreen-rgbIn[1][i];
cmyOut[2][i] ← maxBlue-rgbIn[2][i];
ENDLOOP;
};
MatrixTransform: PUBLIC RGBToCMYProc = {
tables: MatrixTables ← NARROW[data];
rPtr: LONG POINTER TO WORDLOOPHOLE[ImagerSample.PointerToSamples[rgbIn[0], 0, rgbIn.length]];
gPtr: LONG POINTER TO WORDLOOPHOLE[ImagerSample.PointerToSamples[rgbIn[1], 0, rgbIn.length]];
bPtr: LONG POINTER TO WORDLOOPHOLE[ImagerSample.PointerToSamples[rgbIn[2], 0, rgbIn.length]];
yPtr: LONG POINTER TO WORDLOOPHOLE[ImagerSample.PointerToSamples[cmyOut[2], 0, cmyOut.length]];
mPtr: LONG POINTER TO WORDLOOPHOLE[ImagerSample.PointerToSamples[cmyOut[1], 0, cmyOut.length]];
cPtr: LONG POINTER TO WORDLOOPHOLE[ImagerSample.PointerToSamples[cmyOut[0], 0, cmyOut.length]];
m00: MatrixEltTable ← tables.m00;
m01: MatrixEltTable ← tables.m01;
m02: MatrixEltTable ← tables.m02;
m10: MatrixEltTable ← tables.m10;
m11: MatrixEltTable ← tables.m11;
m12: MatrixEltTable ← tables.m12;
m20: MatrixEltTable ← tables.m20;
m21: MatrixEltTable ← tables.m21;
m22: MatrixEltTable ← tables.m22;
yellow: TRCTable ← tables.yellow;
magenta: TRCTable ← tables.magenta;
cyan: TRCTable ← tables.cyan;
FOR j: NAT IN [0..cmyOut.length) DO TRUSTED {
r: CARDINAL ← rPtr^; g: CARDINAL ← gPtr^; b: CARDINAL ← bPtr^;
cyan24: INT ~ MAX[
MIN[m00[r] + m01[g] + m02[b], Largest24bitNumber],
0];
mag24: INT ~ MAX[
MIN[m10[r] + m11[g] + m12[b], Largest24bitNumber],
0];
yel24: INT ~ MAX[
MIN[m20[r] + m21[g] + m22[b], Largest24bitNumber],
0];
yPtr^ ← 255-yellow[LOOPHOLE[yel24, Basics.LongNumber].hl];
mPtr^ ← 255-magenta[LOOPHOLE[mag24, Basics.LongNumber].hl];
cPtr^ ← 255-cyan[LOOPHOLE[cyan24, Basics.LongNumber].hl];
rPtr ← rPtr + 1; gPtr ← gPtr + 1; bPtr ← bPtr + 1;
yPtr ← yPtr + 1; mPtr ← mPtr + 1; cPtr ← cPtr + 1;
} ENDLOOP;
};
Utility Procedures
ReadTRC: PUBLIC PROC [trcFn: ROPE] RETURNS [trc: TRCTable] ~ {
in: IO.STREAM;
in ← FS.StreamOpen[trcFn];
trc ← NEW[TRCTableRec ← ALL[0]];
[] ← in.GetID[];
FOR i:CARDINAL IN [0..255] DO
index:CARDINAL;
prev:CARDINAL ← index;
index ← in.GetCard[];
IF index>0 AND prev+1#index THEN ERROR;
prev ← index;
trc[index] ← IO.GetCard[in];
[] ← in.GetLineRope[];
ENDLOOP;
in.Close[];
};
IdentityTRC: PUBLIC PROC [] RETURNS [initTrc:TRCTable] ~ {
initTrc ← NEW[TRCTableRec ← ALL[0]];
FOR i: NAT IN [0..255] DO
initTrc[i] ← i;
ENDLOOP
};
RGBToLStar: PUBLIC PROC [cal: CalibratedColor.RGBCalibration] RETURNS [convertRGB:TRCTable] = {
white: XYZ ← CalibratedColor.XYZFromRGB[[1,1,1], cal];
getLStar: PROC [val: REAL] RETURNS[lStar: REAL] = { --val in [0..1]
xyz: XYZ ← CalibratedColor.XYZFromRGB[[val, val, val], cal];
lStar ← CalibratedColorFns.LStarFromLuminance[Y: xyz.Y, whiteY: white.Y];
};
step: REAL ← 1.0/255.0;
convertRGB ← NEW[TRCTableRec];
FOR val: INT IN [0..256) DO
convertRGB[val] ← Real.Round[2.55*getLStar[val*step]];
ENDLOOP;
};
DensityToLStar: PUBLIC PROC [dMax: REAL] RETURNS [trc:TRCTable] ~ {
minLStar: REAL ← DensToLStar[dMax];
scale: REAL ← 2.55*100.0/(100-minLStar);
trc ← NEW[TRCTableRec ← ALL[0]];
FOR i: NAT IN [0..255] DO
trc[i] ← Real.Round[scale*(DensToLStar[dMax*(i/255.0)]-minLStar)];
ENDLOOP
};
MatrixFromValues: PUBLIC PROC[c0,m0,y0,c1,m1,y1,c2,m2,y2: REAL] RETURNS[MatrixN] = {
matrix: MatrixN ← NEW[MatrixSeq[3]];
matrix[0] ← NEW[VecSeq[3]];
matrix[0][0] ← c0;
matrix[0][1] ← m0;
matrix[0][2] ← y0;
matrix[1] ← NEW[VecSeq[3]];
matrix[1][0] ← c1;
matrix[1][1] ← m1;
matrix[1][2] ← y1;
matrix[2] ← NEW[VecSeq[3]];
matrix[2][0] ← c2;
matrix[2][1] ← m2;
matrix[2][2] ← y2;
RETURN[matrix];
};
IdentityMatrix: PUBLIC PROC RETURNS[MatrixN] = {
RETURN[MatrixFromValues[1,0,0,0,1,0,0,0,1]];
};
BuildTables: PROC = { --use of this is odd. Run it to read the TRC's, print result and copy it into the code below. Prefer to keep result pickled in code. Data comes from measuring and processing a gray wedge produced by Kedie-Orent.
cyanTable ← ReadTRC["/ivy/stone/coloroffset/SWOP-cyan.trc"];
magentaTable ← ReadTRC["/ivy/stone/coloroffset/SWOP-magenta.trc"];
yellowTable ← ReadTRC["/ivy/stone/coloroffset/SWOP-yellow.trc"];
blackTable ← ReadTRC["/ivy/stone/coloroffset/SWOP-black.trc"];
};
cyanTable: TRCTable ← NEW[TRCTableRec ←
[0, 1, 3, 4, 6, 7, 9, 10, 11, 12, 13, 15, 16, 17, 18, 19, 20, 22, 23, 24, 25, 26, 27, 29, 30, 31, 32, 33, 34, 36, 37, 38, 39, 40, 42, 43, 44, 46, 47, 48, 50, 51, 52, 54, 55, 57, 58, 59, 61, 62, 63, 65, 66, 67, 69, 70, 72, 73, 75, 76, 77, 79, 80, 82, 83, 85, 86, 87, 89, 90, 92, 93, 95, 96, 97, 98, 99, 100, 101, 102, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 172, 173, 174, 175, 175, 176, 177, 178, 178, 179, 180, 181, 181, 182, 183, 184, 184, 185, 186, 187, 187, 188, 189, 190, 190, 191, 192, 193, 193, 194, 195, 196, 196, 197, 198, 199, 199, 200, 201, 202, 202, 203, 204, 204, 205, 205, 206, 206, 207, 207, 208, 208, 209, 209, 210, 210, 211, 211, 212, 212, 213, 213, 214, 214, 215, 215, 216, 216, 217, 217, 218, 218, 219, 219, 219, 220, 220, 221, 221, 221, 222, 222, 223, 223, 223, 224, 224, 225, 225, 225, 226, 226, 227, 227, 228, 228, 229, 229, 230, 231, 231, 232, 233, 233, 234, 234, 235]];
magentaTable: TRCTable ← NEW[TRCTableRec ←
[0, 0, 1, 1, 2, 2, 3, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 52, 53, 54, 55, 56, 58, 59, 60, 61, 62, 63, 65, 66, 67, 68, 69, 71, 72, 73, 74, 75, 75, 76, 77, 78, 79, 79, 80, 81, 82, 83, 84, 84, 85, 86, 87, 88, 88, 89, 90, 91, 92, 92, 93, 94, 95, 96, 97, 97, 98, 99, 100, 101, 102, 102, 103, 104, 105, 106, 107, 108, 108, 109, 110, 111, 112, 113, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 138, 139, 140, 141, 141, 142, 143, 144, 144, 145, 146, 147, 147, 148, 149, 150, 150, 151, 152, 153, 153, 154, 155, 155, 156, 157, 157, 158, 159, 159, 160, 160, 161, 162, 162, 163, 164, 164, 165, 166, 166, 167, 168, 168, 169, 169, 170, 170, 171, 171, 172, 172, 173, 173, 174, 174, 175, 175, 176, 176, 177, 177, 178, 178, 179, 179, 180, 180, 181, 182, 182, 183, 183, 184, 184, 185, 185, 186, 186, 187, 187, 188, 188, 189, 189, 190, 190, 191, 191, 192, 192, 193, 193, 194, 195, 195, 196, 196, 197, 197, 198, 198, 199, 199, 200, 200, 201]];
yellowTable: TRCTable ← NEW[TRCTableRec ←
[0, 0, 1, 1, 2, 2, 3, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 16, 18, 19, 20, 21, 22, 23, 24, 25, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 56, 57, 58, 59, 60, 62, 63, 64, 65, 66, 67, 69, 70, 71, 72, 73, 75, 76, 77, 78, 79, 80, 81, 82, 83, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 95, 96, 97, 98, 99, 100, 101, 102, 103, 103, 104, 105, 106, 107, 107, 108, 109, 110, 111, 112, 112, 113, 114, 115, 116, 116, 117, 118, 119, 120, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 143, 144, 145, 145, 146, 147, 147, 148, 149, 149, 150, 151, 151, 152, 153, 153, 154, 155, 155, 156, 157, 157, 158, 158, 159, 160, 160, 161, 161, 162, 163, 163, 164, 165, 165, 166, 166, 167, 168, 168, 169, 169, 170, 170, 171, 171, 172, 172, 172, 173, 173, 174, 174, 174, 175, 175, 176, 176, 177, 177, 177, 178, 178, 179, 179, 179, 180, 180, 181, 181, 181, 182, 182, 183, 183, 183, 184, 184, 185, 185, 185, 186, 186, 187, 187, 187, 188, 188, 189, 189, 189, 190, 190, 191, 191, 192, 192, 193, 193, 194, 195, 195, 196, 197, 197, 198, 198, 199]];
blackTable: TRCTable ← NEW[TRCTableRec ←
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 10, 10, 11, 11, 12, 13, 13, 14, 15, 15, 16, 17, 17, 18, 18, 19, 20, 20, 21, 22, 22, 23, 24, 24, 25, 26, 26, 27, 28, 29, 30, 31, 32, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 134, 135, 136, 137, 138, 139, 140, 142, 144, 146, 147, 149, 151, 153, 155, 157, 158, 160, 162, 164]];
convertToLStar: TRCTable ← NEW[TRCTableRec ←
[0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 28, 28, 29, 29, 30, 30, 31, 31, 32, 32, 33, 33, 34, 34, 35, 35, 36, 37, 37, 38, 39, 40, 41, 42, 43, 43, 44, 45, 46, 47, 48, 49, 49, 50, 51, 52, 53, 53, 54, 55, 56, 56, 57, 58, 59, 59, 60, 61, 61, 62, 63, 63, 64, 65, 65, 66, 67, 67, 68, 68, 69, 70, 70, 71, 71, 72, 72, 73, 74, 75, 76, 77, 79, 80, 81, 82, 83, 84, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 116, 117, 118, 119, 120, 121, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 137, 138, 139, 140, 141, 141, 142, 143, 144, 144, 145, 146, 147, 148, 150, 151, 152, 154, 155, 156, 158, 159, 160, 162, 163, 164, 165, 167, 168, 169, 170, 171, 172, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 185, 187, 189, 191, 193, 195, 197, 199, 201, 203, 205, 207, 209, 211, 213, 214, 216, 218, 221, 224, 228, 231, 234, 236, 239, 241, 243, 245, 247, 248, 250, 251, 253, 254, 255]];
END.