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();
}
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;
}
}
}
dXNpbmcgU3lzdGVtOwp1c2luZyBTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYzsKdXNpbmcgU3lzdGVtLkNvbXBvbmVudE1vZGVsOwp1c2luZyBTeXN0ZW0uRGF0YTsKdXNpbmcgU3lzdGVtLkRyYXdpbmc7CnVzaW5nIFN5c3RlbS5EcmF3aW5nLlRleHQ7CnVzaW5nIFN5c3RlbS5EcmF3aW5nLkltYWdpbmc7CnVzaW5nIFN5c3RlbS5EcmF3aW5nLkRyYXdpbmcyRDsKdXNpbmcgU3lzdGVtLkxpbnE7CnVzaW5nIFN5c3RlbS5UZXh0Owp1c2luZyBTeXN0ZW0uV2luZG93cy5Gb3JtczsKdXNpbmcgU3lzdGVtLklPOwoKbmFtZXNwYWNlIFdpbmRvd3NGb3Jtc0FwcGxpY2F0aW9uMQp7CiAgICBwdWJsaWMgcGFydGlhbCBjbGFzcyBGb3JtMSA6IEZvcm0KICAgIHsKICAgICAgICBwdWJsaWMgRm9ybTEoKQogICAgICAgIHsKICAgICAgICAgICAgSW5pdGlhbGl6ZUNvbXBvbmVudCgpOwogICAgICAgIH0KICAgICAgICBGb250RmFtaWx5W10gZmZzOwogICAgICAgIFRleHRCb3ggdGI7CiAgICAgICAgUGxheUNhcmQgcGM7CiAgICAgICAgLy/kv53lrZjloLTmiYDjga/jg4fjgrnjgq/jg4jjg4Pjg5cKICAgICAgICBzdHJpbmcgY2FyZFBhc3MgPSBFbnZpcm9ubWVudC5HZXRGb2xkZXJQYXRoKEVudmlyb25tZW50LlNwZWNpYWxGb2xkZXIuRGVza3RvcERpcmVjdG9yeSkgKyAiXFxjYXJkXFwiOwogICAgICAgIHByaXZhdGUgdm9pZCBGb3JtMV9Mb2FkKG9iamVjdCBzZW5kZXIsIEV2ZW50QXJncyBlKQogICAgICAgIHsKICAgICAgICAgICAgdGIgPSBuZXcgVGV4dEJveCgpOwogICAgICAgICAgICB0Yi5NdWx0aWxpbmUgPSB0cnVlOwogICAgICAgICAgICB0Yi5Eb2NrID0gRG9ja1N0eWxlLkZpbGw7CiAgICAgICAgICAgIHRiLlNjcm9sbEJhcnMgPSBTY3JvbGxCYXJzLkJvdGg7CiAgICAgICAgICAgIHRoaXMuQ29udHJvbHMuQWRkKHRiKTsKICAgICAgICAgICAgSW5zdGFsbGVkRm9udENvbGxlY3Rpb24gaWZjID0gbmV3IEluc3RhbGxlZEZvbnRDb2xsZWN0aW9uKCk7CiAgICAgICAgICAgIGZmcyA9IGlmYy5GYW1pbGllczsKICAgICAgICAgICAgaWYgKCFEaXJlY3RvcnkuRXhpc3RzKGNhcmRQYXNzKSkKICAgICAgICAgICAgICAgIERpcmVjdG9yeS5DcmVhdGVEaXJlY3RvcnkoY2FyZFBhc3MpOwogICAgICAgIH0KCiAgICAgICAgcHJpdmF0ZSB2b2lkIEZvcm0xX1Nob3duKG9iamVjdCBzZW5kZXIsIEV2ZW50QXJncyBlKQogICAgICAgIHsKICAgICAgICAgICAgcGMgPSBuZXcgUGxheUNhcmQoKTsKICAgICAgICAgICAgcGMuU2NhbGVYID0gMC41ZjsKICAgICAgICAgICAgcGMuU2NhbGVZID0gMC41ZjsKICAgICAgICAgICAgLy9wYy5PdXRsaW5lID0gZmFsc2U7CiAgICAgICAgICAgIC8vQml0bWFwIGFsbGJtcCA9IG5ldyBCaXRtYXAocGMuU2l6ZS5XaWR0aCAqIDE0LCBwYy5TaXplLkhlaWdodCAqIDQsIFBpeGVsRm9ybWF0LkZvcm1hdDMyYnBwQXJnYik7CiAgICAgICAgICAgIGZvciAoaW50IGsgPSAwOyBrIDwgNDsgaysrKQogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICBmb3IgKGludCBqID0gMDsgaiA8IDE0OyBqKyspCiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgQml0bWFwIGJtcCA9IHBjLkdldFBsYXlDYXJkKGssIGopOwogICAgICAgICAgICAgICAgICAgIC8vdXNpbmcgKEdyYXBoaWNzIGcgPSBHcmFwaGljcy5Gcm9tSW1hZ2UoYWxsYm1wKSkKICAgICAgICAgICAgICAgICAgICAvL3sKICAgICAgICAgICAgICAgICAgICAvLyAgICBnLkRyYXdJbWFnZShibXAsIG5ldyBQb2ludChqICogcGMuU2l6ZS5XaWR0aCwgayAqIHBjLlNpemUuSGVpZ2h0KSk7CiAgICAgICAgICAgICAgICAgICAgLy99CiAgICAgICAgICAgICAgICAgICAgc3RyaW5nIHZpZXd0ZXh0ID0gY2FyZFBhc3MgKyBwYy5DYXJkSW5pdGlhbFtrXSArIChqICsgMSkuVG9TdHJpbmcoIjAwIikgKyAiLnBuZyI7CiAgICAgICAgICAgICAgICAgICAgYm1wLlNhdmUodmlld3RleHQsIEltYWdlRm9ybWF0LlBuZyk7CiAgICAgICAgICAgICAgICAgICAgdGIuQXBwZW5kVGV4dCh2aWV3dGV4dCArICJcclxuIik7CiAgICAgICAgICAgICAgICAgICAgQXBwbGljYXRpb24uRG9FdmVudHMoKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgICAvL2FsbGJtcC5TYXZlKGNhcmRQYXNzICsgImFsbGNhcmQucG5nIiwgSW1hZ2VGb3JtYXQuUG5nKTsKICAgICAgICAgICAgdGIuQXBwZW5kVGV4dCgiZW5kIik7CiAgICAgICAgfQoKICAgIH0KICAgIGNsYXNzIFBsYXlDYXJkIDogUGxheUNhcmRNYXJrCiAgICB7CiAgICAgICAgcHVibGljIENvbG9yIEJhY2tncm91bmRDb2xvciB7IGdldDsgc2V0OyB9CiAgICAgICAgcHVibGljIENvbG9yIEZpbGxDb2xvciB7IGdldDsgc2V0OyB9CiAgICAgICAgcHVibGljIFBpeGVsRm9ybWF0IFBpeGVsRm9ybWF0IHsgZ2V0OyBzZXQ7IH0KICAgICAgICBwdWJsaWMgYm9vbCBPdXRsaW5lIHsgZ2V0OyBzZXQ7IH0KICAgICAgICBwdWJsaWMgaW50IE91dGxpbmVXaWR0aCB7IGdldDsgc2V0OyB9CiAgICAgICAgcHVibGljIENvbG9yIE91dGxpbmVDb2xvciB7IGdldDsgc2V0OyB9CiAgICAgICAgcHVibGljIHN0cmluZ1tdIENhcmRJbml0aWFsID0gbmV3IHN0cmluZ1tdCiAgICAgICAgewogICAgICAgICAgICAiUyIsIkQiLCJDIiwiSCIKICAgICAgICB9OwoKICAgICAgICBwdWJsaWMgUGxheUNhcmQoKQogICAgICAgIHsKICAgICAgICAgICAgdGhpcy5QaXhlbEZvcm1hdCA9IFBpeGVsRm9ybWF0LkZvcm1hdDMyYnBwQXJnYjsKICAgICAgICAgICAgdGhpcy5PdXRsaW5lID0gdHJ1ZTsKICAgICAgICAgICAgdGhpcy5PdXRsaW5lV2lkdGggPSAxOwogICAgICAgICAgICB0aGlzLk91dGxpbmVDb2xvciA9IENvbG9yLkJsYWNrOwogICAgICAgICAgICB0aGlzLkZvbnROYW1lID0gIu+8re+8syDvvLDjgrTjgrfjg4Pjgq8iOwogICAgICAgICAgICB0aGlzLkZpbGxDb2xvciA9IENvbG9yLldoaXRlOwogICAgICAgIH0KICAgICAgICBwdWJsaWMgQml0bWFwIEdldFBsYXlDYXJkKGludCBUeXBlLCBpbnQgQ2FyZE51bWJlcikKICAgICAgICB7CiAgICAgICAgICAgIEJpdG1hcCBibXAgPSBuZXcgQml0bWFwKChpbnQpKChmbG9hdCl0aGlzLlNpemUuV2lkdGggKiB0aGlzLlNjYWxlWCksCiAgICAgICAgICAgICAgICAoaW50KSgoZmxvYXQpKHRoaXMuU2l6ZS5IZWlnaHQgKiB0aGlzLlNjYWxlWSkpLCB0aGlzLlBpeGVsRm9ybWF0KTsKICAgICAgICAgICAgdXNpbmcgKEdyYXBoaWNzIGcgPSBHcmFwaGljcy5Gcm9tSW1hZ2UoYm1wKSkKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgZy5TbW9vdGhpbmdNb2RlID0gU21vb3RoaW5nTW9kZS5IaWdoUXVhbGl0eTsKICAgICAgICAgICAgICAgIC8v5b+144Gu44Gf44KB6YCP5piO6Imy44Gn5aGX44KLCiAgICAgICAgICAgICAgICBnLkZpbGxSZWN0YW5nbGUobmV3IFNvbGlkQnJ1c2goQmFja2dyb3VuZENvbG9yKSwgMCwgMCwgYm1wLldpZHRoLCBibXAuSGVpZ2h0KTsKCiAgICAgICAgICAgICAgICAvL+OCq+ODvOODieS9nOaIkAogICAgICAgICAgICAgICAgTW9kZWxNYW5hZ2VyIG1tID0gbmV3IE1vZGVsTWFuYWdlcigpOwogICAgICAgICAgICAgICAgbW0uQWRkUmVjdGFuZ2xlQXJjKG5ldyBSZWN0YW5nbGVGKDAuMGYsIDAuMGYsIDE5OS4wZiwgMjk5LjBmKSwgMTAuMGYpOwogICAgICAgICAgICAgICAgTWF0cml4IG0gPSBuZXcgTWF0cml4KCk7CiAgICAgICAgICAgICAgICBtLlNjYWxlKHRoaXMuU2NhbGVYLCB0aGlzLlNjYWxlWSk7CiAgICAgICAgICAgICAgICBHcmFwaGljc1BhdGggZ3AgPSBtbS5HZXRNb2RlbFBhdGgobSk7CiAgICAgICAgICAgICAgICBnLkZpbGxQYXRoKG5ldyBTb2xpZEJydXNoKHRoaXMuRmlsbENvbG9yKSwgZ3ApOwogICAgICAgICAgICAgICAgLy/jgqvjg7zjg4njga7ovKrpg60KICAgICAgICAgICAgICAgIGlmICh0aGlzLk91dGxpbmUgPT0gdHJ1ZSkKICAgICAgICAgICAgICAgICAgICBnLkRyYXdQYXRoKG5ldyBQZW4odGhpcy5PdXRsaW5lQ29sb3IsIHRoaXMuT3V0bGluZVdpZHRoKSwgZ3ApOwogICAgICAgICAgICAgICAgLy/jgqvjg7zjg4njga7kuK3lkbMKICAgICAgICAgICAgICAgIGdwID0gdGhpcy5HZXRNYXJrUGF0aChUeXBlLCBDYXJkTnVtYmVyKTsKICAgICAgICAgICAgICAgIGcuRmlsbFBhdGgodGhpcy5NYXJrQ29sb3JbVHlwZV0sIGdwKTsKICAgICAgICAgICAgfQogICAgICAgICAgICByZXR1cm4gYm1wOwogICAgICAgIH0KICAgIH0KICAgIHB1YmxpYyBjbGFzcyBQbGF5Q2FyZE1hcmsKICAgIHsKCiAgICAgICAgY29uc3QgaW50IGhvc2VpX3ggPSAtMTE7CiAgICAgICAgY29uc3QgaW50IGhvc2VpX3kgPSAtMTE7CiAgICAgICAgcHVibGljIHN0cmluZyBGb250TmFtZSB7IGdldDsgc2V0OyB9CiAgICAgICAgcHVibGljIGZsb2F0IFNjYWxlWCB7IGdldDsgc2V0OyB9CiAgICAgICAgcHVibGljIGZsb2F0IFNjYWxlWSB7IGdldDsgc2V0OyB9CiAgICAgICAgcHVibGljIFNpemUgU2l6ZSB7IGdldDsgc2V0OyB9CiAgICAgICAgcHVibGljIEJydXNoW10gTWFya0NvbG9yID0gbmV3IEJydXNoW10KICAgICAgICB7CiAgICAgICAgICAgIEJydXNoZXMuQmxhY2ssCiAgICAgICAgICAgIEJydXNoZXMuQ3JpbXNvbiwKICAgICAgICAgICAgQnJ1c2hlcy5CbGFjaywKICAgICAgICAgICAgQnJ1c2hlcy5Dcmltc29uLAogICAgICAgIH07CiAgICAgICAgcHVibGljIHN0cmluZ1tdIE1hcmsgPSBuZXcgc3RyaW5nW10KICAgICAgICB7CiAgICAgICAgICAgICLimaAiLCLimaYiLCLimaMiLCLimaUiCiAgICAgICAgfTsKICAgICAgICBwdWJsaWMgUG9pbnRbXSBQb2ludCA9IG5ldyBQb2ludFtdCiAgICAgICAgewogICAgICAgICAgICBuZXcgUG9pbnQoaG9zZWlfeCArICAyNSxob3NlaV95ICsgIDI1KSwKICAgICAgICAgICAgbmV3IFBvaW50KGhvc2VpX3ggKyAgMjUsaG9zZWlfeSArICA4NyksCiAgICAgICAgICAgIG5ldyBQb2ludChob3NlaV94ICsgIDI1LGhvc2VpX3kgKyAxMjUpLAoKICAgICAgICAgICAgbmV3IFBvaW50KGhvc2VpX3ggKyAxMjUsaG9zZWlfeSArICAyNSksCiAgICAgICAgICAgIG5ldyBQb2ludChob3NlaV94ICsgMTI1LGhvc2VpX3kgKyAgODcpLAogICAgICAgICAgICBuZXcgUG9pbnQoaG9zZWlfeCArIDEyNSxob3NlaV95ICsgMTI1KSwvLzUKCiAgICAgICAgICAgIG5ldyBQb2ludChob3NlaV94ICsgIDc1LGhvc2VpX3kgKyAgNzUpLAogICAgICAgICAgICBuZXcgUG9pbnQoaG9zZWlfeCArICA3NSxob3NlaV95ICsgMTI1KSwKICAgICAgICAgICAgbmV3IFBvaW50KGhvc2VpX3ggKyAgNzUsaG9zZWlfeSArICAyNSksCiAgICAgICAgICAgIG5ldyBQb2ludChob3NlaV94ICsgIDc1LGhvc2VpX3kgKyAgNjcpLAoKICAgICAgICB9OwogICAgICAgIHB1YmxpYyBTaXplIE1hcmtTaXplOwogICAgICAgIHN0cmluZ1tdIGNhcmRudW1iZXIgPSBuZXcgc3RyaW5nW10KICAgICAgICB7CiAgICAgICAgICAgICLvvKEiLCLvvJIiLCLvvJMiLCLvvJQiLCLvvJUiLCLvvJYiLCLvvJciLCLvvJgiLCLvvJkiLCIxMCIsIu+8qiIsIu+8sSIsIu+8qyIsIkpPS0VSIgogICAgICAgIH07CiAgICAgICAgaW50W10gY2FyZG51bWJlcncgPSBuZXcgaW50W10KICAgICAgICB7CiAgICAgICAgICAgIDEsMSwxLDEsMSwKICAgICAgICAgICAgMSwxLDEsMSwtNSwKICAgICAgICAgICAgMSwxLDEsMQogICAgICAgIH07CiAgICAgICAgcHVibGljIFBsYXlDYXJkTWFyaygpCiAgICAgICAgewogICAgICAgICAgICB0aGlzLlNpemUgPSBuZXcgU2l6ZSgyMDAsIDMwMCk7CiAgICAgICAgfQogICAgICAgIHByaXZhdGUgdm9pZCBHZXRMZWZ0VXBNYXJrKEdyYXBoaWNzUGF0aCBncCwgaW50IFR5cGUsIGludCBDYXJkTnVtYmVyKQogICAgICAgIHsKICAgICAgICAgICAgLy/jgqvjg7zjg4nlt6bkuIrjga7jg57jg7zjgq/jgajmlbDlrZfjgpLmj4/nlLsKICAgICAgICAgICAgLy/lj7PkuIvjga/lm57ou6Ir5bmz6KGM56e75YuV44Gn5a++5b+cCiAgICAgICAgICAgIGdwLkFkZFN0cmluZyh0aGlzLmNhcmRudW1iZXJbQ2FyZE51bWJlcl0sIG5ldyBGb250RmFtaWx5KHRoaXMuRm9udE5hbWUpLAogICAgICAgICAgICAgICAgMCwgMzAsIG5ldyBQb2ludCh0aGlzLmNhcmRudW1iZXJ3W0NhcmROdW1iZXJdLCAwKSwgU3RyaW5nRm9ybWF0LkdlbmVyaWNEZWZhdWx0KTsKICAgICAgICAgICAgaWYgKENhcmROdW1iZXIgPCAxMykgZ3AuQWRkU3RyaW5nKHRoaXMuTWFya1tUeXBlXSwgbmV3IEZvbnRGYW1pbHkodGhpcy5Gb250TmFtZSksCiAgICAgICAgICAgICAgICAgMCwgMzAsIG5ldyBQb2ludCgyLCAzMCksIFN0cmluZ0Zvcm1hdC5HZW5lcmljRGVmYXVsdCk7CiAgICAgICAgICAgIE1hdHJpeCBtID0gbmV3IE1hdHJpeCgpOwogICAgICAgICAgICBtLlNjYWxlKDAuOGYsIDEuMGYpOwogICAgICAgICAgICBncC5UcmFuc2Zvcm0obSk7CiAgICAgICAgfQogICAgICAgIHByaXZhdGUgdm9pZCBHZXRVcHBlck1hcmsoR3JhcGhpY3NQYXRoIGdwLCBpbnQgVHlwZSwgaW50IENhcmROdW1iZXIpCiAgICAgICAgewogICAgICAgICAgICAvL0HvvZ4xMOOBvuOBp+OBruS4reOBruODnuODvOOCr+OCkuaPj+eUuwogICAgICAgICAgICAvL+S4iuWNiuWIhuWFsemAmumDqOWIhuOBoOOBkeWHpueQhgogICAgICAgICAgICAvL+S4i+WNiuWIhuOBr+S4iuOCkuWbnui7oivlubPooYznp7vli5Xjgaflr77lv5wKICAgICAgICAgICAgc3dpdGNoICgoQ2FyZE51bWJlciArIDEpKQogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICBjYXNlIDI6CiAgICAgICAgICAgICAgICBjYXNlIDM6CiAgICAgICAgICAgICAgICAgICAgZ3AuQWRkU3RyaW5nKHRoaXMuTWFya1tUeXBlXSwgbmV3IEZvbnRGYW1pbHkodGhpcy5Gb250TmFtZSksCiAgICAgICAgICAgICAgICAgICAgICAgIDAsIDcwLCB0aGlzLlBvaW50WzhdLCBTdHJpbmdGb3JtYXQuR2VuZXJpY0RlZmF1bHQpOwogICAgICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICAgICAgY2FzZSA0OgogICAgICAgICAgICAgICAgY2FzZSA1OgogICAgICAgICAgICAgICAgY2FzZSA2OgogICAgICAgICAgICAgICAgY2FzZSA3OgogICAgICAgICAgICAgICAgY2FzZSA4OgogICAgICAgICAgICAgICAgICAgIGdwLkFkZFN0cmluZyh0aGlzLk1hcmtbVHlwZV0sIG5ldyBGb250RmFtaWx5KHRoaXMuRm9udE5hbWUpLAogICAgICAgICAgICAgICAgICAgICAgICAwLCA3MCwgUG9pbnRbMF0sIFN0cmluZ0Zvcm1hdC5HZW5lcmljRGVmYXVsdCk7CiAgICAgICAgICAgICAgICAgICAgZ3AuQWRkU3RyaW5nKHRoaXMuTWFya1tUeXBlXSwgbmV3IEZvbnRGYW1pbHkodGhpcy5Gb250TmFtZSksCiAgICAgICAgICAgICAgICAgICAgICAgIDAsIDcwLCBQb2ludFszXSwgU3RyaW5nRm9ybWF0LkdlbmVyaWNEZWZhdWx0KTsKICAgICAgICAgICAgICAgICAgICBpZiAoKENhcmROdW1iZXIgKyAxKSA9PSA4KQogICAgICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICAgICAgZ3AuQWRkU3RyaW5nKHRoaXMuTWFya1tUeXBlXSwgbmV3IEZvbnRGYW1pbHkodGhpcy5Gb250TmFtZSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAwLCA3MCwgUG9pbnRbNl0sIFN0cmluZ0Zvcm1hdC5HZW5lcmljRGVmYXVsdCk7CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICAgICAgY2FzZSA5OgogICAgICAgICAgICAgICAgY2FzZSAxMDoKICAgICAgICAgICAgICAgICAgICBncC5BZGRTdHJpbmcodGhpcy5NYXJrW1R5cGVdLCBuZXcgRm9udEZhbWlseSh0aGlzLkZvbnROYW1lKSwKICAgICAgICAgICAgICAgICAgICAgICAgMCwgNzAsIFBvaW50WzBdLCBTdHJpbmdGb3JtYXQuR2VuZXJpY0RlZmF1bHQpOwogICAgICAgICAgICAgICAgICAgIGdwLkFkZFN0cmluZyh0aGlzLk1hcmtbVHlwZV0sIG5ldyBGb250RmFtaWx5KHRoaXMuRm9udE5hbWUpLAogICAgICAgICAgICAgICAgICAgICAgICAwLCA3MCwgUG9pbnRbMV0sIFN0cmluZ0Zvcm1hdC5HZW5lcmljRGVmYXVsdCk7CiAgICAgICAgICAgICAgICAgICAgZ3AuQWRkU3RyaW5nKHRoaXMuTWFya1tUeXBlXSwgbmV3IEZvbnRGYW1pbHkodGhpcy5Gb250TmFtZSksCiAgICAgICAgICAgICAgICAgICAgICAgIDAsIDcwLCBQb2ludFszXSwgU3RyaW5nRm9ybWF0LkdlbmVyaWNEZWZhdWx0KTsKICAgICAgICAgICAgICAgICAgICBncC5BZGRTdHJpbmcodGhpcy5NYXJrW1R5cGVdLCBuZXcgRm9udEZhbWlseSh0aGlzLkZvbnROYW1lKSwKICAgICAgICAgICAgICAgICAgICAgICAgMCwgNzAsIFBvaW50WzRdLCBTdHJpbmdGb3JtYXQuR2VuZXJpY0RlZmF1bHQpOwogICAgICAgICAgICAgICAgICAgIGlmICgoQ2FyZE51bWJlciArIDEpID09IDEwKQogICAgICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICAgICAgZ3AuQWRkU3RyaW5nKHRoaXMuTWFya1tUeXBlXSwgbmV3IEZvbnRGYW1pbHkodGhpcy5Gb250TmFtZSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAwLCA3MCwgUG9pbnRbOV0sIFN0cmluZ0Zvcm1hdC5HZW5lcmljRGVmYXVsdCk7CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICAgICAgZGVmYXVsdDoKICAgICAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgfTsKICAgICAgICB9CiAgICAgICAgcHVibGljIEdyYXBoaWNzUGF0aCBHZXRNYXJrUGF0aChpbnQgVHlwZSwgaW50IENhcmROdW1iZXIpCiAgICAgICAgewogICAgICAgICAgICBNb2RlbE1hbmFnZXIgbW0gPSBuZXcgTW9kZWxNYW5hZ2VyKCk7CiAgICAgICAgICAgIC8v5Zue6Lui44Gn5a++5b+c5Y+v6IO944Gq44Oe44O844Kv44Gu5Yem55CGCiAgICAgICAgICAgIC8v5LiK5Y2K5YiGCiAgICAgICAgICAgIEdyYXBoaWNzUGF0aCBncDEgPSBuZXcgR3JhcGhpY3NQYXRoKCk7CiAgICAgICAgICAgIHRoaXMuR2V0TGVmdFVwTWFyayhncDEsIFR5cGUsIENhcmROdW1iZXIpOwogICAgICAgICAgICB0aGlzLkdldFVwcGVyTWFyayhncDEsIFR5cGUsIENhcmROdW1iZXIpOwogICAgICAgICAgICBtbS5BZGRQYXRoKGdwMSk7CiAgICAgICAgICAgIC8v5LiL5Y2K5YiGCiAgICAgICAgICAgIEdyYXBoaWNzUGF0aCBncDIgPSBuZXcgR3JhcGhpY3NQYXRoKCk7CiAgICAgICAgICAgIHRoaXMuR2V0TGVmdFVwTWFyayhncDIsIFR5cGUsIENhcmROdW1iZXIpOwogICAgICAgICAgICB0aGlzLkdldFVwcGVyTWFyayhncDIsIFR5cGUsIENhcmROdW1iZXIpOwogICAgICAgICAgICBNYXRyaXggbSA9IG5ldyBNYXRyaXgoKTsKICAgICAgICAgICAgbS5Sb3RhdGUoMTgwZik7CiAgICAgICAgICAgIGdwMi5UcmFuc2Zvcm0obSk7CiAgICAgICAgICAgIG0uUmVzZXQoKTsKICAgICAgICAgICAgbS5UcmFuc2xhdGUoKGZsb2F0KSh0aGlzLlNpemUuV2lkdGggLSAxKSwgKGZsb2F0KSh0aGlzLlNpemUuSGVpZ2h0IC0gMSkpOwogICAgICAgICAgICBncDIuVHJhbnNmb3JtKG0pOwogICAgICAgICAgICBtbS5BZGRQYXRoKGdwMik7CiAgICAgICAgICAgIC8v5Zue6Lui44Gn5a++5b+c44Gn44GN44Gq44GE44Oe44O844Kv44Gu5Yem55CGCiAgICAgICAgICAgIHN3aXRjaCAoKENhcmROdW1iZXIgKyAxKSkKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgY2FzZSAxOgogICAgICAgICAgICAgICAgY2FzZSAzOgogICAgICAgICAgICAgICAgY2FzZSA1OgogICAgICAgICAgICAgICAgY2FzZSA5OgogICAgICAgICAgICAgICAgICAgIG1tLkFkZFN0cmluZyh0aGlzLk1hcmtbVHlwZV0sIHRoaXMuRm9udE5hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgIDAsIDcwLCBQb2ludFs3XSwgU3RyaW5nRm9ybWF0LkdlbmVyaWNEZWZhdWx0KTsKICAgICAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgICAgIGNhc2UgNjoKICAgICAgICAgICAgICAgIGNhc2UgNzoKICAgICAgICAgICAgICAgIGNhc2UgODoKICAgICAgICAgICAgICAgICAgICBtbS5BZGRTdHJpbmcodGhpcy5NYXJrW1R5cGVdLCB0aGlzLkZvbnROYW1lLAogICAgICAgICAgICAgICAgICAgICAgICAwLCA3MCwgUG9pbnRbMl0sIFN0cmluZ0Zvcm1hdC5HZW5lcmljRGVmYXVsdCk7CiAgICAgICAgICAgICAgICAgICAgbW0uQWRkU3RyaW5nKHRoaXMuTWFya1tUeXBlXSwgdGhpcy5Gb250TmFtZSwKICAgICAgICAgICAgICAgICAgICAgICAgMCwgNzAsIFBvaW50WzVdLCBTdHJpbmdGb3JtYXQuR2VuZXJpY0RlZmF1bHQpOwogICAgICAgICAgICAgICAgICAgIGlmICgoQ2FyZE51bWJlciArIDEpID09IDcpCiAgICAgICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgICAgICBtbS5BZGRTdHJpbmcodGhpcy5NYXJrW1R5cGVdLCB0aGlzLkZvbnROYW1lLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgMCwgNzAsIFBvaW50WzZdLCBTdHJpbmdGb3JtYXQuR2VuZXJpY0RlZmF1bHQpOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgICAgIGRlZmF1bHQ6CiAgICAgICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgIH07CiAgICAgICAgICAgIG0uUmVzZXQoKTsKICAgICAgICAgICAgbS5TY2FsZSh0aGlzLlNjYWxlWCwgdGhpcy5TY2FsZVkpOwogICAgICAgICAgICByZXR1cm4gbW0uR2V0TW9kZWxQYXRoKG0pOwogICAgICAgIH0KICAgIH0KICAgIHB1YmxpYyBjbGFzcyBNb2RlbE1hbmFnZXIKICAgIHsKICAgICAgICBwdWJsaWMgTWF0cml4IE1hdHJpeCB7IGdldDsgc2V0OyB9CiAgICAgICAgcHVibGljIExpc3Q8VmVjdG9yTW9kZWw+IE1vZGVsIHsgZ2V0OyBzZXQ7IH0KICAgICAgICBwdWJsaWMgTW9kZWxNYW5hZ2VyKCkKICAgICAgICB7CiAgICAgICAgICAgIHRoaXMuTW9kZWwgPSBuZXcgTGlzdDxWZWN0b3JNb2RlbD4oKTsKICAgICAgICAgICAgdGhpcy5NYXRyaXggPSBuZXcgTWF0cml4KCk7CiAgICAgICAgfQogICAgICAgIHB1YmxpYyB2b2lkIEFkZFZlY3Rvck1vZGVsKFZlY3Rvck1vZGVsIHZtKQogICAgICAgIHsKICAgICAgICAgICAgdGhpcy5Nb2RlbC5BZGQodm0pOwogICAgICAgIH0KICAgICAgICBwdWJsaWMgdm9pZCBBZGRMaW5lKGludCBTdGFydFgsIGludCBTdGFydFksIGludCBFbmRYLCBpbnQgRW5kWSkKICAgICAgICB7CiAgICAgICAgICAgIHRoaXMuQWRkTGluZShuZXcgUG9pbnQoU3RhcnRYLCBTdGFydFkpLCBuZXcgUG9pbnQoRW5kWCwgRW5kWSkpOwogICAgICAgIH0KICAgICAgICBwdWJsaWMgdm9pZCBBZGRMaW5lKFBvaW50W10gUG9pbnQpCiAgICAgICAgewogICAgICAgICAgICBWZWN0b3JNb2RlbCB2bSA9IG5ldyBWZWN0b3JNb2RlbCgpOwogICAgICAgICAgICB2bS5UeXBlID0gMDsKICAgICAgICAgICAgdm0uUG9pbnQgPSBQb2ludDsKICAgICAgICAgICAgdGhpcy5BZGRWZWN0b3JNb2RlbCh2bSk7CiAgICAgICAgfQogICAgICAgIHB1YmxpYyB2b2lkIEFkZExpbmUoUG9pbnQgU3RhcnQsIFBvaW50IEVuZCkKICAgICAgICB7CiAgICAgICAgICAgIFBvaW50W10gUG9pbnQgPSBuZXcgUG9pbnRbMl07CiAgICAgICAgICAgIFBvaW50WzBdID0gU3RhcnQ7CiAgICAgICAgICAgIFBvaW50WzFdID0gRW5kOwogICAgICAgICAgICB0aGlzLkFkZExpbmUoUG9pbnQpOwogICAgICAgIH0KICAgICAgICBwdWJsaWMgdm9pZCBBZGRMaW5lcyhQb2ludFtdIFBvaW50KQogICAgICAgIHsKICAgICAgICAgICAgVmVjdG9yTW9kZWwgdm0gPSBuZXcgVmVjdG9yTW9kZWwoKTsKICAgICAgICAgICAgdm0uVHlwZSA9IDE7CiAgICAgICAgICAgIHZtLlBvaW50ID0gUG9pbnQ7CiAgICAgICAgICAgIHRoaXMuQWRkVmVjdG9yTW9kZWwodm0pOwogICAgICAgIH0KICAgICAgICBwdWJsaWMgdm9pZCBBZGRBcmMoUmVjdGFuZ2xlRiBSZWN0YW5nbGVGLCBmbG9hdCBTdGFydEFuZ2xlLCBmbG9hdCBTd2VlcEFuZ2xlKQogICAgICAgIHsKICAgICAgICAgICAgVmVjdG9yTW9kZWwgdm0gPSBuZXcgVmVjdG9yTW9kZWwoKTsKICAgICAgICAgICAgdm0uVHlwZSA9IDI7CiAgICAgICAgICAgIHZtLlJlY3RhbmdsZUYgPSBSZWN0YW5nbGVGOwogICAgICAgICAgICB2bS5TdGFydEFuZ2xlID0gU3RhcnRBbmdsZTsKICAgICAgICAgICAgdm0uU3dlZXBBbmdsZSA9IFN3ZWVwQW5nbGU7CiAgICAgICAgICAgIHRoaXMuQWRkVmVjdG9yTW9kZWwodm0pOwoKICAgICAgICB9CiAgICAgICAgcHVibGljIHZvaWQgQWRkQXJjKGludCBTdGFydFgsIGludCBTdGFydFksIGludCBXaWR0aCwgaW50IEhlaWdodCwgaW50IFN0YXJ0QW5nbGUsIGludCBTd2VlcEFuZ2xlKQogICAgICAgIHsKICAgICAgICAgICAgdGhpcy5BZGRBcmMobmV3IFJlY3RhbmdsZUYoKGZsb2F0KVN0YXJ0WCwgKGZsb2F0KVN0YXJ0WSwgKGZsb2F0KVdpZHRoLCAoZmxvYXQpSGVpZ2h0KSwKICAgICAgICAgICAgICAgIChmbG9hdClTdGFydEFuZ2xlLCAoZmxvYXQpU3dlZXBBbmdsZSk7CiAgICAgICAgfQogICAgICAgIHB1YmxpYyB2b2lkIEFkZEFyYyhmbG9hdCBTdGFydFgsIGZsb2F0IFN0YXJ0WSwgZmxvYXQgV2lkdGgsIGZsb2F0IEhlaWdodCwgZmxvYXQgU3RhcnRBbmdsZSwgZmxvYXQgU3dlZXBBbmdsZSkKICAgICAgICB7CiAgICAgICAgICAgIHRoaXMuQWRkQXJjKG5ldyBSZWN0YW5nbGVGKFN0YXJ0WCwgU3RhcnRZLCBXaWR0aCwgSGVpZ2h0KSwKICAgICAgICAgICAgICAgIFN0YXJ0QW5nbGUsIFN3ZWVwQW5nbGUpOwogICAgICAgIH0KICAgICAgICBwdWJsaWMgdm9pZCBBZGRTdHJpbmcoU3RyaW5nIFRleHQsIHN0cmluZyBGb250TmFtZSwgaW50IEZvbnRTdHlsZSwgZmxvYXQgRm9udGVtU2l6ZSwgUG9pbnQgUG9pbnQsIFN0cmluZ0Zvcm1hdCBTdHJpbmdGb3JtYXQpCiAgICAgICAgewogICAgICAgICAgICBWZWN0b3JNb2RlbCB2bSA9IG5ldyBWZWN0b3JNb2RlbCgpOwogICAgICAgICAgICB2bS5UeXBlID0gMzsKICAgICAgICAgICAgdm0uVGV4dCA9IFRleHQ7CiAgICAgICAgICAgIHZtLkZvbnROYW1lID0gRm9udE5hbWU7CiAgICAgICAgICAgIHZtLkZvbnRTdHlsZSA9IEZvbnRTdHlsZTsKICAgICAgICAgICAgdm0uRm9udGVtU2l6ZSA9IEZvbnRlbVNpemU7CiAgICAgICAgICAgIHZtLlBvaW50ID0gbmV3IFBvaW50W10geyBQb2ludCB9OwogICAgICAgICAgICB2bS5TdHJpbmdGb3JtYXQgPSBTdHJpbmdGb3JtYXQ7CiAgICAgICAgICAgIHRoaXMuQWRkVmVjdG9yTW9kZWwodm0pOwogICAgICAgIH0KICAgICAgICBwdWJsaWMgdm9pZCBBZGRSZWN0YW5nbGUoUmVjdGFuZ2xlRiBSZWN0YW5nbGVGKQogICAgICAgIHsKICAgICAgICAgICAgVmVjdG9yTW9kZWwgdm0gPSBuZXcgVmVjdG9yTW9kZWwoKTsKICAgICAgICAgICAgdm0uVHlwZSA9IDQ7CiAgICAgICAgICAgIHZtLlJlY3RhbmdsZUYgPSBSZWN0YW5nbGVGOwogICAgICAgICAgICB0aGlzLkFkZFZlY3Rvck1vZGVsKHZtKTsKICAgICAgICB9CiAgICAgICAgcHVibGljIHZvaWQgQWRkUmVjdGFuZ2xlKGludCBTdGFydFgsIGludCBTdGFydFksIGludCBXaWR0aCwgaW50IEhlaWdodCkKICAgICAgICB7CiAgICAgICAgICAgIHRoaXMuQWRkUmVjdGFuZ2xlKG5ldyBSZWN0YW5nbGVGKChmbG9hdClTdGFydFgsIChmbG9hdClTdGFydFksIChmbG9hdClXaWR0aCwgKGZsb2F0KUhlaWdodCkpOwogICAgICAgIH0KICAgICAgICBwdWJsaWMgdm9pZCBBZGRSZWN0YW5nbGUoZmxvYXQgU3RhcnRYLCBmbG9hdCBTdGFydFksIGZsb2F0IFdpZHRoLCBmbG9hdCBIZWlnaHQpCiAgICAgICAgewogICAgICAgICAgICB0aGlzLkFkZFJlY3RhbmdsZShuZXcgUmVjdGFuZ2xlRihTdGFydFgsIFN0YXJ0WSwgV2lkdGgsIEhlaWdodCkpOwogICAgICAgIH0KICAgICAgICBwdWJsaWMgdm9pZCBBZGRSZWN0YW5nbGVBcmMoUmVjdGFuZ2xlRiBSZWN0YW5nbGVGLCBmbG9hdCBSYWRpdXMpCiAgICAgICAgewogICAgICAgICAgICBWZWN0b3JNb2RlbCB2bSA9IG5ldyBWZWN0b3JNb2RlbCgpOwogICAgICAgICAgICBpZiAoUmFkaXVzIDwgMS4wZikKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgLy/ljYrlvoTjgYwx5Lul5LiL44Gu5aC05ZCI44Gv5Li444G/54Sh44GX44Gr5YiH44KK5pu/44GICiAgICAgICAgICAgICAgICB0aGlzLkFkZFJlY3RhbmdsZShSZWN0YW5nbGVGKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBlbHNlCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIHZtLlR5cGUgPSA1OwogICAgICAgICAgICAgICAgdm0uUmVjdGFuZ2xlRiA9IFJlY3RhbmdsZUY7CiAgICAgICAgICAgICAgICB2bS5SYWRpdXMgPSBSYWRpdXM7CiAgICAgICAgICAgICAgICB0aGlzLkFkZFZlY3Rvck1vZGVsKHZtKTsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBwdWJsaWMgdm9pZCBBZGRSZWN0YW5nbGVBcmMoaW50IFN0YXJ0WCwgaW50IFN0YXJ0WSwgaW50IFdpZHRoLCBpbnQgSGVpZ2h0LCBpbnQgUmFkaXVzKQogICAgICAgIHsKICAgICAgICAgICAgdGhpcy5BZGRSZWN0YW5nbGVBcmMobmV3IFJlY3RhbmdsZUYoKGZsb2F0KVN0YXJ0WCwgKGZsb2F0KVN0YXJ0WSwgKGZsb2F0KVdpZHRoLCAoZmxvYXQpSGVpZ2h0KSwgKGZsb2F0KVJhZGl1cyk7CiAgICAgICAgfQogICAgICAgIHB1YmxpYyB2b2lkIEFkZFJlY3RhbmdsZUFyYyhmbG9hdCBTdGFydFgsIGZsb2F0IFN0YXJ0WSwgZmxvYXQgV2lkdGgsIGZsb2F0IEhlaWdodCwgZmxvYXQgUmFkaXVzKQogICAgICAgIHsKICAgICAgICAgICAgdGhpcy5BZGRSZWN0YW5nbGVBcmMobmV3IFJlY3RhbmdsZUYoU3RhcnRYLCBTdGFydFksIFdpZHRoLCBIZWlnaHQpLCBSYWRpdXMpOwogICAgICAgIH0KICAgICAgICBwdWJsaWMgdm9pZCBBZGRQYXRoKEdyYXBoaWNzUGF0aCBQYXRoKQogICAgICAgIHsKICAgICAgICAgICAgLy9pZiAoUGF0aC5Qb2ludENvdW50ID09IDApIHJldHVybjsKICAgICAgICAgICAgVmVjdG9yTW9kZWwgdm0gPSBuZXcgVmVjdG9yTW9kZWwoKTsKICAgICAgICAgICAgdm0uVHlwZSA9IDY7CiAgICAgICAgICAgIHZtLlBhdGggPSBQYXRoOwogICAgICAgICAgICB0aGlzLkFkZFZlY3Rvck1vZGVsKHZtKTsKICAgICAgICB9CiAgICAgICAgcHVibGljIHZvaWQgQ2xlYXIoKQogICAgICAgIHsKICAgICAgICAgICAgdGhpcy5Nb2RlbC5DbGVhcigpOwogICAgICAgIH0KICAgICAgICBwdWJsaWMgR3JhcGhpY3NQYXRoIEdldE1vZGVsUGF0aChNYXRyaXggbSkKICAgICAgICB7CiAgICAgICAgICAgIEdyYXBoaWNzUGF0aCBncCA9IG5ldyBHcmFwaGljc1BhdGgoKTsKICAgICAgICAgICAgZm9yZWFjaCAoVmVjdG9yTW9kZWwgdm0gaW4gdGhpcy5Nb2RlbCkKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgdm0uR2V0UGF0aChncCk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgZ3AuVHJhbnNmb3JtKG0pOwogICAgICAgICAgICByZXR1cm4gZ3A7CiAgICAgICAgfQogICAgICAgIHB1YmxpYyBHcmFwaGljc1BhdGggR2V0TW9kZWxQYXRoKCkKICAgICAgICB7CiAgICAgICAgICAgIC8vR3JhcGhpY3NQYXRoIGdwID0gdGhpcy5HZXRNb2RlbFBhdGgodGhpcy5NYXRyaXgpOwogICAgICAgICAgICAvL3JldHVybiBncDsKICAgICAgICAgICAgcmV0dXJuIHRoaXMuR2V0TW9kZWxQYXRoKHRoaXMuTWF0cml4KTsKICAgICAgICB9CiAgICB9CiAgICBwdWJsaWMgY2xhc3MgVmVjdG9yTW9kZWwKICAgIHsKICAgICAgICBjb25zdCBmbG9hdCBTd0FuZ2xlID0gOTAuMGY7CiAgICAgICAgY29uc3QgZmxvYXQgUzAwMEFuZ2VsID0gMC4wZjsKICAgICAgICBjb25zdCBmbG9hdCBTMDkwQW5nZWwgPSA5MC4wZjsKICAgICAgICBjb25zdCBmbG9hdCBTMTgwQW5nZWwgPSAxODAuMGY7CiAgICAgICAgY29uc3QgZmxvYXQgUzI3MEFuZ2VsID0gMjcwLjBmOwogICAgICAgIC8vcHVibGljIFZlY3Rvck1vZGVsIFBhcmVudCB7IGdldDsgc2V0OyB9CiAgICAgICAgLy9wdWJsaWMgVmVjdG9yTW9kZWwgQ2hpbGQgeyBnZXQ7IHNldDsgfQogICAgICAgIC8vcHVibGljIFZlY3Rvck1vZGVsIE5leHQgeyBnZXQ7IHNldDsgfQogICAgICAgIHB1YmxpYyBpbnQgVHlwZSB7IGdldDsgc2V0OyB9CiAgICAgICAgcHVibGljIFBvaW50W10gUG9pbnQgeyBnZXQ7IHNldDsgfQogICAgICAgIHB1YmxpYyBSZWN0YW5nbGVGIFJlY3RhbmdsZUYgeyBnZXQ7IHNldDsgfQogICAgICAgIHB1YmxpYyBmbG9hdCBTdGFydEFuZ2xlIHsgZ2V0OyBzZXQ7IH0KICAgICAgICBwdWJsaWMgZmxvYXQgU3dlZXBBbmdsZSB7IGdldDsgc2V0OyB9CiAgICAgICAgcHVibGljIHN0cmluZyBUZXh0IHsgZ2V0OyBzZXQ7IH0KICAgICAgICBwdWJsaWMgc3RyaW5nIEZvbnROYW1lIHsgZ2V0OyBzZXQ7IH0KICAgICAgICBwdWJsaWMgaW50IEZvbnRTdHlsZSB7IGdldDsgc2V0OyB9CiAgICAgICAgcHVibGljIGZsb2F0IEZvbnRlbVNpemUgeyBnZXQ7IHNldDsgfQogICAgICAgIHB1YmxpYyBTdHJpbmdGb3JtYXQgU3RyaW5nRm9ybWF0IHsgZ2V0OyBzZXQ7IH0KICAgICAgICBwdWJsaWMgR3JhcGhpY3NQYXRoIFBhdGggeyBnZXQ7IHNldDsgfQogICAgICAgIHB1YmxpYyBmbG9hdCBSYWRpdXMgeyBnZXQ7IHNldDsgfQogICAgICAgIHB1YmxpYyBmbG9hdFtdIFN0QW5nZWwgPSBuZXcgZmxvYXRbXQogICAgICAgIHsKICAgICAgICAgICAgUzE4MEFuZ2VsLAogICAgICAgICAgICBTMjcwQW5nZWwsCiAgICAgICAgICAgIFMwMDBBbmdlbCwKICAgICAgICAgICAgUzA5MEFuZ2VsLAogICAgICAgIH07CiAgICAgICAgcHVibGljIHZvaWQgR2V0UGF0aChHcmFwaGljc1BhdGggZ3ApCiAgICAgICAgewogICAgICAgICAgICAvL2lmICh0aGlzLkNoaWxkICE9IG51bGwpIENoaWxkLkdldFBhdGgoZ3ApOwogICAgICAgICAgICBzd2l0Y2ggKHRoaXMuVHlwZSkKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgY2FzZSAwOgogICAgICAgICAgICAgICAgICAgIGdwLkFkZExpbmUodGhpcy5Qb2ludFswXSwgdGhpcy5Qb2ludFsxXSk7CiAgICAgICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgICAgICBjYXNlIDE6CiAgICAgICAgICAgICAgICAgICAgZ3AuQWRkTGluZXModGhpcy5Qb2ludCk7CiAgICAgICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgICAgICBjYXNlIDI6CiAgICAgICAgICAgICAgICAgICAgZ3AuQWRkQXJjKHRoaXMuUmVjdGFuZ2xlRiwgdGhpcy5TdGFydEFuZ2xlLCB0aGlzLlN3ZWVwQW5nbGUpOwogICAgICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICAgICAgY2FzZSAzOgogICAgICAgICAgICAgICAgICAgIGdwLkFkZFN0cmluZyh0aGlzLlRleHQsIG5ldyBGb250RmFtaWx5KHRoaXMuRm9udE5hbWUpLAogICAgICAgICAgICAgICAgICAgICAgICB0aGlzLkZvbnRTdHlsZSwgdGhpcy5Gb250ZW1TaXplLCBQb2ludFswXSwgdGhpcy5TdHJpbmdGb3JtYXQpOwogICAgICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICAgICAgY2FzZSA0OgogICAgICAgICAgICAgICAgICAgIGdwLkFkZFJlY3RhbmdsZSh0aGlzLlJlY3RhbmdsZUYpOwogICAgICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICAgICAgY2FzZSA1OgogICAgICAgICAgICAgICAgICAgIGludCB4cyA9IChpbnQpdGhpcy5SZWN0YW5nbGVGLkxvY2F0aW9uLlg7CiAgICAgICAgICAgICAgICAgICAgaW50IHlzID0gKGludCl0aGlzLlJlY3RhbmdsZUYuTG9jYXRpb24uWTsKICAgICAgICAgICAgICAgICAgICBpbnQgeGUgPSAoaW50KXRoaXMuUmVjdGFuZ2xlRi5XaWR0aDsKICAgICAgICAgICAgICAgICAgICBpbnQgeWUgPSAoaW50KXRoaXMuUmVjdGFuZ2xlRi5IZWlnaHQ7CiAgICAgICAgICAgICAgICAgICAgaW50IHJhZCA9IChpbnQpKHRoaXMuUmFkaXVzKTsKICAgICAgICAgICAgICAgICAgICBpbnQgZGlhbWV0ZXIgPSByYWQgKiAyOwogICAgICAgICAgICAgICAgICAgIFBvaW50W10gc3AgPSBuZXcgUG9pbnRbXXsKICAgICAgICAgICAgICAgICAgICAgICAgbmV3IFBvaW50KHhzICsgcmFkLCB5cyksCiAgICAgICAgICAgICAgICAgICAgICAgIG5ldyBQb2ludCh4ZSwgeXMgKyByYWQpLAogICAgICAgICAgICAgICAgICAgICAgICBuZXcgUG9pbnQoeGUgLSByYWQsIHllKSwKICAgICAgICAgICAgICAgICAgICAgICAgbmV3IFBvaW50KHhzLCB5ZSAtIHJhZCksCiAgICAgICAgICAgICAgICAgICAgfTsKICAgICAgICAgICAgICAgICAgICBQb2ludFtdIGVwID0gbmV3IFBvaW50W117CiAgICAgICAgICAgICAgICAgICAgICAgIG5ldyBQb2ludCh4ZSAtIHJhZCwgeXMpLAogICAgICAgICAgICAgICAgICAgICAgICBuZXcgUG9pbnQoeGUsIHllIC0gcmFkKSwKICAgICAgICAgICAgICAgICAgICAgICAgbmV3IFBvaW50KHhzICsgcmFkLCB5ZSksCiAgICAgICAgICAgICAgICAgICAgICAgIG5ldyBQb2ludCh4cywgeXMgKyByYWQpLAogICAgICAgICAgICAgICAgICAgIH07CiAgICAgICAgICAgICAgICAgICAgUmVjdGFuZ2xlW10gciA9IG5ldyBSZWN0YW5nbGVbXXsKICAgICAgICAgICAgICAgICAgICAgICAgbmV3IFJlY3RhbmdsZSh4cywgeXMsIGRpYW1ldGVyLCBkaWFtZXRlciksCiAgICAgICAgICAgICAgICAgICAgICAgIG5ldyBSZWN0YW5nbGUoeGUgLSBkaWFtZXRlciwgeXMsIGRpYW1ldGVyLCBkaWFtZXRlciksCiAgICAgICAgICAgICAgICAgICAgICAgIG5ldyBSZWN0YW5nbGUoeGUgLSBkaWFtZXRlciwgeWUgLSBkaWFtZXRlciwgZGlhbWV0ZXIsIGRpYW1ldGVyKSwKICAgICAgICAgICAgICAgICAgICAgICAgbmV3IFJlY3RhbmdsZSh4cywgeWUgLSBkaWFtZXRlciwgZGlhbWV0ZXIsIGRpYW1ldGVyKSwKICAgICAgICAgICAgICAgICAgICB9OwogICAgICAgICAgICAgICAgICAgIGZvciAoaW50IGkgPSAwOyBpIDwgNDsgaSsrKQogICAgICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICAgICAgZ3AuQWRkQXJjKHJbaV0sIHRoaXMuU3RBbmdlbFtpXSwgU3dBbmdsZSk7CiAgICAgICAgICAgICAgICAgICAgICAgIGdwLkFkZExpbmUoc3BbaV0sIGVwW2ldKTsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgICAgICBjYXNlIDY6CiAgICAgICAgICAgICAgICAgICAgZ3AuQWRkUGF0aCh0aGlzLlBhdGgsIGZhbHNlKTsKICAgICAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgICAgIGRlZmF1bHQ6CiAgICAgICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgLy9pZiAodGhpcy5OZXh0ICE9IG51bGwpIE5leHQuR2V0UGF0aChncCk7CiAgICAgICAgICAgIHJldHVybjsKICAgICAgICB9CiAgICB9Cn0=