from itertools import combinations
import threading
from collections import defaultdict
import math
from multiprocessing import Pool
# 配置参数(优化阈值)
TARGET = 6572 # 目标值
BASE_VALUES = [38.5,44,61,70.5,75.5,93] # 基础系数列表
FLUCTUATION = 1.0 # 系数波动范围
MAX_SOLUTIONS = 3 # 每个组合的最大解数量
SOLVER_TIMEOUT = 180 # 求解超时时间(秒)
THREE_VAR_THRESHOLD = 259000 # 使用三个变量的阈值
PRODUCT_RANGE_THRESHOLD = 129000 # 乘积范围限制阈值
HIGH_TARGET_THRESHOLD = 259000 # 更高目标值阈值
SHOW_PROGRESS = True # 是否显示进度
MAX_SOLUTIONS_PER_COMB = 100 # 每个组合的最大解数量,用于提前终止
USE_MULTIPROCESSING = True # 是否使用多进程加速
def is_valid_product(p):
"""确保单个乘积不超过129000"""
return p <= 129000 # 严格限制所有乘积不超过129000
def find_single_variable_solutions(values):
"""查找单个数的解(a*x = TARGET)"""
solutions = []
for a in values:
quotient = TARGET / a
if quotient != int(quotient):
continue
x = int(quotient)
if 1 <= x <= 10000 and is_valid_product(a * x):
solutions.append((a, x))
if len(solutions) >= MAX_SOLUTIONS:
break
return solutions
def find_two_variable_solutions(values):
"""优化的双变量求解算法,确保每个乘积不超过129000"""
solutions = defaultdict(list)
for i, a in enumerate(values):
for b in values[i:]:
seen_xy = set()
# 调整x的最大值,确保a*x不超过129000
max_x
= min
(math.
floor((TARGET
- b
) / a
), math.
floor(129000 / a
)) min_x
= max
(1, math.
ceil((TARGET
- b
* 10000) / a
))
if max_x < min_x:
continue
x_count = max_x - min_x + 1
x_step = max(1, x_count // 1000)
for x in range(min_x, max_x + 1, x_step):
ax = a * x
if ax > 129000: # 额外检查确保不超过129000
continue
remainder = TARGET - ax
if remainder < b:
break
if remainder > b * 10000:
continue
if remainder % b == 0:
y = remainder // b
by = b * y
if 1 <= y <= 10000 and by <= 129000: # 确保b*y也不超过129000
xy_pair = (x, y) if a <= b else (y, x)
if xy_pair not in seen_xy:
seen_xy.add(xy_pair)
solutions[(a, b)].append((a, x, b, y))
if len(solutions[(a, b)]) >= MAX_SOLUTIONS_PER_COMB:
break
return solutions
def process_three_var_combination(args):
"""处理三变量组合的辅助函数,用于并行计算"""
a, b, c, value_ranges, target = args
solutions = []
seen_xyz = set()
min_x, max_x = value_ranges[a]
x_count = max_x - min_x + 1
x_step = max(1, x_count // 1000)
for x in range(min_x, max_x + 1, x_step):
ax = a * x
if not is_valid_product(ax):
continue
remainder1 = target - ax
if remainder1 < 0:
break
max_y
= math.
floor((remainder1
- c
) / b
) min_y
= max
(1, math.
ceil((remainder1
- c
* 10000) / b
))
if max_y < min_y:
continue
y_count = max_y - min_y + 1
y_step = max(1, y_count // 100)
for y in range(min_y, max_y + 1, y_step):
by = b * y
if not is_valid_product(by):
continue
remainder2 = remainder1 - by
if remainder2 < 0:
break
if remainder2 > c * 10000:
continue
if remainder2 % c == 0:
z = remainder2 // c
if 1 <= z <= 10000 and is_valid_product(c * z):
xyz_tuple = tuple(sorted([x, y, z]))
if xyz_tuple not in seen_xyz:
seen_xyz.add(xyz_tuple)
solutions.append((a, x, b, y, c, z))
if len(solutions) >= MAX_SOLUTIONS_PER_COMB:
return solutions
return solutions
def find_three_variable_solutions(values):
"""优化的三变量求解算法,确保每个乘积不超过129000"""
solutions = defaultdict(list)
sorted_values = sorted(values)
# 预计算每个系数的有效范围,确保每个乘积不超过129000
value_ranges = {}
for a in sorted_values:
min_x
= max
(1, math.
ceil(1 / a
)) # 最小为1 max_x
= min
(10000, math.
floor(129000 / a
)) # 确保a*x <= 129000 value_ranges[a] = (min_x, max_x)
combinations_list = []
for i, a in enumerate(sorted_values):
for j in range(i + 1, len(sorted_values)):
b = sorted_values[j]
for k in range(j + 1, len(sorted_values)):
c = sorted_values[k]
combinations_list.append((a, b, c, value_ranges, TARGET))
if USE_MULTIPROCESSING:
with Pool() as pool:
results = pool.map(process_three_var_combination, combinations_list)
for i, (a, b, c, _, _) in enumerate(combinations_list):
if results[i]:
solutions[(a, b, c)] = results[i]
else:
total_combinations = len(combinations_list)
for i, (a, b, c, _, _) in enumerate(combinations_list):
res = process_three_var_combination((a, b, c, value_ranges, TARGET))
if res:
solutions[(a, b, c)] = res
if SHOW_PROGRESS and i % 10 == 0:
print(f"\r三变量组合进度: {i}/{total_combinations} 组", end='')
if SHOW_PROGRESS and not USE_MULTIPROCESSING:
print(f"\r三变量组合进度: {total_combinations}/{total_combinations} 组 - 完成")
return solutions
def find_balanced_solutions(solutions, var_count, num=2):
"""从所有解中筛选出最平衡的解"""
if var_count == 1 or not solutions:
return solutions
balanced = []
for sol in solutions:
vars = sol[1::2] # 获取解中的变量值
diff = max(vars) - min(vars) # 计算变量之间的最大差值
balanced.append((diff, sol))
# 按差值排序,返回差值最小的解
return [s for _, s in sorted(balanced, key=lambda x: x[0])[:num]]
def find_original_solutions(solutions, balanced_solutions, num=3):
"""从剩余解中获取原始顺序的解"""
if not solutions:
return []
remaining = [s for s in solutions if s not in balanced_solutions]
return remaining[:num]
def display_solutions(solutions_dict, var_count):
"""优化的解显示函数"""
if not solutions_dict:
return
print(f"\n找到 {len(solutions_dict)} 组{var_count}变量解:")
for i, (coeffs, pair_solutions) in enumerate(sorted(solutions_dict.items()), 1):
balanced = find_balanced_solutions(pair_solutions, var_count)
original = find_original_solutions(pair_solutions, balanced)
all_display = balanced + original
if var_count == 1:
a = coeffs
print(f"\n{i}. 组合: a={a} ({len(pair_solutions)} 个有效解)")
elif var_count == 2:
a, b = coeffs
print(f"\n{i}. 组合: a={a}, b={b} ({len(pair_solutions)} 个有效解)")
else:
a, b, c = coeffs
print(f"\n{i}. 组合: a={a}, b={b}, c={c} ({len(pair_solutions)} 个有效解)")
for j, sol in enumerate(all_display, 1):
tag = "[平衡解]" if j <= len(balanced) else "[原始解]"
if var_count == 1:
a, x = sol
print(f" {j}. x={x}, a*x={a*x:.1f}, 总和={a*x:.1f} {tag}")
elif var_count == 2:
a, x, b, y = sol
print(f" {j}. x={x}, y={y}, a*x={a*x:.1f}, b*y={b*y:.1f}, 总和={a*x + b*y:.1f} {tag}")
else:
a, x, b, y, c, z = sol
print(f" {j}. x={x}, y={y}, z={z}, "
f"a*x={a*x:.1f}, b*y={b*y:.1f}, c*z={c*z:.1f}, "
f"总和={a*x + b*y + c*z:.1f} {tag}")
def run_with_timeout(func, args=(), kwargs=None, timeout=SOLVER_TIMEOUT):
"""运行函数并设置超时限制"""
if kwargs is None:
kwargs = {}
result = []
error = []
def wrapper():
try:
result.append(func(*args, **kwargs))
except Exception as e:
error.append(e)
thread = threading.Thread(target=wrapper)
thread.daemon = True
thread.start()
thread.join(timeout)
if thread.is_alive():
print(f"警告: {func.__name__} 超时({timeout}秒),跳过此方法")
return None
if error:
return result[0]
def main():
print(f"目标值: {TARGET}")
# 生成波动后的系数
FLUCTUATED_VALUES = [round(v - FLUCTUATION, 1) for v in BASE_VALUES]
# 尝试基础系数
print(f"\n==== 尝试基础系数 ====")
# 目标值255966 > 259000不成立,会按顺序尝试单、双、三变量解
base_solutions = {
'single': run_with_timeout(find_single_variable_solutions, args=(BASE_VALUES,)),
'two': run_with_timeout(find_two_variable_solutions, args=(BASE_VALUES,)),
'three': []
}
has_solution = False
# 显示单变量解
if base_solutions['single']:
has_solution = True
display_solutions({a: [sol] for a, sol in zip(BASE_VALUES, base_solutions['single']) if sol}, 1)
# 显示双变量解
if base_solutions['two'] and len(base_solutions['two']) > 0:
has_solution = True
display_solutions(base_solutions['two'], 2)
# 单变量和双变量都无解时,尝试三变量解
if not has_solution:
print(f"\n==== 单变量和双变量无解,尝试三变量解 ====")
base_solutions['three'] = run_with_timeout(find_three_variable_solutions, args=(BASE_VALUES,))
if base_solutions['three'] and len(base_solutions['three']) > 0:
has_solution = True
display_solutions(base_solutions['three'], 3)
if has_solution:
print(f"\n使用基础系数列表,共找到有效解")
return
# 如果基础系数没有找到解,尝试波动系数
print(f"\n==== 尝试波动系数 ====")
fluctuated_solutions = {
'single': run_with_timeout(find_single_variable_solutions, args=(FLUCTUATED_VALUES,)),
'two': run_with_timeout(find_two_variable_solutions, args=(FLUCTUATED_VALUES,)),
'three': []
}
has_solution = False
# 显示单变量解
if fluctuated_solutions['single']:
has_solution = True
display_solutions({a: [sol] for a, sol in zip(FLUCTUATED_VALUES, fluctuated_solutions['single']) if sol}, 1)
# 显示双变量解
if fluctuated_solutions['two'] and len(fluctuated_solutions['two']) > 0:
has_solution = True
display_solutions(fluctuated_solutions['two'], 2)
# 单变量和双变量都无解时,尝试三变量解
if not has_solution:
print(f"\n==== 单变量和双变量无解,尝试三变量解 ====")
fluctuated_solutions['three'] = run_with_timeout(find_three_variable_solutions, args=(FLUCTUATED_VALUES,))
if fluctuated_solutions['three'] and len(fluctuated_solutions['three']) > 0:
has_solution = True
display_solutions(fluctuated_solutions['three'], 3)
if has_solution:
print(f"\n使用波动系数列表,共找到有效解")
return
# 如果所有系数集都没有找到解
print("\n没有找到符合条件的解,即使使用波动后的系数列表。")
if __name__ == "__main__":
main()
print(f"\n总耗时: {time.time() - start_time:.2f}秒")
ZnJvbSBpdGVydG9vbHMgaW1wb3J0IGNvbWJpbmF0aW9ucwppbXBvcnQgdGltZQppbXBvcnQgdGhyZWFkaW5nCmZyb20gY29sbGVjdGlvbnMgaW1wb3J0IGRlZmF1bHRkaWN0CmltcG9ydCBtYXRoCmZyb20gbXVsdGlwcm9jZXNzaW5nIGltcG9ydCBQb29sCgojIOmFjee9ruWPguaVsO+8iOS8mOWMlumYiOWAvO+8iQpUQVJHRVQgPSA2NTcyICAjIOebruagh+WAvApCQVNFX1ZBTFVFUyA9IFszOC41LDQ0LDYxLDcwLjUsNzUuNSw5M10gIyDln7rnoYDns7vmlbDliJfooagKRkxVQ1RVQVRJT04gPSAxLjAgICMg57O75pWw5rOi5Yqo6IyD5Zu0Ck1BWF9TT0xVVElPTlMgPSAzICAjIOavj+S4que7hOWQiOeahOacgOWkp+ino+aVsOmHjwpTT0xWRVJfVElNRU9VVCA9IDE4MCAgIyDmsYLop6PotoXml7bml7bpl7Qo56eSKQpUSFJFRV9WQVJfVEhSRVNIT0xEID0gMjU5MDAwICAjIOS9v+eUqOS4ieS4quWPmOmHj+eahOmYiOWAvApQUk9EVUNUX1JBTkdFX1RIUkVTSE9MRCA9IDEyOTAwMCAgIyDkuZjnp6/ojIPlm7TpmZDliLbpmIjlgLwKSElHSF9UQVJHRVRfVEhSRVNIT0xEID0gMjU5MDAwICAjIOabtOmrmOebruagh+WAvOmYiOWAvApTSE9XX1BST0dSRVNTID0gVHJ1ZSAgIyDmmK/lkKbmmL7npLrov5vluqYKTUFYX1NPTFVUSU9OU19QRVJfQ09NQiA9IDEwMCAgIyDmr4/kuKrnu4TlkIjnmoTmnIDlpKfop6PmlbDph4/vvIznlKjkuo7mj5DliY3nu4jmraIKVVNFX01VTFRJUFJPQ0VTU0lORyA9IFRydWUgICMg5piv5ZCm5L2/55So5aSa6L+b56iL5Yqg6YCfCgpkZWYgaXNfdmFsaWRfcHJvZHVjdChwKToKICAgICIiIuehruS/neWNleS4quS5mOenr+S4jei2hei/hzEyOTAwMCIiIgogICAgcmV0dXJuIHAgPD0gMTI5MDAwICAjIOS4peagvOmZkOWItuaJgOacieS5mOenr+S4jei2hei/hzEyOTAwMAoKZGVmIGZpbmRfc2luZ2xlX3ZhcmlhYmxlX3NvbHV0aW9ucyh2YWx1ZXMpOgogICAgIiIi5p+l5om+5Y2V5Liq5pWw55qE6Kej77yIYSp4ID0gVEFSR0VU77yJIiIiCiAgICBzb2x1dGlvbnMgPSBbXQogICAgZm9yIGEgaW4gdmFsdWVzOgogICAgICAgIHF1b3RpZW50ID0gVEFSR0VUIC8gYQogICAgICAgIGlmIHF1b3RpZW50ICE9IGludChxdW90aWVudCk6CiAgICAgICAgICAgIGNvbnRpbnVlCiAgICAgICAgeCA9IGludChxdW90aWVudCkKICAgICAgICBpZiAxIDw9IHggPD0gMTAwMDAgYW5kIGlzX3ZhbGlkX3Byb2R1Y3QoYSAqIHgpOgogICAgICAgICAgICBzb2x1dGlvbnMuYXBwZW5kKChhLCB4KSkKICAgICAgICAgICAgaWYgbGVuKHNvbHV0aW9ucykgPj0gTUFYX1NPTFVUSU9OUzoKICAgICAgICAgICAgICAgIGJyZWFrCiAgICByZXR1cm4gc29sdXRpb25zCgpkZWYgZmluZF90d29fdmFyaWFibGVfc29sdXRpb25zKHZhbHVlcyk6CiAgICAiIiLkvJjljJbnmoTlj4zlj5jph4/msYLop6Pnrpfms5XvvIznoa7kv53mr4/kuKrkuZjnp6/kuI3otoXov4cxMjkwMDAiIiIKICAgIHNvbHV0aW9ucyA9IGRlZmF1bHRkaWN0KGxpc3QpCiAgICBmb3IgaSwgYSBpbiBlbnVtZXJhdGUodmFsdWVzKToKICAgICAgICBmb3IgYiBpbiB2YWx1ZXNbaTpdOgogICAgICAgICAgICBzZWVuX3h5ID0gc2V0KCkKICAgICAgICAgICAgIyDosIPmlbR455qE5pyA5aSn5YC877yM56Gu5L+dYSp45LiN6LaF6L+HMTI5MDAwCiAgICAgICAgICAgIG1heF94ID0gbWluKG1hdGguZmxvb3IoKFRBUkdFVCAtIGIpIC8gYSksIG1hdGguZmxvb3IoMTI5MDAwIC8gYSkpCiAgICAgICAgICAgIG1pbl94ID0gbWF4KDEsIG1hdGguY2VpbCgoVEFSR0VUIC0gYiAqIDEwMDAwKSAvIGEpKQogICAgICAgICAgICAKICAgICAgICAgICAgaWYgbWF4X3ggPCBtaW5feDoKICAgICAgICAgICAgICAgIGNvbnRpbnVlCiAgICAgICAgICAgICAgICAKICAgICAgICAgICAgeF9jb3VudCA9IG1heF94IC0gbWluX3ggKyAxCiAgICAgICAgICAgIHhfc3RlcCA9IG1heCgxLCB4X2NvdW50IC8vIDEwMDApCiAgICAgICAgICAgIAogICAgICAgICAgICBmb3IgeCBpbiByYW5nZShtaW5feCwgbWF4X3ggKyAxLCB4X3N0ZXApOgogICAgICAgICAgICAgICAgYXggPSBhICogeAogICAgICAgICAgICAgICAgaWYgYXggPiAxMjkwMDA6ICAjIOmineWkluajgOafpeehruS/neS4jei2hei/hzEyOTAwMAogICAgICAgICAgICAgICAgICAgIGNvbnRpbnVlCiAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICByZW1haW5kZXIgPSBUQVJHRVQgLSBheAogICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICBpZiByZW1haW5kZXIgPCBiOgogICAgICAgICAgICAgICAgICAgIGJyZWFrCiAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICBpZiByZW1haW5kZXIgPiBiICogMTAwMDA6CiAgICAgICAgICAgICAgICAgICAgY29udGludWUKICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgIGlmIHJlbWFpbmRlciAlIGIgPT0gMDoKICAgICAgICAgICAgICAgICAgICB5ID0gcmVtYWluZGVyIC8vIGIKICAgICAgICAgICAgICAgICAgICBieSA9IGIgKiB5CiAgICAgICAgICAgICAgICAgICAgaWYgMSA8PSB5IDw9IDEwMDAwIGFuZCBieSA8PSAxMjkwMDA6ICAjIOehruS/nWIqeeS5n+S4jei2hei/hzEyOTAwMAogICAgICAgICAgICAgICAgICAgICAgICB4eV9wYWlyID0gKHgsIHkpIGlmIGEgPD0gYiBlbHNlICh5LCB4KQogICAgICAgICAgICAgICAgICAgICAgICBpZiB4eV9wYWlyIG5vdCBpbiBzZWVuX3h5OgogICAgICAgICAgICAgICAgICAgICAgICAgICAgc2Vlbl94eS5hZGQoeHlfcGFpcikKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNvbHV0aW9uc1soYSwgYildLmFwcGVuZCgoYSwgeCwgYiwgeSkpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiBsZW4oc29sdXRpb25zWyhhLCBiKV0pID49IE1BWF9TT0xVVElPTlNfUEVSX0NPTUI6CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWsKICAgIHJldHVybiBzb2x1dGlvbnMKCmRlZiBwcm9jZXNzX3RocmVlX3Zhcl9jb21iaW5hdGlvbihhcmdzKToKICAgICIiIuWkhOeQhuS4ieWPmOmHj+e7hOWQiOeahOi+heWKqeWHveaVsO+8jOeUqOS6juW5tuihjOiuoeeulyIiIgogICAgYSwgYiwgYywgdmFsdWVfcmFuZ2VzLCB0YXJnZXQgPSBhcmdzCiAgICBzb2x1dGlvbnMgPSBbXQogICAgc2Vlbl94eXogPSBzZXQoKQogICAgCiAgICBtaW5feCwgbWF4X3ggPSB2YWx1ZV9yYW5nZXNbYV0KICAgIHhfY291bnQgPSBtYXhfeCAtIG1pbl94ICsgMQogICAgeF9zdGVwID0gbWF4KDEsIHhfY291bnQgLy8gMTAwMCkKICAgIAogICAgZm9yIHggaW4gcmFuZ2UobWluX3gsIG1heF94ICsgMSwgeF9zdGVwKToKICAgICAgICBheCA9IGEgKiB4CiAgICAgICAgaWYgbm90IGlzX3ZhbGlkX3Byb2R1Y3QoYXgpOgogICAgICAgICAgICBjb250aW51ZQogICAgICAgICAgICAKICAgICAgICByZW1haW5kZXIxID0gdGFyZ2V0IC0gYXgKICAgICAgICBpZiByZW1haW5kZXIxIDwgMDoKICAgICAgICAgICAgYnJlYWsKICAgICAgICAgICAgCiAgICAgICAgbWF4X3kgPSBtYXRoLmZsb29yKChyZW1haW5kZXIxIC0gYykgLyBiKQogICAgICAgIG1pbl95ID0gbWF4KDEsIG1hdGguY2VpbCgocmVtYWluZGVyMSAtIGMgKiAxMDAwMCkgLyBiKSkKICAgICAgICAKICAgICAgICBpZiBtYXhfeSA8IG1pbl95OgogICAgICAgICAgICBjb250aW51ZQogICAgICAgICAgICAKICAgICAgICB5X2NvdW50ID0gbWF4X3kgLSBtaW5feSArIDEKICAgICAgICB5X3N0ZXAgPSBtYXgoMSwgeV9jb3VudCAvLyAxMDApCiAgICAgICAgCiAgICAgICAgZm9yIHkgaW4gcmFuZ2UobWluX3ksIG1heF95ICsgMSwgeV9zdGVwKToKICAgICAgICAgICAgYnkgPSBiICogeQogICAgICAgICAgICBpZiBub3QgaXNfdmFsaWRfcHJvZHVjdChieSk6CiAgICAgICAgICAgICAgICBjb250aW51ZQogICAgICAgICAgICAgICAgCiAgICAgICAgICAgIHJlbWFpbmRlcjIgPSByZW1haW5kZXIxIC0gYnkKICAgICAgICAgICAgaWYgcmVtYWluZGVyMiA8IDA6CiAgICAgICAgICAgICAgICBicmVhawogICAgICAgICAgICAgICAgCiAgICAgICAgICAgIGlmIHJlbWFpbmRlcjIgPiBjICogMTAwMDA6CiAgICAgICAgICAgICAgICBjb250aW51ZQogICAgICAgICAgICAgICAgCiAgICAgICAgICAgIGlmIHJlbWFpbmRlcjIgJSBjID09IDA6CiAgICAgICAgICAgICAgICB6ID0gcmVtYWluZGVyMiAvLyBjCiAgICAgICAgICAgICAgICBpZiAxIDw9IHogPD0gMTAwMDAgYW5kIGlzX3ZhbGlkX3Byb2R1Y3QoYyAqIHopOgogICAgICAgICAgICAgICAgICAgIHh5el90dXBsZSA9IHR1cGxlKHNvcnRlZChbeCwgeSwgel0pKQogICAgICAgICAgICAgICAgICAgIGlmIHh5el90dXBsZSBub3QgaW4gc2Vlbl94eXo6CiAgICAgICAgICAgICAgICAgICAgICAgIHNlZW5feHl6LmFkZCh4eXpfdHVwbGUpCiAgICAgICAgICAgICAgICAgICAgICAgIHNvbHV0aW9ucy5hcHBlbmQoKGEsIHgsIGIsIHksIGMsIHopKQogICAgICAgICAgICAgICAgICAgICAgICBpZiBsZW4oc29sdXRpb25zKSA+PSBNQVhfU09MVVRJT05TX1BFUl9DT01COgogICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHNvbHV0aW9ucwogICAgCiAgICByZXR1cm4gc29sdXRpb25zCgpkZWYgZmluZF90aHJlZV92YXJpYWJsZV9zb2x1dGlvbnModmFsdWVzKToKICAgICIiIuS8mOWMlueahOS4ieWPmOmHj+axguino+eul+azle+8jOehruS/neavj+S4quS5mOenr+S4jei2hei/hzEyOTAwMCIiIgogICAgc29sdXRpb25zID0gZGVmYXVsdGRpY3QobGlzdCkKICAgIHNvcnRlZF92YWx1ZXMgPSBzb3J0ZWQodmFsdWVzKQogICAgCiAgICAjIOmihOiuoeeul+avj+S4quezu+aVsOeahOacieaViOiMg+WbtO+8jOehruS/neavj+S4quS5mOenr+S4jei2hei/hzEyOTAwMAogICAgdmFsdWVfcmFuZ2VzID0ge30KICAgIGZvciBhIGluIHNvcnRlZF92YWx1ZXM6CiAgICAgICAgbWluX3ggPSBtYXgoMSwgbWF0aC5jZWlsKDEgLyBhKSkgICMg5pyA5bCP5Li6MQogICAgICAgIG1heF94ID0gbWluKDEwMDAwLCBtYXRoLmZsb29yKDEyOTAwMCAvIGEpKSAgIyDnoa7kv51hKnggPD0gMTI5MDAwCiAgICAgICAgdmFsdWVfcmFuZ2VzW2FdID0gKG1pbl94LCBtYXhfeCkKICAgIAogICAgY29tYmluYXRpb25zX2xpc3QgPSBbXQogICAgZm9yIGksIGEgaW4gZW51bWVyYXRlKHNvcnRlZF92YWx1ZXMpOgogICAgICAgIGZvciBqIGluIHJhbmdlKGkgKyAxLCBsZW4oc29ydGVkX3ZhbHVlcykpOgogICAgICAgICAgICBiID0gc29ydGVkX3ZhbHVlc1tqXQogICAgICAgICAgICBmb3IgayBpbiByYW5nZShqICsgMSwgbGVuKHNvcnRlZF92YWx1ZXMpKToKICAgICAgICAgICAgICAgIGMgPSBzb3J0ZWRfdmFsdWVzW2tdCiAgICAgICAgICAgICAgICBjb21iaW5hdGlvbnNfbGlzdC5hcHBlbmQoKGEsIGIsIGMsIHZhbHVlX3JhbmdlcywgVEFSR0VUKSkKICAgIAogICAgaWYgVVNFX01VTFRJUFJPQ0VTU0lORzoKICAgICAgICB3aXRoIFBvb2woKSBhcyBwb29sOgogICAgICAgICAgICByZXN1bHRzID0gcG9vbC5tYXAocHJvY2Vzc190aHJlZV92YXJfY29tYmluYXRpb24sIGNvbWJpbmF0aW9uc19saXN0KQogICAgICAgIAogICAgICAgIGZvciBpLCAoYSwgYiwgYywgXywgXykgaW4gZW51bWVyYXRlKGNvbWJpbmF0aW9uc19saXN0KToKICAgICAgICAgICAgaWYgcmVzdWx0c1tpXToKICAgICAgICAgICAgICAgIHNvbHV0aW9uc1soYSwgYiwgYyldID0gcmVzdWx0c1tpXQogICAgZWxzZToKICAgICAgICB0b3RhbF9jb21iaW5hdGlvbnMgPSBsZW4oY29tYmluYXRpb25zX2xpc3QpCiAgICAgICAgZm9yIGksIChhLCBiLCBjLCBfLCBfKSBpbiBlbnVtZXJhdGUoY29tYmluYXRpb25zX2xpc3QpOgogICAgICAgICAgICByZXMgPSBwcm9jZXNzX3RocmVlX3Zhcl9jb21iaW5hdGlvbigoYSwgYiwgYywgdmFsdWVfcmFuZ2VzLCBUQVJHRVQpKQogICAgICAgICAgICBpZiByZXM6CiAgICAgICAgICAgICAgICBzb2x1dGlvbnNbKGEsIGIsIGMpXSA9IHJlcwogICAgICAgICAgICAKICAgICAgICAgICAgaWYgU0hPV19QUk9HUkVTUyBhbmQgaSAlIDEwID09IDA6CiAgICAgICAgICAgICAgICBwcmludChmIlxy5LiJ5Y+Y6YeP57uE5ZCI6L+b5bqmOiB7aX0ve3RvdGFsX2NvbWJpbmF0aW9uc30g57uEIiwgZW5kPScnKQogICAgCiAgICBpZiBTSE9XX1BST0dSRVNTIGFuZCBub3QgVVNFX01VTFRJUFJPQ0VTU0lORzoKICAgICAgICBwcmludChmIlxy5LiJ5Y+Y6YeP57uE5ZCI6L+b5bqmOiB7dG90YWxfY29tYmluYXRpb25zfS97dG90YWxfY29tYmluYXRpb25zfSDnu4QgLSDlrozmiJAiKQogICAgCiAgICByZXR1cm4gc29sdXRpb25zCgpkZWYgZmluZF9iYWxhbmNlZF9zb2x1dGlvbnMoc29sdXRpb25zLCB2YXJfY291bnQsIG51bT0yKToKICAgICIiIuS7juaJgOacieino+S4reetm+mAieWHuuacgOW5s+ihoeeahOinoyIiIgogICAgaWYgdmFyX2NvdW50ID09IDEgb3Igbm90IHNvbHV0aW9uczoKICAgICAgICByZXR1cm4gc29sdXRpb25zCiAgICAKICAgIGJhbGFuY2VkID0gW10KICAgIGZvciBzb2wgaW4gc29sdXRpb25zOgogICAgICAgIHZhcnMgPSBzb2xbMTo6Ml0gICMg6I635Y+W6Kej5Lit55qE5Y+Y6YeP5YC8CiAgICAgICAgZGlmZiA9IG1heCh2YXJzKSAtIG1pbih2YXJzKSAgIyDorqHnrpflj5jph4/kuYvpl7TnmoTmnIDlpKflt67lgLwKICAgICAgICBiYWxhbmNlZC5hcHBlbmQoKGRpZmYsIHNvbCkpCiAgICAKICAgICMg5oyJ5beu5YC85o6S5bqP77yM6L+U5Zue5beu5YC85pyA5bCP55qE6KejCiAgICByZXR1cm4gW3MgZm9yIF8sIHMgaW4gc29ydGVkKGJhbGFuY2VkLCBrZXk9bGFtYmRhIHg6IHhbMF0pWzpudW1dXQoKZGVmIGZpbmRfb3JpZ2luYWxfc29sdXRpb25zKHNvbHV0aW9ucywgYmFsYW5jZWRfc29sdXRpb25zLCBudW09Myk6CiAgICAiIiLku47liankvZnop6PkuK3ojrflj5bljp/lp4vpobrluo/nmoTop6MiIiIKICAgIGlmIG5vdCBzb2x1dGlvbnM6CiAgICAgICAgcmV0dXJuIFtdCiAgICAKICAgIHJlbWFpbmluZyA9IFtzIGZvciBzIGluIHNvbHV0aW9ucyBpZiBzIG5vdCBpbiBiYWxhbmNlZF9zb2x1dGlvbnNdCiAgICByZXR1cm4gcmVtYWluaW5nWzpudW1dCgpkZWYgZGlzcGxheV9zb2x1dGlvbnMoc29sdXRpb25zX2RpY3QsIHZhcl9jb3VudCk6CiAgICAiIiLkvJjljJbnmoTop6PmmL7npLrlh73mlbAiIiIKICAgIGlmIG5vdCBzb2x1dGlvbnNfZGljdDoKICAgICAgICByZXR1cm4KICAgIAogICAgcHJpbnQoZiJcbuaJvuWIsCB7bGVuKHNvbHV0aW9uc19kaWN0KX0g57uEe3Zhcl9jb3VudH3lj5jph4/op6PvvJoiKQogICAgCiAgICBmb3IgaSwgKGNvZWZmcywgcGFpcl9zb2x1dGlvbnMpIGluIGVudW1lcmF0ZShzb3J0ZWQoc29sdXRpb25zX2RpY3QuaXRlbXMoKSksIDEpOgogICAgICAgIGJhbGFuY2VkID0gZmluZF9iYWxhbmNlZF9zb2x1dGlvbnMocGFpcl9zb2x1dGlvbnMsIHZhcl9jb3VudCkKICAgICAgICBvcmlnaW5hbCA9IGZpbmRfb3JpZ2luYWxfc29sdXRpb25zKHBhaXJfc29sdXRpb25zLCBiYWxhbmNlZCkKICAgICAgICBhbGxfZGlzcGxheSA9IGJhbGFuY2VkICsgb3JpZ2luYWwKICAgICAgICAKICAgICAgICBpZiB2YXJfY291bnQgPT0gMToKICAgICAgICAgICAgYSA9IGNvZWZmcwogICAgICAgICAgICBwcmludChmIlxue2l9LiDnu4TlkIg6IGE9e2F9ICh7bGVuKHBhaXJfc29sdXRpb25zKX0g5Liq5pyJ5pWI6KejKSIpCiAgICAgICAgZWxpZiB2YXJfY291bnQgPT0gMjoKICAgICAgICAgICAgYSwgYiA9IGNvZWZmcwogICAgICAgICAgICBwcmludChmIlxue2l9LiDnu4TlkIg6IGE9e2F9LCBiPXtifSAoe2xlbihwYWlyX3NvbHV0aW9ucyl9IOS4quacieaViOinoykiKQogICAgICAgIGVsc2U6CiAgICAgICAgICAgIGEsIGIsIGMgPSBjb2VmZnMKICAgICAgICAgICAgcHJpbnQoZiJcbntpfS4g57uE5ZCIOiBhPXthfSwgYj17Yn0sIGM9e2N9ICh7bGVuKHBhaXJfc29sdXRpb25zKX0g5Liq5pyJ5pWI6KejKSIpCiAgICAgICAgCiAgICAgICAgZm9yIGosIHNvbCBpbiBlbnVtZXJhdGUoYWxsX2Rpc3BsYXksIDEpOgogICAgICAgICAgICB0YWcgPSAiW+W5s+ihoeino10iIGlmIGogPD0gbGVuKGJhbGFuY2VkKSBlbHNlICJb5Y6f5aeL6KejXSIKICAgICAgICAgICAgCiAgICAgICAgICAgIGlmIHZhcl9jb3VudCA9PSAxOgogICAgICAgICAgICAgICAgYSwgeCA9IHNvbAogICAgICAgICAgICAgICAgcHJpbnQoZiIgIHtqfS4geD17eH0sIGEqeD17YSp4Oi4xZn0sIOaAu+WSjD17YSp4Oi4xZn0ge3RhZ30iKQogICAgICAgICAgICBlbGlmIHZhcl9jb3VudCA9PSAyOgogICAgICAgICAgICAgICAgYSwgeCwgYiwgeSA9IHNvbAogICAgICAgICAgICAgICAgcHJpbnQoZiIgIHtqfS4geD17eH0sIHk9e3l9LCBhKng9e2EqeDouMWZ9LCBiKnk9e2IqeTouMWZ9LCDmgLvlkow9e2EqeCArIGIqeTouMWZ9IHt0YWd9IikKICAgICAgICAgICAgZWxzZToKICAgICAgICAgICAgICAgIGEsIHgsIGIsIHksIGMsIHogPSBzb2wKICAgICAgICAgICAgICAgIHByaW50KGYiICB7an0uIHg9e3h9LCB5PXt5fSwgej17en0sICIKICAgICAgICAgICAgICAgICAgICAgIGYiYSp4PXthKng6LjFmfSwgYip5PXtiKnk6LjFmfSwgYyp6PXtjKno6LjFmfSwgIgogICAgICAgICAgICAgICAgICAgICAgZiLmgLvlkow9e2EqeCArIGIqeSArIGMqejouMWZ9IHt0YWd9IikKCmRlZiBydW5fd2l0aF90aW1lb3V0KGZ1bmMsIGFyZ3M9KCksIGt3YXJncz1Ob25lLCB0aW1lb3V0PVNPTFZFUl9USU1FT1VUKToKICAgICIiIui/kOihjOWHveaVsOW5tuiuvue9rui2heaXtumZkOWItiIiIgogICAgaWYga3dhcmdzIGlzIE5vbmU6CiAgICAgICAga3dhcmdzID0ge30KICAgIAogICAgcmVzdWx0ID0gW10KICAgIGVycm9yID0gW10KICAgIAogICAgZGVmIHdyYXBwZXIoKToKICAgICAgICB0cnk6CiAgICAgICAgICAgIHJlc3VsdC5hcHBlbmQoZnVuYygqYXJncywgKiprd2FyZ3MpKQogICAgICAgIGV4Y2VwdCBFeGNlcHRpb24gYXMgZToKICAgICAgICAgICAgZXJyb3IuYXBwZW5kKGUpCiAgICAKICAgIHRocmVhZCA9IHRocmVhZGluZy5UaHJlYWQodGFyZ2V0PXdyYXBwZXIpCiAgICB0aHJlYWQuZGFlbW9uID0gVHJ1ZQogICAgdGhyZWFkLnN0YXJ0KCkKICAgIHRocmVhZC5qb2luKHRpbWVvdXQpCiAgICAKICAgIGlmIHRocmVhZC5pc19hbGl2ZSgpOgogICAgICAgIHByaW50KGYi6K2m5ZGKOiB7ZnVuYy5fX25hbWVfX30g6LaF5pe277yIe3RpbWVvdXR956eS77yJ77yM6Lez6L+H5q2k5pa55rOVIikKICAgICAgICByZXR1cm4gTm9uZQogICAgCiAgICBpZiBlcnJvcjoKICAgICAgICByYWlzZSBlcnJvclswXQogICAgCiAgICByZXR1cm4gcmVzdWx0WzBdCgpkZWYgbWFpbigpOgogICAgcHJpbnQoZiLnm67moIflgLw6IHtUQVJHRVR9IikKICAgIAogICAgIyDnlJ/miJDms6LliqjlkI7nmoTns7vmlbAKICAgIEZMVUNUVUFURURfVkFMVUVTID0gW3JvdW5kKHYgLSBGTFVDVFVBVElPTiwgMSkgZm9yIHYgaW4gQkFTRV9WQUxVRVNdCiAgICAKICAgICMg5bCd6K+V5Z+656GA57O75pWwCiAgICBwcmludChmIlxuPT09PSDlsJ3or5Xln7rnoYDns7vmlbAgPT09PSIpCiAgICAKICAgICMg55uu5qCH5YC8MjU1OTY2ID4gMjU5MDAw5LiN5oiQ56uL77yM5Lya5oyJ6aG65bqP5bCd6K+V5Y2V44CB5Y+M44CB5LiJ5Y+Y6YeP6KejCiAgICBiYXNlX3NvbHV0aW9ucyA9IHsKICAgICAgICAnc2luZ2xlJzogcnVuX3dpdGhfdGltZW91dChmaW5kX3NpbmdsZV92YXJpYWJsZV9zb2x1dGlvbnMsIGFyZ3M9KEJBU0VfVkFMVUVTLCkpLAogICAgICAgICd0d28nOiBydW5fd2l0aF90aW1lb3V0KGZpbmRfdHdvX3ZhcmlhYmxlX3NvbHV0aW9ucywgYXJncz0oQkFTRV9WQUxVRVMsKSksCiAgICAgICAgJ3RocmVlJzogW10KICAgIH0KICAgIAogICAgaGFzX3NvbHV0aW9uID0gRmFsc2UKICAgIAogICAgIyDmmL7npLrljZXlj5jph4/op6MKICAgIGlmIGJhc2Vfc29sdXRpb25zWydzaW5nbGUnXToKICAgICAgICBoYXNfc29sdXRpb24gPSBUcnVlCiAgICAgICAgZGlzcGxheV9zb2x1dGlvbnMoe2E6IFtzb2xdIGZvciBhLCBzb2wgaW4gemlwKEJBU0VfVkFMVUVTLCBiYXNlX3NvbHV0aW9uc1snc2luZ2xlJ10pIGlmIHNvbH0sIDEpCiAgICAKICAgICMg5pi+56S65Y+M5Y+Y6YeP6KejCiAgICBpZiBiYXNlX3NvbHV0aW9uc1sndHdvJ10gYW5kIGxlbihiYXNlX3NvbHV0aW9uc1sndHdvJ10pID4gMDoKICAgICAgICBoYXNfc29sdXRpb24gPSBUcnVlCiAgICAgICAgZGlzcGxheV9zb2x1dGlvbnMoYmFzZV9zb2x1dGlvbnNbJ3R3byddLCAyKQogICAgCiAgICAjIOWNleWPmOmHj+WSjOWPjOWPmOmHj+mDveaXoOino+aXtu+8jOWwneivleS4ieWPmOmHj+inowogICAgaWYgbm90IGhhc19zb2x1dGlvbjoKICAgICAgICBwcmludChmIlxuPT09PSDljZXlj5jph4/lkozlj4zlj5jph4/ml6Dop6PvvIzlsJ3or5XkuInlj5jph4/op6MgPT09PSIpCiAgICAgICAgYmFzZV9zb2x1dGlvbnNbJ3RocmVlJ10gPSBydW5fd2l0aF90aW1lb3V0KGZpbmRfdGhyZWVfdmFyaWFibGVfc29sdXRpb25zLCBhcmdzPShCQVNFX1ZBTFVFUywpKQogICAgICAgIAogICAgICAgIGlmIGJhc2Vfc29sdXRpb25zWyd0aHJlZSddIGFuZCBsZW4oYmFzZV9zb2x1dGlvbnNbJ3RocmVlJ10pID4gMDoKICAgICAgICAgICAgaGFzX3NvbHV0aW9uID0gVHJ1ZQogICAgICAgICAgICBkaXNwbGF5X3NvbHV0aW9ucyhiYXNlX3NvbHV0aW9uc1sndGhyZWUnXSwgMykKICAgIAogICAgaWYgaGFzX3NvbHV0aW9uOgogICAgICAgIHByaW50KGYiXG7kvb/nlKjln7rnoYDns7vmlbDliJfooajvvIzlhbHmib7liLDmnInmlYjop6MiKQogICAgICAgIHJldHVybgogICAgCiAgICAjIOWmguaenOWfuuehgOezu+aVsOayoeacieaJvuWIsOino++8jOWwneivleazouWKqOezu+aVsAogICAgcHJpbnQoZiJcbj09PT0g5bCd6K+V5rOi5Yqo57O75pWwID09PT0iKQogICAgCiAgICBmbHVjdHVhdGVkX3NvbHV0aW9ucyA9IHsKICAgICAgICAnc2luZ2xlJzogcnVuX3dpdGhfdGltZW91dChmaW5kX3NpbmdsZV92YXJpYWJsZV9zb2x1dGlvbnMsIGFyZ3M9KEZMVUNUVUFURURfVkFMVUVTLCkpLAogICAgICAgICd0d28nOiBydW5fd2l0aF90aW1lb3V0KGZpbmRfdHdvX3ZhcmlhYmxlX3NvbHV0aW9ucywgYXJncz0oRkxVQ1RVQVRFRF9WQUxVRVMsKSksCiAgICAgICAgJ3RocmVlJzogW10KICAgIH0KICAgIAogICAgaGFzX3NvbHV0aW9uID0gRmFsc2UKICAgIAogICAgIyDmmL7npLrljZXlj5jph4/op6MKICAgIGlmIGZsdWN0dWF0ZWRfc29sdXRpb25zWydzaW5nbGUnXToKICAgICAgICBoYXNfc29sdXRpb24gPSBUcnVlCiAgICAgICAgZGlzcGxheV9zb2x1dGlvbnMoe2E6IFtzb2xdIGZvciBhLCBzb2wgaW4gemlwKEZMVUNUVUFURURfVkFMVUVTLCBmbHVjdHVhdGVkX3NvbHV0aW9uc1snc2luZ2xlJ10pIGlmIHNvbH0sIDEpCiAgICAKICAgICMg5pi+56S65Y+M5Y+Y6YeP6KejCiAgICBpZiBmbHVjdHVhdGVkX3NvbHV0aW9uc1sndHdvJ10gYW5kIGxlbihmbHVjdHVhdGVkX3NvbHV0aW9uc1sndHdvJ10pID4gMDoKICAgICAgICBoYXNfc29sdXRpb24gPSBUcnVlCiAgICAgICAgZGlzcGxheV9zb2x1dGlvbnMoZmx1Y3R1YXRlZF9zb2x1dGlvbnNbJ3R3byddLCAyKQogICAgCiAgICAjIOWNleWPmOmHj+WSjOWPjOWPmOmHj+mDveaXoOino+aXtu+8jOWwneivleS4ieWPmOmHj+inowogICAgaWYgbm90IGhhc19zb2x1dGlvbjoKICAgICAgICBwcmludChmIlxuPT09PSDljZXlj5jph4/lkozlj4zlj5jph4/ml6Dop6PvvIzlsJ3or5XkuInlj5jph4/op6MgPT09PSIpCiAgICAgICAgZmx1Y3R1YXRlZF9zb2x1dGlvbnNbJ3RocmVlJ10gPSBydW5fd2l0aF90aW1lb3V0KGZpbmRfdGhyZWVfdmFyaWFibGVfc29sdXRpb25zLCBhcmdzPShGTFVDVFVBVEVEX1ZBTFVFUywpKQogICAgICAgIAogICAgICAgIGlmIGZsdWN0dWF0ZWRfc29sdXRpb25zWyd0aHJlZSddIGFuZCBsZW4oZmx1Y3R1YXRlZF9zb2x1dGlvbnNbJ3RocmVlJ10pID4gMDoKICAgICAgICAgICAgaGFzX3NvbHV0aW9uID0gVHJ1ZQogICAgICAgICAgICBkaXNwbGF5X3NvbHV0aW9ucyhmbHVjdHVhdGVkX3NvbHV0aW9uc1sndGhyZWUnXSwgMykKICAgIAogICAgaWYgaGFzX3NvbHV0aW9uOgogICAgICAgIHByaW50KGYiXG7kvb/nlKjms6Lliqjns7vmlbDliJfooajvvIzlhbHmib7liLDmnInmlYjop6MiKQogICAgICAgIHJldHVybgogICAgCiAgICAjIOWmguaenOaJgOacieezu+aVsOmbhumDveayoeacieaJvuWIsOinowogICAgcHJpbnQoIlxu5rKh5pyJ5om+5Yiw56ym5ZCI5p2h5Lu255qE6Kej77yM5Y2z5L2/5L2/55So5rOi5Yqo5ZCO55qE57O75pWw5YiX6KGo44CCIikKCmlmIF9fbmFtZV9fID09ICJfX21haW5fXyI6CiAgICBzdGFydF90aW1lID0gdGltZS50aW1lKCkKICAgIG1haW4oKQogICAgcHJpbnQoZiJcbuaAu+iAl+aXtjoge3RpbWUudGltZSgpIC0gc3RhcnRfdGltZTouMmZ956eSIikgICAg