using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Text;
using System.Drawing.Imaging;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.Load += new EventHandler(Form1_Load);
this.Shown += new EventHandler(Form1_Shown);
}
FontFamily[] ffs;
TextBox tb;
PlayCard pc;
//保存場所はデスクトップ
string cardPass = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory) + "\\card\\";
private void Form1_Load(object sender, EventArgs e)
{
tb = new TextBox();
tb.Multiline = true;
tb.Dock = DockStyle.Fill;
tb.ScrollBars = ScrollBars.Both;
this.Controls.Add(tb);
InstalledFontCollection ifc = new InstalledFontCollection();
ffs = ifc.Families;
if (!Directory.Exists(cardPass))
Directory.CreateDirectory(cardPass);
}
private void Form1_Shown(object sender, EventArgs e)
{
pc = new PlayCard();
pc.ScaleX = 0.5f;
pc.ScaleY = 0.5f;
//pc.Outline = false;
//Bitmap allbmp = new Bitmap(pc.Size.Width * 14, pc.Size.Height * 4, PixelFormat.Format32bppArgb);
for (int k = 0; k < 4; k++)
{
for (int j = 0; j < 14; j++)
{
Bitmap bmp = pc.GetPlayCard(k, j);
//using (Graphics g = Graphics.FromImage(allbmp))
//{
// g.DrawImage(bmp, new Point(j * pc.Size.Width, k * pc.Size.Height));
//}
string viewtext = cardPass + pc.CardInitial[k] + (j + 1).ToString("00") + ".png";
bmp.Save(viewtext, ImageFormat.Png);
tb.AppendText(viewtext + "\r\n");
Application.DoEvents();
}
}
//allbmp.Save(cardPass + "allcard.png", ImageFormat.Png);
tb.AppendText("end");
}
}
class PlayCard : PlayCardMark
{
public Color BackgroundColor { get; set; }
public Color FillColor { get; set; }
public PixelFormat PixelFormat { get; set; }
public bool Outline { get; set; }
public int OutlineWidth { get; set; }
public Color OutlineColor { get; set; }
public string[] CardInitial = new string[]
{
"S","D","C","H"
};
public PlayCard()
{
this.PixelFormat = PixelFormat.Format32bppArgb;
this.Outline = true;
this.OutlineWidth = 1;
this.OutlineColor = Color.Black;
this.FontName = "MS Pゴシック";
this.FillColor = Color.White;
}
public Bitmap GetPlayCard(int Type, int CardNumber)
{
Bitmap bmp = new Bitmap((int)((float)this.Size.Width * this.ScaleX),
(int)((float)(this.Size.Height * this.ScaleY)), this.PixelFormat);
using (Graphics g = Graphics.FromImage(bmp))
{
g.SmoothingMode = SmoothingMode.HighQuality;
//念のため透明色で塗る
g.FillRectangle(new SolidBrush(BackgroundColor), 0, 0, bmp.Width, bmp.Height);
//カード作成
ModelManager mm = new ModelManager();
mm.AddRectangleArc(new RectangleF(0.0f, 0.0f, 199.0f, 299.0f), 10.0f);
Matrix m = new Matrix();
m.Scale(this.ScaleX, this.ScaleY);
GraphicsPath gp = mm.GetModelPath(m);
g.FillPath(new SolidBrush(this.FillColor), gp);
//カードの輪郭
if (this.Outline == true)
g.DrawPath(new Pen(this.OutlineColor, this.OutlineWidth), gp);
//カードの中味
gp = this.GetMarkPath(Type, CardNumber);
g.FillPath(this.MarkColor[Type], gp);
}
return bmp;
}
}
public class PlayCardMark
{
const int hosei_x = -11;
const int hosei_y = -11;
public string FontName { get; set; }
public float ScaleX { get; set; }
public float ScaleY { get; set; }
public Size Size { get; set; }
public Brush[] MarkColor = new Brush[]
{
Brushes.Black,
Brushes.Crimson,
Brushes.Black,
Brushes.Crimson,
};
public string[] Mark = new string[]
{
"♠","♦","♣","♥"
};
public Point[] Point = new Point[]
{
new Point(hosei_x + 25,hosei_y + 25),
new Point(hosei_x + 25,hosei_y + 87),
new Point(hosei_x + 25,hosei_y + 125),
new Point(hosei_x + 125,hosei_y + 25),
new Point(hosei_x + 125,hosei_y + 87),
new Point(hosei_x + 125,hosei_y + 125),//5
new Point(hosei_x + 75,hosei_y + 75),
new Point(hosei_x + 75,hosei_y + 125),
new Point(hosei_x + 75,hosei_y + 25),
new Point(hosei_x + 75,hosei_y + 67),
};
public Size MarkSize;
string[] cardnumber = new string[]
{
"A","2","3","4","5","6","7","8","9","10","J","Q","K","JOKER"
};
int[] cardnumberw = new int[]
{
1,1,1,1,1,
1,1,1,1,-5,
1,1,1,1
};
public PlayCardMark()
{
this.Size = new Size(200, 300);
}
private void GetLeftUpMark(GraphicsPath gp, int Type, int CardNumber)
{
//カード左上のマークと数字を描画
//右下は回転+平行移動で対応
gp.AddString(this.cardnumber[CardNumber], new FontFamily(this.FontName),
0, 30, new Point(this.cardnumberw[CardNumber], 0), StringFormat.GenericDefault);
if (CardNumber < 13) gp.AddString(this.Mark[Type], new FontFamily(this.FontName),
0, 30, new Point(2, 30), StringFormat.GenericDefault);
Matrix m = new Matrix();
m.Scale(0.8f, 1.0f);
gp.Transform(m);
}
private void GetUpperMark(GraphicsPath gp, int Type, int CardNumber)
{
//A~10までの中のマークを描画
//上半分共通部分だけ処理
//下半分は上を回転+平行移動で対応
switch ((CardNumber + 1))
{
case 2:
case 3:
gp.AddString(this.Mark[Type], new FontFamily(this.FontName),
0, 70, this.Point[8], StringFormat.GenericDefault);
break;
case 4:
case 5:
case 6:
case 7:
case 8:
gp.AddString(this.Mark[Type], new FontFamily(this.FontName),
0, 70, Point[0], StringFormat.GenericDefault);
gp.AddString(this.Mark[Type], new FontFamily(this.FontName),
0, 70, Point[3], StringFormat.GenericDefault);
if ((CardNumber + 1) == 8)
{
gp.AddString(this.Mark[Type], new FontFamily(this.FontName),
0, 70, Point[6], StringFormat.GenericDefault);
}
break;
case 9:
case 10:
gp.AddString(this.Mark[Type], new FontFamily(this.FontName),
0, 70, Point[0], StringFormat.GenericDefault);
gp.AddString(this.Mark[Type], new FontFamily(this.FontName),
0, 70, Point[1], StringFormat.GenericDefault);
gp.AddString(this.Mark[Type], new FontFamily(this.FontName),
0, 70, Point[3], StringFormat.GenericDefault);
gp.AddString(this.Mark[Type], new FontFamily(this.FontName),
0, 70, Point[4], StringFormat.GenericDefault);
if ((CardNumber + 1) == 10)
{
gp.AddString(this.Mark[Type], new FontFamily(this.FontName),
0, 70, Point[9], StringFormat.GenericDefault);
}
break;
default:
break;
};
}
public GraphicsPath GetMarkPath(int Type, int CardNumber)
{
ModelManager mm = new ModelManager();
//回転で対応可能なマークの処理
//上半分
GraphicsPath gp1 = new GraphicsPath();
this.GetLeftUpMark(gp1, Type, CardNumber);
this.GetUpperMark(gp1, Type, CardNumber);
mm.AddPath(gp1);
//下半分
GraphicsPath gp2 = new GraphicsPath();
this.GetLeftUpMark(gp2, Type, CardNumber);
this.GetUpperMark(gp2, Type, CardNumber);
Matrix m = new Matrix();
m.Rotate(180f);
gp2.Transform(m);
m.Reset();
m.Translate((float)(this.Size.Width - 1), (float)(this.Size.Height - 1));
gp2.Transform(m);
mm.AddPath(gp2);
//回転で対応できないマークの処理
switch ((CardNumber + 1))
{
case 1:
case 3:
case 5:
case 9:
mm.AddString(this.Mark[Type], this.FontName,
0, 70, Point[7], StringFormat.GenericDefault);
break;
case 6:
case 7:
case 8:
mm.AddString(this.Mark[Type], this.FontName,
0, 70, Point[2], StringFormat.GenericDefault);
mm.AddString(this.Mark[Type], this.FontName,
0, 70, Point[5], StringFormat.GenericDefault);
if ((CardNumber + 1) == 7)
{
mm.AddString(this.Mark[Type], this.FontName,
0, 70, Point[6], StringFormat.GenericDefault);
}
break;
default:
break;
};
m.Reset();
m.Scale(this.ScaleX, this.ScaleY);
return mm.GetModelPath(m);
}
}
public class ModelManager
{
public Matrix Matrix { get; set; }
public List<VectorModel> Model { get; set; }
public ModelManager()
{
this.Model = new List<VectorModel>();
this.Matrix = new Matrix();
}
public void AddVectorModel(VectorModel vm)
{
this.Model.Add(vm);
}
public void AddLine(int StartX, int StartY, int EndX, int EndY)
{
this.AddLine(new Point(StartX, StartY), new Point(EndX, EndY));
}
public void AddLine(Point[] Point)
{
VectorModel vm = new VectorModel();
vm.Type = 0;
vm.Point = Point;
this.AddVectorModel(vm);
}
public void AddLine(Point Start, Point End)
{
Point[] Point = new Point[2];
Point[0] = Start;
Point[1] = End;
this.AddLine(Point);
}
public void AddLines(Point[] Point)
{
VectorModel vm = new VectorModel();
vm.Type = 1;
vm.Point = Point;
this.AddVectorModel(vm);
}
public void AddArc(RectangleF RectangleF, float StartAngle, float SweepAngle)
{
VectorModel vm = new VectorModel();
vm.Type = 2;
vm.RectangleF = RectangleF;
vm.StartAngle = StartAngle;
vm.SweepAngle = SweepAngle;
this.AddVectorModel(vm);
}
public void AddArc(int StartX, int StartY, int Width, int Height, int StartAngle, int SweepAngle)
{
this.AddArc(new RectangleF((float)StartX, (float)StartY, (float)Width, (float)Height),
(float)StartAngle, (float)SweepAngle);
}
public void AddArc(float StartX, float StartY, float Width, float Height, float StartAngle, float SweepAngle)
{
this.AddArc(new RectangleF(StartX, StartY, Width, Height),
StartAngle, SweepAngle);
}
public void AddString(String Text, string FontName, int FontStyle, float FontemSize, Point Point, StringFormat StringFormat)
{
VectorModel vm = new VectorModel();
vm.Type = 3;
vm.Text = Text;
vm.FontName = FontName;
vm.FontStyle = FontStyle;
vm.FontemSize = FontemSize;
vm.Point = new Point[] { Point };
vm.StringFormat = StringFormat;
this.AddVectorModel(vm);
}
public void AddRectangle(RectangleF RectangleF)
{
VectorModel vm = new VectorModel();
vm.Type = 4;
vm.RectangleF = RectangleF;
this.AddVectorModel(vm);
}
public void AddRectangle(int StartX, int StartY, int Width, int Height)
{
this.AddRectangle(new RectangleF((float)StartX, (float)StartY, (float)Width, (float)Height));
}
public void AddRectangle(float StartX, float StartY, float Width, float Height)
{
this.AddRectangle(new RectangleF(StartX, StartY, Width, Height));
}
public void AddRectangleArc(RectangleF RectangleF, float Radius)
{
VectorModel vm = new VectorModel();
if (Radius < 1.0f)
{
//半径が1以下の場合は丸み無しに切り替え
this.AddRectangle(RectangleF);
}
else
{
vm.Type = 5;
vm.RectangleF = RectangleF;
vm.Radius = Radius;
this.AddVectorModel(vm);
}
}
public void AddRectangleArc(int StartX, int StartY, int Width, int Height, int Radius)
{
this.AddRectangleArc(new RectangleF((float)StartX, (float)StartY, (float)Width, (float)Height), (float)Radius);
}
public void AddRectangleArc(float StartX, float StartY, float Width, float Height, float Radius)
{
this.AddRectangleArc(new RectangleF(StartX, StartY, Width, Height), Radius);
}
public void AddPath(GraphicsPath Path)
{
//if (Path.PointCount == 0) return;
VectorModel vm = new VectorModel();
vm.Type = 6;
vm.Path = Path;
this.AddVectorModel(vm);
}
public void Clear()
{
this.Model.Clear();
}
public GraphicsPath GetModelPath(Matrix m)
{
GraphicsPath gp = new GraphicsPath();
foreach (VectorModel vm in this.Model)
{
vm.GetPath(gp);
}
gp.Transform(m);
return gp;
}
public GraphicsPath GetModelPath()
{
//GraphicsPath gp = this.GetModelPath(this.Matrix);
//return gp;
return this.GetModelPath(this.Matrix);
}
}
public class VectorModel
{
const float SwAngle = 90.0f;
const float S000Angel = 0.0f;
const float S090Angel = 90.0f;
const float S180Angel = 180.0f;
const float S270Angel = 270.0f;
//public VectorModel Parent { get; set; }
//public VectorModel Child { get; set; }
//public VectorModel Next { get; set; }
public int Type { get; set; }
public Point[] Point { get; set; }
public RectangleF RectangleF { get; set; }
public float StartAngle { get; set; }
public float SweepAngle { get; set; }
public string Text { get; set; }
public string FontName { get; set; }
public int FontStyle { get; set; }
public float FontemSize { get; set; }
public StringFormat StringFormat { get; set; }
public GraphicsPath Path { get; set; }
public float Radius { get; set; }
public float[] StAngel = new float[]
{
S180Angel,
S270Angel,
S000Angel,
S090Angel,
};
public void GetPath(GraphicsPath gp)
{
//if (this.Child != null) Child.GetPath(gp);
switch (this.Type)
{
case 0:
gp.AddLine(this.Point[0], this.Point[1]);
break;
case 1:
gp.AddLines(this.Point);
break;
case 2:
gp.AddArc(this.RectangleF, this.StartAngle, this.SweepAngle);
break;
case 3:
gp.AddString(this.Text, new FontFamily(this.FontName),
this.FontStyle, this.FontemSize, Point[0], this.StringFormat);
break;
case 4:
gp.AddRectangle(this.RectangleF);
break;
case 5:
int xs = (int)this.RectangleF.Location.X;
int ys = (int)this.RectangleF.Location.Y;
int xe = (int)this.RectangleF.Width;
int ye = (int)this.RectangleF.Height;
int rad = (int)(this.Radius);
int diameter = rad * 2;
Point[] sp = new Point[]{
new Point(xs + rad, ys),
new Point(xe, ys + rad),
new Point(xe - rad, ye),
new Point(xs, ye - rad),
};
Point[] ep = new Point[]{
new Point(xe - rad, ys),
new Point(xe, ye - rad),
new Point(xs + rad, ye),
new Point(xs, ys + rad),
};
Rectangle[] r = new Rectangle[]{
new Rectangle(xs, ys, diameter, diameter),
new Rectangle(xe - diameter, ys, diameter, diameter),
new Rectangle(xe - diameter, ye - diameter, diameter, diameter),
new Rectangle(xs, ye - diameter, diameter, diameter),
};
for (int i = 0; i < 4; i++)
{
gp.AddArc(r[i], this.StAngel[i], SwAngle);
gp.AddLine(sp[i], ep[i]);
}
break;
case 6:
gp.AddPath(this.Path, false);
break;
default:
break;
}
//if (this.Next != null) Next.GetPath(gp);
return;
}
}
}
dXNpbmcgU3lzdGVtOwp1c2luZyBTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYzsKdXNpbmcgU3lzdGVtLkNvbXBvbmVudE1vZGVsOwp1c2luZyBTeXN0ZW0uRGF0YTsKdXNpbmcgU3lzdGVtLkRyYXdpbmc7CnVzaW5nIFN5c3RlbS5EcmF3aW5nLlRleHQ7CnVzaW5nIFN5c3RlbS5EcmF3aW5nLkltYWdpbmc7CnVzaW5nIFN5c3RlbS5EcmF3aW5nLkRyYXdpbmcyRDsKdXNpbmcgU3lzdGVtLkxpbnE7CnVzaW5nIFN5c3RlbS5UZXh0Owp1c2luZyBTeXN0ZW0uV2luZG93cy5Gb3JtczsKdXNpbmcgU3lzdGVtLklPOwoKbmFtZXNwYWNlIFdpbmRvd3NGb3Jtc0FwcGxpY2F0aW9uMQp7CiAgICBwdWJsaWMgcGFydGlhbCBjbGFzcyBGb3JtMSA6IEZvcm0KICAgIHsKICAgICAgICBwdWJsaWMgRm9ybTEoKQogICAgICAgIHsKICAgICAgICAgICAgSW5pdGlhbGl6ZUNvbXBvbmVudCgpOwogICAgICAgICAgICB0aGlzLkxvYWQgKz0gbmV3IEV2ZW50SGFuZGxlcihGb3JtMV9Mb2FkKTsKICAgICAgICAgICAgdGhpcy5TaG93biArPSBuZXcgRXZlbnRIYW5kbGVyKEZvcm0xX1Nob3duKTsKICAgICAgICB9CiAgICAgICAgRm9udEZhbWlseVtdIGZmczsKICAgICAgICBUZXh0Qm94IHRiOwogICAgICAgIFBsYXlDYXJkIHBjOwogICAgICAgIC8v5L+d5a2Y5aC05omA44Gv44OH44K544Kv44OI44OD44OXCiAgICAgICAgc3RyaW5nIGNhcmRQYXNzID0gRW52aXJvbm1lbnQuR2V0Rm9sZGVyUGF0aChFbnZpcm9ubWVudC5TcGVjaWFsRm9sZGVyLkRlc2t0b3BEaXJlY3RvcnkpICsgIlxcY2FyZFxcIjsKICAgICAgICBwcml2YXRlIHZvaWQgRm9ybTFfTG9hZChvYmplY3Qgc2VuZGVyLCBFdmVudEFyZ3MgZSkKICAgICAgICB7CiAgICAgICAgICAgIHRiID0gbmV3IFRleHRCb3goKTsKICAgICAgICAgICAgdGIuTXVsdGlsaW5lID0gdHJ1ZTsKICAgICAgICAgICAgdGIuRG9jayA9IERvY2tTdHlsZS5GaWxsOwogICAgICAgICAgICB0Yi5TY3JvbGxCYXJzID0gU2Nyb2xsQmFycy5Cb3RoOwogICAgICAgICAgICB0aGlzLkNvbnRyb2xzLkFkZCh0Yik7CiAgICAgICAgICAgIEluc3RhbGxlZEZvbnRDb2xsZWN0aW9uIGlmYyA9IG5ldyBJbnN0YWxsZWRGb250Q29sbGVjdGlvbigpOwogICAgICAgICAgICBmZnMgPSBpZmMuRmFtaWxpZXM7CiAgICAgICAgICAgIGlmICghRGlyZWN0b3J5LkV4aXN0cyhjYXJkUGFzcykpCiAgICAgICAgICAgICAgICBEaXJlY3RvcnkuQ3JlYXRlRGlyZWN0b3J5KGNhcmRQYXNzKTsKICAgICAgICB9CgogICAgICAgIHByaXZhdGUgdm9pZCBGb3JtMV9TaG93bihvYmplY3Qgc2VuZGVyLCBFdmVudEFyZ3MgZSkKICAgICAgICB7CiAgICAgICAgICAgIHBjID0gbmV3IFBsYXlDYXJkKCk7CiAgICAgICAgICAgIHBjLlNjYWxlWCA9IDAuNWY7CiAgICAgICAgICAgIHBjLlNjYWxlWSA9IDAuNWY7CiAgICAgICAgICAgIC8vcGMuT3V0bGluZSA9IGZhbHNlOwogICAgICAgICAgICAvL0JpdG1hcCBhbGxibXAgPSBuZXcgQml0bWFwKHBjLlNpemUuV2lkdGggKiAxNCwgcGMuU2l6ZS5IZWlnaHQgKiA0LCBQaXhlbEZvcm1hdC5Gb3JtYXQzMmJwcEFyZ2IpOwogICAgICAgICAgICBmb3IgKGludCBrID0gMDsgayA8IDQ7IGsrKykKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgZm9yIChpbnQgaiA9IDA7IGogPCAxNDsgaisrKQogICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgIEJpdG1hcCBibXAgPSBwYy5HZXRQbGF5Q2FyZChrLCBqKTsKICAgICAgICAgICAgICAgICAgICAvL3VzaW5nIChHcmFwaGljcyBnID0gR3JhcGhpY3MuRnJvbUltYWdlKGFsbGJtcCkpCiAgICAgICAgICAgICAgICAgICAgLy97CiAgICAgICAgICAgICAgICAgICAgLy8gICAgZy5EcmF3SW1hZ2UoYm1wLCBuZXcgUG9pbnQoaiAqIHBjLlNpemUuV2lkdGgsIGsgKiBwYy5TaXplLkhlaWdodCkpOwogICAgICAgICAgICAgICAgICAgIC8vfQogICAgICAgICAgICAgICAgICAgIHN0cmluZyB2aWV3dGV4dCA9IGNhcmRQYXNzICsgcGMuQ2FyZEluaXRpYWxba10gKyAoaiArIDEpLlRvU3RyaW5nKCIwMCIpICsgIi5wbmciOwogICAgICAgICAgICAgICAgICAgIGJtcC5TYXZlKHZpZXd0ZXh0LCBJbWFnZUZvcm1hdC5QbmcpOwogICAgICAgICAgICAgICAgICAgIHRiLkFwcGVuZFRleHQodmlld3RleHQgKyAiXHJcbiIpOwogICAgICAgICAgICAgICAgICAgIEFwcGxpY2F0aW9uLkRvRXZlbnRzKCk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgICAgLy9hbGxibXAuU2F2ZShjYXJkUGFzcyArICJhbGxjYXJkLnBuZyIsIEltYWdlRm9ybWF0LlBuZyk7CiAgICAgICAgICAgIHRiLkFwcGVuZFRleHQoImVuZCIpOwogICAgICAgIH0KCiAgICB9CiAgICBjbGFzcyBQbGF5Q2FyZCA6IFBsYXlDYXJkTWFyawogICAgewogICAgICAgIHB1YmxpYyBDb2xvciBCYWNrZ3JvdW5kQ29sb3IgeyBnZXQ7IHNldDsgfQogICAgICAgIHB1YmxpYyBDb2xvciBGaWxsQ29sb3IgeyBnZXQ7IHNldDsgfQogICAgICAgIHB1YmxpYyBQaXhlbEZvcm1hdCBQaXhlbEZvcm1hdCB7IGdldDsgc2V0OyB9CiAgICAgICAgcHVibGljIGJvb2wgT3V0bGluZSB7IGdldDsgc2V0OyB9CiAgICAgICAgcHVibGljIGludCBPdXRsaW5lV2lkdGggeyBnZXQ7IHNldDsgfQogICAgICAgIHB1YmxpYyBDb2xvciBPdXRsaW5lQ29sb3IgeyBnZXQ7IHNldDsgfQogICAgICAgIHB1YmxpYyBzdHJpbmdbXSBDYXJkSW5pdGlhbCA9IG5ldyBzdHJpbmdbXQogICAgICAgIHsKICAgICAgICAgICAgIlMiLCJEIiwiQyIsIkgiCiAgICAgICAgfTsKCiAgICAgICAgcHVibGljIFBsYXlDYXJkKCkKICAgICAgICB7CiAgICAgICAgICAgIHRoaXMuUGl4ZWxGb3JtYXQgPSBQaXhlbEZvcm1hdC5Gb3JtYXQzMmJwcEFyZ2I7CiAgICAgICAgICAgIHRoaXMuT3V0bGluZSA9IHRydWU7CiAgICAgICAgICAgIHRoaXMuT3V0bGluZVdpZHRoID0gMTsKICAgICAgICAgICAgdGhpcy5PdXRsaW5lQ29sb3IgPSBDb2xvci5CbGFjazsKICAgICAgICAgICAgdGhpcy5Gb250TmFtZSA9ICLvvK3vvLMg77yw44K044K344OD44KvIjsKICAgICAgICAgICAgdGhpcy5GaWxsQ29sb3IgPSBDb2xvci5XaGl0ZTsKICAgICAgICB9CiAgICAgICAgcHVibGljIEJpdG1hcCBHZXRQbGF5Q2FyZChpbnQgVHlwZSwgaW50IENhcmROdW1iZXIpCiAgICAgICAgewogICAgICAgICAgICBCaXRtYXAgYm1wID0gbmV3IEJpdG1hcCgoaW50KSgoZmxvYXQpdGhpcy5TaXplLldpZHRoICogdGhpcy5TY2FsZVgpLAogICAgICAgICAgICAgICAgKGludCkoKGZsb2F0KSh0aGlzLlNpemUuSGVpZ2h0ICogdGhpcy5TY2FsZVkpKSwgdGhpcy5QaXhlbEZvcm1hdCk7CiAgICAgICAgICAgIHVzaW5nIChHcmFwaGljcyBnID0gR3JhcGhpY3MuRnJvbUltYWdlKGJtcCkpCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIGcuU21vb3RoaW5nTW9kZSA9IFNtb290aGluZ01vZGUuSGlnaFF1YWxpdHk7CiAgICAgICAgICAgICAgICAvL+W/teOBruOBn+OCgemAj+aYjuiJsuOBp+Whl+OCiwogICAgICAgICAgICAgICAgZy5GaWxsUmVjdGFuZ2xlKG5ldyBTb2xpZEJydXNoKEJhY2tncm91bmRDb2xvciksIDAsIDAsIGJtcC5XaWR0aCwgYm1wLkhlaWdodCk7CgogICAgICAgICAgICAgICAgLy/jgqvjg7zjg4nkvZzmiJAKICAgICAgICAgICAgICAgIE1vZGVsTWFuYWdlciBtbSA9IG5ldyBNb2RlbE1hbmFnZXIoKTsKICAgICAgICAgICAgICAgIG1tLkFkZFJlY3RhbmdsZUFyYyhuZXcgUmVjdGFuZ2xlRigwLjBmLCAwLjBmLCAxOTkuMGYsIDI5OS4wZiksIDEwLjBmKTsKICAgICAgICAgICAgICAgIE1hdHJpeCBtID0gbmV3IE1hdHJpeCgpOwogICAgICAgICAgICAgICAgbS5TY2FsZSh0aGlzLlNjYWxlWCwgdGhpcy5TY2FsZVkpOwogICAgICAgICAgICAgICAgR3JhcGhpY3NQYXRoIGdwID0gbW0uR2V0TW9kZWxQYXRoKG0pOwogICAgICAgICAgICAgICAgZy5GaWxsUGF0aChuZXcgU29saWRCcnVzaCh0aGlzLkZpbGxDb2xvciksIGdwKTsKICAgICAgICAgICAgICAgIC8v44Kr44O844OJ44Gu6Lyq6YOtCiAgICAgICAgICAgICAgICBpZiAodGhpcy5PdXRsaW5lID09IHRydWUpCiAgICAgICAgICAgICAgICAgICAgZy5EcmF3UGF0aChuZXcgUGVuKHRoaXMuT3V0bGluZUNvbG9yLCB0aGlzLk91dGxpbmVXaWR0aCksIGdwKTsKICAgICAgICAgICAgICAgIC8v44Kr44O844OJ44Gu5Lit5ZGzCiAgICAgICAgICAgICAgICBncCA9IHRoaXMuR2V0TWFya1BhdGgoVHlwZSwgQ2FyZE51bWJlcik7CiAgICAgICAgICAgICAgICBnLkZpbGxQYXRoKHRoaXMuTWFya0NvbG9yW1R5cGVdLCBncCk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgcmV0dXJuIGJtcDsKICAgICAgICB9CiAgICB9CiAgICBwdWJsaWMgY2xhc3MgUGxheUNhcmRNYXJrCiAgICB7CgogICAgICAgIGNvbnN0IGludCBob3NlaV94ID0gLTExOwogICAgICAgIGNvbnN0IGludCBob3NlaV95ID0gLTExOwogICAgICAgIHB1YmxpYyBzdHJpbmcgRm9udE5hbWUgeyBnZXQ7IHNldDsgfQogICAgICAgIHB1YmxpYyBmbG9hdCBTY2FsZVggeyBnZXQ7IHNldDsgfQogICAgICAgIHB1YmxpYyBmbG9hdCBTY2FsZVkgeyBnZXQ7IHNldDsgfQogICAgICAgIHB1YmxpYyBTaXplIFNpemUgeyBnZXQ7IHNldDsgfQogICAgICAgIHB1YmxpYyBCcnVzaFtdIE1hcmtDb2xvciA9IG5ldyBCcnVzaFtdCiAgICAgICAgewogICAgICAgICAgICBCcnVzaGVzLkJsYWNrLAogICAgICAgICAgICBCcnVzaGVzLkNyaW1zb24sCiAgICAgICAgICAgIEJydXNoZXMuQmxhY2ssCiAgICAgICAgICAgIEJydXNoZXMuQ3JpbXNvbiwKICAgICAgICB9OwogICAgICAgIHB1YmxpYyBzdHJpbmdbXSBNYXJrID0gbmV3IHN0cmluZ1tdCiAgICAgICAgewogICAgICAgICAgICAi4pmgIiwi4pmmIiwi4pmjIiwi4pmlIgogICAgICAgIH07CiAgICAgICAgcHVibGljIFBvaW50W10gUG9pbnQgPSBuZXcgUG9pbnRbXQogICAgICAgIHsKICAgICAgICAgICAgbmV3IFBvaW50KGhvc2VpX3ggKyAgMjUsaG9zZWlfeSArICAyNSksCiAgICAgICAgICAgIG5ldyBQb2ludChob3NlaV94ICsgIDI1LGhvc2VpX3kgKyAgODcpLAogICAgICAgICAgICBuZXcgUG9pbnQoaG9zZWlfeCArICAyNSxob3NlaV95ICsgMTI1KSwKCiAgICAgICAgICAgIG5ldyBQb2ludChob3NlaV94ICsgMTI1LGhvc2VpX3kgKyAgMjUpLAogICAgICAgICAgICBuZXcgUG9pbnQoaG9zZWlfeCArIDEyNSxob3NlaV95ICsgIDg3KSwKICAgICAgICAgICAgbmV3IFBvaW50KGhvc2VpX3ggKyAxMjUsaG9zZWlfeSArIDEyNSksLy81CgogICAgICAgICAgICBuZXcgUG9pbnQoaG9zZWlfeCArICA3NSxob3NlaV95ICsgIDc1KSwKICAgICAgICAgICAgbmV3IFBvaW50KGhvc2VpX3ggKyAgNzUsaG9zZWlfeSArIDEyNSksCiAgICAgICAgICAgIG5ldyBQb2ludChob3NlaV94ICsgIDc1LGhvc2VpX3kgKyAgMjUpLAogICAgICAgICAgICBuZXcgUG9pbnQoaG9zZWlfeCArICA3NSxob3NlaV95ICsgIDY3KSwKCiAgICAgICAgfTsKICAgICAgICBwdWJsaWMgU2l6ZSBNYXJrU2l6ZTsKICAgICAgICBzdHJpbmdbXSBjYXJkbnVtYmVyID0gbmV3IHN0cmluZ1tdCiAgICAgICAgewogICAgICAgICAgICAi77yhIiwi77ySIiwi77yTIiwi77yUIiwi77yVIiwi77yWIiwi77yXIiwi77yYIiwi77yZIiwiMTAiLCLvvKoiLCLvvLEiLCLvvKsiLCJKT0tFUiIKICAgICAgICB9OwogICAgICAgIGludFtdIGNhcmRudW1iZXJ3ID0gbmV3IGludFtdCiAgICAgICAgewogICAgICAgICAgICAxLDEsMSwxLDEsCiAgICAgICAgICAgIDEsMSwxLDEsLTUsCiAgICAgICAgICAgIDEsMSwxLDEKICAgICAgICB9OwogICAgICAgIHB1YmxpYyBQbGF5Q2FyZE1hcmsoKQogICAgICAgIHsKICAgICAgICAgICAgdGhpcy5TaXplID0gbmV3IFNpemUoMjAwLCAzMDApOwogICAgICAgIH0KICAgICAgICBwcml2YXRlIHZvaWQgR2V0TGVmdFVwTWFyayhHcmFwaGljc1BhdGggZ3AsIGludCBUeXBlLCBpbnQgQ2FyZE51bWJlcikKICAgICAgICB7CiAgICAgICAgICAgIC8v44Kr44O844OJ5bem5LiK44Gu44Oe44O844Kv44Go5pWw5a2X44KS5o+P55S7CiAgICAgICAgICAgIC8v5Y+z5LiL44Gv5Zue6LuiK+W5s+ihjOenu+WLleOBp+WvvuW/nAogICAgICAgICAgICBncC5BZGRTdHJpbmcodGhpcy5jYXJkbnVtYmVyW0NhcmROdW1iZXJdLCBuZXcgRm9udEZhbWlseSh0aGlzLkZvbnROYW1lKSwKICAgICAgICAgICAgICAgIDAsIDMwLCBuZXcgUG9pbnQodGhpcy5jYXJkbnVtYmVyd1tDYXJkTnVtYmVyXSwgMCksIFN0cmluZ0Zvcm1hdC5HZW5lcmljRGVmYXVsdCk7CiAgICAgICAgICAgIGlmIChDYXJkTnVtYmVyIDwgMTMpIGdwLkFkZFN0cmluZyh0aGlzLk1hcmtbVHlwZV0sIG5ldyBGb250RmFtaWx5KHRoaXMuRm9udE5hbWUpLAogICAgICAgICAgICAgICAgIDAsIDMwLCBuZXcgUG9pbnQoMiwgMzApLCBTdHJpbmdGb3JtYXQuR2VuZXJpY0RlZmF1bHQpOwogICAgICAgICAgICBNYXRyaXggbSA9IG5ldyBNYXRyaXgoKTsKICAgICAgICAgICAgbS5TY2FsZSgwLjhmLCAxLjBmKTsKICAgICAgICAgICAgZ3AuVHJhbnNmb3JtKG0pOwogICAgICAgIH0KICAgICAgICBwcml2YXRlIHZvaWQgR2V0VXBwZXJNYXJrKEdyYXBoaWNzUGF0aCBncCwgaW50IFR5cGUsIGludCBDYXJkTnVtYmVyKQogICAgICAgIHsKICAgICAgICAgICAgLy9B772eMTDjgb7jgafjga7kuK3jga7jg57jg7zjgq/jgpLmj4/nlLsKICAgICAgICAgICAgLy/kuIrljYrliIblhbHpgJrpg6jliIbjgaDjgZHlh6bnkIYKICAgICAgICAgICAgLy/kuIvljYrliIbjga/kuIrjgpLlm57ou6Ir5bmz6KGM56e75YuV44Gn5a++5b+cCiAgICAgICAgICAgIHN3aXRjaCAoKENhcmROdW1iZXIgKyAxKSkKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgY2FzZSAyOgogICAgICAgICAgICAgICAgY2FzZSAzOgogICAgICAgICAgICAgICAgICAgIGdwLkFkZFN0cmluZyh0aGlzLk1hcmtbVHlwZV0sIG5ldyBGb250RmFtaWx5KHRoaXMuRm9udE5hbWUpLAogICAgICAgICAgICAgICAgICAgICAgICAwLCA3MCwgdGhpcy5Qb2ludFs4XSwgU3RyaW5nRm9ybWF0LkdlbmVyaWNEZWZhdWx0KTsKICAgICAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgICAgIGNhc2UgNDoKICAgICAgICAgICAgICAgIGNhc2UgNToKICAgICAgICAgICAgICAgIGNhc2UgNjoKICAgICAgICAgICAgICAgIGNhc2UgNzoKICAgICAgICAgICAgICAgIGNhc2UgODoKICAgICAgICAgICAgICAgICAgICBncC5BZGRTdHJpbmcodGhpcy5NYXJrW1R5cGVdLCBuZXcgRm9udEZhbWlseSh0aGlzLkZvbnROYW1lKSwKICAgICAgICAgICAgICAgICAgICAgICAgMCwgNzAsIFBvaW50WzBdLCBTdHJpbmdGb3JtYXQuR2VuZXJpY0RlZmF1bHQpOwogICAgICAgICAgICAgICAgICAgIGdwLkFkZFN0cmluZyh0aGlzLk1hcmtbVHlwZV0sIG5ldyBGb250RmFtaWx5KHRoaXMuRm9udE5hbWUpLAogICAgICAgICAgICAgICAgICAgICAgICAwLCA3MCwgUG9pbnRbM10sIFN0cmluZ0Zvcm1hdC5HZW5lcmljRGVmYXVsdCk7CiAgICAgICAgICAgICAgICAgICAgaWYgKChDYXJkTnVtYmVyICsgMSkgPT0gOCkKICAgICAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgICAgIGdwLkFkZFN0cmluZyh0aGlzLk1hcmtbVHlwZV0sIG5ldyBGb250RmFtaWx5KHRoaXMuRm9udE5hbWUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgMCwgNzAsIFBvaW50WzZdLCBTdHJpbmdGb3JtYXQuR2VuZXJpY0RlZmF1bHQpOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgICAgIGNhc2UgOToKICAgICAgICAgICAgICAgIGNhc2UgMTA6CiAgICAgICAgICAgICAgICAgICAgZ3AuQWRkU3RyaW5nKHRoaXMuTWFya1tUeXBlXSwgbmV3IEZvbnRGYW1pbHkodGhpcy5Gb250TmFtZSksCiAgICAgICAgICAgICAgICAgICAgICAgIDAsIDcwLCBQb2ludFswXSwgU3RyaW5nRm9ybWF0LkdlbmVyaWNEZWZhdWx0KTsKICAgICAgICAgICAgICAgICAgICBncC5BZGRTdHJpbmcodGhpcy5NYXJrW1R5cGVdLCBuZXcgRm9udEZhbWlseSh0aGlzLkZvbnROYW1lKSwKICAgICAgICAgICAgICAgICAgICAgICAgMCwgNzAsIFBvaW50WzFdLCBTdHJpbmdGb3JtYXQuR2VuZXJpY0RlZmF1bHQpOwogICAgICAgICAgICAgICAgICAgIGdwLkFkZFN0cmluZyh0aGlzLk1hcmtbVHlwZV0sIG5ldyBGb250RmFtaWx5KHRoaXMuRm9udE5hbWUpLAogICAgICAgICAgICAgICAgICAgICAgICAwLCA3MCwgUG9pbnRbM10sIFN0cmluZ0Zvcm1hdC5HZW5lcmljRGVmYXVsdCk7CiAgICAgICAgICAgICAgICAgICAgZ3AuQWRkU3RyaW5nKHRoaXMuTWFya1tUeXBlXSwgbmV3IEZvbnRGYW1pbHkodGhpcy5Gb250TmFtZSksCiAgICAgICAgICAgICAgICAgICAgICAgIDAsIDcwLCBQb2ludFs0XSwgU3RyaW5nRm9ybWF0LkdlbmVyaWNEZWZhdWx0KTsKICAgICAgICAgICAgICAgICAgICBpZiAoKENhcmROdW1iZXIgKyAxKSA9PSAxMCkKICAgICAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgICAgIGdwLkFkZFN0cmluZyh0aGlzLk1hcmtbVHlwZV0sIG5ldyBGb250RmFtaWx5KHRoaXMuRm9udE5hbWUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgMCwgNzAsIFBvaW50WzldLCBTdHJpbmdGb3JtYXQuR2VuZXJpY0RlZmF1bHQpOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgICAgIGRlZmF1bHQ6CiAgICAgICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgIH07CiAgICAgICAgfQogICAgICAgIHB1YmxpYyBHcmFwaGljc1BhdGggR2V0TWFya1BhdGgoaW50IFR5cGUsIGludCBDYXJkTnVtYmVyKQogICAgICAgIHsKICAgICAgICAgICAgTW9kZWxNYW5hZ2VyIG1tID0gbmV3IE1vZGVsTWFuYWdlcigpOwogICAgICAgICAgICAvL+Wbnui7ouOBp+WvvuW/nOWPr+iDveOBquODnuODvOOCr+OBruWHpueQhgogICAgICAgICAgICAvL+S4iuWNiuWIhgogICAgICAgICAgICBHcmFwaGljc1BhdGggZ3AxID0gbmV3IEdyYXBoaWNzUGF0aCgpOwogICAgICAgICAgICB0aGlzLkdldExlZnRVcE1hcmsoZ3AxLCBUeXBlLCBDYXJkTnVtYmVyKTsKICAgICAgICAgICAgdGhpcy5HZXRVcHBlck1hcmsoZ3AxLCBUeXBlLCBDYXJkTnVtYmVyKTsKICAgICAgICAgICAgbW0uQWRkUGF0aChncDEpOwogICAgICAgICAgICAvL+S4i+WNiuWIhgogICAgICAgICAgICBHcmFwaGljc1BhdGggZ3AyID0gbmV3IEdyYXBoaWNzUGF0aCgpOwogICAgICAgICAgICB0aGlzLkdldExlZnRVcE1hcmsoZ3AyLCBUeXBlLCBDYXJkTnVtYmVyKTsKICAgICAgICAgICAgdGhpcy5HZXRVcHBlck1hcmsoZ3AyLCBUeXBlLCBDYXJkTnVtYmVyKTsKICAgICAgICAgICAgTWF0cml4IG0gPSBuZXcgTWF0cml4KCk7CiAgICAgICAgICAgIG0uUm90YXRlKDE4MGYpOwogICAgICAgICAgICBncDIuVHJhbnNmb3JtKG0pOwogICAgICAgICAgICBtLlJlc2V0KCk7CiAgICAgICAgICAgIG0uVHJhbnNsYXRlKChmbG9hdCkodGhpcy5TaXplLldpZHRoIC0gMSksIChmbG9hdCkodGhpcy5TaXplLkhlaWdodCAtIDEpKTsKICAgICAgICAgICAgZ3AyLlRyYW5zZm9ybShtKTsKICAgICAgICAgICAgbW0uQWRkUGF0aChncDIpOwogICAgICAgICAgICAvL+Wbnui7ouOBp+WvvuW/nOOBp+OBjeOBquOBhOODnuODvOOCr+OBruWHpueQhgogICAgICAgICAgICBzd2l0Y2ggKChDYXJkTnVtYmVyICsgMSkpCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIGNhc2UgMToKICAgICAgICAgICAgICAgIGNhc2UgMzoKICAgICAgICAgICAgICAgIGNhc2UgNToKICAgICAgICAgICAgICAgIGNhc2UgOToKICAgICAgICAgICAgICAgICAgICBtbS5BZGRTdHJpbmcodGhpcy5NYXJrW1R5cGVdLCB0aGlzLkZvbnROYW1lLAogICAgICAgICAgICAgICAgICAgICAgICAwLCA3MCwgUG9pbnRbN10sIFN0cmluZ0Zvcm1hdC5HZW5lcmljRGVmYXVsdCk7CiAgICAgICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgICAgICBjYXNlIDY6CiAgICAgICAgICAgICAgICBjYXNlIDc6CiAgICAgICAgICAgICAgICBjYXNlIDg6CiAgICAgICAgICAgICAgICAgICAgbW0uQWRkU3RyaW5nKHRoaXMuTWFya1tUeXBlXSwgdGhpcy5Gb250TmFtZSwKICAgICAgICAgICAgICAgICAgICAgICAgMCwgNzAsIFBvaW50WzJdLCBTdHJpbmdGb3JtYXQuR2VuZXJpY0RlZmF1bHQpOwogICAgICAgICAgICAgICAgICAgIG1tLkFkZFN0cmluZyh0aGlzLk1hcmtbVHlwZV0sIHRoaXMuRm9udE5hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgIDAsIDcwLCBQb2ludFs1XSwgU3RyaW5nRm9ybWF0LkdlbmVyaWNEZWZhdWx0KTsKICAgICAgICAgICAgICAgICAgICBpZiAoKENhcmROdW1iZXIgKyAxKSA9PSA3KQogICAgICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICAgICAgbW0uQWRkU3RyaW5nKHRoaXMuTWFya1tUeXBlXSwgdGhpcy5Gb250TmFtZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIDAsIDcwLCBQb2ludFs2XSwgU3RyaW5nRm9ybWF0LkdlbmVyaWNEZWZhdWx0KTsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgICAgICBkZWZhdWx0OgogICAgICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICB9OwogICAgICAgICAgICBtLlJlc2V0KCk7CiAgICAgICAgICAgIG0uU2NhbGUodGhpcy5TY2FsZVgsIHRoaXMuU2NhbGVZKTsKICAgICAgICAgICAgcmV0dXJuIG1tLkdldE1vZGVsUGF0aChtKTsKICAgICAgICB9CiAgICB9CiAgICBwdWJsaWMgY2xhc3MgTW9kZWxNYW5hZ2VyCiAgICB7CiAgICAgICAgcHVibGljIE1hdHJpeCBNYXRyaXggeyBnZXQ7IHNldDsgfQogICAgICAgIHB1YmxpYyBMaXN0PFZlY3Rvck1vZGVsPiBNb2RlbCB7IGdldDsgc2V0OyB9CiAgICAgICAgcHVibGljIE1vZGVsTWFuYWdlcigpCiAgICAgICAgewogICAgICAgICAgICB0aGlzLk1vZGVsID0gbmV3IExpc3Q8VmVjdG9yTW9kZWw+KCk7CiAgICAgICAgICAgIHRoaXMuTWF0cml4ID0gbmV3IE1hdHJpeCgpOwogICAgICAgIH0KICAgICAgICBwdWJsaWMgdm9pZCBBZGRWZWN0b3JNb2RlbChWZWN0b3JNb2RlbCB2bSkKICAgICAgICB7CiAgICAgICAgICAgIHRoaXMuTW9kZWwuQWRkKHZtKTsKICAgICAgICB9CiAgICAgICAgcHVibGljIHZvaWQgQWRkTGluZShpbnQgU3RhcnRYLCBpbnQgU3RhcnRZLCBpbnQgRW5kWCwgaW50IEVuZFkpCiAgICAgICAgewogICAgICAgICAgICB0aGlzLkFkZExpbmUobmV3IFBvaW50KFN0YXJ0WCwgU3RhcnRZKSwgbmV3IFBvaW50KEVuZFgsIEVuZFkpKTsKICAgICAgICB9CiAgICAgICAgcHVibGljIHZvaWQgQWRkTGluZShQb2ludFtdIFBvaW50KQogICAgICAgIHsKICAgICAgICAgICAgVmVjdG9yTW9kZWwgdm0gPSBuZXcgVmVjdG9yTW9kZWwoKTsKICAgICAgICAgICAgdm0uVHlwZSA9IDA7CiAgICAgICAgICAgIHZtLlBvaW50ID0gUG9pbnQ7CiAgICAgICAgICAgIHRoaXMuQWRkVmVjdG9yTW9kZWwodm0pOwogICAgICAgIH0KICAgICAgICBwdWJsaWMgdm9pZCBBZGRMaW5lKFBvaW50IFN0YXJ0LCBQb2ludCBFbmQpCiAgICAgICAgewogICAgICAgICAgICBQb2ludFtdIFBvaW50ID0gbmV3IFBvaW50WzJdOwogICAgICAgICAgICBQb2ludFswXSA9IFN0YXJ0OwogICAgICAgICAgICBQb2ludFsxXSA9IEVuZDsKICAgICAgICAgICAgdGhpcy5BZGRMaW5lKFBvaW50KTsKICAgICAgICB9CiAgICAgICAgcHVibGljIHZvaWQgQWRkTGluZXMoUG9pbnRbXSBQb2ludCkKICAgICAgICB7CiAgICAgICAgICAgIFZlY3Rvck1vZGVsIHZtID0gbmV3IFZlY3Rvck1vZGVsKCk7CiAgICAgICAgICAgIHZtLlR5cGUgPSAxOwogICAgICAgICAgICB2bS5Qb2ludCA9IFBvaW50OwogICAgICAgICAgICB0aGlzLkFkZFZlY3Rvck1vZGVsKHZtKTsKICAgICAgICB9CiAgICAgICAgcHVibGljIHZvaWQgQWRkQXJjKFJlY3RhbmdsZUYgUmVjdGFuZ2xlRiwgZmxvYXQgU3RhcnRBbmdsZSwgZmxvYXQgU3dlZXBBbmdsZSkKICAgICAgICB7CiAgICAgICAgICAgIFZlY3Rvck1vZGVsIHZtID0gbmV3IFZlY3Rvck1vZGVsKCk7CiAgICAgICAgICAgIHZtLlR5cGUgPSAyOwogICAgICAgICAgICB2bS5SZWN0YW5nbGVGID0gUmVjdGFuZ2xlRjsKICAgICAgICAgICAgdm0uU3RhcnRBbmdsZSA9IFN0YXJ0QW5nbGU7CiAgICAgICAgICAgIHZtLlN3ZWVwQW5nbGUgPSBTd2VlcEFuZ2xlOwogICAgICAgICAgICB0aGlzLkFkZFZlY3Rvck1vZGVsKHZtKTsKCiAgICAgICAgfQogICAgICAgIHB1YmxpYyB2b2lkIEFkZEFyYyhpbnQgU3RhcnRYLCBpbnQgU3RhcnRZLCBpbnQgV2lkdGgsIGludCBIZWlnaHQsIGludCBTdGFydEFuZ2xlLCBpbnQgU3dlZXBBbmdsZSkKICAgICAgICB7CiAgICAgICAgICAgIHRoaXMuQWRkQXJjKG5ldyBSZWN0YW5nbGVGKChmbG9hdClTdGFydFgsIChmbG9hdClTdGFydFksIChmbG9hdClXaWR0aCwgKGZsb2F0KUhlaWdodCksCiAgICAgICAgICAgICAgICAoZmxvYXQpU3RhcnRBbmdsZSwgKGZsb2F0KVN3ZWVwQW5nbGUpOwogICAgICAgIH0KICAgICAgICBwdWJsaWMgdm9pZCBBZGRBcmMoZmxvYXQgU3RhcnRYLCBmbG9hdCBTdGFydFksIGZsb2F0IFdpZHRoLCBmbG9hdCBIZWlnaHQsIGZsb2F0IFN0YXJ0QW5nbGUsIGZsb2F0IFN3ZWVwQW5nbGUpCiAgICAgICAgewogICAgICAgICAgICB0aGlzLkFkZEFyYyhuZXcgUmVjdGFuZ2xlRihTdGFydFgsIFN0YXJ0WSwgV2lkdGgsIEhlaWdodCksCiAgICAgICAgICAgICAgICBTdGFydEFuZ2xlLCBTd2VlcEFuZ2xlKTsKICAgICAgICB9CiAgICAgICAgcHVibGljIHZvaWQgQWRkU3RyaW5nKFN0cmluZyBUZXh0LCBzdHJpbmcgRm9udE5hbWUsIGludCBGb250U3R5bGUsIGZsb2F0IEZvbnRlbVNpemUsIFBvaW50IFBvaW50LCBTdHJpbmdGb3JtYXQgU3RyaW5nRm9ybWF0KQogICAgICAgIHsKICAgICAgICAgICAgVmVjdG9yTW9kZWwgdm0gPSBuZXcgVmVjdG9yTW9kZWwoKTsKICAgICAgICAgICAgdm0uVHlwZSA9IDM7CiAgICAgICAgICAgIHZtLlRleHQgPSBUZXh0OwogICAgICAgICAgICB2bS5Gb250TmFtZSA9IEZvbnROYW1lOwogICAgICAgICAgICB2bS5Gb250U3R5bGUgPSBGb250U3R5bGU7CiAgICAgICAgICAgIHZtLkZvbnRlbVNpemUgPSBGb250ZW1TaXplOwogICAgICAgICAgICB2bS5Qb2ludCA9IG5ldyBQb2ludFtdIHsgUG9pbnQgfTsKICAgICAgICAgICAgdm0uU3RyaW5nRm9ybWF0ID0gU3RyaW5nRm9ybWF0OwogICAgICAgICAgICB0aGlzLkFkZFZlY3Rvck1vZGVsKHZtKTsKICAgICAgICB9CiAgICAgICAgcHVibGljIHZvaWQgQWRkUmVjdGFuZ2xlKFJlY3RhbmdsZUYgUmVjdGFuZ2xlRikKICAgICAgICB7CiAgICAgICAgICAgIFZlY3Rvck1vZGVsIHZtID0gbmV3IFZlY3Rvck1vZGVsKCk7CiAgICAgICAgICAgIHZtLlR5cGUgPSA0OwogICAgICAgICAgICB2bS5SZWN0YW5nbGVGID0gUmVjdGFuZ2xlRjsKICAgICAgICAgICAgdGhpcy5BZGRWZWN0b3JNb2RlbCh2bSk7CiAgICAgICAgfQogICAgICAgIHB1YmxpYyB2b2lkIEFkZFJlY3RhbmdsZShpbnQgU3RhcnRYLCBpbnQgU3RhcnRZLCBpbnQgV2lkdGgsIGludCBIZWlnaHQpCiAgICAgICAgewogICAgICAgICAgICB0aGlzLkFkZFJlY3RhbmdsZShuZXcgUmVjdGFuZ2xlRigoZmxvYXQpU3RhcnRYLCAoZmxvYXQpU3RhcnRZLCAoZmxvYXQpV2lkdGgsIChmbG9hdClIZWlnaHQpKTsKICAgICAgICB9CiAgICAgICAgcHVibGljIHZvaWQgQWRkUmVjdGFuZ2xlKGZsb2F0IFN0YXJ0WCwgZmxvYXQgU3RhcnRZLCBmbG9hdCBXaWR0aCwgZmxvYXQgSGVpZ2h0KQogICAgICAgIHsKICAgICAgICAgICAgdGhpcy5BZGRSZWN0YW5nbGUobmV3IFJlY3RhbmdsZUYoU3RhcnRYLCBTdGFydFksIFdpZHRoLCBIZWlnaHQpKTsKICAgICAgICB9CiAgICAgICAgcHVibGljIHZvaWQgQWRkUmVjdGFuZ2xlQXJjKFJlY3RhbmdsZUYgUmVjdGFuZ2xlRiwgZmxvYXQgUmFkaXVzKQogICAgICAgIHsKICAgICAgICAgICAgVmVjdG9yTW9kZWwgdm0gPSBuZXcgVmVjdG9yTW9kZWwoKTsKICAgICAgICAgICAgaWYgKFJhZGl1cyA8IDEuMGYpCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIC8v5Y2K5b6E44GMMeS7peS4i+OBruWgtOWQiOOBr+S4uOOBv+eEoeOBl+OBq+WIh+OCiuabv+OBiAogICAgICAgICAgICAgICAgdGhpcy5BZGRSZWN0YW5nbGUoUmVjdGFuZ2xlRik7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgZWxzZQogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICB2bS5UeXBlID0gNTsKICAgICAgICAgICAgICAgIHZtLlJlY3RhbmdsZUYgPSBSZWN0YW5nbGVGOwogICAgICAgICAgICAgICAgdm0uUmFkaXVzID0gUmFkaXVzOwogICAgICAgICAgICAgICAgdGhpcy5BZGRWZWN0b3JNb2RlbCh2bSk7CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgcHVibGljIHZvaWQgQWRkUmVjdGFuZ2xlQXJjKGludCBTdGFydFgsIGludCBTdGFydFksIGludCBXaWR0aCwgaW50IEhlaWdodCwgaW50IFJhZGl1cykKICAgICAgICB7CiAgICAgICAgICAgIHRoaXMuQWRkUmVjdGFuZ2xlQXJjKG5ldyBSZWN0YW5nbGVGKChmbG9hdClTdGFydFgsIChmbG9hdClTdGFydFksIChmbG9hdClXaWR0aCwgKGZsb2F0KUhlaWdodCksIChmbG9hdClSYWRpdXMpOwogICAgICAgIH0KICAgICAgICBwdWJsaWMgdm9pZCBBZGRSZWN0YW5nbGVBcmMoZmxvYXQgU3RhcnRYLCBmbG9hdCBTdGFydFksIGZsb2F0IFdpZHRoLCBmbG9hdCBIZWlnaHQsIGZsb2F0IFJhZGl1cykKICAgICAgICB7CiAgICAgICAgICAgIHRoaXMuQWRkUmVjdGFuZ2xlQXJjKG5ldyBSZWN0YW5nbGVGKFN0YXJ0WCwgU3RhcnRZLCBXaWR0aCwgSGVpZ2h0KSwgUmFkaXVzKTsKICAgICAgICB9CiAgICAgICAgcHVibGljIHZvaWQgQWRkUGF0aChHcmFwaGljc1BhdGggUGF0aCkKICAgICAgICB7CiAgICAgICAgICAgIC8vaWYgKFBhdGguUG9pbnRDb3VudCA9PSAwKSByZXR1cm47CiAgICAgICAgICAgIFZlY3Rvck1vZGVsIHZtID0gbmV3IFZlY3Rvck1vZGVsKCk7CiAgICAgICAgICAgIHZtLlR5cGUgPSA2OwogICAgICAgICAgICB2bS5QYXRoID0gUGF0aDsKICAgICAgICAgICAgdGhpcy5BZGRWZWN0b3JNb2RlbCh2bSk7CiAgICAgICAgfQogICAgICAgIHB1YmxpYyB2b2lkIENsZWFyKCkKICAgICAgICB7CiAgICAgICAgICAgIHRoaXMuTW9kZWwuQ2xlYXIoKTsKICAgICAgICB9CiAgICAgICAgcHVibGljIEdyYXBoaWNzUGF0aCBHZXRNb2RlbFBhdGgoTWF0cml4IG0pCiAgICAgICAgewogICAgICAgICAgICBHcmFwaGljc1BhdGggZ3AgPSBuZXcgR3JhcGhpY3NQYXRoKCk7CiAgICAgICAgICAgIGZvcmVhY2ggKFZlY3Rvck1vZGVsIHZtIGluIHRoaXMuTW9kZWwpCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIHZtLkdldFBhdGgoZ3ApOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGdwLlRyYW5zZm9ybShtKTsKICAgICAgICAgICAgcmV0dXJuIGdwOwogICAgICAgIH0KICAgICAgICBwdWJsaWMgR3JhcGhpY3NQYXRoIEdldE1vZGVsUGF0aCgpCiAgICAgICAgewogICAgICAgICAgICAvL0dyYXBoaWNzUGF0aCBncCA9IHRoaXMuR2V0TW9kZWxQYXRoKHRoaXMuTWF0cml4KTsKICAgICAgICAgICAgLy9yZXR1cm4gZ3A7CiAgICAgICAgICAgIHJldHVybiB0aGlzLkdldE1vZGVsUGF0aCh0aGlzLk1hdHJpeCk7CiAgICAgICAgfQogICAgfQogICAgcHVibGljIGNsYXNzIFZlY3Rvck1vZGVsCiAgICB7CiAgICAgICAgY29uc3QgZmxvYXQgU3dBbmdsZSA9IDkwLjBmOwogICAgICAgIGNvbnN0IGZsb2F0IFMwMDBBbmdlbCA9IDAuMGY7CiAgICAgICAgY29uc3QgZmxvYXQgUzA5MEFuZ2VsID0gOTAuMGY7CiAgICAgICAgY29uc3QgZmxvYXQgUzE4MEFuZ2VsID0gMTgwLjBmOwogICAgICAgIGNvbnN0IGZsb2F0IFMyNzBBbmdlbCA9IDI3MC4wZjsKICAgICAgICAvL3B1YmxpYyBWZWN0b3JNb2RlbCBQYXJlbnQgeyBnZXQ7IHNldDsgfQogICAgICAgIC8vcHVibGljIFZlY3Rvck1vZGVsIENoaWxkIHsgZ2V0OyBzZXQ7IH0KICAgICAgICAvL3B1YmxpYyBWZWN0b3JNb2RlbCBOZXh0IHsgZ2V0OyBzZXQ7IH0KICAgICAgICBwdWJsaWMgaW50IFR5cGUgeyBnZXQ7IHNldDsgfQogICAgICAgIHB1YmxpYyBQb2ludFtdIFBvaW50IHsgZ2V0OyBzZXQ7IH0KICAgICAgICBwdWJsaWMgUmVjdGFuZ2xlRiBSZWN0YW5nbGVGIHsgZ2V0OyBzZXQ7IH0KICAgICAgICBwdWJsaWMgZmxvYXQgU3RhcnRBbmdsZSB7IGdldDsgc2V0OyB9CiAgICAgICAgcHVibGljIGZsb2F0IFN3ZWVwQW5nbGUgeyBnZXQ7IHNldDsgfQogICAgICAgIHB1YmxpYyBzdHJpbmcgVGV4dCB7IGdldDsgc2V0OyB9CiAgICAgICAgcHVibGljIHN0cmluZyBGb250TmFtZSB7IGdldDsgc2V0OyB9CiAgICAgICAgcHVibGljIGludCBGb250U3R5bGUgeyBnZXQ7IHNldDsgfQogICAgICAgIHB1YmxpYyBmbG9hdCBGb250ZW1TaXplIHsgZ2V0OyBzZXQ7IH0KICAgICAgICBwdWJsaWMgU3RyaW5nRm9ybWF0IFN0cmluZ0Zvcm1hdCB7IGdldDsgc2V0OyB9CiAgICAgICAgcHVibGljIEdyYXBoaWNzUGF0aCBQYXRoIHsgZ2V0OyBzZXQ7IH0KICAgICAgICBwdWJsaWMgZmxvYXQgUmFkaXVzIHsgZ2V0OyBzZXQ7IH0KICAgICAgICBwdWJsaWMgZmxvYXRbXSBTdEFuZ2VsID0gbmV3IGZsb2F0W10KICAgICAgICB7CiAgICAgICAgICAgIFMxODBBbmdlbCwKICAgICAgICAgICAgUzI3MEFuZ2VsLAogICAgICAgICAgICBTMDAwQW5nZWwsCiAgICAgICAgICAgIFMwOTBBbmdlbCwKICAgICAgICB9OwogICAgICAgIHB1YmxpYyB2b2lkIEdldFBhdGgoR3JhcGhpY3NQYXRoIGdwKQogICAgICAgIHsKICAgICAgICAgICAgLy9pZiAodGhpcy5DaGlsZCAhPSBudWxsKSBDaGlsZC5HZXRQYXRoKGdwKTsKICAgICAgICAgICAgc3dpdGNoICh0aGlzLlR5cGUpCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIGNhc2UgMDoKICAgICAgICAgICAgICAgICAgICBncC5BZGRMaW5lKHRoaXMuUG9pbnRbMF0sIHRoaXMuUG9pbnRbMV0pOwogICAgICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICAgICAgY2FzZSAxOgogICAgICAgICAgICAgICAgICAgIGdwLkFkZExpbmVzKHRoaXMuUG9pbnQpOwogICAgICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICAgICAgY2FzZSAyOgogICAgICAgICAgICAgICAgICAgIGdwLkFkZEFyYyh0aGlzLlJlY3RhbmdsZUYsIHRoaXMuU3RhcnRBbmdsZSwgdGhpcy5Td2VlcEFuZ2xlKTsKICAgICAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgICAgIGNhc2UgMzoKICAgICAgICAgICAgICAgICAgICBncC5BZGRTdHJpbmcodGhpcy5UZXh0LCBuZXcgRm9udEZhbWlseSh0aGlzLkZvbnROYW1lKSwKICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5Gb250U3R5bGUsIHRoaXMuRm9udGVtU2l6ZSwgUG9pbnRbMF0sIHRoaXMuU3RyaW5nRm9ybWF0KTsKICAgICAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgICAgIGNhc2UgNDoKICAgICAgICAgICAgICAgICAgICBncC5BZGRSZWN0YW5nbGUodGhpcy5SZWN0YW5nbGVGKTsKICAgICAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgICAgIGNhc2UgNToKICAgICAgICAgICAgICAgICAgICBpbnQgeHMgPSAoaW50KXRoaXMuUmVjdGFuZ2xlRi5Mb2NhdGlvbi5YOwogICAgICAgICAgICAgICAgICAgIGludCB5cyA9IChpbnQpdGhpcy5SZWN0YW5nbGVGLkxvY2F0aW9uLlk7CiAgICAgICAgICAgICAgICAgICAgaW50IHhlID0gKGludCl0aGlzLlJlY3RhbmdsZUYuV2lkdGg7CiAgICAgICAgICAgICAgICAgICAgaW50IHllID0gKGludCl0aGlzLlJlY3RhbmdsZUYuSGVpZ2h0OwogICAgICAgICAgICAgICAgICAgIGludCByYWQgPSAoaW50KSh0aGlzLlJhZGl1cyk7CiAgICAgICAgICAgICAgICAgICAgaW50IGRpYW1ldGVyID0gcmFkICogMjsKICAgICAgICAgICAgICAgICAgICBQb2ludFtdIHNwID0gbmV3IFBvaW50W117CiAgICAgICAgICAgICAgICAgICAgICAgIG5ldyBQb2ludCh4cyArIHJhZCwgeXMpLAogICAgICAgICAgICAgICAgICAgICAgICBuZXcgUG9pbnQoeGUsIHlzICsgcmFkKSwKICAgICAgICAgICAgICAgICAgICAgICAgbmV3IFBvaW50KHhlIC0gcmFkLCB5ZSksCiAgICAgICAgICAgICAgICAgICAgICAgIG5ldyBQb2ludCh4cywgeWUgLSByYWQpLAogICAgICAgICAgICAgICAgICAgIH07CiAgICAgICAgICAgICAgICAgICAgUG9pbnRbXSBlcCA9IG5ldyBQb2ludFtdewogICAgICAgICAgICAgICAgICAgICAgICBuZXcgUG9pbnQoeGUgLSByYWQsIHlzKSwKICAgICAgICAgICAgICAgICAgICAgICAgbmV3IFBvaW50KHhlLCB5ZSAtIHJhZCksCiAgICAgICAgICAgICAgICAgICAgICAgIG5ldyBQb2ludCh4cyArIHJhZCwgeWUpLAogICAgICAgICAgICAgICAgICAgICAgICBuZXcgUG9pbnQoeHMsIHlzICsgcmFkKSwKICAgICAgICAgICAgICAgICAgICB9OwogICAgICAgICAgICAgICAgICAgIFJlY3RhbmdsZVtdIHIgPSBuZXcgUmVjdGFuZ2xlW117CiAgICAgICAgICAgICAgICAgICAgICAgIG5ldyBSZWN0YW5nbGUoeHMsIHlzLCBkaWFtZXRlciwgZGlhbWV0ZXIpLAogICAgICAgICAgICAgICAgICAgICAgICBuZXcgUmVjdGFuZ2xlKHhlIC0gZGlhbWV0ZXIsIHlzLCBkaWFtZXRlciwgZGlhbWV0ZXIpLAogICAgICAgICAgICAgICAgICAgICAgICBuZXcgUmVjdGFuZ2xlKHhlIC0gZGlhbWV0ZXIsIHllIC0gZGlhbWV0ZXIsIGRpYW1ldGVyLCBkaWFtZXRlciksCiAgICAgICAgICAgICAgICAgICAgICAgIG5ldyBSZWN0YW5nbGUoeHMsIHllIC0gZGlhbWV0ZXIsIGRpYW1ldGVyLCBkaWFtZXRlciksCiAgICAgICAgICAgICAgICAgICAgfTsKICAgICAgICAgICAgICAgICAgICBmb3IgKGludCBpID0gMDsgaSA8IDQ7IGkrKykKICAgICAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgICAgIGdwLkFkZEFyYyhyW2ldLCB0aGlzLlN0QW5nZWxbaV0sIFN3QW5nbGUpOwogICAgICAgICAgICAgICAgICAgICAgICBncC5BZGRMaW5lKHNwW2ldLCBlcFtpXSk7CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICAgICAgY2FzZSA2OgogICAgICAgICAgICAgICAgICAgIGdwLkFkZFBhdGgodGhpcy5QYXRoLCBmYWxzZSk7CiAgICAgICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgICAgICBkZWZhdWx0OgogICAgICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICB9CiAgICAgICAgICAgIC8vaWYgKHRoaXMuTmV4dCAhPSBudWxsKSBOZXh0LkdldFBhdGgoZ3ApOwogICAgICAgICAgICByZXR1cm47CiAgICAgICAgfQogICAgfQp9