declare
@DateBegin datetime,
@DateEnd datetime,
@GLCode varchar(250),
@Service varchar(250),
@Location varchar(250),
@Employee int;
set @DateBegin = :DateBegin;
set @DateEnd = :DateEnd;
set @Location = :Location;
set @Service = :Service;
set @GLCode = :GLCode;
set @Employee = :Employee;
declare @header table (sort int, description varchar(50));
insert into @header (sort, description)
select 100, 'Location'
union all
select 200, 'Date'
union all
select 300, 'Sub-Total Sales'
union all
select 400, '*Services'
union all
select 500, '*GL Codes (Sales)'
union all
select 600, '*GL Codes (Discounts)'
union all
select 700, 'Discounts'
union all
select 800, 'Taxes'
union all
select 999, 'Total Sales';
print '@dates';
declare @dates table (date datetime, sort int);
insert into @dates
select dateadd(day, number, @DateBegin), number + 1
from master..spt_values
where type = 'P'
and number between 0 and datediff(day, @DateBegin, @DateEnd)
union all
select null, 99999;
print '@services';
declare @services table (code varchar(50), sort int);
insert into @services (code, sort)
select
s.HistoryCode,
row_number() over (order by min(s.HistorySorting), s.HistoryCode)
from (
select distinct
s.HistoryCode,
s.HistorySorting
from dbo.fnSplit(@Service) f
inner join Service s on s.HistoryCode = ltrim(f.value)
) s
group by s.HistoryCode
;
print '@glcodes';
declare @glcodes table (id int, code varchar(50), name varchar(50), coef int, sort int);
insert into @glcodes
select
p.ID, p.Code, p.Name,
case p.PaidOut when 1 then -1 else 1 end,
row_number() over (order by p.Code)
from dbo.fnSplit(@GLCode) s
inner join PaidOutCode p on ltrim(s.value) = p.Code;
print '@locations';
declare @locations table (id int, code varchar(10), name varchar(50), sort int);
insert into @locations
select
ID,
code,
Name,
row_number() over (order by Type, code)
from (
select distinct
l.ID,
l.Type,
case l.Type when 0 then 'O-' else 'F-' end + right('0000' + l.Code, 4) as code,
l.Name
from dbo.fnSplit(@Location) s
inner join Location l
on s.Value = 'o' and l.Type = 0 and l.Active = 1 and cast(l.Code as int) < 9000
or s.Value = 'f' and l.Type = 1 and l.Active = 1 and cast(l.Code as int) < 9000
or s.Value not in ('o', 'f') and cast(l.ID as varchar) = ltrim(s.Value)
inner join (
select [Object Id2] as Location
from Availability
where [Object Identification1] = 4
and [Object Identification2] = 8
and [Object Id1] = @Employee
) a on a.Location = l.ID
) s
union all
select null, null, null, 0
union all
select null, null, null, 99999;
print '@orders';
declare @orders table (
ID int,
Location int,
Sale money,
Discount money,
Tax money,
Date datetime
);
insert into @orders (ID, Location, Sale, Discount, Tax, Date)
select o.ID, o.Location, o.Sale, o.Discount, o.Tax, dateadd(day, datediff(day, 0, DateTimeBegin), 0)
from [Order] o
inner join @locations l on o.Location = l.ID
/*inner join @dates d on o.DateTimeBegin >= d.Date and o.DateTimeBegin < d.Date + 1*/
where o.Status = 0
and o.DateTimeBegin >= @DateBegin
and o.DateTimeBegin < @DateEnd + 1;
print 'TempList';
delete from TempList where spid = @@spid;
insert into TempList (spid, val)
select @@spid, o.ID
from @orders o
inner join [Order Item] oi on o.ID = oi.[Order]
inner join Discount d on oi.[Object Identification] = 2 and oi.[Object ID] = d.ID
inner join @glcodes g on d.GLCode = g.ID and d.ReportAsPaidOut = 1;
print '#ReportSalesAnalysis_CalculatedOrders';
if object_id('tempdb..#ReportSalesAnalysis_CalculatedOrders') is not null drop table #ReportSalesAnalysis_CalculatedOrders;
select *
into #ReportSalesAnalysis_CalculatedOrders
from dbo.fnCalculateMoneyMultiple(0)
print '@glcodesdiscounts';
declare @glcodesdiscounts table (glcodesort int, locationsort int, datesort int, Amount money);
insert into @glcodesdiscounts (glcodesort, locationsort, datesort, Amount)
select
s.glcodesort,
s.locationsort,
d.sort,
sum(s.Amount)
from (
select
glcodesort = g.sort,
locationsort = l.sort,
Date = dateadd(day, datediff(day, 0, o.DateTimeBegin), 0),
Amount = round(case oi.Quantity
when 0 then oi.Price * (c.SubTotalPercentable + d.UpdateTax * c.SalesTaxPercentable) / 100
else oi.Price
end, 2)
from #ReportSalesAnalysis_CalculatedOrders c
inner join [Order] o on c.[Order] = o.ID
inner join @locations l on o.Location = l.ID
inner join [Order Item] oi on c.[Order] = oi.[Order] and oi.[Object Identification] = 2
inner join Discount d on oi.[Object ID] = d.ID and d.ReportAsPaidOut = 1
inner join @glcodes g on d.GLCode = g.ID and d.ReportAsPaidOut = 1
) s
inner join @dates d on s.Date = d.date
group by
s.glcodesort,
s.locationsort,
d.sort;
insert into @orders (Location, Date, Discount)
select l.ID, d.Date, -g.Amount
from @glcodesdiscounts g
inner join @locations l on g.locationsort = l.sort
inner join @dates d on g.datesort = d.sort;
insert into @glcodesdiscounts (glcodesort, locationsort, datesort, Amount)
select glcodesort, locationsort, 99999, sum(Amount) from @glcodesdiscounts group by glcodesort, locationsort
union all
select glcodesort, 99999, 99999, sum(Amount) from @glcodesdiscounts group by glcodesort
union all
select 999, locationsort, datesort, sum(Amount) from @glcodesdiscounts group by locationsort, datesort
union all
select 999, locationsort, 99999, sum(Amount) from @glcodesdiscounts group by locationsort
union all
select 999, 99999, 99999, sum(Amount) from @glcodesdiscounts group by case datesort when 0 then 0 end;
print '@glcodessales';
declare @glcodessales table (glcodesort int, locationsort int, datesort int, Amount money);
insert into @glcodessales (glcodesort, locationsort, datesort, Amount)
select
s.glcodesort,
s.locationsort,
d.sort,
sum(Amount)
from (
select
glcodesort = g.sort,
locationsort = l.sort,
Date = dateadd(day, datediff(day, 0, p.DateTime), 0),
Amount = p.Amount * g.coef
from PaidOut p
inner join @glcodes g on p.PaidOutCode = g.id
inner join @locations l on p.Location = l.ID
where p.DateTime >= @DateBegin
and p.DateTime < @DateEnd + 1
) s
inner join @dates d on s.Date = d.date
group by
s.glcodesort,
s.locationsort,
d.sort;
insert into @glcodessales (glcodesort, locationsort, datesort, Amount)
select glcodesort, locationsort, 99999, sum(Amount) from @glcodessales group by glcodesort, locationsort
union all
select glcodesort, 99999, 99999, sum(Amount) from @glcodessales group by glcodesort
union all
select 999, locationsort, datesort, sum(Amount) from @glcodessales group by locationsort, datesort
union all
select 999, locationsort, 99999, sum(Amount) from @glcodessales group by locationsort
union all
select 999, 99999, 99999, sum(Amount) from @glcodessales group by case datesort when 0 then 0 end;
print '@servicemoney';
declare @servicemoney table (servicesort int, locationsort int, datesort int, Amount money);
insert into @servicemoney (servicesort, locationsort, datesort, Amount)
select
s.sort,
l.sort,
d.sort,
Amount = sum(ot.Price)
from [OIL STOP REPORT].[OIL STOP REPORT].dbo.OperativeTotals ot
inner join [OIL STOP REPORT].[OIL STOP REPORT].dbo.OperativeTotalsItemsDescription otid
on ot.Object = otid.Object and ot.ObjectID = otid.ObjectID
inner join @services s on otid.HistoryCode = s.code
inner join @dates d on ot.Date = d.date
inner join @locations l on ot.Location = l.id
group by
s.sort,
l.sort,
d.sort;
insert into @orders (Location, Date, Sale)
select l.ID, d.Date, -s.Amount
from @servicemoney s
inner join @locations l on s.locationsort = l.sort
inner join @dates d on s.datesort = d.sort;
insert into @servicemoney (servicesort, locationsort, datesort, Amount)
select servicesort, locationsort, 99999, sum(Amount) from @servicemoney group by servicesort, locationsort
union all
select servicesort, 99999, 99999, sum(Amount) from @servicemoney group by servicesort
union all
select 999, locationsort, datesort, sum(Amount) from @servicemoney group by locationsort, datesort
union all
select 999, locationsort, 99999, sum(Amount) from @servicemoney group by locationsort
union all
select 999, 99999, 99999, sum(Amount) from @servicemoney group by case datesort when 0 then 0 end;
print '@ordermoney';
declare @ordermoney table (locationsort int, datesort int, Sale money, Discount money, Tax money);
insert into @ordermoney (locationsort, datesort, Sale, Discount, Tax)
select
l.sort,
d.sort,
Sale = sum(Sale),
Discount = sum(Discount),
Tax = sum(Tax)
from @orders o
inner join @locations l on o.Location = l.ID
inner join @dates d on o.Date = d.date
group by
l.sort,
d.sort;
insert into @ordermoney (locationsort, datesort, Sale, Discount, Tax)
select locationsort, 99999, sum(Sale), sum(Discount), sum(Tax) from @ordermoney group by locationsort
union all
select 99999, 99999, sum(Sale), sum(Discount), sum(Tax) from @ordermoney
union all
select 0, 99999, null, null, null;
if not exists (select * from @servicemoney)
delete from @header where sort = 400;
if not exists (select * from @glcodessales)
delete from @header where sort = 500;
if not exists (select * from @glcodesdiscounts)
delete from @header where sort = 600;
if object_id('tempdb..#ReportSalesAnalysis') is not null drop table #ReportSalesAnalysis;
select
ld.locationsort,
ld.datesort,
columnsort = h.sort + case h.sort
when 400 then ss.sort
when 500 then ggs.sort
when 600 then ggd.sort
else 0
end,
Amount =
case h.sort
when 300 then isnull(o.Sale, 0)
when 400 then isnull(s.Amount, 0)
when 500 then isnull(gs.Amount, 0)
when 600 then -isnull(gd.Amount, 0)
when 700 then -isnull(o.Discount, 0)
when 800 then isnull(o.Tax, 0)
when 999 then isnull(o.Sale, 0) + isnull(s.Amount, 0) + isnull(gs.Amount, 0) - isnull(gd.Amount, 0) - isnull(o.Discount, 0) + isnull(o.Tax, 0)
end,
Caption =
case h.sort
when 100 then case ll.sort when 0 then h.description else case dd.sort when 99999 then 'Total' else ll.code end end
when 200 then case ll.sort when 0 then h.description else convert(varchar, dd.date, 101) end
when 400 then ss.code
when 500 then ggs.code + ' ' + ggs.name
when 600 then ggd.code + ' (Discounts)'
else h.description
end
into #ReportSalesAnalysis
from (select distinct locationsort from @ordermoney) l
inner join (select distinct locationsort, datesort from @ordermoney) ld on l.locationsort = ld.locationsort
inner join @locations ll on l.locationsort = ll.sort
inner join @dates dd on ld.datesort = dd.sort
cross join @header h
left join @ordermoney o on h.sort in (300, 700, 800, 999)
and ld.locationsort = o.locationsort
and ld.datesort = o.datesort
left join (select distinct t.*, m.servicesort from @servicemoney m left join @services t on m.servicesort = t.sort) ss
on h.sort = ss.servicesort or (h.sort = 400 and ss.servicesort < 100)
left join @servicemoney s on ss.servicesort = s.servicesort
and ld.locationsort = s.locationsort -- this line produces the error
-- the error is:
-- The multi-part identifier "ld.locationsort" could not be bound
and ld.datesort = s.datesort
left join (select distinct t.*, m.glcodesort from @glcodessales m left join @glcodes t on m.glcodesort = t.sort) ggs
on h.sort = ggs.glcodesort or (h.sort = 500 and ggs.glcodesort < 100)
left join @glcodessales gs on ggs.glcodesort = gs.glcodesort
and ld.locationsort = gs.locationsort
and ld.datesort = gs.datesort
left join (select distinct t.*, m.glcodesort from @glcodesdiscounts m left join @glcodes t on m.glcodesort = t.sort) ggd
on h.sort = ggd.glcodesort or (h.sort = 600 and ggd.glcodesort < 100)
left join @glcodesdiscounts gd on ggd.glcodesort = gd.glcodesort
and ld.locationsort = gd.locationsort
and ld.datesort = gd.datesort;
select
*, (select count(distinct columnsort) from #ReportSalesAnalysis) as ColumnCnt
from #ReportSalesAnalysis
order by
ld.locationsort,
ld.datesort,
columnsort;
ZGVjbGFyZQogIEBEYXRlQmVnaW4gZGF0ZXRpbWUsCiAgQERhdGVFbmQgZGF0ZXRpbWUsCiAgQEdMQ29kZSB2YXJjaGFyKDI1MCksCiAgQFNlcnZpY2UgdmFyY2hhcigyNTApLAogIEBMb2NhdGlvbiB2YXJjaGFyKDI1MCksCiAgQEVtcGxveWVlIGludDsKCnNldCBARGF0ZUJlZ2luID0gOkRhdGVCZWdpbjsKc2V0IEBEYXRlRW5kID0gOkRhdGVFbmQ7CnNldCBATG9jYXRpb24gPSA6TG9jYXRpb247CnNldCBAU2VydmljZSA9IDpTZXJ2aWNlOwpzZXQgQEdMQ29kZSA9IDpHTENvZGU7CnNldCBARW1wbG95ZWUgPSA6RW1wbG95ZWU7CgpkZWNsYXJlIEBoZWFkZXIgdGFibGUgKHNvcnQgaW50LCBkZXNjcmlwdGlvbiB2YXJjaGFyKDUwKSk7Cmluc2VydCBpbnRvIEBoZWFkZXIgKHNvcnQsIGRlc2NyaXB0aW9uKQpzZWxlY3QgMTAwLCAnTG9jYXRpb24nCnVuaW9uIGFsbApzZWxlY3QgMjAwLCAnRGF0ZScKdW5pb24gYWxsCnNlbGVjdCAzMDAsICdTdWItVG90YWwgU2FsZXMnCnVuaW9uIGFsbApzZWxlY3QgNDAwLCAnKlNlcnZpY2VzJwp1bmlvbiBhbGwKc2VsZWN0IDUwMCwgJypHTCBDb2RlcyAoU2FsZXMpJwp1bmlvbiBhbGwKc2VsZWN0IDYwMCwgJypHTCBDb2RlcyAoRGlzY291bnRzKScKdW5pb24gYWxsCnNlbGVjdCA3MDAsICdEaXNjb3VudHMnCnVuaW9uIGFsbApzZWxlY3QgODAwLCAnVGF4ZXMnCnVuaW9uIGFsbApzZWxlY3QgOTk5LCAnVG90YWwgU2FsZXMnOwoKcHJpbnQgJ0BkYXRlcyc7CmRlY2xhcmUgQGRhdGVzIHRhYmxlIChkYXRlIGRhdGV0aW1lLCBzb3J0IGludCk7Cmluc2VydCBpbnRvIEBkYXRlcwpzZWxlY3QgZGF0ZWFkZChkYXksIG51bWJlciwgQERhdGVCZWdpbiksIG51bWJlciArIDEKZnJvbSBtYXN0ZXIuLnNwdF92YWx1ZXMKd2hlcmUgdHlwZSA9ICdQJwogIGFuZCBudW1iZXIgYmV0d2VlbiAwIGFuZCBkYXRlZGlmZihkYXksIEBEYXRlQmVnaW4sIEBEYXRlRW5kKQp1bmlvbiBhbGwKc2VsZWN0IG51bGwsIDk5OTk5OwoKcHJpbnQgJ0BzZXJ2aWNlcyc7CmRlY2xhcmUgQHNlcnZpY2VzIHRhYmxlIChjb2RlIHZhcmNoYXIoNTApLCBzb3J0IGludCk7Cmluc2VydCBpbnRvIEBzZXJ2aWNlcyAoY29kZSwgc29ydCkKc2VsZWN0CiAgcy5IaXN0b3J5Q29kZSwKICByb3dfbnVtYmVyKCkgb3ZlciAob3JkZXIgYnkgbWluKHMuSGlzdG9yeVNvcnRpbmcpLCBzLkhpc3RvcnlDb2RlKQpmcm9tICgKICBzZWxlY3QgZGlzdGluY3QKICAgIHMuSGlzdG9yeUNvZGUsCiAgICBzLkhpc3RvcnlTb3J0aW5nCiAgZnJvbSBkYm8uZm5TcGxpdChAU2VydmljZSkgZgogICAgaW5uZXIgam9pbiBTZXJ2aWNlIHMgb24gcy5IaXN0b3J5Q29kZSA9IGx0cmltKGYudmFsdWUpCikgcwpncm91cCBieSBzLkhpc3RvcnlDb2RlCjsKCnByaW50ICdAZ2xjb2Rlcyc7CmRlY2xhcmUgQGdsY29kZXMgdGFibGUgKGlkIGludCwgY29kZSB2YXJjaGFyKDUwKSwgbmFtZSB2YXJjaGFyKDUwKSwgY29lZiBpbnQsIHNvcnQgaW50KTsKaW5zZXJ0IGludG8gQGdsY29kZXMKc2VsZWN0CiAgcC5JRCwgcC5Db2RlLCBwLk5hbWUsCiAgY2FzZSBwLlBhaWRPdXQgd2hlbiAxIHRoZW4gLTEgZWxzZSAxIGVuZCwKICByb3dfbnVtYmVyKCkgb3ZlciAob3JkZXIgYnkgcC5Db2RlKQpmcm9tIGRiby5mblNwbGl0KEBHTENvZGUpIHMKICBpbm5lciBqb2luIFBhaWRPdXRDb2RlIHAgb24gbHRyaW0ocy52YWx1ZSkgPSBwLkNvZGU7CgpwcmludCAnQGxvY2F0aW9ucyc7CmRlY2xhcmUgQGxvY2F0aW9ucyB0YWJsZSAoaWQgaW50LCBjb2RlIHZhcmNoYXIoMTApLCBuYW1lIHZhcmNoYXIoNTApLCBzb3J0IGludCk7Cmluc2VydCBpbnRvIEBsb2NhdGlvbnMKc2VsZWN0CiAgSUQsCiAgY29kZSwKICBOYW1lLAogIHJvd19udW1iZXIoKSBvdmVyIChvcmRlciBieSBUeXBlLCBjb2RlKQpmcm9tICgKICBzZWxlY3QgZGlzdGluY3QKICAgIGwuSUQsCiAgICBsLlR5cGUsCiAgICBjYXNlIGwuVHlwZSB3aGVuIDAgdGhlbiAnTy0nIGVsc2UgJ0YtJyBlbmQgKyByaWdodCgnMDAwMCcgKyBsLkNvZGUsIDQpIGFzIGNvZGUsCiAgICBsLk5hbWUKICBmcm9tIGRiby5mblNwbGl0KEBMb2NhdGlvbikgcwogICAgaW5uZXIgam9pbiBMb2NhdGlvbiBsCiAgICAgIG9uIHMuVmFsdWUgPSAnbycgYW5kIGwuVHlwZSA9IDAgYW5kIGwuQWN0aXZlID0gMSBhbmQgY2FzdChsLkNvZGUgYXMgaW50KSA8IDkwMDAKICAgICAgb3Igcy5WYWx1ZSA9ICdmJyBhbmQgbC5UeXBlID0gMSBhbmQgbC5BY3RpdmUgPSAxIGFuZCBjYXN0KGwuQ29kZSBhcyBpbnQpIDwgOTAwMAogICAgICBvciBzLlZhbHVlIG5vdCBpbiAoJ28nLCAnZicpIGFuZCBjYXN0KGwuSUQgYXMgdmFyY2hhcikgPSBsdHJpbShzLlZhbHVlKQogICAgaW5uZXIgam9pbiAoCiAgICAgIHNlbGVjdCBbT2JqZWN0IElkMl0gYXMgTG9jYXRpb24KICAgICAgZnJvbSBBdmFpbGFiaWxpdHkKICAgICAgd2hlcmUgW09iamVjdCBJZGVudGlmaWNhdGlvbjFdID0gNAogICAgICAgIGFuZCBbT2JqZWN0IElkZW50aWZpY2F0aW9uMl0gPSA4CiAgICAgICAgYW5kIFtPYmplY3QgSWQxXSA9IEBFbXBsb3llZQogICAgKSBhIG9uIGEuTG9jYXRpb24gPSBsLklECikgcwp1bmlvbiBhbGwKc2VsZWN0IG51bGwsIG51bGwsIG51bGwsIDAKdW5pb24gYWxsCnNlbGVjdCBudWxsLCBudWxsLCBudWxsLCA5OTk5OTsKCnByaW50ICdAb3JkZXJzJzsKZGVjbGFyZSBAb3JkZXJzIHRhYmxlICgKICBJRCBpbnQsCiAgTG9jYXRpb24gaW50LAogIFNhbGUgbW9uZXksCiAgRGlzY291bnQgbW9uZXksCiAgVGF4IG1vbmV5LAogIERhdGUgZGF0ZXRpbWUKKTsKaW5zZXJ0IGludG8gQG9yZGVycyAoSUQsIExvY2F0aW9uLCBTYWxlLCBEaXNjb3VudCwgVGF4LCBEYXRlKQpzZWxlY3Qgby5JRCwgby5Mb2NhdGlvbiwgby5TYWxlLCBvLkRpc2NvdW50LCBvLlRheCwgZGF0ZWFkZChkYXksIGRhdGVkaWZmKGRheSwgMCwgRGF0ZVRpbWVCZWdpbiksIDApCmZyb20gW09yZGVyXSBvCiAgaW5uZXIgam9pbiBAbG9jYXRpb25zIGwgb24gby5Mb2NhdGlvbiA9IGwuSUQKICAvKmlubmVyIGpvaW4gQGRhdGVzIGQgb24gby5EYXRlVGltZUJlZ2luID49IGQuRGF0ZSBhbmQgby5EYXRlVGltZUJlZ2luIDwgZC5EYXRlICsgMSovCndoZXJlIG8uU3RhdHVzID0gMAogIGFuZCBvLkRhdGVUaW1lQmVnaW4gPj0gQERhdGVCZWdpbgogIGFuZCBvLkRhdGVUaW1lQmVnaW4gPCBARGF0ZUVuZCArIDE7CgpwcmludCAnVGVtcExpc3QnOwpkZWxldGUgZnJvbSBUZW1wTGlzdCB3aGVyZSBzcGlkID0gQEBzcGlkOwppbnNlcnQgaW50byBUZW1wTGlzdCAoc3BpZCwgdmFsKQpzZWxlY3QgQEBzcGlkLCBvLklECmZyb20gQG9yZGVycyBvCiAgaW5uZXIgam9pbiBbT3JkZXIgSXRlbV0gb2kgb24gby5JRCA9IG9pLltPcmRlcl0KICBpbm5lciBqb2luIERpc2NvdW50IGQgb24gb2kuW09iamVjdCBJZGVudGlmaWNhdGlvbl0gPSAyIGFuZCBvaS5bT2JqZWN0IElEXSA9IGQuSUQKICBpbm5lciBqb2luIEBnbGNvZGVzIGcgb24gZC5HTENvZGUgPSBnLklEIGFuZCBkLlJlcG9ydEFzUGFpZE91dCA9IDE7CgpwcmludCAnI1JlcG9ydFNhbGVzQW5hbHlzaXNfQ2FsY3VsYXRlZE9yZGVycyc7CmlmIG9iamVjdF9pZCgndGVtcGRiLi4jUmVwb3J0U2FsZXNBbmFseXNpc19DYWxjdWxhdGVkT3JkZXJzJykgaXMgbm90IG51bGwgZHJvcCB0YWJsZSAjUmVwb3J0U2FsZXNBbmFseXNpc19DYWxjdWxhdGVkT3JkZXJzOwpzZWxlY3QgKgppbnRvICNSZXBvcnRTYWxlc0FuYWx5c2lzX0NhbGN1bGF0ZWRPcmRlcnMKZnJvbSBkYm8uZm5DYWxjdWxhdGVNb25leU11bHRpcGxlKDApCgpwcmludCAnQGdsY29kZXNkaXNjb3VudHMnOwpkZWNsYXJlIEBnbGNvZGVzZGlzY291bnRzIHRhYmxlIChnbGNvZGVzb3J0IGludCwgbG9jYXRpb25zb3J0IGludCwgZGF0ZXNvcnQgaW50LCBBbW91bnQgbW9uZXkpOwppbnNlcnQgaW50byBAZ2xjb2Rlc2Rpc2NvdW50cyAoZ2xjb2Rlc29ydCwgbG9jYXRpb25zb3J0LCBkYXRlc29ydCwgQW1vdW50KQpzZWxlY3QKICBzLmdsY29kZXNvcnQsCiAgcy5sb2NhdGlvbnNvcnQsCiAgZC5zb3J0LAogIHN1bShzLkFtb3VudCkKZnJvbSAoCiAgc2VsZWN0CiAgICBnbGNvZGVzb3J0ID0gZy5zb3J0LAogICAgbG9jYXRpb25zb3J0ID0gbC5zb3J0LAogICAgRGF0ZSA9IGRhdGVhZGQoZGF5LCBkYXRlZGlmZihkYXksIDAsIG8uRGF0ZVRpbWVCZWdpbiksIDApLAogICAgQW1vdW50ID0gcm91bmQoY2FzZSBvaS5RdWFudGl0eQogICAgICB3aGVuIDAgdGhlbiBvaS5QcmljZSAqIChjLlN1YlRvdGFsUGVyY2VudGFibGUgKyBkLlVwZGF0ZVRheCAqIGMuU2FsZXNUYXhQZXJjZW50YWJsZSkgLyAxMDAKICAgICAgZWxzZSBvaS5QcmljZQogICAgZW5kLCAyKQogIGZyb20gI1JlcG9ydFNhbGVzQW5hbHlzaXNfQ2FsY3VsYXRlZE9yZGVycyBjCiAgICBpbm5lciBqb2luIFtPcmRlcl0gbyBvbiBjLltPcmRlcl0gPSBvLklECiAgICBpbm5lciBqb2luIEBsb2NhdGlvbnMgbCBvbiBvLkxvY2F0aW9uID0gbC5JRAogICAgaW5uZXIgam9pbiBbT3JkZXIgSXRlbV0gb2kgb24gYy5bT3JkZXJdID0gb2kuW09yZGVyXSBhbmQgb2kuW09iamVjdCBJZGVudGlmaWNhdGlvbl0gPSAyCiAgICBpbm5lciBqb2luIERpc2NvdW50IGQgb24gb2kuW09iamVjdCBJRF0gPSBkLklEIGFuZCBkLlJlcG9ydEFzUGFpZE91dCA9IDEKICAgIGlubmVyIGpvaW4gQGdsY29kZXMgZyBvbiBkLkdMQ29kZSA9IGcuSUQgYW5kIGQuUmVwb3J0QXNQYWlkT3V0ID0gMQopIHMKICBpbm5lciBqb2luIEBkYXRlcyBkIG9uIHMuRGF0ZSA9IGQuZGF0ZQpncm91cCBieQogIHMuZ2xjb2Rlc29ydCwKICBzLmxvY2F0aW9uc29ydCwKICBkLnNvcnQ7CgppbnNlcnQgaW50byBAb3JkZXJzIChMb2NhdGlvbiwgRGF0ZSwgRGlzY291bnQpCnNlbGVjdCBsLklELCBkLkRhdGUsIC1nLkFtb3VudApmcm9tIEBnbGNvZGVzZGlzY291bnRzIGcKICBpbm5lciBqb2luIEBsb2NhdGlvbnMgbCBvbiBnLmxvY2F0aW9uc29ydCA9IGwuc29ydAogIGlubmVyIGpvaW4gQGRhdGVzIGQgb24gZy5kYXRlc29ydCA9IGQuc29ydDsKCmluc2VydCBpbnRvIEBnbGNvZGVzZGlzY291bnRzIChnbGNvZGVzb3J0LCBsb2NhdGlvbnNvcnQsIGRhdGVzb3J0LCBBbW91bnQpCnNlbGVjdCBnbGNvZGVzb3J0LCBsb2NhdGlvbnNvcnQsIDk5OTk5LCBzdW0oQW1vdW50KSAgICBmcm9tIEBnbGNvZGVzZGlzY291bnRzIGdyb3VwIGJ5IGdsY29kZXNvcnQsIGxvY2F0aW9uc29ydAp1bmlvbiBhbGwKc2VsZWN0IGdsY29kZXNvcnQsIDk5OTk5LCAgICAgICAgOTk5OTksIHN1bShBbW91bnQpICAgIGZyb20gQGdsY29kZXNkaXNjb3VudHMgZ3JvdXAgYnkgZ2xjb2Rlc29ydAp1bmlvbiBhbGwKc2VsZWN0IDk5OSwgICAgICAgIGxvY2F0aW9uc29ydCwgZGF0ZXNvcnQsIHN1bShBbW91bnQpIGZyb20gQGdsY29kZXNkaXNjb3VudHMgZ3JvdXAgYnkgbG9jYXRpb25zb3J0LCBkYXRlc29ydAp1bmlvbiBhbGwKc2VsZWN0IDk5OSwgICAgICAgIGxvY2F0aW9uc29ydCwgOTk5OTksICAgIHN1bShBbW91bnQpIGZyb20gQGdsY29kZXNkaXNjb3VudHMgZ3JvdXAgYnkgbG9jYXRpb25zb3J0CnVuaW9uIGFsbApzZWxlY3QgOTk5LCAgICAgICAgOTk5OTksICAgICAgICA5OTk5OSwgICAgc3VtKEFtb3VudCkgZnJvbSBAZ2xjb2Rlc2Rpc2NvdW50cyBncm91cCBieSBjYXNlIGRhdGVzb3J0IHdoZW4gMCB0aGVuIDAgZW5kOwoKcHJpbnQgJ0BnbGNvZGVzc2FsZXMnOwpkZWNsYXJlIEBnbGNvZGVzc2FsZXMgdGFibGUgKGdsY29kZXNvcnQgaW50LCBsb2NhdGlvbnNvcnQgaW50LCBkYXRlc29ydCBpbnQsIEFtb3VudCBtb25leSk7Cmluc2VydCBpbnRvIEBnbGNvZGVzc2FsZXMgKGdsY29kZXNvcnQsIGxvY2F0aW9uc29ydCwgZGF0ZXNvcnQsIEFtb3VudCkKc2VsZWN0CiAgcy5nbGNvZGVzb3J0LAogIHMubG9jYXRpb25zb3J0LAogIGQuc29ydCwKICBzdW0oQW1vdW50KQpmcm9tICgKICBzZWxlY3QKICAgIGdsY29kZXNvcnQgPSBnLnNvcnQsCiAgICBsb2NhdGlvbnNvcnQgPSBsLnNvcnQsCiAgICBEYXRlID0gZGF0ZWFkZChkYXksIGRhdGVkaWZmKGRheSwgMCwgcC5EYXRlVGltZSksIDApLAogICAgQW1vdW50ID0gcC5BbW91bnQgKiBnLmNvZWYKICBmcm9tIFBhaWRPdXQgcAogICAgaW5uZXIgam9pbiBAZ2xjb2RlcyBnIG9uIHAuUGFpZE91dENvZGUgPSBnLmlkCiAgICBpbm5lciBqb2luIEBsb2NhdGlvbnMgbCBvbiBwLkxvY2F0aW9uID0gbC5JRAogIHdoZXJlIHAuRGF0ZVRpbWUgPj0gQERhdGVCZWdpbgogICAgYW5kIHAuRGF0ZVRpbWUgPCBARGF0ZUVuZCArIDEKKSBzCiAgaW5uZXIgam9pbiBAZGF0ZXMgZCBvbiBzLkRhdGUgPSBkLmRhdGUKZ3JvdXAgYnkKICBzLmdsY29kZXNvcnQsCiAgcy5sb2NhdGlvbnNvcnQsCiAgZC5zb3J0OwoKaW5zZXJ0IGludG8gQGdsY29kZXNzYWxlcyAoZ2xjb2Rlc29ydCwgbG9jYXRpb25zb3J0LCBkYXRlc29ydCwgQW1vdW50KQpzZWxlY3QgZ2xjb2Rlc29ydCwgbG9jYXRpb25zb3J0LCA5OTk5OSwgICAgc3VtKEFtb3VudCkgZnJvbSBAZ2xjb2Rlc3NhbGVzIGdyb3VwIGJ5IGdsY29kZXNvcnQsIGxvY2F0aW9uc29ydAp1bmlvbiBhbGwKc2VsZWN0IGdsY29kZXNvcnQsIDk5OTk5LCAgICAgICAgOTk5OTksICAgIHN1bShBbW91bnQpIGZyb20gQGdsY29kZXNzYWxlcyBncm91cCBieSBnbGNvZGVzb3J0CnVuaW9uIGFsbApzZWxlY3QgOTk5LCAgICAgICAgbG9jYXRpb25zb3J0LCBkYXRlc29ydCwgc3VtKEFtb3VudCkgZnJvbSBAZ2xjb2Rlc3NhbGVzIGdyb3VwIGJ5IGxvY2F0aW9uc29ydCwgZGF0ZXNvcnQKdW5pb24gYWxsCnNlbGVjdCA5OTksICAgICAgICBsb2NhdGlvbnNvcnQsIDk5OTk5LCAgICBzdW0oQW1vdW50KSBmcm9tIEBnbGNvZGVzc2FsZXMgZ3JvdXAgYnkgbG9jYXRpb25zb3J0CnVuaW9uIGFsbApzZWxlY3QgOTk5LCAgICAgICAgOTk5OTksICAgICAgICA5OTk5OSwgICAgc3VtKEFtb3VudCkgZnJvbSBAZ2xjb2Rlc3NhbGVzIGdyb3VwIGJ5IGNhc2UgZGF0ZXNvcnQgd2hlbiAwIHRoZW4gMCBlbmQ7CgpwcmludCAnQHNlcnZpY2Vtb25leSc7CmRlY2xhcmUgQHNlcnZpY2Vtb25leSB0YWJsZSAoc2VydmljZXNvcnQgaW50LCBsb2NhdGlvbnNvcnQgaW50LCBkYXRlc29ydCBpbnQsIEFtb3VudCBtb25leSk7Cmluc2VydCBpbnRvIEBzZXJ2aWNlbW9uZXkgKHNlcnZpY2Vzb3J0LCBsb2NhdGlvbnNvcnQsIGRhdGVzb3J0LCBBbW91bnQpCnNlbGVjdAogIHMuc29ydCwKICBsLnNvcnQsCiAgZC5zb3J0LAogIEFtb3VudCA9IHN1bShvdC5QcmljZSkKZnJvbSBbT0lMIFNUT1AgUkVQT1JUXS5bT0lMIFNUT1AgUkVQT1JUXS5kYm8uT3BlcmF0aXZlVG90YWxzIG90CiAgaW5uZXIgam9pbiBbT0lMIFNUT1AgUkVQT1JUXS5bT0lMIFNUT1AgUkVQT1JUXS5kYm8uT3BlcmF0aXZlVG90YWxzSXRlbXNEZXNjcmlwdGlvbiBvdGlkCiAgICBvbiBvdC5PYmplY3QgPSBvdGlkLk9iamVjdCBhbmQgb3QuT2JqZWN0SUQgPSBvdGlkLk9iamVjdElECiAgaW5uZXIgam9pbiBAc2VydmljZXMgcyBvbiBvdGlkLkhpc3RvcnlDb2RlID0gcy5jb2RlCiAgaW5uZXIgam9pbiBAZGF0ZXMgZCBvbiBvdC5EYXRlID0gZC5kYXRlCiAgaW5uZXIgam9pbiBAbG9jYXRpb25zIGwgb24gb3QuTG9jYXRpb24gPSBsLmlkCmdyb3VwIGJ5CiAgcy5zb3J0LAogIGwuc29ydCwKICBkLnNvcnQ7CgppbnNlcnQgaW50byBAb3JkZXJzIChMb2NhdGlvbiwgRGF0ZSwgU2FsZSkKc2VsZWN0IGwuSUQsIGQuRGF0ZSwgLXMuQW1vdW50CmZyb20gQHNlcnZpY2Vtb25leSBzCiAgaW5uZXIgam9pbiBAbG9jYXRpb25zIGwgb24gcy5sb2NhdGlvbnNvcnQgPSBsLnNvcnQKICBpbm5lciBqb2luIEBkYXRlcyBkIG9uIHMuZGF0ZXNvcnQgPSBkLnNvcnQ7CgppbnNlcnQgaW50byBAc2VydmljZW1vbmV5IChzZXJ2aWNlc29ydCwgbG9jYXRpb25zb3J0LCBkYXRlc29ydCwgQW1vdW50KQpzZWxlY3Qgc2VydmljZXNvcnQsIGxvY2F0aW9uc29ydCwgOTk5OTksICAgIHN1bShBbW91bnQpIGZyb20gQHNlcnZpY2Vtb25leSBncm91cCBieSBzZXJ2aWNlc29ydCwgbG9jYXRpb25zb3J0CnVuaW9uIGFsbApzZWxlY3Qgc2VydmljZXNvcnQsIDk5OTk5LCAgICAgICAgOTk5OTksICAgIHN1bShBbW91bnQpIGZyb20gQHNlcnZpY2Vtb25leSBncm91cCBieSBzZXJ2aWNlc29ydAp1bmlvbiBhbGwKc2VsZWN0IDk5OSwgICAgICAgICBsb2NhdGlvbnNvcnQsIGRhdGVzb3J0LCBzdW0oQW1vdW50KSBmcm9tIEBzZXJ2aWNlbW9uZXkgZ3JvdXAgYnkgbG9jYXRpb25zb3J0LCBkYXRlc29ydAp1bmlvbiBhbGwKc2VsZWN0IDk5OSwgICAgICAgICBsb2NhdGlvbnNvcnQsIDk5OTk5LCAgICBzdW0oQW1vdW50KSBmcm9tIEBzZXJ2aWNlbW9uZXkgZ3JvdXAgYnkgbG9jYXRpb25zb3J0CnVuaW9uIGFsbApzZWxlY3QgOTk5LCAgICAgICAgIDk5OTk5LCAgICAgICAgOTk5OTksICAgIHN1bShBbW91bnQpIGZyb20gQHNlcnZpY2Vtb25leSBncm91cCBieSBjYXNlIGRhdGVzb3J0IHdoZW4gMCB0aGVuIDAgZW5kOwoKcHJpbnQgJ0BvcmRlcm1vbmV5JzsKZGVjbGFyZSBAb3JkZXJtb25leSB0YWJsZSAobG9jYXRpb25zb3J0IGludCwgZGF0ZXNvcnQgaW50LCBTYWxlIG1vbmV5LCBEaXNjb3VudCBtb25leSwgVGF4IG1vbmV5KTsKaW5zZXJ0IGludG8gQG9yZGVybW9uZXkgKGxvY2F0aW9uc29ydCwgZGF0ZXNvcnQsIFNhbGUsIERpc2NvdW50LCBUYXgpCnNlbGVjdAogIGwuc29ydCwKICBkLnNvcnQsCiAgU2FsZSA9IHN1bShTYWxlKSwKICBEaXNjb3VudCA9IHN1bShEaXNjb3VudCksCiAgVGF4ID0gc3VtKFRheCkKZnJvbSBAb3JkZXJzIG8KICBpbm5lciBqb2luIEBsb2NhdGlvbnMgbCBvbiBvLkxvY2F0aW9uID0gbC5JRAogIGlubmVyIGpvaW4gQGRhdGVzIGQgb24gby5EYXRlID0gZC5kYXRlCmdyb3VwIGJ5CiAgbC5zb3J0LAogIGQuc29ydDsKCmluc2VydCBpbnRvIEBvcmRlcm1vbmV5IChsb2NhdGlvbnNvcnQsIGRhdGVzb3J0LCBTYWxlLCBEaXNjb3VudCwgVGF4KQpzZWxlY3QgbG9jYXRpb25zb3J0LCA5OTk5OSwgc3VtKFNhbGUpLCBzdW0oRGlzY291bnQpLCBzdW0oVGF4KSBmcm9tIEBvcmRlcm1vbmV5IGdyb3VwIGJ5IGxvY2F0aW9uc29ydAp1bmlvbiBhbGwKc2VsZWN0IDk5OTk5LCAgICAgICAgOTk5OTksIHN1bShTYWxlKSwgc3VtKERpc2NvdW50KSwgc3VtKFRheCkgZnJvbSBAb3JkZXJtb25leQp1bmlvbiBhbGwKc2VsZWN0IDAsICAgICAgICAgICAgOTk5OTksIG51bGwsICAgICAgbnVsbCwgICAgICAgICAgbnVsbDsKCmlmIG5vdCBleGlzdHMgKHNlbGVjdCAqIGZyb20gQHNlcnZpY2Vtb25leSkKICBkZWxldGUgZnJvbSBAaGVhZGVyIHdoZXJlIHNvcnQgPSA0MDA7CmlmIG5vdCBleGlzdHMgKHNlbGVjdCAqIGZyb20gQGdsY29kZXNzYWxlcykKICBkZWxldGUgZnJvbSBAaGVhZGVyIHdoZXJlIHNvcnQgPSA1MDA7CmlmIG5vdCBleGlzdHMgKHNlbGVjdCAqIGZyb20gQGdsY29kZXNkaXNjb3VudHMpCiAgZGVsZXRlIGZyb20gQGhlYWRlciB3aGVyZSBzb3J0ID0gNjAwOwoKaWYgb2JqZWN0X2lkKCd0ZW1wZGIuLiNSZXBvcnRTYWxlc0FuYWx5c2lzJykgaXMgbm90IG51bGwgZHJvcCB0YWJsZSAjUmVwb3J0U2FsZXNBbmFseXNpczsKCnNlbGVjdAogIGxkLmxvY2F0aW9uc29ydCwKICBsZC5kYXRlc29ydCwKICBjb2x1bW5zb3J0ID0gaC5zb3J0ICsgY2FzZSBoLnNvcnQKICAgIHdoZW4gNDAwIHRoZW4gc3Muc29ydAogICAgd2hlbiA1MDAgdGhlbiBnZ3Muc29ydAogICAgd2hlbiA2MDAgdGhlbiBnZ2Quc29ydAogICAgZWxzZSAwCiAgZW5kLAogIEFtb3VudCA9ICAKICBjYXNlIGguc29ydAogICAgd2hlbiAzMDAgdGhlbiBpc251bGwoby5TYWxlLCAwKQogICAgd2hlbiA0MDAgdGhlbiBpc251bGwocy5BbW91bnQsIDApCiAgICB3aGVuIDUwMCB0aGVuIGlzbnVsbChncy5BbW91bnQsIDApCiAgICB3aGVuIDYwMCB0aGVuIC1pc251bGwoZ2QuQW1vdW50LCAwKQogICAgd2hlbiA3MDAgdGhlbiAtaXNudWxsKG8uRGlzY291bnQsIDApCiAgICB3aGVuIDgwMCB0aGVuIGlzbnVsbChvLlRheCwgMCkKICAgIHdoZW4gOTk5IHRoZW4gaXNudWxsKG8uU2FsZSwgMCkgKyBpc251bGwocy5BbW91bnQsIDApICsgaXNudWxsKGdzLkFtb3VudCwgMCkgLSBpc251bGwoZ2QuQW1vdW50LCAwKSAtIGlzbnVsbChvLkRpc2NvdW50LCAwKSArIGlzbnVsbChvLlRheCwgMCkKICBlbmQsCiAgQ2FwdGlvbiA9ICAKICBjYXNlIGguc29ydAogICAgd2hlbiAxMDAgdGhlbiBjYXNlIGxsLnNvcnQgd2hlbiAwIHRoZW4gaC5kZXNjcmlwdGlvbiBlbHNlIGNhc2UgZGQuc29ydCB3aGVuIDk5OTk5IHRoZW4gJ1RvdGFsJyBlbHNlIGxsLmNvZGUgZW5kIGVuZAogICAgd2hlbiAyMDAgdGhlbiBjYXNlIGxsLnNvcnQgd2hlbiAwIHRoZW4gaC5kZXNjcmlwdGlvbiBlbHNlIGNvbnZlcnQodmFyY2hhciwgZGQuZGF0ZSwgMTAxKSBlbmQKICAgIHdoZW4gNDAwIHRoZW4gc3MuY29kZQogICAgd2hlbiA1MDAgdGhlbiBnZ3MuY29kZSArICcgJyArIGdncy5uYW1lCiAgICB3aGVuIDYwMCB0aGVuIGdnZC5jb2RlICsgJyAoRGlzY291bnRzKScKICAgIGVsc2UgaC5kZXNjcmlwdGlvbgogIGVuZAppbnRvICNSZXBvcnRTYWxlc0FuYWx5c2lzCmZyb20gKHNlbGVjdCBkaXN0aW5jdCBsb2NhdGlvbnNvcnQgZnJvbSBAb3JkZXJtb25leSkgbAppbm5lciBqb2luIChzZWxlY3QgZGlzdGluY3QgbG9jYXRpb25zb3J0LCBkYXRlc29ydCBmcm9tIEBvcmRlcm1vbmV5KSBsZCBvbiBsLmxvY2F0aW9uc29ydCA9IGxkLmxvY2F0aW9uc29ydAppbm5lciBqb2luIEBsb2NhdGlvbnMgbGwgb24gbC5sb2NhdGlvbnNvcnQgPSBsbC5zb3J0CmlubmVyIGpvaW4gQGRhdGVzIGRkIG9uIGxkLmRhdGVzb3J0ID0gZGQuc29ydApjcm9zcyBqb2luIEBoZWFkZXIgaApsZWZ0IGpvaW4gQG9yZGVybW9uZXkgbyBvbiBoLnNvcnQgaW4gKDMwMCwgNzAwLCA4MDAsIDk5OSkKICBhbmQgbGQubG9jYXRpb25zb3J0ID0gby5sb2NhdGlvbnNvcnQKICBhbmQgbGQuZGF0ZXNvcnQgPSBvLmRhdGVzb3J0CmxlZnQgam9pbiAoc2VsZWN0IGRpc3RpbmN0IHQuKiwgbS5zZXJ2aWNlc29ydCBmcm9tIEBzZXJ2aWNlbW9uZXkgbSBsZWZ0IGpvaW4gQHNlcnZpY2VzIHQgb24gbS5zZXJ2aWNlc29ydCA9IHQuc29ydCkgc3MKICBvbiBoLnNvcnQgPSBzcy5zZXJ2aWNlc29ydCBvciAoaC5zb3J0ID0gNDAwIGFuZCBzcy5zZXJ2aWNlc29ydCA8IDEwMCkKbGVmdCBqb2luIEBzZXJ2aWNlbW9uZXkgcyBvbiBzcy5zZXJ2aWNlc29ydCA9IHMuc2VydmljZXNvcnQKICBhbmQgbGQubG9jYXRpb25zb3J0ID0gcy5sb2NhdGlvbnNvcnQgIC0tIHRoaXMgbGluZSBwcm9kdWNlcyB0aGUgZXJyb3IKLS0gdGhlIGVycm9yIGlzOgotLSBUaGUgbXVsdGktcGFydCBpZGVudGlmaWVyICJsZC5sb2NhdGlvbnNvcnQiIGNvdWxkIG5vdCBiZSBib3VuZAogIGFuZCBsZC5kYXRlc29ydCA9IHMuZGF0ZXNvcnQKbGVmdCBqb2luIChzZWxlY3QgZGlzdGluY3QgdC4qLCBtLmdsY29kZXNvcnQgZnJvbSBAZ2xjb2Rlc3NhbGVzIG0gbGVmdCBqb2luIEBnbGNvZGVzIHQgb24gbS5nbGNvZGVzb3J0ID0gdC5zb3J0KSBnZ3MKICBvbiBoLnNvcnQgPSBnZ3MuZ2xjb2Rlc29ydCBvciAoaC5zb3J0ID0gNTAwIGFuZCBnZ3MuZ2xjb2Rlc29ydCA8IDEwMCkKbGVmdCBqb2luIEBnbGNvZGVzc2FsZXMgZ3Mgb24gZ2dzLmdsY29kZXNvcnQgPSBncy5nbGNvZGVzb3J0CiAgYW5kIGxkLmxvY2F0aW9uc29ydCA9IGdzLmxvY2F0aW9uc29ydAogIGFuZCBsZC5kYXRlc29ydCA9IGdzLmRhdGVzb3J0CmxlZnQgam9pbiAoc2VsZWN0IGRpc3RpbmN0IHQuKiwgbS5nbGNvZGVzb3J0IGZyb20gQGdsY29kZXNkaXNjb3VudHMgbSBsZWZ0IGpvaW4gQGdsY29kZXMgdCBvbiBtLmdsY29kZXNvcnQgPSB0LnNvcnQpIGdnZAogIG9uIGguc29ydCA9IGdnZC5nbGNvZGVzb3J0IG9yIChoLnNvcnQgPSA2MDAgYW5kIGdnZC5nbGNvZGVzb3J0IDwgMTAwKQpsZWZ0IGpvaW4gQGdsY29kZXNkaXNjb3VudHMgZ2Qgb24gZ2dkLmdsY29kZXNvcnQgPSBnZC5nbGNvZGVzb3J0CiAgYW5kIGxkLmxvY2F0aW9uc29ydCA9IGdkLmxvY2F0aW9uc29ydAogIGFuZCBsZC5kYXRlc29ydCA9IGdkLmRhdGVzb3J0OwoKc2VsZWN0CiAgKiwgKHNlbGVjdCBjb3VudChkaXN0aW5jdCBjb2x1bW5zb3J0KSBmcm9tICNSZXBvcnRTYWxlc0FuYWx5c2lzKSBhcyBDb2x1bW5DbnQKZnJvbSAjUmVwb3J0U2FsZXNBbmFseXNpcwpvcmRlciBieQogIGxkLmxvY2F0aW9uc29ydCwKICBsZC5kYXRlc29ydCwKICBjb2x1bW5zb3J0Owo=