using Microsoft.VisualBasic ;
using System;
using System.Collections ;
using System.Collections .Generic ;
using System.Data ;
using System.Diagnostics ;
public class Form1
{
LogicMap Logic = new LogicMap( ) ;
private void Form1_KeyDown( object sender, System.Windows .Forms .KeyEventArgs e)
{
if ( e.KeyData == Keys.Space ) {
Console.WriteLine ( "------- New Step ---------" ) ;
Logic.DoLogic ( ) ;
}
}
private void Form1_Load( System.Object sender, System.EventArgs e)
{
Logic.AddGate ( new Point( 100 , 130 ) , 0 , 0 , 0 ) ;
Logic.AddGate ( new Point( 160 , 40 ) , 0 , 0 , 4 ) ;
Logic.AddGate ( new Point( 205 , 105 ) , 0 , 3 , 1 ) ;
Logic.AddGate ( new Point( 450 , 35 ) , 0 , 4 , 0 ) ;
Logic.AddGate ( new Point( 595 , 135 ) , 0 , 0 , 1 ) ;
Logic.AddPulse ( Color.FromArgb ( 255 , 0 , 0 ) , 1 , 5 ) ;
Logic.AddPulse ( Color.FromArgb ( 255 , 128 , 162 ) , 2 , 7 ) ;
}
private void DrawLogicMap( )
{
Graphics g = this.CreateGraphics ( ) ;
}
public class LogicMap
{
public List< LogicGate> NextGates;
public List< LogicGate> ActiveGates;
private List< LogicGate> Gates;
public void AddGate( Point Pos, LogicType Logic, int TrueGate, int FalseGate)
{
Gates.Add ( new LogicGate {
L = Logic,
NT = TrueGate,
NF = FalseGate,
P = new List< Pulse> ( ) ,
isActive = false ,
id = Gates.Count ,
Position = Pos
} ) ;
Console.WriteLine ( "#Added Gate(" + Gates.Count - 1 + "): Logic(" + Logic + "), FalseGate(" + FalseGate + "), TrueGate(" + TrueGate + ")" ) ;
}
public bool AddPulse( Color Color, int Gate, int Value)
{
if ( Gate >= Gates.Count | Gate <= - 1 )
return false ;
Gates[ Gate] .AddPulse ( Color, ref this, ref Value) ;
Console.WriteLine ( "#Added Pulse at Gate(" + Gate + ") with Value(" + Value + ")" ) ;
return true ;
}
public LogicMap( )
{
NextGates = new List< LogicGate> ( ) ;
ActiveGates = new List< LogicGate> ( ) ;
Gates = new List< LogicGate> ( ) ;
Console.WriteLine ( "#Created new Logic Map" ) ;
}
public bool DoLogic( )
{
ActiveGates.Clear ( ) ;
//Replace and make room for new changes.
ActiveGates.AddRange ( NextGates) ;
NextGates.Clear ( ) ;
Form1.CreateGraphics ( ) .Clear ( Color.Black ) ;
foreach ( object Gate_loopVariable in Gates) {
Gate = Gate_loopVariable;
Gate.DrawDebugBase ( ) ;
Gate.DebugDrawLines ( this, Gates) ;
}
foreach ( LogicGate Gate in ActiveGates) {
Gate.DoLogic ( ref this, ref Gates) ;
Gate.DrawDebug ( ) ;
}
return true ;
}
}
public struct Pulse
{
public int Value;
public Color Color;
public object MoveTo( ref LogicMap LogMap, ref LogicGate OldGate, ref LogicGate NewGate, bool State)
{
OldGate.P .Remove ( this) ;
Graphics G = Form1.CreateGraphics ( ) ;
Point Position = default ( Point) ;
if ( LogicGate.IsVoid ( ref NewGate) ) {
Console.WriteLine ( "Stopped at Gate:" + OldGate.id ) ;
if ( State == false )
Position = new Point( OldGate.Position .X + 20 , OldGate.Position .Y + 10 ) ;
else
Position = new Point( OldGate.Position .X + 20 , OldGate.Position .Y - 10 ) ;
G.DrawEllipse ( new Pen( this.Color ) , Position.X - 7 , Position.Y - 7 , 14 , 14 ) ;
return false ;
}
NewGate.P .Add ( this) ;
if ( State == false )
Position = new Point( OldGate.Position .X + 20 , OldGate.Position .Y + 10 ) ;
else
Position = new Point( OldGate.Position .X + 20 , OldGate.Position .Y - 10 ) ;
G.DrawLine ( new Pen( this.Color , this.Value ) , Position, NewGate.Position ) ;
Console.WriteLine ( "Moved from to " + OldGate.id + " to Gate: " + NewGate.id ) ;
if ( NewGate.isActive == false ) {
LogMap.NextGates .Add ( NewGate) ;
NewGate.isActive = true ;
}
return true ;
}
}
public struct LogicGate
{
public int NT;
public int NF;
public List< Pulse> P;
public LogicType L;
public bool isActive;
public int id;
public Point Position;
public bool AddPulse( Color Colore, ref LogicMap LogMap, ref int Value)
{
P.Add ( new Pulse {
Value = Value,
Color = Colore
} ) ;
this.isActive = true ;
LogMap.NextGates .Add ( this) ;
return true ;
}
public static LogicGate VoidGate( )
{
return new LogicGate {
NT = - 1 ,
L = LogicType.None ,
NF = - 1
} ;
}
public static bool IsVoid( ref LogicGate Gate)
{
if ( Gate.NF == - 1 & Gate.NT == - 1 & Gate.L == LogicType.None & ( Gate.P == null ) )
return true ;
return false ;
}
public void DebugDrawLines( ref LogicMap LogMap, ref List< LogicGate> Gates)
{
LogicGate TrueGate = default ( LogicGate) ;
LogicGate FalseGate = default ( LogicGate) ;
Graphics g = Form1.CreateGraphics ;
if ( ( NT >= Gates.Count | NT <= - 1 ) ) {
TrueGate = LogicGate.VoidGate ( ) ;
Point PosTrue = new Point( Position.X + 20 , Position.Y - 10 ) ;
g.DrawEllipse ( Pens.WhiteSmoke , PosTrue.X - 4 , PosTrue.Y - 4 , 8 , 8 ) ;
} else {
TrueGate = Gates[ NT] ;
Point PosTrue = new Point( Position.X + 20 , Position.Y - 10 ) ;
g.DrawLine ( Pens.White , PosTrue, TrueGate.Position ) ;
}
if ( ( NF >= Gates.Count | NF <= - 1 ) ) {
Point PosFalse = new Point( Position.X + 20 , Position.Y + 10 ) ;
FalseGate = LogicGate.VoidGate ( ) ;
g.DrawEllipse ( Pens.WhiteSmoke , PosFalse.X - 4 , PosFalse.Y - 4 , 8 , 8 ) ;
} else {
FalseGate = Gates[ NF] ;
Point PosFalse = new Point( Position.X + 20 , Position.Y + 10 ) ;
g.DrawLine ( Pens.White , PosFalse, FalseGate.Position ) ;
}
}
public bool DoLogic( ref LogicMap LogMap, ref List< LogicGate> Gates)
{
LogicGate TrueGate = default ( LogicGate) ;
LogicGate FalseGate = default ( LogicGate) ;
this.isActive = false ;
if ( L == LogicType.None )
return false ;
if ( ( NT >= Gates.Count | NT <= - 1 ) )
TrueGate = LogicGate.VoidGate ( ) ;
else
TrueGate = Gates[ NT] ;
if ( ( NF >= Gates.Count | NF <= - 1 ) )
FalseGate = LogicGate.VoidGate ( ) ;
else
FalseGate = Gates[ NF] ;
return Form1.LFunc [ L] ( LogMap, this, TrueGate, FalseGate) ;
}
public void DrawDebug( )
{
dynamic G = Form1.CreateGraphics ( ) ;
G.FillRectangle ( Brushes.Red , Position.X - 20 , Position.Y - 10 , 40 , 20 ) ;
G.FillRectangle ( Brushes.Green , Position.X + 18 , Position.Y - 12 , 4 , 4 ) ;
G.FillRectangle ( Brushes.Blue , Position.X + 18 , Position.Y + 8 , 4 , 4 ) ;
}
public void DrawDebugBase( )
{
dynamic G = Form1.CreateGraphics ( ) ;
G.FillRectangle ( Brushes.Gray , Position.X - 20 , Position.Y - 10 , 40 , 20 ) ;
G.FillRectangle ( Brushes.Green , Position.X + 18 , Position.Y - 12 , 4 , 4 ) ;
G.FillRectangle ( Brushes.Blue , Position.X + 18 , Position.Y + 8 , 4 , 4 ) ;
G.DrawString ( this.id .ToString ( ) , Form1.Font , Brushes.Black , new Point( Position.X - 6 , Position.Y - 7 ) ) ;
}
}
public enum LogicType
{
MoreThan = 0 ,
LessThan = 1 ,
MoreOrEqualTo = 2 ,
LessOrEqualTo = 3 ,
EqualTo = 4 ,
NotEqualTo = 5 ,
None = 255
}
public static readonly System.Func < LogicMap, LogicGate, LogicGate, LogicGate, bool> [ ] LFunc = { ( LogicMap LM, LogicGate L, LogicGate TL, LogicGate FL) =>
{
List< Pulse> TrueList = new List< Pulse> ( ) ;
List< Pulse> FalseList = new List< Pulse> ( ) ;
foreach ( Pulse P1 in L.P ) {
int SumF = 0 ;
int SumT = 0 ;
foreach ( Pulse P2 in L.P ) {
if ( ! ( Pulse.ReferenceEquals ( P1, P2) ) ) {
if ( P1.Value >= P2.Value )
SumT += 1 ;
else
SumF += 1 ;
}
}
if ( SumT >= SumF)
TrueList.Add ( P1) ;
else
FalseList.Add ( P1) ;
}
foreach ( Pulse P in TrueList) {
Console.WriteLine ( "Pulse at Gate(" + L.id + ") Returned True" ) ;
P.MoveTo ( LM, L, TL, true ) ;
}
foreach ( Pulse P in FalseList) {
Console.WriteLine ( "Pulse at Gate(" + L.id + ") Returned False" ) ;
P.MoveTo ( LM, L, FL, false ) ;
}
return true ;
} } ;
public Form1( )
{
Load += Form1_Load;
KeyDown += Form1_KeyDown;
}
}
dXNpbmcgTWljcm9zb2Z0LlZpc3VhbEJhc2ljOwp1c2luZyBTeXN0ZW07CnVzaW5nIFN5c3RlbS5Db2xsZWN0aW9uczsKdXNpbmcgU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWM7CnVzaW5nIFN5c3RlbS5EYXRhOwp1c2luZyBTeXN0ZW0uRGlhZ25vc3RpY3M7CnB1YmxpYyBjbGFzcyBGb3JtMQp7CgoJTG9naWNNYXAgTG9naWMgPSBuZXcgTG9naWNNYXAoKTsKCXByaXZhdGUgdm9pZCBGb3JtMV9LZXlEb3duKG9iamVjdCBzZW5kZXIsIFN5c3RlbS5XaW5kb3dzLkZvcm1zLktleUV2ZW50QXJncyBlKQoJewoJCWlmIChlLktleURhdGEgPT0gS2V5cy5TcGFjZSkgewoJCQlDb25zb2xlLldyaXRlTGluZSgiLS0tLS0tLSBOZXcgU3RlcCAtLS0tLS0tLS0iKTsKCQkJTG9naWMuRG9Mb2dpYygpOwoJCX0KCX0KCglwcml2YXRlIHZvaWQgRm9ybTFfTG9hZChTeXN0ZW0uT2JqZWN0IHNlbmRlciwgU3lzdGVtLkV2ZW50QXJncyBlKQoJewoJCUxvZ2ljLkFkZEdhdGUobmV3IFBvaW50KDEwMCwgMTMwKSwgMCwgMCwgMCk7CgkJTG9naWMuQWRkR2F0ZShuZXcgUG9pbnQoMTYwLCA0MCksIDAsIDAsIDQpOwoJCUxvZ2ljLkFkZEdhdGUobmV3IFBvaW50KDIwNSwgMTA1KSwgMCwgMywgMSk7CgkJTG9naWMuQWRkR2F0ZShuZXcgUG9pbnQoNDUwLCAzNSksIDAsIDQsIDApOwoJCUxvZ2ljLkFkZEdhdGUobmV3IFBvaW50KDU5NSwgMTM1KSwgMCwgMCwgMSk7CgoJCUxvZ2ljLkFkZFB1bHNlKENvbG9yLkZyb21BcmdiKDI1NSwgMCwgMCksIDEsIDUpOwoJCUxvZ2ljLkFkZFB1bHNlKENvbG9yLkZyb21BcmdiKDI1NSwgMTI4LCAxNjIpLCAyLCA3KTsKCX0KCglwcml2YXRlIHZvaWQgRHJhd0xvZ2ljTWFwKCkKCXsKCQlHcmFwaGljcyBnID0gdGhpcy5DcmVhdGVHcmFwaGljcygpOwoKCgl9CgoJcHVibGljIGNsYXNzIExvZ2ljTWFwCgl7CgkJcHVibGljIExpc3Q8TG9naWNHYXRlPiBOZXh0R2F0ZXM7CgkJcHVibGljIExpc3Q8TG9naWNHYXRlPiBBY3RpdmVHYXRlczsKCgkJcHJpdmF0ZSBMaXN0PExvZ2ljR2F0ZT4gR2F0ZXM7CgkJcHVibGljIHZvaWQgQWRkR2F0ZShQb2ludCBQb3MsIExvZ2ljVHlwZSBMb2dpYywgaW50IFRydWVHYXRlLCBpbnQgRmFsc2VHYXRlKQoJCXsKCQkJR2F0ZXMuQWRkKG5ldyBMb2dpY0dhdGUgewoJCQkJTCA9IExvZ2ljLAoJCQkJTlQgPSBUcnVlR2F0ZSwKCQkJCU5GID0gRmFsc2VHYXRlLAoJCQkJUCA9IG5ldyBMaXN0PFB1bHNlPigpLAoJCQkJaXNBY3RpdmUgPSBmYWxzZSwKCQkJCWlkID0gR2F0ZXMuQ291bnQsCgkJCQlQb3NpdGlvbiA9IFBvcwoJCQl9KTsKCQkJQ29uc29sZS5Xcml0ZUxpbmUoIiNBZGRlZCBHYXRlKCIgKyBHYXRlcy5Db3VudCAtIDEgKyAiKTogTG9naWMoIiArIExvZ2ljICsgIiksIEZhbHNlR2F0ZSgiICsgRmFsc2VHYXRlICsgIiksIFRydWVHYXRlKCIgKyBUcnVlR2F0ZSArICIpIik7CgkJfQoKCQlwdWJsaWMgYm9vbCBBZGRQdWxzZShDb2xvciBDb2xvciwgaW50IEdhdGUsIGludCBWYWx1ZSkKCQl7CgkJCWlmIChHYXRlID49IEdhdGVzLkNvdW50IHwgR2F0ZSA8PSAtMSkKCQkJCXJldHVybiBmYWxzZTsKCQkJR2F0ZXNbR2F0ZV0uQWRkUHVsc2UoQ29sb3IsIHJlZiB0aGlzLCByZWYgVmFsdWUpOwoJCQlDb25zb2xlLldyaXRlTGluZSgiI0FkZGVkIFB1bHNlIGF0IEdhdGUoIiArIEdhdGUgKyAiKSB3aXRoIFZhbHVlKCIgKyBWYWx1ZSArICIpIik7CgkJCXJldHVybiB0cnVlOwoJCX0KCgkJcHVibGljIExvZ2ljTWFwKCkKCQl7CgkJCU5leHRHYXRlcyA9IG5ldyBMaXN0PExvZ2ljR2F0ZT4oKTsKCQkJQWN0aXZlR2F0ZXMgPSBuZXcgTGlzdDxMb2dpY0dhdGU+KCk7CgkJCUdhdGVzID0gbmV3IExpc3Q8TG9naWNHYXRlPigpOwoJCQlDb25zb2xlLldyaXRlTGluZSgiI0NyZWF0ZWQgbmV3IExvZ2ljIE1hcCIpOwoJCX0KCgoJCXB1YmxpYyBib29sIERvTG9naWMoKQoJCXsKCQkJQWN0aXZlR2F0ZXMuQ2xlYXIoKTsKCQkJLy9SZXBsYWNlIGFuZCBtYWtlIHJvb20gZm9yIG5ldyBjaGFuZ2VzLgoJCQlBY3RpdmVHYXRlcy5BZGRSYW5nZShOZXh0R2F0ZXMpOwoJCQlOZXh0R2F0ZXMuQ2xlYXIoKTsKCQkJRm9ybTEuQ3JlYXRlR3JhcGhpY3MoKS5DbGVhcihDb2xvci5CbGFjayk7CgkJCWZvcmVhY2ggKG9iamVjdCBHYXRlX2xvb3BWYXJpYWJsZSBpbiBHYXRlcykgewoJCQkJR2F0ZSA9IEdhdGVfbG9vcFZhcmlhYmxlOwoJCQkJR2F0ZS5EcmF3RGVidWdCYXNlKCk7CgkJCQlHYXRlLkRlYnVnRHJhd0xpbmVzKHRoaXMsIEdhdGVzKTsKCQkJfQoKCQkJZm9yZWFjaCAoTG9naWNHYXRlIEdhdGUgaW4gQWN0aXZlR2F0ZXMpIHsKCQkJCUdhdGUuRG9Mb2dpYyhyZWYgdGhpcywgcmVmIEdhdGVzKTsKCQkJCUdhdGUuRHJhd0RlYnVnKCk7CgkJCX0KCgkJCXJldHVybiB0cnVlOwoJCX0KCX0KCglwdWJsaWMgc3RydWN0IFB1bHNlCgl7CgkJcHVibGljIGludCBWYWx1ZTsKCQlwdWJsaWMgQ29sb3IgQ29sb3I7CgkJcHVibGljIG9iamVjdCBNb3ZlVG8ocmVmIExvZ2ljTWFwIExvZ01hcCwgcmVmIExvZ2ljR2F0ZSBPbGRHYXRlLCByZWYgTG9naWNHYXRlIE5ld0dhdGUsIGJvb2wgU3RhdGUpCgkJewoJCQlPbGRHYXRlLlAuUmVtb3ZlKHRoaXMpOwoKCQkJR3JhcGhpY3MgRyA9IEZvcm0xLkNyZWF0ZUdyYXBoaWNzKCk7CgkJCVBvaW50IFBvc2l0aW9uID0gZGVmYXVsdChQb2ludCk7CgoJCQlpZiAoTG9naWNHYXRlLklzVm9pZChyZWYgTmV3R2F0ZSkpIHsKCQkJCUNvbnNvbGUuV3JpdGVMaW5lKCJTdG9wcGVkIGF0IEdhdGU6IiArIE9sZEdhdGUuaWQpOwoKCQkJCWlmIChTdGF0ZSA9PSBmYWxzZSkKCQkJCQlQb3NpdGlvbiA9IG5ldyBQb2ludChPbGRHYXRlLlBvc2l0aW9uLlggKyAyMCwgT2xkR2F0ZS5Qb3NpdGlvbi5ZICsgMTApOwoJCQkJZWxzZQoJCQkJCVBvc2l0aW9uID0gbmV3IFBvaW50KE9sZEdhdGUuUG9zaXRpb24uWCArIDIwLCBPbGRHYXRlLlBvc2l0aW9uLlkgLSAxMCk7CgkJCQlHLkRyYXdFbGxpcHNlKG5ldyBQZW4odGhpcy5Db2xvciksIFBvc2l0aW9uLlggLSA3LCBQb3NpdGlvbi5ZIC0gNywgMTQsIDE0KTsKCQkJCXJldHVybiBmYWxzZTsKCQkJfQoJCQlOZXdHYXRlLlAuQWRkKHRoaXMpOwoKCQkJaWYgKFN0YXRlID09IGZhbHNlKQoJCQkJUG9zaXRpb24gPSBuZXcgUG9pbnQoT2xkR2F0ZS5Qb3NpdGlvbi5YICsgMjAsIE9sZEdhdGUuUG9zaXRpb24uWSArIDEwKTsKCQkJZWxzZQoJCQkJUG9zaXRpb24gPSBuZXcgUG9pbnQoT2xkR2F0ZS5Qb3NpdGlvbi5YICsgMjAsIE9sZEdhdGUuUG9zaXRpb24uWSAtIDEwKTsKCQkJRy5EcmF3TGluZShuZXcgUGVuKHRoaXMuQ29sb3IsIHRoaXMuVmFsdWUpLCBQb3NpdGlvbiwgTmV3R2F0ZS5Qb3NpdGlvbik7CgoJCQlDb25zb2xlLldyaXRlTGluZSgiTW92ZWQgZnJvbSB0byAiICsgT2xkR2F0ZS5pZCArICIgdG8gR2F0ZTogIiArIE5ld0dhdGUuaWQpOwoJCQlpZiAoTmV3R2F0ZS5pc0FjdGl2ZSA9PSBmYWxzZSkgewoJCQkJTG9nTWFwLk5leHRHYXRlcy5BZGQoTmV3R2F0ZSk7CgkJCQlOZXdHYXRlLmlzQWN0aXZlID0gdHJ1ZTsKCQkJfQoJCQlyZXR1cm4gdHJ1ZTsKCQl9Cgl9CgoJcHVibGljIHN0cnVjdCBMb2dpY0dhdGUKCXsKCQlwdWJsaWMgaW50IE5UOwoJCXB1YmxpYyBpbnQgTkY7CgkJcHVibGljIExpc3Q8UHVsc2U+IFA7CgkJcHVibGljIExvZ2ljVHlwZSBMOwoJCXB1YmxpYyBib29sIGlzQWN0aXZlOwoJCXB1YmxpYyBpbnQgaWQ7CgoJCXB1YmxpYyBQb2ludCBQb3NpdGlvbjsKCQlwdWJsaWMgYm9vbCBBZGRQdWxzZShDb2xvciBDb2xvcmUsIHJlZiBMb2dpY01hcCBMb2dNYXAsIHJlZiBpbnQgVmFsdWUpCgkJewoJCQlQLkFkZChuZXcgUHVsc2UgewoJCQkJVmFsdWUgPSBWYWx1ZSwKCQkJCUNvbG9yID0gQ29sb3JlCgkJCX0pOwoJCQl0aGlzLmlzQWN0aXZlID0gdHJ1ZTsKCQkJTG9nTWFwLk5leHRHYXRlcy5BZGQodGhpcyk7CgkJCXJldHVybiB0cnVlOwoJCX0KCgkJcHVibGljIHN0YXRpYyBMb2dpY0dhdGUgVm9pZEdhdGUoKQoJCXsKCQkJcmV0dXJuIG5ldyBMb2dpY0dhdGUgewoJCQkJTlQgPSAtMSwKCQkJCUwgPSBMb2dpY1R5cGUuTm9uZSwKCQkJCU5GID0gLTEKCQkJfTsKCQl9CgoJCXB1YmxpYyBzdGF0aWMgYm9vbCBJc1ZvaWQocmVmIExvZ2ljR2F0ZSBHYXRlKQoJCXsKCQkJaWYgKEdhdGUuTkYgPT0gLTEgJiBHYXRlLk5UID09IC0xICYgR2F0ZS5MID09IExvZ2ljVHlwZS5Ob25lICYgKEdhdGUuUCA9PSBudWxsKSkKCQkJCXJldHVybiB0cnVlOwoJCQlyZXR1cm4gZmFsc2U7CgkJfQoKCQlwdWJsaWMgdm9pZCBEZWJ1Z0RyYXdMaW5lcyhyZWYgTG9naWNNYXAgTG9nTWFwLCByZWYgTGlzdDxMb2dpY0dhdGU+IEdhdGVzKQoJCXsKCQkJTG9naWNHYXRlIFRydWVHYXRlID0gZGVmYXVsdChMb2dpY0dhdGUpOwoJCQlMb2dpY0dhdGUgRmFsc2VHYXRlID0gZGVmYXVsdChMb2dpY0dhdGUpOwoJCQlHcmFwaGljcyBnID0gRm9ybTEuQ3JlYXRlR3JhcGhpY3M7CgoJCQlpZiAoKE5UID49IEdhdGVzLkNvdW50IHwgTlQgPD0gLTEpKSB7CgkJCQlUcnVlR2F0ZSA9IExvZ2ljR2F0ZS5Wb2lkR2F0ZSgpOwoJCQkJUG9pbnQgUG9zVHJ1ZSA9IG5ldyBQb2ludChQb3NpdGlvbi5YICsgMjAsIFBvc2l0aW9uLlkgLSAxMCk7CgkJCQlnLkRyYXdFbGxpcHNlKFBlbnMuV2hpdGVTbW9rZSwgUG9zVHJ1ZS5YIC0gNCwgUG9zVHJ1ZS5ZIC0gNCwgOCwgOCk7CgkJCX0gZWxzZSB7CgkJCQlUcnVlR2F0ZSA9IEdhdGVzW05UXTsKCQkJCVBvaW50IFBvc1RydWUgPSBuZXcgUG9pbnQoUG9zaXRpb24uWCArIDIwLCBQb3NpdGlvbi5ZIC0gMTApOwoJCQkJZy5EcmF3TGluZShQZW5zLldoaXRlLCBQb3NUcnVlLCBUcnVlR2F0ZS5Qb3NpdGlvbik7CgoJCQl9CgkJCWlmICgoTkYgPj0gR2F0ZXMuQ291bnQgfCBORiA8PSAtMSkpIHsKCQkJCVBvaW50IFBvc0ZhbHNlID0gbmV3IFBvaW50KFBvc2l0aW9uLlggKyAyMCwgUG9zaXRpb24uWSArIDEwKTsKCQkJCUZhbHNlR2F0ZSA9IExvZ2ljR2F0ZS5Wb2lkR2F0ZSgpOwoJCQkJZy5EcmF3RWxsaXBzZShQZW5zLldoaXRlU21va2UsIFBvc0ZhbHNlLlggLSA0LCBQb3NGYWxzZS5ZIC0gNCwgOCwgOCk7CgkJCX0gZWxzZSB7CgkJCQlGYWxzZUdhdGUgPSBHYXRlc1tORl07CgkJCQlQb2ludCBQb3NGYWxzZSA9IG5ldyBQb2ludChQb3NpdGlvbi5YICsgMjAsIFBvc2l0aW9uLlkgKyAxMCk7CgkJCQlnLkRyYXdMaW5lKFBlbnMuV2hpdGUsIFBvc0ZhbHNlLCBGYWxzZUdhdGUuUG9zaXRpb24pOwoKCQkJfQoJCX0KCgoJCXB1YmxpYyBib29sIERvTG9naWMocmVmIExvZ2ljTWFwIExvZ01hcCwgcmVmIExpc3Q8TG9naWNHYXRlPiBHYXRlcykKCQl7CgkJCUxvZ2ljR2F0ZSBUcnVlR2F0ZSA9IGRlZmF1bHQoTG9naWNHYXRlKTsKCQkJTG9naWNHYXRlIEZhbHNlR2F0ZSA9IGRlZmF1bHQoTG9naWNHYXRlKTsKCQkJdGhpcy5pc0FjdGl2ZSA9IGZhbHNlOwoJCQlpZiAoTCA9PSBMb2dpY1R5cGUuTm9uZSkKCQkJCXJldHVybiBmYWxzZTsKCQkJaWYgKChOVCA+PSBHYXRlcy5Db3VudCB8IE5UIDw9IC0xKSkKCQkJCVRydWVHYXRlID0gTG9naWNHYXRlLlZvaWRHYXRlKCk7CgkJCWVsc2UKCQkJCVRydWVHYXRlID0gR2F0ZXNbTlRdOwoJCQlpZiAoKE5GID49IEdhdGVzLkNvdW50IHwgTkYgPD0gLTEpKQoJCQkJRmFsc2VHYXRlID0gTG9naWNHYXRlLlZvaWRHYXRlKCk7CgkJCWVsc2UKCQkJCUZhbHNlR2F0ZSA9IEdhdGVzW05GXTsKCQkJcmV0dXJuIEZvcm0xLkxGdW5jW0xdKExvZ01hcCwgdGhpcywgVHJ1ZUdhdGUsIEZhbHNlR2F0ZSk7CgkJfQoKCQlwdWJsaWMgdm9pZCBEcmF3RGVidWcoKQoJCXsKCQkJZHluYW1pYyBHID0gRm9ybTEuQ3JlYXRlR3JhcGhpY3MoKTsKCQkJRy5GaWxsUmVjdGFuZ2xlKEJydXNoZXMuUmVkLCBQb3NpdGlvbi5YIC0gMjAsIFBvc2l0aW9uLlkgLSAxMCwgNDAsIDIwKTsKCQkJRy5GaWxsUmVjdGFuZ2xlKEJydXNoZXMuR3JlZW4sIFBvc2l0aW9uLlggKyAxOCwgUG9zaXRpb24uWSAtIDEyLCA0LCA0KTsKCQkJRy5GaWxsUmVjdGFuZ2xlKEJydXNoZXMuQmx1ZSwgUG9zaXRpb24uWCArIDE4LCBQb3NpdGlvbi5ZICsgOCwgNCwgNCk7CgkJfQoKCQlwdWJsaWMgdm9pZCBEcmF3RGVidWdCYXNlKCkKCQl7CgkJCWR5bmFtaWMgRyA9IEZvcm0xLkNyZWF0ZUdyYXBoaWNzKCk7CgkJCUcuRmlsbFJlY3RhbmdsZShCcnVzaGVzLkdyYXksIFBvc2l0aW9uLlggLSAyMCwgUG9zaXRpb24uWSAtIDEwLCA0MCwgMjApOwoJCQlHLkZpbGxSZWN0YW5nbGUoQnJ1c2hlcy5HcmVlbiwgUG9zaXRpb24uWCArIDE4LCBQb3NpdGlvbi5ZIC0gMTIsIDQsIDQpOwoJCQlHLkZpbGxSZWN0YW5nbGUoQnJ1c2hlcy5CbHVlLCBQb3NpdGlvbi5YICsgMTgsIFBvc2l0aW9uLlkgKyA4LCA0LCA0KTsKCQkJRy5EcmF3U3RyaW5nKHRoaXMuaWQuVG9TdHJpbmcoKSwgRm9ybTEuRm9udCwgQnJ1c2hlcy5CbGFjaywgbmV3IFBvaW50KFBvc2l0aW9uLlggLSA2LCBQb3NpdGlvbi5ZIC0gNykpOwoJCX0KCX0KCglwdWJsaWMgZW51bSBMb2dpY1R5cGUKCXsKCQlNb3JlVGhhbiA9IDAsCgkJTGVzc1RoYW4gPSAxLAoJCU1vcmVPckVxdWFsVG8gPSAyLAoJCUxlc3NPckVxdWFsVG8gPSAzLAoJCUVxdWFsVG8gPSA0LAoJCU5vdEVxdWFsVG8gPSA1LAoJCU5vbmUgPSAyNTUKCX0KCglwdWJsaWMgc3RhdGljIHJlYWRvbmx5IFN5c3RlbS5GdW5jPExvZ2ljTWFwLCBMb2dpY0dhdGUsIExvZ2ljR2F0ZSwgTG9naWNHYXRlLCBib29sPltdIExGdW5jID0geyAoTG9naWNNYXAgTE0sIExvZ2ljR2F0ZSBMLCBMb2dpY0dhdGUgVEwsIExvZ2ljR2F0ZSBGTCkgPT4KCXsKCQlMaXN0PFB1bHNlPiBUcnVlTGlzdCA9IG5ldyBMaXN0PFB1bHNlPigpOwoJCUxpc3Q8UHVsc2U+IEZhbHNlTGlzdCA9IG5ldyBMaXN0PFB1bHNlPigpOwoJCWZvcmVhY2ggKFB1bHNlIFAxIGluIEwuUCkgewoJCQlpbnQgU3VtRiA9IDA7CgkJCWludCBTdW1UID0gMDsKCQkJZm9yZWFjaCAoUHVsc2UgUDIgaW4gTC5QKSB7CgkJCQlpZiAoIShQdWxzZS5SZWZlcmVuY2VFcXVhbHMoUDEsIFAyKSkpIHsKCQkJCQlpZiAoUDEuVmFsdWUgPj0gUDIuVmFsdWUpCgkJCQkJCVN1bVQgKz0gMTsKCQkJCQllbHNlCgkJCQkJCVN1bUYgKz0gMTsKCQkJCX0KCQkJfQoJCQlpZiAoU3VtVCA+PSBTdW1GKQoJCQkJVHJ1ZUxpc3QuQWRkKFAxKTsKCQkJZWxzZQoJCQkJRmFsc2VMaXN0LkFkZChQMSk7CgkJfQoJCWZvcmVhY2ggKFB1bHNlIFAgaW4gVHJ1ZUxpc3QpIHsKCQkJQ29uc29sZS5Xcml0ZUxpbmUoIlB1bHNlIGF0IEdhdGUoIiArIEwuaWQgKyAiKSBSZXR1cm5lZCBUcnVlIik7CgkJCVAuTW92ZVRvKExNLCBMLCBUTCwgdHJ1ZSk7CgkJfQoJCWZvcmVhY2ggKFB1bHNlIFAgaW4gRmFsc2VMaXN0KSB7CgkJCUNvbnNvbGUuV3JpdGVMaW5lKCJQdWxzZSBhdCBHYXRlKCIgKyBMLmlkICsgIikgUmV0dXJuZWQgRmFsc2UiKTsKCQkJUC5Nb3ZlVG8oTE0sIEwsIEZMLCBmYWxzZSk7CgkJfQoJCXJldHVybiB0cnVlOwoKCX0gfTsKCXB1YmxpYyBGb3JtMSgpCgl7CgkJTG9hZCArPSBGb3JtMV9Mb2FkOwoJCUtleURvd24gKz0gRm9ybTFfS2V5RG93bjsKCX0KCn0K