// Generate nth Hamming number, for n < 1.5e12
// Joe Knapp knapp.167@osu.edu
//
// To generate "band" of triples in the vicinity of the nth number,
// uses basic scheme of Louis Klauder described in:
// http://w...content-available-to-author-only...s.com/architecture-and-design/hamming-problem/228700538
//
// Once the lower triple in the band is identified, and the offset
// from that number to the nth number determined, the table in
// hamtab3.h is used to generate iterates up to the nth number.
//
#define TRUE 1
#define FALSE 0
#define LOG2 log(2.0)
#define LOG3 log(3.0)
#define LOG5 log(5.0)
#define THIRD (1.0/3.0)
#define LOWOFFSET 1.703
#define HIOFFSET 1.693
#define NMIN 50000 // below NMIN, just get the Nth number by chugging
// through the whole sequence
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
// table of intervals to compute the next Hamming number (2^p2*3^p3*5^p5)
// The interval to use is the first one in the table twhere multiplication
// results in positive powers for all three prime factors 2, 3, and 5.
//
// These factors cover the first 1.59 trillion (1.59e12) Hamming numbers,
// yielding values up to about 10^10000.
#define NTAB 119 // number of table entries
struct {
short p2 ; // power of 2
short p3 ; // power of 3
short p5 ; // power of 5
} hamtab[NTAB] = {
{16875,7633,-12478}, // 1.000000000053896
{-22109,20086,-4189}, // 1.000000001373946
{14639,-17295,5501}, // 1.000000002068432
{31514,-9662,-6977}, // 1.000000002122329
{-24345,-4842,13790}, // 1.000000003388482
{-7470,2791,1312}, // 1.000000003442378
{9405,10424,-11166}, // 1.000000003496275
{7169,-14504,6813}, // 1.000000005510811
{24044,-6871,-5665}, // 1.000000005564707
{1935,13215,-9854}, // 1.000000006938654
{-301,-11713,8125}, // 1.000000008953190
{16574,-4080,-4353}, // 1.000000009007086
{-5535,16006,-8542}, // 1.000000010381033
{9104,-1289,-3041}, // 1.000000012449465
{1634,1502,-1729}, // 1.000000015891844
{-5836,4293,-417}, // 1.000000019334223
{8803,-13002,5084}, // 1.000000021402655
{1333,-10211,6396}, // 1.000000024845034
{-6137,-7420,7708}, // 1.000000028287413
{2967,-8709,4667}, // 1.000000040736879
{-4503,-5918,5979}, // 1.000000044179258
{4601,-7207,2938}, // 1.000000056628724
{-2869,-4416,4250}, // 1.000000060071103
{6235,-5705,1209}, // 1.000000072520570
{-1235,-2914,2521}, // 1.000000075962949
{7869,-4203,-520}, // 1.000000088412415
{399,-1412,792}, // 1.000000091854795
{-7071,1379,2104}, // 1.000000095297174
{2033,90,-937}, // 1.000000107746641
{-5437,2881,375}, // 1.000000111189020
{2432,-1322,-145}, // 1.000000199601446
{-5038,1469,1167}, // 1.000000203043825
{-3404,2971,-562}, // 1.000000218935673
{-4639,57,1959}, // 1.000000294898639
{-3005,1559,230}, // 1.000000310790488
{-2606,147,1022}, // 1.000000402645312
{-972,1649,-707}, // 1.000000418537163
{-2207,-1265,1814}, // 1.000000494500144
{-573,237,85}, // 1.000000510391996
{-174,-1175,877}, // 1.000000602246838
{1460,327,-852}, // 1.000000618138692
{1859,-1085,-60}, // 1.000000709993544
{887,564,-767}, // 1.000001128531004
{1286,-848,25}, // 1.000001220385903
{314,801,-682}, // 1.000001638923577
{713,-611,110}, // 1.000001730778523
{-259,1038,-597}, // 1.000002149316410
{140,-374,195}, // 1.000002241171403
{-433,-137,280}, // 1.000002751564543
{1600,-47,-657}, // 1.000002859311481
{1027,190,-572}, // 1.000003369704937
{454,427,-487}, // 1.000003880098653
{-119,664,-402}, // 1.000004390492630
{1167,-184,-377}, // 1.000005610883892
{594,53,-292}, // 1.000006121278753
{21,290,-207}, // 1.000006631673873
{-552,527,-122}, // 1.000007142069255
{734,-321,-97}, // 1.000008362463875
{161,-84,-12}, // 1.000008872860139
{-412,153,73}, // 1.000009383256665
{-272,-221,268}, // 1.000011624449097
{-391,443,-134}, // 1.000016014992765
{-251,69,61}, // 1.000018256200061
{-111,-305,256}, // 1.000020497412379
{-230,359,-146}, // 1.000024887995004
{-90,-15,49}, // 1.000027129222185
{-69,275,-158}, // 1.000033761075971
{71,-99,37}, // 1.000036002323039
{92,191,-170}, // 1.000042634235669
{-159,260,-109}, // 1.000060891214069
{2,176,-121}, // 1.000069764614488
{-249,245,-60}, // 1.000088022088186
{-88,161,-72}, // 1.000096895729334
{73,77,-84}, // 1.000105769449216
{-178,146,-23}, // 1.000124027580225
{-17,62,-35}, // 1.000132901540844
{144,-22,-47}, // 1.000141775580201
{-107,47,14}, // 1.000160034368546
{54,-37,2}, // 1.000168908648648
{127,40,-82}, // 1.000274695963239
{37,25,-33}, // 1.000301832637713
{-53,10,16}, // 1.000328970048383
{91,-12,-31}, // 1.000470792268504
{1,-27,18}, // 1.000497934262918
{-16,35,-17}, // 1.000630901979994
{38,-2,-15}, // 1.000799917193443
{-52,-17,34}, // 1.000827068116760
{-15,8,1}, // 1.001129150390625
{22,33,-32}, // 1.001431323842778
{-14,-19,19}, // 1.001627646896210
{23,6,-14}, // 1.001929970810880
{24,-21,4}, // 1.002428866072391
{8,14,-13}, // 1.003061300428800
{9,-13,5}, // 1.003560759018091
{-7,22,-12}, // 1.004193907488000
{-6,-5,6}, // 1.004693930041152
{32,-7,-9}, // 1.005497601989940
{17,1,-8}, // 1.006632960000000
{2,9,-7}, // 1.007769600000000
{-13,17,-6}, // 1.008907523437500
{26,-12,-3}, // 1.010217337390227
{11,-4,-2}, // 1.011358024691358
{-4,4,-1}, // 1.012500000000000
{5,-9,4}, // 1.016105268505817
{-10,-1,5}, // 1.017252604166666
{7,0,-3}, // 1.024000000000000
{1,-5,3}, // 1.028806584362139
{-14,3,4}, // 1.029968261718750
{-3,-1,2}, // 1.041666666666666
{-7,3,1}, // 1.054687500000000
{4,-1,-1}, // 1.066666666666666
{0,3,-2}, // 1.080000000000000
{1,-2,1}, // 1.111111111111111
{-3,2,0}, // 1.125000000000000
{1,1,-1}, // 1.200000000000000
{-2,0,1}, // 1.250000000000000
{2,-1,0}, // 1.333333333333333
{-1,1,0}, // 1.500000000000000
{1,0,0} // 2.000000000000000
} ;
void hammahead(unsigned long n, int *i0, int *j0, int *k0) ;
int main(int argc, char **argv) {
double l2 = LOG2, l3 = LOG3, l5 = LOG5 ; // precomputed logarithms
double logM, logMlo, logMhi ; // per the Dr. Dobbs article,
// logMlo < i*l2 + j*l3 + k*l5 < logMhi
int i, j, k ; //loop counters
int imin, imax, jmax, kmax ; // limits for i,j,k loops
double logMmin = 1e9 ; // minimum logM seen, defaults to big number
unsigned long n ; // want nth Hamming number
unsigned long totn = 0 ; // total i,j,k combinations below logMlo
int i0, j0, k0 ; // i,j,k values for minimum logM in band
unsigned long nahead ; // number of values to skip ahead from i0, j0, k0
unsigned char found = FALSE ;
n = 1000000000000 ;
if (n >= NMIN) {
// get range of logM
logM
= pow((6.0*l2
*l3
*l5
)*n
,THIRD
) ; logMlo = logM - LOWOFFSET ;
logMhi = logM - HIOFFSET ;
kmax
= floor(logMhi
/l5
) ; for (k = 0 ; k <= kmax ; k++) {
jmax
= floor((logMhi
- k
*l5
)/l3
) ; for (j = 0 ; j <= jmax ; j++) {
imin
= ceil((logMlo
- k
*l5
- j
*l3
)/l2
) ; imax
= floor((logMhi
- k
*l5
- j
*l3
)/l2
) ; totn += imin ;
for (i = imin ; i <= imax ; i++) {
logM = i*l2 + j*l3 + k*l5 ;
if (logM < logMmin) {
logMmin = logM ;
i0 = i ;
j0 = j ;
k0 = k ;
}
}
}
}
nahead = n - totn - 1 ;
hammahead(nahead,&i0,&j0,&k0) ;
}
else {
int m, in ;
i0 = 0 ;
j0 = 0 ;
k0 = 0 ;
for (in = 0 ; in < n-1 ; in++) {
m = 0 ;
found = FALSE ;
while (!found && m < NTAB) {
if (i0 + hamtab[m].p2 >= 0)
if (j0 + hamtab[m].p3 >= 0)
if (k0 + hamtab[m].p5 >= 0)
found = TRUE ;
m++ ;
}
m-- ;
i0 += hamtab[m].p2 ;
j0 += hamtab[m].p3 ;
k0 += hamtab[m].p5 ;
}
}
printf("%d %d %d\n",i0
,j0
,k0
) ; // output nth i,j,k values }
// From the Hamming number 2^i0*3^j0*5^k0, skip ahead
// nhead numbers and update i0, j0 and k0 accordingly.
void hammahead(unsigned long nahead, int *i0, int *j0, int *k0) {
unsigned char k ;
unsigned long j ;
unsigned char found ;
for (j = 0 ; j < nahead ; j++) {
// for each Hamming number, find the minimum interval in hamtab
// i.e., the minimum entry where multiplication would result
// in positive powers for i, j & k
k = 0 ;
found = FALSE ;
while (!found && k < NTAB) {
if (*i0 + hamtab[k].p2 >= 0)
if (*j0 + hamtab[k].p3 >= 0)
if (*k0 + hamtab[k].p5 >= 0)
found = TRUE ;
if (!found)
k++ ;
}
if (!found) {
fprintf(stderr
,"error: suitable table entry not found, j=%ld\n",j
) ; }
else {
// got the next interval, update counts
*i0 += hamtab[k].p2 ;
*j0 += hamtab[k].p3 ;
*k0 += hamtab[k].p5 ;
}
}
}
Ly8gR2VuZXJhdGUgbnRoIEhhbW1pbmcgbnVtYmVyLCBmb3IgbiA8IDEuNWUxMgovLyBKb2UgS25hcHAgIGtuYXBwLjE2N0Bvc3UuZWR1Ci8vCi8vIFRvIGdlbmVyYXRlICJiYW5kIiBvZiB0cmlwbGVzIGluIHRoZSB2aWNpbml0eSBvZiB0aGUgbnRoIG51bWJlciwKLy8gdXNlcyBiYXNpYyBzY2hlbWUgb2YgTG91aXMgS2xhdWRlciBkZXNjcmliZWQgaW46Ci8vIGh0dHA6Ly93Li4uY29udGVudC1hdmFpbGFibGUtdG8tYXV0aG9yLW9ubHkuLi5zLmNvbS9hcmNoaXRlY3R1cmUtYW5kLWRlc2lnbi9oYW1taW5nLXByb2JsZW0vMjI4NzAwNTM4Ci8vIAovLyBPbmNlIHRoZSBsb3dlciB0cmlwbGUgaW4gdGhlIGJhbmQgaXMgaWRlbnRpZmllZCwgYW5kIHRoZSBvZmZzZXQKLy8gZnJvbSB0aGF0IG51bWJlciB0byB0aGUgbnRoIG51bWJlciBkZXRlcm1pbmVkLCB0aGUgdGFibGUgaW4KLy8gaGFtdGFiMy5oIGlzIHVzZWQgdG8gZ2VuZXJhdGUgaXRlcmF0ZXMgdXAgdG8gdGhlIG50aCBudW1iZXIuCi8vCiNkZWZpbmUgVFJVRSAxCiNkZWZpbmUgRkFMU0UgMAoKI2RlZmluZSBMT0cyIGxvZygyLjApCiNkZWZpbmUgTE9HMyBsb2coMy4wKQojZGVmaW5lIExPRzUgbG9nKDUuMCkKI2RlZmluZSBUSElSRCAoMS4wLzMuMCkKCiNkZWZpbmUgTE9XT0ZGU0VUIDEuNzAzCiNkZWZpbmUgSElPRkZTRVQgMS42OTMKCiNkZWZpbmUgTk1JTiA1MDAwMCAgIC8vIGJlbG93IE5NSU4sIGp1c3QgZ2V0IHRoZSBOdGggbnVtYmVyIGJ5IGNodWdnaW5nCiAgICAgICAgICAgICAgICAgICAgIC8vIHRocm91Z2ggdGhlIHdob2xlIHNlcXVlbmNlCgojaW5jbHVkZSA8dW5pc3RkLmg+CiNpbmNsdWRlIDxzdGRsaWIuaD4KI2luY2x1ZGUgPHN0ZGlvLmg+CiNpbmNsdWRlIDxtYXRoLmg+CgovLyB0YWJsZSBvZiBpbnRlcnZhbHMgdG8gY29tcHV0ZSB0aGUgbmV4dCBIYW1taW5nIG51bWJlciAoMl5wMiozXnAzKjVecDUpCi8vIFRoZSBpbnRlcnZhbCB0byB1c2UgaXMgdGhlIGZpcnN0IG9uZSBpbiB0aGUgdGFibGUgdHdoZXJlIG11bHRpcGxpY2F0aW9uCi8vIHJlc3VsdHMgaW4gcG9zaXRpdmUgcG93ZXJzIGZvciBhbGwgdGhyZWUgcHJpbWUgZmFjdG9ycyAyLCAzLCBhbmQgNS4KLy8gCi8vIFRoZXNlIGZhY3RvcnMgY292ZXIgdGhlIGZpcnN0IDEuNTkgdHJpbGxpb24gKDEuNTllMTIpIEhhbW1pbmcgbnVtYmVycywKLy8geWllbGRpbmcgdmFsdWVzIHVwIHRvIGFib3V0IDEwXjEwMDAwLgojZGVmaW5lIE5UQUIgMTE5ICAvLyBudW1iZXIgb2YgdGFibGUgZW50cmllcwpzdHJ1Y3QgewogICAgc2hvcnQgcDIgOyAvLyBwb3dlciBvZiAyCiAgICBzaG9ydCBwMyA7IC8vIHBvd2VyIG9mIDMKICAgIHNob3J0IHA1IDsgLy8gcG93ZXIgb2YgNQp9IGhhbXRhYltOVEFCXSA9IHsKezE2ODc1LDc2MzMsLTEyNDc4fSwgLy8gMS4wMDAwMDAwMDAwNTM4OTYKey0yMjEwOSwyMDA4NiwtNDE4OX0sIC8vIDEuMDAwMDAwMDAxMzczOTQ2CnsxNDYzOSwtMTcyOTUsNTUwMX0sIC8vIDEuMDAwMDAwMDAyMDY4NDMyCnszMTUxNCwtOTY2MiwtNjk3N30sIC8vIDEuMDAwMDAwMDAyMTIyMzI5CnstMjQzNDUsLTQ4NDIsMTM3OTB9LCAvLyAxLjAwMDAwMDAwMzM4ODQ4Mgp7LTc0NzAsMjc5MSwxMzEyfSwgLy8gMS4wMDAwMDAwMDM0NDIzNzgKezk0MDUsMTA0MjQsLTExMTY2fSwgLy8gMS4wMDAwMDAwMDM0OTYyNzUKezcxNjksLTE0NTA0LDY4MTN9LCAvLyAxLjAwMDAwMDAwNTUxMDgxMQp7MjQwNDQsLTY4NzEsLTU2NjV9LCAvLyAxLjAwMDAwMDAwNTU2NDcwNwp7MTkzNSwxMzIxNSwtOTg1NH0sIC8vIDEuMDAwMDAwMDA2OTM4NjU0CnstMzAxLC0xMTcxMyw4MTI1fSwgLy8gMS4wMDAwMDAwMDg5NTMxOTAKezE2NTc0LC00MDgwLC00MzUzfSwgLy8gMS4wMDAwMDAwMDkwMDcwODYKey01NTM1LDE2MDA2LC04NTQyfSwgLy8gMS4wMDAwMDAwMTAzODEwMzMKezkxMDQsLTEyODksLTMwNDF9LCAvLyAxLjAwMDAwMDAxMjQ0OTQ2NQp7MTYzNCwxNTAyLC0xNzI5fSwgLy8gMS4wMDAwMDAwMTU4OTE4NDQKey01ODM2LDQyOTMsLTQxN30sIC8vIDEuMDAwMDAwMDE5MzM0MjIzCns4ODAzLC0xMzAwMiw1MDg0fSwgLy8gMS4wMDAwMDAwMjE0MDI2NTUKezEzMzMsLTEwMjExLDYzOTZ9LCAvLyAxLjAwMDAwMDAyNDg0NTAzNAp7LTYxMzcsLTc0MjAsNzcwOH0sIC8vIDEuMDAwMDAwMDI4Mjg3NDEzCnsyOTY3LC04NzA5LDQ2Njd9LCAvLyAxLjAwMDAwMDA0MDczNjg3OQp7LTQ1MDMsLTU5MTgsNTk3OX0sIC8vIDEuMDAwMDAwMDQ0MTc5MjU4Cns0NjAxLC03MjA3LDI5Mzh9LCAvLyAxLjAwMDAwMDA1NjYyODcyNAp7LTI4NjksLTQ0MTYsNDI1MH0sIC8vIDEuMDAwMDAwMDYwMDcxMTAzCns2MjM1LC01NzA1LDEyMDl9LCAvLyAxLjAwMDAwMDA3MjUyMDU3MAp7LTEyMzUsLTI5MTQsMjUyMX0sIC8vIDEuMDAwMDAwMDc1OTYyOTQ5Cns3ODY5LC00MjAzLC01MjB9LCAvLyAxLjAwMDAwMDA4ODQxMjQxNQp7Mzk5LC0xNDEyLDc5Mn0sIC8vIDEuMDAwMDAwMDkxODU0Nzk1CnstNzA3MSwxMzc5LDIxMDR9LCAvLyAxLjAwMDAwMDA5NTI5NzE3NAp7MjAzMyw5MCwtOTM3fSwgLy8gMS4wMDAwMDAxMDc3NDY2NDEKey01NDM3LDI4ODEsMzc1fSwgLy8gMS4wMDAwMDAxMTExODkwMjAKezI0MzIsLTEzMjIsLTE0NX0sIC8vIDEuMDAwMDAwMTk5NjAxNDQ2CnstNTAzOCwxNDY5LDExNjd9LCAvLyAxLjAwMDAwMDIwMzA0MzgyNQp7LTM0MDQsMjk3MSwtNTYyfSwgLy8gMS4wMDAwMDAyMTg5MzU2NzMKey00NjM5LDU3LDE5NTl9LCAvLyAxLjAwMDAwMDI5NDg5ODYzOQp7LTMwMDUsMTU1OSwyMzB9LCAvLyAxLjAwMDAwMDMxMDc5MDQ4OAp7LTI2MDYsMTQ3LDEwMjJ9LCAvLyAxLjAwMDAwMDQwMjY0NTMxMgp7LTk3MiwxNjQ5LC03MDd9LCAvLyAxLjAwMDAwMDQxODUzNzE2Mwp7LTIyMDcsLTEyNjUsMTgxNH0sIC8vIDEuMDAwMDAwNDk0NTAwMTQ0CnstNTczLDIzNyw4NX0sIC8vIDEuMDAwMDAwNTEwMzkxOTk2CnstMTc0LC0xMTc1LDg3N30sIC8vIDEuMDAwMDAwNjAyMjQ2ODM4CnsxNDYwLDMyNywtODUyfSwgLy8gMS4wMDAwMDA2MTgxMzg2OTIKezE4NTksLTEwODUsLTYwfSwgLy8gMS4wMDAwMDA3MDk5OTM1NDQKezg4Nyw1NjQsLTc2N30sIC8vIDEuMDAwMDAxMTI4NTMxMDA0CnsxMjg2LC04NDgsMjV9LCAvLyAxLjAwMDAwMTIyMDM4NTkwMwp7MzE0LDgwMSwtNjgyfSwgLy8gMS4wMDAwMDE2Mzg5MjM1NzcKezcxMywtNjExLDExMH0sIC8vIDEuMDAwMDAxNzMwNzc4NTIzCnstMjU5LDEwMzgsLTU5N30sIC8vIDEuMDAwMDAyMTQ5MzE2NDEwCnsxNDAsLTM3NCwxOTV9LCAvLyAxLjAwMDAwMjI0MTE3MTQwMwp7LTQzMywtMTM3LDI4MH0sIC8vIDEuMDAwMDAyNzUxNTY0NTQzCnsxNjAwLC00NywtNjU3fSwgLy8gMS4wMDAwMDI4NTkzMTE0ODEKezEwMjcsMTkwLC01NzJ9LCAvLyAxLjAwMDAwMzM2OTcwNDkzNwp7NDU0LDQyNywtNDg3fSwgLy8gMS4wMDAwMDM4ODAwOTg2NTMKey0xMTksNjY0LC00MDJ9LCAvLyAxLjAwMDAwNDM5MDQ5MjYzMAp7MTE2NywtMTg0LC0zNzd9LCAvLyAxLjAwMDAwNTYxMDg4Mzg5Mgp7NTk0LDUzLC0yOTJ9LCAvLyAxLjAwMDAwNjEyMTI3ODc1Mwp7MjEsMjkwLC0yMDd9LCAvLyAxLjAwMDAwNjYzMTY3Mzg3Mwp7LTU1Miw1MjcsLTEyMn0sIC8vIDEuMDAwMDA3MTQyMDY5MjU1Cns3MzQsLTMyMSwtOTd9LCAvLyAxLjAwMDAwODM2MjQ2Mzg3NQp7MTYxLC04NCwtMTJ9LCAvLyAxLjAwMDAwODg3Mjg2MDEzOQp7LTQxMiwxNTMsNzN9LCAvLyAxLjAwMDAwOTM4MzI1NjY2NQp7LTI3MiwtMjIxLDI2OH0sIC8vIDEuMDAwMDExNjI0NDQ5MDk3CnstMzkxLDQ0MywtMTM0fSwgLy8gMS4wMDAwMTYwMTQ5OTI3NjUKey0yNTEsNjksNjF9LCAvLyAxLjAwMDAxODI1NjIwMDA2MQp7LTExMSwtMzA1LDI1Nn0sIC8vIDEuMDAwMDIwNDk3NDEyMzc5CnstMjMwLDM1OSwtMTQ2fSwgLy8gMS4wMDAwMjQ4ODc5OTUwMDQKey05MCwtMTUsNDl9LCAvLyAxLjAwMDAyNzEyOTIyMjE4NQp7LTY5LDI3NSwtMTU4fSwgLy8gMS4wMDAwMzM3NjEwNzU5NzEKezcxLC05OSwzN30sIC8vIDEuMDAwMDM2MDAyMzIzMDM5Cns5MiwxOTEsLTE3MH0sIC8vIDEuMDAwMDQyNjM0MjM1NjY5CnstMTU5LDI2MCwtMTA5fSwgLy8gMS4wMDAwNjA4OTEyMTQwNjkKezIsMTc2LC0xMjF9LCAvLyAxLjAwMDA2OTc2NDYxNDQ4OAp7LTI0OSwyNDUsLTYwfSwgLy8gMS4wMDAwODgwMjIwODgxODYKey04OCwxNjEsLTcyfSwgLy8gMS4wMDAwOTY4OTU3MjkzMzQKezczLDc3LC04NH0sIC8vIDEuMDAwMTA1NzY5NDQ5MjE2CnstMTc4LDE0NiwtMjN9LCAvLyAxLjAwMDEyNDAyNzU4MDIyNQp7LTE3LDYyLC0zNX0sIC8vIDEuMDAwMTMyOTAxNTQwODQ0CnsxNDQsLTIyLC00N30sIC8vIDEuMDAwMTQxNzc1NTgwMjAxCnstMTA3LDQ3LDE0fSwgLy8gMS4wMDAxNjAwMzQzNjg1NDYKezU0LC0zNywyfSwgLy8gMS4wMDAxNjg5MDg2NDg2NDgKezEyNyw0MCwtODJ9LCAvLyAxLjAwMDI3NDY5NTk2MzIzOQp7MzcsMjUsLTMzfSwgLy8gMS4wMDAzMDE4MzI2Mzc3MTMKey01MywxMCwxNn0sIC8vIDEuMDAwMzI4OTcwMDQ4MzgzCns5MSwtMTIsLTMxfSwgLy8gMS4wMDA0NzA3OTIyNjg1MDQKezEsLTI3LDE4fSwgLy8gMS4wMDA0OTc5MzQyNjI5MTgKey0xNiwzNSwtMTd9LCAvLyAxLjAwMDYzMDkwMTk3OTk5NAp7MzgsLTIsLTE1fSwgLy8gMS4wMDA3OTk5MTcxOTM0NDMKey01MiwtMTcsMzR9LCAvLyAxLjAwMDgyNzA2ODExNjc2MAp7LTE1LDgsMX0sIC8vIDEuMDAxMTI5MTUwMzkwNjI1CnsyMiwzMywtMzJ9LCAvLyAxLjAwMTQzMTMyMzg0Mjc3OAp7LTE0LC0xOSwxOX0sIC8vIDEuMDAxNjI3NjQ2ODk2MjEwCnsyMyw2LC0xNH0sIC8vIDEuMDAxOTI5OTcwODEwODgwCnsyNCwtMjEsNH0sIC8vIDEuMDAyNDI4ODY2MDcyMzkxCns4LDE0LC0xM30sIC8vIDEuMDAzMDYxMzAwNDI4ODAwCns5LC0xMyw1fSwgLy8gMS4wMDM1NjA3NTkwMTgwOTEKey03LDIyLC0xMn0sIC8vIDEuMDA0MTkzOTA3NDg4MDAwCnstNiwtNSw2fSwgLy8gMS4wMDQ2OTM5MzAwNDExNTIKezMyLC03LC05fSwgLy8gMS4wMDU0OTc2MDE5ODk5NDAKezE3LDEsLTh9LCAvLyAxLjAwNjYzMjk2MDAwMDAwMAp7Miw5LC03fSwgLy8gMS4wMDc3Njk2MDAwMDAwMDAKey0xMywxNywtNn0sIC8vIDEuMDA4OTA3NTIzNDM3NTAwCnsyNiwtMTIsLTN9LCAvLyAxLjAxMDIxNzMzNzM5MDIyNwp7MTEsLTQsLTJ9LCAvLyAxLjAxMTM1ODAyNDY5MTM1OAp7LTQsNCwtMX0sIC8vIDEuMDEyNTAwMDAwMDAwMDAwCns1LC05LDR9LCAvLyAxLjAxNjEwNTI2ODUwNTgxNwp7LTEwLC0xLDV9LCAvLyAxLjAxNzI1MjYwNDE2NjY2Ngp7NywwLC0zfSwgLy8gMS4wMjQwMDAwMDAwMDAwMDAKezEsLTUsM30sIC8vIDEuMDI4ODA2NTg0MzYyMTM5CnstMTQsMyw0fSwgLy8gMS4wMjk5NjgyNjE3MTg3NTAKey0zLC0xLDJ9LCAvLyAxLjA0MTY2NjY2NjY2NjY2Ngp7LTcsMywxfSwgLy8gMS4wNTQ2ODc1MDAwMDAwMDAKezQsLTEsLTF9LCAvLyAxLjA2NjY2NjY2NjY2NjY2Ngp7MCwzLC0yfSwgLy8gMS4wODAwMDAwMDAwMDAwMDAKezEsLTIsMX0sIC8vIDEuMTExMTExMTExMTExMTExCnstMywyLDB9LCAvLyAxLjEyNTAwMDAwMDAwMDAwMAp7MSwxLC0xfSwgLy8gMS4yMDAwMDAwMDAwMDAwMDAKey0yLDAsMX0sIC8vIDEuMjUwMDAwMDAwMDAwMDAwCnsyLC0xLDB9LCAvLyAxLjMzMzMzMzMzMzMzMzMzMwp7LTEsMSwwfSwgLy8gMS41MDAwMDAwMDAwMDAwMDAKezEsMCwwfSAvLyAyLjAwMDAwMDAwMDAwMDAwMAp9IDsKCnZvaWQgaGFtbWFoZWFkKHVuc2lnbmVkIGxvbmcgbiwgaW50ICppMCwgaW50ICpqMCwgaW50ICprMCkgIDsKCmludCBtYWluKGludCBhcmdjLCBjaGFyICoqYXJndikgewogICAgZG91YmxlIGwyID0gTE9HMiwgbDMgPSBMT0czLCBsNSA9IExPRzUgOyAvLyBwcmVjb21wdXRlZCBsb2dhcml0aG1zCiAgICBkb3VibGUgbG9nTSwgbG9nTWxvLCBsb2dNaGkgOyAvLyBwZXIgdGhlIERyLiBEb2JicyBhcnRpY2xlLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGxvZ01sbyA8IGkqbDIgKyBqKmwzICsgaypsNSA8IGxvZ01oaQogICAgaW50IGksIGosIGsgOyAgLy9sb29wIGNvdW50ZXJzIAogICAgaW50IGltaW4sIGltYXgsIGptYXgsIGttYXggOyAgLy8gbGltaXRzIGZvciBpLGosayBsb29wcwogICAgZG91YmxlIGxvZ01taW4gPSAxZTkgOyAgLy8gbWluaW11bSBsb2dNIHNlZW4sIGRlZmF1bHRzIHRvIGJpZyBudW1iZXIKCiAgICB1bnNpZ25lZCBsb25nIG4gOyAgLy8gd2FudCBudGggSGFtbWluZyBudW1iZXIKICAgIHVuc2lnbmVkIGxvbmcgdG90biA9IDAgOyAgLy8gdG90YWwgaSxqLGsgY29tYmluYXRpb25zIGJlbG93IGxvZ01sbwoKICAgIGludCBpMCwgajAsIGswIDsgLy8gaSxqLGsgdmFsdWVzIGZvciBtaW5pbXVtIGxvZ00gaW4gYmFuZAogICAgdW5zaWduZWQgbG9uZyBuYWhlYWQgOyAgLy8gbnVtYmVyIG9mIHZhbHVlcyB0byBza2lwIGFoZWFkIGZyb20gaTAsIGowLCBrMAoKICAgIHVuc2lnbmVkIGNoYXIgZm91bmQgPSBGQUxTRSA7CgogICAgbiA9IDEwMDAwMDAwMDAwMDAgOwoKICAgIGlmIChuID49IE5NSU4pIHsKICAgICAgICAvLyBnZXQgcmFuZ2Ugb2YgbG9nTQogICAgICAgIGxvZ00gPSBwb3coKDYuMCpsMipsMypsNSkqbixUSElSRCkgOwogICAgICAgIGxvZ01sbyA9IGxvZ00gLSBMT1dPRkZTRVQgOwogICAgICAgIGxvZ01oaSA9IGxvZ00gLSBISU9GRlNFVCA7CiAgICAKICAgICAgICBrbWF4ID0gZmxvb3IobG9nTWhpL2w1KSA7CiAgICAgICAgZm9yIChrID0gMCA7IGsgPD0ga21heCA7IGsrKykgewogICAgICAgICAgICBqbWF4ID0gZmxvb3IoKGxvZ01oaSAtIGsqbDUpL2wzKSA7CiAgICAgICAgICAgIGZvciAoaiA9IDAgOyBqIDw9IGptYXggOyBqKyspIHsKICAgICAgICAgICAgICAgIGltaW4gPSBjZWlsKChsb2dNbG8gLSBrKmw1IC0gaipsMykvbDIpIDsKICAgICAgICAgICAgICAgIGltYXggPSBmbG9vcigobG9nTWhpIC0gaypsNSAtIGoqbDMpL2wyKSA7CiAgICAgICAgICAgICAgICB0b3RuICs9IGltaW4gOwogICAgICAgICAgICAgICAgZm9yIChpID0gaW1pbiA7IGkgPD0gaW1heCA7IGkrKykgewogICAgICAgICAgICAgICAgICAgIGxvZ00gPSBpKmwyICsgaipsMyArIGsqbDUgOwogICAgICAgICAgICAgICAgICAgIGlmIChsb2dNIDwgbG9nTW1pbikgewogICAgICAgICAgICAgICAgICAgICAgICBsb2dNbWluID0gbG9nTSA7CiAgICAgICAgICAgICAgICAgICAgICAgIGkwID0gaSA7CiAgICAgICAgICAgICAgICAgICAgICAgIGowID0gaiA7CiAgICAgICAgICAgICAgICAgICAgICAgIGswID0gayA7CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIG5haGVhZCA9IG4gLSB0b3RuIC0gMSA7CiAgICAgICAgaGFtbWFoZWFkKG5haGVhZCwmaTAsJmowLCZrMCkgOwogICAgfQogICAgZWxzZSB7CgkJaW50IG0sIGluIDsKCQlpMCA9IDAgOwoJCWowID0gMCA7CgkJazAgPSAwIDsKCQlmb3IgKGluID0gMCA7IGluIDwgbi0xIDsgaW4rKykgewoJCSAgICBtID0gMCA7CgkJICAgIGZvdW5kID0gRkFMU0UgOwoJCSAgICB3aGlsZSAoIWZvdW5kICYmIG0gPCBOVEFCKSB7CgkJCSAgICBpZiAoaTAgKyBoYW10YWJbbV0ucDIgPj0gMCkKCQkJICAgICAgICBpZiAoajAgKyBoYW10YWJbbV0ucDMgPj0gMCkKCQkJICAgICAgICAgICAgaWYgKGswICsgaGFtdGFiW21dLnA1ID49IDApCgkJCQkJCSAgICBmb3VuZCA9IFRSVUUgOwoJCQkgICAgbSsrIDsKCQkgICAgfQoJCQltLS0gOwoJCQlpMCArPSBoYW10YWJbbV0ucDIgOwoJCQlqMCArPSBoYW10YWJbbV0ucDMgOwoJCQlrMCArPSBoYW10YWJbbV0ucDUgOwogICAgICAgIH0KICAgIH0KICAgIHByaW50ZigiJWQgJWQgJWRcbiIsaTAsajAsazApIDsgIC8vIG91dHB1dCBudGggaSxqLGsgdmFsdWVzCn0KCi8vIEZyb20gdGhlIEhhbW1pbmcgbnVtYmVyIDJeaTAqM15qMCo1XmswLCBza2lwIGFoZWFkCi8vIG5oZWFkIG51bWJlcnMgYW5kIHVwZGF0ZSBpMCwgajAgYW5kIGswIGFjY29yZGluZ2x5Lgp2b2lkIGhhbW1haGVhZCh1bnNpZ25lZCBsb25nIG5haGVhZCwgaW50ICppMCwgaW50ICpqMCwgaW50ICprMCkgewogICAgdW5zaWduZWQgY2hhciBrIDsKICAgIHVuc2lnbmVkIGxvbmcgaiA7CiAgICB1bnNpZ25lZCBjaGFyIGZvdW5kIDsKCiAgICBmb3IgKGogPSAwIDsgaiA8IG5haGVhZCA7IGorKykgewogICAgICAgIC8vIGZvciBlYWNoIEhhbW1pbmcgbnVtYmVyLCBmaW5kIHRoZSBtaW5pbXVtIGludGVydmFsIGluIGhhbXRhYgogICAgICAgIC8vIGkuZS4sIHRoZSBtaW5pbXVtIGVudHJ5IHdoZXJlIG11bHRpcGxpY2F0aW9uIHdvdWxkIHJlc3VsdAogICAgICAgIC8vIGluIHBvc2l0aXZlIHBvd2VycyBmb3IgaSwgaiAmIGsKICAgICAgICBrID0gMCA7CiAgICAgICAgZm91bmQgPSBGQUxTRSA7CiAgICAgICAgd2hpbGUgKCFmb3VuZCAmJiBrIDwgTlRBQikgewogICAgICAgICAgICBpZiAoKmkwICsgaGFtdGFiW2tdLnAyID49IDApCiAgICAgICAgICAgICAgICBpZiAoKmowICsgaGFtdGFiW2tdLnAzID49IDApCiAgICAgICAgICAgICAgICAgICAgaWYgKCprMCArIGhhbXRhYltrXS5wNSA+PSAwKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgZm91bmQgPSBUUlVFIDsKICAgICAgICAgICAgaWYgKCFmb3VuZCkKICAgICAgICAgICAgICAgIGsrKyA7CiAgICAgICAgfQoKICAgICAgICBpZiAoIWZvdW5kKSB7CiAgICAgICAgICAgIGZwcmludGYoc3RkZXJyLCJlcnJvcjogc3VpdGFibGUgdGFibGUgZW50cnkgbm90IGZvdW5kLCBqPSVsZFxuIixqKSA7CiAgICAgICAgICAgIGV4aXQoMSkgOwogICAgICAgIH0KICAgICAgICBlbHNlIHsKICAgICAgICAgICAgLy8gZ290IHRoZSBuZXh0IGludGVydmFsLCB1cGRhdGUgY291bnRzCiAgICAgICAgICAgICppMCArPSBoYW10YWJba10ucDIgOwogICAgICAgICAgICAqajAgKz0gaGFtdGFiW2tdLnAzIDsKICAgICAgICAgICAgKmswICs9IGhhbXRhYltrXS5wNSA7CiAgICAgICAgfQogICAgfQp9Cg==