Create a new JavaScript RegExp benchmark
authormsaboff@apple.com <msaboff@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 5 Aug 2017 00:20:23 +0000 (00:20 +0000)
committermsaboff@apple.com <msaboff@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 5 Aug 2017 00:20:23 +0000 (00:20 +0000)
https://bugs.webkit.org/show_bug.cgi?id=175225

Reviewed by JF Bastien.

This is a new benchmark for Regular Expressions.  It borrows regex-dna from
SunSpider, the regexp test from Octane2, the BASIC parser from ARES-6/Basic,
and adds a new flight planner benchmark that uses RegExp's for textual parsing.

There needs to be some additions and changes to some of the textual content.
This includes adding more BASIC programs to the Basic test and increasing
keyword usage in the Flight Planner to increase the 16-bit coverage.

The intent is to grow this benchmark by adding a JavaScript implementation of the
offline assembler lexer and parser as well as adding some targeted micro benchmark
tests.

* RexBench: Added.
* RexBench/Basic: Added.
* RexBench/Basic/ast.js: Added.
* RexBench/Basic/basic.js: Added.
* RexBench/Basic/benchmark.js: Added.
* RexBench/Basic/caseless_map.js: Added.
* RexBench/Basic/lexer.js: Added.
* RexBench/Basic/number.js: Added.
* RexBench/Basic/parser.js: Added.
* RexBench/Basic/random.js: Added.
* RexBench/Basic/state.js: Added.
* RexBench/Basic/stress-test.js: Added.
* RexBench/Basic/util.js: Added.
* RexBench/FlightPlanner: Added.
* RexBench/FlightPlanner/airways.js: Added.
* RexBench/FlightPlanner/benchmark.js: Added.
* RexBench/FlightPlanner/convert-nfdc.py: Added.
* RexBench/FlightPlanner/expectations.js: Added.
* RexBench/FlightPlanner/flight_planner.js: Added.
* RexBench/FlightPlanner/use_unicode.js: Added.
* RexBench/FlightPlanner/waypoints.js: Added.
* RexBench/Octane2: Added.
* RexBench/Octane2/base.js: Added.
* RexBench/Octane2/regexp.js: Added.
* RexBench/SunSpider: Added.
* RexBench/SunSpider/regex-dna.js: Added.
* RexBench/about.html: Added.
* RexBench/basic_benchmark.js: Added.
* RexBench/cli.js: Added.
* RexBench/driver.js: Added.
* RexBench/flightplan_benchmark.js: Added.
* RexBench/flightplan_unicode_benchmark.js: Added.
* RexBench/glue.js: Added.
* RexBench/index.html: Added.
* RexBench/octane2_benchmark.js: Added.
* RexBench/results.js: Added.
* RexBench/stats.js: Added.
* RexBench/styles.css: Added.
* RexBench/sunspider_benchmark.js: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@220307 268f45cc-cd09-0410-ab3c-d52691b4dbfc

35 files changed:
PerformanceTests/ChangeLog
PerformanceTests/RexBench/Basic/ast.js [new file with mode: 0644]
PerformanceTests/RexBench/Basic/basic.js [new file with mode: 0644]
PerformanceTests/RexBench/Basic/benchmark.js [new file with mode: 0644]
PerformanceTests/RexBench/Basic/caseless_map.js [new file with mode: 0644]
PerformanceTests/RexBench/Basic/lexer.js [new file with mode: 0644]
PerformanceTests/RexBench/Basic/number.js [new file with mode: 0644]
PerformanceTests/RexBench/Basic/parser.js [new file with mode: 0644]
PerformanceTests/RexBench/Basic/random.js [new file with mode: 0644]
PerformanceTests/RexBench/Basic/state.js [new file with mode: 0644]
PerformanceTests/RexBench/Basic/stress-test.js [new file with mode: 0644]
PerformanceTests/RexBench/Basic/util.js [new file with mode: 0644]
PerformanceTests/RexBench/FlightPlanner/airways.js [new file with mode: 0644]
PerformanceTests/RexBench/FlightPlanner/benchmark.js [new file with mode: 0644]
PerformanceTests/RexBench/FlightPlanner/convert-nfdc.py [new file with mode: 0644]
PerformanceTests/RexBench/FlightPlanner/expectations.js [new file with mode: 0644]
PerformanceTests/RexBench/FlightPlanner/flight_planner.js [new file with mode: 0644]
PerformanceTests/RexBench/FlightPlanner/use_unicode.js [new file with mode: 0644]
PerformanceTests/RexBench/FlightPlanner/waypoints.js [new file with mode: 0644]
PerformanceTests/RexBench/Octane2/base.js [new file with mode: 0644]
PerformanceTests/RexBench/Octane2/regexp.js [new file with mode: 0644]
PerformanceTests/RexBench/SunSpider/regex-dna.js [new file with mode: 0644]
PerformanceTests/RexBench/about.html [new file with mode: 0644]
PerformanceTests/RexBench/basic_benchmark.js [new file with mode: 0644]
PerformanceTests/RexBench/cli.js [new file with mode: 0644]
PerformanceTests/RexBench/driver.js [new file with mode: 0644]
PerformanceTests/RexBench/flightplan_benchmark.js [new file with mode: 0644]
PerformanceTests/RexBench/flightplan_unicode_benchmark.js [new file with mode: 0644]
PerformanceTests/RexBench/glue.js [new file with mode: 0644]
PerformanceTests/RexBench/index.html [new file with mode: 0644]
PerformanceTests/RexBench/octane2_benchmark.js [new file with mode: 0644]
PerformanceTests/RexBench/results.js [new file with mode: 0644]
PerformanceTests/RexBench/stats.js [new file with mode: 0644]
PerformanceTests/RexBench/styles.css [new file with mode: 0644]
PerformanceTests/RexBench/sunspider_benchmark.js [new file with mode: 0644]

index 2df8b27..58f3dd2 100644 (file)
@@ -1,3 +1,62 @@
+2017-08-04  Michael Saboff  <msaboff@apple.com>
+
+        Create a new JavaScript RegExp benchmark
+        https://bugs.webkit.org/show_bug.cgi?id=175225
+
+        Reviewed by JF Bastien.
+
+        This is a new benchmark for Regular Expressions.  It borrows regex-dna from
+        SunSpider, the regexp test from Octane2, the BASIC parser from ARES-6/Basic,
+        and adds a new flight planner benchmark that uses RegExp's for textual parsing.
+
+        There needs to be some additions and changes to some of the textual content.
+        This includes adding more BASIC programs to the Basic test and increasing 
+        keyword usage in the Flight Planner to increase the 16-bit coverage.
+        
+        The intent is to grow this benchmark by adding a JavaScript implementation of the 
+        offline assembler lexer and parser as well as adding some targeted micro benchmark
+        tests.
+
+        * RexBench: Added.
+        * RexBench/Basic: Added.
+        * RexBench/Basic/ast.js: Added.
+        * RexBench/Basic/basic.js: Added.
+        * RexBench/Basic/benchmark.js: Added.
+        * RexBench/Basic/caseless_map.js: Added.
+        * RexBench/Basic/lexer.js: Added.
+        * RexBench/Basic/number.js: Added.
+        * RexBench/Basic/parser.js: Added.
+        * RexBench/Basic/random.js: Added.
+        * RexBench/Basic/state.js: Added.
+        * RexBench/Basic/stress-test.js: Added.
+        * RexBench/Basic/util.js: Added.
+        * RexBench/FlightPlanner: Added.
+        * RexBench/FlightPlanner/airways.js: Added.
+        * RexBench/FlightPlanner/benchmark.js: Added.
+        * RexBench/FlightPlanner/convert-nfdc.py: Added.
+        * RexBench/FlightPlanner/expectations.js: Added.
+        * RexBench/FlightPlanner/flight_planner.js: Added.
+        * RexBench/FlightPlanner/use_unicode.js: Added.
+        * RexBench/FlightPlanner/waypoints.js: Added.
+        * RexBench/Octane2: Added.
+        * RexBench/Octane2/base.js: Added.
+        * RexBench/Octane2/regexp.js: Added.
+        * RexBench/SunSpider: Added.
+        * RexBench/SunSpider/regex-dna.js: Added.
+        * RexBench/about.html: Added.
+        * RexBench/basic_benchmark.js: Added.
+        * RexBench/cli.js: Added.
+        * RexBench/driver.js: Added.
+        * RexBench/flightplan_benchmark.js: Added.
+        * RexBench/flightplan_unicode_benchmark.js: Added.
+        * RexBench/glue.js: Added.
+        * RexBench/index.html: Added.
+        * RexBench/octane2_benchmark.js: Added.
+        * RexBench/results.js: Added.
+        * RexBench/stats.js: Added.
+        * RexBench/styles.css: Added.
+        * RexBench/sunspider_benchmark.js: Added.
+
 2017-07-31  Mathias Bynens  <mathias@qiwi.be>
 
         Speedometer 2.0: Remove <base> from Angular 4 test
diff --git a/PerformanceTests/RexBench/Basic/ast.js b/PerformanceTests/RexBench/Basic/ast.js
new file mode 100644 (file)
index 0000000..bebd9f6
--- /dev/null
@@ -0,0 +1,273 @@
+/*
+ * Copyright (C) 2016-2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+"use strict";
+
+const Basic = {};
+
+Basic.NumberApply = function(state)
+{
+    // I'd call this arguments but we're in strict mode.
+    let parameters = this.parameters.map(value => value.evaluate(state));
+    
+    return state.getValue(this.name, parameters.length).apply(state, parameters);
+};
+
+Basic.Variable = function(state)
+{
+    let parameters = this.parameters.map(value => value.evaluate(state));
+    
+    return state.getValue(this.name, parameters.length).leftApply(state, parameters);
+}
+
+Basic.Const = function(state)
+{
+    return this.value;
+}
+
+Basic.NumberPow = function(state)
+{
+    return Math.pow(this.left.evaluate(state), this.right.evaluate(state));
+}
+
+Basic.NumberMul = function(state)
+{
+    return this.left.evaluate(state) * this.right.evaluate(state);
+}
+
+Basic.NumberDiv = function(state)
+{
+    return this.left.evaluate(state) / this.right.evaluate(state);
+}
+
+Basic.NumberNeg = function(state)
+{
+    return -this.term.evaluate(state);
+}
+
+Basic.NumberAdd = function(state)
+{
+    return this.left.evaluate(state) + this.right.evaluate(state);
+}
+
+Basic.NumberSub = function(state)
+{
+    return this.left.evaluate(state) - this.right.evaluate(state);
+}
+
+Basic.StringVar = function(state)
+{
+    let value = state.stringValues.get(this.name);
+    if (value == null)
+        state.abort("Could not find string variable " + this.name);
+    return value;
+}
+
+Basic.Equals = function(state)
+{
+    return this.left.evaluate(state) == this.right.evaluate(state);
+}
+
+Basic.NotEquals = function(state)
+{
+    return this.left.evaluate(state) != this.right.evaluate(state);
+}
+
+Basic.LessThan = function(state)
+{
+    return this.left.evaluate(state) < this.right.evaluate(state);
+}
+
+Basic.GreaterThan = function(state)
+{
+    return this.left.evaluate(state) > this.right.evaluate(state);
+}
+
+Basic.LessEqual = function(state)
+{
+    return this.left.evaluate(state) <= this.right.evaluate(state);
+}
+
+Basic.GreaterEqual = function(state)
+{
+    return this.left.evaluate(state) >= this.right.evaluate(state);
+}
+
+Basic.GoTo = function*(state)
+{
+    state.nextLineNumber = this.target;
+}
+
+Basic.GoSub = function*(state)
+{
+    state.subStack.push(state.nextLineNumber);
+    state.nextLineNumber = this.target;
+}
+
+Basic.Def = function*(state)
+{
+    state.validate(!state.values.has(this.name), "Cannot redefine function");
+    state.values.set(this.name, new NumberFunction(this.parameters, this.expression));
+}
+
+Basic.Let = function*(state)
+{
+    this.variable.evaluate(state).assign(this.expression.evaluate(state));
+}
+
+Basic.If = function*(state)
+{
+    if (this.condition.evaluate(state))
+        state.nextLineNumber = this.target;
+}
+
+Basic.Return = function*(state)
+{
+    this.validate(state.subStack.length, "Not in a subroutine");
+    this.nextLineNumber = state.subStack.pop();
+}
+
+Basic.Stop = function*(state)
+{
+    state.nextLineNumber = null;
+}
+
+Basic.On = function*(state)
+{
+    let index = this.expression.evaluate(state);
+    if (!(index >= 1) || !(index <= this.targets.length))
+        state.abort("Index out of bounds: " + index);
+    this.nextLineNumber = this.targets[Math.floor(index)];
+}
+
+Basic.For = function*(state)
+{
+    let sideState = state.getSideState(this);
+    sideState.variable = state.getValue(this.variable, 0).leftApply(state, []);
+    sideState.initialValue = this.initial.evaluate(state);
+    sideState.limitValue = this.limit.evaluate(state);
+    sideState.stepValue = this.step.evaluate(state);
+    sideState.variable.assign(sideState.initialValue);
+    sideState.shouldStop = function() {
+        return (sideState.variable.value - sideState.limitValue) * Math.sign(sideState.stepValue) > 0;
+    };
+    if (sideState.shouldStop())
+        this.nextLineNumber = this.target.lineNumber + 1;
+}
+
+Basic.Next = function*(state)
+{
+    let sideState = state.getSideState(this.target);
+    sideState.variable.assign(sideState.variable.value + sideState.stepValue);
+    if (sideState.shouldStop())
+        return;
+    state.nextLineNumber = this.target.lineNumber + 1;
+}
+
+Basic.Next.isBlockEnd = true;
+
+Basic.Print = function*(state)
+{
+    let string = "";
+    for (let item of this.items) {
+        switch (item.kind) {
+        case "comma":
+            while (string.length % 14)
+                string += " ";
+            break;
+        case "tab": {
+            let value = item.value.evaluate(state);
+            value = Math.max(Math.round(value), 1);
+            while (string.length % value)
+                string += " ";
+            break;
+        }
+        case "string":
+        case "number":
+            string += item.value.evaluate(state);
+            break;
+        default:
+            throw new Error("Bad item kind: " + item.kind);
+        }
+    }
+    
+    yield {kind: "output", string};
+}
+
+Basic.Input = function*(state)
+{
+    let results = yield {kind: "input", numItems: this.items.length};
+    state.validate(results != null && results.length == this.items.length, "Input did not get the right number of items");
+    for (let i = 0; i < results.length; ++i)
+        this.items[i].evaluate(state).assign(results[i]);
+}
+
+Basic.Read = function*(state)
+{
+    for (let item of this.items) {
+        state.validate(state.dataIndex < state.program.data.length, "Attempting to read past the end of data");
+        item.assign(state.program.data[state.dataIndex++]);
+    }
+}
+
+Basic.Restore = function*(state)
+{
+    state.dataIndex = 0;
+}
+
+Basic.Dim = function*(state)
+{
+    for (let item of this.items) {
+        state.validate(!state.values.has(item.name), "Variable " + item.name + " already exists");
+        state.validate(item.bounds.length, "Dim statement is for arrays");
+        state.values.set(item.name, new NumberArray(item.bounds.map(bound => bound + 1)));
+    }
+}
+
+Basic.Randomize = function*(state)
+{
+    state.rng = createRNGWithRandomSeed();
+}
+
+Basic.End = function*(state)
+{
+    state.nextLineNumber = null;
+}
+
+Basic.End.isBlockEnd = true;
+
+Basic.Program = function* programGenerator(state)
+{
+    state.validate(state.program == this, "State must match program");
+    let maxLineNumber = Math.max(...this.statements.keys());
+    while (state.nextLineNumber != null) {
+        state.validate(state.nextLineNumber <= maxLineNumber, "Went out of bounds of the program");
+        let statement = this.statements.get(state.nextLineNumber++);
+        if (statement == null || statement.process == null)
+            continue;
+        state.statement = statement;
+        yield* statement.process(state);
+    }
+}
+
diff --git a/PerformanceTests/RexBench/Basic/basic.js b/PerformanceTests/RexBench/Basic/basic.js
new file mode 100644 (file)
index 0000000..bbb14d2
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2016-2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+"use strict";
+
+function prepare(string)
+{
+    let program = parse(lex(string)).program();
+    return program.process(new State(program));
+}
+
+function simulate(program, inputs = [])
+{
+    let result = "";
+    let args = [];
+    for (;;) {
+        let next = program.next(...args);
+        args = [];
+        if (next.done)
+            break;
+        if (next.value.kind == "output") {
+            result += next.value.string + "\n";
+            continue;
+        }
+        if (next.value.kind == "input") {
+            args = inputs.splice(0, next.value.numItems);
+            continue;
+        }
+    }
+    return result;
+}
+
diff --git a/PerformanceTests/RexBench/Basic/benchmark.js b/PerformanceTests/RexBench/Basic/benchmark.js
new file mode 100644 (file)
index 0000000..f15678b
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2016-2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+"use strict";
+
+class BasicBenchmark {
+    constructor(verbose = 0)
+    {
+        this._verbose = verbose;
+    }
+    
+    runIteration()
+    {
+        prepare("10 print \"hello, world!\"\n20 end");
+        prepare("10 let x = 0\n20 let x = x + 1\n30 print x\n40 if x < 10 then 20\n50 end");
+        prepare("10 print int(rnd * 100)\n20 end\n");
+        prepare("10 let value = int(rnd * 2000)\n20 print value\n30 if value <> 100 then 10\n40 end");
+    for (let i = 0; i < 100; ++i)
+        prepare("10 dim a(2000)\n20 for i = 2 to 2000\n30 let a(i) = 1\n40 next i\n50 for i = 2 to sqr(2000)\n60 if a(i) = 0 then 100\n70 for j = i ^ 2 to 2000 step i\n80 let a(j) = 0\n90 next j\n100 next i\n110 for i = 2 to 2000\n120 if a(i) = 0 then 140\n130 print i\n140 next i\n150 end\n");
+    }
+}
+    
+function runBenchmark()
+{
+    const verbose = 0;
+    const numIterations = 150;
+    
+    let before = currentTime();
+    
+    let benchmark = new Benchmark(verbose);
+    
+    for (let iteration = 0; iteration < numIterations; ++iteration)
+        benchmark.runIteration();
+    
+    let after = currentTime();
+    return after - before;
+}
diff --git a/PerformanceTests/RexBench/Basic/caseless_map.js b/PerformanceTests/RexBench/Basic/caseless_map.js
new file mode 100644 (file)
index 0000000..62df380
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2016-2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+"use strict";
+
+class CaselessMap {
+    constructor(otherMap)
+    {
+        if (otherMap == null)
+            this._map = new Map();
+        else
+            this._map = new Map(otherMap._map);
+    }
+    
+    set(key, value)
+    {
+        this._map.set(key.toLowerCase(), value);
+    }
+    
+    has(key)
+    {
+        return this._map.has(key.toLowerCase());
+    }
+    
+    get(key)
+    {
+        return this._map.get(key.toLowerCase());
+    }
+
+    [Symbol.iterator]()
+    {
+        return this._map[Symbol.iterator]();
+    }
+}
+
diff --git a/PerformanceTests/RexBench/Basic/lexer.js b/PerformanceTests/RexBench/Basic/lexer.js
new file mode 100644 (file)
index 0000000..e947b7c
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2016-2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+"use strict";
+
+// Loosely based on ECMA 55 sections 4-8, but loosened to allow for modern conventions, like
+// multi-character variable names. But this doesn't go too far - in particular, this doesn't do
+// unicode, because that would require more thought.
+function* lex(string)
+{
+    let sourceLineNumber = 0;
+    for (let line of string.split("\n")) {
+        ++sourceLineNumber;
+        
+        function consumeWhitespace()
+        {
+            if (/^\s+/.test(line))
+                line = RegExp.rightContext;
+        }
+   
+        function consume(kind)
+        {
+            line = RegExp.rightContext;
+            return {kind, string: RegExp.lastMatch, sourceLineNumber, userLineNumber};
+        }
+        
+        const isIdentifier = /^[a-z_]([a-z0-9_]*)/i;
+        const isNumber = /^(([0-9]+(\.([0-9]*))?)|(\.[0-9]+)(e([+-]?)([0-9]+))?)/i;
+        const isString = /^\"([^\"]|(\"\"))*\"/;
+        const isKeyword = /^((base)|(data)|(def)|(dim)|(end)|(for)|(go)|(gosub)|(goto)|(if)|(input)|(let)|(next)|(on)|(option)|(print)|(randomize)|(read)|(restore)|(return)|(step)|(stop)|(sub)|(then)|(to))/i;
+        const isOperator = /^(-|\+|\*|\/|\^|\(|\)|(<[>=]?)|(>=?)|=|,|\$|;)/;
+        const isRem = /^rem\s.*/;
+        
+        consumeWhitespace();
+        
+        if (!/^[0-9]+/.test(line))
+            throw new Error("At line " + sourceLineNumber + ": Expect line number: " + line);
+        let userLineNumber = +RegExp.lastMatch;
+        line = RegExp.rightContext;
+        yield {kind: "userLineNumber", string: RegExp.lastMatch, sourceLineNumber, userLineNumber};
+        
+        consumeWhitespace();
+        
+        while (line.length) {
+            if (isKeyword.test(line))
+                yield consume("keyword");
+            else if (isIdentifier.test(line))
+                yield consume("identifier");
+            else if (isNumber.test(line)) {
+                let token = consume("number");
+                token.value = +token.string;
+                yield token;
+            } else if (isString.test(line)) {
+                let token = consume("string");
+                token.value = "";
+                for (let i = 1; i < token.string.length - 1; ++i) {
+                    let char = token.string.charAt(i);
+                    if (char == "\"")
+                        i++;
+                    token.value += char;
+                }
+                yield token;
+            } else if (isOperator.test(line))
+                yield consume("operator");
+            else if (isRem.test(line))
+                yield consume("remark");
+            else
+                throw new Error("At line " + sourceLineNumber + ": Cannot lex token: " + line);
+            consumeWhitespace();
+        }
+        
+        // Note: this is necessary for the parser, which may look-ahead without checking if we're
+        // done. Fortunately, it won't look-ahead past a newLine.
+        yield {kind: "newLine", string:"\n", sourceLineNumber, userLineNumber};
+    }
+}
diff --git a/PerformanceTests/RexBench/Basic/number.js b/PerformanceTests/RexBench/Basic/number.js
new file mode 100644 (file)
index 0000000..1532d87
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2016-2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+"use strict";
+
+class NumberValue {
+    constructor(value = 0)
+    {
+        this._value = value;
+    }
+    
+    get value() { return this._value; }
+    
+    apply(state, parameters)
+    {
+        state.validate(parameters.length == 0, "Should not pass arguments to simple numeric variables");
+        return this._value;
+    }
+    
+    leftApply(state, parameters)
+    {
+        state.validate(parameters.length == 0, "Should not pass arguments to simple numeric variables");
+        return this;
+    }
+    
+    assign(value)
+    {
+        this._value = value;
+    }
+}
+
+class NumberArray {
+    constructor(dim = [11])
+    {
+        function allocateDim(index)
+        {
+            let result = new Array(dim[index]);
+            if (index + 1 < dim.length) {
+                for (let i = 0; i < dim[index]; ++i)
+                    result[i] = allocateDim(index + 1);
+            } else {
+                for (let i = 0; i < dim[index]; ++i)
+                    result[i] = new NumberValue();
+            }
+            return result;
+        }
+        
+        this._array = allocateDim(0);
+        this._dim = dim;
+    }
+    
+    apply(state, parameters)
+    {
+        return this.leftApply(state, parameters).apply(state, []);
+    }
+    
+    leftApply(state, parameters)
+    {
+        if (this._dim.length != parameters.length)
+            state.abort("Expected " + this._dim.length + " arguments but " + parameters.length + " were passed.");
+        let result = this._array;
+        for (var i = 0; i < parameters.length; ++i) {
+            let index = Math.floor(parameters[i]);
+            if (!(index >= state.program.base) || !(index < result.length))
+                state.abort("Index out of bounds: " + index);
+            result = result[index];
+        }
+        return result;
+    }
+}
+
+class NumberFunction {
+    constructor(parameters, code)
+    {
+        this._parameters = parameters;
+        this._code = code;
+    }
+    
+    apply(state, parameters)
+    {
+        if (this._parameters.length != parameters.length)
+            state.abort("Expected " + this._parameters.length + " arguments but " + parameters.length + " were passed");
+        let oldValues = state.values;
+        state.values = new Map(oldValues);
+        for (let i = 0; i < parameters.length; ++i)
+            state.values.set(this._parameters[i], parameters[i]);
+        let result = this.code.evaluate(state);
+        state.values = oldValues;
+        return result;
+    }
+    
+    leftApply(state, parameters)
+    {
+        state.abort("Cannot use a function as an lvalue");
+    }
+}
+
+class NativeFunction {
+    constructor(callback)
+    {
+        this._callback = callback;
+    }
+    
+    apply(state, parameters)
+    {
+        if (this._callback.length != parameters.length)
+            state.abort("Expected " + this._callback.length + " arguments but " + parameters.length + " were passed");
+        return this._callback(...parameters);
+    }
+    
+    leftApply(state, parameters)
+    {
+        state.abort("Cannot use a native function as an lvalue");
+    }
+}
+
diff --git a/PerformanceTests/RexBench/Basic/parser.js b/PerformanceTests/RexBench/Basic/parser.js
new file mode 100644 (file)
index 0000000..96c2118
--- /dev/null
@@ -0,0 +1,558 @@
+/*
+ * Copyright (C) 2016-2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+"use strict";
+
+function parse(tokenizer)
+{
+    let program;
+    
+    let pushBackBuffer = [];
+    
+    function nextToken()
+    {
+        if (pushBackBuffer.length)
+            return pushBackBuffer.pop();
+        let result = tokenizer.next();
+        if (result.done)
+            return {kind: "endOfFile", string: "<end of file>"};
+        return result.value;
+    }
+    
+    function pushToken(token)
+    {
+        pushBackBuffer.push(token);
+    }
+    
+    function peekToken()
+    {
+        let result = nextToken();
+        pushToken(result);
+        return result;
+    }
+    
+    function consumeKind(kind)
+    {
+        let token = nextToken();
+        if (token.kind != kind) {
+            throw new Error("At " + token.sourceLineNumber + ": expected " + kind + " but got: " + token.string);
+        }
+        return token;
+    }
+    
+    function consumeToken(string)
+    {
+        let token = nextToken();
+        if (token.string.toLowerCase() != string.toLowerCase())
+            throw new Error("At " + token.sourceLineNumber + ": expected " + string + " but got: " + token.string);
+        return token;
+    }
+    
+    function parseVariable()
+    {
+        let name = consumeKind("identifier").string;
+        let result = {evaluate: Basic.Variable, name, parameters: []};
+        if (peekToken().string == "(") {
+            do {
+                nextToken();
+                result.parameters.push(parseNumericExpression());
+            } while (peekToken().string == ",");
+            consumeToken(")");
+        }
+        return result;
+    }
+    
+    function parseNumericExpression()
+    {
+        function parsePrimary()
+        {
+            let token = nextToken();
+            switch (token.kind) {
+            case "identifier": {
+                let result = {evaluate: Basic.NumberApply, name: token.string, parameters: []};
+                if (peekToken().string == "(") {
+                    do {
+                        nextToken();
+                        result.parameters.push(parseNumericExpression());
+                    } while (peekToken().string == ",");
+                    consumeToken(")");
+                }
+                return result;
+            }
+                
+            case "number":
+                return {evaluate: Basic.Const, value: token.value};
+                
+            case "operator":
+                switch (token.string) {
+                case "(": {
+                    let result = parseNumericExpression();
+                    consumeToken(")");
+                    return result;
+                } }
+                break;
+            }
+            throw new Error("At " + token.sourceLineNumber + ": expected identifier, number, or (, but got: " + token.string);
+        }
+        
+        function parseFactor()
+        {
+            let primary = parsePrimary();
+            
+            let ok = true;
+            while (ok) {
+                switch (peekToken().string) {
+                case "^":
+                    nextToken();
+                    primary = {evaluate: Basic.NumberPow, left: primary, right: parsePrimary()};
+                    break;
+                default:
+                    ok = false;
+                    break;
+                }
+            }
+            
+            return primary;
+        }
+        
+        function parseTerm()
+        {
+            let factor = parseFactor();
+            
+            let ok = true;
+            while (ok) {
+                switch (peekToken().string) {
+                case "*":
+                    nextToken();
+                    factor = {evaluate: Basic.NumberMul, left: factor, right: parseFactor()};
+                    break;
+                case "/":
+                    nextToken();
+                    factor = {evaluate: Basic.NumberDiv, left: factor, right: parseFactor()};
+                    break;
+                default:
+                    ok = false;
+                    break;
+                }
+            }
+            
+            return factor;
+        }
+        
+        // Only the leading term in Basic can have a sign.
+        let negate = false;
+        switch (peekToken().string) {
+        case "+":
+            nextToken();
+            break;
+        case "-":
+            negate = true;
+            nextToken()
+            break;
+        }
+        
+        let term = parseTerm();
+        if (negate)
+            term = {evaluate: Basic.NumberNeg, term: term};
+        
+        let ok = true;
+        while (ok) {
+            switch (peekToken().string) {
+            case "+":
+                nextToken();
+                term = {evaluate: Basic.NumberAdd, left: term, right: parseTerm()};
+                break;
+            case "-":
+                nextToken();
+                term = {evaluate: Basic.NumberSub, left: term, right: parseTerm()};
+                break;
+            default:
+                ok = false;
+                break;
+            }
+        }
+        
+        return term;
+    }
+    
+    function parseConstant()
+    {
+        switch (peekToken().string) {
+        case "+":
+            nextToken();
+            return consumeKind("number").value;
+        case "-":
+            nextToken();
+            return -consumeKind("number").value;
+        default:
+            if (isStringExpression())
+                return consumeKind("string").value;
+            return consumeKind("number").value;
+        }
+    }
+    
+    function parseStringExpression()
+    {
+        let token = nextToken();
+        switch (token.kind) {
+        case "string":
+            return {evaluate: Basic.Const, value: token.value};
+        case "identifier":
+            consumeToken("$");
+            return {evaluate: Basic.StringVar, name: token.string};
+        default:
+            throw new Error("At " + token.sourceLineNumber + ": expected string expression but got " + token.string);
+        }
+    }
+    
+    function isStringExpression()
+    {
+        // A string expression must start with a string variable or a string constant.
+        let token = nextToken();
+        if (token.kind == "string") {
+            pushToken(token);
+            return true;
+        }
+        if (token.kind == "identifier") {
+            let result = peekToken().string == "$";
+            pushToken(token);
+            return result;
+        }
+        pushToken(token);
+        return false;
+    }
+    
+    function parseRelationalExpression()
+    {
+        if (isStringExpression()) {
+            let left = parseStringExpression();
+            let operator = nextToken();
+            let evaluate;
+            switch (operator.string) {
+            case "=":
+                evaluate = Basic.Equals;
+                break;
+            case "<>":
+                evaluate = Basic.NotEquals;
+                break;
+            default:
+                throw new Error("At " + operator.sourceLineNumber + ": expected a string comparison operator but got: " + operator.string);
+            }
+            return {evaluate, left, right: parseStringExpression()};
+        }
+        
+        let left = parseNumericExpression();
+        let operator = nextToken();
+        let evaluate;
+        switch (operator.string) {
+        case "=":
+            evaluate = Basic.Equals;
+            break;
+        case "<>":
+            evaluate = Basic.NotEquals;
+            break;
+        case "<":
+            evaluate = Basic.LessThan;
+            break;
+        case ">":
+            evaluate = Basic.GreaterThan;
+            break;
+        case "<=":
+            evaluate = Basic.LessEqual;
+            break;
+        case ">=":
+            evaluate = Basic.GreaterEqual;
+            break;
+        default:
+            throw new Error("At " + operator.sourceLineNumber + ": expected a numeric comparison operator but got: " + operator.string);
+        }
+        return {evaluate, left, right: parseNumericExpression()};
+    }
+    
+    function parseNonNegativeInteger()
+    {
+        let token = nextToken();
+        if (!/^[0-9]+$/.test(token.string))
+            throw new Error("At ", token.sourceLineNumber + ": expected a line number but got: " + token.string);
+        return token.value;
+    }
+    
+    function parseGoToStatement()
+    {
+        statement.kind = Basic.GoTo;
+        statement.target = parseNonNegativeInteger();
+    }
+    
+    function parseGoSubStatement()
+    {
+        statement.kind = Basic.GoSub;
+        statement.target = parseNonNegativeInteger();
+    }
+    
+    function parseStatement()
+    {
+        let statement = {};
+        statement.lineNumber = consumeKind("userLineNumber").userLineNumber;
+        program.statements.set(statement.lineNumber, statement);
+        
+        let command = nextToken();
+        statement.sourceLineNumber = command.sourceLineNumber;
+        switch (command.kind) {
+        case "keyword":
+            switch (command.string.toLowerCase()) {
+            case "def":
+                statement.process = Basic.Def;
+                statement.name = consumeKind("identifier");
+                statement.parameters = [];
+                if (peekToken().string == "(") {
+                    do {
+                        nextToken();
+                        statement.parameters.push(consumeKind("identifier"));
+                    } while (peekToken().string == ",");
+                }
+                statement.expression = parseNumericExpression();
+                break;
+            case "let":
+                statement.process = Basic.Let;
+                statement.variable = parseVariable();
+                consumeToken("=");
+                if (statement.process == Basic.Let)
+                    statement.expression = parseNumericExpression();
+                else
+                    statement.expression = parseStringExpression();
+                break;
+            case "go": {
+                let next = nextToken();
+                if (next.string == "to")
+                    parseGoToStatement();
+                else if (next.string == "sub")
+                    parseGoSubStatement();
+                else
+                    throw new Error("At " + next.sourceLineNumber + ": expected to or sub but got: " + next.string);
+                break;
+            }
+            case "goto":
+                parseGoToStatement();
+                break;
+            case "gosub":
+                parseGoSubStatement();
+                break;
+            case "if":
+                statement.process = Basic.If;
+                statement.condition = parseRelationalExpression();
+                consumeToken("then");
+                statement.target = parseNonNegativeInteger();
+                break;
+            case "return":
+                statement.process = Basic.Return;
+                break;
+            case "stop":
+                statement.process = Basic.Stop;
+                break;
+            case "on":
+                statement.process = Basic.On;
+                statement.expression = parseNumericExpression();
+                if (peekToken().string == "go") {
+                    consumeToken("go");
+                    consumeToken("to");
+                } else
+                    consumeToken("goto");
+                statement.targets = [];
+                for (;;) {
+                    statement.targets.push(parseNonNegativeInteger());
+                    if (peekToken().string != ",")
+                        break;
+                    nextToken();
+                }
+                break;
+            case "for":
+                statement.process = Basic.For;
+                statement.variable = consumeKind("identifier").string;
+                consumeToken("=");
+                statement.initial = parseNumericExpression();
+                consumeToken("to");
+                statement.limit = parseNumericExpression();
+                if (peekToken().string == "step") {
+                    nextToken();
+                    statement.step = parseNumericExpression();
+                } else
+                    statement.step = {evaluate: Basic.Const, value: 1};
+                consumeKind("newLine");
+                let lastStatement = parseStatements();
+                if (lastStatement.process != Basic.Next)
+                    throw new Error("At " + lastStatement.sourceLineNumber + ": expected next statement");
+                if (lastStatement.variable != statement.variable)
+                    throw new Error("At " + lastStatement.sourceLineNumber + ": expected next for " + statement.variable + " but got " + lastStatement.variable);
+                lastStatement.target = statement;
+                statement.target = lastStatement;
+                return statement;
+            case "next":
+                statement.process = Basic.Next;
+                statement.variable = consumeKind("identifier").string;
+                break;
+            case "print": {
+                statement.process = Basic.Print;
+                statement.items = [];
+                let ok = true;
+                while (ok) {
+                    switch (peekToken().string) {
+                    case ",":
+                        nextToken();
+                        statement.items.push({kind: "comma"});
+                        break;
+                    case ";":
+                        nextToken();
+                        break;
+                    case "tab":
+                        nextToken();
+                        consumeToken("(");
+                        statement.items.push({kind: "tab", value: parseNumericExpression()});
+                        break;
+                    case "\n":
+                        ok = false;
+                        break;
+                    default:
+                        if (isStringExpression()) {
+                            statement.items.push({kind: "string", value: parseStringExpression()});
+                            break;
+                        }
+                        statement.items.push({kind: "number", value: parseNumericExpression()});
+                        break;
+                    }
+                }
+                break;
+            }
+            case "input":
+                statement.process = Basic.Input;
+                statement.items = [];
+                for (;;) {
+                    statement.items.push(parseVariable());
+                    if (peekToken().string != ",")
+                        break;
+                    nextToken();
+                }
+                break;
+            case "read":
+                statement.process = Basic.Read;
+                statement.items = [];
+                for (;;) {
+                    stament.items.push(parseVariable());
+                    if (peekToken().string != ",")
+                        break;
+                    nextToken();
+                }
+                break;
+            case "restore":
+                statement.process = Basic.Restore;
+                break;
+            case "data":
+                for (;;) {
+                    program.data.push(parseConstant());
+                    if (peekToken().string != ",")
+                        break;
+                    nextToken();
+                }
+                break;
+            case "dim":
+                statement.process = Basic.Dim;
+                statement.items = [];
+                for (;;) {
+                    let name = consumeKind("identifier").string;
+                    consumeToken("(");
+                    let bounds = [];
+                    bounds.push(parseNonNegativeInteger());
+                    if (peekToken().string == ",") {
+                        nextToken();
+                        bounds.push(parseNonNegativeInteger());
+                    }
+                    consumeToken(")");
+                    statement.items.push({name, bounds});
+                    
+                    if (peekToken().string != ",")
+                        break;
+                    consumeToken(",");
+                }
+                break;
+            case "option": {
+                consumeToken("base");
+                let base = parseNonNegativeInteger();
+                if (base != 0 && base != 1)
+                    throw new Error("At " + command.sourceLineNumber + ": unexpected base: " + base);
+                program.base = base;
+                break;
+            }
+            case "randomize":
+                statement.process = Basic.Randomize;
+                break;
+            case "end":
+                statement.process = Basic.End;
+                break;
+            default:
+                throw new Error("At " + command.sourceLineNumber + ": unexpected command but got: " + command.string);
+            }
+            break;
+        case "remark":
+            // Just ignore it.
+            break;
+        default:
+            throw new Error("At " + command.sourceLineNumber + ": expected command but got: " + command.string + " (of kind " + command.kind + ")");
+        }
+        
+        consumeKind("newLine");
+        return statement;
+    }
+    
+    function parseStatements()
+    {
+        let statement;
+        do {
+            statement = parseStatement();
+        } while (!statement.process || !statement.process.isBlockEnd);
+        return statement;
+    }
+    
+    return {
+        program()
+        {
+            program = {
+                process: Basic.Program,
+                statements: new Map(),
+                data: [],
+                base: 0
+            };
+            let lastStatement = parseStatements(program.statements);
+            if (lastStatement.process != Basic.End)
+                throw new Error("At " + lastStatement.sourceLineNumber + ": expected end");
+            
+            return program;
+        },
+        
+        statement(program_)
+        {
+            program = program_;
+            return parseStatement();
+        }
+    };
+}
+
diff --git a/PerformanceTests/RexBench/Basic/random.js b/PerformanceTests/RexBench/Basic/random.js
new file mode 100644 (file)
index 0000000..9f3b408
--- /dev/null
@@ -0,0 +1,54 @@
+// Copyright 2013 the V8 project authors. All rights reserved.
+// Copyright (C) 2015-2017 Apple Inc. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+"use strict";
+
+// This is based on Octane's RNG.
+function createRNG(seed)
+{
+    return function() {
+        // Robert Jenkins' 32 bit integer hash function.
+        seed = ((seed + 0x7ed55d16) + (seed << 12))  & 0xffffffff;
+        seed = ((seed ^ 0xc761c23c) ^ (seed >>> 19)) & 0xffffffff;
+        seed = ((seed + 0x165667b1) + (seed << 5))   & 0xffffffff;
+        seed = ((seed + 0xd3a2646c) ^ (seed << 9))   & 0xffffffff;
+        seed = ((seed + 0xfd7046c5) + (seed << 3))   & 0xffffffff;
+        seed = ((seed ^ 0xb55a4f09) ^ (seed >>> 16)) & 0xffffffff;
+        return (seed & 0xfffffff) / 0x10000000;
+    };
+}
+
+function createRNGWithFixedSeed()
+{
+    // This uses Octane's initial seed.
+    return createRNG(49734321);
+}
+
+function createRNGWithRandomSeed()
+{
+    return createRNG((Math.random() * 4294967296) | 0);
+}
diff --git a/PerformanceTests/RexBench/Basic/state.js b/PerformanceTests/RexBench/Basic/state.js
new file mode 100644 (file)
index 0000000..8565fc1
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2016-2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+"use strict";
+
+class State {
+    constructor(program)
+    {
+        this.values = new CaselessMap();
+        this.stringValues = new CaselessMap();
+        this.sideState = new WeakMap();
+        this.statement = null;
+        this.nextLineNumber = 0;
+        this.subStack = [];
+        this.dataIndex = 0;
+        this.program = program;
+        this.rng = createRNGWithFixedSeed();
+        
+        let addNative = (name, callback) => {
+            this.values.set(name, new NativeFunction(callback));
+        };
+        
+        addNative("abs", x => Math.abs(x));
+        addNative("atn", x => Math.atan(x));
+        addNative("cos", x => Math.cos(x));
+        addNative("exp", x => Math.exp(x));
+        addNative("int", x => Math.floor(x));
+        addNative("log", x => Math.log(x));
+        addNative("rnd", () => this.rng());
+        addNative("sgn", x => Math.sign(x));
+        addNative("sin", x => Math.sin(x));
+        addNative("sqr", x => Math.sqrt(x));
+        addNative("tan", x => Math.tan(x));
+    }
+    
+    getValue(name, numParameters)
+    {
+        if (this.values.has(name))
+            return this.values.get(name);
+
+        let result;
+        if (numParameters == 0)
+            result = new NumberValue();
+        else {
+            let dim = [];
+            while (numParameters--)
+                dim.push(11);
+            result = new NumberArray(dim);
+        }
+        this.values.set(name, result);
+        return result;
+    }
+    
+    getSideState(key)
+    {
+        if (!this.sideState.has(key)) {
+            let result = {};
+            this.sideState.set(key, result);
+            return result;
+        }
+        return this.sideState.get(key);
+    }
+    
+    abort(text)
+    {
+        if (!this.statement)
+            throw new Error("At beginning of execution: " + text);
+        throw new Error("At " + this.statement.sourceLineNumber + ": " + text);
+    }
+    
+    validate(predicate, text)
+    {
+        if (!predicate)
+            this.abort(text);
+    }
+}
+
diff --git a/PerformanceTests/RexBench/Basic/stress-test.js b/PerformanceTests/RexBench/Basic/stress-test.js
new file mode 100644 (file)
index 0000000..1d12ec6
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2016-2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+"use strict";
+
+load("ast.js");
+load("basic.js");
+load("caseless_map.js");
+load("lexer.js");
+load("number.js");
+load("parser.js");
+load("random.js");
+load("state.js");
+load("util.js");
+load("benchmark.js");
+
+let benchmark = new BasicBenchmark();
+let before = preciseTime();
+
+// Run for at least 10 iterations.
+for (let i = 0; i < 10; ++i) {
+    print("Running mandatory iteration #" + (i + 1) + ":");
+    benchmark.runIteration();
+}
+
+// Run until we have been running for two seconds.
+while (preciseTime() < before + 2) {
+    print("Running bonus iteration:");
+    benchmark.runIteration();
+}
+
+print("Success!");
+
diff --git a/PerformanceTests/RexBench/Basic/util.js b/PerformanceTests/RexBench/Basic/util.js
new file mode 100644 (file)
index 0000000..eff6517
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2016-2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+"use strict";
+
+let currentTime;
+if (this.performance && performance.now)
+    currentTime = function() { return performance.now() };
+else if (this.preciseTime)
+    currentTime = function() { return preciseTime() * 1000; };
+else
+    currentTime = function() { return +new Date(); };
+
diff --git a/PerformanceTests/RexBench/FlightPlanner/airways.js b/PerformanceTests/RexBench/FlightPlanner/airways.js
new file mode 100644 (file)
index 0000000..49a4e7b
--- /dev/null
@@ -0,0 +1,1012 @@
+var _faaAirways = {
+    "J1":{ "name":"J1", "fixes":["TIJ", "TEYON", "MZB", "OCN", "LAX", "FIM", "REYES", "DERBB", "AVE", "OAK", "RBL", "HANDY", "OED", "DREWS", "BTG", "ALDER", "SEA"]},
+    "J10":{ "name":"J10", "fixes":["LAX", "JUGLI", "CIVET", "RUSTT", "PIONE", "TNP", "CADEZ", "HIPPI", "FLG", "RSK", "HBU", "FQF", "LBF", "OBH", "DSM", "IOW"]},
+    "J100":{ "name":"J100", "fixes":["LAX", "DAG", "MISEN", "CLARR", "LAS", "SUVIE", "NORRA", "BCE", "SAKES", "EKR", "FROGS", "SNY", "ELJAY", "OBH", "TODDO", "JORDY", "CAPPR", "DBQ", "COTON", "OBK"]},
+    "J101":{ "name":"J101", "fixes":["IAH", "LFK", "SKKIP", "ADUKE", "BERKE", "CISAR", "WASKO", "LIT", "IGLOO", "PLIED", "TWRAY", "STL", "FARGO", "SPI", "PNT", "JOT", "OBK", "BAE", "GRB", "SSM"]},
+    "J102":{ "name":"J102", "fixes":["PXR", "FORPE", "CHEKR", "BOLIC", "ZUN", "GUP", "PUMPS", "RGINA", "ALS", "LAA", "RYLIE", "SLN"]},
+    "J103":{ "name":"J103", "fixes":["OMN", "BEENO", "MILIE", "SAV"]},
+    "J104":{ "name":"J104", "fixes":["LAX", "JUGLI", "CIVET", "RUSTT", "PIONE", "TNP", "PKE", "MESSI", "CULTS", "KOFFA", "GBN", "ALMON", "TUS", "SSAND", "SSO", "WOBUG", "GREBE", "TMACK", "ONM", "FTI", "PUB"]},
+    "J105":{ "name":"J105", "fixes":["FUZ", "PLATE", "MLC", "KLUBB", "RZC", "SGF", "ULMAN", "ELSTO", "WELTS", "BAYLI", "MAGOO", "NORIS", "BDF", "VORIN", "BAE"]},
+    "J106":{ "name":"J106", "fixes":["JHW", "HOXIE", "DMACK", "STENT", "MAGIO", "LVZ", "JENNO", "HARTY", "STW", "LGA"]},
+    "J107":{ "name":"J107", "fixes":["LAX", "JUGLI", "CIVET", "RESOR", "HEC", "BLD", "OVETO", "NORRA", "BERYL", "MLF", "URNUW", "OCS", "DDY", "DPR", "HML", "VBI"]},
+    "J108":{ "name":"J108", "fixes":["INW", "SJN", "TCS", "GINGR", "INK"]},
+    "J109":{ "name":"J109", "fixes":["ILM", "FAK", "LDN"]},
+    "J11":{ "name":"J11", "fixes":["TUS", "TOTEC", "TUKEE", "PXR", "DRK", "KIDDR", "NAVHO", "CORKR", "FREDD", "BCE", "URNUW", "NEEBO", "FFU", "TCH"]},
+    "J110":{ "name":"J110", "fixes":["OAK", "SNS", "CZQ", "PINNI", "MITEL", "FURNY", "SHADO", "FUZZY", "BLD", "LRAIN", "RSK", "ALS", "GCK", "KIRKE", "PEABO", "FRACA", "BUM", "SCAWT", "ELSTO", "TRAKE", "STL", "COWES", "TILMN", "VHP", "FYLLS", "CREEP", "EMPTY", "BOWRR", "ZANDR", "CORVS", "AIR", "LEJOY", "VINSE", "GRAHM", "BEETS", "LARRI", "KIPPI", "FLIRT", "PENSY", "CYN"]},
+    "J112":{ "name":"J112", "fixes":["BUM", "EUNIK", "ULMAN", "CROCK", "FAM", "PLESS", "PXV", "IIU"]},
+    "J113":{ "name":"J113", "fixes":["VKZ", "ARKES", "LLNCH", "DEARY", "DRUDJ", "CRG"]},
+    "J114":{ "name":"J114", "fixes":["DVV", "LANDR", "SNY", "BENNZ", "YANKI", "NARLY", "ONL", "FSD", "GEP"]},
+    "J116":{ "name":"J116", "fixes":["TCH", "FFU", "EKR", "FQF"]},
+    "J118":{ "name":"J118", "fixes":["MEM", "FLORS", "SALMS", "GQO", "SPA"]},
+    "J119":{ "name":"J119", "fixes":["PIE", "CORSU", "FAGAN", "TAY"]},
+    "J12":{ "name":"J12", "fixes":["SEA", "NORMY", "BLUIT", "EPH", "DNJ", "TWF", "TCH", "FFU", "HELPR", "RIFMN", "JNC"]},
+    "J121":{ "name":"J121", "fixes":["CRG", "MILIE", "CHS", "JMACK", "BARTL", "ISO", "WEAVR", "ORF", "SAWED", "KALDA", "DUNFE", "SWL", "RADDS", "SIE", "AVALO", "BRIGS", "DRIFT", "MANTA", "PLUME", "SHERL", "DUNEE", "SARDI", "SHLEP", "HOFFI", "HTO", "SEY", "BURDY", "ENE"]},
+    "J126":{ "name":"J126", "fixes":["LAX", "RZS", "CEANO", "ROBIE", "GOALI", "SNS", "SAC", "RBL", "HANDY", "OED", "EUG", "UBG", "OLM", "YVR"]},
+    "J128":{ "name":"J128", "fixes":["LAX", "JUGLI", "CIVET", "RUSTT", "EMMEY", "DIKES", "BUGGA", "ETINE", "PGS", "TBC", "LRAIN", "HBU", "FQF", "HCT", "OBH", "TODDO", "JORDY", "CAPPR", "DBQ", "COTON", "OBK"]},
+    "J13":{ "name":"J13", "fixes":["BECON", "RUTER", "TCS", "ABQ", "FRIHO", "FLYBY", "ESPAN", "ALS", "BINKE", "VIMPY", "FQF", "CYS", "DDY", "BIL", "GTF", "COUTS"]},
+    "J130":{ "name":"J130", "fixes":["MCK", "PWE"]},
+    "J131":{ "name":"J131", "fixes":["SAT", "HENLY", "SPURS", "JUMBO", "EDNAS", "FUZ", "TXK", "LIT", "RUSLR", "HUMBO", "PENBE", "PXV"]},
+    "J132":{ "name":"J132", "fixes":["ULW", "DARBO", "CORDS", "HUO"]},
+    "J134":{ "name":"J134", "fixes":["LAX", "SLI", "TRM", "PKE", "LANCY", "DRK", "KEYKE", "GUP", "CIM", "LBL", "VARNR", "ICT", "ROKNE", "DOSOA", "BUM", "SCAWT", "ELSTO", "TRAKE", "STL", "JIGSY", "CAROL", "JUDDI", "MOSEY", "GBEES", "FLM", "HNN", "LAYED", "STEVY", "COLNS", "LDN"]},
+    "J136":{ "name":"J136", "fixes":["ONP", "BTG", "YKM", "GEG", "HILIE", "MLP", "HLN", "BIL", "MBW"]},
+    "J137":{ "name":"J137", "fixes":["SPI", "FAM", "BSIDE", "ARG", "LIT"]},
+    "J138":{ "name":"J138", "fixes":["FST", "SHUCK", "CSI", "SAT", "SEEDS", "WEMAR", "HUB", "KAPAA", "LCH", "LSU", "SJI"]},
+    "J14":{ "name":"J14", "fixes":["PNH", "CRUSR", "IRW", "DWINE", "KLUBB", "KOMMA", "LIT", "ARIGY", "CARIN", "XESSS", "YAALL", "VUZ", "ATL", "AJFEB", "SPA", "BYJAC", "GSO", "JAXSN", "CREWE", "RIC", "VIPKE", "COLIN", "PXT"]},
+    "J140":{ "name":"J140", "fixes":["FAR", "DLH", "SSM"]},
+    "J141":{ "name":"J141", "fixes":["ELP", "KEYLO"]},
+    "J142":{ "name":"J142", "fixes":["ONM", "MAXXO", "ACH", "BGD"]},
+    "J143":{ "name":"J143", "fixes":["PYE", "ENI", "RBG", "EUG", "LTJ", "GEG"]},
+    "J144":{ "name":"J144", "fixes":["OBH", "DSM", "DBQ"]},
+    "J145":{ "name":"J145", "fixes":["ODF", "HLRRY", "KONGO", "HVQ"]},
+    "J146":{ "name":"J146", "fixes":["LAX", "DAG", "MISEN", "CLARR", "LAS", "BEALE", "NOOTN", "BETHL", "FREDD", "DICEE", "DVC", "HBU", "GLD", "LNK", "CNOTA", "IOW", "VORIN", "JOT", "GIJ", "PLAIN", "GERBS", "IDEAS", "WOOST", "CXR", "TEESY", "MIGET", "WEVEL", "ETG", "MIP", "FJC", "JFK"]},
+    "J147":{ "name":"J147", "fixes":["BKW", "LWB", "RHODE", "CSN"]},
+    "J148":{ "name":"J148", "fixes":["OAL", "KROST", "DTA", "MTU", "CYS", "HANKI", "ONL", "GOOLD", "MCW"]},
+    "J149":{ "name":"J149", "fixes":["AML", "GINYA", "RAMAY", "EYTEE", "SINDE", "GEFFS", "HACKS", "SUMET", "VLADY", "EMPTY", "MECAN", "ROD", "FWA"]},
+    "J15":{ "name":"J15", "fixes":["IAH", "MARCS", "JCT", "FUSCO", "LOWGO", "INK", "CME", "HONDS", "CNX", "ABQ", "CURLY", "TANER", "PUMPS", "RSK", "BDROC", "SINSY", "JNC", "TCH", "TWF", "BOI", "IMB", "TIMEE", "BTG"]},
+    "J150":{ "name":"J150", "fixes":["GVE", "BOOYA", "OTT", "GRACO", "AGARD", "BROSS", "STIKY", "OOD", "BESSI", "CYN", "AJGON", "HTO", "MONTT", "OFTUR", "LFV", "STOOL"]},
+    "J151":{ "name":"J151", "fixes":["CTY", "CAPPS", "NEDDY", "WYATT", "VUZ", "GETME", "BEATS", "FLORS", "DITZL", "VISQA", "CRELL", "FAM", "SLVER", "STL", "IRK", "OVR", "ONL", "RAP", "BIL", "JAPER", "HIA"]},
+    "J152":{ "name":"J152", "fixes":["ROD", "TRAKK", "BLISS", "AVERE", "JST", "MIROY", "COFAX", "LOMON", "HAR"]},
+    "J153":{ "name":"J153", "fixes":["REO", "BKE", "BEAMO", "CHASS", "BLUNT", "GEG"]},
+    "J154":{ "name":"J154", "fixes":["BAM", "SPRUZ", "BVL", "TCH", "OCS", "ALPOE", "AUTIM", "RAMMS", "AVVVS", "DVV", "DANDD", "SELLS", "RYLIE", "GCK"]},
+    "J156":{ "name":"J156", "fixes":["ILC", "EKR"]},
+    "J157":{ "name":"J157", "fixes":["MTU", "LAR", "BFF", "RAP"]},
+    "J158":{ "name":"J158", "fixes":["MVA", "TOYBE", "RUBII", "SPRUZ", "LCU", "MLD", "BPI", "DDY", "RAP", "ABR"]},
+    "J159":{ "name":"J159", "fixes":["BTG", "DSD"]},
+    "J16":{ "name":"J16", "fixes":["BTG", "LAVAA", "KOTAA", "PDT", "CHASS", "DOXIE", "HIA", "BIL", "RECAP", "DPR", "FSD", "HAYNS", "ONTIJ", "MCW", "SABBO", "SIBER", "DUTYS", "BAE"]},
+    "J161":{ "name":"J161", "fixes":["ZUN", "RSK"]},
+    "J162":{ "name":"J162", "fixes":["DJB", "GAABE", "MAINE", "SPOOL", "AIR", "MGW", "BAABY", "LIZIO", "MRB"]},
+    "J163":{ "name":"J163", "fixes":["BKE", "BOI", "PIH", "OCS", "CHE"]},
+    "J165":{ "name":"J165", "fixes":["CHS", "DWYTE", "NKKIE", "RIC"]},
+    "J166":{ "name":"J166", "fixes":["SSO", "TCS", "CME", "DUMPS", "SPS"]},
+    "J168":{ "name":"J168", "fixes":["SPS", "LAA"]},
+    "J169":{ "name":"J169", "fixes":["LAX", "SLI", "TRM", "SHADI", "BLH", "SALOM", "KOFFA", "TFD"]},
+    "J17":{ "name":"J17", "fixes":["SAT", "ROOMY", "ABI", "DUMPS", "TURKI", "PNH", "KENTO", "TBE", "PUB", "FQF", "CYS", "RAP"]},
+    "J170":{ "name":"J170", "fixes":["CZI", "DDY", "MBW"]},
+    "J171":{ "name":"J171", "fixes":["TBE", "TODDE", "HGO"]},
+    "J173":{ "name":"J173", "fixes":["TCH", "ODUCE", "EKR"]},
+    "J174":{ "name":"J174", "fixes":["CRG", "MILIE", "CHS", "ILM", "DIW", "CLAPY", "GILMA", "EDDYS", "ORF", "SAWED", "KALDA", "DUNFE", "SWL", "WARNN", "ZIZZI", "YAZUU", "EMJAY", "GEDIC", "RIFLE", "HTO", "MONTT", "OFTUR", "LFV", "HERIN"]},
+    "J175":{ "name":"J175", "fixes":["CYS", "LAR", "DBS"]},
+    "J177":{ "name":"J177", "fixes":["IAH", "HUB", "PSX", "KANNA"]},
+    "J178":{ "name":"J178", "fixes":["FWA", "APE"]},
+    "J18":{ "name":"J18", "fixes":["MZB", "GWIRE", "IPL", "HEEDS", "BZA", "HOGGZ", "MOHAK", "JUDTH", "GBN", "PXR", "FORPE", "CHEKR", "BOLIC", "VERNO", "SJN", "ABQ", "FTI", "KENTO", "DRAWL", "GCK", "SLN", "STJ", "BACNN", "CHASY", "ALBRT", "MZV", "JOT"]},
+    "J180":{ "name":"J180", "fixes":["IAH", "DAS", "CIDOR", "FOSIN", "SWB", "KAMEN", "DHART", "JOLET", "LIT", "ZAVEL", "FTZ"]},
+    "J181":{ "name":"J181", "fixes":["FUZ", "OKM", "EOS", "HLV", "BAYLI", "MAGOO", "NORIS", "BDF"]},
+    "J182":{ "name":"J182", "fixes":["GLD", "KIRKE", "RASCL", "ICT", "BURDN", "CHELI", "COODY", "RZC"]},
+    "J183":{ "name":"J183", "fixes":["ELP", "PEQ", "FUSCO", "LLO", "CLL"]},
+    "J184":{ "name":"J184", "fixes":["BXK", "SATRN", "WOBUG", "DMN", "EWM"]},
+    "J186":{ "name":"J186", "fixes":["ODF", "SOT", "KTRYN", "BULEY", "OHOLO", "OHIOS", "APE"]},
+    "J187":{ "name":"J187", "fixes":["MEM", "ZESAM", "BSIDE", "FTZ"]},
+    "J189":{ "name":"J189", "fixes":["AVE", "LIN", "LMT", "HRMNS", "MRTEN", "BTG", "ALDER", "SEA"]},
+    "J19":{ "name":"J19", "fixes":["PXR", "CHEAR", "ZUN", "BUKKO", "FLYBY", "FTI", "LBL", "VARNR", "ICT", "ROKNE", "DOSOA", "BUM", "SCAWT", "ELSTO", "TRAKE", "STL", "RBS", "OBK"]},
+    "J190":{ "name":"J190", "fixes":["CRL", "KEEHO", "DORET", "ZORBO", "SLT", "KONJE", "REBBL", "CFB", "KODEY", "RKA", "ALB"]},
+    "J191":{ "name":"J191", "fixes":["RBV", "BRAND", "DAVYS", "EDJER", "BESSI", "ENO", "PALMM", "CANNY", "RIDGY", "CLASY", "GARED", "PXT", "HUBBS", "HPW", "PELTO", "ILM"]},
+    "J192":{ "name":"J192", "fixes":["GLD", "PWE", "IOW"]},
+    "J193":{ "name":"J193", "fixes":["ILM", "WEAVR", "CVI", "KATZN", "HCM", "HUBBS"]},
+    "J196":{ "name":"J196", "fixes":["BCE", "RIFMN", "EKR"]},
+    "J197":{ "name":"J197", "fixes":["DVC", "HGO", "GLD", "OBH", "FSD"]},
+    "J198":{ "name":"J198", "fixes":["MVA", "KROST", "ILC", "OFTEC", "RIFMN", "EKR"]},
+    "J199":{ "name":"J199", "fixes":["ILC", "DTA", "OFFIG", "HELPR", "EKR"]},
+    "J2":{ "name":"J2", "fixes":["MZB", "GWIRE", "IPL", "HEEDS", "BZA", "HOGGZ", "MOHAK", "JUDTH", "GBN", "ALMON", "TUS", "OLIIN", "ALIBY", "ELP", "FIGMO", "FST", "KEMPL", "JCT", "LEJON", "SAT", "IAH", "LCH", "LSU", "SJI", "MUURY", "INBRD", "CEW", "DEFUN", "OJHAP", "SZW", "CAPPS", "ZOOSS", "TAY"]},
+    "J20":{ "name":"J20", "fixes":["SEA", "RADDY", "YKM", "BRUKK", "PDT", "BEAMO", "DNJ", "PIH", "OCS", "FQF", "QUAIL", "HGO", "LAA", "DRAWL", "LBL", "ROLLS", "IRW", "ATOKA", "PLATE", "DECOD", "EIC", "BERKE", "MIXIE", "STAGE", "KAMEN", "MHZ", "MEI", "MGM", "SZW", "VIRHI", "ORL"]},
+    "J202":{ "name":"J202", "fixes":["FFU", "ODUCE", "OCS", "DDY"]},
+    "J203":{ "name":"J203", "fixes":["BIL", "HILGR", "GTF"]},
+    "J204":{ "name":"J204", "fixes":["DPR", "MLS", "HILGR", "GTF"]},
+    "J206":{ "name":"J206", "fixes":["ALS", "HBU", "DBL", "NLSEN", "OCS"]},
+    "J207":{ "name":"J207", "fixes":["SAV", "FLO", "STUKK", "RDU", "JIMAR", "FKN"]},
+    "J208":{ "name":"J208", "fixes":["AHN", "GLOVR", "LIB", "SAMMB", "FOZZY", "ZITTO", "HPW"]},
+    "J209":{ "name":"J209", "fixes":["GRD", "DARRL", "BEAUU", "RDU", "FRANZ", "TYI", "ORF", "SAWED", "SBY", "VILLS", "CYN", "WHITE"]},
+    "J21":{ "name":"J21", "fixes":["SUTOL", "TTXOX", "LRD", "SAT", "CWK", "ACT", "FUZ", "ADM", "IRW", "ICT", "PEABO", "GOSSL", "JUDGE", "OVR", "TODDO", "EYHUX", "SIMJI", "GOOLD", "ONTIJ", "HARPI", "GEP", "DLH"]},
+    "J210":{ "name":"J210", "fixes":["DUNKN", "DEQUE", "VAN", "JOINT", "JMACK", "ILM"]},
+    "J211":{ "name":"J211", "fixes":["YNG", "HAGUD", "GRACE", "JST", "LEONI", "BUSTR", "JERES", "EMI"]},
+    "J212":{ "name":"J212", "fixes":["TFD", "BXK", "CULTS", "HRRBR", "CURIV", "DECAS", "PSP"]},
+    "J213":{ "name":"J213", "fixes":["BKW", "ROCKA", "DILNN", "SEALZ", "FINKS", "KERRE", "DOCCS", "AML"]},
+    "J217":{ "name":"J217", "fixes":["HNK", "ZUUCS", "ETG"]},
+    "J22":{ "name":"J22", "fixes":["NLD", "LRD", "CRP", "HYNES", "PSX", "HEIGH", "LCH", "MCB", "MEI", "DELBE", "VUZ", "CALCO", "VXV", "YICUT", "PSK", "MOL"]},
+    "J220":{ "name":"J220", "fixes":["AML", "JERES", "BEETS", "MICAH", "VALLO", "OGESY", "FORTT", "BIGEO", "WUNDR", "SFK"]},
+    "J222":{ "name":"J222", "fixes":["RBV", "LAURN", "JFK", "GREKI", "CAM"]},
+    "J223":{ "name":"J223", "fixes":["LGA", "NEION", "HOPCE", "CORDS"]},
+    "J225":{ "name":"J225", "fixes":["VCN", "DITCH", "LUIGI", "HNNAH", "JFK", "NEWES", "BAWLL", "RAALF", "PVD"]},
+    "J227":{ "name":"J227", "fixes":["AML", "JERES", "BEETS", "MICAH", "VALLO", "OGESY", "TYMAN", "BABEE", "STENT", "KONJE", "ULW"]},
+    "J23":{ "name":"J23", "fixes":["SAT", "HENLY", "SPURS", "JUMBO", "EDNAS", "HICOE", "MQP", "BATIK", "IRW", "PER", "JAMEY", "ICT"]},
+    "J230":{ "name":"J230", "fixes":["RBV", "COPES", "BYRDD", "SAAME", "LARRI", "BEETS", "GRAHM", "VINSE", "LEJOY", "AIR"]},
+    "J231":{ "name":"J231", "fixes":["TNP", "CADEZ", "HIPPI", "DRK", "NABOB", "PAYSO", "CHEAR", "SJN", "ACH", "LBL"]},
+    "J232":{ "name":"J232", "fixes":["MZV", "BURKK", "IRK"]},
+    "J233":{ "name":"J233", "fixes":["STL", "IRK", "SKBOZ", "CNOTA", "CAPPR", "ALO"]},
+    "J236":{ "name":"J236", "fixes":["TRM", "EED", "TBC"]},
+    "J239":{ "name":"J239", "fixes":["ATL", "WEONE", "JAMMR", "MEI"]},
+    "J24":{ "name":"J24", "fixes":["MTU", "CHE", "HGO", "SELLS", "OATHE", "HYS", "SLN", "JUDGE", "MCI", "DRIVL", "WELTS", "STL", "COWES", "TILMN", "VHP", "BIGXX", "HICKI", "FLM", "HVQ", "TARCI", "TUKEY", "OAKLE", "BIGAL", "MOL", "FAK", "RUSSL", "HCM"]},
+    "J240":{ "name":"J240", "fixes":["MTU", "HBU"]},
+    "J244":{ "name":"J244", "fixes":["FTI", "ZUN", "CHEAR", "PXR"]},
+    "J25":{ "name":"J25", "fixes":["MAM", "BRO", "CRP", "ICEMN", "SAT", "CWK", "ACT", "FUZ", "ATOKA", "DWINE", "TUL", "DOSOA", "MCI", "BACNN", "DSM", "JORDY", "MCW", "GEP", "OLLEE", "GOLLF", "BRD", "YWG"]},
+    "J26":{ "name":"J26", "fixes":["CJS", "ELP", "SUMMY", "CME", "PNH", "MMB", "ZENDA", "ICT", "FRACA", "MCI", "IRK", "COLIE", "LOAMY", "KEOKK", "BDF", "JOT"]},
+    "J27":{ "name":"J27", "fixes":["SAT", "MARCS", "PUFER", "BAZBL", "STELL", "LFK"]},
+    "J28":{ "name":"J28", "fixes":["MLF", "HVE", "BDROC", "HBU", "ELWAY", "KANON", "RODDY", "FLOOD", "PUB", "GCK", "KYLER", "ICT"]},
+    "J29":{ "name":"J29", "fixes":["SUTOL", "DEVOE", "CRP", "HYNES", "PSX", "IAH", "RAECN", "DARTR", "VELCO", "ENJOY", "LURIC", "MIXIE", "ELD", "SUTTN", "TOZZI", "CARIN", "MEM", "VISQA", "TINGS", "PXV"]},
+    "J3":{ "name":"J3", "fixes":["OAK", "RBL", "LKV", "IMB", "GEG"]},
+    "J30":{ "name":"J30", "fixes":["ODI", "SIBER", "BRIBE", "COTON", "JOT", "MOPER", "WHETT", "TRAKK", "APE", "OTMAN", "KARYL", "LUISE", "BUCKO", "SHAAR", "ESL", "DRUZZ", "TRIXY"]},
+    "J31":{ "name":"J31", "fixes":["LEV", "HRV", "MEI", "DELBE", "VUZ"]},
+    "J32":{ "name":"J32", "fixes":["OAK", "SAC", "COLOM", "FMG", "LLC", "BAM", "PARKA", "MLD", "BOY", "CZI", "DPR", "ABR", "DLH"]},
+    "J33":{ "name":"J33", "fixes":["IAH", "LITLD", "BLTWY", "STELL", "CRIED", "DONIE", "TANBE", "FUZ"]},
+    "J34":{ "name":"J34", "fixes":["HQM", "OLM", "RADDY", "MWH", "ODESS", "HLN", "BIL", "RECAP", "DPR", "RWF", "HARPI", "ODI", "HILRO", "DLL", "BAE", "ADALE", "VIO", "HASTE", "ALPHE", "CRL", "WOOST", "RIEKE", "DJB", "GAABE", "MAINE", "SPOOL", "AIR", "BUCKO", "SHAAR", "ESL", "DRUZZ", "TRIXY"]},
+    "J35":{ "name":"J35", "fixes":["LEV", "OYSTY", "ZYDCO", "MCB", "MCGEE", "SQS", "XESSS", "MEM", "KIMEL", "RUSLR", "FAM", "SLVER", "STL", "FARGO", "SPI", "PNT", "JOT", "OBK"]},
+    "J36":{ "name":"J36", "fixes":["MLP", "GTF", "HILGR", "DIK", "FAR", "GEP", "ODI", "DUTYS", "BAE", "DABJU", "FNT"]},
+    "J37":{ "name":"J37", "fixes":["HUB", "HEIGH", "PEKON", "HRV", "SJI", "CATLN", "MGM", "AJFEB", "SPA", "COLZI", "SANNY", "LYH", "GVE", "BRV", "CLASY", "NALES", "VILLS", "CYN", "JFK", "LLUND", "DUEYS", "GANDE", "IGN", "ATHOS", "ALB", "MSS"]},
+    "J39":{ "name":"J39", "fixes":["CEW", "MGM", "VUZ", "SALMS", "BNA", "IIU", "GBEES", "HICKI", "CREEP", "ROD"]},
+    "J4":{ "name":"J4", "fixes":["LAX", "JUGLI", "CIVET", "RUSTT", "PIONE", "TNP", "PKE", "MESSI", "BXK", "SSO", "EWM", "CONNE", "INK", "ABI", "FUZ", "EIC", "BERKE", "MIXIE", "STAGE", "KAMEN", "MHZ", "MEI", "MGM", "AJFEB", "IRQ", "CAE", "FLO", "DWYTE", "MULLS", "BARTL", "ILM"]},
+    "J40":{ "name":"J40", "fixes":["MGM", "MCN", "TWINS", "TYDOE", "CHS", "ILM", "TILTZ", "TYI", "JAGEM", "RIC"]},
+    "J41":{ "name":"J41", "fixes":["EYW", "MARCI", "RSW", "PIE", "TABIR", "PLYER", "LEGGT", "HEVVN", "SZW", "MGM", "VUZ", "LOBBS", "GOOGY", "MEM", "LUKKY", "ZAVEL", "SGF", "EUNIK", "SCAWT", "MCI", "AGENT", "OVR"]},
+    "J42":{ "name":"J42", "fixes":["DEL", "AMUKI", "FST", "LOWGO", "ABI", "FUZ", "TXK", "WASKO", "MATIE", "JOLET", "ARIGY", "MEM", "DITZL", "KAZER", "BNA", "SWAPP", "GHATS", "FOUNT", "TONIO", "KONGO", "NEALS", "BKW", "ASBUR", "DENNY", "MOL", "GVE", "BOOYA", "OTT", "GRACO", "AGARD", "BROSS", "STIKY", "OOD", "DAVYS", "BRAND", "RBV", "LAURN", "LLUND", "SANTT", "PACER", "HFD", "PUT", "BOS"]},
+    "J43":{ "name":"J43", "fixes":["DHP", "WINCO", "LBV", "CHRRI", "MMDUQ", "PIE", "TABIR", "PLYER", "LEGGT", "HEVVN", "SZW", "NEDDY", "SOTWO", "ATL", "NOTWO", "VXV", "FOUNT", "YOCKY", "DACOS", "FLM", "ROD", "JECKA", "MAYZE", "ANEWA", "IDEAS", "NELLS", "CRL"]},
+    "J44":{ "name":"J44", "fixes":["PXR", "INW", "DILCO", "DEXTR", "RSK", "ALS", "BINKE", "VIMPY", "FQF", "MCK", "LNK"]},
+    "J45":{ "name":"J45", "fixes":["VKZ", "HEATT", "BLUFI", "TRV", "OVIDO", "OMN", "CRG", "YULEE", "HILRD", "AMG", "MCN", "ATL", "BNA", "LAJUG", "TINGS", "DENNI", "PLESS", "STL", "IRK", "DSM", "EYHUX", "FSD", "ABR"]},
+    "J46":{ "name":"J46", "fixes":["TUL", "PLIED", "LUKKY", "ARG", "ZESAM", "KIMEL", "SOPIE", "BNA", "RABOW", "VXV", "AHN", "AMG"]},
+    "J47":{ "name":"J47", "fixes":["CHS", "CAE", "SPA"]},
+    "J478":{ "name":"J478", "fixes":["GGW", "YQL"]},
+    "J48":{ "name":"J48", "fixes":["LANNA", "PTW", "BYRDD", "HAAGN", "PENSY", "EMI", "CSN", "MOL", "FLASK", "REAVS", "ODF"]},
+    "J483":{ "name":"J483", "fixes":["MOT", "VLN"]},
+    "J49":{ "name":"J49", "fixes":["PSB", "BIGEO", "MAGIO", "DGRAF", "DARBO", "BUFFY", "HNK", "ALB", "SQUAM", "FRIAR", "BGR", "PQI"]},
+    "J5":{ "name":"J5", "fixes":["LAX", "LANDO", "EHF", "PINNI", "TIOGA", "SONNY", "TILTS", "FMG", "PYRAM", "HARTT", "BAARB", "LKV", "POWEL", "SUMMA", "TAOMA", "SEA", "YVR"]},
+    "J50":{ "name":"J50", "fixes":["EHF", "LANDO", "BOILE", "PDZ", "YCDIL", "WBERG", "BLH", "SALOM", "KOFFA", "GBN", "TFD", "TOTEC", "ITEMM", "SSO", "ALIBY", "ELP", "LINZY", "INK", "ABI", "HICOE", "ACT", "TORNN", "CRIED", "LFK", "VELCO", "TBEND", "CIDOR", "AEX", "MCB", "CEW"]},
+    "J501":{ "name":"J501", "fixes":["RZS", "PEGRS", "ZONAL", "BSR", "PYE", "NIECE", "OED", "HQM", "WAPTO", "TOU", "YAZ", "YZP", "MOCHA", "BKA", "HOLIE", "YAK", "KATAT", "CASEL", "JOH", "TED", "YONEK", "TORTE", "SQA", "VIDDA", "BET"]},
+    "J502":{ "name":"J502", "fixes":["SEA", "ORCUS", "YYJ", "ARRUE", "ROYST", "YZT", "PRYCE", "DUGGS", "HANRY", "ANN", "GESTI", "DOOZI", "LVD", "HOODS", "SSR", "DB", "AYZOL", "ORT", "RDFLG", "HRDNG", "FAI", "OTZ"]},
+    "J503":{ "name":"J503", "fixes":["SEA", "DIABO", "IWACK", "FOLDY", "YDC"]},
+    "J505":{ "name":"J505", "fixes":["SEA", "FLAAK", "TWISP", "ONSET", "SILVR", "YXC"]},
+    "J506":{ "name":"J506", "fixes":["MLT", "TOPPS", "AJGUB"]},
+    "J51":{ "name":"J51", "fixes":["CRG", "VIYAP", "SAV", "CAE", "CASAT", "TUBAS", "FLOPS", "FOZZY", "CREWE", "FAK", "SHONA", "QBEES", "OTT", "PALEO", "SWANN", "KERNO", "DQO", "ARD"]},
+    "J515":{ "name":"J515", "fixes":["FAR", "HML", "YWG", "YXY", "BIBEM", "ORT", "RDFLG", "HRDNG", "FAI", "BTT", "BRW"]},
+    "J516":{ "name":"J516", "fixes":["GTF", "COUTS", "YQL"]},
+    "J517":{ "name":"J517", "fixes":["BOI", "GEG", "EDGES", "BZXIV", "YXC"]},
+    "J518":{ "name":"J518", "fixes":["DJB", "SRPEN", "LEPEW", "LIVER", "KOZAR", "KODIE", "AVERE", "LEJOY", "IHD", "MCRAY", "BUFFR", "LINSE", "BAL"]},
+    "J52":{ "name":"J52", "fixes":["YVR", "SHUKA", "TWISP", "GEG", "DOXIE", "LKT", "DBS", "OCS", "FQF", "QUAIL", "HGO", "LAA", "DRAWL", "LBL", "ROLLS", "DANKS", "CRUSR", "MRMAC", "ADM", "TXK", "CISAR", "SUTTN", "SQS", "CLOUT", "IGB", "FIBER", "VUZ", "ATL", "AJFEB", "IRQ", "CAE", "CASAT", "TUBAS", "RDU", "HAKOK", "JADEE", "ZITTO", "RIC"]},
+    "J523":{ "name":"J523", "fixes":["BCE", "ELY", "REKKA", "DERMT", "REO", "IMB", "LTJ", "WANTA", "SEA", "ARRIE", "TOU", "INHAM", "YZT", "YZP", "BOKMA", "ANN"]},
+    "J526":{ "name":"J526", "fixes":["BKW", "ZIEBR", "IIU"]},
+    "J53":{ "name":"J53", "fixes":["DHP", "BRIKL", "HEDLY", "PHK", "CFVPP", "ORL", "WORMS", "BARBS", "MATEO", "CRG", "NOWAY", "DUNKN", "GRADY", "IRQ", "SPA", "PSK"]},
+    "J530":{ "name":"J530", "fixes":["GTF", "GGRBI", "YYN"]},
+    "J533":{ "name":"J533", "fixes":["DLH", "MPCEG", "YQT"]},
+    "J534":{ "name":"J534", "fixes":["IWACK", "HUH", "JBBDT", "SEATN", "KANOO", "YWL"]},
+    "J537":{ "name":"J537", "fixes":["REO", "MLP", "ONEAL", "YYC"]},
+    "J538":{ "name":"J538", "fixes":["VBI", "HLDOL", "DLH", "DLL", "BAE"]},
+    "J539":{ "name":"J539", "fixes":["GGW", "YYN"]},
+    "J54":{ "name":"J54", "fixes":["TOU", "OLM", "SUMMA", "WANTA", "KOTAA", "BKE", "BOI", "PIH", "CKW", "LAR"]},
+    "J540":{ "name":"J540", "fixes":["MLP", "STIGS", "YQL"]},
+    "J547":{ "name":"J547", "fixes":["OBK", "KUBBS", "PMM", "HASTE", "DEWIT", "FNT"]},
+    "J548":{ "name":"J548", "fixes":["PMM", "WLTER", "ADALE", "BITTR", "UFDUH", "PECOK", "TVC"]},
+    "J549":{ "name":"J549", "fixes":["ISN", "YBR"]},
+    "J55":{ "name":"J55", "fixes":["DHP", "THNDR", "RELLI", "LLAKE", "INPIN", "LOULO", "CRG", "VIYAP", "SAV", "CHS", "FLO", "TUBAS", "RDU", "HAKOK", "JADEE", "ZITTO", "HPW", "HUBBS", "SIE", "AVALO", "BRIGS", "DRIFT", "MANTA", "PLUME", "SHERL", "DUNEE", "SARDI", "SHLEP", "HOFFI", "HTO", "PARCH", "TRAIT", "PVD", "BOS", "ENE", "FRIAR", "PQI"]},
+    "J554":{ "name":"J554", "fixes":["GIJ", "BENJO", "CRL", "COHOW", "SURLY", "JHW"]},
+    "J56":{ "name":"J56", "fixes":["MVA", "TCH", "NLSEN", "CHE", "GOULL", "FROGS", "RIDJE", "TOMSN", "FQF"]},
+    "J561":{ "name":"J561", "fixes":["PQI", "YYY"]},
+    "J562":{ "name":"J562", "fixes":["DIK", "YBR"]},
+    "J563":{ "name":"J563", "fixes":["ALB", "LAMED", "COVAN", "YSC"]},
+    "J569":{ "name":"J569", "fixes":["GTF", "DORSE", "YXC"]},
+    "J57":{ "name":"J57", "fixes":["TCS", "ONM", "ABQ"]},
+    "J570":{ "name":"J570", "fixes":["ALB", "NIPPY", "BUGSY", "KELVI", "YMX"]},
+    "J573":{ "name":"J573", "fixes":["ENE", "SCARS", "SEAER", "EBONY", "YSJ"]},
+    "J575":{ "name":"J575", "fixes":["BOS", "SCUPP", "CANAL", "TUSKY", "YQI"]},
+    "J58":{ "name":"J58", "fixes":["OAL", "ILC", "MLF", "RSK", "RGINA", "ESPAN", "FTI", "PNH", "SPS", "BATIK", "FUZ", "ADUKE", "LURIC", "NOBBL", "TURNN", "FOSIN", "AEX", "PEBBY", "HRV"]},
+    "J582":{ "name":"J582", "fixes":["PQI", "YZV"]},
+    "J584":{ "name":"J584", "fixes":["OBK", "UNBAR", "COYNU", "CRL", "KEEHO", "DORET", "ZORBO", "SLT", "FQM", "MEGSS", "HAYED", "BWZ"]},
+    "J585":{ "name":"J585", "fixes":["ACK", "STOOL", "DAVES", "YQI"]},
+    "J589":{ "name":"J589", "fixes":["RBG", "CVO", "ELMAA", "YYJ"]},
+    "J59":{ "name":"J59", "fixes":["PSB", "ZUUCS", "CNTER", "EXTOL", "AUDIL", "SYR"]},
+    "J590":{ "name":"J590", "fixes":["LCH", "LSU", "GCV", "MGM"]},
+    "J591":{ "name":"J591", "fixes":["HUH", "ANTLR"]},
+    "J599":{ "name":"J599", "fixes":["MLP", "TWIGY", "FINBO", "YXC"]},
+    "J6":{ "name":"J6", "fixes":["SNS", "GOALI", "ROBIE", "AVE", "LANDO", "PMD", "HELDE", "HEC", "EED", "CHILY", "DRK", "PYRIT", "ZUN", "ABQ", "TCC", "PNH", "CRUSR", "IRW", "DWINE", "KLUBB", "KOMMA", "LIT", "SOPIE", "LAJUG", "BWG", "RYANS", "UNCKL", "YOCKY", "SPAYD", "HVQ", "PERKS", "COLNS", "EYTEE", "MRB", "HYPER", "FLIRT", "SAAME", "LRP", "HOUTN", "KAYNE", "TOWIN", "PARKE", "BWZ", "SAX", "JEFFF", "FLOSI", "WEETS", "ACOVE", "ALB"]},
+    "J60":{ "name":"J60", "fixes":["LAX", "PDZ", "CIVET", "RESOR", "HEC", "BLD", "BCE", "HVE", "DBL", "DVV", "HCT", "DRABS", "LNK", "CNOTA", "IOW", "VORIN", "JOT", "HOBAR", "GSH", "ASHEN", "NAPOL", "MAYZE", "JERRI", "DJB", "CANCR", "HAGUD", "TYSUN", "MIDST", "PSB", "DOOTH", "FORTT", "DANNR", "GYNTS", "NEWEL", "CANDR", "SAX"]},
+    "J61":{ "name":"J61", "fixes":["EDDYS", "FORTS", "HUBBS", "COLIN", "DAILY", "OTT", "EMI", "LARRI", "MICAH", "BURNI", "PSB"]},
+    "J614":{ "name":"J614", "fixes":["SRQ", "RSW", "KUBIC", "OHOFO", "DHP"]},
+    "J616":{ "name":"J616", "fixes":["SRQ", "MMDUQ", "CHRRI", "LBV", "WINCO", "DHP"]},
+    "J62":{ "name":"J62", "fixes":["RBV", "JOANI", "CREEL", "SHLEP", "RIFLE", "KYSKY", "CUTOX", "CUJKE", "ACK"]},
+    "J64":{ "name":"J64", "fixes":["LAX", "JUGLI", "CIVET", "RESOR", "HEC", "GLACO", "PGS", "TBC", "RHYSS", "COCAN", "RSK", "PUB", "HLC", "PWE", "LMN", "JAVAS", "ALBRT", "BURKK", "BDF", "CADIZ", "WHETT", "FWA", "GONER", "CASIO", "MAINE", "LEPEW", "EWC", "BURNI", "MCMAN", "VALLO", "RAV", "SUZIE", "SARAA"]},
+    "J65":{ "name":"J65", "fixes":["SAT", "WEELS", "ABI", "CME", "TCS", "TMACK", "TAGGS", "PXR", "KOFFA", "SALOM", "BLH", "DECAS", "AERRO", "PMD", "LANDO", "EHF", "CZQ", "SAC", "RBL", "LMT", "SEA"]},
+    "J66":{ "name":"J66", "fixes":["EWM", "BGS", "ABI", "FUZ", "BYP", "DECOD", "GLOVE", "MEEOW", "LIT", "GEEYY", "MEM", "BEATS", "DEVAC", "WODDY", "CALCO", "RMG"]},
+    "J67":{ "name":"J67", "fixes":["LIN", "LKV", "BTG"]},
+    "J68":{ "name":"J68", "fixes":["GEP", "NICKL", "DLL", "BAE", "DABJU", "FNT", "HNK", "PONEE", "DEKOW", "SWALO", "PUT", "PVD", "ACK"]},
+    "J69":{ "name":"J69", "fixes":["SJI", "DELBE", "VUZ"]},
+    "J7":{ "name":"J7", "fixes":["LAX", "FIM", "REYES", "DERBB", "REBRG", "FRA", "GENNE", "FMG", "GASSI", "REO", "BOI", "LKT", "GTF", "GGRBI"]},
+    "J70":{ "name":"J70", "fixes":["HQM", "ELMAA", "SEA", "NORMY", "BLUIT", "EPH", "MLP", "LWT", "DIK", "ABR", "GEP", "NICKL", "WILDD", "AUGER", "BAE", "PMM", "ALPHE", "DUNKS", "SVM", "DAFLU", "BROKK", "BEWEL", "JHW", "HOXIE", "DMACK", "STENT", "MAGIO", "LVZ", "JENNO", "HARTY", "STW", "LGA", "JFK"]},
+    "J71":{ "name":"J71", "fixes":["MEM", "HUMBO", "CRELL", "ENL", "BOSIE", "CAROL", "COWES", "WLDBL", "GORDO", "JARKE", "RBS", "OBK"]},
+    "J713":{ "name":"J713", "fixes":["BIL", "BOY", "BPI", "TCH"]},
+    "J72":{ "name":"J72", "fixes":["BLD", "PGS", "CUTRO", "BAVPE", "HMFRY", "DILCO", "GUP", "LORAT", "ABQ", "MIERA", "TXO", "TURKI", "GANJA", "SPS"]},
+    "J73":{ "name":"J73", "fixes":["DHP", "WINCO", "LBV", "CHRRI", "LAL", "KRNEL", "CORSU", "BLRNE", "SZW", "WYATT", "GOONS", "LGC", "BNA", "PXV", "TILMN", "GUIDO", "OBK"]},
+    "J74":{ "name":"J74", "fixes":["LAX", "PDZ", "YCDIL", "PKE", "NICKT", "NABOB", "PAYSO", "CHEAR", "SJN", "DRYHT", "MAXXO", "CNX", "TXO", "IRW"]},
+    "J75":{ "name":"J75", "fixes":["DHP", "OHOFO", "KUBIC", "RSW", "TEPEE", "KRNEL", "HITTR", "TAY", "DUNKN", "TYDOE", "TREAL", "CAE", "GLOVR", "GSO", "DRAIK", "GVE", "BINKS", "MURPH", "SACRI", "STOEN", "MXE", "COPES", "BIGGY", "SBJ", "JERSY", "DUEYS", "CMK", "GREKI", "NELIE", "SWALO", "BOS"]},
+    "J76":{ "name":"J76", "fixes":["LAS", "RENTT", "CUNDY", "CORKR", "TBC", "TANER", "FTI", "TCC", "SONYA", "SPS"]},
+    "J78":{ "name":"J78", "fixes":["LAX", "SLI", "TRM", "PKE", "LANCY", "DRK", "PYRIT", "ZUN", "ABQ", "TCC", "PNH", "CRUSR", "IRW", "TUL", "FAM", "PLESS", "PXV", "IIU", "DACOS", "HVQ"]},
+    "J79":{ "name":"J79", "fixes":["EYW", "CARNU", "DVALL", "DHP", "PBI", "TRV", "MALET", "OMN", "BEENO", "MILIE", "CHS", "JOINT", "MULLS", "HASET", "BLAMO", "TYI", "FKN", "KATZN", "LEESA", "SBY", "VILLS", "JOANI", "JFK", "HOFFI", "CUTOX", "CUJKE", "LFV", "AWNUM", "SEAER", "BGR"]},
+    "J8":{ "name":"J8", "fixes":["EED", "CADDU", "FLG", "GUP", "BUKKO", "FLYBY", "FTI", "BGD", "DANKS", "IFI", "SEGLR", "COODY", "SGF", "CROCK", "STL", "BOSIE", "ELIOE", "IMPEL", "IIU", "DACOS", "HVQ", "PERRI", "DILNN", "RHODE", "CSN"]},
+    "J80":{ "name":"J80", "fixes":["OAL", "ILC", "MLF", "SAKES", "JNC", "GLENO", "DBL", "FQF", "GLD", "CUGGA", "HLC", "SLOWR", "CATTS", "MCI", "SAAGS", "TWAIN", "BAYLI", "SPI", "GORDO", "JAAVE", "VHP", "FYLLS", "CREEP", "EMPTY", "BOWRR", "ZANDR", "CORVS", "AIR"]},
+    "J81":{ "name":"J81", "fixes":["DHP", "BRIKL", "HEDLY", "PHK", "CFVPP", "ORL", "KRSTN", "VQQ", "YULEE", "CHESN", "NOWAY", "DUNKN", "GRADY", "IRQ"]},
+    "J82":{ "name":"J82", "fixes":["BTG", "DNJ", "DBS", "CZI", "RAP", "VIVID", "FSD", "SIMJI", "FOD", "VIGGR", "DBQ", "COTON", "JOT", "HOBAR", "GSH"]},
+    "J83":{ "name":"J83", "fixes":["SPA", "SPAYD", "APE", "WAAHU", "DJB"]},
+    "J84":{ "name":"J84", "fixes":["OAK", "LIN", "MELTS", "SONNY", "BABIT", "MVA", "PAWLY", "DTA", "EKR", "FROGS", "SNY", "ELJAY", "OBH", "TODDO", "JORDY", "CAPPR", "DBQ", "COTON", "OBK", "MOPER", "WORDY", "RIGGL", "DNV"]},
+    "J85":{ "name":"J85", "fixes":["DHP", "THNDR", "RELLI", "LLAKE", "INPIN", "LOULO", "GNV", "TAY", "SUESS", "AMG", "TWINS", "IRQ", "SPA", "NEALS", "HVQ", "LAYED", "JAMOX", "OTMAN", "BLISS", "BIGLE", "BOBCT", "DJB"]},
+    "J86":{ "name":"J86", "fixes":["BTY", "FUZZY", "BLD", "PGS", "CUTRO", "BAVPE", "INW", "PYRIT", "VERNO", "GREBE", "RUTER", "ELP", "FIGMO", "FST", "KEMPL", "JCT", "SPURS", "PUFER", "CUZZZ", "IAH", "KAPAA", "PEKON", "LEV"]},
+    "J87":{ "name":"J87", "fixes":["IAH", "TNV", "JUDDY", "HOMRN", "BILEE", "HOOTZ", "TORNN", "CHMPZ", "TANBE", "CVE", "TUL", "COODY", "BUM", "TYGER", "DRIVL", "SAAGS", "IRK", "BURKK", "MZV", "JOT", "OBK"]},
+    "J88":{ "name":"J88", "fixes":["LAX", "RZS", "CEANO", "ROBIE", "GOALI", "SNS", "PYE"]},
+    "J89":{ "name":"J89", "fixes":["HITTR", "FAGAN", "NECOS", "OTK", "ICBOD", "SOONE", "ATL", "NOONE", "WUDEE", "RESPE", "SWAPP", "IIU", "KURTZ", "MACES", "TORIO", "BVT", "FATOX", "CADIZ", "OBK", "BAE", "BGOSH", "DLH", "WIEDS", "YWG"]},
+    "J9":{ "name":"J9", "fixes":["LAX", "DAG", "MISEN", "CLARR", "LAS", "SUVIE", "NORRA", "BERYL", "MLF", "FRNZY", "FFU", "TCH", "DBS", "DLN", "GTF"]},
+    "J90":{ "name":"J90", "fixes":["SEA", "NORMY", "BLUIT", "MWH", "ODESS", "HLN", "MLS", "ABR", "RWF", "MCW", "SUZYQ", "VIKNG", "LARVA", "JIBOR", "BRIBE", "OBK"]},
+    "J91":{ "name":"J91", "fixes":["INPIN", "HITTR", "CTY", "JOHNN", "ATL", "NOTWO", "VXV", "BUGME", "TONIO", "BULEY", "HNN"]},
+    "J92":{ "name":"J92", "fixes":["LMT", "WNDEL", "FMG", "RYANN", "YERIN", "BABIT", "OAL", "LIDAT", "BTY", "BLD", "KADDY", "PRFUM", "CADDU", "HOBES", "DRK", "PXR", "TFD", "PICAH", "ALMON", "TUS", "VYLLA"]},
+    "J93":{ "name":"J93", "fixes":["ASUTA", "AMMOR", "JLI", "PDZ", "JUGLI", "LAX"]},
+    "J94":{ "name":"J94", "fixes":["FMG", "LLC", "BAM", "LCU", "OCS", "BFF", "ONL", "KATES", "FOD", "VIGGR", "DBQ", "COTON", "OBK", "KUBBS", "PMM", "HASTE", "DEWIT", "FNT"]},
+    "J95":{ "name":"J95", "fixes":["DPK", "HOBAM", "GAYEL", "MSLIN", "STOMP", "BUFFY", "CFB"]},
+    "J96":{ "name":"J96", "fixes":["LAX", "PDZ", "YCDIL", "PKE", "LANCY", "DRK", "KEYKE", "GUP", "CIM", "GCK", "SLN", "AGENT", "KIDER", "IRK", "NORIS", "PIA", "JOT"]},
+    "J97":{ "name":"J97", "fixes":["SLATN", "LACKS", "ACK", "BOS"]},
+    "J98":{ "name":"J98", "fixes":["LBL", "MMB", "IRW", "TUL", "ADAIR", "SGF", "TWRAY", "FAM"]},
+    "J99":{ "name":"J99", "fixes":["IRQ", "VXV", "GHATS", "RYANS", "IIU"]},
+    "Q1":{ "name":"Q1", "fixes":["PYE", "ETCHY", "TOCOS", "ENVIE", "ELENN", "EBINY", "EASON", "ERAVE", "ELMAA"]},
+    "Q103":{ "name":"Q103", "fixes":["PSK", "ASBUR", "OAKLE", "PERRI", "PERKS", "RICCS", "EMNEM", "AIRRA"]},
+    "Q104":{ "name":"Q104", "fixes":["DEFUN", "HEVVN", "LEGGT", "PLYER", "SWABE", "PIE", "CYY"]},
+    "Q106":{ "name":"Q106", "fixes":["SMELZ", "BULZI", "DRABK", "GADAY"]},
+    "Q108":{ "name":"Q108", "fixes":["GADAY", "IZZEY", "FRNKS", "HKUNA"]},
+    "Q11":{ "name":"Q11", "fixes":["PAAGE", "PAWLI", "PITVE", "PUSHH", "PASKE", "LAX"]},
+    "Q110":{ "name":"Q110", "fixes":["BLANS", "BETIE", "SKIDO", "BFOLO", "JYROD", "FEONA", "GULFR", "BRUTS", "KPASA", "RVERO", "JAYMC", "THNDR"]},
+    "Q112":{ "name":"Q112", "fixes":["INPIN", "HEVVN", "DEFUN"]},
+    "Q114":{ "name":"Q114", "fixes":["NATEE", "BLD", "ZAINY", "AHOWW", "BAWER", "BUGGG"]},
+    "Q116":{ "name":"Q116", "fixes":["KPASA", "BRUTS", "GULFR", "CEEYA"]},
+    "Q118":{ "name":"Q118", "fixes":["MZZ", "HEVAN", "VOSTK", "HELUB", "JEDER", "GLAZR", "KAILL", "JOHNN", "BRUTS", "KPASA"]},
+    "Q120":{ "name":"Q120", "fixes":["ORRCA", "BETBE", "ZORUN", "GALLI", "JAJAY", "TRAKY", "PROXI", "BPI", "JUGIV", "HIKOX", "JASTI", "UFFDA"]},
+    "Q121":{ "name":"Q121", "fixes":["PARZZ", "PIH", "TOUGH"]},
+    "Q122":{ "name":"Q122", "fixes":["MOGEE", "MACUS", "MCORD", "LCU", "BEARR", "KURSE", "ONL", "FOD"]},
+    "Q123":{ "name":"Q123", "fixes":["PARZZ", "COKEE"]},
+    "Q124":{ "name":"Q124", "fixes":["MOGEE", "MACUS", "MCORD", "SLOWN", "FASTE", "BVL", "WAATS"]},
+    "Q125":{ "name":"Q125", "fixes":["PARZZ", "WLLES"]},
+    "Q126":{ "name":"Q126", "fixes":["TIPRE", "INSLO", "GAROT", "EKR"]},
+    "Q128":{ "name":"Q128", "fixes":["SYRAH", "JSICA", "TABLL", "EDLES", "FLOOD", "ZAROS", "VEGUC", "VLUST", "ECIGE", "MUDHO", "JILLS"]},
+    "Q13":{ "name":"Q13", "fixes":["PRFUM", "CENIT", "TUMBE", "TACUS", "WODIN", "LEAHI", "LOMIA", "PAWLI"]},
+    "Q130":{ "name":"Q130", "fixes":["SYRAH", "JSICA", "REANA", "ROCCY", "HASSL", "TAHIB", "DIXAN", "MIRME", "PNH"]},
+    "Q132":{ "name":"Q132", "fixes":["WEBGO", "ANAHO", "MYBAD", "ZERAM", "MAGPY"]},
+    "Q134":{ "name":"Q134", "fixes":["DUGLE", "TATOO", "JULIK", "HERSH", "VOAXA"]},
+    "Q136":{ "name":"Q136", "fixes":["OAL", "RUMPS", "KATTS", "WEEMN", "VOAXA"]},
+    "Q138":{ "name":"Q138", "fixes":["ILA", "FIMUV", "JENSA", "ROOHZ", "PARZZ", "UROCO", "RICCO", "MOTLY", "DKOTA", "WELOK", "CESNA", "GUUME", "SNARG", "SSM"]},
+    "Q140":{ "name":"Q140", "fixes":["WOBED", "GETNG", "CORDU", "PETIY", "CHOTE", "LEWIT", "SAYOR", "WILTN", "TTAIL", "CESNA", "WISCN", "EEGEE", "DAYYY", "RUBKI", "MEDAV", "AHPAH", "HANKK", "BEEPS", "EXTOL", "MEMMS", "KODEY", "ARKKK", "RODYY", "YODAA"]},
+    "Q142":{ "name":"Q142", "fixes":["METOW", "MLP", "KEETA", "OKVUJ", "KIXCO"]},
+    "Q144":{ "name":"Q144", "fixes":["ZIRAN", "ZOOMR", "BLOWS", "KEETA", "LEWIT"]},
+    "Q145":{ "name":"Q145", "fixes":["KONGO", "HVQ", "CLNTN", "FOXEE"]},
+    "Q146":{ "name":"Q146", "fixes":["CASHS", "BLUNT", "DIPHU", "CUSDA", "ZERZO", "KIXCO", "TIMMR", "SMERF", "HUFFR"]},
+    "Q148":{ "name":"Q148", "fixes":["STEVS", "ZAXUL", "FINUT", "WEDAK", "WAIDE", "JUGIV", "MBW", "MOCTU", "LEWOY", "CUGGA", "PENUT", "KIRKE", "MORRR", "BVO"]},
+    "Q15":{ "name":"Q15", "fixes":["CHILY", "DOVEE", "BIKKR", "KENNO", "RUSME", "LOMIA"]},
+    "Q150":{ "name":"Q150", "fixes":["STEVS", "ZAXUL", "LEZLE", "BAXGO", "LAMON", "GANNE", "OPPEE"]},
+    "Q152":{ "name":"Q152", "fixes":["SUNED", "LEZLE", "WEDAK", "IKFOM", "WUVUT", "ONL"]},
+    "Q154":{ "name":"Q154", "fixes":["WANTA", "JELTI", "HOVEL", "VELUY", "BYI", "PIMIE", "NAGNE", "BONGO", "PITMN", "TAYLR", "GOSIP", "KENTO", "NOSEW", "UKW"]},
+    "Q156":{ "name":"Q156", "fixes":["STEVS", "ZAXUL", "FINUT", "TUFFY", "UPUGE", "HEXOL", "TOUGH", "JELRO", "KEKPE", "UFFDA", "HSTIN", "ZZIPR"]},
+    "Q158":{ "name":"Q158", "fixes":["NTELL", "PPARK", "TRTIS", "BIKKR", "MYCAL", "JEDNA"]},
+    "Q160":{ "name":"Q160", "fixes":["SHVVR", "FAANG", "RIVVO", "BIKKR"]},
+    "Q162":{ "name":"Q162", "fixes":["NTELL", "CABAB", "VIKSN", "KENNO", "ESSAA", "TUMBE", "MYCAL"]},
+    "Q164":{ "name":"Q164", "fixes":["NTELL", "CABAB", "KICHI", "KATTS", "KITTN", "ROCCY"]},
+    "Q166":{ "name":"Q166", "fixes":["VIKSN", "UHILL", "BIKKR"]},
+    "Q168":{ "name":"Q168", "fixes":["FNNDA", "SHIVA", "KRINA", "JASSE"]},
+    "Q19":{ "name":"Q19", "fixes":["BNA", "LAJUG", "TINGS", "DENNI", "PLESS", "STL", "TWAIN", "COLIE", "SKBOZ", "CHASY", "JAVAS", "DSM", "EYHUX", "FSD", "ABR"]},
+    "Q2":{ "name":"Q2", "fixes":["BOILE", "HEDVI", "HOBOL", "ITUCO", "EWM"]},
+    "Q20":{ "name":"Q20", "fixes":["CNX", "HONDS", "UNNOS", "FUSCO", "JCT"]},
+    "Q21":{ "name":"Q21", "fixes":["JONEZ", "RZC"]},
+    "Q22":{ "name":"Q22", "fixes":["GUSTI", "OYSTY", "ACMES", "CATLN", "TWOUP", "SPA", "NYBLK", "MASHI", "KIDDO", "OMENS", "BEARI"]},
+    "Q23":{ "name":"Q23", "fixes":["FSM", "RZC"]},
+    "Q24":{ "name":"Q24", "fixes":["LCH", "LSU", "IRUBE", "PAYTN"]},
+    "Q25":{ "name":"Q25", "fixes":["MEEOW", "ARG", "WLSUN", "PXV"]},
+    "Q26":{ "name":"Q26", "fixes":["ARG", "HENSY", "DEVAC"]},
+    "Q27":{ "name":"Q27", "fixes":["FSM", "ZALDA"]},
+    "Q28":{ "name":"Q28", "fixes":["GRAZN", "PYRMD", "HAKAT", "ESTEE", "PXV"]},
+    "Q29":{ "name":"Q29", "fixes":["HARES", "BAKRE", "MEM", "OMDUE", "SIDAE", "CREEP", "KLYNE", "DUTSH", "WWSHR", "DORET", "JHW", "HANKK", "GONZZ", "KRAZZ", "NIPPY", "CABCI", "EBONY", "DUNOM"]},
+    "Q3":{ "name":"Q3", "fixes":["FEPOT", "FAMUK", "FRFLY", "FINER", "FOWND", "PYE"]},
+    "Q30":{ "name":"Q30", "fixes":["SQS", "VUZ"]},
+    "Q31":{ "name":"Q31", "fixes":["DHART", "JODOX", "UJM", "TIIDE", "PXV"]},
+    "Q32":{ "name":"Q32", "fixes":["ELD", "BAKRE", "GAGLE", "CRAMM", "BNA", "SWAPP"]},
+    "Q33":{ "name":"Q33", "fixes":["DHART", "EDWAH", "LIT", "PROWL"]},
+    "Q34":{ "name":"Q34", "fixes":["TXK", "WASKO", "MATIE", "EDWAH", "MEM", "HENSY", "WAKOL", "SWAPP"]},
+    "Q35":{ "name":"Q35", "fixes":["DRK", "NAVHO", "CORKR", "WINEN", "NEERO", "KOATA", "IMB"]},
+    "Q36":{ "name":"Q36", "fixes":["RZC", "TWITS", "OMDUE", "DEPEC", "BNA", "SWAPP"]},
+    "Q37":{ "name":"Q37", "fixes":["FST", "CAVRN", "YORUB", "IMMAS", "PUB"]},
+    "Q38":{ "name":"Q38", "fixes":["ROKIT", "INCIN", "LAREY", "BESOM"]},
+    "Q39":{ "name":"Q39", "fixes":["CLAWD", "WISTA"]},
+    "Q4":{ "name":"Q4", "fixes":["BOILE", "HEDVI", "SCOLE", "SPTFR", "ZEBOL", "SKTTR", "ELP"]},
+    "Q40":{ "name":"Q40", "fixes":["AEX", "DOOMS", "WINAP", "MISLE", "BFOLO", "NIOLA", "JAARE", "OJESS", "ALEAN", "YICUT", "FEEDS", "MAULS", "FANPO"]},
+    "Q406":{ "name":"Q406", "fixes":["BWZ", "DBABE", "BASYE", "TRIBS", "BIGGO", "BAF"]},
+    "Q42":{ "name":"Q42", "fixes":["IRK", "STRUK", "DNV", "MIE", "HIDON", "BUBAA", "PSYKO", "BRNAN", "HOTEE", "MIKYG", "SPOTZ", "ZIMMZ"]},
+    "Q436":{ "name":"Q436", "fixes":["EMMMA", "DIXSN", "BOOTT", "RRONS", "YARRK", "CHAAP", "RAAKK", "HERBA", "REXXY", "REBBL", "MTCAF", "DGRAF", "YYOST", "LAAYK", "COATE"]},
+    "Q438":{ "name":"Q438", "fixes":["RUBYY", "BERYS", "TWIGS", "JAAJA", "ICHOL", "FARGN", "RAAKK"]},
+    "Q440":{ "name":"Q440", "fixes":["HUFFR", "IDIOM", "DEANI", "SLLAP", "BERYS", "TWIGS", "JAAJA", "ICHOL", "FARGN", "RAAKK"]},
+    "Q448":{ "name":"Q448", "fixes":["PTW", "LANNA", "DBABE", "BASYE", "TRIBS", "BIGGO", "BAF"]},
+    "Q480":{ "name":"Q480", "fixes":["ZANDR", "AIR", "LEJOY", "VINSE", "BEETS", "HOTEE", "MIKYG", "SPOTZ", "CANDR", "JEFFF", "IGN", "LESWL", "BAF", "ENE"]},
+    "Q5":{ "name":"Q5", "fixes":["HAROB", "MINNE", "HISKU", "HARPR", "HOMEG", "HUPTU", "STIKM"]},
+    "Q50":{ "name":"Q50", "fixes":["IIU", "HELUB", "ENGRA", "IBATE", "CUBIM"]},
+    "Q52":{ "name":"Q52", "fixes":["CHOPZ", "IPTAY", "AWYAT", "COLZI"]},
+    "Q54":{ "name":"Q54", "fixes":["GRD", "NYLLA", "CHYPS", "AHOEY", "RAANE", "NUTZE"]},
+    "Q56":{ "name":"Q56", "fixes":["CATLN", "KBLER", "KELLN", "KTOWN", "BYSCO", "JOOLI", "NUUMN", "ORACL", "KIWII"]},
+    "Q58":{ "name":"Q58", "fixes":["KELLN", "GLOVR", "LUMAY", "STUKI", "PEETT"]},
+    "Q60":{ "name":"Q60", "fixes":["SPA", "BYJAC", "EVING", "LOOEY", "JAXSN"]},
+    "Q62":{ "name":"Q62", "fixes":["WATSN", "DAIFE", "NOLNN", "WEEVR", "PSKUR", "FAALS", "ALEEE", "QUARM", "BURNI", "MCMAN", "VALLO", "RAV", "SUZIE", "SARAA"]},
+    "Q63":{ "name":"Q63", "fixes":["DOOGE", "HAPKI", "TONIO", "OCASE", "HEVAN"]},
+    "Q64":{ "name":"Q64", "fixes":["CATLN", "FIGEY", "GRD", "DARRL", "IDDAA", "TYI"]},
+    "Q65":{ "name":"Q65", "fixes":["JEFOI", "CESKI", "DAREE", "LORNN", "SOGEE", "ENGRA", "OCASE", "ROD"]},
+    "Q66":{ "name":"Q66", "fixes":["LIT", "CIVKI", "RICKX", "TROVE", "BAZOO", "METWO", "MXEEN", "ALEAN"]},
+    "Q67":{ "name":"Q67", "fixes":["SMTTH", "CEMEX", "IBATE", "TONIO", "JONEN", "COLTZ"]},
+    "Q68":{ "name":"Q68", "fixes":["HVQ", "TOMCA", "RONZZ", "HHOLZ", "HAMME", "CAPOE", "OTTTO"]},
+    "Q69":{ "name":"Q69", "fixes":["BLAAN", "RYCKI", "LUNDD", "ILLSA", "EWESS", "RICCS"]},
+    "Q7":{ "name":"Q7", "fixes":["JINMO", "JOGEN", "JUNEJ", "JAGWA", "AVE"]},
+    "Q70":{ "name":"Q70", "fixes":["HAILO", "LAS", "IFEYE", "BLIPP", "EEVUN", "BLOBB", "BAWER", "SAKES"]},
+    "Q71":{ "name":"Q71", "fixes":["BOBBD", "ATUME", "HAPKI", "KONGO", "WISTA", "GEFFS", "EMNEM", "PSYKO", "PSB"]},
+    "Q72":{ "name":"Q72", "fixes":["HACKS", "GEQUE", "BENSH", "RAMAY"]},
+    "Q73":{ "name":"Q73", "fixes":["MOMAR", "CABIC", "CHADT", "LVELL", "HAKMN", "ZZYZX", "LAKRR", "GUNTR", "ZAINY", "EEVUN", "WINEN", "CRITO", "BROPH", "DERSO", "SAWTT", "ZATIP", "CORDU"]},
+    "Q74":{ "name":"Q74", "fixes":["NATEE", "BLD", "ZAINY", "FIZZL", "GARDD", "DEANN"]},
+    "Q78":{ "name":"Q78", "fixes":["MARUE", "DUGGN", "TOADD"]},
+    "Q80":{ "name":"Q80", "fixes":["FAREV", "JEDER", "ENGRA", "DEWAK", "CEGMA", "JONEN", "BULVE", "WISTA", "LEVII", "RONZZ", "HHOLZ", "HAMME", "CAPOE", "OTTTO"]},
+    "Q806":{ "name":"Q806", "fixes":["MEKSO", "MLT", "CANME", "VIGDU", "OMADU", "VOGET"]},
+    "Q812":{ "name":"Q812", "fixes":["TIMMR", "WELOK", "CEWDA", "ZOHAN", "NOSIK", "AGDOX", "KELTI", "AHPAH", "GOATR", "SYR", "FABEN", "LOXXE", "ARKKK", "STOMP", "MSLIN", "GAYEL"]},
+    "Q816":{ "name":"Q816", "fixes":["HOCKE", "OMRAK", "AGDOX", "KELTI", "AHPAH", "GOATR", "ARNII", "HANAA"]},
+    "Q818":{ "name":"Q818", "fixes":["FNT", "TANKO", "KITOK", "DERLO", "IKNAV", "WOZEE", "KELIE", "VIEEW", "CFB", "BUFFY", "STOMP", "MSLIN", "GAYEL"]},
+    "Q82":{ "name":"Q82", "fixes":["WWSHR", "DORET", "JHW", "WAYLA", "VIEEW", "TYROD", "MEMMS", "LOXXE", "PONCT"]},
+    "Q822":{ "name":"Q822", "fixes":["FNT", "TANKO", "KITOK", "DERLO", "GOPUN", "HOZIR", "GONZZ", "PUPPY", "PAYGE", "CAM", "ENE", "AJJAY", "ALLEX"]},
+    "Q824":{ "name":"Q824", "fixes":["FNT", "HOCKE", "TAGUM"]},
+    "Q84":{ "name":"Q84", "fixes":["JHW", "AUDIL", "PUPPY", "PAYGE", "CAM"]},
+    "Q842":{ "name":"Q842", "fixes":["BEALE", "BLIPP", "WINEN", "TABLL", "PICHO", "PATIO", "PROXI", "VAANE", "KEETA", "TOVUM"]},
+    "Q844":{ "name":"Q844", "fixes":["SYR", "VIBRU"]},
+    "Q848":{ "name":"Q848", "fixes":["SLLAP", "HHIPP", "KARIT", "MENKO"]},
+    "Q86":{ "name":"Q86", "fixes":["TTRUE", "YORRK", "SCHLS", "CUTRO", "VALEQ", "PLNDL"]},
+    "Q88":{ "name":"Q88", "fixes":["HAKMN", "ZZYZX", "LAKRR", "NOOTN", "GARDD", "VERKN", "PROMT", "CHESZ"]},
+    "Q9":{ "name":"Q9", "fixes":["SUMMA", "SMIGE", "SUNBE", "REBRG", "DERBB"]},
+    "Q90":{ "name":"Q90", "fixes":["DNERO", "ESGEE", "AREAF", "JASSE"]},
+    "Q905":{ "name":"Q905", "fixes":["HOCKE", "DASIR", "SIKBO"]},
+    "Q907":{ "name":"Q907", "fixes":["POSTS", "PADDE", "SVM", "GADAV", "DERLO", "ATENE", "IMAMA", "MIILS"]},
+    "Q913":{ "name":"Q913", "fixes":["RAKAM", "CABCI", "TOPPS"]},
+    "Q917":{ "name":"Q917", "fixes":["SSM", "ULUTO", "VIGLO", "DUTEL", "PEPLA", "PIKSA", "HOZIR", "WOZEE"]},
+    "Q923":{ "name":"Q923", "fixes":["HOCKE", "KARIT", "DUTEL"]},
+    "Q935":{ "name":"Q935", "fixes":["MONEE", "HOCKE", "OMRAK", "DERLO", "IKNAV", "WOZEE", "HANKK", "JOSSY", "AUDIL", "FABEN", "PONCT", "GDM", "BOS"]},
+    "Q937":{ "name":"Q937", "fixes":["TULEG", "WAYGO", "KRAZZ"]},
+    "Q94":{ "name":"Q94", "fixes":["WELUM", "MNGGO", "ROOLL"]},
+    "Q947":{ "name":"Q947", "fixes":["REVEN", "TOPPS", "CUZWA", "XIBUL", "DUVOK"]},
+    "Q951":{ "name":"Q951", "fixes":["POSTS", "PADDE", "SVM", "GADAV", "DERLO", "ALONI", "KATEK", "DAVDA", "SAVAL", "TALNO", "RABIK", "ANTOV", "KERVO", "DANOL"]},
+    "Q96":{ "name":"Q96", "fixes":["PURSE", "DODDL", "BFUNE", "GUNTR", "PIIXR", "FIZZL", "BAWER", "ROCCY", "SARAF", "KIMMR"]},
+    "Q98":{ "name":"Q98", "fixes":["HAKMN", "ZZYZX", "LAKRR", "DUZIT", "EEEZY", "PEEWE"]},
+    "T201":{ "name":"T201", "fixes":["MEVAE", "TRUEX", "FEGNO", "NUROE", "BORTZ"]},
+    "T202":{ "name":"T202", "fixes":["GURSH", "AWRYT", "RICHE", "HUSTN", "FEGNO", "GANTS", "ZADEL"]},
+    "T203":{ "name":"T203", "fixes":["ANDYS", "AWRYT", "ROUTH", "FADOS", "OREAD"]},
+    "T204":{ "name":"T204", "fixes":["TAY", "SSI"]},
+    "T205":{ "name":"T205", "fixes":["OCF", "OTK"]},
+    "T206":{ "name":"T206", "fixes":["ENADE", "FADOS", "GOTHS", "NUROE", "ZADEL"]},
+    "T207":{ "name":"T207", "fixes":["OMN", "CARRA", "VQQ", "MONIA", "AYS"]},
+    "T208":{ "name":"T208", "fixes":["GNV", "CARRA", "OMN"]},
+    "T209":{ "name":"T209", "fixes":["EHEJO", "NASDE", "YASLU", "JAMTA", "IRQ"]},
+    "T210":{ "name":"T210", "fixes":["TAY", "OHLEE", "BRADO"]},
+    "T211":{ "name":"T211", "fixes":["OCF", "JUTTS", "CARRA", "PRKKS", "CRG"]},
+    "T212":{ "name":"T212", "fixes":["RASHE", "SEG", "KIACK", "BLESS", "DIANO", "LVZ", "LAAYK", "QTIPP", "WEARD", "WEETS", "TRESA", "STUBY", "VEERS", "RONGE", "NELIE", "DARTH", "PUT"]},
+    "T213":{ "name":"T213", "fixes":["IIU", "GAMKE", "MILAN", "ZESOD", "RID"]},
+    "T214":{ "name":"T214", "fixes":["OREAD", "BORTZ", "THMSN", "ZADEL", "ORPEE"]},
+    "T215":{ "name":"T215", "fixes":["HYK", "GAMKE"]},
+    "T216":{ "name":"T216", "fixes":["PSB", "SWISS", "ZAGTI", "FQM", "ORDMO", "ELEXY", "LOPEZ", "LECOR", "LAAYK", "HAWLY", "RAGER", "RUBER", "HELON", "SPECL", "IGN", "DEEDE", "MOONI", "JUDDS", "HFD", "THUMB", "ARENE", "SALEM", "GON", "TRAIT", "SEY", "NEWBE", "BENNT", "ACK"]},
+    "T217":{ "name":"T217", "fixes":["HYK", "BOSTR", "HEDEN", "PRUDE", "SGH", "BONEE"]},
+    "T218":{ "name":"T218", "fixes":["SFK", "GUYED", "LACIE", "SCOFF", "LAAYK", "TALLI", "COATE", "SAX"]},
+    "T221":{ "name":"T221", "fixes":["MAZIE", "TROXL", "FJC", "BEERS", "ROCOY", "RITTY", "LAAYK", "TYYLR", "CFB"]},
+    "T243":{ "name":"T243", "fixes":["PUNGO", "HULIP", "ZOLMN"]},
+    "T245":{ "name":"T245", "fixes":["SLI", "POPPR", "SMO", "SILEX"]},
+    "T247":{ "name":"T247", "fixes":["SLI", "POPPR", "SMO", "CANOG"]},
+    "T249":{ "name":"T249", "fixes":["VNY", "SMO", "POPPR", "SLI"]},
+    "T251":{ "name":"T251", "fixes":["FAM", "FTZ", "RIVRS"]},
+    "T254":{ "name":"T254", "fixes":["CLL", "HIPPS", "EAKES", "CREPO", "LCH"]},
+    "T255":{ "name":"T255", "fixes":["MVY", "FALMA", "PVD", "NOXSE", "EGAKE", "BLATT", "NELIE"]},
+    "T257":{ "name":"T257", "fixes":["VTU", "RZS", "MQO", "CALIS", "BLANC", "HNNTR", "DUBSS", "CAATE", "CHAWZ", "PORTE", "THHEO", "JAMIN", "PYE", "FREES", "NACKI", "ENI", "MERRI", "FLUEN", "PLYAT", "CCHUK", "CICRO", "SEGVE", "SCUPY", "OLJEK", "CIGCA", "FURNS", "MITUE", "JANAS", "ONP", "CUTEL", "EYCEH", "ILWAC", "ZEDAT", "WAVLU", "HQM", "COPLS", "WAPTO", "OZETT", "TOU"]},
+    "T259":{ "name":"T259", "fixes":["LHS", "EHF", "AVE", "MBARI", "LKHRN", "SNS", "CAATE", "SANTY", "SAPID", "CRTER", "NORCL", "MOVDD", "OOWEN", "OXJEF", "SAAGO", "BNAKI", "WEXIM", "NIKOL", "DAYMN", "ELY"]},
+    "T261":{ "name":"T261", "fixes":["SXC", "GVO", "MQO", "CLMNS", "HRRNG", "HMPBK", "WOZZZ", "DUBSS", "SNS", "KARNN", "WINDY", "SMONE", "MOVDD", "RBLEW", "GIFME", "HNNRY", "GRIDD", "TALUM", "JINGO", "GONGS", "HOMAN", "GARSA", "CCAPS", "MUREX", "MIXUP", "PIIKZ", "TUPSE", "DSD", "HERBS", "CUPRI", "SUPOC", "KUKTE", "VECCU", "SUNSN", "MUDLE", "YKM", "SELAH", "GEBTE", "LARDY", "QUINT", "KLSEY", "PAWYO", "HVARD", "SOFFE", "JSTEN"]},
+    "T263":{ "name":"T263", "fixes":["FIM", "DERBB", "AVE", "PXN", "WINDY", "SMONE", "MOVDD", "RBLEW", "PITTS", "SGD", "POPES", "NAKPT", "DIBLE", "KENDL", "FOLDS", "HOMEG", "ZUNAS", "TALEM", "OREGN", "EROWY", "NOTTI", "CVO", "ARTTY", "UBG", "LOATH", "WINLO", "ULESS", "MTLOK", "QUIIN", "ARRIE", "ELWHA"]},
+    "T265":{ "name":"T265", "fixes":["AHMED", "START", "BULLZ", "VEENA"]},
+    "T272":{ "name":"T272", "fixes":["HLV", "VLA"]},
+    "T274":{ "name":"T274", "fixes":["ONP", "CRAAF"]},
+    "T276":{ "name":"T276", "fixes":["COUGA", "CARBY"]},
+    "T281":{ "name":"T281", "fixes":["YOZLE", "BOKKI", "ANW", "LKOTA", "PIR"]},
+    "T283":{ "name":"T283", "fixes":["BFF", "GRN", "WNDED", "PIR"]},
+    "T285":{ "name":"T285", "fixes":["LBF", "TDD", "MARSS", "VTN", "LKOTA", "ISD", "HON"]},
+    "T286":{ "name":"T286", "fixes":["RAP", "KEOTA", "GRN", "EFFEX", "TDD", "BOKKI", "GRI"]},
+    "T287":{ "name":"T287", "fixes":["DENNN", "CAARY", "WILMY", "KAIJE", "BAMMY", "REEES", "TOMYD"]},
+    "T288":{ "name":"T288", "fixes":["GCC", "TRTTL", "KARAS", "PACTO", "RAP", "JSSCA", "WNDED", "VTN", "ANW", "FESNT", "OBH"]},
+    "T290":{ "name":"T290", "fixes":["SCAIL", "BBAIT", "BBASS", "BBOAT", "BOBBR", "JACET"]},
+    "T291":{ "name":"T291", "fixes":["LOUIE", "BAABS", "HAR", "MORTO", "SEG", "MIP", "MEGSS", "LAAYK", "DNY", "OAKIL", "ALB"]},
+    "T292":{ "name":"T292", "fixes":["RKMRT", "POLLL", "CCATT", "REELL", "TRREE", "JACET"]},
+    "T293":{ "name":"T293", "fixes":["CHUTT", "NFTRY", "ZINTU", "SHAKK", "RTLRY", "HONRR", "POLLL", "DAISI"]},
+    "T294":{ "name":"T294", "fixes":["HEFIN", "BAHRR", "ZINTU", "BBAIT", "JMPPR", "GRANT"]},
+    "T295":{ "name":"T295", "fixes":["LOUIE", "BAABS", "LRP", "DUMMR", "HAILS", "SNOWY", "KRAZE", "LYTEL", "LVZ", "LAAYK", "KERRI", "PRNCE", "SAGES", "TALCO", "WIGAN", "BOWAN", "MOBBS", "SASHA", "MOLDS", "WHATE", "WARIC", "EEN", "TAPSE", "CON", "SATAN", "ENE", "BRNNS", "RAZZR", "BGR"]},
+    "T296":{ "name":"T296", "fixes":["JMPPR", "BBASS", "TATRS", "TACKL"]},
+    "T297":{ "name":"T297", "fixes":["PAIRA", "NFTRY", "HEFIN", "RKMRT", "CHTTE", "DAISI", "AWSON", "REELL"]},
+    "T298":{ "name":"T298", "fixes":["OAK", "SALAD", "ALTAM", "RBLEW", "ORANG", "EVETT", "ELKHN", "SMURA", "NIKOL", "OAL", "KATTS", "KITTN", "ILC", "WOOOP", "MLF", "DETAN", "EBOVE", "PUC", "MTU", "OCS", "DORTN", "CZI"]},
+    "T299":{ "name":"T299", "fixes":["UCREK", "KAIJE", "BAMMY", "REEES", "SCAPE"]},
+    "T300":{ "name":"T300", "fixes":["ALB", "CANAN", "SHIGY", "STELA", "MOLDS", "TOMES", "COBOL", "NELIE", "WIPOR", "ORW", "LAFAY", "MINNK", "FALMA", "MVY"]},
+    "T302":{ "name":"T302", "fixes":["CUKIS", "JJACE", "JJETT", "JERMM", "CUPRI"]},
+    "T304":{ "name":"T304", "fixes":["GLARA", "PUTZZ", "JJETT", "WISSL", "HERBS"]},
+    "T306":{ "name":"T306", "fixes":["LAX", "PRADO", "PDZ", "SETER", "BANDS", "AHLEX", "PSP", "BLH", "BXK", "PERKY", "PXR", "TOTEC", "TUS", "NOCHI", "ANIMA", "DARCE", "CUS", "ELP"]},
+    "T310":{ "name":"T310", "fixes":["TUS", "SULLI", "MESCA", "HOOVE", "NOCHI", "SSO", "SVC", "KEAPS", "TCS"]},
+    "T319":{ "name":"T319", "fixes":["CCLAY", "DUNCS", "SHURT", "KLOWD", "BLEWW"]},
+    "T321":{ "name":"T321", "fixes":["BBOAT", "TACKL", "REELL", "BIGNN"]},
+    "T323":{ "name":"T323", "fixes":["CROCS", "BOBBR", "BIGNN", "ZPPLN", "HIGGI"]},
+    "T325":{ "name":"T325", "fixes":["BWG", "RENRO", "LOONE", "APALO", "BUNKA", "TTH"]},
+    "T326":{ "name":"T326", "fixes":["MZB", "HAILE", "BLLYJ", "STAXS", "GILYY", "KUMBA", "IPL"]},
+    "T329":{ "name":"T329", "fixes":["MQO", "PRB", "LKHRN", "PXN", "MKNNA", "OXJEF", "TIPRE", "OLIPH", "HNNRY", "ROWWN", "RAGGS", "POPES", "NACKI"]},
+    "T331":{ "name":"T331", "fixes":["NTELL", "MKNNA", "KARNN", "VINCO", "NORCL", "MOVDD", "EVETT", "TIPRE", "ESSOH", "SWR", "TRUCK", "FMG", "HIXUP", "LLC", "CUTVA", "BAM", "PARZZ", "DRYAD", "TULIE", "AMFAL", "PIH", "VIPUC", "IDA", "PULTE", "SABAT", "WAHNZ", "BUFVO", "SPECT", "BIL", "TRUED", "EXADE", "JEKOK", "FONIA"]},
+    "T333":{ "name":"T333", "fixes":["KLIDE", "BORED", "SMONE", "OOWEN", "EVETT", "TIPRE"]},
+    "T608":{ "name":"T608", "fixes":["WOZEE", "UKNIX", "BIMRO", "DERLO", "HAVOK", "BOSEP", "KATNO", "HOCKE"]},
+    "T616":{ "name":"T616", "fixes":["FNT", "URSSA", "HOCKE", "RAKAP", "LEPOS"]},
+    "T781":{ "name":"T781", "fixes":["FNT", "KATTY", "HANKY", "ADRIE", "MARGN", "BLUEZ", "AXOBU"]},
+    "TK50":{ "name":"TK50", "fixes":["EMI", "TAYLO", "WINGO", "SINON", "GRIBL", "TOLAN", "BALDE", "SPATE", "DECKR", "RUSEY", "CIDOB", "HAMOR", "ARCUM", "TULLY", "BORKE", "BANKA"]},
+    "V1":{ "name":"V1", "fixes":["CRG", "LLIPS", "OCNOP", "STARY", "TYBEE", "RUBYS", "BASSO", "HONAP", "ROOFS", "COTAK", "CHS", "CARNO", "WANDO", "CUBBY", "KIMMY", "INLET", "PLANN", "CRE", "ASHES", "RAPEN", "YOAST", "LAYZE", "WALLO", "ISO", "IRAKE", "ZAGGY", "CVI", "DRONE", "EDTAJ", "PSALM", "DEEMS", "VEGHE", "ORF", "CCV", "FATOM", "JAMIE", "MAGGO", "SBY", "ATR", "PEAPS", "LEEAH", "HOWIE", "CRESI", "CYN", "WHITE", "DIXIE", "MOVFA", "JFK", "DPK", "BELTT", "MAD", "YODEL", "WEGOT", "HFD", "DVANY", "GRAYM", "GRIPE", "BOSOX", "WHYBE", "BOS"]},
+    "V10":{ "name":"V10", "fixes":["PUB", "ORWAY", "TODDE", "WOSUR", "LAA", "ADEER", "LACKA", "GCK", "ONIPE", "KUDIC", "POKPE", "HEPVA", "DDC", "FIVLI", "EARPP", "CUKTO", "STAFF", "KILLE", "HUT", "BURTO", "WAIVE", "FLOSS", "ANUGE", "EMP", "EBJEL", "DODSN", "WETZL", "ANX", "ROBDY", "LEXIN", "MURTE", "IRK", "MURLY", "JURIX", "LOAMY", "BRL", "VICKS", "BDF", "OWENA", "KELSI", "AHMED", "SHOOZ", "PLANO", "NILES", "HARRT", "CHETT", "STYLE", "GIJ", "LINGS", "VENTU", "YURUD", "JONES", "GEEBE", "NUPGE", "LFD", "CRUXX", "JUSUL", "CRL", "MACCS", "SSUNN", "AZTRO", "GILLS", "FAILS", "WONOP", "WEIDS", "ZITER", "YNG", "VOLAN", "EARED", "TALLS", "LUCCA", "REC", "JUNEY", "WILSS", "LRP"]},
+    "V100":{ "name":"V100", "fixes":["MBW", "ZIKRU", "BFF", "HAPOP", "JUNUM", "AIA", "EVENN", "EFFEX", "MARSS", "ANW", "GIYED", "ONL", "CUGUX", "BEWIG", "ATLES", "SUX", "CUSHO", "NEMAH", "MONKS", "BABYA", "FOD", "SEKDE", "ALOCK", "ARTYS", "ALO", "DEWAR", "INDET", "DBQ", "LENAS", "RFD", "GRIFT", "SMULA", "KRENA", "FARMM", "UMUZI", "OBK", "DEERE", "BRAIK", "MINCE", "MUSKY", "YOLUR", "ELX", "RESGY", "LFD"]},
+    "V101":{ "name":"V101", "fixes":["GLL", "LIBEL", "RIDJE", "FROGS", "BROCC", "UYRAG", "ECHOA", "ZOMBU", "LORIN", "CHE", "HAGJI", "STRIM", "RENAE", "VEL", "NEOLA", "TCH", "KAYZE", "OGD", "KREBS", "BEARR", "BLIDA", "SHEAR", "NULTE", "MALTT", "BYI", "REAPS", "HLE", "SOLDE"]},
+    "V102":{ "name":"V102", "fixes":["SFL", "AXEPE", "JALEB", "CNM", "KEHFY", "HOMEX", "WUDRU", "DYETT", "HOB", "DEKEC", "IBOCO", "ELOYE", "TASNE", "RUKTE", "HEGTA", "MANIC", "JOXUL", "LBB", "RALLS", "GTH", "SNEED", "ELECT", "SPS"]},
+    "V103":{ "name":"V103", "fixes":["CTF", "ZOPOC", "GANTS", "KEWPI", "GSO", "MAYOS", "PLEXI", "HENBY", "TABER", "ROA", "COVEY", "CAXWO", "NATTS", "VELLI", "AHCIN", "EKN", "CKB", "STORE", "BURGS", "KIVGE", "AIR", "ATWOO", "MINER", "WNGFT", "ACO", "AZTRO", "SPHRE", "MAARS", "VEELA", "CAGAP", "DXO", "KUPNE", "PSI", "SPRTN", "QUBEE", "LAN"]},
+    "V104":{ "name":"V104", "fixes":["BTV", "POROE", "CEVIB", "MPV", "AYZOO", "BML", "ANSYN", "PUVIE", "BGR"]},
+    "V105":{ "name":"V105", "fixes":["TUS", "TORTS", "ALMON", "BASER", "TFD", "POPKE", "PXR", "JONHH", "GINKE", "KARLO", "DRK", "HOBES", "BEYMI", "SINHO", "TRUXE", "PRFUM", "ZIVSI", "WINDS", "BLD", "LAS", "HARLS", "LUCKY", "HIDEN", "BTY", "LIDAT", "TEZUM", "ZOTUX", "OAL", "YERIN", "RYANN", "CHIME", "FMG"]},
+    "V106":{ "name":"V106", "fixes":["JST", "WILTT", "HUDON", "RASHE", "SEG", "KIACK", "BLESS", "DIANO", "LVZ", "LAAYK", "BAF", "FAIDS", "PUDGY", "LAPEL", "GDM", "JOHNZ", "MHT", "KHRIS", "RAYMY", "YUKES", "ENE"]},
+    "V107":{ "name":"V107", "fixes":["LAX", "STABO", "SMO", "BAYST", "SADDE", "GUYBE", "GINNA", "FIM", "PIRUE", "REYES", "DERBB", "AVE", "CITIE", "PXN", "CATHE", "VINCO", "MABRY", "MISON", "IMPLY", "DECOT", "OAK", "COMMO", "MICRA", "PYE", "BOARS"]},
+    "V108":{ "name":"V108", "fixes":["STS", "HABAP", "SGD", "CROIT", "CCR", "PITTS", "OAKEY", "LODDI", "LIN", "EKR", "TRUEL", "LILXO", "AJAXX", "DBL", "JNETT", "BASEE", "MURFE", "STAMY", "BRK", "ADANE", "CHEBA", "HGO", "YAKIY", "KURIQ", "GLD", "DEPAY", "CUGGA", "HLC"]},
+    "V11":{ "name":"V11", "fixes":["BFM", "GIKEY", "BURIN", "GCV", "NEELI", "PICAN", "CATTI", "SOSOE", "MIZZE", "OBUJI", "RAKIN", "MHZ", "BOOSI", "YONUD", "SQS", "NEDUE", "UBABY", "RIGCY", "HLI", "ZAMXU", "MIOLA", "OSORY", "DYR", "SACDO", "AHOYE", "CNG", "ROOKE", "WESON", "PXV", "MACKY", "CLOWN", "RACYR", "SCOTO", "KELLY", "VHP", "WELDO", "DEEKS", "MZZ", "LATES", "CHMLY", "CRETE", "FWA", "ZOLNR", "GRABI", "EDGEE", "PIONS", "HIRED", "CRUXX"]},
+    "V110":{ "name":"V110", "fixes":["DMN", "NUWIN", "WUMEX", "LAYEN", "TCS"]},
+    "V111":{ "name":"V111", "fixes":["BSR", "SNS", "JEJMA", "HENCE", "CATHE", "KARNN", "WINDY", "PATYY", "MOD"]},
+    "V112":{ "name":"V112", "fixes":["HQM", "ZEDAT", "ILWAC", "AST", "KEIKO", "PITER", "BTG", "PIQRI", "GYMME", "CARBY", "LTJ", "VECCU", "OGPAY", "LOAMS", "ECHOD", "FODOP", "PDT", "TACUP", "LYLES", "RODNA", "GEG", "CEMOM", "JOMRU", "DIANN", "EDGES", "BZXIV", "YXC"]},
+    "V113":{ "name":"V113", "fixes":["MQO", "JEDGI", "PRB", "ROM", "PXN", "PATYY", "MOD", "LIN", "KATSO", "SPOOK", "RICHY", "HUYJO", "FMG", "NICER", "ROBUD", "GOWZE", "SDO", "REO", "RENOL", "BOI", "PLUTO", "LKT", "FANID", "JUNKA", "SLIPP", "CPN", "EVVER", "HUDVU", "LOCIS", "UGACE", "HLN", "HONVI", "ANNEM", "LINGE", "AXABE", "LWT"]},
+    "V114":{ "name":"V114", "fixes":["PNH", "CAUDE", "DOGIN", "CDS", "PEWAE", "VASTY", "SPS", "FLOPP", "FERET", "BYP", "UIM", "OTTUV", "AWLAR", "GGG", "SPOUT", "EKPOW", "CARTH", "EXITE", "COVEX", "MARTA", "NUBOY", "BOYCE", "AEX", "CATCS", "MIKLE", "MOGAN", "KNAPP", "ALIYA", "LSU", "VEILS", "RQR", "SNAKI", "SLIDD", "CLERY", "MUDDA", "GPT", "MINDO", "WIGGO", "AKXUT", "LBY"]},
+    "V115":{ "name":"V115", "fixes":["CEW", "ITUYU", "ROMEK", "PIGON", "CHAFF", "REDDI", "MGM", "BEING", "KORNR", "WALTY", "TASYU", "HEENA", "JAPAM", "VUZ", "COLIG", "WILED", "SNEAR", "ARBEE", "BOAZE", "GESTS", "FOCEY", "CUGNI", "ADMIT", "GQO", "DUBBS", "ETOWA", "GROSS", "VXV", "MALIN", "MIAMI", "ROSAR", "AZQ", "CELLI", "WHIRL", "HVQ", "GAYED", "MORAN", "JPU", "CADRE", "LORES", "CTW", "ATWOO", "ZUTIV", "CAPEL", "MERCY", "FKL", "TDT", "JHW", "LANGS", "BUF"]},
+    "V116":{ "name":"V116", "fixes":["WILLA", "NEPTS", "MAPER", "ZIMEG", "ZIVDO", "ELX", "AZO", "LEROY", "ZEGBI", "ECKDO", "JXN", "HARWL", "DEXER", "SVM", "YQG", "OCTAS", "ERRTH", "CODDS", "TRACE", "ERI", "BFD", "DECOY", "SFK", "GUYED", "LACIE", "LOPEZ", "LVZ", "EXAGE", "TALLI", "COATE", "SAX"]},
+    "V117":{ "name":"V117", "fixes":["JPU", "PYRAT", "WEELD", "BEALL", "AIR", "WISKE"]},
+    "V118":{ "name":"V118", "fixes":["MBW", "YEKUS", "PUCIP", "LAR", "JESAR", "SENSE", "RENRE", "CYS"]},
+    "V119":{ "name":"V119", "fixes":["ECB", "MILLK", "CROUP", "HNN", "UJOYU", "JACEE", "JPU", "ANTIO", "BURGS", "GALLS", "JOHNB", "OTOWN", "IHD", "QUARY", "MILWO", "HOMEE", "UDUSE", "TALLS", "CIP", "COOBE", "DETPE", "SCENT", "BFD", "ELZ", "BURST", "GEE", "ROC"]},
+    "V12":{ "name":"V12", "fixes":["GVO", "RZS", "EMUXY", "PMD", "ETHER", "NASTE", "HELDE", "NULMN", "BASAL", "HEC", "ZELMA", "CLIPP", "EED", "MEMPE", "JAWSY", "MUMTE", "CHILY", "DRK", "JUWSO", "OATES", "HOXOL", "INW", "ZUN", "CARTY", "HEGMA", "ABQ", "OTO", "ACH", "WASBI", "TCC", "JADIL", "VEGGE", "PNH", "UKDEW", "BROKE", "HINOD", "MMB", "TUZXY", "CARON", "ANY", "WYYNR", "MIROR", "ICT", "KUDPY", "INDIC", "GAMWY", "LASKI", "AGEXY", "EMP", "EBJEL", "DODSN", "WETZL", "ANX", "OCTAM", "FRANC", "HUCKS", "COU", "STITH", "FTZ", "AUGST", "SNYDR", "TOY", "JACOB", "TWILA", "JIGSY", "CORKI", "BIB", "JOVAR", "WORKE", "LUPCE", "KELLY", "ZARHO", "OZMOE", "SHB", "CUPJU", "VOCCA", "RID", "DQN", "TRUNC", "BONEE", "TARRY", "MECAN", "PIZZA", "DIPNE", "APE", "ROSCO", "CTW", "PIDYY", "HEFJA", "AGC", "FURIX", "MILWO", "JST", "ZOTBI", "COFAX", "JUNEY", "POLLS", "LOMON", "HAR", "KUPPS", "BOYER", "WEPNA", "PTW"]},
+    "V120":{ "name":"V120", "fixes":["SEA", "TAGOR", "NORMY", "FITGA", "WINIM", "CUNUR", "CASHS", "EAT", "OZALI", "EPH", "WIPES", "OWOSE", "EPAFY", "GEG", "EPENE", "JURSY", "KARPS", "MLP", "EDOBE", "HANIM", "CHARL", "SHIMY", "GTF", "JAYKE", "YOGOS", "ZEKEL", "UFXIT", "LWT", "CIWXU", "ESTRO", "MLS", "DIXLE", "DPR", "TUZCO", "NENOE", "PIR", "ELREE", "KAATS", "MHE", "YUGUL", "FRYRE", "FSD", "BILOO", "HAYNS", "GRUVE", "ONTIJ", "BANCO", "HAYOR", "JUGTO", "MCW", "AREDA", "SEATS", "ALO"]},
+    "V121":{ "name":"V121", "fixes":["FJS", "BAYTS", "GYPSE", "OED", "UZEHE", "BROKN", "MOURN", "RBG", "SOZKY", "OTH", "SCOTY", "VAUGN", "EUG", "DOSEE", "MOHWK", "VIDAS", "WHIFF", "SNOKY", "DSD", "JABOT", "IMB", "JONWE", "BKE", "GOYEK", "DNJ", "LKT", "OSURE", "NOSEY", "DLN"]},
+    "V122":{ "name":"V122", "fixes":["CEC", "REFIX", "OBRIN", "CONLI", "WISEP", "PAPLE", "OLECY", "GNATS", "OED", "BRUTE", "LANKS", "JEXAM", "CEGAN", "ACLOB", "LEIFF", "OLEBY", "LMT", "BIDDS", "LKV", "REO"]},
+    "V123":{ "name":"V123", "fixes":["MITCH", "GEEMO", "SWANN", "TACKS", "UKIEY", "CANUV", "OOD", "RUUTH", "DAVYS", "ENZEW", "HOLEY", "BRAND", "KORRY", "RBV", "TYKES", "MINKS", "RENUE", "APPLE", "TICKL", "PROUD", "DIALS", "LGA", "FAMMA", "CRALY", "HAARP", "RYMES", "CMK", "NOBBI", "CASSH", "TRESA", "WIGAN", "ATHOS", "GROUP", "ALB", "TIMKE", "CAM", "GFL"]},
+    "V124":{ "name":"V124", "fixes":["BYP", "OKUCI", "MONTE", "RAKOC", "PRX", "YOTUB", "DEENS", "NEPRE", "HOT", "LONNS", "TAYUV", "BEGAN", "JENAN", "LIT", "TAFTE", "SIBOE", "HILLE", "GQE", "ZIVNY", "FAXIP", "DWSON", "OZSOM", "JKS", "GHM"]},
+    "V125":{ "name":"V125", "fixes":["CGI", "DUEAS", "NIKEL", "BURCK", "SPUDZ", "STL"]},
+    "V126":{ "name":"V126", "fixes":["BEARZ", "HALIE", "INKEN", "NOMES", "GSH", "BAGEL", "ILTON", "EDGEE", "VWV", "DJB", "ZITER", "JFN", "ERI", "BFD", "DECOY", "SFK"]},
+    "V127":{ "name":"V127", "fixes":["BDF", "WYNET", "LEECS", "PLL", "RFD"]},
+    "V128":{ "name":"V128", "fixes":["JVL", "RFD", "SHOOF", "URRBS", "KELSI", "SMARS", "IKK", "KENLA", "YIXCI", "BOSSY", "BOSWL", "VAGES", "ATTIL", "POTES", "JAKKS", "JELLS", "ADVAY", "VHP", "OZMOE", "NOBYI", "WAGSE", "DECEE", "HIGMA", "AMARG", "LOVEY", "LOPYU", "JADRO", "CVG", "CALIF", "BOSTR", "GIPLE", "RHOMM", "YRK", "ILILE", "CROUP", "RULEY", "HVQ", "SWIFT", "BITES", "HAWKI", "VELLI", "BOIER", "DEKAY", "TTUMS", "LURAY", "CSN"]},
+    "V129":{ "name":"V129", "fixes":["SPI", "GROWL", "LOTTO", "EVERY", "PIA", "JPAUL", "GENSO", "NOWSO", "CVA", "LOTTE", "DBQ", "SWAGG", "FARON", "QUEST", "DOURS", "PKRNA", "ODI", "CALMS", "WUMBO", "EAU", "UCACI", "ENTAF", "QESCA", "LAMPY", "DLH", "HIB", "TOEGO", "INKER", "ZUNNI", "RAXUE", "SWAMP", "INL", "KDNKD", "BOFIN", "VBI"]},
+    "V13":{ "name":"V13", "fixes":["MFE", "RAYMO", "MANNY", "OPULL", "ASCOT", "SOLON", "POGOE", "CRP", "WORRY", "AUSTS", "BLOKS", "IVOLY", "TANNA", "PSX", "PUKME", "COSDI", "ROSEN", "IAH", "CLEEP", "LEGGE", "WELRO", "LFK", "JIPRI", "CARTH", "SAMMS", "ZEVEB", "BEKEN", "YECLU", "EIC", "IDDAS", "YIBUN", "DUBOW", "TXK", "DEENS", "PGO", "HADES", "FSM", "IXNEL", "CHESO", "BARKK", "BOYLE", "RZC", "PINNE", "HEXER", "EOS", "DROOP", "WADET", "NASHE", "YUGTU", "DIZZI", "ZOSKI", "BUM", "INRAM", "ANX", "LYMES", "EXCEL", "LASSO", "JAWED", "LMN", "WIVEY", "DSM", "ANKEN", "NEVAD", "SHODR", "ALOCK", "MCW", "GOTHE", "NEWRY", "KASPR", "ZIBBY", "DELZY", "PEPPR", "AHMIT", "FGT", "WAGNR", "WHISK", "BLAYN", "CINCI", "RZN", "KINGZ", "BARUM", "DAYAR", "DLH", "VURLY", "WEMAN", "SUZLI", "UDORY", "HUDRU", "BYPOR", "MECNU", "YQT"]},
+    "V130":{ "name":"V130", "fixes":["ORW", "LAFAY", "MINNK", "FALMA", "MVY"]},
+    "V131":{ "name":"V131", "fixes":["OKM", "ZORLA", "HASKL", "TUL", "MURNA", "DELAT", "JIBUT", "TYROE", "WENIX", "HOTAP", "CNU", "KACED", "HOCJO", "TOP"]},
+    "V132":{ "name":"V132", "fixes":["MBW", "MOIST", "CYS", "HAMER", "SHOOP", "RAYME", "TUMBL", "AKO", "GERON", "GLD", "ORION", "RANSO", "DISKS", "HARAN", "SPELT", "HUT", "BURTO", "WAIVE", "FLOSS", "LASKI", "UBWIK", "CNU", "KUVPE", "NALLY", "NASHE", "ZEDDI", "OZARK", "JACCK", "SGF", "ROBCO", "LANEZ", "STEME", "TBN", "BACTA", "LENOX"]},
+    "V133":{ "name":"V133", "fixes":["LINCO", "ALDOH", "BZM", "ZUGAT", "MULBE", "HUBVA", "STOVE", "DORFF", "TELOC", "KENYA", "PINEE", "FEDEX", "HVQ", "LIVES", "CUSTO", "UJOYU", "FARLN", "STURR", "GAZED", "ZZV", "ROSCO", "TVT", "MFD", "SVM", "JEKAV", "POLAR", "CLIOO", "FLIPE", "MBS", "WHIPP", "LADIN", "BORIN", "TVC", "CUBKO", "ESC", "ZALKI", "VNZNT", "SAW", "PEVXI", "CMX", "VAYUC", "FEMOK", "KJDRS", "YQT", "KJDPL", "TAGUC", "INL", "JGKPL", "YRL"]},
+    "V134":{ "name":"V134", "fixes":["FFU", "MAYGY", "YMONT", "ARBIH", "PUC", "COPUK", "JISIG", "JNC", "PACES", "EDUKY", "HUGSI", "RIYNO", "SLOLM", "GLENO", "LINDZ", "DBL", "HERLS", "LAWSN", "DAVVY", "FUNDS", "BREWS", "BINBE", "FQF"]},
+    "V135":{ "name":"V135", "fixes":["SAYUL", "BZA", "COPAW", "CAZZI", "YOCEP", "BLH", "ROGBE", "PKE", "EED", "GORSY", "GFS", "WHIGG", "CLARR", "HIDEN", "BTY", "LIDAT", "TEZUM", "TPH"]},
+    "V136":{ "name":"V136", "fixes":["HCH", "SWELL", "VXV", "AUBRY", "PITTE", "SOT", "BARRD", "AFTEN", "HMV", "DAMAS", "STOVE", "SPEEL", "MAXME", "PSK", "TABER", "PIGGS", "DUNCE", "JAVVA", "SBV", "ALDAN", "BILLA", "DUHAM", "RDU", "GURBE", "LANHO", "DENIL", "HOKMU", "FAY", "EYOBI", "NERTE", "COTUB", "WILDS", "MOKKA", "HICKE", "CRE"]},
+    "V137":{ "name":"V137", "fixes":["NOVOS", "IPL", "BRAWL", "ZUNGU", "HENOM", "TRM", "PSP", "WHETO", "MORON", "ARRAN", "HITOP", "HESPE", "PURPS", "PMD", "MOLTT", "VICKY", "JEFFY", "GMN", "TAFTO", "AVE", "NEFDE", "OKEEF", "ROM", "ZURET", "CANRI", "SNS"]},
+    "V138":{ "name":"V138", "fixes":["RIW", "HUNTZ", "MBW", "CIKNA", "MILKY", "CYS", "MOCTU", "EGBER", "PIETY", "SNY", "GRI", "BRADY", "YATDO", "GAMBL", "OCEYI", "LNK", "LEBYI", "MEPWE", "CALDU", "OVR", "GLENE", "MADUP", "VAYUB", "FOD", "KADCO", "TICUV", "ZUTIG", "KEFIG", "MCW", "WOTVI", "FOYDE", "UKN"]},
+    "V139":{ "name":"V139", "fixes":["FLO", "JONAP", "CARLI", "LAVIE", "MOKKA", "RAPEN", "DELKO", "ILM", "KOBBY", "WIDGE", "EWN", "PEARS", "SUNNS", "ORF", "CCV", "EWOOD", "ARICE", "DUNFE", "SWL", "CBEAV", "RADDS", "SEWEL", "SIE", "AVALO", "BRIGS", "HARBO", "DRIFT", "MANTA", "PLUME", "SHERL", "DUNEE", "KOPPY", "SARDI", "RICED", "BEDYA", "SHLEP", "BEADS", "HTO", "PARCH", "GARRD", "TRAIT", "WACKY", "ASHWY", "LAFAY", "JIKUK", "YBERA", "PVD", "INNDY", "BURDY", "KYLES", "TONNI", "WIMPY", "EXALT", "LBSTA", "SILVE", "SEEDY", "ENE"]},
+    "V14":{ "name":"V14", "fixes":["CME", "ONSOM", "CAPRO", "WINNS", "FLATT", "SHALO", "LBB", "SHOES", "FLOYD", "EXONE", "CDS", "JAPUX", "JAMMZ", "ADOBE", "JUMEK", "HBR", "CARFF", "DATTA", "IRW", "TOTES", "DROPS", "KEVIL", "TUL", "ROBDE", "ADAIR", "TIFFS", "MIYDA", "EOS", "MIPCY", "ZOGAR", "MEVDY", "SGF", "ROBCO", "LANEZ", "STEME", "STOUT", "REBBS", "VIH", "STEER", "DERDF", "STL", "PRAYS", "YIBFO", "VLA", "UFJUV", "SHUMY", "MOBBY", "DELCO", "IFIGO", "JUMOM", "KOCUJ", "TTH", "KIYSI", "MATAN", "FILMS", "VHP", "JOLVU", "CLANG", "PENDS", "MIE", "FAXIG", "REDKE", "BOOKS", "NADIR", "HINES", "LINZZ", "FBC", "OBRLN", "BRUNZ", "DJB", "ZITER", "JFN", "ERI", "HAMIT", "FOUTN", "DKK", "LODIY", "BUF", "GEE", "UMAGY", "BEEPS", "SCIPO", "BOCKS", "VESPE", "GGT", "SHERB", "BROOD", "COOES", "REAVE", "COBIA", "CASIL", "CEDOR", "ALB", "WARUV", "GRAVE", "GRISY", "WARIC", "HURLY", "GDM", "GRAYM", "BLATT", "MOGUL", "ORW"]},
+    "V140":{ "name":"V140", "fixes":["PNH", "GOONI", "WUDPI", "ASAZE", "BFV", "HISLA", "ZELNU", "IFI", "WENDY", "LASTS", "GULLI", "IBAAH", "YARNS", "SEARS", "TUL", "INOLA", "TUSOC", "PRYOR", "GENET", "ZOSEN", "JAMDO", "RZC", "CATEX", "SPRAY", "FALUG", "GREEM", "HRO", "CADAN", "BERGG", "PYATT", "MUVUE", "INNAM", "SUBIC", "CEMUK", "WASUD", "VILLO", "ARG", "HEPUL", "LUMXU", "BLITH", "HELMS", "DYR", "GOSHN", "DELHA", "BEVEE", "JEDAT", "BNA", "LENON", "HETAP", "HARME", "LVT", "WNSOR", "ESONE", "LOZ", "AZQ", "STACY", "KENYA", "BLF", "OBERS", "SOFTY", "ZOOMS", "CASTE", "COVEY", "HOBOS", "RELEE", "MOL", "TURGA", "MITER", "WITTO", "HOODE", "CSN"]},
+    "V141":{ "name":"V141", "fixes":["ACK", "GROGG", "CRACO", "BRUWN", "GAILS", "DUNKK", "CELTS", "BOS", "MHT", "CON", "KERSY", "KELLI", "LEB", "RUCKY", "GREEK", "BTV", "KEESE", "RIGID", "TRIKY", "BUGSY", "MSS"]},
+    "V142":{ "name":"V142", "fixes":["TWF", "MURTH", "OCLEY", "SHEAR", "MLD", "HUSEM", "ORNEY", "FBR", "WEGEM", "PUDVY", "OCS"]},
+    "V143":{ "name":"V143", "fixes":["GIZMO", "AZELL", "GSO", "LEAKS", "ULAKE", "ENTUK", "DUNCE", "HURTT", "LYH", "ELLON", "CLYFF", "MOL", "CEROL", "LURAY", "KERRE", "AANTS", "HOAGE", "MRB", "MAPEL", "ROBRT", "MULRR", "HYPER", "BINNS", "SUEDE", "DELRO", "JOANE", "LRP", "PTW", "ARD"]},
+    "V144":{ "name":"V144", "fixes":["BDF", "SMARS", "IKK", "ZORRO", "RODNY", "MAPPS", "DENAM", "CLEFT", "TELEY", "OYIDU", "FWA", "UCAYU", "BUZZI", "ZEDIN", "GUNNE", "APE", "CINAB", "ZZV", "MUNOE", "HISOM", "BEALL", "BURGS", "TEDDS", "MGW", "MOTME", "ESL", "LDN"]},
+    "V145":{ "name":"V145", "fixes":["UCA", "WEEPY", "FLOOR", "LIDLE", "ART", "REEDO"]},
+    "V146":{ "name":"V146", "fixes":["ALB", "CTR", "BAF", "KIBBE", "WITNY", "PUT", "FOSTY", "PVD", "AVONN", "COSSY", "MVY", "ACK"]},
+    "V147":{ "name":"V147", "fixes":["ARD", "TATVE", "MAZIE", "ZUVIV", "CFCCJ", "SPUDS", "ETX", "SLATT", "WHITT", "LVZ", "LOPEZ", "LACIE", "TWIIN", "BIPOD", "ULW", "ATTAR", "GEE", "ROC"]},
+    "V148":{ "name":"V148", "fixes":["FQF", "LIMEX", "BORDR", "TXC", "RUDVE", "WODUG", "MCJEF", "HCT", "CINIV", "LBF", "OGEZO", "ECYUS", "BOKKI", "JIKNU", "ONL", "CURIR", "TYNDA", "PUKIC", "DOLTS", "FSD", "SECTO", "POEMS", "POGSE", "ZERAD", "PILIY", "RWF", "COMOS", "WIDIS", "RIXIE", "MAYER", "WOXEB", "FUDGE", "GEP", "AQUAT", "CINCI", "FEDMU", "ALEEN", "HYR", "IWD", "NIMTE", "IKUTE", "PAVGE", "CIPMI", "CMX"]},
+    "V149":{ "name":"V149", "fixes":["FJC", "BEERS", "ROCOY", "RITTY", "LAAYK", "TYYLR", "CFB"]},
+    "V15":{ "name":"V15", "fixes":["HUB", "ADING", "MIFFI", "TNV", "WELTT", "HEDIX", "CLL", "GASEC", "HAMAN", "LOTTA", "SATTY", "OMOBE", "ACT", "OVFAC", "FEPHY", "IMIPE", "DRILL", "THING", "CQY", "ZONTO", "CINOK", "KEYEG", "IKOYA", "BYP", "PRIZZ", "RIGYA", "WOLUR", "DOMCO", "DESDE", "MLC", "BASAY", "HOFFE", "CUTYA", "OKM", "MALTS", "PRYOR", "MUCAZ", "EOS", "SUX", "ESTIS", "JILRO", "CANTS", "FSD", "HON", "TULLA", "EFJAM", "ABR", "MUNEF", "IRIWY", "WISEK", "MOFIT", "BIS", "FIKAG", "WILTN", "WASHR", "TERTL", "HIDEL", "PABIC", "MOT"]},
+    "V150":{ "name":"V150", "fixes":["SFO", "SUTRO", "GOBBS", "SAU", "COMMO", "REBAS", "CROIT", "FLEAT", "EMBER", "SAC"]},
+    "V151":{ "name":"V151", "fixes":["GAILS", "UPBIN", "HOPTU", "INNDY", "PVD", "FOSTY", "PUT", "GRIPE", "GDM", "EEN", "STRUM", "UNKER", "MCADM", "LEB", "ZIECH", "DAVID", "MPV", "CEVIB", "POROE", "BTV"]},
+    "V152":{ "name":"V152", "fixes":["PIE", "PLUMY", "KNEED", "JENSN", "KIZER", "OMN"]},
+    "V154":{ "name":"V154", "fixes":["RMG", "TIROE", "BOWLN", "FOBES", "MCN", "OTGUQ", "CARYS", "APELE", "DBN", "OCONE", "EHEJO", "LOTTS", "BROSE", "MAYAR", "SAV"]},
+    "V155":{ "name":"V155", "fixes":["CSG", "CANER", "GRANT", "HUZER", "SMARR", "SINCA", "BEYLO", "ANNAN", "IRQ", "TREAD", "JOKER", "MONET", "LEDAS", "WIDER", "BLOTS", "LOAFS", "CTF", "NOMOE", "LILLS", "SDZ", "OCHOC", "MOATS", "RDU", "WIPER", "BEXGO", "LVL", "MANGE", "MELIA", "FAK", "ROOKY", "NABBS", "COATT", "OGATE", "FALKO", "BRV"]},
+    "V156":{ "name":"V156", "fixes":["CID", "REZIE", "MOSCO", "MZV", "JPAUL", "WAKDI", "BDF", "MOTIF", "EON", "LUCIT", "MAPPS", "OXI", "NOMES", "GIJ", "JJANN", "AZO"]},
+    "V157":{ "name":"V157", "fixes":["EYW", "STRAP", "TIGAR", "CARNU", "DVALL", "WEVER", "FAMIN", "FOGSO", "DHP", "FRRDY", "HOLID", "NEWER", "GILBI", "THNDR", "LBV", "RINSE", "FUPGE", "DOWNN", "LAL", "URIVE", "WEBBS", "HYZER", "SADEY", "OCF", "DODNY", "DRAFT", "TAY", "WIWHE", "JOPXU", "AYS", "AMG", "BAXLY", "REIDS", "LOTTS", "DOVER", "ALD", "HARAB", "BOWMA", "VAN", "MADLY", "PEGIE", "DUTEE", "FLO", "TROCK", "ROWEL", "CEGAD", "FAY", "BYRNE", "MANWE", "JOSCH", "ISO", "WIBID", "TYI", "DUFFI", "LVL", "MANGE", "DALTO", "MATOX", "RIC", "SVILL", "TAPPA", "DUPEY", "COLIN", "PXT", "GOFER", "CHURK", "GARED", "CHOPS", "ORETE", "HEDGE", "RIDGY", "CANNY", "ENO", "ZITTE", "OOD", "RUUTH", "DAVYS", "ENZEW", "HOLEY", "BRAND", "KORRY", "RBV", "TYKES", "MINKS", "RENUE", "APPLE", "TICKL", "PROUD", "DIALS", "LGA", "FAMMA", "CRALY", "HAARP", "DOSWL", "BASYE", "VALRE", "IGN", "TRESA", "WIGAN", "ATHOS", "GROUP", "ALB"]},
+    "V158":{ "name":"V158", "fixes":["MCW", "POUND", "ZEZDU", "DBQ", "SAVAN", "TROST", "WACKS", "PLL", "SHOOF"]},
+    "V159":{ "name":"V159", "fixes":["VKZ", "ZARNA", "SHANC", "ATONE", "ARKES", "NITNY", "YIGBO", "JUPEM", "TBIRD", "BIWIK", "TRV", "TPSTR", "DEARY", "JIHMU", "PRESK", "ORL", "MAMBO", "LEESE", "SHIMM", "CUSAB", "ALADN", "OCF", "PERSE", "WILON", "CTY", "GEF", "YALMI", "HARKE", "SALER", "PZD", "XOCOT", "SHANY", "AYUVO", "SAWES", "AXOSE", "EUF", "MILER", "TGE", "KENTT", "SEMAN", "NIXBY", "FAYEZ", "KYLEE", "ADZIN", "HANDE", "VUZ", "NEGEE", "CORES", "CHOOK", "EXIST", "FOGUM", "IVMEC", "HAB", "HAGIV", "IXBOL", "GANTT", "ZATEL", "ICAVY", "HLI", "ERPOW", "CUXEG", "ZEDTU", "KUMGE", "KALIE", "GQE", "ARG", "ZERTY", "AVARR", "DGD", "REVEE", "FORDS", "SGF", "OLIVA", "OLLII", "TRALE", "AUGIE", "HODEN", "ANX", "LYMES", "EXCEL", "LASSO", "HANOT", "STJ", "TRAIG", "VIKKI", "OVR", "ZISIX", "CANIO", "AANDY", "BECOM", "SUX", "HURLI", "OBERT", "ZUSBU", "YKN", "PUKIC", "TECUD", "MHE", "WELEK", "HON"]},
+    "V16":{ "name":"V16", "fixes":["LAX", "DODGR", "LAHAB", "PRADO", "WISUP", "PDZ", "EDITS", "SETER", "BANDS", "GARNE", "PSP", "CONES", "BLH", "JAROZ", "SODSE", "VICKO", "BXK", "ALLIS", "PERKY", "AVONA", "PXR", "TUKEE", "SACAT", "IFNUR", "JIPON", "RIYCO", "GICGE", "TOTEC", "PICLI", "PIMMA", "TUS", "SSO", "ANIMA", "DARCE", "CUS", "HANCH", "ELP", "GIFEN", "RIOWE", "SFL", "DILLI", "CAVRN", "FEVOM", "INK", "JUGUD", "GOMIT", "PIZON", "MERGE", "TARZN", "BGS", "WEEPE", "LORAN", "TREAT", "MERKE", "ABI", "ROGEE", "CIYAL", "GACEB", "SHAKY", "HIBIS", "UKW", "ZUMKI", "BYP", "OKUCI", "MONTE", "RAKOC", "PRX", "LENYI", "GIGVE", "TXK", "KECEC", "HOSES", "SPARO", "BUNNS", "HUTOR", "IYUNE", "PBF", "BUCAY", "KIYEL", "UJM", "JEPOB", "WSTON", "YUGPU", "HLI", "JKS", "POLAN", "LEARY", "SYI", "KEYSE", "FOSUL", "WAKEE", "MCMIN", "LAUNS", "HCH", "BUCKY", "SWASO", "VXV", "PENCE", "WHINS", "OTWAY", "TAKEN", "HMV", "DAMAS", "STOVE", "SPEEL", "MAXME", "PSK", "BUFIY", "ROA", "GOOZE", "HEMEV", "OTINE", "LYH", "LOSEC", "CONCO", "VOUCH", "SHEPS", "CRUMB", "FAK", "RIC", "SVILL", "TAPPA", "DUPEY", "COLIN", "PXT", "GOFER", "CHURK", "GARED", "CHOPS", "ORETE", "HEDGE", "RIDGY", "CANNY", "ENO", "BRIEF", "VCN", "LEBVE", "CYN", "WHITE", "DIXIE", "MOVFA", "JFK", "KEEPM", "TRANZ", "JAFFY", "CCC", "KEYED", "VIKKY", "CREAM", "FLIBB", "YODER", "KURTY", "SALEM", "ORW", "JEWIT", "FOSTY", "HEFTY", "WOONS", "MILIS", "BOS"]},
+    "V160":{ "name":"V160", "fixes":["HBU", "SKIPT", "LOZUL", "RONBE", "TERRO", "MURFE", "LARKS", "SIGNE", "FQF", "HOKER", "WITNE", "SAYGE", "SYLVR", "TUMBL", "OGJUN", "WUBNO", "SNY"]},
+    "V161":{ "name":"V161", "fixes":["THX", "TINIE", "OTVIW", "LEMIG", "SOMER", "TRAGO", "KICED", "CSI", "LEJON", "LLO", "BUILT", "DUFFA", "MQP", "TIEON", "UKW", "FERET", "ADM", "JULKU", "HOLLE", "PHARA", "OKM", "ZORLA", "HASKL", "TUL", "NOVEL", "KOYXE", "OSW", "NALLY", "BIKNL", "NABYY", "BUM", "INRAM", "ANX", "LYMES", "EXCEL", "LASSO", "JAWED", "LMN", "WIVEY", "DSM", "ANKEN", "NEVAD", "SHODR", "ALOCK", "MCW", "KEFGO", "LIYIK", "RST", "CORDY", "DOKTR", "FOBUG", "FGT", "GEP", "SAUGR", "ZAPIN", "PLUGS", "OLLEE", "GOLLF", "YEPSU", "BRD", "MEBGY", "GPZ", "WIMJY", "SQEAK", "BEBEL", "WANRI", "JIBDU", "INL", "JGKGR", "KRANG", "PRADA", "YWG"]},
+    "V162":{ "name":"V162", "fixes":["HAR", "BOBSS", "HWANG", "DUMMR", "ETX", "FJC", "SCOUP", "HOPCE", "HUO"]},
+    "V163":{ "name":"V163", "fixes":["MAM", "BRO", "HAVIX", "RELAX", "MANNY", "OPULL", "ASCOT", "SOLON", "POGOE", "CRP", "SINTO", "SKIDS", "ZAMLI", "THX", "YENNS", "EMBOW", "SAT", "GOBBY", "AMUSE", "BASIS", "SLIMM", "AGJ", "TENAT", "JEN"]},
+    "V164":{ "name":"V164", "fixes":["BUF", "BIZON", "BENEE", "ELZ", "CAFKI", "DMACK", "SFK", "FQM", "DIANO", "ETX"]},
+    "V165":{ "name":"V165", "fixes":["MZB", "SARGS", "REDIN", "OCN", "KELPS", "DANAH", "KRAUZ", "BALBO", "MIDDS", "SLI", "POPPR", "HERMO", "LAX", "VALEY", "LANGE", "SAUGS", "LHS", "JEFFY", "LOPES", "AMONT", "MINGI", "ARVIN", "EHF", "IVECU", "TTE", "EXTRA", "DINUB", "SELMA", "CZQ", "COGOL", "DARBI", "MARRI", "JIMPA", "RAMRE", "YARKU", "FMG", "PYRAM", "LIBGE", "SEDTO", "BINNZ", "HETUX", "CHOIR", "NEWPI", "LKV", "POCIT", "URBIA", "DSD", "BOTTL", "HORRN", "WALDO", "ELKES", "MAVER", "RAWER", "UBG", "HOGUM", "SCAPO", "DAFFI", "PITER", "LOATH", "ATASY", "WINLO", "HOKBO", "CETRA", "OLM", "CARRO", "JUVGA", "ARPEE", "DIGGN", "CVV", "ISLND", "CANDL", "HUH"]},
+    "V166":{ "name":"V166", "fixes":["JPU", "MOSIC", "CASOP", "CKB", "TYGAR", "UGJOB", "ESL", "CAPON", "MEPEW", "MRB", "RUANE", "EMI", "TAFFI", "FEGOZ", "BELAY", "SUDOY", "CURVY", "BAINS", "ELUDE", "DQO", "OOD", "BRIEF", "LEEAH", "SIE"]},
+    "V167":{ "name":"V167", "fixes":["HNK", "FITRE", "KERRI", "WEARD", "HELON", "SPECL", "IGN", "DEEDE", "MOONI", "JUDDS", "HFD", "JEWIT", "PVD", "TUTOR", "ZUNUX", "PEAKE", "LFV", "SCUPP", "WEEZE", "CEKAY", "SEROC", "ARMIE", "ENE"]},
+    "V168":{ "name":"V168", "fixes":["VUZ", "LINTZ", "GOSSE", "GIFFY", "LGC", "CRAWL", "MILER", "KOMER", "CHIRP", "EFORD", "ZUTAG", "RRS"]},
+    "V169":{ "name":"V169", "fixes":["TBE", "KINGO", "TODDE", "HGO", "TXC", "AKO", "HINGA", "SNY", "JENUK", "MEILE", "OFOCI", "BFF", "OFOWY", "SPONS", "TST", "WAXER", "CURSE", "RAP", "BEEFY", "ZAVLI", "DPR", "ALENS", "SHYLS", "TIMMR", "OHROR", "BIS", "ODUBY", "CHACE", "DVL"]},
+    "V17":{ "name":"V17", "fixes":["BRO", "HRL", "FLATZ", "MFE", "FATOR", "ELIZA", "NELEE", "HEVUM", "LRD", "IRICI", "KAHAN", "COT", "MILET", "SOMER", "SAT", "SHEPE", "BETTI", "ZINGO", "GARDS", "CWK", "DARTE", "REDDA", "ZURGU", "CONRA", "ROLAC", "ACT", "IGORR", "GAINS", "BRIAN", "JEN", "MQP", "TIEON", "UKW", "FERET", "ADM", "ZALUN", "MUSKS", "WETIX", "COFIX", "HAVAK", "IRW", "CAMET", "ZELNU", "ODINS", "OLVAE", "PANIY", "CAMAR", "TISSY", "MMB", "TUDPE", "EKEWU", "FLACK", "KASBE", "ZILCH", "GCK", "YANUK", "COFFE", "WILVA", "GLD"]},
+    "V170":{ "name":"V170", "fixes":["DVL", "WADIM", "FARRM", "JMS", "FAHTU", "GICAY", "WODTY", "FIGOB", "ABR", "AZZOZ", "ZOTBY", "FSD", "BRAIN", "OTG", "ISLER", "FRM", "BLEND", "FREED", "NEWRY", "ENDSS", "ZOLET", "RST", "DLANY", "DIMMY", "ODI", "BOOTY", "FAPKO", "DLL", "WREST", "RANDO", "EWAWI", "WIDKI", "BAE", "LIIME", "PETTY", "BRAVE", "ENKOW", "PAITN", "RAINE", "PMM", "OSEGO", "HEBEL", "BEJAE", "POSIE", "LESSY", "DUNKS", "POVCI", "SVM", "ERI", "BFD", "SLT", "FAVUM", "SWISS", "COVOB", "SEG", "RAV", "HWANG", "KERYN", "BOYER", "DETTE", "MXE", "DQO", "KIRKK", "ODESA", "KERNO", "GATBY", "SWANN", "PALEO", "POLLA"]},
+    "V171":{ "name":"V171", "fixes":["HYK", "SAAPP", "MCFEE", "CHALI", "LAZYT", "IIU", "MAIZE", "HONOS", "FRIZN", "SCOTO", "TTH", "JAZZY", "STATE", "DNV", "BATAM", "WEARS", "EON", "OCEDO", "MEDAN", "JOT", "SWETT", "HINCK", "SIMMN", "NOAHE", "RFD", "DAVIS", "LUANN", "GLARS", "DALEY", "LNR", "HIRUM", "WEBYE", "ODI", "VUZID", "EMILS", "YUGYY", "ELIKE", "FGT", "ONARE", "PRIOR", "JONNA", "MAYER", "DWN", "TESEE", "AXN", "STARR", "ROLAG", "APRIW", "IRILE", "SHELS", "GFK", "EYWUS", "FALPA", "ROX"]},
+    "V172":{ "name":"V172", "fixes":["LBF", "ITEYA", "YAMNA", "BONIL", "OBH", "HUDNI", "OLU", "HOVAR", "BOYSS", "OVR", "WUNOT", "USORE", "LINDE", "GUMBO", "ZISTA", "ANKEN", "CINOR", "TNU", "OPDUY", "BEIGE", "CID", "LISBO", "GIZCY", "CIDSO", "LOTTE", "PACAF", "MIHAL", "PLL", "DAYVL", "CHANA", "RUSLL", "SIMMN", "NUELG", "DPA"]},
+    "V173":{ "name":"V173", "fixes":["SPI", "RAILS", "JILLY", "NEWTT", "EON"]},
+    "V174":{ "name":"V174", "fixes":["YRK", "HNN", "GAYED", "CARLA", "EKN"]},
+    "V175":{ "name":"V175", "fixes":["MAW", "NARDY", "LEPER", "WOSGI", "BUNKS", "JELNA", "VIH", "ZIPUR", "HODGS", "STITH", "HLV", "MCM", "WOGOL", "IRK", "OHGEE", "LACON", "DSM", "ILODE", "LINDE", "MADUP", "YETJA", "WELTE", "SUX", "OYENS", "COPYE", "OTG", "LEVRE", "GOPEC", "RWF", "FITAS", "ARMUW", "ULJAB", "AXN", "WATAM", "PKD", "UCOVO", "CELIS", "BLUOX", "ORESE", "TITUE", "ROX", "CDSCC", "YWG"]},
+    "V176":{ "name":"V176", "fixes":["CRL", "MACCS", "SSUNN", "HIMEZ"]},
+    "V177":{ "name":"V177", "fixes":["JOT", "NUELG", "JULOX", "GRIFT", "JVL", "TAVNE", "PASYO", "GARTT", "MSN", "WREST", "HAMTN", "STE", "TAYUY", "AUW", "CULOG", "LACIY", "BAITS", "HYR", "POTLY", "DLH", "FOSUP", "KUMDE", "ELO"]},
+    "V178":{ "name":"V178", "fixes":["HLV", "BNTON", "WEVRA", "CYTKA", "VIH", "FAM", "DEDEE", "CGI", "HIKIE", "CNG", "VERTS", "YANUS", "CCT", "MAHEN", "RENRO", "OSINE", "EWO", "DEMSE", "HERMS", "MAUDD", "MCFEE", "SAAPP", "HYK", "LOGIC", "TRENT", "SLINK", "BLF"]},
+    "V179":{ "name":"V179", "fixes":["SSI", "KIRNS", "WABIT", "REIDS", "TRUET", "DBN", "RIPPI", "WOGOM", "SINCA", "CANUK", "HUSKY"]},
+    "V18":{ "name":"V18", "fixes":["GTH", "BEKLE", "ROGEE", "MQP", "JEN", "CELTC", "ACUFF", "CQY", "AWOLF", "UIM", "LASSA", "PIKTE", "CADOZ", "EIC", "WEBBY", "GAMMS", "MLU", "WOVAS", "STUEE", "HEDUD", "ZIPGI", "MHZ", "NOYIG", "FANEN", "ENAKE", "CUNEV", "HABJE", "MEI", "NOSRY", "BOYDD", "ALICE", "LDK", "SITES", "OAKGO", "WUNET", "RIMZO", "VUZ", "TRUST", "JOTAV", "NOPVE", "TDG", "ZOMDI", "KOCEY", "LAYIN", "HEFIN", "ARPPE", "TEMPO", "ATL", "CONNI", "MEGGN", "MADDI", "CORVI", "EXJAN", "RAFFE", "APIAN", "IRQ", "LASHE", "NORMS", "HARAB", "SACKS", "DORCE", "LAMKE", "GISTS", "MEGEE", "CHS"]},
+    "V180":{ "name":"V180", "fixes":["INL", "JGPTT", "YHD"]},
+    "V181":{ "name":"V181", "fixes":["IRK", "OSIVE", "LMN", "RILGE", "CETUB", "SAJHO", "OBREC", "EMEND", "OVR", "KENAR", "IBHEN", "OFK", "MAGET", "HARDS", "YKN", "FSD", "VOLGA", "OBITT", "VESTY", "ATY", "STUCK", "RIRCO", "GUVEY", "BANEY", "RUSTD", "FAR", "PAWSS", "JOCOR", "GFK", "WUTSO", "NALCO", "WUBED", "HML", "ZOMTA", "YWG"]},
+    "V182":{ "name":"V182", "fixes":["OTH", "YUPVU", "GAMMA", "BOSVE", "JANAS", "ONP", "FOSTI", "LANKE", "TIYOT", "COGOK", "LUSEY", "UBG", "OSWEG", "BTG", "PIQRI", "GYMME", "CARBY", "LTJ", "BREED", "HEPPE", "UKIAH", "JELTI", "BKE", "NUDEQ", "WOLIP", "IBEAM", "ATOKE", "LEZLE", "MQG"]},
+    "V183":{ "name":"V183", "fixes":["RZS", "TAFTO", "MARIC", "STIGR", "EHF"]},
+    "V184":{ "name":"V184", "fixes":["ERI", "MUGOE", "TDT", "DETPE", "DAAAV", "PSB", "RASHE", "MCMAN", "PYCAT", "HAR", "FAMAV", "DELRO", "ROAST", "GEERI", "RICKF", "PADRE", "MXE", "EKSEW", "SAVVY", "OOD", "VCN", "ACY", "PANZE", "FALON", "ZIGGI"]},
+    "V185":{ "name":"V185", "fixes":["SAV", "SPONG", "DOVER", "MILEN", "SARDY", "HEDIL", "BEANS", "IRQ", "COLON", "BLANE", "LUKES", "GRD", "REEDY", "PETON", "DUNKE", "ILEYO", "PELAM", "UNMAN", "SUG", "OZONE", "RIGEL", "MUMMI", "SOT", "PENCE", "VXV"]},
+    "V186":{ "name":"V186", "fixes":["RZS", "ZIQOR", "DEANO", "HENER", "FIM", "SESPE", "VNY", "DARTS", "PURMS", "ELMOO", "ITSME", "PIRRO", "ADAMM", "BAYJY", "TIFNI", "PDZ", "NIKKL", "WESIN", "TANNR", "DEGLE", "ROBNN", "HAILE", "PGY"]},
+    "V187":{ "name":"V187", "fixes":["ONM", "WUBBY", "ENCIA", "MOPSE", "BUPNY", "ABQ", "AWASH", "CURLY", "CABZO", "TANER", "MISSY", "RSK", "RIZAL", "MANCA", "HAVWU", "HERRM", "SINSY", "JNC", "LOMMA", "TESSY", "RACER", "RENAE", "OCS", "SWEAT", "HONOX", "RIW", "FETIK", "BOY", "CRANY", "PECKK", "PRYER", "NELWN", "BIL", "TASSE", "JUGAP", "ZERZO", "KAVMY", "GTF", "TUCKB", "GUGYI", "ROSOE", "OCEDA", "SQIDS", "MSO", "WAANE", "LOLLO", "DAIRE", "RIVAL", "JIROS", "OFINO", "CEPER", "PETEZ", "MQG", "POTOR", "SEVER", "RENGO", "BUTOC", "DATES", "BACUN", "OYREX", "PSC", "EXODE", "NIALS", "FEBUS", "ELN", "THICK", "WUSVI", "RADDY", "MOUNT", "ORTIN", "COTNY", "TCM", "CFCFF", "OLM", "OZEYO", "RINDS", "CETUV", "HEVOL", "AST"]},
+    "V188":{ "name":"V188", "fixes":["CRL", "MACCS", "SSUNN", "AZTRO", "GILLS", "FAILS", "WONOP", "CLERI", "JFN", "ALLCO", "TDT", "SCENT", "CLERO", "SLT", "BLAZE", "TRUER", "FQM", "MUNCI", "SWANK", "LVZ", "EXAGE", "TALLI", "COATE", "SAX", "NYACK", "DOSWL", "CMK", "FZOOL", "SEALL", "CARLD", "KURTY", "GON"]},
+    "V189":{ "name":"V189", "fixes":["RBX", "ALGTR", "STIKK", "DAREZ", "RMACK", "TYI", "FKN", "WAIKS", "HPW"]},
+    "V19":{ "name":"V19", "fixes":["CVG", "HEDEN", "MARTZ", "GAILL", "JORUV", "APE"]},
+    "V190":{ "name":"V190", "fixes":["PXR", "LAKEY", "ZERLO", "GRINE", "PEAKS", "TEDDI", "FORPE", "IZTIR", "CHEKR", "SALTS", "WEKUM", "CAMVI", "HOZER", "SJN", "IZZOM", "ACOMA", "ABQ", "DULKE", "CAYAL", "RENCO", "FTI", "HOLSU", "ASOYA", "OWUPO", "DHT", "REPPA", "MMB", "TUZXY", "CARON", "FIRET", "PER", "IDLUY", "JIPMA", "BVO", "ITEXE", "DELAT", "EJYAR", "OSW", "COOKI", "HOFMN", "JETIP", "WACCO", "QUALM", "SGF", "SIPES", "PYLER", "WYLLS", "MAP", "BUNKS", "FAM", "GENTS", "MWA", "HARCE", "TEXAS", "HORAV", "UXZOR", "RIDDY", "PXV"]},
+    "V191":{ "name":"V191", "fixes":["TOY", "OREPE", "DAYRE", "PANAE", "AXC", "MOCEL", "BLLUE", "LODGE", "TARPE", "RBS", "NEWTT", "BOJAK", "LISKE", "OBK", "WIPED", "BONOT", "BAE", "CORIR", "EDENN", "OSH", "EYITI", "BIPID", "CHURP", "USERS", "ZITOD", "PEPVY", "RHI", "CESSI", "IWD", "WASPS", "NOYIC", "HUGRA", "LAZNU", "MASWE", "DLH", "HIB", "GPZ"]},
+    "V192":{ "name":"V192", "fixes":["CMI", "NEWMY", "BLANO", "TTH", "CLOTT", "VHP", "JOLVU", "CLANG", "PENDS", "MIE", "WINNO", "DQN"]},
+    "V193":{ "name":"V193", "fixes":["MUSKY", "PMM", "JAKES", "CLOCK", "KENTS", "HIC", "BABBE", "CEGSI", "TVC", "SKIPR", "TIDDU", "ADENO", "IROTO", "LORIW", "PLN", "PINES", "SIGOE", "SSM"]},
+    "V194":{ "name":"V194", "fixes":["CQY", "ALLMO", "KISER", "NAVYS", "CLL", "JEPED", "COUTH", "PRARI", "SEALY", "DREWZ", "HUB", "SBI", "TEMCO", "CIPDA", "GUSTI", "LFT", "ROSEY", "TATER", "LSU", "CAZZZ", "MCB", "NEMCI", "WIKZO", "MIZZE", "BAING", "PAULD", "MEI", "LIB", "GUSES", "RDU", "ZEBUL", "EXULE", "FEBEL", "TYI", "CVI", "SUNNS"]},
+    "V195":{ "name":"V195", "fixes":["OAK", "BERKS", "SABLO", "CROIT", "CORDD", "RAGGS", "BESSA", "ELEGY", "ILA", "JINGO", "GONGS", "RBL", "BURRS", "TOMAD", "DINSE", "YAGER", "TOYEE", "FOT"]},
+    "V196":{ "name":"V196", "fixes":["UCA", "USICI", "GACKE", "BECKS", "SMAIR", "FOSYU", "SLK", "RIGID"]},
+    "V197":{ "name":"V197", "fixes":["PDZ", "POM", "HASSA", "PMD", "FISCH", "JERID", "ZALJE", "WIJYI", "KELEN", "AMONT", "MINGI", "ARVIN", "EHF"]},
+    "V198":{ "name":"V198", "fixes":["SSO", "HUSIT", "CUS", "HANCH", "ELP", "TYLAN", "FABAN", "HUP", "AGAZY", "DOWES", "FST", "OZMOS", "KEMPL", "JCT", "DOSSY", "LEJON", "TATAR", "SAT", "CHURN", "SEEDS", "WEMAR", "FFSSH", "WHAEL", "ELA", "GLAND", "BLUMS", "HUB", "SBI", "HERBY", "LLA", "DOYAD", "EYUGU", "ORICH", "LUFFS", "LASYO", "TBD", "OLEDD", "SAFES", "HRV", "MENTC", "PEARL", "MINNI", "DOGMA", "ELSIE", "ROMMY", "VICKI", "PLEBE", "SAINT", "BFM", "LOXLY", "BRATT", "PENSI", "INBRD", "ITNEW", "BAKOS", "CEW", "CORKY", "DEFUN", "IKMOQ", "LAARA", "CHEWS", "BJLEW", "MAI", "SNEAD", "QUILL", "SZW", "LLOYD", "GEF", "HADDE", "TAY", "MONIA", "LIBBY", "CRG"]},
+    "V199":{ "name":"V199", "fixes":["SFO", "SUTRO", "GOBBS", "STINS", "DUBRY", "MOLEN", "BOARS", "FROSH", "NATIC", "ENI", "WEPLO", "SABBY", "MENSE", "HENLE", "OBGEE", "RBL"]},
+    "V2":{ "name":"V2", "fixes":["SEA", "VAMPS", "BANDR", "BEEZR", "ELN", "BOVYA", "DOFDO", "EDSEW", "UDECU", "PLUSS", "MWH", "BATUM", "SUBDY", "ZOOMR", "YICUB", "GANGS", "GEG", "ROPES", "HIPRR", "HILIE", "MLP", "LIBRE", "ALTON", "MSO", "SPUNK", "BAMBE", "PIXXI", "RICHD", "HLN", "CUSRI", "SWEDD", "CONNS", "NUKUW", "LVM", "SUBKY", "REEPO", "COLUS", "NARUW", "BIL", "KOXMY", "NIBBE", "CONUK", "ASHLI", "MLS", "KIXCO", "UMWEL", "QATSA", "RUNYO", "DIK", "POCIG", "SOXOW", "ULLIN", "SAILM", "HIPNU", "BIS", "ZOLUN", "STIEL", "TAPNN", "JMS", "HUHJO", "CHAFE", "HONET", "FAR", "WIRDE", "PANIC", "TILER", "AXN", "OBARE", "OKOMY", "TLBAT", "SODIE", "GEP", "ZASKY", "KANAC", "PRESS", "MANIE", "TROLL", "PEGGS", "ODI", "WEBYE", "HIRUM", "LNR", "OGUYU", "NEGUS", "IMMES", "MSN", "DREAR", "WAITS", "BAE", "IRITE", "CARNA", "PROOT", "SUDDS", "LYSTR", "MINNY", "MKG", "WALKS", "SARAN", "LAN", "BAMBY", "SVM", "DELOW", "SPICA", "WOLIS", "DUSUT", "YQO", "JARVS", "MOAWK", "MYPAL", "WELLA", "VICCU", "SUSKE", "HIDUB", "BUF", "CLUNG", "MONCK", "ROC", "LORTH", "MAGEN", "KONDO", "WIFFY", "SYR", "FAYET", "STODA", "VASTS", "UCA", "NORSE", "MARIA", "ALB", "WARUV", "GRAVE", "GRISY", "WARIC", "HURLY", "GDM"]},
+    "V20":{ "name":"V20", "fixes":["MFE", "SANCA", "HARGI", "LATEX", "JIMIE", "ASCOT", "SOLON", "POGOE", "CRP", "COPAN", "BETZY", "BOINT", "PSX", "MAGUS", "KEEDS", "ACOLA", "HUB", "FRYED", "MOCKS", "BPT", "WASPY", "LCH", "ARTEL", "CRISP", "MICRO", "ZIROR", "LFT", "LULEW", "BUDAM", "MYRIC", "WOVON", "DONBE", "AWDAD", "SIMBY", "VOODO", "RQR", "SNAKI", "SLIDD", "CLERY", "MUDDA", "GPT", "NESFE", "BUGLE", "SQWID", "SJI", "AXSIS", "AXEJA", "TENSA", "MVC", "PICKS", "JEFER", "ALOON", "MGM", "CECAL", "SILOS", "TGE", "DRYDN", "CRAWL", "MARVO", "CSG", "CANER", "GRANT", "HUZER", "SMARR", "SINCA", "GLOSS", "MADDI", "JOTNO", "DACHA", "AHN", "JOSPI", "BOWMN", "HARTI", "ELW", "ELLID", "PEDAL", "CLEVA", "DOODD", "TUXDO", "SUG", "GENOD", "SWENK", "VAESE", "BZM", "SANFI", "JOTTA", "INGON", "PROVE", "MAYOS", "LEAKS", "UFFIN", "SBV", "LELLI", "YUDUG", "NUTTS", "MELIA", "RIC", "SVILL", "TAPPA", "DUPEY", "COLIN", "WHINO", "JUDED", "DAILY", "OTT"]},
+    "V200":{ "name":"V200", "fixes":["ENI", "LAPED", "DALON", "ILA", "YUBBA", "RAILE", "MRGGO", "RANGO", "SIGNA", "TRUCK", "VERDI", "FMG", "BVL", "ZONSU", "BAGGI", "CEVAR", "STACO", "ANEYI", "FFU", "PANEL", "NONTY", "MTU", "FECYE", "OHAPE", "BONGO", "RACER", "EKR", "TOJAM", "JESIE", "RLG"]},
+    "V201":{ "name":"V201", "fixes":["LAX", "BERRI", "SOLED", "PMD"]},
+    "V202":{ "name":"V202", "fixes":["SSO", "VIYUL", "SVC", "KEAPS", "KAPEY", "TCS"]},
+    "V203":{ "name":"V203", "fixes":["STELA", "SHIGY", "CANAN", "ALB", "OTOLE", "WAREN", "GASSY", "DINNY", "SLK", "MUNZA", "SCCOT", "MSS"]},
+    "V204":{ "name":"V204", "fixes":["HQM", "HIGDA", "SOUPY", "DOCRA", "OLM", "MCKEN", "ALDER", "WEBIM", "WHYTE", "WOREM", "TAMPO", "TUDGY", "YKM", "MARRK", "PAPPS", "PAIDS", "GUSSE", "PSC", "SMITT", "WATSY", "CFFMJ", "GRAPH", "GEG"]},
+    "V206":{ "name":"V206", "fixes":["ANX", "ROBDY", "LEXIN", "MURTE", "IRK", "DELOO", "ZEDGU", "OTM"]},
+    "V207":{ "name":"V207", "fixes":["GLL", "SHOOP", "PIETY", "HALOD", "BFF"]},
+    "V208":{ "name":"V208", "fixes":["VTU", "WEEZL", "SXC", "AVOLS", "PACIF", "HUBRD", "OCN", "VISTA", "ROBNN", "BONDO", "JLI", "WARNE", "TRM", "CONES", "CLOWD", "TNP", "EED", "PATOK", "PGS", "GUCRU", "AMERE", "GCN", "AWIZO", "TBC", "CELAY", "AROGE", "PGA", "AXGEX", "HVE", "ADIBE", "FOSOV", "PUC", "MTU", "EGRIW", "VEL", "SNAKY", "CKW"]},
+    "V209":{ "name":"V209", "fixes":["SJI", "BURIN", "HAZEY", "YARBO", "ANTUH", "JANES", "EWA", "EUTAW", "MOVIL", "OKW", "VUZ", "TRUST", "SPATT", "WENDO", "STAMP", "GAD", "EBAZE", "MENLA", "ATUNE", "EBESY", "FIDGO", "GQO"]},
+    "V21":{ "name":"V21", "fixes":["SXC", "SLI", "AHEIM", "OLLIE", "POXKU", "EBITE", "PDZ", "CIVET", "RAVON", "GAREY", "ARRAN", "DAWNA", "RESOR", "LUCER", "BULGY", "HEC", "DANBY", "WHIGG", "WOPMA", "BOACH", "CRESO", "DICSA", "BLD", "LAPIN", "MMM", "HUNKU", "URIAH", "BERYL", "MLF", "BEVRR", "MUBNE", "ZIBRA", "DTA", "RUBOY", "PUCIT", "FRNZY", "REEKA", "FFU", "JAURN", "MASIE", "TCH", "KAYZE", "OGD", "CORIN", "PIMIE", "MLD", "BANNO", "PIH", "FALLO", "CHEER", "IDA", "RIGBY", "DBS", "WEMKO", "DLN", "YARUP", "HIA", "GUSIE", "NNORA", "JEVAM", "ICADU", "HLN", "TICUS", "PATRR", "PONVE", "HOXEK", "NUMIJ", "ETIJO", "GTF", "KYELL", "BRADZ", "CTB", "CDLYC", "YQL"]},
+    "V210":{ "name":"V210", "fixes":["LAX", "DOWNE", "WUJEG", "PIRRO", "POM", "CALBE", "MEANT", "GARDY", "HESPE", "APLES", "BASAL", "HEC", "GFS", "UNPAS", "PRFUM", "DOMMS", "PGS", "GUCRU", "AMERE", "GCN", "TBC", "YIKLO", "ROUGH", "WUDIR", "ZENFO", "FULLY", "RSK", "PELDY", "RESER", "GEMKY", "MRKKO", "ALS", "BLOKE", "ACHES", "GOSIP", "RADIO", "JUKEX", "BLOOM", "KINGO", "TEKAE", "LAA", "UPIRE", "YUNUP", "LBL", "HIRAS", "ROLLS", "WAXEY", "HISLA", "IRW", "MINGG", "LOBOE", "OKM", "VHP", "JOLVU", "CLANG", "PENDS", "MIE", "DEBAR", "ROSSY", "RUSIA", "ROD", "GUNNE", "GIVES", "TVT", "ZETMU", "WILMO", "CEPSI", "BSV", "DEFOE", "SEING", "CAMES", "CAPEL", "VOLAN", "EARED", "TALLS", "LUCCA", "REC", "WILTT", "BLINK", "FANSI", "MARTT", "HAR", "WILEN", "BOUHN", "LRP", "TRAGG", "BUNTS", "SPERY", "AWISA", "PROPP", "ARD"]},
+    "V211":{ "name":"V211", "fixes":["BRAZO", "FEMAD", "COKRI", "DRO", "SWILL", "FIMGA", "UNLAP", "WOHCI", "MANCA", "CEZ"]},
+    "V212":{ "name":"V212", "fixes":["SAT", "CHURN", "SEEDS", "WEMAR", "IDU", "TNV", "OSCER", "LFK", "KIYER", "BODTA", "VELCO", "RAFTO", "APPIN", "COSGO", "COCOS", "AEX", "JOHON", "SETTA", "MCB"]},
+    "V213":{ "name":"V213", "fixes":["CRE", "CHAMS", "WYLMS", "BILLL", "ILM", "HELNA", "WALLO", "JOSCH", "ESTER", "TYI", "GUMBE", "MAZON", "HPW", "NEMAN", "KINKE", "TAPPA", "DUPEY", "COLIN", "PXT", "GOFER", "CHURK", "GARED", "CHOPS", "ORETE", "HEDGE", "RIDGY", "CANNY", "ENO", "SKIPY", "BESSI", "EDJER", "DAVYS", "ENZEW", "HOLEY", "BRAND", "KORRY", "RBV", "WARRD", "BONIE", "DIRMY", "JOELL", "PIYIN", "SHOTT", "TINNI", "WEKAS", "SAX", "SHAFF", "CRANK", "FLOSI", "HELON", "WEETS", "TALCO", "ACOVE", "ALB"]},
+    "V214":{ "name":"V214", "fixes":["OKK", "MZZ", "FOOTE", "MIE", "OCOVE", "WAMBO", "MOTTS", "RID", "GLOOM", "AMALE", "ZZV", "SABGE", "LORES", "AIR", "AHTIY", "OBEID", "GALLS", "GRV", "ELGEE", "MRB", "WOOLY", "YANNI", "BAL", "SWANN", "GATBY", "KERNO", "ODESA", "KIRKK", "DQO", "SAVVY", "STEFE", "SOMTO", "ARD", "MERSR", "METRO", "LINER", "DIRMY", "TEB"]},
+    "V215":{ "name":"V215", "fixes":["JYBEE", "RAINE", "SALES", "MKG", "HIC", "LADIN", "CARGA", "GLR"]},
+    "V216":{ "name":"V216", "fixes":["LAA", "WILVA", "ORION", "HLC", "RISHO", "KOTZA", "TKO", "KOPSY", "FAZED", "OYITO", "STEEL", "PWE", "COVUT", "TRAIG", "KARMA", "LMN", "OHGEE", "OTM", "YABUY", "IOW", "REZIE", "BILOX", "LOTTE", "WACKS", "LENAS", "DAVIS", "PAPOW", "JVL"]},
+    "V217":{ "name":"V217", "fixes":["FARMM", "BESIE", "TRUDO", "BAE", "HAWKN", "CANUL", "HISUB", "LEWKO", "CHING", "SHOOD", "GRB", "CECIL", "JEVBI", "CRUMS", "RHI", "PEWLE", "CINEX", "GOLYE", "KRSMS", "ERIYI", "GRASS", "CEKDA", "UPADE", "DLH", "HIB", "DUNEC", "SQEAK", "BDE", "KDCDK", "VOKUV", "JOVIN", "PRADA", "YWG"]},
+    "V218":{ "name":"V218", "fixes":["GPZ", "NEBBS", "LINDR", "CIVOL", "DOCKN", "UDILE", "GEP", "LDASH", "YUGYY", "FISIN", "BOCAG", "EYATE", "DLANY", "LEFTY", "PEDSY", "UKN", "FARON", "ISINY", "BAULK", "MADDY", "RFD", "ELX", "WIPEP", "BRONZ", "HEBEL", "DERRE", "RETOR", "LAN"]},
+    "V219":{ "name":"V219", "fixes":["HCT", "JAPTA", "YOZLE", "OBH", "ERGUC", "OFK", "PENDE", "GEGGE", "DECGA", "SUX", "CEKEG", "FEXAT", "KILEY", "CISAC", "FEDVO", "RITTA", "MILSS", "DOSNY", "GRUVE", "COZFO", "FRM", "MKT"]},
+    "V220":{ "name":"V220", "fixes":["JNC", "PACES", "EDUKY", "HUGSI", "RIYNO", "SLOLM", "RIL", "NOVJO", "EKR", "AXIAL", "JESKU", "CHE", "EGFAX", "HABRO", "SBURG", "TILLI", "GUVYU", "RLG", "HYGEN", "NIWOT", "GLL", "SYLVR", "AKO", "MCJEF", "QWILT", "MCK", "LIDIC", "SPRIT", "EAR", "LENIY", "MORGS", "HSI", "VAPGE", "BRADY", "GRASI", "COBED", "OLU"]},
+    "V221":{ "name":"V221", "fixes":["BIB", "LISLE", "BUNKA", "RACYR", "OPMUC", "OOM", "MOUTH", "SHB", "HOMAR", "MIE", "HAROD", "AJAYS", "WGNER", "FWA", "GAREN", "TAZCE", "ILTON", "MODEM", "LFD", "JXN", "HARWL", "DEXER", "SVM", "DELOW", "SPICA", "WOLIS", "HEGEL", "DOGGS", "SNIPE", "ERI"]},
+    "V222":{ "name":"V222", "fixes":["ELP", "GIFEN", "RIOWE", "SFL", "HOBAN", "FST", "OZMOS", "KEMPL", "JCT", "ARPER", "STV", "GOBBY", "BETTI", "MARCS", "CRAYS", "IDU", "SEALY", "IAH", "COSBI", "TRIOS", "BDDRO", "FALSE", "SHINA", "BPT", "WASPY", "LCH", "HATHA", "MAXON", "BOZAN", "MOGAN", "WRACK", "LESTE", "NEMRY", "MCB", "CETDA", "WOBAK", "LBY", "LIGIC", "PICAN", "YARBO", "MVC", "PICKS", "JEFER", "ALOON", "MGM", "PETOC", "MARST", "KENTT", "YARBE", "TIMMY", "LGC", "HONIE", "TIROE", "LOGEN", "WOMAC", "MACEY", "CORCE", "ODF", "CALOK", "SUNET", "FREEZ", "SUG", "GENOD", "SWENK", "VAESE", "BZM", "RIVYR", "BURCH", "FREON", "HENBY", "PIGGS", "AYARA", "LYH"]},
+    "V223":{ "name":"V223", "fixes":["FAK", "EMMIE", "HANEY", "FLUKY"]},
+    "V224":{ "name":"V224", "fixes":["SAW", "ISQ"]},
+    "V225":{ "name":"V225", "fixes":["EYW", "STING", "GIGIH", "RIGOR", "MARCI", "CITAG", "HICUP", "RSW", "JICTI", "LBV", "VASQZ", "DIDDY", "CUSMO", "TRV"]},
+    "V226":{ "name":"V226", "fixes":["GRACE", "EARED", "CIP", "PARDY", "HONLU", "DAAAV", "ETG", "FAVUM", "ZIMEL", "FQM", "MUNCI", "SWANK", "LVZ", "HARTY", "SCOUP", "MUGZY", "STW"]},
+    "V227":{ "name":"V227", "fixes":["BVT", "BOSWL", "WEARS", "RBS", "JILLY", "PNT", "MEITZ", "PLANO"]},
+    "V228":{ "name":"V228", "fixes":["STE", "BANKY", "ZAVOX", "DLL", "MSN", "DEBOW", "BESIE", "FARMM", "UMUZI", "OBK", "THORR", "NEPTS", "GIJ"]},
+    "V229":{ "name":"V229", "fixes":["PXT", "GOFER", "CHURK", "GARED", "COSHA", "ATWEL", "GROUT", "DONIL", "LEEAH", "TUBER", "ACY", "PANZE", "DIXIE", "MOVFA", "JFK", "KEEPM", "TRANZ", "PUGGS", "BDR", "MILUM", "BAYYS", "DWAIN", "SEALL", "SNIVL", "HFD", "DVANY", "DARTH", "WITNY", "SPENO", "GDM", "EEN", "JAMMA", "EBERT", "MUDDI", "BTV"]},
+    "V23":{ "name":"V23", "fixes":["MZB", "CARIF", "HURSI", "OCN", "KELPS", "DANAH", "KRAUZ", "BALBO", "MIDDS", "SLI", "POPPR", "HERMO", "LAX", "CHATY", "TWINE", "CASTA", "GMN", "GRAPE", "LAMPE", "EHF", "DELNO", "PONDD", "PIXEY", "LATON", "FRAME", "CZQ", "OXVEV", "BEREN", "LAPOW", "UYOKA", "EBTUW", "TURLO", "NEBBY", "AWALI", "HONEZ", "WRAPS", "LIN", "GALTS", "SAC", "CAPTO", "EYPOF", "GRIME", "YUBBA", "GRIDD", "TALUM", "JINGO", "GONGS", "RBL", "BEIRA", "TAYTO", "SHATA", "FOLDS", "FJS", "ZUNAS", "LEANN", "TALEM", "LIPWO", "OED", "UZEHE", "BROKN", "MOURN", "CURTI", "SAGIN", "EUG", "ALFOR", "SHEDD", "MAGOT", "TURNO", "EMADE", "GNNET", "RAWER", "CANBY", "OSWEG", "BTG", "ROARK", "COUGA", "MALAY", "ONALS", "MCKEN", "SEA", "PAE", "AMEKE", "IWANY", "BEZOV", "EGRET", "ACORD", "HUH", "YVR"]},
+    "V230":{ "name":"V230", "fixes":["SHOEY", "ISIFU", "JEJZE", "SNS", "BASEC", "PANOS", "FIDDO", "PXN", "MENDO", "BLEAR", "CZQ", "NIVEE", "FRA", "CAINS", "RBRTS", "NIKOL", "MVA"]},
+    "V231":{ "name":"V231", "fixes":["BYI", "MENIN", "HOSUN", "LKT", "FIPFE", "FAXON", "WEDAK", "JENKI", "OCFOW", "NOHHA", "TUFFY", "MSO", "SULFY", "ARLEE", "EMIBE", "JESSY", "CHARL", "SKOTT", "ANGIL", "FCA"]},
+    "V232":{ "name":"V232", "fixes":["CXR", "BARLY", "HAGAR", "FKL", "PUNCO", "COOBE", "ETG", "WATSO", "MIP", "LYTEL", "BEERS", "HOPPS", "SBJ", "TYKES", "COL"]},
+    "V233":{ "name":"V233", "fixes":["SPI", "OBACO", "LASKK", "KENNS", "EWITT", "SAYBA", "RBS", "KENLA", "RODNY", "MAPPS", "OXI", "GSH", "SEWTO", "LFD", "ECKDO", "POSIE", "LAN", "CUTTY", "POMPE", "ELMME", "MOP", "JOMID", "CARGA", "GLR", "WOMOP", "DRIPE", "PLN"]},
+    "V234":{ "name":"V234", "fixes":["SJN", "BUREW", "STONY", "ABQ", "CYOTE", "CADVO", "RUINS", "ACH", "WIXIX", "DHT", "OXUTE", "BRAKR", "RILYO", "LBL", "FLACK", "KRIER", "BYWAY", "GABIE", "WUPNU", "HUT", "BURTO", "WAIVE", "FLOSS", "ANUGE", "EMP", "UDCOS", "ERXOL", "BUM", "ROFBE", "AUGIE", "ROACH", "LUYIR", "ZOPUD", "VIH", "DELMA", "GLASS", "NEWAT", "ENL"]},
+    "V235":{ "name":"V235", "fixes":["PGS", "MMM", "PHYLI", "JITKA", "JEZOB", "MATZO", "EHK", "CUSAK", "MLF", "BEVRR", "MUBNE", "ZIBRA", "DTA", "RUBOY", "PUCIT", "FRNZY", "REEKA", "FFU", "GRODI", "FBR", "OCS", "BORGG", "OILLY", "GIPEC", "DDY", "WAPAP", "ECS"]},
+    "V236":{ "name":"V236", "fixes":["CEVAR", "EMONT", "OGD"]},
+    "V237":{ "name":"V237", "fixes":["EED", "UNPAS", "CUTAD", "LYNSY", "BLD", "KIDDS", "LAS"]},
+    "V238":{ "name":"V238", "fixes":["MAP", "LENOX", "DELMA", "IMPER", "FONTI", "TOY"]},
+    "V239":{ "name":"V239", "fixes":["TBN", "TOMAT", "YAMBO", "BNTON", "HLV"]},
+    "V24":{ "name":"V24", "fixes":["ABR", "FIBDA", "CALAG", "WICKA", "ATY", "BUCCA", "RISLE", "MOLOW", "JOVIR", "RWF", "KUKGE", "ZELET", "ALMAY", "KASPR", "RST", "EMORE", "LEFTY", "FALAR", "DOURS", "WITOL", "LNR", "DALEY", "GLARS", "GENZU", "JVL", "LOCEN", "TIRRO", "BULLZ", "TEDDY", "KRENA", "FARMM", "UMUZI", "OBK", "EON", "KENLA", "YIXCI", "BOSSY", "BOSWL", "VAGES", "ATTIL", "POTES", "JAKKS", "JELLS", "ADVAY", "VHP"]},
+    "V240":{ "name":"V240", "fixes":["HRV", "MENTC", "PEARL", "MINNI", "DOGMA", "ELSIE", "ROMMY", "TOOTS", "SJI"]},
+    "V241":{ "name":"V241", "fixes":["SJI", "ZUGTI", "LOXLY", "BRATT", "PENSI", "INBRD", "ITNEW", "BAKOS", "CEW", "GALON", "HACKK", "DARED", "HOUND", "IVGIF", "RRS", "HAVSO", "BAIZE", "EUF", "OMAHO", "WESUV", "CSG", "GARDI", "LANGA", "PIZZO", "TIROE"]},
+    "V242":{ "name":"V242", "fixes":["INL", "YUPNU", "CIVLU", "JGTSC", "IB"]},
+    "V243":{ "name":"V243", "fixes":["CRG", "OHDEA", "EJIPE", "AYS", "UPTON", "LURGE", "DUMMY", "VNA", "SSONY", "PHYLL", "TOYOT", "POTAR", "PRATZ", "CANER", "LANGA", "LGC", "RAVOC", "HEFIN", "FELTO", "GORGO", "YAVUL", "METAE", "UZOVO", "GQO", "PALER", "FARAD", "MCMIN", "HARME", "GARVY", "LEJCO", "BWG"]},
+    "V244":{ "name":"V244", "fixes":["OAK", "SALAD", "ALTAM", "JANEY", "DARYL", "ECA", "WRAPS", "HABXU", "DUCKE", "NIKOL", "JABIM", "OAL", "WURIL", "ELFES", "TPH", "ILC", "MLF", "DETAN", "HAMET", "OMUCE", "HVE", "PIGSE", "ANIUM", "PAROX", "HERRM", "AGIME", "NADIN", "MTJ", "MEYRS", "HBU", "DUFEL", "SKOTI", "KANON", "RODDY", "FLOOD", "ACZES", "STANO", "FSHER", "PUB", "ORWAY", "TODDE", "WOSUR", "LAA", "WIZGE", "NARNE", "COFFE", "ZAMPO", "RANSO", "HYS", "ZISDA", "GLIDE", "HETAB", "SLN"]},
+    "V245":{ "name":"V245", "fixes":["AEX", "LARTO", "NIFTE", "HEZ", "CREEM", "BARNE", "WUDVI", "MHZ", "ECESU", "IGB", "UYSEF", "MINIM", "CAYAP", "LDK"]},
+    "V246":{ "name":"V246", "fixes":["JVL", "LUANN", "MADDY", "ILOBE", "DBQ", "CASSY", "UKN", "FALAR", "SHLGN", "ODI", "SAUCY", "MILTO", "STE"]},
+    "V247":{ "name":"V247", "fixes":["BFF", "KACTI", "AFWOX", "POKSY", "IIP", "AFYAB", "WAPAP", "CZI", "ONECI", "FOURS", "SHR", "ZAGHI", "SEXPE", "ARDMO", "BIL", "WIBMU", "PELJE", "BAXTA", "YOSWO", "HEXOL", "WAUTS", "FALDE", "ICUBI", "FAVOX", "HLN"]},
+    "V248":{ "name":"V248", "fixes":["SNS", "SARDO", "FIKDU", "BRALY", "YERGU", "PRB", "JEBNO", "REDDE", "AVE", "COREZ", "SCRAP", "EHF"]},
+    "V249":{ "name":"V249", "fixes":["RBV", "JERYY", "METRO", "SBJ", "SAX", "SHAFF", "CRANK", "FLOSI", "HELON", "WEETS", "FILPS", "PRNCE", "RIMBA", "DNY", "CODDI", "MILID", "COOES", "UCA"]},
+    "V25":{ "name":"V25", "fixes":["MZB", "REDIN", "PACIF", "MINOE", "ALBAS", "FERMY", "WILMA", "HERMO", "LAX", "MERMA", "EXERT", "VTU", "DEANO", "ZIQOR", "RZS", "WYNNR", "POZOE", "KIKII", "PRB", "LUCAB", "WIGGL", "HAGRO", "CASRA", "SNS", "MOVER", "SANTY", "SAPID", "OSI", "SFO", "SUTRO", "GOBBS", "STINS", "PYE", "FREES", "GETER", "LAPED", "GRENY", "RBL", "HOMAN", "ITMOR", "GARSA", "KAGYE", "MUREX", "LMT", "SPRAG", "FESOD", "OCTAD", "DSD", "HERBS", "YONKU", "CUPRI", "GASHE", "KUKTE", "JIREN", "LTJ", "YABLU", "GUBSE", "MUDLE", "YKM", "CIDOG", "ELN", "AYISO", "BEEHI", "EAT"]},
+    "V250":{ "name":"V250", "fixes":["ONL", "YAPUC", "HIVNO", "YKN", "JAKDI", "JILRO", "CUBEX", "CATID", "OTG", "CUDET", "YOPBU", "WAGIK", "TUPBU", "MKT"]},
+    "V251":{ "name":"V251", "fixes":["AXC", "HAMMO", "REGOY", "BEMEN", "CMI", "OCTOE", "BUBLE", "DNV", "STAKS", "VAGES", "BVT"]},
+    "V252":{ "name":"V252", "fixes":["AIRCO", "EHMAN", "FIXUS", "WELTI", "GEE", "RITCH", "GIBBE", "XUCCO", "VILCU", "MESTE", "CFB", "LATTY", "HUGIE", "ORSON", "RAGER", "HUO", "LEMOR", "COATE", "ARMMS", "HOPAT", "SLYNG", "JOKMI", "VANER", "LINER", "PLEXS", "KOPPS", "RBV", "COBUS", "DQO"]},
+    "V253":{ "name":"V253", "fixes":["LCU", "ROGET", "OYXOJ", "TWF", "LITKE", "SECAR", "UYEME", "YUWFE", "ALKAL", "CANEK", "BOI", "SALLA", "BANGS", "RAQXE", "DNJ", "KOVRY", "ZOSNO", "OXLEY", "MELLR", "PIYOL", "MQG", "WHELE", "PUW", "CISOV", "ATOXE", "HUNIB", "GEG"]},
+    "V254":{ "name":"V254", "fixes":["IIP", "TOOKE", "JUGIP", "GCC", "HITOS", "CISPU", "MLS", "JITAG", "GGW"]},
+    "V255":{ "name":"V255", "fixes":["GCK", "KUVVU", "TOKIE", "WAMIP", "HYS"]},
+    "V256":{ "name":"V256", "fixes":["TUL", "LOMAC", "FRAKS", "IDLUY", "PER", "REKOC", "HUT"]},
+    "V257":{ "name":"V257", "fixes":["PXR", "AVENT", "BANYO", "COYOT", "MAIER", "DRK", "IRODY", "KACEE", "NAVHO", "BISOP", "GCN", "DOZIT", "JALMA", "KACIR", "CIXAP", "HEGID", "BCE", "EYPUZ", "HURTU", "ENICE", "DETAN", "BICAN", "JULIK", "DTA", "WADOK", "LOLIC", "VERNE", "ENJAK", "STACO", "EMONT", "RIDEN", "MOINT", "NUBGE", "KREBS", "MLD", "BANNO", "PIH", "ROCCA", "TERRE", "DBS", "WEMKO", "DLN", "NUWLI", "DIVID", "CPN", "GLUES", "SCAAT", "KELTY", "RICHD", "SIEBE", "WOKEN", "TUCOK", "MSURY", "GTF", "PSHKN", "SHONK", "BELCA", "YOYNO", "HVR"]},
+    "V258":{ "name":"V258", "fixes":["HVQ", "SCRIB", "NUTTR", "BKW", "ZOOMS", "ROA", "DEWET", "JEXOV", "PIGGS", "ENTUK", "DAN"]},
+    "V259":{ "name":"V259", "fixes":["CRE", "KOOKE", "CLETA", "FLO", "COPEL", "WARNR", "CTF", "HUSTN", "MOPED", "BZM", "GOWBE", "COREX", "HOMEK", "HMV"]},
+    "V26":{ "name":"V26", "fixes":["HBU", "MEYRS", "MTJ", "PAGRE", "BRICK", "SPADA", "JNC", "RAYMN", "AWRAW", "HAPRA", "EKR", "STRIM", "CELIA", "NEDAE", "CKW", "ARFEJ", "CHOMP", "ALCOS", "DDY", "AFYAB", "SALON", "WILDA", "RULER", "RAP", "CRETO", "PHP", "CABKU", "PIR", "CHANS", "VAYLA", "DAKPE", "OPOJE", "HON", "ZOTBY", "GOLDS", "OBITT", "ASTOE", "CARIT", "GHENT", "JUNES", "RWF", "OSHOF", "BEEGR", "WULEP", "LYDIA", "FGT", "LDASH", "PRESS", "ELPAS", "UCEGA", "EAU", "VIYUR", "MAXMA", "EDGRR", "AUW", "WITEN", "CHURP", "WOVET", "GRB", "PRIME", "JAVAM", "NEROE", "YULNU", "WELKO", "RUMUE", "HIC", "TRUFA", "GIBER", "ORIEN", "LAN", "BAMBY", "SVM", "DXO", "CFRWG", "MUSCA", "GEMNI", "YYOUR", "DJB"]},
+    "V260":{ "name":"V260", "fixes":["HVQ", "MONTS", "GAULE", "LAFOR", "RNL", "VUTCU", "TILFO", "PEEBE", "CASTE", "ROA", "GOOZE", "HEMEV", "OTINE", "LYH", "LOSEC", "CONCO", "VOUCH", "SHEPS", "CRUMB", "FAK", "RIC", "HPW", "WAIKS", "FKN", "CVI"]},
+    "V261":{ "name":"V261", "fixes":["ICT", "KAKEL", "JUXON", "CEKIS", "MHK"]},
+    "V262":{ "name":"V262", "fixes":["PIA", "DULAP", "WETEV", "BDF", "MOTIF", "MINOK", "JOT"]},
+    "V263":{ "name":"V263", "fixes":["CNX", "BUDPY", "FOSED", "ENCIA", "MOPSE", "BUPNY", "ABQ", "FRIHO", "ZIASE", "HEGMI", "SAF", "FTI", "CELAV", "ADOZO", "CIM", "SAYKA", "FOGLE", "WATGU", "ECDOL", "TBE", "KOWTO", "LAA", "WEYYI", "ZANON", "HGO", "LIMEX", "KANDO", "AKO", "PIR", "HATKA", "LIVVA", "ALLOT", "ARJEL", "OPNAH", "ABR"]},
+    "V264":{ "name":"V264", "fixes":["LAX", "STABO", "AMTRA", "ITSME", "HOPUN", "COVIN", "POM", "RAVON", "REANS", "YUCCA", "TNP", "JEHLI", "PKE", "DRK", "JUWSO", "OATES", "HOXOL", "INW", "AVANS", "IRECU", "SJN", "ONM", "CNX", "PELCI", "TCC"]},
+    "V265":{ "name":"V265", "fixes":["KRANT", "BELTS", "CUTOP", "CLEAT", "DATED", "YANNI", "EMI", "BINNS", "PIFER", "KOLBY", "HAR", "PYCAT", "MCMAN", "RASHE", "PSB", "ETG", "CLERO", "BFD", "ATAME", "JHW", "DKK", "MWNNV", "THORL"]},
+    "V266":{ "name":"V266", "fixes":["ELW", "PELZE", "WANOL", "DUNKE", "SPA", "GSO", "REIDE", "YANCE", "SBV", "HARVY", "LVL", "GEPKE", "MAZON", "FKN", "DRONE", "SUNNS", "ECG", "OCSIP", "NORTN", "RBX"]},
+    "V267":{ "name":"V267", "fixes":["DHP", "PIONN", "BRIKL", "ENVER", "HEDLY", "PHK", "DIDDY", "BAIRN", "ODDEL", "SABOT", "ORL", "PAOLA", "KIZER", "WORMS", "GUANO", "BARBS", "ROYES", "MATEO", "BRADO", "CRG", "HABLE", "BAXLY", "NEDRE", "AILEY", "DBN", "HEPUT", "HADOC", "BEYLO", "TRAPI", "CORVI", "PENFI", "AHN", "IRMOS", "CORCE", "TALLE", "HRS", "FORMS", "KNITS", "VXV"]},
+    "V268":{ "name":"V268", "fixes":["NESTO", "PLEEZ", "NIDGY", "IHD", "HGR", "KEMAR", "EMI", "SLOAF", "BAL", "SWANN", "GOLDA", "BROSS", "ENO", "LEEAH", "AZXEW", "AVALO", "BRIGS", "HARBO", "DRIFT", "MANTA", "PLUME", "SHERL", "DUNEE", "KOPPY", "SARDI", "RICED", "BEDYA", "SHLEP", "BEADS", "HTO", "JORDN", "SEY", "MINNK", "AVONN", "INNDY", "BURDY", "KYLES", "TONNI", "WIMPY", "EXALT", "LBSTA", "CEKAY", "SCOGS", "MESHL", "SAPPE", "AUG"]},
+    "V269":{ "name":"V269", "fixes":["ELY", "FAPGI", "SPATS", "LWL", "JACKS", "YUSUN", "IXUVE", "TWF", "APGUH", "BYI", "JALIK", "COLAY", "YERUP", "PIH", "JATTS", "YOYYU", "WABUD", "LKT", "DNJ", "NEYGI", "HOVEL", "PIYID", "FONNA", "ILR", "NAXZY", "FUFQO", "SAKKO", "DSD", "EENIE", "MANTE", "MOBIL", "COBUR", "EUG"]},
+    "V27":{ "name":"V27", "fixes":["MZB", "REDIN", "PACIF", "AVOLS", "SXC", "PAROL", "DOYLE", "EXERT", "VTU", "HENER", "DEANO", "KWANG", "GOLET", "GVO", "AFOXY", "ORCUT", "FABEG", "AVILA", "MQO", "FRAMS", "CALIS", "BLANC", "WONGO", "BSR", "CARME", "PEBBS", "PENNI", "SAGUE", "SHOEY", "EUGEN", "TAILS", "HADLY", "SEEMS", "STINS", "PYE", "FREES", "GETER", "CABEX", "ENI", "MERRI", "FLUEN", "EBBLS", "HIDAK", "OLRIO", "TUNGS", "FOT", "SEGVE", "HEXIT", "HOCUT", "TRIAL", "WHEEL", "CULDU", "OLJEK", "ZIKNO", "CHIDE", "CEC", "KEVZU", "WIPOG", "ROOTY", "LEDGE", "LUPCI", "OVLEE", "OLINE", "OTH", "YUPVU", "GAMMA", "BOSVE", "JANAS", "ONP", "COKLA", "CUTEL", "DANES", "ULKAW", "FETUJ", "ZIGPI", "KULOA", "AST", "PULYI", "PUGIC", "WAVLU", "HQM", "OZALU", "ULESS", "SANDR", "WONKU", "ZOLGI", "CARRO", "HOOME", "SEA"]},
+    "V270":{ "name":"V270", "fixes":["ERI", "WABOR", "HERMA", "JHW", "VAIRS", "ELZ", "WOMAN", "ULW", "CFB", "DNY", "PETER", "TUSON", "AGNEZ", "ACOVE", "ATHOS", "HIDAL", "STELA", "CTR", "FAIDS", "SPENO", "GLYDE", "BOS"]},
+    "V271":{ "name":"V271", "fixes":["MKG", "WELKO", "FOXEX", "MBL", "WINEP", "ESC"]},
+    "V272":{ "name":"V272", "fixes":["DHT", "OWUKU", "ZETIB", "OVPUH", "OVUGY", "BGD", "OVSAW", "OVOKE", "BROKE", "BRISC", "BFV", "LIONS", "IRW", "MINGG", "HOLLE", "AKUME", "CALNA", "MLC", "ELKVI", "KLEEN", "FSM"]},
+    "V273":{ "name":"V273", "fixes":["FALLZ", "HAAYS", "HUO", "RAGER", "WECOL", "HNK", "OXFOR", "PITCH", "GGT", "POMPY", "FATUP", "SYR"]},
+    "V274":{ "name":"V274", "fixes":["PMM", "SAMME", "BLBBY", "VIO", "SARAN", "ORIEN", "PALOW", "POMPE", "INDEX", "MBS"]},
+    "V275":{ "name":"V275", "fixes":["CVG", "NEATS", "IZZOF", "CAMMS", "FRAAM", "DQN", "CUBOB", "JINAK", "KLINE"]},
+    "V276":{ "name":"V276", "fixes":["RASHE", "HERDA", "MORTO", "RAV", "VAYRE", "OUTLT", "DUMMR", "FLOAT", "KATVE", "HIKES", "ARD", "RBV", "CASVI", "DIXIE", "ZIGGI", "GAMBY", "MANTA", "PREPI"]},
+    "V277":{ "name":"V277", "fixes":["ROD", "BUTYN", "NADIR", "OSBER", "FWA", "RABBT", "BAGEL", "AYUYI", "LINGS", "JJANN", "HAPUR", "ELX"]},
+    "V278":{ "name":"V278", "fixes":["TXO", "HURIK", "PVW", "FLOYD", "GTH", "NIFDE", "POSTE", "KARYN", "UKW", "ZUMKI", "BYP", "OKUCI", "MONTE", "RAKOC", "PRX", "LENYI", "GIGVE", "TXK", "WEEBR", "WARLO", "LOCUS", "HAMPT", "MON", "POYNI", "ZIRUL", "OZIGE", "EDOME", "IXDIL", "GLH", "CECAR", "LAARI", "SQS", "TOMLN", "NEEON", "CLOUT", "HANOP", "IGB", "UYSEF", "MINIM", "BESOM", "FIBER", "VUZ"]},
+    "V279":{ "name":"V279", "fixes":["GUNNE", "ESSIE", "OJACE", "YOGGI", "FBC"]},
+    "V28":{ "name":"V28", "fixes":["OAK", "SALAD", "ALTAM", "HAIRE", "ORANG", "LIN", "KATSO", "SPOOK", "RICHY", "HUYJO", "FMG"]},
+    "V280":{ "name":"V280", "fixes":["CJS", "ELP", "WHOLE", "CORUD", "PIO", "JAKKY", "HOPET", "CME", "FRAIZ", "CURIB", "DEBRA", "HIMRO", "KEBYO", "TXO", "ZULAK", "YACUL", "PNH", "UKDEW", "BROKE", "HINOD", "MMB", "RICBU", "CARKO", "WIPET", "HUT", "BUHLS", "STONS", "WILSY", "HEYDN", "DIETS", "TOP"]},
+    "V281":{ "name":"V281", "fixes":["PSC", "BAKCA", "OZONI", "OLFUS", "ODECE", "MWH"]},
+    "V282":{ "name":"V282", "fixes":["SLK", "BUGSY", "FAWNS"]},
+    "V283":{ "name":"V283", "fixes":["SLI", "JOGIT", "KAYOH", "FRETS", "HDF", "ACINS", "DAWNA", "RESOR", "LUCER", "BULGY", "HEC", "DANBY", "WHIGG", "WOPMA", "BOACH", "CRESO", "DICSA", "BLD"]},
+    "V284":{ "name":"V284", "fixes":["SIE", "AZXEW", "VCN"]},
+    "V285":{ "name":"V285", "fixes":["VHP", "ZIPPY", "EDMEW", "HUBOP", "PASEW", "OKK", "CLEFT", "WATSN", "GSH", "VENTU", "RESGY", "AZO", "BOHRR", "VIO", "WALKS", "CLOCK", "KENTS", "HIC", "FARUB", "MBL", "CEMOB", "TVC"]},
+    "V286":{ "name":"V286", "fixes":["EKN", "DERIN", "TEAKK", "AANTS", "CSN", "FLUKY", "ANTNY", "BRV", "GRUBY", "ZUNAR", "TAPPA", "FAGED", "CORET", "STEIN", "GWYNN", "CCV"]},
+    "V287":{ "name":"V287", "fixes":["FJS", "GRENA", "EHPUG", "HIVEG", "FOBRO", "KLAMA", "OED", "AZURE", "KOLER", "CAMAS", "DEROY", "OTH", "ZUBOR", "RARES", "TICKY", "CRAAF", "MCCOY", "UBG", "ENDZZ", "BTG", "ROARK", "COUGA", "MALAY", "TONNO", "OLM", "CARRO", "JUVGA", "ARPEE", "LOFAL", "PAE", "CVV"]},
+    "V288":{ "name":"V288", "fixes":["LCU", "SWITZ", "BEARR", "CORIN", "NIWTE", "FBR"]},
+    "V289":{ "name":"V289", "fixes":["BPT", "KIELL", "HONEE", "LFK", "AFRUH", "ARMOR", "PIPES", "GGG", "NEVER", "LASSA", "DOGGE", "TXK", "CUGSO", "PROVO", "UMPIR", "BATEZ", "SISCO", "UVUZU", "FSM", "FIGGS", "MULBY", "CASKS", "MADES", "MARBI", "HRO", "DGD", "MODNY", "MUPIE", "GOBEY", "PEKLE", "BACTA", "ZOREB", "VIH"]},
+    "V29":{ "name":"V29", "fixes":["SWL", "SBY", "EZIZI", "LAFLN", "COSHA", "ENO", "BLARE", "DQO", "MXE", "PTW", "HIKES", "ETX", "SLATT", "WHITT", "LVZ", "LECOR", "SCOFF", "WONGS", "NOSEE", "CFB", "CORTA", "VESPE", "TUMPS", "SYR", "PAGER", "BRUIN", "ART", "WILRD", "LETUS", "MSS"]},
+    "V290":{ "name":"V290", "fixes":["RNL", "FRETT", "NATTS", "BOOME", "OBEPE", "MOL", "ROMAN", "BRAIL", "ARVON", "FAK", "TYI", "KENIR", "WEMOX", "PUNGO"]},
+    "V291":{ "name":"V291", "fixes":["HOB", "WOKAM", "HEBIX", "BOZDA", "CME", "DUPAL", "BUCZO", "CNX", "CADVO", "CYOTE", "ABQ", "HEXEM", "AROYO", "LORAT", "EMUXE", "BLINI", "GUP", "DODAH", "GRINT", "FORAN", "INW", "TAWNE", "FLG", "KACEE", "PGS"]},
+    "V292":{ "name":"V292", "fixes":["HNK", "RIMBA", "SAGES", "WIGAN", "BOWAN", "MOBBS", "SASHA", "TOMES", "BAF", "GLYDE", "BOS"]},
+    "V293":{ "name":"V293", "fixes":["GCN", "KLIFF", "PGA", "ACOSI", "CABER", "BCE", "EHK", "BERYL", "ILC", "DOTME", "EPUHE", "ELY", "HARRV", "INGOL", "JEBEG", "YANKU", "SIKEE", "DUCAY", "BQU", "ARAYI", "YOBBO", "YIKUK", "SAMAN", "YIRUR", "TWF", "WALIL", "GOODE", "TORIN", "DERSO", "SIDZY", "PEPUC", "DNJ"]},
+    "V294":{ "name":"V294", "fixes":["DSM", "SINGR", "NASAL", "RIDCO", "GUERN", "CID", "SOLUM", "BILOX", "CVA"]},
+    "V295":{ "name":"V295", "fixes":["VKZ", "KAINS", "QEPRO", "KUCEP", "HILEY", "LONNI", "HEATT", "LIDRE", "BLUFI", "STOOP", "TRV", "SMERE", "BAIRN", "ODDEL", "SABOT", "ORL", "MAMBO", "LEESE", "SHIMM", "CUSAB", "ALADN", "OCF", "PERSE", "WILON", "CTY", "CILLA", "CODYS", "OLUGY", "SZW"]},
+    "V296":{ "name":"V296", "fixes":["HUSTN", "CLINE", "LILLS", "RAEFO", "LORRY", "FAY", "GANDS", "ZUNIT", "RAPVY", "YOAST", "URRIE", "ILM"]},
+    "V297":{ "name":"V297", "fixes":["JST", "TALLS", "EARED", "VOLAN", "CAPEL", "CAMES", "SEING", "ACO", "CANCR", "STUKL", "OTOCE", "CAMGU", "LLEEO"]},
+    "V298":{ "name":"V298", "fixes":["SEA", "VAMPS", "BANDR", "BEEZR", "THICK", "PERTT", "DATVE", "SELAH", "YKM", "SUNED", "BENTY", "PSC", "GAWWY", "GINLE", "OLODE", "PDT", "CABAN", "EYUYA", "HAGRD", "IBEAM", "SUMOQ", "DNJ", "YOWLS", "DBS", "SABAT", "LAMON", "RELAE", "QUIRT", "NALSI", "DNW", "BOY", "HIKOX", "DDY", "CESPI", "CHANG", "JENNE", "GCC"]},
+    "V299":{ "name":"V299", "fixes":["LAX", "SADDE", "VTU", "ACRAT", "FIM", "ZUWNI", "WOTOK", "GMN"]},
+    "V3":{ "name":"V3", "fixes":["EYW", "BIPIN", "JANKA", "GUCEL", "DROWN", "TWNNS", "MNATE", "DHP", "FLL", "PBI", "MORGA", "SMUGS", "WUBUR", "TRV", "MLBSO", "VALKA", "MLB", "INDIA", "TICCO", "MALET", "FORNI", "OAKIE", "SMYRA", "MIKBE", "OMN", "SEBAG", "VEDRA", "LLIPS", "TOMDY", "SSI", "BROUN", "HARPS", "WOHPY", "KELER", "SAV", "REBUS", "OWENS", "STOAS", "SACKS", "VAN", "MADLY", "PEGIE", "DUTEE", "FLO", "IDEBE", "DUNGY", "TOWEY", "TESYU", "SDZ", "OCHOC", "MOATS", "RDU", "ESTMA", "STEMM", "YITUP", "OXFRD", "HARVY", "DOCMO", "NUTTS", "CARML", "FAK", "GVE", "WITTO", "LURAY", "KERRE", "AANTS", "HOAGE", "MRB", "RUANE", "EMI", "VINNY", "KITHE", "GLOMO", "MXE", "FROSE", "MUDNE", "DASDE", "MAZIE", "HARRS", "BIGGY", "SBJ", "PIYIN", "FALLZ", "NYACK", "DOSWL", "CMK", "RACEY", "SORRY", "YALER", "HFD", "JEWIT", "FOSTY", "HEFTY", "WOONS", "MILIS", "BOS", "REVER", "WAXEN", "WITCH", "PSM", "YUKES", "SATAN", "PARSO", "LABEL", "SERPA", "NOLLI", "QUIPS", "ROLAF", "AUG", "VEEDA", "YOSTT", "WUGES", "BGR", "NIELD", "LAUDS", "PRENT", "HUL", "PQI", "JURDO", "LABRE", "YQB"]},
+    "V30":{ "name":"V30", "fixes":["BAE", "SQUIB", "SALES", "PMM", "BRONZ", "LEROY", "LFD", "HIRED", "RANDL", "VWV", "DJB", "WOMGO", "ACO", "SEING", "CAMES", "CAPEL", "VOLAN", "PEREA", "CIP", "DBEAM", "LATEC", "PSB", "SEG", "PINNA", "ETX", "TROXL", "BOPLY", "LANNA", "SBJ"]},
+    "V300":{ "name":"V300", "fixes":["YQT", "KJNGG", "AVALE", "SRADE", "CATGA", "SSM", "ALVUS", "RIBIR", "NAASH", "MKPDG", "APNEL", "YVV", "YSC", "RNSLL", "CAMPO", "WRAPT", "MLT", "PRENT", "BBPVK"]},
+    "V301":{ "name":"V301", "fixes":["PXN", "KARNN", "BORED", "BUSHY", "SUNOL", "OAK", "COMMO", "MICRA", "PYE", "STS", "KLOGE", "RUMSY", "ILA"]},
+    "V302":{ "name":"V302", "fixes":["AUG", "RAZZR", "ANCOR"]},
+    "V303":{ "name":"V303", "fixes":["HOT", "BLURB", "BLIMP", "IXEYA", "FSM"]},
+    "V304":{ "name":"V304", "fixes":["PNH", "JUNVE", "JOXEP", "BGD", "LBL", "YUNUP", "UPIRE", "LAA"]},
+    "V305":{ "name":"V305", "fixes":["ELD", "LOCUS", "BUNNS", "HERID", "LIT", "BRAUM", "DUMPI", "UKORE", "JEBEP", "ARG", "HARIB", "VILUC", "MAW", "NAPTY", "SNOWD", "LAKKR", "CNG", "ROOKE", "WESON", "PXV", "AUGUS", "WEGEE", "EYTEJ", "OOM", "ZARHO", "VHP", "WELDO", "OKK"]},
+    "V306":{ "name":"V306", "fixes":["JCT", "CORVY", "FLIES", "AMUSE", "CWK", "HOOKK", "ILEXY", "JAYJO", "BLUBL", "COUTH", "TNV", "GOMER", "ZMSKL", "CLEEP", "DAS", "KIELL", "SILBE", "KUUPR", "OFERS", "STRUT", "LCH"]},
+    "V307":{ "name":"V307", "fixes":["HRO", "PPAMM", "HARKS", "SUEEY", "WALTN", "EOS", "NERNE", "OSW", "KUBKY", "CNU", "FOWNE", "EMP", "HEYDN", "ALMAS", "LEGAL", "ZINUR", "PWE", "IPALY", "OVR", "MITZY", "DECKA", "SUX"]},
+    "V308":{ "name":"V308", "fixes":["OTT", "BILIT", "CHOPS", "LAFLN", "ATR", "TESTA", "SIE", "AVALO", "BRIGS", "HARBO", "DRIFT", "MANTA", "PLUME", "SHERL", "DUNEE", "KOPPY", "SARDI", "RICED", "BEDYA", "SHLEP", "BEADS", "HTO", "BOROS", "GON", "ORW"]},
+    "V309":{ "name":"V309", "fixes":["HVQ", "KETTA", "JULEA", "RANDE", "BURGS", "KIVGE", "AIR"]},
+    "V31":{ "name":"V31", "fixes":["PXT", "ARUYE", "OTT", "BAL", "MEHAN", "SKILS", "TAFFI", "SHILO", "VINNY", "SUEDE", "GRAMO", "HAR", "MORTO", "SEG", "WATSO", "FQM", "GUYED", "ULW", "GIBBE", "BEEPS", "FAULT", "ROC", "AIRCO"]},
+    "V310":{ "name":"V310", "fixes":["IIU", "MAUDD", "DARBY", "UNCKL", "DOLLY", "LOZ", "JARAM", "ROSAR", "YUMMY", "HMV", "STAIN", "MULBE", "BURCH", "GSO", "KIMES", "HOJPA", "SNOWS", "CHAPL", "RDU", "ZEBUL", "EXULE", "FEBEL", "TYI", "ECG"]},
+    "V311":{ "name":"V311", "fixes":["HCH", "KIRCH", "DUBBS", "MADOL", "USIZI", "NELLO", "AWSON", "CORCE", "ELW", "IVANS", "GRD", "CHATT", "LEDAS", "CAE", "ERNIE", "SHIPY", "BOWMA", "SACKS", "DORCE", "LAMKE", "GISTS", "MEGEE", "CHS"]},
+    "V312":{ "name":"V312", "fixes":["POLLA", "PALEO", "GOLDA", "DEWIR", "TACKS", "UKIEY", "CANUV", "OOD", "ALBEK", "INNEZ", "DITCH", "CYN", "JIMEE", "FALON", "WINKK", "DRIFT", "PREPI"]},
+    "V313":{ "name":"V313", "fixes":["MAW", "TAXOE", "AVOTE", "CGI", "ALING", "GENTS", "DEVER", "ZORAL", "ENL", "CORKI", "AQUAS", "AXC", "EWITT", "THEME", "COOKS", "PNT"]},
+    "V314":{ "name":"V314", "fixes":["YQB", "NALRU", "ATENE", "PATTA", "MLT"]},
+    "V315":{ "name":"V315", "fixes":["PRX", "PGO"]},
+    "V316":{ "name":"V316", "fixes":["IWD", "COTMO", "SAW", "YEXJO", "UZMEF", "ERY", "WUYFO", "HITAL", "WALDI", "SSM", "YEL", "YSB"]},
+    "V317":{ "name":"V317", "fixes":["MZB", "PGY", "JONDA", "IPL"]},
+    "V318":{ "name":"V318", "fixes":["YQB", "PINTE", "HUL", "SBGSK", "MOWND"]},
+    "V319":{ "name":"V319", "fixes":["BOY", "ZURNA", "RLY", "ALVIL", "CRANY", "COD"]},
+    "V32":{ "name":"V32", "fixes":["FMG", "OHOSO", "HZN", "LLC", "ZUSRU", "FESKO", "WIKLO", "BAM", "OLGAA", "BQU", "SPATS", "UHEPI", "BVL", "ZONSU", "BAGGI", "CEVAR", "YADDY", "STACO", "WEGET", "SALTA", "TCH", "COOLI", "EXILE", "FBR"]},
+    "V320":{ "name":"V320", "fixes":["PLN", "LORIW", "IROTO", "ADENO", "TIDDU", "SKIPR", "TVC", "ZOLOX", "ICADA", "MOP", "MBS"]},
+    "V321":{ "name":"V321", "fixes":["PZD", "KUTVE", "DUVAT", "LUMPP", "PREST", "CSG", "JALVO", "UKAVE", "STUKY", "LGC", "RAVOC", "HEFIN", "JAMUD", "HOKES", "GAD", "BOAZE", "ALBER", "OWENT", "RQZ", "HATAS", "VOYUD", "JEKBA", "ATWUS", "KUXYI", "SYI", "PECON", "OKENE", "CENOP", "GRILL", "LVT"]},
+    "V322":{ "name":"V322", "fixes":["CON", "YECKA", "GRUMP", "LAROE", "NOTTY", "WYLIE", "JOBBY", "BUKER", "BML", "RNPSB", "YSC"]},
+    "V323":{ "name":"V323", "fixes":["MGM", "FITTZ", "PEECH", "KOMER", "EUF", "RENFO", "PREST", "WILMS", "POTAR", "BYROE", "MCN", "OTPUQ", "JUDRY", "SMARR", "NALIZ", "HUSKY"]},
+    "V324":{ "name":"V324", "fixes":["GCC", "DEBBI", "CZI", "CHAPY", "RLY"]},
+    "V325":{ "name":"V325", "fixes":["CAE", "BLANE", "GOLFR", "VESTO", "AHN", "CONLY", "GOGBE", "WOMAC", "LOGEN", "DALAS", "CARAN", "FELTO", "MAYES", "GAD", "SNEAR", "JOSEP", "FEWER", "KAZDU", "MASHA", "JUVLO", "MSL"]},
+    "V326":{ "name":"V326", "fixes":["FIM", "GINNA", "SUANA", "CANOG", "VNY"]},
+    "V327":{ "name":"V327", "fixes":["PXR", "KNOBB", "RADOM", "ZCARR", "FERER", "MINGY", "OATES", "FLG"]},
+    "V328":{ "name":"V328", "fixes":["JAC", "TUVOC", "IDECA", "BPI", "SEYTO", "FETLI", "OCS", "CEBAL", "SNAKY", "CELIA", "MEKWY", "HUPEG", "CHE", "EGFAX", "HABRO", "SBURG", "TILLI", "GUVYU", "RLG", "DOBEE", "SKEED", "POWDR", "DVV"]},
+    "V33":{ "name":"V33", "fixes":["HCM", "MODEL", "FAGED", "COLIN", "WHINO", "JUDED", "DAILY", "OTT", "BAL", "MEHAN", "SKILS", "TAFFI", "SHILO", "VINNY", "SUEDE", "GRAMO", "HAR", "PYCAT", "MCMAN", "RASHE", "PSB", "ETG", "CLERO", "BFD", "VAIRS", "BUF"]},
+    "V330":{ "name":"V330", "fixes":["ILR", "GAYTE", "NOFFE", "CADKI", "BOYCA", "BOI", "CANEK", "ALKAL", "TORIN", "KINZE", "IDA", "OSITY", "LUDIC", "PIINE", "JAC", "DNW", "NEEDS", "ROWEY", "ARUXY", "RIW", "JUMKO", "DDY"]},
+    "V331":{ "name":"V331", "fixes":["AZQ", "ECB"]},
+    "V332":{ "name":"V332", "fixes":["FRA", "HNW", "COLOM", "MRGGO", "DURHA", "SATNE", "RBL"]},
+    "V333":{ "name":"V333", "fixes":["DALAS", "ERLIN", "RMG", "JIXGU", "GQO", "BOOPS", "HCH", "JELLO", "WNSOR", "DOLLY", "REILY", "HYK"]},
+    "V334":{ "name":"V334", "fixes":["SJC", "SUNOL", "ALTAM", "OAKEY", "VISTO", "SAC"]},
+    "V335":{ "name":"V335", "fixes":["STL", "MERAM", "IMPER", "ARNOL", "GLASS", "NIKEL", "DEVER", "MWA"]},
+    "V336":{ "name":"V336", "fixes":["ELN", "ZAXUL", "QUINT", "COYYA", "EPH"]},
+    "V338":{ "name":"V338", "fixes":["LIN", "MUREQ", "HNW", "SWR"]},
+    "V339":{ "name":"V339", "fixes":["AZQ", "KAVCO", "TRENT", "MASSE", "SPROW", "FLM"]},
+    "V34":{ "name":"V34", "fixes":["ROC", "FAULT", "BEEPS", "PTAKI", "HNK", "RIMBA", "PRNCE", "FILPS", "WEETS", "PWL", "MOONI", "ZATMI", "SORRY", "SEALL", "MAD", "CREAM", "BOROS", "GARRD", "SUFOK", "SEY", "NEWBE", "BENNT", "ACK"]},
+    "V340":{ "name":"V340", "fixes":["BEARZ", "HALIE", "AZUMO", "OXI", "SELOE", "CUDRU", "FWA", "ZULUG", "DEBAR", "ARBAS", "RID"]},
+    "V341":{ "name":"V341", "fixes":["CID", "ANOSA", "DBQ", "JIJLU", "BAULK", "DALEY", "THEBO", "MSN", "RANDO", "DOYAG", "BADAN", "OSH", "GRB", "WARWF", "MNM", "HAVEL", "IMT", "SAW", "PEVXI", "CMX"]},
+    "V343":{ "name":"V343", "fixes":["DBS", "PUFFS", "WAIDE", "QUERY", "JOXIT", "RANEY", "WOMET", "GATEY", "BZN", "THESE", "SUZZY", "GUSIE", "EVVER"]},
+    "V344":{ "name":"V344", "fixes":["DPR", "CALOG", "UNIBY", "HEXID", "ABR", "OPLOW", "OPILY", "EVUKY", "DAYAV", "FAR"]},
+    "V345":{ "name":"V345", "fixes":["DLL", "HURST", "MILTO", "FALEN", "RUYBO", "EAU", "THATS", "HOMLO", "HYR"]},
+    "V346":{ "name":"V346", "fixes":["VLV", "BBYKC", "MOTOR", "ZANAK", "ROCOW", "MLT"]},
+    "V347":{ "name":"V347", "fixes":["LOZ", "SALTZ", "HCH"]},
+    "V348":{ "name":"V348", "fixes":["YQT", "GRIBY", "CWSKQ", "WAGGO", "KJSCR", "KJSTL", "SSM", "BEPUP"]},
+    "V349":{ "name":"V349", "fixes":["HUH", "COGLE"]},
+    "V35":{ "name":"V35", "fixes":["DHP", "CURVE", "WORPP", "DEEDS", "CORFU", "RSW", "ERRIN", "CEXAN", "CHARO", "SABEE", "MURDO", "PAIRS", "CARIR", "PIE", "DONHU", "ENDED", "KAJYE", "CEDDI", "CTY", "GEF", "YALMI", "HARKE", "SALER", "PZD", "DESKS", "CAPAC", "BAVCA", "LILLY", "FRAUD", "BOSAY", "PHYLL", "METER", "MCN", "SINCA", "GLOSS", "MADDI", "JOTNO", "DACHA", "AHN", "JOSPI", "BOWMN", "HARTI", "ELW", "ELLID", "PEDAL", "CLEVA", "DOODD", "TUXDO", "SUG", "BUSIC", "ROANS", "HMV", "GZG", "ZOMAD", "STACY", "SLINK", "MACET", "DIPUH", "HVQ", "GLAZE", "WARDO", "CARLA", "BENZO", "CKB", "MGW", "PSB", "BLAZE", "SFK", "WUDUL", "ULW", "XUCCO", "VAFKU", "PTAKI", "SCIPO", "SYR"]},
+    "V350":{ "name":"V350", "fixes":["LBL", "VARNR", "KUHCU", "ICT", "NUTME", "OBDAW", "CNU"]},
+    "V352":{ "name":"V352", "fixes":["VLV", "DCDGG", "PATTA", "HUL", "SBCDC"]},
+    "V353":{ "name":"V353", "fixes":["JXN", "HAVEN", "QUBEE", "FNT"]},
+    "V354":{ "name":"V354", "fixes":["IRW", "OVAYE", "TRUMP", "GULLI", "PER", "OBDAW", "UBWIK", "EMP"]},
+    "V355":{ "name":"V355", "fixes":["UKW", "DOPEY", "HUNKI", "SPS"]},
+    "V356":{ "name":"V356", "fixes":["DBL", "FISTR", "FIDLE", "DOBEE", "ELORE", "DVV"]},
+    "V357":{ "name":"V357", "fixes":["LKV", "NIDIC", "ILR", "POTSY", "OXVEN", "BKE", "NUDEQ", "WOLIP", "IBEAM", "TOLGA", "ALW", "BACUN", "WATSY", "UPBOB", "MWH", "QUINT", "EAT"]},
+    "V358":{ "name":"V358", "fixes":["SAT", "GUADA", "STV", "FLIES", "FRUGG", "MOGWI", "AGJ", "SONET", "WAKMO", "ACT"]},
+    "V359":{ "name":"V359", "fixes":["NLD", "LRD"]},
+    "V36":{ "name":"V36", "fixes":["YQT", "YXZ", "SSM", "YEL", "BUF", "DALEE", "BURST", "HORNE", "THINK", "ULW", "SAYRE", "TIVUC", "OKZUS", "DOMVY", "TYYLR", "HAWLY", "HOPCE", "NEION"]},
+    "V360":{ "name":"V360", "fixes":["SSM", "WALAC"]},
+    "V361":{ "name":"V361", "fixes":["RSK", "MARKE", "UNLAP", "SCRUB", "LYZZA", "MTJ", "ICIES", "GEJYU", "DIRDY", "PITMN", "DBL", "VAILE", "RRIVR", "KIMBL", "FOTTY", "RLG", "ALLAN", "BARGR", "CYS"]},
+    "V362":{ "name":"V362", "fixes":["SSI", "WIGID", "BERTT", "HABLE", "AMG", "NIYIB", "SEYBO", "CENVA", "VNA", "MCN"]},
+    "V363":{ "name":"V363", "fixes":["MZB", "CARIF", "HURSI", "OORAH", "OFREE", "DANAH", "ELB", "WOKRO", "JOGIT", "POXKU", "PRADO", "BAYJY", "POM"]},
+    "V364":{ "name":"V364", "fixes":["LINCO", "SUG", "WEAKS", "UNICO", "HMV"]},
+    "V365":{ "name":"V365", "fixes":["BYI", "ACFIJ", "JATTS", "ZELOR", "ROCCA", "IDA", "RIGBY", "SABAT", "LVM", "ZUBLI", "BZN", "MENAR", "GODFE", "SWEDD", "CUSRI", "HLN", "USOBE", "KOTLE", "CUSDA", "WOKEN", "ROSOE", "SHIMY", "CHOTE", "PENRY", "WELUR", "CTB"]},
+    "V366":{ "name":"V366", "fixes":["HGO", "CONAL", "QUAIL", "JEFEL", "AVNEW", "HUNTN", "FQF"]},
+    "V367":{ "name":"V367", "fixes":["INL", "JGRLN", "CUTTL", "YXL"]},
+    "V368":{ "name":"V368", "fixes":["ALS", "RODDS", "WAPRE", "BRAZO", "MANUL", "TURLY", "RSK"]},
+    "V369":{ "name":"V369", "fixes":["TNV", "JUDDY", "HOMRN", "SUXOE", "GNL", "DARTZ", "TTT"]},
+    "V37":{ "name":"V37", "fixes":["CRG", "CARVL", "SSI", "BROUN", "HARPS", "WOHPY", "KELER", "SAV", "TILLS", "WIXON", "ALD", "NORMS", "SALLY", "CAE", "BEFTY", "BLOTS", "GREAT", "RICHE", "ZUKUR", "CIBOB", "CLT", "MOPED", "OWALT", "JOTTA", "MEGXE", "DOILY", "PSK", "ZOOMS", "PEEBE", "FRETT", "OAKLE", "HAWKI", "EKN", "CKB", "METZE", "TEDDS", "AKSAR", "CETPU", "EWC", "MERCY", "HAGAR", "ERI", "FOWEL", "JARVS"]},
+    "V370":{ "name":"V370", "fixes":["LAX", "DODGR", "LAHAB", "PRADO", "WISUP", "PDZ", "EDITS", "SETER", "BANDS", "GARNE", "PSP", "STOWN", "TNP"]},
+    "V371":{ "name":"V371", "fixes":["BVT", "MONON", "DENAM", "OXI"]},
+    "V372":{ "name":"V372", "fixes":["SLI", "JOGIT", "KAYOH", "FRETS", "HDF", "BANDS", "AHLEX", "GARNE", "PSP", "CONES", "BLH"]},
+    "V373":{ "name":"V373", "fixes":["GSO", "UZUDO", "EETEE", "SDZ"]},
+    "V374":{ "name":"V374", "fixes":["CFB", "QTIPP", "MSLIN", "CRANK", "GAYEL", "VOLLU", "MICAL", "CMK", "DENNA", "BETHA", "CREAM", "FLIBB", "YODER", "KURTY", "GON", "WACKY", "MINNK", "FALMA", "MVY"]},
+    "V375":{ "name":"V375", "fixes":["ROA", "FOSER", "PROSE", "RADIA", "CLYFF", "ROMAN", "KENNI", "GVE", "MAZKO", "HANEY", "FLUKY"]},
+    "V376":{ "name":"V376", "fixes":["RIC", "EPICS", "DEGAY", "BEUGA", "PEGBY", "JIMBE", "GRUBY", "OJAAY", "SABBI", "IRONS"]},
+    "V377":{ "name":"V377", "fixes":["MOL", "TTUMS", "TEAKK", "ESL", "ELGEE", "TOMAC", "HGR", "SCAPE", "HAR"]},
+    "V378":{ "name":"V378", "fixes":["BAL", "ENSUE", "DLUCA", "CLIPR", "TRISH", "BELAY", "TROYZ", "NUGGY", "MXE"]},
+    "V379":{ "name":"V379", "fixes":["OTT", "RAVNN", "JETTA", "GRACO", "PRICE", "ENO"]},
+    "V38":{ "name":"V38", "fixes":["MZV", "GENSO", "WYNET", "TRIDE", "KELSI", "MEITZ", "MEDAN", "OCEDO", "EON", "LUCIT", "MAPPS", "DENAM", "CLEFT", "TELEY", "OYIDU", "FWA", "CHIZM", "WINES", "JINAK", "FBC", "LAWTO", "MEEKS", "APE", "CINAB", "ZZV", "CUMBA", "RAVES", "BROCH", "JPU", "TRION", "SACKY", "JULEA", "ZOBIG", "BENZO", "PAGVE", "EKN", "BUGEL", "DEKAY", "CEROL", "ZEDPA", "MITER", "GVE", "EMMIE", "ROOKY", "RIC", "NEMAN", "HCM", "JUDLU", "TERKS", "CCV"]},
+    "V380":{ "name":"V380", "fixes":["ONL", "OBH", "GRI", "HSI", "IKUME", "TKO"]},
+    "V381":{ "name":"V381", "fixes":["BIH", "EVERR", "NIKOL"]},
+    "V382":{ "name":"V382", "fixes":["JNC", "ECNOF", "ETL", "DRO"]},
+    "V383":{ "name":"V383", "fixes":["ROD", "IREJU", "YOGGI", "CHOOT", "SCORR", "DXO"]},
+    "V384":{ "name":"V384", "fixes":["LVT", "JELLO", "WINNA", "VXV"]},
+    "V385":{ "name":"V385", "fixes":["LBB", "WAGUN", "ABI"]},
+    "V386":{ "name":"V386", "fixes":["RZS", "OHIGH", "FIM", "UMBER", "SAUGS", "PMD", "ZOREN", "APLES", "SOGGI", "OKACO", "YUCCA", "PSP"]},
+    "V387":{ "name":"V387", "fixes":["MFE", "REX"]},
+    "V388":{ "name":"V388", "fixes":["PDZ", "KNDAL", "LENHO", "ACINS", "DEWAY", "PSP"]},
+    "V389":{ "name":"V389", "fixes":["CIM", "SAYKA", "FOGLE", "EARLS", "JOGEL", "RADIO", "PUB", "DRAKE", "ADANE", "LUFSE", "FQF"]},
+    "V39":{ "name":"V39", "fixes":["SDZ", "MERIL", "SNOWS", "UXEWE", "SEGPE", "SBV", "INSAC", "SHEPS", "COLAB", "ARVON", "GVE", "WITTO", "LURAY", "KERRE", "AANTS", "HOAGE", "MRB", "MAPEL", "ROBRT", "MULRR", "HYPER", "BINNS", "SUEDE", "DELRO", "JOANE", "LRP", "BOYER", "FLOAT", "ETX", "ELIOT", "SAX", "WANVA", "BREZY", "VOLLU", "MICAL", "CMK", "GREKI", "SOARS", "MOONI", "STUBY", "SASHA", "MOLDS", "CTR", "LEADS", "VAPER", "GDM", "LURCH", "CON", "NEETS", "LIMER", "LABEL", "SERPA", "NOLLI", "QUIPS", "ROLAF", "AUG", "LIPVE", "RINTH", "MLT", "CROIX", "PQI", "GRINS", "YYY"]},
+    "V390":{ "name":"V390", "fixes":["TCC", "IREVE", "BGD", "IPIME", "EKWIY", "BUVLE", "FILEL", "MMB"]},
+    "V391":{ "name":"V391", "fixes":["RSK", "PLATA", "CEZ", "YURVE", "DVC", "PAROX", "JNC", "MACKS", "ZIKOS", "BONGO", "VEL", "OCS"]},
+    "V392":{ "name":"V392", "fixes":["OAK", "SALAD", "ALTAM", "OAKEY", "VISTO", "SAC", "ROZZY", "HAGAN", "AUDIO", "CONYO", "SIGNA", "TRUCK", "VERDI", "FMG"]},
+    "V393":{ "name":"V393", "fixes":["TUS", "OLS", "AKACU", "HMO"]},
+    "V394":{ "name":"V394", "fixes":["SLI", "AHEIM", "POWUP", "ADAMM", "POM", "CALBE", "MEANT", "GARDY", "HESPE", "APLES", "BASAL", "DAG", "DISBE", "CHRLT", "CLARR", "OASYS", "LAS", "SUVIE", "MMM"]},
+    "V395":{ "name":"V395", "fixes":["TUS", "ARVEY", "OLS"]},
+    "V396":{ "name":"V396", "fixes":["YQG", "OCTAS", "ERRTH", "CAGKA", "CXR"]},
+    "V397":{ "name":"V397", "fixes":["MLU", "ANPIY", "JUDUN", "RUTTS", "GLH", "CARYA", "UJM"]},
+    "V398":{ "name":"V398", "fixes":["ABR", "AMMAJ", "ATY", "BUCCA", "RISLE", "MOLOW", "JOVIR", "RWF", "KUKGE", "ZELET", "ALMAY", "KASPR", "RST", "GABDE", "UKN", "QUEST", "LNR"]},
+    "V399":{ "name":"V399", "fixes":["VHP", "ADVAY", "JELLS", "JAKKS", "BVT", "ERNEY", "YIXCI", "KENLA", "EON"]},
+    "V4":{ "name":"V4", "fixes":["TOU", "JAWBN", "DIGGN", "LOFAL", "SEA", "BLAKO", "HUMPP", "RADDY", "CHINS", "CADED", "TITON", "GLEED", "YKM", "SUNED", "BRUKK", "AMPLE", "LACIB", "CORDO", "PDT", "PIANO", "HEKPI", "LACED", "BKE", "HOVEL", "PAYET", "EMETT", "NICPE", "BOI", "CANEK", "ALKAL", "YUWFE", "GOODE", "JEROT", "HAZZL", "BYI", "MEDEA", "MLD", "TINRE", "FILOB", "HODNI", "GEGME", "GRIPS", "OCS", "TOGUY", "ARUTE", "CKW", "ZOLGA", "TRUMA", "KLASH", "NATTI", "LYMPS", "LAR", "FLEMS", "BARGR", "WISER", "GLL", "HOYTT", "TXC", "FLAGG", "EHVER", "GLD", "DEPAY", "CUGGA", "HLC", "PUQZE", "WESAL", "SLN", "ZITIK", "VASCO", "DIVBE", "CEKIS", "DRAMA", "ALMAS", "WEVAL", "MOPPS", "ULNAZ", "TOP", "ROVVO", "MCI", "LYMES", "LEXIN", "YOJCO", "HLV", "JAGGI", "MEMAC", "CABIT", "SADEN", "STL", "TOY", "BREEZ", "ENL", "ZOLLI", "DAHLL", "HILTS", "MAUNI", "PXV", "LAMBS", "APALO", "DOWNS", "ZOGUN", "NADDI", "BETHY", "IIU", "FEDRA", "HYK", "CODEL", "MASSE", "CICKE", "ECB", "RODIC", "HAITI", "SALTY", "HVQ", "CAMMA", "ITALY", "FILES", "REACH", "EKN", "OMIYO", "ESL", "SOGBE", "DRUZZ", "TRIXY", "HOAGE", "JASEN", "MANNE", "GILBY", "AML"]},
+    "V40":{ "name":"V40", "fixes":["DJB", "SAROW", "RITZS", "KEATN", "JOSEF", "BSV", "CUTTA"]},
+    "V400":{ "name":"V400", "fixes":["PQI", "EIKMN", "DCLNK", "VLV"]},
+    "V401":{ "name":"V401", "fixes":["RLY", "RANKK", "JITIP", "JYMBO", "DDY"]},
+    "V402":{ "name":"V402", "fixes":["TCC", "MOSER", "PORCU", "SIDER", "PNH", "BRISC", "EYMUV", "MMB"]},
+    "V403":{ "name":"V403", "fixes":["BELAY", "GLOMO", "SPERY", "PTW", "DIRPE", "SBJ"]},
+    "V404":{ "name":"V404", "fixes":["CDS", "SNEED", "ELECT", "SPS"]},
+    "V405":{ "name":"V405", "fixes":["BELAY", "GLOMO", "SPERY", "PTW", "ZUVIV", "LANNA", "SBJ", "PIYIN", "FALLZ", "NYACK", "DOSWL", "CMK", "NOBBI", "CASSH", "PWL", "VEERS", "COBOL", "BAF", "KIBBE", "WITNY", "PUT", "FOSTY", "PVD", "FALMA", "MVY"]},
+    "V406":{ "name":"V406", "fixes":["SVM", "COFGI", "MOONN", "BROKK", "BOVEX", "DUSUT", "FINGL", "YXU"]},
+    "V407":{ "name":"V407", "fixes":["BRO", "HRL", "JIMIE", "LOCOE", "JETTY", "CRP", "WORRY", "AUSTS", "BLOKS", "IVOLY", "TANNA", "PSX", "BUHOL", "GLAND", "IAH", "REHAB", "INNIS", "DAETN", "DAYBO", "DAS", "LFK", "EXITE", "MOKPE", "EMG", "INWAM", "ELD"]},
+    "V408":{ "name":"V408", "fixes":["ROBRT", "GATHR", "VINNY", "KITHE", "GLOMO", "MXE", "PTW", "HIKES", "ETX", "FJC"]},
+    "V409":{ "name":"V409", "fixes":["CLT", "LOCAS", "GANTS", "LIB", "GUSES", "RDU"]},
+    "V41":{ "name":"V41", "fixes":["CUTTA", "CAMES", "YNG"]},
+    "V410":{ "name":"V410", "fixes":["PSI", "IKTIH", "SWWAN", "HIGIG", "CABTI"]},
+    "V411":{ "name":"V411", "fixes":["LNR", "QUEST", "UKN", "GABDE", "RST", "EGUPE", "DELZY", "PEPPR", "AHMIT", "FGT"]},
+    "V412":{ "name":"V412", "fixes":["RWF", "DRAIL", "FCM"]},
+    "V413":{ "name":"V413", "fixes":["IWD", "ERIYI", "RUSSH", "LAYVU", "EAU", "BITLR", "ANDDE", "WAGNR", "GEP", "KEYEN", "AMMBR", "DAYLE", "GITTI", "JIPKO", "BRD"]},
+    "V415":{ "name":"V415", "fixes":["MGM", "WETUM", "SEMAN", "CAMPP", "GIFFY", "HEFIN", "FELTO", "GORGO", "RMG", "YESVU", "NELLO", "ANNYE", "TALLE", "ODF", "PEDAL", "PELAM", "SPA", "EHAXY", "LOCKS"]},
+    "V416":{ "name":"V416", "fixes":["ROD", "BUZZI", "LAWTO", "JUVDU", "MFD", "ZABER", "JAKEE"]},
+    "V417":{ "name":"V417", "fixes":["MEI", "NOSRY", "BOYDD", "ALICE", "LDK", "SITES", "OAKGO", "WUNET", "RIMZO", "VUZ", "HOKES", "MAYES", "GORGO", "RMG", "YESVU", "NELLO", "AWSON", "CORCE", "IRMOS", "AHN", "OCENU", "DANBI", "TIGNA", "MSTRS", "KANDY", "IRQ", "STUGE", "ALD", "STOAS", "CUBER", "CHS"]},
+    "V418":{ "name":"V418", "fixes":["SVM", "COFGI", "MOONN", "BROKK", "BEWEL", "JHW"]},
+    "V419":{ "name":"V419", "fixes":["EMI", "HERES", "MXE", "FROSE", "MUDNE", "DASDE", "MAZIE", "HARRS", "BIGGY", "SBJ", "PIYIN", "FALLZ", "NYACK", "DOSWL", "CMK", "GREKI", "SOARS", "JUDDS", "BRISS"]},
+    "V420":{ "name":"V420", "fixes":["GRB", "AGOMA", "NENSE", "ZUXIN", "FEPEX", "TVC", "BARAK", "ELBOT", "GLR", "SPARR", "APN"]},
+    "V421":{ "name":"V421", "fixes":["ZUN", "GUP", "DERTY", "CHACO", "RSK", "DRO", "ZEANS", "LAZON", "POWES", "COGRI", "HBU", "WENDT", "CAZUU", "SKIER", "DBL", "VAILE", "RRIVR", "KIMBL", "FOTTY", "RLG", "HETGI", "ACAGI", "BQZ", "ECHOA", "HAHNS"]},
+    "V422":{ "name":"V422", "fixes":["BEBEE", "NILES", "CGT", "BOONE", "OXI", "WATSN", "OLK", "TWERP", "FBC"]},
+    "V423":{ "name":"V423", "fixes":["FQM", "TWIIN", "CFB", "ITH", "BOCKS", "SYR"]},
+    "V424":{ "name":"V424", "fixes":["ANX", "DRADE", "MCM"]},
+    "V425":{ "name":"V425", "fixes":["BFM", "ZUGTI", "WORIR", "AXSIS"]},
+    "V426":{ "name":"V426", "fixes":["CRL", "STIEN", "SALFE", "AMRST", "HUDDZ", "DJB"]},
+    "V428":{ "name":"V428", "fixes":["ULW", "WIKKI", "VILCU", "ITH", "CORTA", "GGT", "EATEN", "UCA"]},
+    "V429":{ "name":"V429", "fixes":["CGI", "PAMPI", "DONGO", "MAKAN", "MWA", "EWING", "ZOLLI", "CRATS", "BIB", "MOBBY", "MTO", "ARCOL", "TUSCO", "CMI", "LUDLO", "RBS", "SERCY", "MEDAN", "JOT"]},
+    "V43":{ "name":"V43", "fixes":["APE", "UTTER", "TVT", "ZETMU", "WILMO", "CEPSI", "BSV", "DEFOE", "SEING", "YNG", "BARLY", "ERI", "TWGKD", "MYPAL", "WELLA", "VICCU", "SUSKE", "HIDUB", "BUF"]},
+    "V430":{ "name":"V430", "fixes":["CTB", "HEKIT", "AGRYN", "WEBVO", "ETOHO", "HVR", "ISITE", "IVIVE", "CAGAT", "BOWDN", "KEEVR", "GGW", "NEGAE", "DORIA", "RILMY", "OFEGY", "ISN", "OFBUF", "UNCUP", "FONIA", "ERUVE", "WELOG", "CUDRI", "MOT", "ORMIE", "BALTA", "CAREW", "SCULY", "DVL", "NERDE", "BISCA", "DITRE", "GFK", "ROPBO", "UGACU", "TVF", "ZALSO", "BLUOX", "BUCAN", "YOBRI", "GPZ", "MAZPI", "CIBNA", "GECRE", "MATEC", "PYKLA", "DLH", "MASWE", "LAZNU", "HUGRA", "NOYIC", "WASPS", "IWD", "DINER", "CINOP", "IMT", "VUKFI", "ESC"]},
+    "V431":{ "name":"V431", "fixes":["REVER", "SOSYO", "LOBBY", "BRONC", "GDM", "EEN", "BRATS", "GFL", "GASSY"]},
+    "V432":{ "name":"V432", "fixes":["TRM", "PKE"]},
+    "V433":{ "name":"V433", "fixes":["OTT", "PALEO", "SWANN", "GATBY", "KERNO", "ODESA", "KIRKK", "DQO", "SAVVY", "STEFE", "SOMTO", "ARD", "MERSR", "METRO", "PLEXS", "BONIE", "KILMA", "GRITY", "TICKL", "PROUD", "DIALS", "LGA", "DUNBO", "WRENN", "PRENO", "BDR", "DENNA", "FZOOL", "LOVES", "DEEDE", "PWL", "TRESA", "CYPER", "PETER", "CODDI", "RKA", "SHERB", "EATEN", "DINNO", "TEBOR", "STODA", "FAYET", "SYR"]},
+    "V434":{ "name":"V434", "fixes":["OTM", "VOYUG", "ACKLY", "WAPEL", "POCIN", "MZV", "ONEID", "VICKS", "GREGG", "PIA", "MACIN", "NINIC", "MCLEN", "LODGE", "CMI", "EMTEE", "JAGER", "LUNEY", "JAZZY", "ALLOE", "ANTTI", "VHP"]},
+    "V435":{ "name":"V435", "fixes":["ROD", "JUVDU", "OBRLN", "BRUNZ", "DJB"]},
+    "V436":{ "name":"V436", "fixes":["HBR", "NEADS", "IRW", "BARNS", "SAPPA", "TUL"]},
+    "V437":{ "name":"V437", "fixes":["DHP", "PIONN", "BRIKL", "ENVER", "HEDLY", "PHK", "MODOE", "SMERE", "TPSTR", "MLB", "AWINY", "OVIDO", "KIZER", "OMN", "COKES", "COBOK", "JETSO", "SUBER", "HOTAR", "STARY", "CATHY", "KELER", "SAV", "YUHVY", "NOMAS", "TERLY", "BAGGY", "JACKE", "CULAP", "CHS", "GINNE", "HERMN", "MUGSE", "WESEL", "FILLI", "NUTAL", "FLO"]},
+    "V438":{ "name":"V438", "fixes":["GRV", "FLINT", "TOMAC", "HGR", "LUCKE"]},
+    "V439":{ "name":"V439", "fixes":["DIK", "HASOS", "ISN"]},
+    "V44":{ "name":"V44", "fixes":["COU", "CANDY", "HODGS", "FTZ", "FEKRO", "MOODS", "SUGAR", "DUTMY", "COFEY", "ENL", "JETON", "SAM", "FLM", "HAFTU", "YRK", "NABLE", "JPU", "BENDS", "RANDE", "STORE", "METZE", "MGW", "PINIC", "BAABY", "LIZIO", "KEYER", "MUMSY", "MRB", "WOOLY", "YANNI", "BAL", "PALEO", "AGARD", "SPEAK", "CANNY", "DONIL", "SIE", "HOGGS", "PANZE", "WINKK", "KARRS", "GAMBY", "CAMRN", "SATES", "DPK", "BELTT", "NESSI", "BDR", "DENNA", "FZOOL", "LOVES", "DEEDE", "PWL", "GELAW", "ATHOS", "GROUP", "ALB"]},
+    "V440":{ "name":"V440", "fixes":["PNH", "BRISC", "BFV", "LEPIY", "CARFF", "DATTA", "IRW"]},
+    "V441":{ "name":"V441", "fixes":["MLB", "DEARY", "ODDEL", "YONMA", "YOJIX", "LAL", "PIE", "BAYPO", "NITTS", "NUCIS", "OCF", "LEJKO", "GNV", "BOCAP", "MONIA", "CIRSA", "CIPDU", "CUBDU", "SSI", "STARY", "CATHY", "KELER", "SAV"]},
+    "V442":{ "name":"V442", "fixes":["PDZ", "EMMLN", "APLES", "HEC", "ZELMA", "CLIPP", "WAGJI", "PKE"]},
+    "V443":{ "name":"V443", "fixes":["WISKE", "CTW", "TVT", "READS", "STROK", "DJB", "FAILS", "CRPSL", "DOGGS", "YQO"]},
+    "V444":{ "name":"V444", "fixes":["GEG", "DATES", "ALW", "BKE", "HOVEL", "PAYET", "EMETT", "NICPE", "BOI", "AROWS", "HESGO", "EREXE", "DERSO", "SOLDE", "KINZE", "SHONE", "BYI"]},
+    "V445":{ "name":"V445", "fixes":["MITCH", "GEEMO", "SWANN", "GATBY", "KERNO", "ODESA", "KIRKK", "DQO", "SAVVY", "STEFE", "SOMTO", "ARD", "KOPPS", "EMPYR", "NANCI", "RENUE", "APPLE", "TICKL", "PROUD", "DIALS", "LGA"]},
+    "V446":{ "name":"V446", "fixes":["TOY", "KENBE", "CRATS", "SAM"]},
+    "V447":{ "name":"V447", "fixes":["CAM", "KOSPE", "KERST", "MUDDI", "RUCKY", "MPV", "PLOTT", "HURDS", "RNPCY", "LIAND", "YSC"]},
+    "V448":{ "name":"V448", "fixes":["OED", "PITON", "SAMIE", "MOPIO", "RBG", "ACONI", "DRAIN", "FRITT", "EUG", "LATHE", "GLORR", "ENDNG", "MAVER", "GLARA", "MULES", "BTG", "DMAZH", "OJUMU", "LEARN", "ANGOO", "OXNAS", "SIMCO", "WIKIK", "YKM", "FEBUS", "RUBEL", "MWH", "BATUM", "SUBDY", "ZOOMR", "YICUB", "GANGS", "GEG", "EPENE", "JURSY", "KARPS", "CLASS", "EYESE", "OLIBY", "KILLY", "FCA"]},
+    "V45":{ "name":"V45", "fixes":["EWN", "WILUN", "ISO", "HOPIM", "TILTZ", "ESTER", "WADUG", "BRADE", "WENDI", "RDU", "CHAPL", "SNOWS", "HOJPA", "KIMES", "GSO", "PROVE", "FREON", "WILIZ", "NANKY", "PSK", "ERATH", "HECKE", "BLF", "KEGLY", "CINDO", "TERRN", "HVQ", "HNN", "TASKE", "LARIC", "NIKLS", "BREMN", "FAIRF", "APE", "KIRBY", "DUSKY", "TUMAY", "DAZEY", "VWV", "RANDL", "HIRED", "JXN", "LESSY", "LAN", "LUGGS", "ASHUR", "MBS", "SEEKS", "SNOWW", "WHOOP", "TUSYU", "AILES", "APN", "RNAND", "REEFY", "HITAM", "SSM"]},
+    "V450":{ "name":"V450", "fixes":["ESC", "MAARC", "LOGIF", "MNM", "WARWF", "GRB", "NICOT", "RABEE", "MOTAN", "MKG", "CLOCK", "GIBER", "PALOW", "CFCCV", "CUTTY", "LUGGS", "OWOSO", "FNT", "KATTY", "HANKY", "ADRIE", "MARGN", "BLUEZ", "DMYFC"]},
+    "V451":{ "name":"V451", "fixes":["LGA", "ODALE", "JOHNE", "WORMY", "NESSI", "KEYED", "VIKKY", "CREAM", "GON"]},
+    "V452":{ "name":"V452", "fixes":["ONP", "TICKY", "HORTE", "EUG", "JUXIB", "CHEEZ", "MANSN", "MIXUP", "LMT", "TULIP", "WOGRO", "BACHS", "WNDEL", "RAROC", "HALLE", "FITUN", "FMG"]},
+    "V453":{ "name":"V453", "fixes":["GVE", "BUVBE", "CSN", "LDN"]},
+    "V454":{ "name":"V454", "fixes":["BFM", "STETS", "YORUP", "MVC", "CHAFF", "RUTEL", "YIBYI", "CRENS", "BANBI", "PEECH", "MILER", "CSG", "CANER", "GRANT", "HUZER", "SMARR", "SINCA", "GLOSS", "MADDI", "PENFI", "DANBI", "VESTO", "NADZU", "GRD", "UNARM", "ADENA", "LOCKS", "GIZMO", "KEWPI", "LIB", "STASE", "BILLA", "WUMVA", "OXFRD", "NOKIY", "LVL", "JUNKI", "JUVPO", "HPW"]},
+    "V455":{ "name":"V455", "fixes":["RQR", "WAVEZ", "PCU", "PLUGG", "LBY", "TEGBE", "SOSOE", "UTOWE", "NOVCA", "MEI"]},
+    "V456":{ "name":"V456", "fixes":["FOD", "HOXIV", "SHELB", "BANCO", "BLEND", "MKT", "ZANNA", "WULEP", "FCM"]},
+    "V457":{ "name":"V457", "fixes":["BWZ", "PARKE", "TOWIN", "KATVE", "HOUTN", "WEPNA", "DETTE", "LRP", "ROAST", "VINNY", "EMI", "RUANE", "MRB"]},
+    "V458":{ "name":"V458", "fixes":["SXC", "AVOLS", "PACIF", "HUBRD", "OCN", "VISTA", "ROBNN", "BONDO", "JLI", "KUMBA", "NICKK", "IPL", "ARGUS", "HEEDS", "ARAZI", "BZA"]},
+    "V459":{ "name":"V459", "fixes":["SLI", "DODGR", "DARTS", "BERRI", "KIMMO", "SAUGS", "LHS", "JEFFY", "LOPES", "AMONT", "WRING", "TTE", "EXTRA", "ALTTA", "SIBOC", "FRA", "COGOL", "BAGBY", "HOFED", "HABXU", "LIN"]},
+    "V46":{ "name":"V46", "fixes":["DPK", "PAZTA", "CCC", "HTO", "ARCAV", "LIBBE", "OSSER", "FLAPE", "DEEPO", "CLAMY", "ACK"]},
+    "V460":{ "name":"V460", "fixes":["MZB", "HAILE", "RYAHH", "BARET", "CANNO", "JLI", "KARRO", "BOREN", "HENOM", "MOMAR", "SHADI", "BLH"]},
+    "V461":{ "name":"V461", "fixes":["GBN", "BXK"]},
+    "V462":{ "name":"V462", "fixes":["FOD", "SIMJI", "NELIC", "NEWRN", "FIBIK", "CATID", "ANBUJ", "FSD"]},
+    "V463":{ "name":"V463", "fixes":["WOMAC", "ANNYE", "HRS"]},
+    "V464":{ "name":"V464", "fixes":["SVM", "DELOW", "SPICA", "WOLIS", "DUSUT", "YQO", "FOWEL", "FWBKB", "BROTO", "DKK", "LANGS", "BIZON", "GEE"]},
+    "V465":{ "name":"V465", "fixes":["BQU", "MUNGO", "BUCAK", "ELROD", "LWL", "SHEAR", "MLD", "LUNDI", "OLNUE", "GIGSE", "CILEG", "ELKHO", "ECUNA", "JAC", "DNW", "TOCUD", "REDLO", "HAKDI", "CUKUV", "LAREI", "BIL", "KOXMY", "NIBBE", "CONUK", "ASHLI", "MLS", "ZITGA", "SAYOR", "ACAKO", "EXADE", "LAMBE", "ISN"]},
+    "V466":{ "name":"V466", "fixes":["VXV", "NEYLN", "GOODL", "TAMPI", "FARLI", "YUMMY", "HILTO", "GZG", "DORFF", "KLAND", "ROCIR", "PSK"]},
+    "V467":{ "name":"V467", "fixes":["RID", "RUSIA", "LINZZ", "VWV", "JUSKI", "DXO"]},
+    "V468":{ "name":"V468", "fixes":["BTG", "DMBOR", "AXQOX", "TROTS", "ADOJA", "SWANY", "HITCH", "YKM", "GLEED", "SELAH", "GEBTE", "ELN"]},
+    "V469":{ "name":"V469", "fixes":["DAN", "JAVVA", "SYCAM", "LYH", "LUCLI", "RADIA", "RELEE", "BOOME", "IFAVU", "EXRAS", "BRUCY", "BOIER", "EKN", "TYGAR", "MGW", "ZETGA", "OTOWN", "NESTO", "QUARY", "JST", "YEDUS", "TATES", "THS", "GRAHM", "BADDI", "HAR", "JOANE", "RICKF", "DQO", "OOD"]},
+    "V47":{ "name":"V47", "fixes":["PBF", "DRAST", "AGOTE", "GQE", "BOROW", "DYR", "SACDO", "AHOYE", "CNG", "ROOKE", "WESON", "PXV", "CVG", "MOWED", "MIZZA", "CINPA", "ELIHO", "ZAKIT", "TRUNC", "ROD", "KINDE", "FBC", "OHZUF", "YOTUG", "VWV"]},
+    "V470":{ "name":"V470", "fixes":["PSK", "TABER", "DEWET", "PARTE", "MONAT", "LYH"]},
+    "V471":{ "name":"V471", "fixes":["BGR", "HOSEP", "MLT", "HUL", "RNSYN", "BAGLE", "YQM"]},
+    "V472":{ "name":"V472", "fixes":["ECG", "WINAL", "BERTI", "ZAGGY", "IRAKE", "ISO"]},
+    "V473":{ "name":"V473", "fixes":["ROA", "SPRAT", "HOBOS", "RELEE", "MOL", "GVE"]},
+    "V474":{ "name":"V474", "fixes":["NESTO", "PLEEZ", "NIDGY", "IHD", "ASUTE", "THS", "AMISH", "SCAPE", "NOENO", "PIFER", "GRAMO", "DELRO", "ROAST", "GEERI", "PADRE", "MXE"]},
+    "V475":{ "name":"V475", "fixes":["LGA", "DUNBO", "WRENN", "PRENO", "BDR", "MUVGE", "MAD", "CARLD", "ARENE", "ORW", "PVD"]},
+    "V476":{ "name":"V476", "fixes":["LYH", "SWARM", "BRAIL", "TURCO", "GVE"]},
+    "V477":{ "name":"V477", "fixes":["IAH", "PEPBI", "ZMSKL", "LITLD", "BLTWY", "LOVAZ", "LOA", "NARCS", "HOXDE", "CQY"]},
+    "V478":{ "name":"V478", "fixes":["FLM", "ECB", "CELLI", "BIVDY", "TERRN", "BKW"]},
+    "V479":{ "name":"V479", "fixes":["DQO", "WILJR", "RUUTH", "MENGE", "ZIDET", "ARD"]},
+    "V48":{ "name":"V48", "fixes":["OTM", "VOMZY", "BRL", "LOGOS", "PIA", "MAROC", "HUMUL", "PNT"]},
+    "V481":{ "name":"V481", "fixes":["EUG", "CVO", "CRAAF"]},
+    "V483":{ "name":"V483", "fixes":["DPK", "JOHNE", "RYMES", "CMK", "NOBBI", "CASSH", "IGN", "WEETS", "FILPS", "PRNCE", "RIMBA", "DNY", "RKA", "SHERB", "EATEN", "DINNO", "TEBOR", "STODA", "FAYET", "SYR", "WACOR", "LYSAN", "DINES", "ROC"]},
+    "V484":{ "name":"V484", "fixes":["HLE", "KINZE", "JEROT", "TOXEE", "TWF", "FERUD", "WODEN", "CEEDY", "DRYAD", "SWITZ", "HOGUP", "CAUSE", "RIDEN", "JOSIF", "TCH", "PARLE", "MTU", "IGEHU", "WINDO", "JNC", "AYEDY", "MIRXE", "CESBA", "BATTZ", "HAQHY", "BRUUK", "ICIES", "HBU", "LUISS", "ICORY", "HOMME", "ALS"]},
+    "V485":{ "name":"V485", "fixes":["VTU", "HENER", "OHIGH", "FLW", "REDDE", "ROM", "RANCK", "PANOS", "ULENY", "HENCE", "GILRO", "LICKE", "SJC"]},
+    "V486":{ "name":"V486", "fixes":["LEBRN", "CXR", "GEAGA", "ALLCO", "JHW"]},
+    "V487":{ "name":"V487", "fixes":["LGA", "DUNBO", "WRENN", "PRENO", "BDR", "TRUDE", "SOARS", "MOONI", "STUBY", "BOWAN", "HIDAL", "CANAN", "CAM", "JOGIM", "GRISS", "ENSON", "WEIGH", "WINLA", "BTV", "JUTEK", "WARDS", "YJN"]},
+    "V489":{ "name":"V489", "fixes":["COATE", "LEMOR", "HUO", "RUBER", "WEARD", "FILPS", "SAGES", "CYPER", "AGNEZ", "ALB", "GFL"]},
+    "V49":{ "name":"V49", "fixes":["VUZ", "CAPUN", "DELFI", "ZUSMA", "BOUNT", "FOLSO", "MASHA", "HASEL", "DCU", "ELKED", "ARDER", "LOYYI", "JOVNA", "FOREV", "BNA", "CEBDA", "CHAFA", "TANDS", "BWG", "OSINE", "MYS"]},
+    "V490":{ "name":"V490", "fixes":["UCA", "ROOMS", "PAYGE", "GALWA", "ETZUN", "CAM", "DORIS", "BRATS", "STRUM", "DUBIN", "LURCH", "MUGGY", "BASUU", "MHT"]},
+    "V491":{ "name":"V491", "fixes":["RAP", "JORNO", "BFFLO", "DIXLE", "JELRO", "HAYNI", "NEXRU", "DIK", "MOT"]},
+    "V492":{ "name":"V492", "fixes":["PIE", "GIBBS", "BRDGE", "ROGAN", "QUNCY", "UTELE", "LBV", "RELLI", "PHK", "NITNY", "PBI", "WHELM", "STOOP", "ANGEE", "CUKPO", "MLB"]},
+    "V493":{ "name":"V493", "fixes":["LVT", "BRUNO", "HYK", "NOUNS", "SPROW", "BEAER", "YRK", "ROHDE", "TARTO", "VADUY", "APE", "KIRBY", "DUSKY", "TUMAY", "DAZEY", "VWV", "HARBS", "ANOVE", "CRL", "MNM", "LOPJA", "CRAZE", "DADYE", "RHI"]},
+    "V494":{ "name":"V494", "fixes":["CEC", "YOBUN", "ANAJE", "DUHJY", "SEVLY", "FOYTE", "FOT", "JENNI", "ENI", "CABEX", "GETER", "STS", "SNUPY", "POPES", "RAGGS", "PIVSE", "SAC", "ROZZY", "HAGAN", "AUDIO", "SWR", "HETRY", "HUYJO", "WAGGE", "VIKES", "CHIME", "OHOLI", "HZN"]},
+    "V495":{ "name":"V495", "fixes":["XX", "HUH", "APDON", "TECUV", "BUICK", "YYJ", "IDNEY", "CONDI", "DISCO", "CDGPN", "ORCUS", "JIGEB", "WATTR", "JAWBN", "DIGGN", "LOFAL", "SEA", "CIDUG", "ALDER", "TOUTL", "OKARE", "BTG", "ENDZZ", "UBG", "BREAF", "ADLOW", "CVO", "HORTE", "NOTTI", "VAUGN", "RBG", "KOLER", "MERLI", "PAPLE", "BAYTS", "FJS"]},
+    "V496":{ "name":"V496", "fixes":["UCA", "MALLO", "WAREN", "GFL", "KERST", "EBERT", "LEB", "BILLS", "ANIER", "GRUMP", "NEETS", "ENE"]},
+    "V497":{ "name":"V497", "fixes":["REO", "ILR", "AKUKY", "WIPLO", "DOWCY", "IMB", "RENCE", "CEVBI", "LTJ", "SUNED", "PAPPS", "MWH", "EPH"]},
+    "V499":{ "name":"V499", "fixes":["BAL", "ENSUE", "DLUCA", "CLIPR", "TRISH", "BELAY", "KITHE", "GEERI", "LRP", "KERYN", "JUPAS", "CHLSE", "MARRC", "MEGSS", "MEATS", "OYUCA", "CFB"]},
+    "V5":{ "name":"V5", "fixes":["PZD", "GILLY", "VNA", "UCALA", "DBN", "HEPUT", "HADOC", "BEYLO", "TRAPI", "CORVI", "PENFI", "AHN", "IRMOS", "CORCE", "AWSON", "NELLO", "ETONE", "HOCHE", "ZIROB", "GQO", "PALER", "FARAD", "MCMIN", "HARME", "GARVY", "LEJCO", "BWG", "KEDLE", "EWO", "JBEAM", "BRBON", "IIU", "ZOPOM", "NERVE", "WARSA", "CVG", "WUSPU", "BRNIE", "MOAKS", "JENEY", "PRUDE", "FODAN", "SHIRT", "JOGER", "LIMPS", "GOBVE", "GLOOM", "TIYOY", "FABDO", "APE", "GIVES", "MFD", "NEWLO", "DJB", "OTOCE", "CRIBS", "GILLS", "DCTYP", "DOLFN", "BROKK", "BOVEX", "DUSUT"]},
+    "V50":{ "name":"V50", "fixes":["HSI", "SHART", "KECER", "SUEKI", "GADWY", "KOPFY", "PWE", "UBELE", "STJ", "WITAG", "PATTN", "JAWED", "YIGRE", "IRK", "HEBET", "UIN", "SEXTN", "YALUR", "GINIA", "SPI", "BUDDY", "LATHA", "HASSE", "AXC", "LUSLY", "ZARIR", "ARCOL", "GAULS", "ORLEY", "TTH", "KIYSI", "MATAN", "FILMS", "VHP", "ZAVNE", "HOMAR", "NEWTO", "MOTTS", "ARBAS", "LEEDS", "DQN"]},
+    "V500":{ "name":"V500", "fixes":["BTG", "ENDZZ", "UBG", "CANBY", "GLARA", "HARZL", "JJACE", "RATZZ", "GASHE", "COVBO", "ROAMS", "IMB", "POTSY", "FONNA", "HOSTS", "DAGNE", "PARMO", "BOI", "AROWS", "HESGO", "EREXE", "DERSO", "SOLDE", "PRESN", "REAPS", "MENIN", "BETRE", "KNURL", "JANIN", "TANOY", "SICOY", "PIH"]},
+    "V501":{ "name":"V501", "fixes":["MRB", "HGR", "THS", "COFAX", "BLINK", "PSB", "ELZ", "HORNE", "ATTAR", "RITCH", "BEEPS"]},
+    "V502":{ "name":"V502", "fixes":["DDC", "KUDDO", "SOSPE", "DISKS", "HARAN", "SPELT", "HUT", "BURTO", "WAIVE", "FLOSS", "ANUGE", "EMP", "KICRE", "JHAWK", "HOOZE", "RUGBB", "NOAHS", "MCI", "AYOCI", "LASSO", "BQS", "CUTAN", "FONIX", "KIVDE", "IRK"]},
+    "V503":{ "name":"V503", "fixes":["RST", "TALNE", "FARVI", "CID"]},
+    "V505":{ "name":"V505", "fixes":["DSM", "GUMBO", "EIEIO", "ZEMET", "WURPU", "ROYOV", "FOD", "KADCO", "TICUV", "ZUTIG", "KEFIG", "MCW", "HIBLO", "FREED", "ALMAY", "PRAGS", "LYDIA", "PRIOR", "GEP", "LENCK", "RZN", "KINGZ", "BARUM", "DAYAR", "DLH", "AYIHE", "HIB", "DUNEC", "SQEAK", "BEBEL", "WANRI", "JIBDU", "INL"]},
+    "V506":{ "name":"V506", "fixes":["TUL", "BICEP", "VINTA", "EOS", "UROYI", "BILIE", "RIZUR", "SGF"]},
+    "V507":{ "name":"V507", "fixes":["ADM", "ZALUN", "MUSKS", "WETIX", "COFIX", "HAVAK", "IRW", "HISLA", "WAXEY", "ROLLS", "EZKUP", "MMB", "ZALIK", "LBL", "BOONS", "YECUT", "GCK"]},
+    "V508":{ "name":"V508", "fixes":["HLC", "IBQUP", "HYS", "ZISDA", "GLIDE", "HETAB", "SLN", "ZITIK", "VASCO", "DIVBE", "CEKIS", "MHK", "ZOYFY", "KENEC", "TOP", "RUGBB"]},
+    "V509":{ "name":"V509", "fixes":["PIE", "CROWD", "HALLR"]},
+    "V51":{ "name":"V51", "fixes":["PHK", "YATUR", "SHEDS", "TRV", "OVIDO", "OMN", "JODAB", "BULLI", "ASTOR", "BUNDE", "CRG", "CIRSA", "AMG", "IYONU", "DBN", "HEPUT", "HADOC", "BEYLO", "TRAPI", "CORVI", "PENFI", "AHN", "IRMOS", "CORCE", "TALLE", "HRS", "MARBL", "YUGUC", "HENGU", "ETOWA", "PEEKS", "HCH", "LVT", "HERMS", "MIXKO", "IIU", "SHB", "ZAVNE", "ZIPPY", "AZHUP", "OCKEL", "ZOFRI", "BVT", "OXFAT", "ZORRO", "LUCIT", "COKED", "CGT"]},
+    "V510":{ "name":"V510", "fixes":["DIK", "IFPOB", "BIS", "YIRNU", "SANDD", "BEHQY", "JMS", "HUHJO", "CHAFE", "HONET", "FAR", "WAGNI", "YILUV", "STARR", "AXN", "INONY", "SIYON", "DAYLE", "AMMBR", "KEYEN", "GEP", "WAGNR", "ANDDE", "BITLR", "ODI", "BOOTY", "FAPKO", "DLL", "OSH", "LEWKO", "ERAGE", "FAH", "GAYLE", "MKG", "FIVLO", "JAKES", "VIO", "UNSUN", "LAN", "BUF", "EHMAN", "ROC"]},
+    "V511":{ "name":"V511", "fixes":["LAL", "CAVAR", "HALLR", "SIGNL", "RELLI", "THNDR", "GILBI", "NEWER", "HOLID", "FRRDY", "DHP"]},
+    "V512":{ "name":"V512", "fixes":["PXV", "HOLAN", "SACKO", "CHERI", "DAMEN", "IIU", "FINCH", "CLEGG", "HYK"]},
+    "V513":{ "name":"V513", "fixes":["LVT", "CENUD", "ZEZJA", "OJETO", "GHOUT", "LEFVO", "EWO", "JBEAM", "BRBON", "IIU"]},
+    "V514":{ "name":"V514", "fixes":["MZB", "HAILE", "RYAHH", "BARET", "CANNO", "JLI", "WARNE", "TRM", "CONES", "CLOWD", "TNP", "JOTNU", "ZELMA", "GFS", "SHUSS", "LYNSY", "BLD"]},
+    "V516":{ "name":"V516", "fixes":["LBL", "OPVOE", "LAYIC", "LATOC", "CARKO", "STACS", "ANY", "DOREC", "PER", "TYROE", "OSW"]},
+    "V517":{ "name":"V517", "fixes":["SOT", "WHINS", "TAMPI", "MIAMI", "LOZ", "IRVIN", "LOGIC", "CODEL", "NOUNS", "FLM", "CVG", "BATHY", "RID", "DQN"]},
+    "V518":{ "name":"V518", "fixes":["FIM", "TWINE", "LANGE", "KIMMO", "SLAPP", "BOGET", "PMD"]},
+    "V519":{ "name":"V519", "fixes":["VXV", "NEYLN", "GOODL", "TAMPI", "FARLI", "YUMMY", "HILTO", "GZG", "TELOC", "BLF", "BKW"]},
+    "V52":{ "name":"V52", "fixes":["DSM", "BUSSY", "OTM", "LOAMY", "UIN", "CAVED", "RIVRS", "NEDLE", "HARDI", "STL", "TOY", "KENBE", "CRATS", "OFEND", "ZIMUN", "PXV", "ARLUV", "DIXEY", "GEPER", "CCT", "BWG", "FLIPU", "LVT"]},
+    "V520":{ "name":"V520", "fixes":["BTG", "OGYAJ", "LTJ", "AMPLE", "OZODU", "VIRTU", "PSC", "CITYS", "LYLES", "ALW", "ARTIN", "CLOVA", "MQG", "ZATIP", "FERDI", "LKT", "KEVME", "ORELE", "UNEPE", "DBS", "JAC"]},
+    "V521":{ "name":"V521", "fixes":["DHP", "WINCO", "RUTHY", "RSW", "VASES", "QUNCY", "RINSE", "FUPGE", "DOWNN", "LAL", "PLUMY", "JUVAS", "DADES", "NITTS", "ORATE", "CTY", "HEVVN", "TERES", "CRESS", "CLRRK", "BRITS", "MAI", "MALON", "RRS", "EGEST", "SKIPO", "CLIOS", "BANBI", "PETRY", "SHADY", "JEDOP", "MGM", "ITWAN", "KYLEE", "ADZIN", "HANDE", "VUZ"]},
+    "V522":{ "name":"V522", "fixes":["DJB", "FAILS", "ERI", "HAMIT", "FOUTN", "DKK", "MYPAL"]},
+    "V523":{ "name":"V523", "fixes":["APE", "UTTER", "TVT", "AKUTE", "DALTS", "JOSEF", "ACO", "YNG", "BARLY", "ERI"]},
+    "V524":{ "name":"V524", "fixes":["CHE", "VAREQ", "HAHNS", "WALRU", "LAR", "AFMAG", "BFF", "JADOB", "HICKO", "JANUR", "OGFAJ", "LBF"]},
+    "V525":{ "name":"V525", "fixes":["APE", "UTTER", "TVT", "RITZS", "SAROW", "DJB"]},
+    "V526":{ "name":"V526", "fixes":["OBK", "DEERE", "BRAIK", "MINCE", "MUSKY", "MAPER", "GIJ"]},
+    "V527":{ "name":"V527", "fixes":["HOT", "KRAMS", "HIDER", "VALLS", "ROVER", "DANIL", "SCRAN", "CASKS", "WESTY", "YUGUN", "RZC", "GAMPS", "CITGA", "SUEEY", "JENKY", "BILIE", "RIZUR", "SGF"]},
+    "V528":{ "name":"V528", "fixes":["PXR", "BUNTR", "WORZO", "HOMRR", "DBACK", "PICHR", "EAGUL", "PAYSO", "DEHOG", "SJN"]},
+    "V529":{ "name":"V529", "fixes":["FAMIN", "WORPP", "SWAGS", "LBV"]},
+    "V53":{ "name":"V53", "fixes":["CHS", "GRECI", "ADCOM", "CAE", "WIDER", "BUBBA", "WILLS", "UNARM", "BUILD", "SPA", "CARTT", "OBURY", "SUG", "BUSIC", "ROANS", "HMV", "HILTO", "FLENR", "RISTE", "AZQ", "OLETE", "HUGEN", "IRVIN", "HYK", "FEDRA", "IIU", "HEALS", "STREP", "HOUSE", "MOUTH", "ICUCO", "VHP"]},
+    "V530":{ "name":"V530", "fixes":["TXO", "CDS"]},
+    "V531":{ "name":"V531", "fixes":["PBI", "TBIRD", "SHEDS", "LLNCH", "CUSMO", "BAIRN", "ODDEL", "SABOT", "ORL"]},
+    "V532":{ "name":"V532", "fixes":["LIT", "TADAW", "PARON", "GATZY", "VALLS", "BLURB", "BLIMP", "IXEYA", "FSM", "AKINS", "VIANE", "HANIG", "OKM", "INHOF", "WOTNA", "SAPPA", "KEVIL", "SEARS", "CALVA", "PER", "BIKCA", "DOTEE", "JAMEY", "TEROY", "ICT", "WAIVE", "STONS", "ANTON", "SLN", "OXETY", "WIDMA", "STEEL", "KOPFY", "VACUS", "LNK"]},
+    "V533":{ "name":"V533", "fixes":["PIE", "LAL", "JIJCI", "ZOVLU", "CAMBE", "ORL", "OVIDO", "OAKIE", "SMYRA", "MIKBE", "OMN"]},
+    "V534":{ "name":"V534", "fixes":["LIT", "ROLAN", "BIBBS", "HAAWK", "SCRAN", "DRANO", "FSM"]},
+    "V535":{ "name":"V535", "fixes":["SQS", "CRINK", "ZETUR", "VOSFY", "HLI"]},
+    "V536":{ "name":"V536", "fixes":["OTH", "ZUBOR", "RARES", "TICKY", "CVO", "SHEDD", "LATHE", "JAIME", "MANTE", "EENIE", "DSD", "DUMMP", "ZORNS", "ARNOY", "ZEMAB", "ROAMS", "RENCE", "HEPPE", "OLNUC", "PDT", "ZUTED", "ALW", "RENGO", "BIDDY", "LEKIC", "PUW", "PENAE", "JETTS", "MLP", "FIKAB", "VAILL", "FCA", "KIVVE", "GAPAR", "PIKUN", "CHOTE", "DATSA", "GTF", "URELE", "ANNEM", "FALDE", "SWEDD", "GODFE", "MENAR", "BZN", "SHR", "HERKA", "MIDGE", "GCC", "WUVUT", "ECS", "ZAMBI", "RAP"]},
+    "V537":{ "name":"V537", "fixes":["PBI", "WHELM", "STOOP", "TRV", "TPSTR", "DEARY", "JIHMU", "PRESK", "CERMO", "VANNI", "OCF", "LEJKO", "GNV", "ALVIN", "GEF"]},
+    "V538":{ "name":"V538", "fixes":["TNP", "JOTNU", "ZELMA", "GFS", "CRESO", "LAS"]},
+    "V539":{ "name":"V539", "fixes":["EYW", "CORGI", "KARTR", "GOODY", "MILES", "RSW"]},
+    "V54":{ "name":"V54", "fixes":["ACT", "OVFAC", "FEPHY", "IMIPE", "DRILL", "THING", "CQY", "AWOLF", "UIM", "HEBIP", "ZUKOS", "GUDEC", "TXK", "WASHO", "MUFRE", "CANEY", "MALVE", "BAUDE", "LIT", "QITXO", "ATERS", "BILLI", "DRAST", "UJM", "JEPOB", "WSTON", "YUGPU", "HLI", "NUJLE", "SULLY", "KERMI", "BRADS", "TILVY", "AYOTE", "MSL", "TINCA", "TANNE", "RQZ", "PRONE", "COMAR", "GQO", "CRAND", "MADOL", "MELLS", "HRS", "DAYEL", "DILLA", "SUNET", "RESTS", "CLEVA", "UNMAN", "SPA", "GAFFE", "BRYDE", "CLT", "LOCAS", "ZOPOC", "GIPPR", "PEKNN", "RELPY", "SDZ", "RAEFO", "LORRY", "FAY", "BYRNE", "MANWE", "JOSCH", "ISO"]},
+    "V540":{ "name":"V540", "fixes":["CNG", "TAMMS", "PAMPI", "ALING", "DUEAS", "FAM"]},
+    "V541":{ "name":"V541", "fixes":["GAD", "ARBEE", "AWPOJ", "EDDIE", "HOBBI", "DCU", "MSL"]},
+    "V542":{ "name":"V542", "fixes":["ROD", "BUZZI", "LAWTO", "JUVDU", "MFD", "JUSEP", "READS", "DALTS", "JOSEF", "ACO", "YNG", "HAGAR", "TDT", "BFD", "CAFKI", "EXALL", "ULW", "CFB", "GROWS", "OXFOR", "RKA", "MILID", "SUMIT", "SHAHE", "ALB", "TIMKE", "CAM", "JAMMA", "BAUER", "LEB"]},
+    "V543":{ "name":"V543", "fixes":["LEV", "PEPSI", "GOING", "SAFES", "RAYOP", "WAVEZ", "OYSTY", "RYTHM", "CILVU", "LBY", "BAING", "PAULD", "MEI"]},
+    "V545":{ "name":"V545", "fixes":["MLS", "FESTU", "MARRO", "OYICE", "YAFLU", "GINBE", "OFETI", "ISN"]},
+    "V546":{ "name":"V546", "fixes":["INK", "YOGSU", "MAF", "QUADZ", "BGS"]},
+    "V547":{ "name":"V547", "fixes":["CYS", "HOCXU", "JEZZY", "POLDE", "IIP", "GLEES", "DDY"]},
+    "V548":{ "name":"V548", "fixes":["HUB", "DREWZ", "SEALY", "PRARI", "COUTH", "JEPED", "CLL", "THONY", "YOBUR", "DRPPD", "RIFFY", "BUSTS", "BARBA", "BARES", "ONUPY", "BOSEL", "ACT"]},
+    "V549":{ "name":"V549", "fixes":["HYS", "PUQZE", "MAWNO", "TKO"]},
+    "V55":{ "name":"V55", "fixes":["DQN", "ROSSY", "HIGLA", "BOOKS", "BERNE", "FWA", "WERBU", "GSH", "GIJ", "ELX", "PMM", "ZEELE", "SINNI", "MKG", "WHALL", "YULNU", "NEROE", "JAVAM", "PRIME", "GRB", "BECKY", "COMTS", "BIPID", "STE", "BELGO", "EAU", "TONOC", "ALEEN", "RZN", "ZOVNA", "WENIB", "LINDR", "BRD", "CUCAC", "PKD", "STRAW", "BETRA", "AKKIF", "JIXIR", "GFK", "UYTAG", "BEHQY", "SANDD", "YIRNU", "BIS"]},
+    "V550":{ "name":"V550", "fixes":["COT", "MILET", "LEMIG", "SAT", "PINCH", "CWK"]},
+    "V551":{ "name":"V551", "fixes":["SLN", "IKDEW", "TKO"]},
+    "V552":{ "name":"V552", "fixes":["BPT", "PEVET", "OFERS", "STRUT", "LCH", "HATHA", "SWIFF", "RAYNE", "LFT", "CLYNT", "HATCH", "CUSAL", "GRICE", "WAGPO", "TBD", "OLEDD", "SAFES", "HRV", "SNAKI", "PCU", "STENN", "CAESA", "MINDO", "SCALY", "OBOES", "SUVOC", "SJI", "STETS", "YORUP", "MVC"]},
+    "V553":{ "name":"V553", "fixes":["SLN", "URAVY", "ENUBE", "HURDO", "PWE"]},
+    "V554":{ "name":"V554", "fixes":["HEZ", "PISAN", "TULLO", "BOSCY", "MLU"]},
+    "V555":{ "name":"V555", "fixes":["PCU", "DUNBE", "CILVU", "MCB"]},
+    "V556":{ "name":"V556", "fixes":["SJT", "CHILD", "JCT", "ARPER", "STV", "GOBBY", "BETTI", "MARCS", "SEEDS", "WEMAR", "FFSSH", "WHAEL", "ELA", "KEEDS", "VUH", "BOLOS", "SBI"]},
+    "V558":{ "name":"V558", "fixes":["LLO", "SLIMM", "KALLA", "CWK", "MOUZE", "IDU", "ELA", "GLAND", "BLUMS", "HUB"]},
+    "V559":{ "name":"V559", "fixes":["LFT", "ZUNOE", "BEDDY", "SALVO", "LSU"]},
+    "V56":{ "name":"V56", "fixes":["MEI", "EWA", "JAILS", "BENTO", "NUMTE", "MGM", "CECAL", "SILOS", "TGE", "DRYDN", "CRAWL", "MARVO", "CSG", "GEMMY", "TALBO", "PRATZ", "OTVEZ", "ROBBS", "MCN", "RIPPI", "HADOC", "MISTY", "HARLE", "IRQ", "GRAZE", "SAMMI", "STEET", "CAE", "HOPKI", "COINT", "CHART", "SHEBA", "LARDS", "FLO", "TROCK", "ROWEL", "CEGAD", "FAY", "ROZBO", "WALLO", "BEULA", "FONPO", "KROVE", "EWN"]},
+    "V560":{ "name":"V560", "fixes":["EWM", "PRISO", "PIERS", "WHOLE", "DECAN", "MAYFY", "CONNE", "SFL", "DILLI", "LANIC", "CNM"]},
+    "V561":{ "name":"V561", "fixes":["GFK", "UNIZY", "JMS", "PIR"]},
+    "V562":{ "name":"V562", "fixes":["PXR", "KNOBB", "RADOM", "ZCARR", "FERER", "DRK", "APEMY", "PGS", "MILKI", "CROWE", "MEADS", "BAMAA", "LAPIN", "KIDDS", "LAS"]},
+    "V563":{ "name":"V563", "fixes":["LBB", "WINEY", "YOTUD", "YALUT", "BGS"]},
+    "V564":{ "name":"V564", "fixes":["OAL", "MVA", "YERIN", "RYANN", "CHIME", "FMG"]},
+    "V565":{ "name":"V565", "fixes":["LLO", "FRUGG", "AMUSE", "CWK", "SCOLL", "KABBA", "OSUME", "CLL", "OSCER", "LFK"]},
+    "V566":{ "name":"V566", "fixes":["GGG", "PODCI", "WORKS", "KANNE", "EIC", "AYEEE", "LUCEN", "KNELT", "COVEX", "MARTA", "NUBOY", "BOYCE", "AEX", "MUSHE", "FISTY", "WRACK", "DOCET", "CAZZZ", "DILLS", "EYEKI", "VEILS", "RQR"]},
+    "V567":{ "name":"V567", "fixes":["PXR", "KNOBB", "RADOM", "ZCARR", "FERER", "INW"]},
+    "V568":{ "name":"V568", "fixes":["CRP", "EJUXO", "ATHIS", "CARTI", "OTWED", "THX", "TINIE", "OTVIW", "LEMIG", "SAT", "GUADA", "STV", "CORVY", "LLO", "BUILT", "JEN", "MQP", "MUZZO", "SHAKY", "KARYN", "SPS"]},
+    "V569":{ "name":"V569", "fixes":["BPT", "SILBE", "ROMER", "LFK", "MIGDE", "FZT", "HEXAS", "CQY"]},
+    "V57":{ "name":"V57", "fixes":["HYK", "SADDL", "FLM"]},
+    "V570":{ "name":"V570", "fixes":["AEX", "LARTO", "NIFTE", "HEZ", "RUCBO", "GOBTY", "MCB"]},
+    "V571":{ "name":"V571", "fixes":["IAH", "TNV", "OXITY", "LOA", "KISER", "ALLMO", "CQY"]},
+    "V572":{ "name":"V572", "fixes":["INW", "MAZDA", "FRISY", "FLG"]},
+    "V573":{ "name":"V573", "fixes":["IRW", "CESTA", "ALEXX", "ADM", "TEYUS", "YOGVA", "CAINE", "BYP", "SLR", "JAXAB", "OSUYE", "TXK", "TOYOY", "PIKES", "ELMMO", "APINE", "MARKI", "HOT", "LONNS", "TAYUV", "BEGAN", "JENAN", "LIT"]},
+    "V574":{ "name":"V574", "fixes":["CWK", "MOUZE", "TNV", "IAH", "REHAB", "INNIS", "DAETN", "DAYBO", "DAS", "BPT", "WASPY", "LCH"]},
+    "V575":{ "name":"V575", "fixes":["LAR", "RAMMS", "NIWOT", "PRONG", "WOLTS", "DVV"]},
+    "V576":{ "name":"V576", "fixes":["PSB", "SWISS", "ZAGTI", "FQM", "NOSEE", "HNK", "DNY"]},
+    "V577":{ "name":"V577", "fixes":["VCN", "BRIGS"]},
+    "V578":{ "name":"V578", "fixes":["PZD", "CHULA", "IFM", "IBEBE", "UPTON", "AMG", "WABIT", "BARWU", "JANIE", "SAV"]},
+    "V579":{ "name":"V579", "fixes":["RSW", "PINTS", "VIOLA", "SRQ", "JRGAL", "PIE", "BAYPO", "NITTS", "PERSE", "GNV", "CTY", "HADDE", "OTK", "JOGOS", "WALPI", "IFM", "ROCKM", "HIDBI", "HANET", "VNA"]},
+    "V58":{ "name":"V58", "fixes":["GRACE", "EARED", "PSB", "SWISS", "ZAGTI", "FQM", "HELON", "SPECL", "IGN", "DEEDE", "MOONI", "JUDDS", "HFD", "THUMB", "ARENE", "SALEM", "GON", "TRAIT", "SEY", "NEWBE", "BENNT", "ACK"]},
+    "V580":{ "name":"V580", "fixes":["STL", "LEBOY", "SEXTN", "BRL"]},
+    "V581":{ "name":"V581", "fixes":["PIE", "TUMPY", "DADES", "LIMMO", "OCF"]},
+    "V582":{ "name":"V582", "fixes":["STL", "LEBOY", "UIN"]},
+    "V583":{ "name":"V583", "fixes":["CWK", "TOAMY", "CLL", "GIFLE", "LOA", "OXAKY", "FZT", "BOLRE", "UIM", "JAXAB", "PRX", "MLC"]},
+    "V584":{ "name":"V584", "fixes":["VWV", "AMRST", "HUDDZ", "DJB"]},
+    "V586":{ "name":"V586", "fixes":["EXCEL", "POYOL", "MCM", "UIN", "ALUGE", "BADER", "PIA", "MAROC", "HUMUL", "PNT", "MOTIF", "MINOK", "JOT"]},
+    "V587":{ "name":"V587", "fixes":["HDF", "ACINS", "DAWNA", "RESOR", "LUCER", "BULGY", "DAG", "TEELE", "DANBY", "WHIGG", "WOPMA", "BOACH", "CRESO", "DICSA", "BLD"]},
+    "V589":{ "name":"V589", "fixes":["MBW", "ALCOS", "DDY"]},
+    "V59":{ "name":"V59", "fixes":["PSK", "WAKIS", "SOFTY", "ESTEM", "BKW", "GAULE", "ITALY", "WARDO", "EDSOE", "JPU", "CADRE", "LORES", "CTW", "DONUT", "BSV"]},
+    "V591":{ "name":"V591", "fixes":["JNC", "PACES", "EDUKY", "HUGSI", "RIYNO", "SLOLM", "GLENO", "LINDZ", "IDENE", "LILXO", "SXW", "UVTUH", "JESIE", "RLG"]},
+    "V595":{ "name":"V595", "fixes":["OED", "CUTTR", "COPPR", "DRACK", "DSD"]},
+    "V597":{ "name":"V597", "fixes":["RZS", "OHIGH", "FIM", "SESPE", "VNY", "DARTS", "DODGR", "SLI", "MIDDS", "BALBO", "KRAUZ", "DANAH", "KELPS", "OCN", "HURSI", "CARIF", "MZB"]},
+    "V599":{ "name":"V599", "fixes":["RSW", "TIRTE", "THNDR", "GILBI", "NEWER", "HOLID", "FRRDY", "DHP"]},
+    "V6":{ "name":"V6", "fixes":["OAK", "FESIK", "COLLI", "PITTS", "RYMAR", "REJOY", "COUPS", "SAC", "FOLLY", "CORLY", "COLOM", "SWR", "FMG", "WADDS", "LLC", "CUTVA", "RAJKO", "BAM", "DEGHU", "DOBYS", "ARAYI", "VODOU", "LWL", "LCU", "MOINT", "OGD", "EVIEW", "PACKY", "FBR", "WEGEM", "PUDVY", "OCS", "TOGUY", "ARUTE", "CKW", "EDIFY", "CEXIT", "MBW", "MOIST", "LITER", "ALBIN", "OMBIE", "APAYU", "SNY", "RIYOP", "KESSE", "SOKHA", "LBF", "YESUS", "YOZLE", "RAGAR", "DECKY", "GRI", "GRASI", "ITBEW", "DWELL", "HUSKR", "YUTAN", "GRETT", "OVR", "EYNOR", "PSFIC", "LYMAN", "UKIPE", "BRIDJ", "MIDLE", "DSM", "SINGR", "NASAL", "WELMA", "IOW", "MOSCO", "ZELMI", "CVA", "ENAME", "YOBUV", "LEECS", "WEPTA", "SHOOF", "START", "HERVY", "HINCK", "DPA", "NILES", "HARRT", "CHETT", "STYLE", "GIJ", "SEWTO", "BRYTO", "MODEM", "ZOSER", "PIONS", "LEYIR", "VWV", "DJB", "DROVE", "STUKL", "IXORE", "WEXER", "MOROW", "HIRES", "YNG", "SHANT", "MERCY", "CIP", "DBEAM", "LATEC", "PSB", "SEG", "SNOWY", "SLATT", "FJC", "LIZZI", "SBJ", "MABLE", "EMPYR", "NANCI", "RENUE", "APPLE", "TICKL", "PROUD", "DIALS", "LGA"]},
+    "V60":{ "name":"V60", "fixes":["GUP", "HERET", "CROIN", "CUBBA", "ABQ", "CYOTE", "OTO", "TAFOY", "FTI"]},
+    "V601":{ "name":"V601", "fixes":["PHK", "SWAGS", "DEEDS", "EYW"]},
+    "V605":{ "name":"V605", "fixes":["SPA", "GENOD", "HMV"]},
+    "V607":{ "name":"V607", "fixes":["ENI", "PLYAT", "JEPIT", "YAGER", "KNEES", "ACV"]},
+    "V609":{ "name":"V609", "fixes":["MBS", "BENNY", "WELVI", "BANJO", "ZABLE", "SPARR", "RONDO", "OTREE", "PLN"]},
+    "V61":{ "name":"V61", "fixes":["GRI", "NUCDI", "TEVUW", "VACUS", "PWE", "RBA", "JUDAA", "BOWLR"]},
+    "V611":{ "name":"V611", "fixes":["EWM", "WATEX", "WIKKR", "MOLLY", "FRIAN", "CAGEV", "DUCAS", "TCS", "WOLKI", "BOTAW", "ONM", "ABQ", "NODME", "NELGE", "LIYIR", "SAF", "FTI", "CELAV", "ADOZO", "CIM", "FENON", "TATKE", "GOSIP", "VIGIL", "HUNER", "PUB", "ZITUG", "JOWEE", "BRK", "LUFSE", "JEFEL", "LIMEX", "WITNE", "YIMZO", "ZERNA", "WAVDI", "CEDUK", "GLL", "KROMM", "CIKNU", "CYS", "MOIST", "HEITY", "DEALT", "DDY", "EBIYO", "CZI", "SHERZ", "SHR", "PARBE", "KRONA", "BIL", "POCOV", "SHELA", "ESTRO", "CIWXU", "LWT", "ANALE", "SHONK", "BELCA", "YOYNO", "HVR"]},
+    "V613":{ "name":"V613", "fixes":["FJC", "RACKI", "LVZ"]},
+    "V615":{ "name":"V615", "fixes":["RDU", "HIKOR", "ARGAL", "MEYER", "DUFFI", "GEPKE", "HPW"]},
+    "V62":{ "name":"V62", "fixes":["GUP", "HERET", "CROIN", "CABZO", "PEDRA", "ZIASE", "HEGMI", "SAF", "ECISA", "RENCO", "TAFOY", "ACH", "FLUTY", "SELPE", "TXO", "SPADE", "LBB", "HYDRO", "WABVI", "ROTAN", "ABI", "FLECK", "GEENI", "CADES", "ZOSKU", "SICUM", "JEN"]},
+    "V623":{ "name":"V623", "fixes":["SAX", "SEAVY", "ESJAY", "PINNS", "CMK"]},
+    "V625":{ "name":"V625", "fixes":["BITVE", "OLS"]},
+    "V626":{ "name":"V626", "fixes":["YMONT", "MTU"]},
+    "V629":{ "name":"V629", "fixes":["SHUSS", "BLD"]},
+    "V63":{ "name":"V63", "fixes":["UKW", "TEYUS", "URH", "MLC", "BUKSE", "KLUBB", "GORES", "VIANE", "BUTCH", "SWALL", "SUMMO", "INOTE", "RZC", "GAMPS", "CITGA", "SUEEY", "JENKY", "BILIE", "RIZUR", "SGF", "PLADD", "RUZSU", "LOJOV", "ROACH", "BARTI", "JICDA", "MIZZU", "GIBSN", "HLV", "ALHAH", "UIN", "COBOD", "KAMIW", "EBSER", "BRL", "KOOLL", "KALKY", "MZV", "CVA", "MIHAL", "RFD", "JVL", "DEBOW", "RASTT", "GREAS", "BAE", "CORIR", "EDENN", "OSH", "LIMME", "STE", "TAYUY", "AUW", "ENETE", "ZUPIG", "YANUT", "RHI", "JAYME", "CUSAS", "CMX"]},
+    "V64":{ "name":"V64", "fixes":["LAX", "LIMBO", "WILMA", "SLI", "TUSTI", "WOKRO", "COREL", "NIKKL", "PERIS", "HEMET", "HAPPE", "BALDI", "CORLA", "TRM", "SHADI", "BLH"]},
+    "V66":{ "name":"V66", "fixes":["MZB", "HAILE", "RYAHH", "BARET", "CANNO", "PILLO", "GREED", "KUMBA", "NICKK", "IPL", "ARGUS", "HEEDS", "ARAZI", "BZA", "WARTT", "MOHAK", "JUDTH", "GBN", "FLIER", "ALMON", "TORTS", "TUS", "OBISE", "SULLI", "MESCA", "TOMBS", "JORTO", "CAYLA", "YIRTU", "DEYNE", "IZOSI", "DUG", "IZMIR", "ANIMA", "DARCE", "CUS", "HANCH", "ELP", "TYLAN", "FABAN", "HUP", "PEQ", "ALLYN", "LOPEY", "MAF", "BYPAS", "TAYOL", "HYMAN", "NOLAN", "TYEES", "ABI", "TRUSS", "WAPEV", "MQP", "LDK", "ZIVMU", "OKW", "HEENA", "KYLEE", "CAMPP", "LGC", "LANGA", "CANER", "GRANT", "HUZER", "SMARR", "SINCA", "GLOSS", "MADDI", "JOTNO", "DACHA", "AHN", "GRD", "WILLS", "TAYSO", "RICHE", "NATCH", "SDZ", "OCHOC", "MOATS", "RDU", "HIKOR", "ARGAL", "MEYER", "DUFFI", "GUMBE", "FKN"]},
+    "V67":{ "name":"V67", "fixes":["GQO", "TOBAY", "NOGIC", "SYI", "TUNGY", "GHM", "LANKY", "NUBEE", "KABLE", "CNG", "UBJUF", "BUNCO", "MWA", "AYAZE", "ENL", "CORKI", "VLA", "CLEEK", "EDINS", "SPI", "ULAXY", "ATTIC", "BADER", "HAKAV", "BRL", "UTXIH", "WAPEL", "IOW", "CID", "VINTY", "LYERS", "ALO", "FOYDE", "YESUR", "RST"]},
+    "V68":{ "name":"V68", "fixes":["MTJ", "DEYUC", "ETL", "HAVWU", "DVC", "YURVE", "CEZ", "PLATA", "RSK", "OTINS", "HUXZI", "PEDRA", "ABQ", "BEANN", "CABUS", "WARRE", "CNX", "REYOK", "HONDS", "JOGPO", "CME", "WOKUM", "HAGER", "WEDUT", "KUCEY", "YOYUR", "HOB", "ZUSDA", "GECKE", "ANEEL", "PIZON", "MAF", "MIPEE", "JOKES", "DEWEY", "STEEP", "TANKR", "SJT", "EDWAR", "JCT", "CSI", "BENEY", "MEDIN", "REUBE", "SAT", "CRISS", "TROOP", "BRAUN", "MARCS", "CRAYS", "IDU", "SEALY", "DREWZ", "HUB"]},
+    "V69":{ "name":"V69", "fixes":["ELD", "ARIRE", "HAMPT", "JUSGA", "ZAMTU", "RISON", "PBF", "UBECA", "BILLI", "HILLE", "ARG", "GACES", "UMWIX", "LEPER", "FAM", "SELLY", "TOY", "PRAYS", "GIFTS", "LITCH", "AUBUR", "DUPON", "SPI", "ALAND", "MCLEN", "MERKY", "KAPPA", "YEARY", "PNT", "MOTIF", "MINOK", "JOT"]},
+    "V7":{ "name":"V7", "fixes":["DHP", "WUDIP", "KUBIC", "SWAGS", "FORTL", "RSW", "SERFS", "JOCKS", "ROGAN", "CROWD", "LAL", "PLUMY", "JUVAS", "DADES", "NITTS", "ORATE", "CTY", "CILLA", "CODYS", "OLUGY", "SZW", "SAIML", "RADME", "OALDY", "IVCOB", "RRS", "EGEST", "SKIPO", "CLIOS", "BANBI", "PETRY", "SHADY", "JEDOP", "MGM", "BOWIN", "CIPBA", "GOTBY", "VUZ", "SIPSY", "NATAN", "JOHNY", "LANER", "YOSNU", "MSL", "RESGE", "GILLE", "POLAN", "GHM", "DELHA", "VALER", "GNSHP", "WASMO", "CCT", "GEPER", "DIXEY", "ARLUV", "PXV", "PRINC", "APUFO", "LISLE", "GOZUM", "LUPCE", "TTH", "VANJI", "WAVEL", "ALLOE", "WENGS", "POTES", "BVT", "OXFAT", "ZORRO", "LUCIT", "COKED", "CGT", "NILES", "BEBEE", "LAIRD", "THORR", "DEERE", "PAPPI", "TALOR", "PETTY", "HOGMI", "PROOT", "WOKNO", "CYNDI", "FAH", "MURRI", "CLINS", "WAFLE", "GRB", "WARWF", "MNM", "VUKFI", "EVYIP", "SAW"]},
+    "V70":{ "name":"V70", "fixes":["MTY", "ACREW", "CFGBH", "BRO", "CAMER", "HIRLI", "MADRE", "RAYMO", "JIMIE", "LOCOE", "JETTY", "CRP", "COPAN", "BETZY", "BOINT", "PSX", "EZAFU", "ECHOE", "LETTY", "AGGIT", "DELVE", "VUH", "BOLOS", "SBI", "MARSA", "POPEY", "HIDUR", "LCH", "ARTEL", "CRISP", "MICRO", "ZIROR", "LFT", "ROSEY", "TATER", "LSU", "DILLS", "WALKE", "TICKS", "RYTHM", "FRANK", "PCU", "WIGGO", "GCV", "ERNON", "MVC", "CHAFF", "RUTEL", "YIBYI", "CRENS", "BANBI", "CHIRP", "EUF", "LUMPP", "AMAPO", "LILLY", "GUVNR", "GAMSE", "VNA", "RATOC", "OCONE", "KLICK", "MILEN", "ALD", "CRE", "CHAMS", "WYLMS", "BILLL", "ILM", "GOLLA", "BEULA", "ISO", "PIDEE", "PEARS", "CVI"]},
+    "V71":{ "name":"V71", "fixes":["LSU", "RELAY", "WRACK", "HEZ", "ZAROX", "MLU", "ZETEG", "FLESH", "ELD", "DODBE", "SPARO", "CANEY", "HOT", "GATZY", "OLLAS", "HAAWK", "JASPE", "HRO", "RASON", "REEDS", "ENDRS", "SPOKE", "SGF", "SHIRE", "ATOPE", "STARE", "BUM", "CUNON", "DODSN", "TOP", "PWE", "PANNY", "JOTEB", "LNK", "DWELL", "OLU", "ERGUC", "ONL", "ADEDY", "ISD", "JAGSO", "WABAM", "PIR", "THORE", "GILTE", "ILECU", "BAYAF", "YAITS", "LINTN", "ODUFA", "BIS", "CENTR", "BULAH", "POVNY", "FORBI", "ISN"]},
+    "V72":{ "name":"V72", "fixes":["RZC", "TEEUP", "EDUGE", "JEPRO", "HARKS", "ONITY", "WUTIB", "REEDS", "DGD", "MODNY", "MUPIE", "GOBEY", "DUFAL", "MAP", "BUNKS", "FAM", "NIKEL", "SUMAN", "ENL", "KENBE", "BIB", "MOBBY", "MTO", "ZARIR", "REGOY", "MOCEL", "THEME", "BMI"]},
+    "V73":{ "name":"V73", "fixes":["TUL", "LOMAC", "FRAKS", "WAKOP", "JETBU", "CAWBU", "ICT", "MUGER", "WUKOL", "WUKUS", "HUT", "ZUPAB", "GUTER", "AWHOV", "LENIN", "SLN"]},
+    "V74":{ "name":"V74", "fixes":["GCK", "ONIPE", "KUDIC", "POKPE", "HEPVA", "DDC", "SAFER", "ANY", "DOREC", "PER", "MANON", "HOMIN", "STEBB", "TUL", "OWETA", "MALTS", "BUTCH", "LAVER", "AWIJE", "FSM", "CHARR", "MAGGA", "DANIL", "OLLAS", "MAUME", "LIT", "HOBER", "MOMTE", "PBF", "IYTEL", "JUPDA", "GLH", "DESKE", "WOSBU", "MHZ"]},
+    "V75":{ "name":"V75", "fixes":["MGW", "LEFSO", "AIR", "ATWOO", "BSV", "JOSEF", "KEATN", "RITZS", "SAROW", "DJB", "CAKEB", "LLEEO"]},
+    "V76":{ "name":"V76", "fixes":["LBB", "JUNVA", "SLIDE", "ZOPNI", "WELCH", "PATTS", "VUCUL", "BGS", "HYMAN", "WATOR", "JIGEM", "SJT", "EVILE", "BREDY", "LLO", "MOGWI", "BASIS", "CWK", "MOUZE", "IDU", "SEALY", "DREWZ", "HUB"]},
+    "V77":{ "name":"V77", "fixes":["SJT", "CUGPA", "OWENN", "SHEPP", "ABI", "AJAHO", "VAYTU", "MEGGA", "POSTE", "SPS", "WALTO", "TEYUV", "FOYER", "FLECH", "NEADS", "IRW", "CASTN", "WENDY", "LARKO", "ALCOR", "PER", "BIKCA", "DOTEE", "JAMEY", "TEROY", "ICT", "FLOSS", "WILSY", "HEYDN", "DIETS", "TOP", "BOWLR", "STJ", "TOSAE", "LMN", "WIVEY", "DSM", "ZAGTU", "MIXIN", "TNU", "HAKES", "NEVIS", "ALO", "ZEZDU", "UKN"]},
+    "V78":{ "name":"V78", "fixes":["HON", "OPODY", "CAGUX", "AYUNE", "ATY", "DAWSO", "ARDUE", "CLAPS", "FITAS", "DWN", "PIKAW", "GEP", "WHISK", "STILS", "AGUDE", "BOSEN", "EAU", "BAITS", "FASUX", "RHI", "CAYAN", "IMT", "VUKFI", "ESC", "ISQ", "DIPLE", "BETAY", "JATRA", "PLN", "RABBO", "APN", "ZABLE", "BANJO", "WELVI", "BENNY", "MBS"]},
+    "V79":{ "name":"V79", "fixes":["HSI", "ROMAD", "IVEHO", "NUCDI", "LNK"]},
+    "V8":{ "name":"V8", "fixes":["DOYLE", "TANDY", "INISH", "LIMBO", "WILMA", "SLI", "AHEIM", "OLLIE", "POXKU", "EBITE", "PDZ", "CIVET", "RAVON", "GAREY", "ARRAN", "DAWNA", "RESOR", "LUCER", "BULGY", "HEC", "GFS", "SHUSS", "LYNSY", "WINDS", "ACLAM", "MEADS", "MMM", "PHYLI", "JITKA", "JEZOB", "MATZO", "POBME", "CEXAT", "ETYIR", "BCE", "MOJVI", "UJACI", "HVE", "KIDNE", "EDLES", "ARCHH", "ZUKSO", "JNC", "PATUC", "SQUAT", "HORST", "RIL", "COMFR", "TRUEL", "UVTUH", "HABUX", "RLG", "PENEY", "DVV", "HOYTT", "AKO", "ETUDE", "OGLIE", "LINVE", "ASHBY", "ATCAY", "SIJVI", "HCT", "FIMER", "TOKKU", "POOLS", "ADRUM", "GRI", "GRASI", "ITBEW", "DWELL", "HUSKR", "YUTAN", "GRETT", "OVR", "EYNOR", "PSFIC", "LYMAN", "UKIPE", "BRIDJ", "MIDLE", "DSM", "SINGR", "NASAL", "WELMA", "IOW", "CHOLS", "BUFAL", "MZV", "GENSO", "WYNET", "TRIDE", "URRBS", "AHMED", "BENKY", "JOT", "CGT", "HALIE", "INKEN", "NOMES", "GSH", "RABBT", "GAREN", "GRABI", "TWERP", "FBC", "DUSKY", "MFD", "JUSEP", "READS", "DALTS", "BSV", "ATWOO", "AIR", "AHTIY", "OBEID", "GALLS", "GRV", "ELGEE", "MRB", "LUCKE", "RAYEE", "DCA"]},
+    "V80":{ "name":"V80", "fixes":["AKO", "CITMU", "NACIK", "HOLYO", "UYOGI", "LBF", "OGEZO", "ECYUS", "BOKKI", "JIKNU", "ONL", "CURIR", "TYNDA", "PUKIC", "DOLTS", "FSD"]},
+    "V81":{ "name":"V81", "fixes":["CUU", "ALKEM", "MRF", "VUYUP", "FST", "OHARA", "MAF", "MERGE", "PATTS", "WELCH", "ZOPNI", "SLIDE", "JUNVA", "LBB", "PIBCI", "ZONLO", "PVW", "YOCAN", "PNH", "LANTT", "EXELL", "DHT", "COYAG", "EPAYI", "ACAGU", "TBE", "BLOOM", "STAXX", "EYULE", "PUB", "ZITUG", "JOWEE", "BRK", "HOHUM", "SIGNE", "BJC", "LPORT", "WISER", "BENNE", "CYS", "VIDEE", "ALBIN", "BFF", "OFOWY", "SPONS", "TST"]},
+    "V82":{ "name":"V82", "fixes":["BDE", "ZEBES", "IMUKE", "FATIK", "BLUOX", "RECOS", "HUUTA", "BRD", "YEPSU", "GOLLF", "OLLEE", "PLUGS", "ZAPIN", "SAUGR", "GEP", "FGT", "FOBUG", "DOKTR", "CORDY", "RST", "DLANY", "DIMMY", "ODI", "BOOTY", "FAPKO", "DLL"]},
+    "V83":{ "name":"V83", "fixes":["CNM", "ROHYO", "FATAP", "NELON", "IPNUC", "CME", "JOGPO", "HONDS", "REYOK", "CNX", "RUINS", "OTO", "CAYAL", "LACRO", "SAF", "VECUT", "NAMBE", "POAKE", "ZEDAN", "NAXUE", "DIXAN", "TELOY", "TAS", "ZOTOS", "LYSSA", "MASSA", "ALS", "BLOKE", "ACHES", "GOSIP", "VIGIL", "HUNER", "PUB", "DRAKE", "BRK"]},
+    "V84":{ "name":"V84", "fixes":["OBK", "WARPI", "PAPPI", "KUBBS", "STORY", "PIVOT", "PEEPS", "JYBEE", "CLAUD", "PMM", "BOHRR", "LAN", "ERRYS", "FNT", "BUF", "GEE", "UMAGY", "BEEPS", "RODAN", "SYR"]},
+    "V85":{ "name":"V85", "fixes":["FQF", "FIPSS", "HYGEN", "TOMSN", "ALLAN", "RIDJE", "OCETE", "LAR", "PUCIP", "YEKUS", "MBW", "MULTI", "EVENT", "DDY", "JUMKO", "RIW", "FETIK", "BOY", "NICQE", "COD", "SEZJI", "SOLME", "EDDAR", "BIL"]},
+    "V86":{ "name":"V86", "fixes":["MSO", "TAGOE", "PUNNS", "WAKIX", "UBIJO", "CPN", "MARRG", "HIA", "BZN", "ZUBLI", "LVM", "SUBKY", "REEPO", "COLUS", "NARUW", "BIL", "KRONA", "PARBE", "SHR", "WETON", "IMUNE", "KOCYE", "KARAS", "ROCNO", "PACTO", "RAP"]},
+    "V87":{ "name":"V87", "fixes":["PXN", "RANCK", "RUDNY", "SNS", "MOVER", "SANTY", "SAPID", "OSI", "SFO", "REBAS", "SGD"]},
+    "V88":{ "name":"V88", "fixes":["TUL", "BICEP", "VINTA", "NARCI", "NERNE", "WACCO", "QUALM", "SGF", "ROBCO", "LANEZ", "STEME", "STOUT", "REBBS", "VIH", "STEER", "EMKAA", "FEKRO", "TOY"]},
+    "V89":{ "name":"V89", "fixes":["GLL", "AIMES", "PACHE", "CRIMS", "HAMER", "CYS", "POGTE", "LITER", "WHARF", "TST"]},
+    "V9":{ "name":"V9", "fixes":["LEV", "PEPSI", "GOING", "SAFES", "RAYOP", "WAVEZ", "OYSTY", "RYTHM", "FOILS", "ZYDCO", "MCB", "CEVDA", "CIAAA", "ROMAR", "JOTEK", "MHZ", "BOOSI", "YONUD", "SQS", "GUBEC", "TILUC", "AKAYI", "AYOBA", "PAULH", "UJM", "FAREB", "GQE", "ICJIX", "OPSEE", "MAW", "SOBAW", "MOGYU", "FAM", "MOJOB", "SLVER", "GLASS", "ARNOL", "IMPER", "MERAM", "STL", "ELDON", "FASHE", "LOFTY", "WAVLY", "SPI", "ALAND", "MCLEN", "MERKY", "KAPPA", "YEARY", "PNT", "SMARS", "KELSI", "URRBS", "SHOOF", "RFD", "JVL", "TAVNE", "PASYO", "GARTT", "MSN", "RANDO", "DOYAG", "BADAN", "OSH", "GRB", "SPRYS", "CRAZE", "IMT", "EMQIF", "CIBPA", "CMX"]},
+    "V90":{ "name":"V90", "fixes":["SVM", "COFGI", "MOONN", "BROKK", "BEWEL", "DKK"]},
+    "V91":{ "name":"V91", "fixes":["SARDI", "CCC", "BELTT", "NESSI", "BDR", "TRUDE", "SOARS", "MOONI", "STUBY", "BOWAN", "CIRRU", "ALB", "GFL", "ENSON", "WEIGH", "WINLA", "BTV"]},
+    "V92":{ "name":"V92", "fixes":["BEBEE", "NILES", "CGT", "HALIE", "INKEN", "NOMES", "GSH", "BAGEL", "ILTON", "EDGEE", "VWV", "KOREW", "REELS", "VIZXO", "MFD", "TVT", "CTW", "WISVA", "AIR", "AHTIY", "OBEID", "GALLS", "GRV", "KEYER", "CAPON", "TRIXY", "HOAGE", "JASEN", "MANNE", "GILBY", "AML"]},
+    "V93":{ "name":"V93", "fixes":["PXT", "LOUIE", "GRACO", "PALEO", "BAL", "MEHAN", "SKILS", "TAFFI", "SHILO", "VINNY", "ROAST", "LRP", "DUMMR", "HAILS", "SNOWY", "KRAZE", "LYTEL", "GIDEC", "LVZ", "LAAYK", "HELON", "SPECL", "IGN", "PWL", "STUBY", "SASHA", "MOLDS", "CTR", "WHATE", "WARIC", "EEN", "TAPSE", "CON", "SATAN", "ENE", "BRNNS", "RAZZR", "ACYOG", "TICBU", "BGR"]},
+    "V94":{ "name":"V94", "fixes":["BLH", "JAROZ", "SODSE", "VICKO", "SADLL", "GBN", "POTER", "TFD", "TOTEC", "CROME", "ITEMM", "DEPHE", "SSO", "KUNRE", "FAAST", "DMN", "AXARY", "SEMRE", "ZAXOX", "CRATT", "COSES", "MOLLY", "WIKKR", "WATEX", "EWM", "SFL", "DILLI", "CAVRN", "FEVOM", "INK", "YOGSU", "MAF", "BYPAS", "TAYOL", "HYMAN", "SHEPP", "TQA", "MEDLY", "SITNA", "GEENI", "CADES", "ZOSKU", "SICUM", "JEN", "CELTC", "ACUFF", "CQY", "SWANI", "SNOWE", "CAPTI", "OTTIF", "GODHO", "GGG", "TUYPO", "GIDER", "BEKEN", "LUCEN", "EMG", "JENNA", "WETER", "YAKUC", "MLU", "GALIO", "HEGOG", "AVONS", "GLH", "BARGE", "DEYEV", "AKAYI", "CRINK", "ZETUR", "VOSFY", "HLI", "JKS", "VALER", "ROGOE", "TEACH", "SPARE", "OSAYI", "BWG"]},
+    "V95":{ "name":"V95", "fixes":["GBN", "POTER", "PXR", "INW", "BUTTE", "CASTI", "DEXTR", "HUNVI", "GUVBE", "DERMA", "RSK", "DRO", "ZEANS", "LAZON", "POWES", "COGRI", "HBU", "ROMLY", "COBIX", "GORJE", "STAMY", "HOHUM", "FQF"]},
+    "V96":{ "name":"V96", "fixes":["VHP", "ZIPPY", "EDMEW", "HUBOP", "PASEW", "OKK", "FORCE", "YAVUS", "FWA", "NATTY", "TWERP", "ILLIE", "ANNTS", "CUSMA", "DXO"]},
+    "V97":{ "name":"V97", "fixes":["DHP", "WINCO", "LBV", "UTELE", "QUNCY", "ROGAN", "BRDGE", "GIBBS", "PIE", "DARBS", "TABIR", "PLYER", "CLAMP", "HEVVN", "ADDAX", "WOUND", "SZW", "RENOE", "LEBBY", "DOGGI", "ELMOE", "PZD", "BRONN", "WIPPS", "AMAPO", "WILMS", "PRATZ", "GRANT", "BOWLN", "OLISY", "ATL", "BAPPY", "ENSOR", "NELLO", "MELLS", "MARBL", "OLBUE", "HINDE", "TALLA", "VXV", "NOISE", "LOZ", "REBEL", "HYK", "NEBIY", "GENUS", "DARKS", "ZIRKE", "CUCJU", "CVG", "MILAN", "SHB", "ZAVNE", "ZIPPY", "AZHUP", "OCKEL", "ZOFRI", "BVT", "OXFAT", "ZORRO", "LUCIT", "COKED", "CGT", "NILES", "BEBEE", "FARMM", "KRENA", "TEDDY", "BULLZ", "TIRRO", "LOCEN", "JVL", "ATOBE", "OMONE", "THEBO", "SARRO", "LNR", "HIRUM", "WEBYE", "ODI", "PEGGS", "TROLL", "MANIE", "PRESS", "KANAC", "ZASKY", "GEP"]},
+    "V98":{ "name":"V98", "fixes":["DQN", "HINES", "WOCKY", "PIONS", "RANDL", "MIZAR"]},
+    "V99":{ "name":"V99", "fixes":["LGA", "OUTTE", "VAGUS", "ANNEI", "TRUDE", "MERIT", "SORRY", "YALER", "HFD"]}
+};
diff --git a/PerformanceTests/RexBench/FlightPlanner/benchmark.js b/PerformanceTests/RexBench/FlightPlanner/benchmark.js
new file mode 100644 (file)
index 0000000..0386c21
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+"use strict";
+
+let currentTime;
+if (this.performance && performance.now)
+    currentTime = function() { return performance.now() };
+else if (this.preciseTime)
+    currentTime = function() { return preciseTime() * 1000; };
+else
+    currentTime = function() { return +new Date(); };
+
+class FlightPlannerBenchmark {
+    constructor(verbose = 0)
+    {
+        this._verbose = verbose;
+    }
+
+    runIteration()
+    {
+        for (let iteration = 0; iteration < 10; ++iteration) {
+            setupUserWaypoints();
+            
+            for (let flightPlan of expectedFlightPlans) {
+                flightPlan.reset();
+                flightPlan.resolveRoute();
+            }
+        }
+        this.checkResults();
+    }
+
+    checkResults()
+    {
+        for (let flightPlan of expectedFlightPlans) {
+            flightPlan.calculate();
+            flightPlan.checkExpectations();
+        }
+    }
+}
+
+function runBenchmark()
+{
+    const verbose = 0;
+    const numIterations = 10;
+
+    let benchmark = new FlightPlannerBenchmark(verbose);
+
+    let before = currentTime();
+
+    for (let iteration = 0; iteration < numIterations; ++iteration)
+        benchmark.runIteration();
+    
+    let after = currentTime();
+
+    for (let iteration = 0; iteration < numIterations; ++iteration)
+        benchmark.checkResults();
+    
+    return after - before;
+}
+
+
+//  print("Benchmark ran in " + runBenchmark());
diff --git a/PerformanceTests/RexBench/FlightPlanner/convert-nfdc.py b/PerformanceTests/RexBench/FlightPlanner/convert-nfdc.py
new file mode 100644 (file)
index 0000000..3e298f0
--- /dev/null
@@ -0,0 +1,251 @@
+# Copyright (C) 2017 Apple Inc. All rights reserved.
+# Copyright (C) 2016-2017 Michael Saboff. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# This parses the legacy FAA NFDC text files APT.txt, AWY.txt, NAV.txt
+# and FIX.txt into a JavaScript format that he Flight Planner can use.
+# These text files can be downloaded from the FAA at
+# https://nfdc.faa.gov/xwiki/bin/view/NFDC/28+Day+NASR+Subscription
+# This script generates two JavaScript object literal files, one for
+# waypoints and the other for airways.  Both files create maps, where
+# the key is the waypoint or airway identifier and the value is the
+# corresponding data.
+#
+# Run this file in a directory where APT.txt, AWY.txt, NAV.txt and FIX.txt
+# are downloaded.
+
+import re
+
+latLongRE = re.compile('\s*(\d+)-(\d{2})-(\d{2}.\d{3,8})([NS])\s*(\d+)-(\d{2})-(\d{2}.\d{3,8})([EW])')
+statesAbbreviationsToExclude = ['AK', 'HI']
+navaidsToInclude = ['VOR', 'NDB']
+airwayFixTypes = frozenset(['CN', 'NDB/DME', 'NDB', 'MIL-REP-PT', 'REP-PT', 'RNAV', 'VOR', 'VOR/DME', 'VORTAC'])
+airwayTypes = frozenset(['J', 'T', 'Q', 'V'])
+
+
+class WaypointData:
+    def __init__(self):
+        self.waypoints = []
+        self.allNames = set()
+
+    def parseLatLongDMS(self, latLongString):
+        match = latLongRE.match(latLongString)
+        latitude = float(match.group(1)) + (float(match.group(2)) * 60 + float(match.group(3))) / 3600
+        if match.group(4) == 'S':
+            latitude = -latitude
+
+        longitude = float(match.group(5)) + (float(match.group(6)) * 60 + float(match.group(7))) / 3600
+        if match.group(8) == 'W':
+            longitude = -longitude
+
+        return (latitude, longitude)
+
+    def parseAirportData(self, airportFile):
+        file = open(airportFile, 'r')
+
+        for line in file:
+            if line[0:3] != 'APT':
+                continue
+
+            if line[48:50] in statesAbbreviationsToExclude:
+                continue
+
+            facilityType = line[14:27].rstrip().title()
+
+            latLong = self.parseLatLongDMS(line[523:538] + line[550:565])
+
+            description = line[133:183].rstrip().title() + ' ' + facilityType + ', ' + line[93:133].rstrip().title() + ', ' + line[48:50]
+            description = description.replace('"', '\\"');
+
+            name = line[1210:1217].rstrip()
+            if not len(name):
+                name = line[27:31].rstrip()
+
+            if name in self.allNames:
+                print('Duplicate airport waypoint name {0}'.format(name))
+                continue
+
+            self.allNames.add(name)
+            self.waypoints.append((name, facilityType, description, latLong[0], latLong[1]))
+
+        file.close()
+
+    def parseNavAidData(self, navaidFile):
+        file = open(navaidFile, 'r')
+
+        self.ndbs = []
+        for line in file:
+            if line[0:4] != 'NAV1':
+                continue
+
+            if line[144:147] == 'AIN':
+                continue
+
+            if not line[8:11] in navaidsToInclude:
+                continue
+
+            facilityType = line[8:28].rstrip()
+
+            latLong = self.parseLatLongDMS(line[371:385] + line[396:410])
+
+            name = line[4:8].rstrip()
+            description = line[42:72].rstrip().title() + ' ' + line[8:28].rstrip()
+
+            # Since NDBs can have the same name as a VOR, we keep track of them separately
+            # and add NDBs below if the NDB has a unique name.
+            if line[8:11] == 'NDB':
+                self.ndbs.append((name, facilityType, description, latLong[0], latLong[1]))
+            else:
+                self.allNames.add(name)
+                self.waypoints.append((name, facilityType, description, latLong[0], latLong[1]))
+
+        for ndb in self.ndbs:
+            if ndb[0] not in self.allNames:
+                self.allNames.add(ndb[0])
+                self.waypoints.append(ndb)
+
+        file.close()
+
+    def parseFixData(self, fixFile):
+        file = open(fixFile, 'r')
+
+        for line in file:
+            if line[0:4] != 'FIX1':
+                continue
+
+            if line[4] < 'A' or line[4] > 'Z':
+                continue
+
+            facilityType = 'Intersection'
+
+            latLong = self.parseLatLongDMS(line[66:80] + line[80:94])
+
+            name = line[4:34].rstrip()
+            description = name + ' Intersection'
+
+            if name in self.allNames:
+                print('Duplicate fix name {0}'.format(name))
+                continue
+
+            self.allNames.add(name)
+            self.waypoints.append((name, facilityType, description, latLong[0], latLong[1], ''))
+
+        file.close()
+
+    def outputWaypointFile(self, outputFilename):
+        sortedWaypoints = sorted(self.waypoints, key=lambda waypoint: waypoint[0])
+
+        outputFile = open(outputFilename, 'w+')
+
+        outputFile.write('var _faaWaypoints = {\n');
+        isFirst = True
+        for waypoint in sortedWaypoints:
+            if isFirst:
+                isFirst = False
+            else:
+                outputFile.write(',\n');
+            outputFile.write('    "{0}":{{ "name":"{0}", "type":"{1}", "description":"{2}", "latitude":{3}, "longitude":{4}}}'.format(waypoint[0], waypoint[1], waypoint[2], waypoint[3], waypoint[4]))
+        outputFile.write('\n};\n');
+
+
+class AirwayData:
+    def __init__(self):
+        self.airways = []
+
+    def parseAirwayData(self, airwayFile):
+        file = open(airwayFile, 'r')
+
+        self.currentAirway = ''
+        self.airwayPoints = []
+
+        for line in file:
+            airway = line[4:8].rstrip()
+            if airway != self.currentAirway:
+                if self.currentAirway != '':
+                    self.airways.append((self.currentAirway, self.airwayPoints))
+                self.currentAirway = ''
+                self.airwayPoints = []
+
+            if line[0:4] != 'AWY2':
+                continue
+
+            if line[4] not in airwayTypes:
+                continue
+
+            if line[9] != ' ':
+                continue
+
+            if line[45:64].rstrip() not in airwayFixTypes:
+                continue
+
+            if self.currentAirway == '':
+                self.currentAirway = airway
+
+            if line[64:79].rstrip() == 'FIX':
+                self.airwayPoints.append(line[15:45].rstrip())
+            else:
+                self.airwayPoints.append(line[116:120].rstrip())
+
+        if self.currentAirway != '':
+            self.airways.append((self.currentAirway, self.airwayPoints))
+
+        file.close()
+
+    def outputAirwayFile(self, outputFilename):
+        sortedAirways = sorted(self.airways, key=lambda airways: airways[0])
+
+        outputFile = open(outputFilename, 'w+')
+
+        outputFile.write('var _faaAirways = {\n');
+        isFirst = True
+        for airway in sortedAirways:
+            if isFirst:
+                isFirst = False
+            else:
+                outputFile.write(',\n');
+            outputFile.write('    "{0}":{{ "name":"{0}", "fixes":['.format(airway[0]))
+            isFirstFix = True
+            for fix in airway[1]:
+                if isFirstFix:
+                    isFirstFix = False
+                else:
+                    outputFile.write(', ');
+
+                outputFile.write('"{0}"'.format(fix))
+            outputFile.write(']}')
+        outputFile.write('\n};\n');
+
+
+def main():
+    waypoints = WaypointData()
+    waypoints.parseAirportData('APT.txt')
+    waypoints.parseNavAidData('NAV.txt')
+    waypoints.parseFixData('FIX.txt')
+    waypoints.outputWaypointFile('waypoints.js')
+    airways = AirwayData()
+    airways.parseAirwayData('AWY.txt')
+    airways.outputAirwayFile('airways.js')
+
+
+if __name__ == "__main__":
+    main()
diff --git a/PerformanceTests/RexBench/FlightPlanner/expectations.js b/PerformanceTests/RexBench/FlightPlanner/expectations.js
new file mode 100644 (file)
index 0000000..2abdea4
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+"use strict";
+
+
+let expectedFlightPlans = [
+    new ExpectedFlightPlan("Rally Practice 1", "C83|" + keywords.get("Start") + " " + keywords.get("Taxi") + "|6:00 " + keywords.get("Runup") + "|0:30 " + keywords.get("Taxi") + "|1:00 " + keywords.get("Takeoff") + " " + keywords.get("Climb") + "|5500|5:00 CA67 0CN1 28CA 126kts I5.165 PT.ALPHA|" + keywords.get("Timing") + " KLSN " + keywords.get("Pattern") + "|0:45 " + keywords.get("Taxi") + "|2:00", "C83|Start Taxi|6:00 Runup|0:30 Taxi|1:00 Takeoff Climb|5500|5:00 CA67 0CN1 28CA 126kts I5.165 PT.ALPHA|Timing KLSN Pattern|0:45 Taxi|2:00", new Time("52:05"), new Time("44:35")),
+    new ExpectedFlightPlan("Rally Practice 2", "C83|" + keywords.get("Start") + " " + keywords.get("Taxi") + "|6:00 " + keywords.get("Runup") + "|0:30 " + keywords.get("Taxi") + "|1:00 " + keywords.get("Takeoff") + " " + keywords.get("Climb") + "|5500|5:00 ECA 343@4 5CL3 67CA 314@12 126kts I5.165 126kts PT.ALPHA|" + keywords.get("Timing") + "  126kts KLSN " + keywords.get("Pattern") + "|0:45 " + keywords.get("Taxi") + "|2:00", "C83|Start Taxi|6:00 Runup|0:30 Taxi|1:00 Takeoff Climb|5500|5:00 ECA 343@4 5CL3 67CA 314@12 126kts I5.165 126kts PT.ALPHA|Timing 126kts KLSN Pattern|0:45 Taxi|2:00", new Time("1:03:44"), new Time("56:14")),
+    new ExpectedFlightPlan("Rally Practice 3", "KTCY|" + keywords.get("Start") + " " + keywords.get("Taxi") + "|6:00 " + keywords.get("Runup") + "|0:30 " + keywords.get("Taxi") + "|1:00 " + keywords.get("Takeoff") + " " + keywords.get("Climb") + "|3500|5:00 O27 67CA OILCAMP I5.WESTSHIELDS I5.165 I5.VOLTA PT.ALPHA|" + keywords.get("Timing") + " KLSN " + keywords.get("Pattern") + "|0:45 " + keywords.get("Taxi") + "|2:00", "KTCY|Start Taxi|6:00 Runup|0:30 Taxi|1:00 Takeoff Climb|3500|5:00 O27 67CA Oilcamp I5.Westshields I5.165 I5.VOLTA PT.ALPHA|Timing KLSN Pattern|0:45 Taxi|2:00", new Time("1:06:20"), new Time("58:50")),
+    new ExpectedFlightPlan("Rally Practice 4", "C83|" + keywords.get("Start") + " " + keywords.get("Taxi") + "|6:00 " + keywords.get("Runup") + "|0:30 " + keywords.get("Taxi") + "|1:00 " + keywords.get("Takeoff") + " " + keywords.get("Climb") + "|5500|5:00 62@3 9CL0 342@9 CL84 28CA 315@10 126kts I5.165 126kts PT.ALPHA|" + keywords.get("Timing") + "  126kts KLSN " + keywords.get("Pattern") + "|0:45 " + keywords.get("Taxi") + "|2:00", "C83|Start Taxi|6:00 Runup|0:30 Taxi|1:00 Takeoff Climb|5500|5:00 62@3 9CL0 342@9 CL84 28CA 315@10 126kts I5.165 126kts PT.ALPHA|Timing 126kts KLSN Pattern|0:45 Taxi|2:00", new Time("54:32"), new Time("47:02")),
+    new ExpectedFlightPlan("Rally Practice 5", "C83|" + keywords.get("Start") + " " + keywords.get("Taxi") + "|6:00 " + keywords.get("Runup") + "|0:30 " + keywords.get("Taxi") + "|1:00 " + keywords.get("Takeoff") + " " + keywords.get("Climb") + "|5500|7:00 O27 9CL0 CL01 I5.165 PT.ALPHA KLSN " + keywords.get("Pattern") + "|0:45 " + keywords.get("Taxi") + "|2:00", "C83|Start Taxi|6:00 Runup|0:30 Taxi|1:00 Takeoff Climb|5500|7:00 O27 9CL0 CL01 I5.165 PT.ALPHA KLSN Pattern|0:45 Taxi|2:00", new Time("1:01:43"), new Time("54:13")),
+    new ExpectedFlightPlan("2014 HWD Rally Leg 1", "KHWD|" + keywords.get("Start") + " " + keywords.get("Taxi") + "|6:00 " + keywords.get("Runup") + "|0:30 " + keywords.get("Taxi") + "|1:00 " + keywords.get("Takeoff") + " " + keywords.get("Climb") + "|5500|4:35 VPDUB " + keywords.get("Climb") + "|8500|6:25 2CL9 " + keywords.get("Left") + "|+1 09CL " + keywords.get("Left") + "|+1 O02 " + keywords.get("Left") + "|+1 77NV " + keywords.get("Left") + " 126kts HALE|" + keywords.get("Timing") + " KSPZ " + keywords.get("Pattern") + "|0:45 " + keywords.get("Taxi") + "|2:00", "KHWD|Start Taxi|6:00 Runup|0:30 Taxi|1:00 Takeoff Climb|5500|4:35 VPDUB Climb|8500|6:25 2CL9 Left|+1 09CL Left|+1 O02 Left|+1 77NV Left 126kts HALE|Timing KSPZ Pattern|0:45 Taxi|2:00", new Time("1:52:28"), new Time("1:44:58")),
+    new ExpectedFlightPlan("2014 HWD Rally Leg 2", "KSPZ|" + keywords.get("Start") + " " + keywords.get("Taxi") + "|4:00 " + keywords.get("Runup") + "|0:30 " + keywords.get("Taxi") + "|1:00 " + keywords.get("Takeoff") + " " + keywords.get("Climb") + "|7500|9:00 NV30 " + keywords.get("Left") + " MicrowaveSt " + keywords.get("Left") + " DOBYS " + keywords.get("Left") + " RanchTower " + keywords.get("Left") + " 126kts Winnie|" + keywords.get("Timing") + " KENV " + keywords.get("Pattern") + "|0:45 " + keywords.get("Taxi") + "|2:00", "KSPZ|Start Taxi|4:00 Runup|0:30 Taxi|1:00 Takeoff Climb|7500|9:00 NV30 Left MicrowaveSt Left DOBYS Left RanchTower Left 126kts WINNIE|Timing KENV Pattern|0:45 Taxi|2:00", new Time("2:03:43"), new Time("1:58:13")),
+    new ExpectedFlightPlan("2014 HWD Rally Leg 3", "KENV|" + keywords.get("Start") + " " + keywords.get("Taxi") + "|5:00 " + keywords.get("Runup") + "|0:30 " + keywords.get("Taxi") + "|1:00 " + keywords.get("Takeoff") + " " + keywords.get("Climb") + "|7500|8:30 FremontIsland " + keywords.get("Left") + "|+1 Tremonton " + keywords.get("Left") + "|+1 RandomPoint " + keywords.get("Left") + "|+1 Farson " + keywords.get("Left") + " 126kts WindRiver|" + keywords.get("Timing") + " KLND " + keywords.get("Pattern") + "|0:45 " + keywords.get("Taxi") + "|2:00", "KENV|Start Taxi|5:00 Runup|0:30 Taxi|1:00 Takeoff Climb|7500|8:30 FremontIsland Left|+1 Tremonton Left|+1 RandomPoint Left|+1 Farson Left 126kts WINDRIVER|Timing KLND Pattern|0:45 Taxi|2:00", new Time("2:25:05"), new Time("2:18:35")),
+    new ExpectedFlightPlan("2014 HWD Rally Leg 4", "KLND|" + keywords.get("Start") + " " + keywords.get("Taxi") + "|6:00 " + keywords.get("Runup") + "|0:30 " + keywords.get("Taxi") + "|1:00 " + keywords.get("Takeoff") + " " + keywords.get("Climb") + "|7500|10:00 Midwest " + keywords.get("Left") + " Bill " + keywords.get("Right") + "|+1 WY09 " + keywords.get("Left") + " KCUT " + keywords.get("Left") + " 126kts BUFF|" + keywords.get("Timing") + " KRAP " + keywords.get("Pattern") + "|0:45 " + keywords.get("Taxi") + "|2:00", "KLND|Start Taxi|6:00 Runup|0:30 Taxi|1:00 Takeoff Climb|7500|10:00 Midwest Left Bill Right|+1 WY09 Left KCUT Left 126kts BUFF|Timing KRAP Pattern|0:45 Taxi|2:00", new Time("2:32:10"), new Time("2:24:40")),
+    new ExpectedFlightPlan("2014 HWD Rally Leg 5", "KRAP|" + keywords.get("Start") + " " + keywords.get("Taxi") + "|5:00 " + keywords.get("Runup") + "|0:30 " + keywords.get("Taxi") + "|3:00 " + keywords.get("Takeoff") + " " + keywords.get("Climb") + "|7500|9:00 MMNHS " + keywords.get("Left") + "|+1 Tracks " + keywords.get("Left") + "|+1 8D7 " + keywords.get("Left") + " 5H3 " + keywords.get("Left") + " 126kts Omega KMVE " + keywords.get("Pattern") + "|0:45 " + keywords.get("Taxi") + "|2:00", "KRAP|Start Taxi|5:00 Runup|0:30 Taxi|3:00 Takeoff Climb|7500|9:00 MMNHS Left|+1 Tracks Left|+1 8D7 Left 5H3 Left 126kts Omega KMVE Pattern|0:45 Taxi|2:00", new Time("2:50:12"), new Time("2:41:42")),
+    new ExpectedFlightPlan("2014 HWD Rally Leg 6", "KMVE|" + keywords.get("Start") + " " + keywords.get("Taxi") + "|6:00 " + keywords.get("Runup") + "|0:30 " + keywords.get("Taxi") + "|2:00 " + keywords.get("Takeoff") + " " + keywords.get("Climb") + "|5500|6:00 1D6 " + keywords.get("Left") + " 68Y " + keywords.get("Right") + "|+1 Towers " + keywords.get("Left") + " KCHU " + keywords.get("Left") + " 126kts Paul|" + keywords.get("Timing") + " KMSN " + keywords.get("Pattern") + "|0:45 " + keywords.get("Taxi") + "|2:00", "KMVE|Start Taxi|6:00 Runup|0:30 Taxi|2:00 Takeoff Climb|5500|6:00 1D6 Left 68Y Right|+1 Towers Left KCHU Left 126kts PAUL|Timing KMSN Pattern|0:45 Taxi|2:00", new Time("2:26:56"), new Time("2:18:26")),
+    new ExpectedFlightPlan("2015 HWD Rally Leg 1", "KHWD|" + keywords.get("Start") + " " + keywords.get("Taxi") + "|6:00 " + keywords.get("Runup") + "|0:30 " + keywords.get("Taxi") + "|1:00 " + keywords.get("Takeoff") + " " + keywords.get("Climb") + "|5500|4:35 VPDUB " + keywords.get("Climb") + "|5500|3:25 IsletonBridge Mystery15 " + keywords.get("Left") + "|+1 71CL " + keywords.get("Left") + "|+1 Paskenta " + keywords.get("Left") + "|+1 O37 " + keywords.get("Left") + "|+1 JELLYSFERRY HOWIE|" + keywords.get("Timing") + " KRDD " + keywords.get("Pattern") + "|0:45 " + keywords.get("Taxi") + "|2:00", "KHWD|Start Taxi|6:00 Runup|0:30 Taxi|1:00 Takeoff Climb|5500|4:35 VPDUB Climb|5500|3:25 IsletonBridge Mystery15 Left|+1 71CL Left|+1 Paskenta Left|+1 O37 Left|+1 Jellysferry HOWIE|Timing KRDD Pattern|0:45 Taxi|2:00", new Time("2:04:00"), new Time("1:56:30")),
+    new ExpectedFlightPlan("2015 HWD Rally Leg 2", "KRDD|" + keywords.get("Start") + " " + keywords.get("Taxi") + "|6:00 " + keywords.get("Runup") + "|0:30 " + keywords.get("Taxi") + "|2:00 " + keywords.get("Takeoff") + " " + keywords.get("Climb") + "|8500|1:20 REDDING.POND " + keywords.get("Climb") + "|8500|7:40 A26 O81 " + keywords.get("Left") + " 340@6 Bonanza " + keywords.get("Left") + "|+1 Silverlake " + keywords.get("Left") + "|+1 Millican 126kts Goering|" + keywords.get("Timing") + " KBDN " + keywords.get("pattern") + "|30 " + keywords.get("taxi") + "|2:00", "KRDD|Start Taxi|6:00 Runup|0:30 Taxi|2:00 Takeoff Climb|8500|1:20 Redding.Pond Climb|8500|7:40 A26 O81 Left 340@6 Bonanza Left|+1 Silverlake Left|+1 Millican 126kts GOERING|Timing KBDN Pattern|0:30 Taxi|2:00", new Time("2:27:39"), new Time("2:19:09")),
+    new ExpectedFlightPlan("2016 HWD Rally Leg 1", "KHWD|" + keywords.get("Start") + " " + keywords.get("Taxi") + "|6:00 " + keywords.get("Runup") + "|0:30 " + keywords.get("Taxi") + "|1:00 " + keywords.get("Takeoff") + " " + keywords.get("Climb") + "|5500|4:35 VPDUB " + keywords.get("Climb") + "|5500|3:25 65CN 3CN7 57CN " + keywords.get("Left") + "|+1 2CL1 " + keywords.get("Left") + "|+1 O37 " + keywords.get("Left") + "|+1 JELLYSFERRY HOWIE|" + keywords.get("Timing") + " KRDD " + keywords.get("Pattern") + "|0:45 " + keywords.get("Taxi") + "|2:00", "KHWD|Start Taxi|6:00 Runup|0:30 Taxi|1:00 Takeoff Climb|5500|4:35 VPDUB Climb|5500|3:25 65CN 3CN7 57CN Left|+1 2CL1 Left|+1 O37 Left|+1 Jellysferry HOWIE|Timing KRDD Pattern|0:45 Taxi|2:00", new Time("1:50:15"), new Time("1:42:45")),
+    new ExpectedFlightPlan("2016 HWD Rally Leg 2", "KRDD|" + keywords.get("Start") + " " + keywords.get("Taxi") + "|6:00 " + keywords.get("Runup") + "|0:30 " + keywords.get("Taxi") + "|2:00 " + keywords.get("Takeoff") + " " + keywords.get("Climb") + "|8500|1:20 REDDING.POND " + keywords.get("Climb") + "|8500|7:40 O89 KAAT " + keywords.get("Left") + " 1Q2 KSVE " + keywords.get("Left") + " H37 " + keywords.get("Left") + " CONSTANTIA2 HALLELUJAH2|" + keywords.get("Timing") + " KRTS " + keywords.get("pattern") + "|30 " + keywords.get("taxi") + "|2:00", "KRDD|Start Taxi|6:00 Runup|0:30 Taxi|2:00 Takeoff Climb|8500|1:20 Redding.Pond Climb|8500|7:40 O89 KAAT Left 1Q2 KSVE Left H37 Left Constantia2 HALLELUJAH2|Timing KRTS Pattern|0:30 Taxi|2:00", new Time("2:06:06"), new Time("1:57:36")),
+    new ExpectedFlightPlan("2017 HWD Rally Leg 1", "KHWD|" + keywords.get("Start") + " " + keywords.get("Taxi") + "|6:00 " + keywords.get("Runup") + "|0:30 " + keywords.get("Taxi") + "|1:00 " + keywords.get("Takeoff") + " " + keywords.get("Climb") + "|4500|8:00 10@6 9CL9 63CL THUNDERHILL 60@10 90CL 0O4 350@10 126kts JELLYSFERRY 126kts HOWIE|" + keywords.get("Timing") + " KRDD " + keywords.get("Pattern") + "|0:45 " + keywords.get("Taxi") + "|4:00", "KHWD|Start Taxi|6:00 Runup|0:30 Taxi|1:00 Takeoff Climb|4500|8:00 10@6 9CL9 63CL Thunderhill 60@10 90CL 0O4 350@10 126kts Jellysferry 126kts HOWIE|Timing KRDD Pattern|0:45 Taxi|4:00", new Time("1:41:46"), new Time("1:34:16")),
+    new ExpectedFlightPlan("2017 HWD Rally Leg 2", "KRDD|" + keywords.get("Start") + " " + keywords.get("Taxi") + "|6:00 " + keywords.get("Runup") + "|0:30 " + keywords.get("Taxi") + "|2:00 " + keywords.get("Takeoff") + " " + keywords.get("Climb") + "|8500|6:40 CASCADEHIGHWAY " + keywords.get("Climb") + "|8500|8:20 KLKV 210@2 EAGLEVILLE DUCKLAKEPASS 210@5 O39 209@8 AHC 148@6 126kts CONSTANTIA2 126kts Hallelujah2|" + keywords.get("Timing") + " KRTS " + keywords.get("Pattern") + "|0:30 " + keywords.get("Taxi") + "|2:00", "KRDD|Start Taxi|6:00 Runup|0:30 Taxi|2:00 Takeoff Climb|8500|6:40 CascadeHighway Climb|8500|8:20 KLKV 210@2 Eagleville DuckLakePass 210@5 O39 209@8 AHC 148@6 126kts Constantia2 126kts HALLELUJAH2|Timing KRTS Pattern|0:30 Taxi|2:00", new Time("2:14:36"), new Time("2:06:06")),
+    new ExpectedFlightPlan("San Jose to San Diego", "KSJC LICKE SNS V25 REDIN KMYF", "KSJC LICKE SNS CASRA HAGRO WIGGL LUCAB PRB KIKII POZOE WYNNR RZS ZIQOR DEANO VTU EXERT MERMA LAX HERMO WILMA FERMY ALBAS MINOE PACIF REDIN KMYF", new Time("2:40:16"), undefined),
+    new ExpectedFlightPlan("San Diego to San Jose", "KMYF JOPDO CARIF V23 LAX V299 VTU V25 PRB SARDO RANCK V485 LICKE KSJC", "KMYF JOPDO CARIF HURSI OCN KELPS DANAH KRAUZ BALBO MIDDS SLI POPPR HERMO LAX SADDE VTU DEANO ZIQOR RZS WYNNR POZOE KIKII PRB SARDO RANCK PANOS ULENY HENCE GILRO LICKE KSJC", new Time("2:38:48"), undefined),
+    new ExpectedFlightPlan("San Jose to Renton", "KSJC SUNOL RBL V23 SEA KRNT", "KSJC SUNOL RBL BEIRA TAYTO SHATA FOLDS FJS ZUNAS LEANN TALEM LIPWO OED UZEHE BROKN MOURN CURTI SAGIN EUG ALFOR SHEDD MAGOT TURNO EMADE GNNET RAWER CANBY OSWEG BTG ROARK COUGA MALAY ONALS MCKEN SEA KRNT", new Time("4:23:52"), undefined),
+    new ExpectedFlightPlan("Renton to Willows", "KRNT SEA V495 BTG V23 RBL KWLW", "KRNT SEA CIDUG ALDER TOUTL OKARE BTG OSWEG CANBY RAWER GNNET EMADE TURNO MAGOT SHEDD ALFOR EUG SAGIN CURTI MOURN BROKN UZEHE OED LIPWO TALEM LEANN ZUNAS FJS FOLDS SHATA TAYTO BEIRA RBL KWLW", new Time("3:27:06"), undefined),
+    new ExpectedFlightPlan("SJC to SEA #1", "ksjc sunol 135kts 300@12 rdd 0kts pdx ksea", "KSJC SUNOL 300@12 135kts RDD PDX KSEA", new Time("4:33:24"), undefined),
+    new ExpectedFlightPlan("SJC to SEA #2", "KSJC SJC V334 SAC V23 BTG V495 SEA KSEA", "KSJC SJC SUNOL ALTAM OAKEY VISTO SAC CAPTO EYPOF GRIME YUBBA GRIDD TALUM JINGO GONGS RBL BEIRA TAYTO SHATA FOLDS FJS ZUNAS LEANN TALEM LIPWO OED UZEHE BROKN MOURN CURTI SAGIN EUG ALFOR SHEDD MAGOT TURNO EMADE GNNET RAWER CANBY OSWEG BTG OKARE TOUTL ALDER CIDUG SEA KSEA", new Time("4:23:27"), undefined),
+    new ExpectedFlightPlan("SJC to SEA #3", "KSJC SJC V334 SAC V23 FJS V495 SEA KSEA", "KSJC SJC SUNOL ALTAM OAKEY VISTO SAC CAPTO EYPOF GRIME YUBBA GRIDD TALUM JINGO GONGS RBL BEIRA TAYTO SHATA FOLDS FJS BAYTS PAPLE MERLI KOLER RBG VAUGN NOTTI HORTE CVO ADLOW BREAF UBG ENDZZ BTG OKARE TOUTL ALDER CIDUG SEA KSEA", new Time("4:26:18"), undefined),
+    new ExpectedFlightPlan("Roseburg to San Jose", "KRBG RBG KOLER V495 FJS V23 RBL SUNOL KSJC", "KRBG RBG KOLER MERLI PAPLE BAYTS FJS FOLDS SHATA TAYTO BEIRA RBL SUNOL KSJC", new Time("2:33:19"), undefined),
+    new ExpectedFlightPlan("SAN to DEN", "KSAN HAILE V514 LYNSY V8 JNC V134 BINBE KDEN", "KSAN HAILE RYAHH BARET CANNO JLI WARNE TRM CONES CLOWD TNP JOTNU ZELMA GFS SHUSS LYNSY WINDS ACLAM MEADS MMM PHYLI JITKA JEZOB MATZO POBME CEXAT ETYIR BCE MOJVI UJACI HVE KIDNE EDLES ARCHH ZUKSO JNC PACES EDUKY HUGSI RIYNO SLOLM GLENO LINDZ DBL HERLS LAWSN DAVVY FUNDS BREWS BINBE KDEN", new Time("5:35:24"), undefined),
+    new ExpectedFlightPlan("Denver to Minneapolis", "KDEN DVV V8 AKO V80 FSD V148 RWF V412 FCM KMSP", "KDEN DVV HOYTT AKO CITMU NACIK HOLYO UYOGI LBF OGEZO ECYUS BOKKI JIKNU ONL CURIR TYNDA PUKIC DOLTS FSD SECTO POEMS POGSE ZERAD PILIY RWF DRAIL FCM KMSP", new Time("4:14:33"), undefined),
+    new ExpectedFlightPlan("Reno to Chicago", "KRNO FMG V6 LLC V32 CEVAR V200 STACO V32 FBR V6 MBW V100 RFD V171 SIMMN V172 DPA KORD", "KRNO FMG WADDS LLC ZUSRU FESKO WIKLO BAM OLGAA BQU SPATS UHEPI BVL ZONSU BAGGI CEVAR STACO WEGET SALTA TCH COOLI EXILE FBR WEGEM PUDVY OCS TOGUY ARUTE CKW EDIFY CEXIT MBW ZIKRU BFF HAPOP JUNUM AIA EVENN EFFEX MARSS ANW GIYED ONL CUGUX BEWIG ATLES SUX CUSHO NEMAH MONKS BABYA FOD SEKDE ALOCK ARTYS ALO DEWAR INDET DBQ LENAS RFD NOAHE SIMMN NUELG DPA KORD", new Time("10:22:34"), undefined),
+    new ExpectedFlightPlan("Denver to Oklahoma City", "KDEN AVNEW V366 HGO V263 LAA V304 LBL V507 MMB V17 IRW KOKC", "KDEN AVNEW JEFEL QUAIL CONAL HGO ZANON WEYYI LAA UPIRE YUNUP LBL ZALIK MMB TISSY CAMAR PANIY OLVAE ODINS ZELNU CAMET IRW KOKC", new Time("3:05:36"), undefined),
+    new ExpectedFlightPlan("Stockton to Hawthorne 1", "KSCK MOD V113 PXN V107 AVE V137 GMN V23 LAX KHHR", "KSCK MOD PATYY PXN CITIE AVE TAFTO GMN CASTA TWINE CHATY LAX KHHR", new Time("2:02:15"), undefined),
+    new ExpectedFlightPlan("Stockton to Hawthorne 2", "ksck patyy v113 rom v485  exert v25 lax khhr", "KSCK PATYY ROM EXERT LAX KHHR", new Time("2:05:38"), undefined),
+    new ExpectedFlightPlan("Long View to Corpus Christi", "KGGG PIPES V289 LFK V13 WORRY KCRP", "KGGG PIPES ARMOR AFRUH LFK WELRO LEGGE CLEEP IAH ROSEN COSDI PUKME PSX TANNA IVOLY BLOKS AUSTS WORRY KCRP", new Time("2:19:06"), undefined),
+    new ExpectedFlightPlan("Austin Exec to Beaumont 1", "KEDC HOOKK V306 TNV V574 IAH V222 SHINA KBPT", "KEDC HOOKK ILEXY JAYJO BLUBL COUTH TNV IAH COSBI TRIOS BDDRO FALSE SHINA KBPT", new Time("1:20:01"), undefined),
+    new ExpectedFlightPlan("Austin Exec to Beaumont 2", "KEDC HOOKK V306 DAS KBPT", "KEDC HOOKK ILEXY JAYJO BLUBL COUTH TNV GOMER ZMSKL CLEEP DAS KBPT", new Time("1:19:37"), undefined),
+    new ExpectedFlightPlan("Austin Exec to Beaumont 3", "KEDC HOOKK V306 TNV DAS KBPT", "KEDC HOOKK ILEXY JAYJO BLUBL COUTH TNV DAS KBPT", new Time("1:19:13"), undefined),
+    new ExpectedFlightPlan("Savannah to Daytona Beach", "KSAV KELER V437 COKES KDAB", "KSAV KELER CATHY STARY HOTAR SUBER JETSO COBOK COKES KDAB", new Time("1:14:55"), undefined),
+    new ExpectedFlightPlan("Philly to Hartford 1", "KPNE ARD V276 DIXIE V16 JFK V229 SNIVL KHFD", "KPNE ARD RBV CASVI DIXIE MOVFA JFK KEEPM TRANZ PUGGS BDR MILUM BAYYS DWAIN SEALL SNIVL KHFD", new Time("1:12:28"), undefined),
+    new ExpectedFlightPlan("Philly to Hartford 2", "KPNE ARD V276 MANTA V139 RICED MAD KHFD", "KPNE ARD RBV CASVI DIXIE ZIGGI GAMBY MANTA PLUME SHERL DUNEE KOPPY SARDI RICED MAD KHFD", new Time("1:25:52"), undefined),
+    new ExpectedFlightPlan("Philly to Hartford 3", "KPNE DITCH V312 DRIFT V139 SARDI V308 ORW KHFD", "KPNE DITCH CYN JIMEE FALON WINKK DRIFT MANTA PLUME SHERL DUNEE KOPPY SARDI RICED BEDYA SHLEP BEADS HTO BOROS GON ORW KHFD", new Time("1:38:35"), undefined),
+    new ExpectedFlightPlan("Philly to Hartford 4", "KPNE ZIDET V479 ARD V433 LGA V99 YALER KHFD", "KPNE ZIDET ARD MERSR METRO PLEXS BONIE KILMA GRITY TICKL PROUD DIALS LGA OUTTE VAGUS ANNEI TRUDE MERIT SORRY YALER KHFD", new Time("1:04:01"), undefined),
+    new ExpectedFlightPlan("West Georgie Regional to Frankfort, KY 1", "kctj noone nello v5 gqo kfft", "KCTJ NOONE NELLO GQO KFFT", new Time("2:08:18"), undefined),
+    new ExpectedFlightPlan("West Georgie Regional to Frankfort, KY 2", "kctj felto v243 gqo v333 hyk v512 clegg kfft", "KCTJ FELTO GQO HYK CLEGG KFFT", new Time("2:02:52"), undefined),
+    new ExpectedFlightPlan("West Georgie Regional to Frankfort, KY 3", "kctj rmg v333 hyk v512 clegg kfft", "KCTJ RMG HYK CLEGG KFFT", new Time("2:01:15"), undefined),
+    new ExpectedFlightPlan("West Georgie Regional to Frankfort, KY 4", "kctj rmg v333 hch v51 lvt v493 hyk kfft", "KCTJ RMG HCH LVT HYK KFFT", new Time("2:03:24"), undefined),
+    new ExpectedFlightPlan("Raleigh / Durham to Baltimore Martin State 1", "KRDU aimhi  KMTN", "KRDU AIMHI KMTN", new Time("1:39:49"), undefined),
+    new ExpectedFlightPlan("Raleigh / Durham to Baltimore Martin State 2", "KRDU rdu v155 lvl ric ott KMTN", "KRDU RDU LVL RIC OTT KMTN", new Time("1:40:45"), undefined),
+    new ExpectedFlightPlan("Raleigh / Durham to Baltimore Martin State 3", "KRDU rdu v155 mange v157 colin v33 ott v433 paleo KMTN", "KRDU RDU MANGE COLIN OTT PALEO KMTN", new Time("1:45:10"), undefined),
+    new ExpectedFlightPlan("Raleigh / Durham to Baltimore Martin State 4", "KRDU rdu v155 LVL V157 RIC V16 PXT V93 GRACO KMTN", "KRDU RDU WIPER BEXGO LVL MANGE DALTO MATOX RIC SVILL TAPPA DUPEY COLIN PXT LOUIE GRACO KMTN", new Time("1:45:57"), undefined),
+    new ExpectedFlightPlan("Roswell, NM to Longview, TX", "KROW " + keywords.get("Climb") + "|9500|6:00 070@14 HOB V68 PIZON 050@16 V16 ABI V62 JEN V94 OTTIF KGGG", "KROW Climb|9500|6:00 70@14 HOB ZUSDA GECKE ANEEL PIZON 50@16 ABI FLECK GEENI CADES ZOSKU SICUM JEN CELTC ACUFF CQY SWANI SNOWE CAPTI OTTIF KGGG", new Time("3:58:24"), undefined),
+    new ExpectedFlightPlan("Lubbock to Longview 1", "KLBB JEN CQY KGGG", "KLBB JEN CQY KGGG", new Time("2:40:35"), undefined),
+    new ExpectedFlightPlan("Lubbock to Longview 2", "KLBB ralls v102 gth v278 byp v114 awlar KGGG", "KLBB RALLS GTH BYP AWLAR KGGG", new Time("2:42:00"), undefined),
+    new ExpectedFlightPlan("Lubbock to Longview 3", "KLBB hydro v62 jen v94 ottif KGGG", "KLBB HYDRO JEN OTTIF KGGG", new Time("2:40:32"), undefined),
+    new ExpectedFlightPlan("Stockton, CA to North Las Vegas 1", "KSCK ECA V244 OAL V105 LUCKY KVGT", "KSCK ECA WRAPS HABXU DUCKE NIKOL JABIM OAL ZOTUX TEZUM LIDAT BTY HIDEN LUCKY KVGT", new Time("2:29:10"), undefined),
+    new ExpectedFlightPlan("Stockton, CA to North Las Vegas 2", "KSCK ehf v197 pmd v12 basal v394 oasys KVGT", "KSCK EHF PMD BASAL OASYS KVGT", new Time("3:01:42"), undefined),
+    new ExpectedFlightPlan("Bakersfield to Santa Rosa 1", "KBFL EHF V248 AVE OAK SAU KSTS", "KBFL EHF SCRAP COREZ AVE OAK SAU KSTS", new Time("1:54:22"), undefined),
+    new ExpectedFlightPlan("Bakersfield to Santa Rosa 2", "KBFL EHF V248 AVE PXN V301 SUNOL KSTS", "KBFL EHF SCRAP COREZ AVE PXN KARNN BORED BUSHY SUNOL KSTS", new Time("1:53:02"), undefined),
+    new ExpectedFlightPlan("Bakersfield to Santa Rosa 3", "KBFL SCRAP V248 AVE V107 OAK V195 CROIT V108 STS KSTS", "KBFL SCRAP COREZ AVE CITIE PXN CATHE VINCO MABRY MISON IMPLY DECOT OAK BERKS SABLO CROIT SGD HABAP STS KSTS", new Time("1:55:37"), undefined),
+    new ExpectedFlightPlan("Bakersfield to Santa Rosa 4", "KBFL EHF V23 SAC V494 SNUPY KSTS", "KBFL EHF DELNO PONDD PIXEY LATON FRAME CZQ OXVEV BEREN LAPOW UYOKA EBTUW TURLO NEBBY AWALI HONEZ WRAPS LIN GALTS SAC PIVSE RAGGS POPES SNUPY KSTS", new Time("1:57:59"), undefined),
+    new ExpectedFlightPlan("Bakersfield to Santa Rosa 5", "KBFL EHF V248 AVE V137 SNS V230 SHOEY V27 PYE KSTS", "KBFL EHF SCRAP COREZ AVE NEFDE OKEEF ROM ZURET CANRI SNS JEJZE ISIFU SHOEY EUGEN TAILS HADLY SEEMS STINS PYE KSTS", new Time("2:01:34"), undefined),
+    new ExpectedFlightPlan("Bakersfield to Santa Rosa 6", "KBFL EHF V23 CZQ MOD OAKEY KSTS", "KBFL EHF DELNO PONDD PIXEY LATON FRAME CZQ MOD OAKEY KSTS", new Time("1:53:12"), undefined),
+    new ExpectedFlightPlan("Bakersfield to Santa Rosa 7", "KBFL EHF V23 LIN CCR CROIT SGD KSTS", "KBFL EHF DELNO PONDD PIXEY LATON FRAME CZQ OXVEV BEREN LAPOW UYOKA EBTUW TURLO NEBBY AWALI HONEZ WRAPS LIN CCR CROIT SGD KSTS", new Time("1:59:11"), undefined),
+    new ExpectedFlightPlan("Bakersfield to Santa Rosa 8", "KBFL EHF V248 AVE V107 PXN SGD KSTS", "KBFL EHF SCRAP COREZ AVE CITIE PXN SGD KSTS", new Time("1:53:04"), undefined),
+    new ExpectedFlightPlan("Great Falls to Boeing King Field 1", "KGTF GTF V120 MLP V2 GEG V120 NORMY KBFI", "KGTF GTF SHIMY CHARL HANIM EDOBE MLP HILIE HIPRR ROPES GEG EPAFY OWOSE WIPES EPH OZALI EAT CASHS CUNUR WINIM FITGA NORMY KBFI", new Time("3:08:44"), undefined),
+    new ExpectedFlightPlan("Great Falls to Boeing King Field 2", "KGTF GTF V120 MLP J70 SEA KBFI", "KGTF GTF SHIMY CHARL HANIM EDOBE MLP EPH BLUIT NORMY SEA KBFI", new Time("3:10:35"), undefined),
+    new ExpectedFlightPlan("Great Falls to Boeing King Field 3", "KGTF GTF V187 ELN V2 SEA KBFI", "KGTF GTF TUCKB GUGYI ROSOE OCEDA SQIDS MSO WAANE LOLLO DAIRE RIVAL JIROS OFINO CEPER PETEZ MQG POTOR SEVER RENGO BUTOC DATES BACUN OYREX PSC EXODE NIALS FEBUS ELN BEEZR BANDR VAMPS SEA KBFI", new Time("3:26:13"), undefined),
+    new ExpectedFlightPlan("Great Falls to Boeing King Field 4", "KGTF KEETA Q144 ZIRAN KBFI", "KGTF KEETA BLOWS ZOOMR ZIRAN KBFI", new Time("3:08:13"), undefined),
+    new ExpectedFlightPlan("Boise to Centenial 1", "KBOI BOI V4 LAR RAMMS NIWOT KAPA", "KBOI BOI CANEK ALKAL YUWFE GOODE JEROT HAZZL BYI MEDEA MLD TINRE FILOB HODNI GEGME GRIPS OCS TOGUY ARUTE CKW ZOLGA TRUMA KLASH NATTI LYMPS LAR RAMMS NIWOT KAPA", new Time("4:18:57"), undefined),
+    new ExpectedFlightPlan("Boise to Centenial 2", "KBOI ROARR PIH J20 OCS J154 AVVVS KAPA", "KBOI ROARR PIH OCS ALPOE AUTIM RAMMS AVVVS KAPA", new Time("4:09:34"), undefined),
+    new ExpectedFlightPlan("Boise to Centenial 3", "KBOI CANEK V4 OCS V328 DOBEE V356 ELORE KAPA", "KBOI CANEK ALKAL YUWFE GOODE JEROT HAZZL BYI MEDEA MLD TINRE FILOB HODNI GEGME GRIPS OCS CEBAL SNAKY CELIA MEKWY HUPEG CHE EGFAX HABRO SBURG TILLI GUVYU RLG DOBEE ELORE KAPA", new Time("4:07:58"), undefined),
+    new ExpectedFlightPlan("Boise to Centenial 4", "KBOI BOI J54 PIH J20 OCS J52 FQF KAPA", "KBOI BOI PIH OCS FQF KAPA", new Time("4:06:43"), undefined),
+    new ExpectedFlightPlan("St. Louis to Birmingham 1", "KSTL SPUDZ V125 DUEAS V540 CNG V67 SYI V321 BOAZE V115 COLIG KBHM", "KSTL SPUDZ BURCK NIKEL DUEAS ALING PAMPI TAMMS CNG KABLE NUBEE LANKY GHM TUNGY SYI KUXYI ATWUS JEKBA VOYUD HATAS RQZ OWENT ALBER BOAZE ARBEE SNEAR WILED COLIG KBHM", new Time("2:57:41"), undefined),
+    new ExpectedFlightPlan("St. Louis to Birmingham 2", "KSTL ODUJY FAM CGI JKS MSL VUZ KBHM", "KSTL ODUJY FAM CGI JKS MSL VUZ KBHM", new Time("2:35:27"), undefined),
+    new ExpectedFlightPlan("Chattanoga to Augusta 1", "KCHA ODF AHN V417 MSTRS KAGS", "KCHA ODF AHN OCENU DANBI TIGNA MSTRS KAGS", new Time("1:32:34"), undefined),
+    new ExpectedFlightPlan("Chattanoga to Augusta 2", "KCHA GQO NELLO CCATT T292 JACET KAGS", "KCHA GQO NELLO CCATT REELL TRREE JACET KAGS", new Time("1:21:13"), undefined),
+    new ExpectedFlightPlan("Chattanoga to Augusta 3", "KCHA GQO ATL ANNAN KAGS", "KCHA GQO ATL ANNAN KAGS", new Time("1:31:50"), undefined),
+    new ExpectedFlightPlan("Chattanoga to Augusta 4", "KCHA HOCHE V5 AHN V417 IRQ KAGS", "KCHA HOCHE ETONE NELLO AWSON CORCE IRMOS AHN OCENU DANBI TIGNA MSTRS KANDY IRQ KAGS", new Time("1:28:00"), undefined),
+    new ExpectedFlightPlan("Concord, NC to Richmond, VA 1", "KJQF SBV V20 RIC KRIC", "KJQF SBV LELLI YUDUG NUTTS MELIA RIC KRIC", new Time("1:27:57"), undefined),
+    new ExpectedFlightPlan("Concord, NC to Richmond, VA 2", "KJQF GIZMO V143 GSO V266 SBV V20 RIC KRIC", "KJQF GIZMO AZELL GSO REIDE YANCE SBV LELLI YUDUG NUTTS MELIA RIC KRIC", new Time("1:28:38"), undefined),
+    new ExpectedFlightPlan("Concord, NC to Richmond, VA 3", "KJQF GSO SBV V20 RIC KRIC", "KJQF GSO SBV LELLI YUDUG NUTTS MELIA RIC KRIC", new Time("1:28:04"), undefined),
+    new ExpectedFlightPlan("Concord, NC to Richmond, VA 4", "KJQF GIZMO V454 LVL V157 RIC KRIC", "KJQF GIZMO KEWPI LIB STASE BILLA WUMVA OXFRD NOKIY LVL MANGE DALTO MATOX RIC KRIC", new Time("1:31:04"), undefined),
+    new ExpectedFlightPlan("Buffalo, NY to Portland, ME 1", "KBUF BUF V2 UCA V496 NEETS V39 LIMER KPWM", "KBUF BUF CLUNG MONCK ROC LORTH MAGEN KONDO WIFFY SYR FAYET STODA VASTS UCA MALLO WAREN GFL KERST EBERT LEB BILLS ANIER GRUMP NEETS LIMER KPWM", new Time("2:41:10"), undefined),
+    new ExpectedFlightPlan("Buffalo, NY to Portland, ME 2", "KBUF HANKK AUDIL PUPPY GFL KPWM", "KBUF HANKK AUDIL PUPPY GFL KPWM", new Time("2:37:35"), undefined),
+    new ExpectedFlightPlan("Buffalo, NY to Portland, ME 3", "KBUF BUF V14 GGT V428 UCA V496 ENE KPWM", "KBUF BUF GEE UMAGY BEEPS SCIPO BOCKS VESPE GGT EATEN UCA MALLO WAREN GFL KERST EBERT LEB BILLS ANIER GRUMP NEETS ENE KPWM", new Time("2:42:53"), undefined),
+    new ExpectedFlightPlan("Buffalo, NY to Portland, ME 4", "KBUF JOSSY Q935 PONCT ARIME CDOGG ENE KPWM", "KBUF JOSSY AUDIL FABEN PONCT ARIME CDOGG ENE KPWM", new Time("2:41:59"), undefined),
+    new ExpectedFlightPlan("Moline, IL to Battle Creek, MI 1", "KMLI GENSO V8 NOMES V156 AZO KBTL", "KMLI GENSO WYNET TRIDE URRBS AHMED BENKY JOT CGT HALIE INKEN NOMES GIJ JJANN AZO KBTL", new Time("1:48:41"), undefined),
+    new ExpectedFlightPlan("Moline, IL to Battle Creek, MI 2", "KMLI OBK J547 PMM KBTL", "KMLI OBK KUBBS PMM KBTL", new Time("1:43:50"), undefined),
+    new ExpectedFlightPlan("Moline, IL to Battle Creek, MI 3", "KMLI PLL OBK ELX KBTL", "KMLI PLL OBK ELX KBTL", new Time("1:44:25"), undefined),
+    new ExpectedFlightPlan("Moline, IL to Battle Creek, MI 4", "KMLI PLL RFD V100 ELX AZO KBTL", "KMLI PLL RFD GRIFT SMULA KRENA FARMM UMUZI OBK DEERE BRAIK MINCE MUSKY YOLUR ELX AZO KBTL", new Time("1:47:49"), undefined),
+    new ExpectedFlightPlan("Green Bay, WI to Indianapolis, IN 1", "KGRB OKK V305 WELDO KIND", "KGRB OKK WELDO KIND", new Time("2:09:02"), undefined),
+    new ExpectedFlightPlan("Green Bay, WI to Indianapolis, IN 2", "KGRB GRB J101 BAE J89 OBK EON V24 VHP KIND", "KGRB GRB BAE OBK EON KENLA YIXCI BOSSY BOSWL VAGES ATTIL POTES JAKKS JELLS ADVAY VHP KIND", new Time("2:16:10"), undefined),
+    new ExpectedFlightPlan("Green Bay, WI to Indianapolis, IN 3", "KGRB WAFLE V7 BVT V399 ADVAY KIND", "KGRB WAFLE CLINS MURRI FAH CYNDI WOKNO PROOT HOGMI PETTY TALOR PAPPI DEERE THORR LAIRD BEBEE NILES CGT COKED LUCIT ZORRO OXFAT BVT JAKKS JELLS ADVAY KIND", new Time("2:09:16"), undefined),
+    new ExpectedFlightPlan("Green Bay, WI to Indianapolis, IN 4", "KGRB WAFLE V7 BVT VHP KIND", "KGRB WAFLE CLINS MURRI FAH CYNDI WOKNO PROOT HOGMI PETTY TALOR PAPPI DEERE THORR LAIRD BEBEE NILES CGT COKED LUCIT ZORRO OXFAT BVT VHP KIND", new Time("2:08:40"), undefined),
+    new ExpectedFlightPlan("Anoka County, MN to Springfield, IL 1", "KANE KANAC V97 ODI V129 GROWL KSPI", "KANE KANAC PRESS MANIE TROLL PEGGS ODI PKRNA DOURS QUEST FARON SWAGG DBQ LOTTE CVA NOWSO GENSO JPAUL PIA EVERY LOTTO GROWL KSPI", new Time("2:34:30"), undefined),
+    new ExpectedFlightPlan("Anoka County, MN to Springfield, IL 2", "KANE GEP PRIOR FGT V411 RST V67 ULAXY KSPI", "KANE GEP PRIOR FGT AHMIT PEPPR DELZY EGUPE RST YESUR FOYDE ALO LYERS VINTY CID IOW WAPEL UTXIH BRL HAKAV BADER ATTIC ULAXY KSPI", new Time("2:44:02"), undefined),
+    new ExpectedFlightPlan("Anoka County, MN to Springfield, IL 3", "KANE GEP PRIOR FGT V411 RST V503 CID V67 ULAXY KSPI", "KANE GEP PRIOR FGT AHMIT PEPPR DELZY EGUPE RST TALNE FARVI CID IOW WAPEL UTXIH BRL HAKAV BADER ATTIC ULAXY KSPI", new Time("2:42:35"), undefined),
+    new ExpectedFlightPlan("Anoka County, MN to Springfield, IL 4", "KANE WAGNR V510 ODI V129 SPI KSPI", "KANE WAGNR ANDDE BITLR ODI PKRNA DOURS QUEST FARON SWAGG DBQ LOTTE CVA NOWSO GENSO JPAUL PIA EVERY LOTTO GROWL SPI KSPI", new Time("2:36:35"), undefined),
+    new ExpectedFlightPlan("Little Rock to Souix City 1", "KLIT MCI J41 OVR KSUX", "KLIT MCI AGENT OVR KSUX", new Time("3:31:26"), undefined),
+    new ExpectedFlightPlan("Little Rock to Souix City 2", "KLIT ROLAN V534 HAAWK V71 SGF V159 SUX KSUX", "KLIT ROLAN BIBBS HAAWK JASPE HRO RASON REEDS ENDRS SPOKE SGF OLIVA OLLII TRALE AUGIE HODEN ANX LYMES EXCEL LASSO HANOT STJ TRAIG VIKKI OVR ZISIX CANIO AANDY BECOM SUX KSUX", new Time("3:42:22"), undefined),
+    new ExpectedFlightPlan("Little Rock to Souix City 3 ", "KLIT ROLAN V534 SCRAN V527 RZC V13 BUM V71 PANNY KSUX", "KLIT ROLAN BIBBS HAAWK SCRAN CASKS WESTY YUGUN RZC PINNE HEXER EOS DROOP WADET NASHE YUGTU DIZZI ZOSKI BUM CUNON DODSN TOP PWE PANNY KSUX", new Time("3:48:48"), undefined),
+    new ExpectedFlightPlan("Little Rock to Souix City 4", "KLIT ROLAN V534 SCRAN V527 RZC V13 EOS V307 CNU V131 TOP PWE SUX KSUX", "KLIT ROLAN BIBBS HAAWK SCRAN CASKS WESTY YUGUN RZC PINNE HEXER EOS NERNE OSW KUBKY CNU KACED HOCJO TOP PWE SUX KSUX", new Time("3:51:21"), undefined),
+];
diff --git a/PerformanceTests/RexBench/FlightPlanner/flight_planner.js b/PerformanceTests/RexBench/FlightPlanner/flight_planner.js
new file mode 100644 (file)
index 0000000..52f3c2e
--- /dev/null
@@ -0,0 +1,1657 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ * Copyright (C) 2016-2017 Michael Saboff. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+"use strict";
+
+let earthRadius = 3440; // In nautical miles.
+let TwoPI = Math.PI * 2;
+let degreeCharacter = "\u00b0";
+
+let regExpOptionalUnicodeFlag;
+var keywords;
+
+if (this.useUnicode) {
+    regExpOptionalUnicodeFlag = "u";
+    keywords = UnicodeStrings;
+} else {
+    regExpOptionalUnicodeFlag = "";
+    keywords = { get: function(str) { return str; } };
+}
+
+function status(text)
+{
+    console.debug("Status: " + text);
+}
+
+function error(text)
+{
+    console.error("Error: " + text);
+}
+
+if (typeof(Number.prototype.toRadians) === "undefined") {
+    Number.prototype.toRadians = function() {
+        return this * Math.PI / 180;
+    }
+}
+
+if (typeof(Number.prototype.toDegrees) === "undefined") {
+    Number.prototype.toDegrees = function() {
+        return this * 180 / Math.PI;
+    }
+}
+
+function distanceFromSpeedAndTime(speed, time)
+{
+    return speed * time.hours();
+}
+
+let LatRE = new RegExp("^([NS\\-])?(90|[0-8]?\\d)(?:( [0-5]?\\d\\.\\d{0,3})'?|(\\.\\d{0,6})|( ([0-5]?\\d)\" ?([0-5]?\\d)'?))?", "i" + regExpOptionalUnicodeFlag);
+
+function decimalLatitudeFromString(latitudeString)
+{
+    if (typeof latitudeString != "string")
+        return 0;
+
+    let match = latitudeString.match(LatRE);
+
+    if (!match)
+        return 0;
+
+    let result = 0;
+    let sign = 1;
+
+    if (match[1] && (match[1].toUpperCase() == "S" || match[1] == "-"))
+        sign = -1;
+
+    result = Number(match[2]);
+
+    if (result != 90) {
+        if (match[3]) {
+            // e.g. N37 42.874
+            let minutes = Number(match[3]);
+            result = result + (minutes / 60);
+        } else if (match[4]) {
+            // e.g. N37.30697
+            let decimalDegrees = Number(match[4]);
+            result = result + decimalDegrees;
+        } else if (match[5]) {
+            // e.g. N37 18" 27'
+            let degrees = Number(match[6]);
+            let minutes = Number(match[7]);
+            result = result + (degrees + minutes / 60) / 60;
+        }
+    }
+
+    return result * sign;
+}
+
+let LongRE = new RegExp("^([EW\\-]?)(180|(?:1[0-7]|\\d)?\\d)(?:( [0-5]?\\d\\.\\d{0,3})|(\\.\\d{0,6})|( ([0-5]?\\d)\" ?([0-5]?\\d)'?)?)", "i" + regExpOptionalUnicodeFlag);
+
+function decimalLongitudeFromString(longitudeString)
+{
+    if (typeof longitudeString != "string")
+        return 0;
+
+    let match = longitudeString.match(LongRE);
+
+    if (!match)
+        return 0;
+
+    let result = 0;
+    let sign = 1;
+
+    if (match[1] && (match[1].toUpperCase() == "W" || match[1] == "-"))
+        sign = -1;
+
+    result = Number(match[2]);
+
+    if (result != 180) {
+        if (match[3]) {
+            // e.g. W121 53.254
+            let minutes = Number(match[3]);
+            result = result + (minutes / 60);
+        } else if (match[4]) {
+            // e.g. W121.8876
+            let decimalDegrees = Number(match[4]);
+            result = result + decimalDegrees;
+        } else if (match[5]) {
+            // e.g. W121 53" 15'
+            let degrees = Number(match[6]);
+            let minutes = Number(match[7]);
+            result = result + (degrees + minutes / 60) / 60;
+        }
+    }
+
+    return result * sign;
+}
+
+let TimeRE = new RegExp("^([0-9][0-9]?)(?:\:([0-5][0-9]))?(?:\:([0-5][0-9]))?$");
+
+class Time
+{
+    constructor(time)
+    {
+        if (time instanceof Date) {
+            this._seconds = Math.Round(time.valueOf() / 1000);
+            return;
+        }
+
+        if (typeof time == "string") {
+            let match = time.match(TimeRE);
+
+            if (!match) {
+                this._seconds = 0;
+                return;
+            }
+
+            if (match[3]) {
+                let hours = parseInt(match[1].toString());
+                let minutes = parseInt(match[2].toString());
+                let seconds = parseInt(match[3].toString());
+
+                this._seconds = (hours * 60 + minutes) * 60 + seconds;
+            } else if (match[2]) {
+                let minutes = parseInt(match[1].toString());
+                let seconds = parseInt(match[2].toString());
+
+                this._seconds = minutes * 60 + seconds;
+            } else
+                this._seconds = parseInt(match[1].toString());
+            return;
+        }
+
+        if (typeof time == "number") {
+            this._seconds = Math.round(time);
+            return;
+        }
+
+        this._seconds = 0;
+    }
+
+    add(otherTime)
+    {
+        return new Time(this._seconds + otherTime._seconds);
+    }
+
+    addDate(otherDate)
+    {
+        return new Date(this._seconds * 1000 + otherDate.valueOf());
+    }
+
+    static differenceBetween(time2, time1)
+    {
+        let seconds1;
+        let seconds2;
+        if (time1 instanceof Time)
+            seconds1 = time1.seconds();
+        else
+            seconds1 = Math.Round(time1.valueOf() / 1000);
+
+        if (time2 instanceof Time)
+            seconds2 = time2.seconds();
+        else
+            seconds2 = Math.Round(time2.valueOf() / 1000);
+
+        return new Time(seconds2 - seconds1);
+    }
+
+    seconds()
+    {
+        return this._seconds;
+    }
+
+    minutes()
+    {
+        return this._seconds / 60;
+    }
+
+    hours()
+    {
+        return this._seconds / 3600;
+    }
+
+    toString()
+    {
+        let result = "";
+        let seconds = this._seconds % 60;
+        if (seconds < 0) {
+            result = "-";
+            seconds = -seconds;
+        }
+        let minutes = this._seconds / 60 | 0;
+        let hours = minutes / 60 | 0;
+        minutes = minutes % 60;
+
+        if (hours)
+            result = result + hours + ":";
+        if (minutes < 10 && hours)
+            result = result + "0";
+        result = result + minutes + ":";
+        if (seconds < 10)
+            result = result + "0";
+        result = result + seconds;
+
+        return result;
+    }
+}
+
+class GeoLocation
+{
+    constructor(latitude, longitude)
+    {
+        this.latitude = latitude;
+        this.longitude = longitude;
+    }
+
+    latitudeString()
+    {
+        let latitude = this.latitude;
+        let latitudePrefix = "N";
+        if (latitude < 0) {
+            latitude = -latitude;
+            latitudePrefix = "S"
+        }
+        let latitudeDegrees = Math.floor(latitude);
+        let latitudeMinutes = ((latitude - latitudeDegrees) * 60).toFixed(3);
+        let latitudeMinutesFiller = latitudeMinutes < 10 ? " " : "";
+        return latitudePrefix + latitudeDegrees + degreeCharacter + latitudeMinutesFiller + latitudeMinutes + "'";
+    }
+
+    longitudeString()
+    {
+        let longitude = this.longitude;
+        let longitudePrefix = "E";
+        if (longitude < 0) {
+            longitude = -longitude;
+            longitudePrefix = "W"
+        }
+
+        let longitudeDegrees = Math.floor(longitude);
+        let longitudeMinutes = ((longitude - longitudeDegrees) * 60).toFixed(3);
+        let longitudeMinutesFiller = longitudeMinutes < 10 ? " " : "";
+        return longitudePrefix + longitudeDegrees + degreeCharacter + longitudeMinutesFiller + longitudeMinutes + "'";
+    }
+
+    distanceTo(otherLocation)
+    {
+        let dLat = (otherLocation.latitude - this.latitude).toRadians();
+        let dLon = (otherLocation.longitude - this.longitude).toRadians();
+        let a = Math.sin(dLat/2) * Math.sin(dLat/2) +
+            Math.cos(this.latitude.toRadians()) * Math.cos(otherLocation.latitude.toRadians()) *
+            Math.sin(dLon/2) * Math.sin(dLon/2);
+        let c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
+        return earthRadius * c;
+    }
+    
+    bearingFrom(otherLocation, magneticVariation)
+    {
+        if (magneticVariation == undefined)
+            magneticVariation = 0;
+
+        let dLon = (this.longitude - otherLocation.longitude).toRadians();
+        let thisLatitudeRadians = this.latitude.toRadians();
+        let otherLatitudeRadians = otherLocation.latitude.toRadians();
+        let y = Math.sin(dLon) * Math.cos(this.latitude.toRadians());
+        let x = Math.cos(otherLatitudeRadians) * Math.sin(thisLatitudeRadians) -
+            Math.sin(otherLatitudeRadians) * Math.cos(thisLatitudeRadians) * Math.cos(dLon);
+        return (Math.atan2(y, x).toDegrees() + 720 + magneticVariation) % 360;
+    }
+
+    bearingTo(otherLocation, magneticVariation)
+    {
+        if (magneticVariation == undefined)
+            magneticVariation = 0;
+
+        let dLon = (otherLocation.longitude - this.longitude).toRadians();
+        let thisLatitudeRadians = this.latitude.toRadians();
+        let otherLatitudeRadians = otherLocation.latitude.toRadians();
+        let y = Math.sin(dLon) * Math.cos(otherLocation.latitude.toRadians());
+        let x = Math.cos(thisLatitudeRadians) * Math.sin(otherLatitudeRadians) -
+            Math.sin(thisLatitudeRadians) * Math.cos(otherLatitudeRadians) * Math.cos(dLon);
+        return (Math.atan2(y, x).toDegrees() + 720 + magneticVariation) % 360
+    }
+
+    locationFrom(bearing, distance, magneticVariation)
+    {
+        if (magneticVariation == undefined)
+            magneticVariation = 0;
+
+        let bearingRadians = (bearing - magneticVariation).toRadians();
+        let thisLatitudeRadians = this.latitude.toRadians();
+        let angularDistance = distance / earthRadius;
+        let latitudeRadians = Math.asin(Math.sin(thisLatitudeRadians) * Math.cos(angularDistance) +
+                                 Math.cos(thisLatitudeRadians) * Math.sin(angularDistance) * Math.cos(bearingRadians));
+        let longitudeRadians = this.longitude.toRadians() +
+            Math.atan2(Math.sin(bearingRadians) * Math.sin(angularDistance) * Math.cos(thisLatitudeRadians),
+                       Math.cos(angularDistance) - Math.sin(thisLatitudeRadians) * Math.sin(latitudeRadians));
+
+        return new GeoLocation(latitudeRadians.toDegrees(), longitudeRadians.toDegrees());
+    }
+
+    toString()
+    {
+        return "(" + this.latitudeString() + ", " + this.longitudeString() + ")";
+    }
+}
+
+function findFaaWaypoint(waypoint)
+{
+    return faaWaypoints[waypoint];
+}
+
+class FaaWaypoints
+{
+    constructor()
+    {
+        if (!FaaWaypoints.instance) {
+            FaaWaypoints.instance = this;
+            this.waypoints = _faaWaypoints;
+        }
+
+        return FaaWaypoints.instance;
+    }
+
+    find(waypoint)
+    {
+        return this.waypoints[waypoint];
+    }
+}
+
+FaaWaypoints.instance = undefined;
+
+let faaWaypoints = new FaaWaypoints();
+
+class FaaAirways
+{
+    constructor()
+    {
+        if (!FaaAirways.instance) {
+            FaaAirways.instance = this;
+            this.airways = _faaAirways;
+        }
+
+        return FaaAirways.instance;
+    }
+
+    isAirway(identifier)
+    {
+        return !!this.airways[identifier];
+    }
+
+    resolveAirway(airwayID, entryPoint, exitPoint)
+    {
+        let airway = this.airways[airwayID];
+
+        if (!airway)
+            return "";
+
+        let entryIndex = airway.fixes.indexOf(entryPoint);
+        let exitIndex = airway.fixes.indexOf(exitPoint);
+
+        if (entryIndex == -1 || exitIndex == -1)
+            return "";
+
+        let stride = (entryIndex <= exitIndex) ? 1 : -1;
+
+        let route = [];
+
+        for (let idx = entryIndex; idx != exitIndex; idx = idx + stride)
+            route.push(airway.fixes[idx]);
+
+        route.push(airway.fixes[exitIndex]);
+
+        return route;
+    }
+}
+
+FaaAirways.instance = undefined;
+
+let faaAirways = new FaaAirways();
+
+class UserWaypoints
+{
+    constructor()
+    {
+        if (!UserWaypoints.instance) {
+            UserWaypoints.instance = this;
+            this.waypoints = {};
+        }
+
+        return UserWaypoints.instance;
+    }
+
+    clear()
+    {
+        this.waypoints = {};
+    }
+
+    find(waypoint)
+    {
+        return this.waypoints[waypoint];
+    }
+
+    update(name, description, latitude, longitude)
+    {
+        if (typeof latitude == "string")
+            latitude = decimalLatitudeFromString(latitude);
+
+        if (typeof longitude == "string")
+            longitude = decimalLongitudeFromString(longitude);
+
+        this.waypoints[name.toUpperCase()] = {
+            "name": name,
+            "description": description,
+            "latitude": latitude,
+            "longitude": longitude
+        };
+    }
+}
+
+UserWaypoints.instance = undefined;
+
+let userWaypoints = new UserWaypoints();
+
+
+class EngineConfig
+{
+    constructor(type, fuelFlow, trueAirspeed)
+    {
+        this.type = type;
+        this._fuelFlow = fuelFlow;
+        this._trueAirspeed = trueAirspeed;
+    }
+
+    trueAirspeed()
+    {
+        return this._trueAirspeed;
+    }
+
+    fuelFlow()
+    {
+        return this._fuelFlow;
+    }
+
+    static appendConfig(type, fuelFlow, trueAirspeed)
+    {
+        if (this.allConfigsByType[type]) {
+            status("Duplicate Engine configuration: " + type);
+            return;
+        }
+
+        var newConfig = new EngineConfig(type, fuelFlow, trueAirspeed);
+        this.allConfigs.push(newConfig);
+        this.allConfigsByType[type] = newConfig;
+    }
+
+    static getConfig(n)
+    {
+        if (n >= this.allConfigs.length)
+            return undefined;
+
+        return this.allConfigs[n];
+    }
+}
+
+EngineConfig.allConfigs = [];
+EngineConfig.allConfigsByType = {};
+EngineConfig.Taxi = 0;
+EngineConfig.Runup = 1;
+EngineConfig.Takeoff = 2;
+EngineConfig.Climb = 3;
+EngineConfig.Cruise = 4;
+EngineConfig.Pattern= 5;
+
+class Waypoint
+{
+    constructor(name, type, description, latitude, longitude)
+    {
+        this.name = name;
+        this.type = type;
+        this.description = description;
+        this.latitude = latitude;
+        this.longitude = longitude;
+    }
+}
+
+class Leg
+{
+    constructor(fix, location)
+    {
+        this.previous = undefined;
+        this.next = undefined;
+        this.fix = fix;
+        this.location = location;
+        this.course = 0;
+        this.distance = 0;
+        this.trueAirspeed = 0;
+        this.windDirection = 0;
+        this.windSpeed = 0;
+        this.heading = 0;
+        this.estGS = 0;
+        this.startFlightTiming = false;
+        this.stopFlightTiming = false;
+        this.engineConfig = EngineConfig.Cruise;
+        this.fuelFlow = 0;
+        this.distanceRemaining = 0;
+        this.estimatedTimeEnroute = undefined;
+        this.estTimeRemaining = 0;
+        this.estFuel = 0;
+    }
+
+    fixName()
+    {
+        return this.fix;
+    }
+
+    toString()
+    {
+        return this.fix;
+    }
+
+    setPrevious(leg)
+    {
+        this.previous = leg;
+    }
+
+    previousLeg()
+    {
+        return this.previous;
+    }
+
+    setNext(leg)
+    {
+        this.next = leg;
+    }
+
+    nextLeg()
+    {
+        return this.next;
+    }
+
+    setWind(windDirection, windSpeed)
+    {
+        this.windDirection = windDirection;
+        this.windSpeed = windSpeed;
+    }
+
+    isSameWind(windDirection, windSpeed)
+    {
+        return this.windDirection == windDirection && this.windSpeed == windSpeed;
+    }
+
+    windToString()
+    {
+        if (!this.windSpeed)
+            return "";
+
+        return (this.windDirection ? this.windDirection : "360") + "@" + this.windSpeed;
+    }
+
+    setTrueAirspeed(trueAirspeed)
+    {
+        this.trueAirspeed = trueAirspeed;
+    }
+
+    isStandardTrueAirspeed()
+    {
+
+        let engineConfig = EngineConfig.getConfig(this.engineConfig);
+
+        return (this.trueAirspeed == engineConfig.trueAirspeed());
+    }
+
+    trueAirspeedToString()
+    {
+        return this.trueAirspeed + "kts";
+    }
+
+    updateDistanceAndBearing(other)
+    {
+        this.distance = this.location.distanceTo(other);
+        this.course = Math.round(this.location.bearingFrom(other));
+        if (this.estimatedTimeEnroute == undefined && this.estGS != 0) {
+            let estimatedTimeEnrouteInSeconds = Math.round(this.distance * 3600 / this.estGS);
+            this.estimatedTimeEnroute = new Time(estimatedTimeEnrouteInSeconds);
+        }
+
+        if (this.estimatedTimeEnroute.seconds())
+            this.estFuel = this.fuelFlow * this.estimatedTimeEnroute.hours();
+    }
+
+    propagateWind()
+    {
+        let windDirection = this.windDirection;
+        let windSpeed = this.windSpeed;
+
+        windDirection = (windDirection + 360) % 360;
+        if (!windDirection)
+            windDirection = 360;
+
+        for (let currLeg = this; currLeg; currLeg = currLeg.nextLeg()) {
+            currLeg.windDirection = windDirection;
+            currLeg.windSpeed = windSpeed;
+            if (currLeg.stopFlightTiming)
+                break;
+        }
+    }
+
+    updateForWind()
+    {
+        if (!this.windSpeed || !this.trueAirspeed) {
+            this.heading = this.course;
+            this.estGS = this.trueAirspeed;
+            return;
+        }
+
+        let windDirectionRadians = this.windDirection.toRadians();
+        let courseRadians = this.course.toRadians();
+        let swc = (this.windSpeed / this.trueAirspeed) * Math.sin(windDirectionRadians - courseRadians);
+        if (Math.abs(swc) > 1) {
+            status("Wind to strong to fly!");
+            return;
+        }
+
+        let headingRadians = courseRadians + Math.asin(swc);
+        if (headingRadians < 0)
+            headingRadians += TwoPI;
+        if (headingRadians > TwoPI)
+            headingRadians -= TwoPI
+        let groundSpeed = this.trueAirspeed * Math.sqrt(1 - swc * swc) -
+            this.windSpeed * Math.cos(windDirectionRadians - courseRadians);
+        if (groundSpeed < 0) {
+            status("Wind to strong to fly!");
+            return;
+        }
+
+        this.estGS = groundSpeed;
+        this.heading = Math.round(headingRadians.toDegrees());
+    }
+
+    calculate()
+    {
+        let engineConfig = EngineConfig.getConfig(this.engineConfig);
+
+        if (!this.trueAirspeed)
+            this.trueAirspeed = engineConfig.trueAirspeed();
+        this.fuelFlow = engineConfig.fuelFlow();
+
+        this.updateForWind();
+    }
+
+    updateForward()
+    {
+        if (this.specialUpdateForward)
+            this.specialUpdateForward();
+
+        let previousLeg = this.previousLeg();
+        let havePrevious = true;
+        if (!previousLeg) {
+            havePrevious = false;
+            previousLeg = this;
+            if (!this.estimatedTimeEnroute)
+                this.estimatedTimeEnroute = new Time(0);
+        }
+
+        let thisLegType = this.type;
+        if (thisLegType == "Climb" && havePrevious)
+            this.location = previousLeg.location;
+        else {
+            this.updateDistanceAndBearing(previousLeg.location);
+            this.updateForWind();
+            let nextLeg = this.nextLeg();
+            let previousLegType = previousLeg.type;
+            if (havePrevious) {
+                if (previousLegType == "Climb") {
+                    let climbDistance = distanceFromSpeedAndTime(previousLeg.estGS, previousLeg.climbTime);
+                    if (climbDistance < this.distance) {
+                        let climbStartLocation = previousLeg.location;
+                        let climbEndLocation = climbStartLocation.locationFrom(this.course, climbDistance);
+                        previousLeg.location = climbEndLocation;
+                        previousLeg.updateDistanceAndBearing(climbStartLocation);
+                        this.estimatedTimeEnroute = undefined;
+                        this.updateDistanceAndBearing(climbEndLocation);
+                    } else {
+                        status("Not enough distance to climb in leg #" + previousLeg.index);
+                    }
+                } else if ((thisLegType == "Left" || thisLegType == "Right") && nextLeg && nextLeg.location) {
+                    let standardRateCircumference = this.trueAirspeed / 30;
+                    let standardRateRadius = standardRateCircumference / TwoPI;
+                    let offsetInboundBearing = 360 + previousLeg.course + (thisLegType == "Left" ? -90 : 90);
+                    offsetInboundBearing = Math.round((offsetInboundBearing + 360) % 360);
+                    // Save original location
+                    if (!previousLeg.originalLocation)
+                        previousLeg.originalLocation = previousLeg.location;
+                    let previousLocation = previousLeg.originalLocation;
+                    let inboundLocation = previousLocation.locationFrom(offsetInboundBearing, standardRateRadius);
+                    let bearingToNext = Math.round(nextLeg.location.bearingFrom(previousLocation));
+                    let offsetOutboundBearing = bearingToNext + (thisLegType == "Left" ? 90 : -90);
+                    offsetOutboundBearing = (offsetOutboundBearing + 360) % 360;
+                    let outboundLocation = previousLocation.locationFrom(offsetOutboundBearing, standardRateRadius);
+                    let turnAngle = thisLegType == "Left" ? (360 + bearingToNext - previousLeg.course) : (360 + previousLeg.course - bearingToNext);
+                    turnAngle = (turnAngle + 360) % 360;
+                    let totalDegrees = turnAngle + 360 * this.extraTurns;
+                    let secondsInTurn = Math.round(totalDegrees / 3);
+                    this.estimatedTimeEnroute = new Time(Math.round((turnAngle + 360 * this.extraTurns) / 3));
+                    this.estFuel = this.fuelFlow * this.estimatedTimeEnroute.hours();
+                    this.location = outboundLocation;
+                    this.distance = distanceFromSpeedAndTime(this.trueAirspeed, this.estimatedTimeEnroute);
+                    previousLeg.location = inboundLocation;
+                    let prevPrevLeg = previousLeg.previousLeg();
+                    if (prevPrevLeg && prevPrevLeg.location) {
+                        previousLeg.estimatedTimeEnroute = undefined;
+                        previousLeg.updateDistanceAndBearing(prevPrevLeg.location);
+                    }
+                }
+            }
+        }
+    }
+
+    updateBackward()
+    {
+        let nextLeg = this.nextLeg();
+
+        let distanceRemaining;
+        let timeRemaining;
+
+        if (nextLeg) {
+            distanceRemaining = nextLeg.distanceRemaining;
+            timeRemaining = nextLeg.estTimeRemaining;
+        } else {
+            distanceRemaining = 0;
+            timeRemaining = new Time(0);
+        }
+
+        if (this.stopFlightTiming || timeRemaining.seconds()) {
+            this.distanceRemaining = distanceRemaining + this.distance;;
+            this.estTimeRemaining = timeRemaining.add(this.estimatedTimeEnroute);
+        } else
+            this.estTimeRemaining = new Time(0);
+    }
+}
+
+let RallyLegWithFixRE = new RegExp("^([0-9a-z\.]{3,16})\\|(" + keywords.get("START") + "|" + keywords.get("TIMING") + ")", "i" + regExpOptionalUnicodeFlag);
+
+class RallyLeg extends Leg
+{
+    constructor(type, fix, location, engineConfig)
+    {
+        super(fix, location);
+        this.type = type;
+        this.engineConfig = engineConfig;
+    }
+
+    fixName()
+    {
+        return this.type;
+    }
+
+    toString()
+    {
+        return this.fixName();
+    }
+
+    static reset()
+    {
+        RallyLeg.startLocation = undefined;
+        RallyLeg.startFix = "";
+        RallyLeg.totalTaxiTime = new Time(0);
+        RallyLeg.taxiSegments = [];
+    }
+
+    static fixNeeded(fix)
+    {
+        let match = fix.match(RallyLegWithFixRE);
+
+        if (!match)
+            return "";
+
+        return match[1].toString();
+    }
+
+    static getLegWithFix(waypointText, fix, location)
+    {
+        let match = waypointText.match(RallyLegWithFixRE);
+
+        if (!match)
+            return undefined;
+
+        let legType = match[2].toString();
+
+        if (legType == keywords.get("START")) {
+            if (this.startLocation) {
+                status("Trying to create second start leg");
+                return undefined;
+            }
+
+            this.startLocation = location;
+            this.startFix = fix;
+            this.totalTaxiTime = new Time(0);
+            this.taxiSegments = [];
+
+            return new StartLeg(waypointText, fix, location);
+        }
+
+        if (legType == keywords.get("TIMING"))
+            return new TimingLeg(waypointText, fix, location);
+
+
+        error("Unhandled Rally Leg type " + legType);
+        return undefined;
+    }
+}
+
+RallyLeg.startLocation = undefined;
+RallyLeg.startFix = "";
+RallyLeg.totalTaxiTime = new Time(0);
+RallyLeg.taxiSegments = [];
+
+class StartLeg extends RallyLeg
+{
+    constructor(fixText, fix, location)
+    {
+        super("Start", fix, location, EngineConfig.Taxi);
+    }
+
+    fixName()
+    {
+        return this.fix + "|Start";
+    }
+}
+
+class TimingLeg extends RallyLeg
+{
+    constructor(fixText, fix, location)
+    {
+        super("Timing", fix, location, EngineConfig.Cruise);
+        this.stopFlightTiming = true;
+    }
+
+    fixName()
+    {
+        return this.fix + "|Timing";
+    }
+}
+
+let RallyLegNoFixRE = new RegExp(keywords.get("TAXI") + "|" + keywords.get("RUNUP") + "|" + keywords.get("TAKEOFF") + "|" + keywords.get("CLIMB") + "|" + keywords.get("PATTERN") + "|" + keywords.get("LEFT") + "|" + keywords.get("RIGHT"), "i" + regExpOptionalUnicodeFlag);
+
+class RallyLegWithoutFix extends RallyLeg
+{
+    constructor(type, CommentsAsFix, location, engineConfig)
+    {
+        super(type, CommentsAsFix, location, engineConfig);
+    }
+
+    setPrevious(previous)
+    {
+        if (this.setLocationFromPrevious() && previous)
+            this.location = previous.location;
+
+        super.setPrevious(previous);
+    }
+
+    setLocationFromPrevious()
+    {
+        return false;
+    }
+
+    static isRallyLegWithoutFix(fix)
+    {
+        let barPosition = fix.indexOf("|");
+        let firstPart = barPosition < 0 ? fix : fix.substring(0, barPosition);
+
+        return RallyLegNoFixRE.test(firstPart);
+    }
+
+    static getLegNoFix(waypointText)
+    {
+        let barPosition = waypointText.indexOf("|");
+        let firstPart = barPosition < 0 ? waypointText : waypointText.substring(0, barPosition);
+        firstPart = firstPart.toUpperCase();
+
+        let match = firstPart.match(RallyLegNoFixRE);
+
+        if (!match)
+            return undefined;
+
+        let legType = match[0].toString();
+
+        if (legType == keywords.get("TAXI"))
+            return new TaxiLeg(waypointText);
+
+        if (legType == keywords.get("RUNUP"))
+            return new RunupLeg(waypointText);
+
+        if (legType == keywords.get("TAKEOFF")) {
+            if (!this.startLocation) {
+                status("Trying to create a Takeoff leg without start leg");
+                return undefined;
+            }
+
+            return new TakeoffLeg(waypointText);
+        }
+
+        if (legType == keywords.get("CLIMB"))
+            return new ClimbLeg(waypointText);
+
+        if (legType == keywords.get("PATTERN"))
+            return new PatternLeg(waypointText);
+
+        if (legType == keywords.get("LEFT") || legType == keywords.get("RIGHT"))
+            return new TurnLeg(waypointText, legType == keywords.get("RIGHT"));
+
+        error("Unhandled Rally Leg type " + legType);
+        return undefined;
+    }
+}
+
+// TAXI[|<time>]  e.g. TAXI|2:30
+let TaxiLegRE = new RegExp("^" + keywords.get("TAXI") + "(?:\\|([0-9][0-9]?(?:\:[0-5][0-9])?))?$", "i" + regExpOptionalUnicodeFlag);
+
+class TaxiLeg extends RallyLegWithoutFix
+{
+    constructor(fixText)
+    {
+        let match = fixText.match(TaxiLegRE);
+
+        super("Taxi", "", new GeoLocation(-1, -1), EngineConfig.Taxi);
+
+        let taxiTimeString = "5:00";
+        if (match[1])
+            taxiTimeString = match[1].toString();
+
+        this.estimatedTimeEnroute = new Time(taxiTimeString);
+    }
+
+    setLocationFromPrevious()
+    {
+        return true;
+    }    
+
+    fixName()
+    {
+        return "Taxi|" + this.estimatedTimeEnroute.toString();
+    }
+}
+
+// RUNUP[|<time>]  e.g. RUNUP|0:30
+let RunupLegRE = new RegExp("^" + keywords.get("RUNUP") + "(?:\\|([0-9][0-9]?(?:\:[0-5][0-9])?))?$", "i" + regExpOptionalUnicodeFlag);
+
+class RunupLeg extends RallyLegWithoutFix
+{
+    constructor(fixText)
+    {
+        let match = fixText.match(RunupLegRE);
+
+        super("Runup", "", new GeoLocation(-1, -1), EngineConfig.Runup);
+
+        let runupTimeString = "30";
+        if (match[1])
+            runupTimeString = match[1].toString();
+
+        this.estimatedTimeEnroute = new Time(runupTimeString);
+    }
+
+    setLocationFromPrevious()
+    {
+        return true;
+    }    
+
+    fixName()
+    {
+        return "Runup|" + this.estimatedTimeEnroute.toString();
+    }
+}
+
+// TAKEOFF[|<time>][|<bearing>|<distance>]  e.g. TAKEOFF|2:00|270@3.5
+let TakeoffLegRE = new RegExp("^" + keywords.get("TAKEOFF") + "(?:\\|([0-9][0-9]?(?:\:[0-5][0-9])?))?(?:\\|([0-9]{1,2}|[0-2][0-9][0-9]|3[0-5][0-9]|360)(?:@)(\\d{1,2}(?:\\.\\d{1,4})?))?$", "i" + regExpOptionalUnicodeFlag);
+
+class TakeoffLeg extends RallyLegWithoutFix
+{
+    constructor(fixText)
+    {
+        let match = fixText.match(TakeoffLegRE);
+
+        let bearingFromStart = 0;
+        let distanceFromStart = 0;
+        let takeoffEndLocation = RallyLeg.startLocation;
+        if (match && match[2] && match[3]) {
+            bearingFromStart = parseInt(match[2].toString()) % 360;
+            distanceFromStart = parseFloat(match[3].toString());
+            takeoffEndLocation = RallyLeg.startLocation.locationFrom(bearingFromStart, distanceFromStart);
+        }
+
+        super("Takeoff", "", takeoffEndLocation, EngineConfig.Takeoff);
+
+        this.bearingFromStart = bearingFromStart;
+        this.distanceFromStart = distanceFromStart;
+
+        let takeoffTimeString = "2:00";
+        if (match[1])
+            takeoffTimeString = match[1].toString();
+
+        this.estimatedTimeEnroute = new Time(takeoffTimeString);
+        this.startFlightTiming = true;
+    }
+
+    fixName()
+    {
+        let result = "Takeoff";
+
+        if (this.estimatedTimeEnroute.seconds() != 120)
+            result += "|" + this.estimatedTimeEnroute.toString();
+        if (this.distanceFromStart)
+            result += "|" + this.bearingFromStart + "@" + this.distanceFromStart;
+
+        return result;
+    }
+}
+
+// CLIMB|<alt>|<time>  e.g. CLIMB|5000|7:00
+let ClimbLegRE = new RegExp("^" + keywords.get("CLIMB") + "(?:\\|)(\\d{3,5})(?:\\|([0-9][0-9]?(?:\:[0-5][0-9])?))$", "i" + regExpOptionalUnicodeFlag);
+
+class ClimbLeg extends RallyLegWithoutFix
+{
+    constructor(fixText)
+    {
+        let match = fixText.match(ClimbLegRE);
+
+        let altitude = 5500;
+        if (match && match[1])
+            altitude = match[1].toString();
+
+        super("Climb", altitude + "\"", undefined, EngineConfig.Climb);
+
+        let timeToClimb = "8:00";
+        if (match && match[2])
+            timeToClimb = match[2].toString();
+
+        this.altitude = altitude;
+        this.climbTime = this.estimatedTimeEnroute = new Time(timeToClimb);
+    }
+
+    setLocationFromPrevious()
+    {
+        return true;
+    }    
+
+    fixName()
+    {
+        return "Climb|" + this.altitude + "|" + this.estimatedTimeEnroute.toString();
+    }
+}
+
+// PATTERN|<time>  e.g. PATTERN|0:30
+let PatternLegRE = new RegExp("^" + keywords.get("PATTERN") + "(?:\\|([0-9][0-9]?(?:\:[0-5][0-9])?))$", "i" + regExpOptionalUnicodeFlag);
+
+class PatternLeg extends RallyLegWithoutFix
+{
+    constructor(fixText)
+    {
+        super("Pattern", "", undefined, EngineConfig.Pattern);
+
+        let match = fixText.match(PatternLegRE);
+        let patternTimeString = match[1].toString();
+        this.estimatedTimeEnroute = new Time(patternTimeString);
+    }
+
+    setLocationFromPrevious()
+    {
+        return true;
+    }    
+
+    fixName()
+    {
+        return "Pattern|" + this.estimatedTimeEnroute.toString();
+    }
+}
+
+// {LEFT,RIGHT}[|+<extra_turns>]  e.g. LEFT|2
+let TurnLegRE = new RegExp("^(" + keywords.get("LEFT") + "|" + keywords.get("RIGHT") + ")(?:\\|\\+(\\d))?$", "i");
+
+class TurnLeg extends RallyLegWithoutFix
+{
+    constructor(fixText, isRightTurn)
+    {
+        let match = fixText.match(TurnLegRE);
+
+        let direction = "Left";
+        if (match && match[1])
+            direction = match[1].toString().toUpperCase() == keywords.get("LEFT") ? "Left" : "Right";
+
+        let engineConfig = EngineConfig.Cruise;
+
+        super(direction, "", new GeoLocation(-1, -1), engineConfig);
+
+        this.extraTurns = (match && match[2]) ? parseInt(match[2]) : 0;
+    }
+
+    fixName()
+    {
+        let result = this.type;
+        if (this.extraTurns)
+            result += ("|+" + this.extraTurns);
+
+        return result;
+    }
+}
+
+let LegModifier = new RegExp("(360|3[0-5][0-9]|[0-2][0-9]{2}|[0-9]{1,2})@([0-9]{1,3})|([1-9][0-9]{1,2}|0)kts", "i");
+
+class FlightPlan
+{
+    constructor(name, route)
+    {
+        this._name = name;
+        this._route = route;
+        this._firstLeg = undefined;
+        this._lastLeg = undefined;
+        this._legCount = 0;
+        this._defaultWindDirection = 0;
+        this._defaultWindSpeed = 0;
+        this._trueAirspeedOverride = 0;
+        this._timeToGate = undefined;
+        this._estimatedTimeEnroute = undefined;
+        this._totalFuel = 0;
+        this._totalTime = new Time();
+        this._gateTime = new Time();
+
+        RallyLeg.reset();   //  Refactor to make this more OO
+    }
+
+    clear()
+    {
+    }
+
+    appendLeg(leg)
+    {
+        if (!this._firstLeg)
+            this._firstLeg = leg;
+        if (this._lastLeg)
+            this._lastLeg.setNext(leg);
+        leg.setPrevious(this._lastLeg);
+        leg.setNext(undefined);
+
+        if (this._trueAirspeedOverride) {
+            leg.setTrueAirspeed(this._trueAirspeedOverride);
+            this.clearTrueAirspeedOverride(0);
+        }
+
+        if (this._defaultWindSpeed)
+            leg.setWind(this._defaultWindDirection, this._defaultWindSpeed);
+
+        this._lastLeg = leg;
+        this._legCount++;
+    }
+
+    setDefaultWind(windDirection, windSpeed)
+    {
+        this._defaultWindDirection = windDirection;
+        this._defaultWindSpeed = windSpeed;
+    }
+
+    clearTrueAirspeedOverride()
+    {
+        this._trueAirspeedOverride = 0;
+    }
+
+    setTrueAirspeedOverride(trueAirspeed)
+    {
+        this._trueAirspeedOverride = trueAirspeed;
+    }
+
+    isLegModifier(fix)
+    {
+        return LegModifier.test(fix);
+    }
+
+    processLegModifier(fix)
+    {
+        let match = fix.match(LegModifier);
+
+        if (match) {
+            if (match[1] && match[2]) {
+                let windDirection = parseInt(match[1].toString()) % 360;
+                let windSpeed = parseInt(match[2].toString());
+
+                this.setDefaultWind(windDirection, windSpeed);
+            } else if (match[3]) {
+                let trueAirspeed = parseInt(match[3].toString());
+                this.setTrueAirspeedOverride(trueAirspeed);
+            }
+        }
+    }
+
+    resolveWaypoint(waypointText)
+    {
+        if (this.isLegModifier(waypointText))
+            this.processLegModifier(waypointText);
+        else if (RallyLegWithoutFix.isRallyLegWithoutFix(waypointText)) {
+            let rallyLeg = RallyLegWithoutFix.getLegNoFix(waypointText);
+            if (rallyLeg)
+                this.appendLeg(rallyLeg);
+        } else {
+            let fixName = RallyLeg.fixNeeded(waypointText);
+            let isRallyWaypoint = false;
+
+            if (fixName)
+                isRallyWaypoint = true;
+            else
+                fixName = waypointText;
+
+            let waypoint = userWaypoints.find(fixName);
+            if (!waypoint)
+                waypoint = faaWaypoints.find(fixName);
+            if (!waypoint) {
+                error("Couldn't find waypoint \"" + waypointText + "\"");
+                return;
+            }
+
+            let location = new GeoLocation(waypoint.latitude, waypoint.longitude);
+
+            if (isRallyWaypoint) {
+                let rallyLeg = RallyLeg.getLegWithFix(waypointText, fixName, location);
+                this.appendLeg(rallyLeg);
+            } else
+                this.appendLeg(new Leg(waypoint.name, location));
+        }
+    }
+
+    parseRoute()
+    {
+        let waypointsToLookup = this._route.split(/ +/);
+        let priorWaypoint = "";
+
+        for (let waypointIndex = 0; waypointIndex < waypointsToLookup.length; waypointIndex++) {
+            let currentWaypoint = waypointsToLookup[waypointIndex].toUpperCase();
+            if (faaAirways.isAirway(currentWaypoint) && (waypointIndex + 1) < waypointsToLookup.length) {
+                let exitWaypointFix = waypointsToLookup[waypointIndex + 1];
+                let airwayFixes = faaAirways.resolveAirway(currentWaypoint, priorWaypoint, exitWaypointFix);
+
+                // We skip the entry and exit fixes, because they are handled in the prior / next
+                // iterations of the outer loop.
+                for (let airwayFixIndex = 1; airwayFixIndex < airwayFixes.length - 1; airwayFixIndex++)
+                    this.resolveWaypoint(airwayFixes[airwayFixIndex]);
+            } else
+                this.resolveWaypoint(currentWaypoint);
+            
+            priorWaypoint = currentWaypoint;
+        }
+    }
+
+    calculate()
+    {
+        if (!this._firstLeg)
+            return;
+
+        let haveStartTiming = false;
+        let haveStopTiming = false;
+        for (let thisLeg = this._firstLeg; thisLeg; thisLeg = thisLeg.nextLeg()) {
+            thisLeg.calculate();
+            if (thisLeg.startFlightTiming) {
+                if (haveStartTiming)
+                    status("Have duplicate Start timing leg in row " + thisLeg.toString());
+                haveStartTiming = true;
+            }
+            if (thisLeg.stopFlightTiming) {
+                if (haveStopTiming)
+                    status("Have duplicate Timing leg in row " + thisLeg.toString());
+                haveStopTiming = true;
+            }
+        }
+
+        if (!haveStartTiming)
+            this._firstLeg.startFlightTiming = true;
+        if (!haveStopTiming)
+            this._lastLeg.stopFlightTiming = true;
+
+        for (let thisLeg = this._firstLeg; thisLeg; thisLeg = thisLeg.nextLeg())
+            thisLeg.updateForward();
+
+        for (let thisLeg = this._lastLeg; thisLeg; thisLeg = thisLeg.previousLeg())
+            thisLeg.updateBackward();
+
+        for (let thisLeg = this._firstLeg; thisLeg; thisLeg = thisLeg.nextLeg()) {
+            if (thisLeg.startFlightTiming)
+                this._gateTime = thisLeg.estTimeRemaining;
+        }
+
+        this._totalTime = this._firstLeg.estTimeRemaining;
+    }
+
+    resolvedRoute()
+    {
+        let result = "";
+        let lastWindDirection = 0;
+        let lastWindSpeed = 0;
+
+        let legIndex = 0;
+        let currentLeg = this._firstLeg;
+        
+        for (; currentLeg; currentLeg = currentLeg.nextLeg(), legIndex++) {
+
+            if (legIndex)
+                result = result + " ";
+
+            if (!currentLeg.isSameWind(lastWindDirection, lastWindSpeed)) {
+                result = result + currentLeg.windToString() + " ";
+                lastWindDirection = currentLeg.windDirection;
+                lastWindSpeed = currentLeg.windSpeed;
+            }
+
+            if (!currentLeg.isStandardTrueAirspeed())
+                result = result + currentLeg.trueAirspeedToString() + " ";
+
+            result = result + currentLeg.toString();
+        }
+
+        return result;
+    }
+
+    name()
+    {
+        return this._name;
+    }
+
+    totalTime()
+    {
+        return this._totalTime;
+    }
+    
+    gateTime()
+    {
+        return this._gateTime;
+    }
+    
+    toString()
+    {
+        let result = "";
+        let lastWindDirection = 0;
+        let lastWindSpeed = 0;
+
+        let legIndex = 0;
+        let currentLeg = this._firstLeg;
+        
+        for (; currentLeg; currentLeg = currentLeg.nextLeg(), legIndex++) {
+
+            if (legIndex)
+                result = result + " ";
+
+            if (!currentLeg.isSameWind(lastWindDirection, lastWindSpeed)) {
+                result = result + currentLeg.windToString() + " ";
+                lastWindDirection = currentLeg.windDirection;
+                lastWindSpeed = currentLeg.windSpeed;
+            }
+
+            if (!currentLeg.isStandardTrueAirspeed())
+                result = result + currentLeg.trueAirspeedToString() + " ";
+
+            result = result + currentLeg.toString();
+            result = result + " " + currentLeg.location + " " + currentLeg.distance.toFixed(2) + "nm " + currentLeg.estGS.toFixed(2) + "kts " + currentLeg.estimatedTimeEnroute + " ";
+        }
+
+        if (this._gateTime)
+            result = result + " gate time " + this._gateTime;
+
+        result = result + " total time " + this._firstLeg.estTimeRemaining;
+        return result;
+    }
+}
+
+EngineConfig.appendConfig("Taxi", 2, 0);
+EngineConfig.appendConfig("Runup", 8, 0);
+EngineConfig.appendConfig("Takeoff", 27, 105);
+EngineConfig.appendConfig("Climb", 22, 125);
+EngineConfig.appendConfig("Cruise", 15, 142);
+EngineConfig.appendConfig("Pattern", 11, 95);
+
+class ExpectedFlightPlan
+{
+    constructor(name, route, expectedRoute, expectedTotalTime, expectedGateTime)
+    {
+        this._name = name;
+        this._route = route;
+        this._expectedRoute = expectedRoute;
+        this._expectedTotalTime = expectedTotalTime;
+        this._expectedGateTime = expectedGateTime;
+    }
+
+    reset()
+    {
+        this._flightPlan = new FlightPlan(this._name, this._route);
+    }
+
+    resolveRoute()
+    {
+        this._flightPlan.parseRoute();
+    }
+
+    calculate()
+    {
+        this._flightPlan.calculate();
+    }
+
+    checkExpectations()
+    {
+        if (this._expectedRoute) {
+            let computedRoute = this._flightPlan.resolvedRoute();
+            if (this._expectedRoute != computedRoute)
+                error("Flight plan " + this._flightPlan.name() + " route different than expected (\"" +
+                      this._expectedRoute + "\"), got (\"" + computedRoute + "\")");
+        }
+
+        if (this._expectedTotalTime) {
+            let computedTotalTime = this._flightPlan.totalTime();
+            let deltaTime = Math.abs(Time.differenceBetween(this._expectedTotalTime, computedTotalTime).seconds());
+            if (deltaTime > 5)
+                error("Flight plan " + this._flightPlan.name() + " total time different than expected (" +
+                      this._expectedTotalTime + "), got (" + computedTotalTime + ")");
+        }
+
+        if (this._expectedGateTime) {
+            let computedGateTime = this._flightPlan.gateTime();
+            let deltaTime = Math.abs(Time.differenceBetween(this._expectedGateTime, computedGateTime).seconds());
+            if (deltaTime > 5)
+                error("Flight plan " + this._flightPlan.name() + " gate time different than expected (" +
+                      this._expectedGateTime + "), got (" + computedGateTime + ")");
+        }
+    }
+}
+
+function setupUserWaypoints()
+{
+    userWaypoints.clear();   
+    userWaypoints.update("Oilcamp", "Oil storage in the middle of no where", "36.68471", "-120.50277");
+    userWaypoints.update("I5.Westshields", "I5 & West Shields", "36.77774", "-120.72426");
+    userWaypoints.update("I5.165", "Intersection of I5 and CA165", "36.93022", "-120.84068");
+    userWaypoints.update("I5.VOLTA", "I5 & Volta Road", "37.01419", "-120.92878");
+    userWaypoints.update("PT.ALPHA", "Intersection of I5 and CA152", "37.05665", "-120.96990");
+    userWaypoints.update("Jellysferry", "Jelly's Ferry bridge across Sacramento River", "N40 19.037", "W122 11.359");
+    userWaypoints.update("Howie", "RDD Timing Point", "N40 21.893", "W122 13.042");
+    userWaypoints.update("Hale", "2014 Leg 1 Timing", "N39 33.621", "W119 14.438");
+    userWaypoints.update("Winnie", "2014 Leg 2 Timing", "N40 50.499", "W114 12.595");
+    userWaypoints.update("WindRiver", "2014 Leg 3 Timing", "N42 43.733", "W108 38.800");
+    userWaypoints.update("Buff", "2014 Leg 4 Timing", "N43 59.455", "W103 16.171");
+    userWaypoints.update("Omega", "2014 Leg 5 Timing", "N44 53.388", "W95 38.935");
+    userWaypoints.update("Paul", "2014 Leg 6 Timing", "N43 22.027", "W89 37.111");
+    userWaypoints.update("MicrowaveSt", "2014 Microwave Station", "N40 24.89", "W117 12.37");
+    userWaypoints.update("RanchTower", "2014 Ranch/Tower", "N41 6.16", "W115 5.43");
+    userWaypoints.update("FremontIsland", "2014 Fremont Island", "N41 10.49", "W112 20.64");
+    userWaypoints.update("Tremonton", "2014 Tremonton", "N41 42.86", "W112 11.05");
+    userWaypoints.update("RandomPoint", "2014 Random Point", "N42", "W111 03");
+    userWaypoints.update("Farson", "2014 Farson", "N42 6.40", "W109 26.95");
+    userWaypoints.update("Midwest", "2014 Midwest", "N43 24.49", "W109 16.68");
+    userWaypoints.update("Bill", "2014 Bill", "N43 13.96", "W105 15.60");
+    userWaypoints.update("MMNHS", "2014 MMNHS", "N43 52.67", "W101 57.65");
+    userWaypoints.update("Tracks", "2014 Tracks", "N44 21", "W100 22");
+    userWaypoints.update("Towers", "2014 Towers", "N43 34.25", "W92 25.64");
+    userWaypoints.update("IsletonBridge", "Isleton Bridge", "N38 10.32", "W121 35.62");
+    userWaypoints.update("Mystery15", "2015 Mystery", "N38 46.22", "W122 34.25");
+    userWaypoints.update("Paskenta", "Paskenta Town", "N39 53.13", "W122 32.36");
+    userWaypoints.update("Bonanza", "Bonanza Town", "N42 12.15", "W121 24.53");
+    userWaypoints.update("Silverlake", "Silverlake", "N43 07.41", "W121 03.74");
+    userWaypoints.update("Millican", "Bend Timing Start", "N43 52.75", "W120 55.13");
+    userWaypoints.update("Goering", "Bend Timing", "N44 05.751", "W120 56.834");
+    userWaypoints.update("Constantia2", "Our Constantia Wpt", "N39 56.068", "W120 0.831");
+    userWaypoints.update("Hallelujah2", "Reno Timing", "N39 46.509", "W120 2.336");
+    userWaypoints.update("Redding.Pond", "Pond 6nm North of KRDD", "N40 36", "W122 17");
+    userWaypoints.update("Thunderhill", "Thunder Hill Race Track", "N39 32.36", "W122 19.83");
+    userWaypoints.update("CascadeHighway", "Cascade Wonderland Highway", "N40 46.63", "W122 19.12");
+    userWaypoints.update("Eagleville", "Eagleville closed airport", "N41 18.73", "W120 3.00");
+    userWaypoints.update("DuckLakePass", "Saddle near Duck Lake", "N41 3.00", "W120 3.00");
+}
+
+function createTestRoutes()
+{
+    let flightPlans = [
+        { name: "Rally Practice 1", route: "C83|Start Taxi|6:00 Runup|0:30 Taxi|1:00 Takeoff Climb|5500|5:00 CA67 0CN1 28CA 126kts I5.165 PT.ALPHA KLSN|Timing Pattern|0:45 Taxi|2:00" },
+        { name: "Rally Practice 2", route: "C83|Start Taxi|6:00 Runup|0:30 Taxi|1:00 Takeoff Climb|5500|5:00 ECA 343@4 5CL3 67CA 314@12 126kts I5.165 126kts PT.ALPHA|Timing  126kts KLSN Pattern|0:45 Taxi|2:00" },
+        { name: "Rally Practice 3", route: "KTCY|Start Taxi|6:00 Runup|0:30 Taxi|1:00 Takeoff Climb|3500|5:00 O27 67CA OILCAMP I5.WESTSHIELDS I5.165 I5.VOLTA PT.ALPHA|Timing KLSN Pattern|0:45 Taxi|2:00" },
+        { name: "Rally Practice 4", route: "C83|Start Taxi|6:00 Runup|0:30 Taxi|1:00 Takeoff Climb|5500|5:00 62@3 9CL0 342@9 CL84 28CA 315@10 126kts I5.165 126kts PT.ALPHA|Timing  126kts KLSN Pattern|0:45 Taxi|2:00" },
+        { name: "Rally Practice 5", route: "C83|Start Taxi|6:00 Runup|0:30 Taxi|1:00 Takeoff Climb|5500|7:00 O27 9CL0 CL01 I5.165 PT.ALPHA KLSN Pattern|0:45 Taxi|2:00" },
+        { name: "2014 HWD Rally Leg 1", route: "KHWD|Start Taxi|6:00 Runup|0:30 Taxi|1:00 Takeoff Climb|5500|4:35 VPDUB Climb|8500|6:25 2CL9 Left|+1 09CL Left|+1 O02 Left|+1 77NV Left 126kts HALE|Timing KSPZ Pattern|0:45 Taxi|2:00"},
+        { name: "2014 HWD Rally Leg 2", route: "KSPZ|Start Taxi|4:00 Runup|0:30 Taxi|1:00 Takeoff Climb|7500|9:00 NV30 Left MicrowaveSt Left DOBYS Left RanchTower Left 126kts Winnie|Timing KENV Pattern|0:45 Taxi|2:00"},
+        { name: "2014 HWD Rally Leg 3", route: "KENV|Start Taxi|5:00 Runup|0:30 Taxi|1:00 Takeoff Climb|7500|8:30 FremontIsland Left|+1 Tremonton Left|+1 RandomPoint Left|+1 Farson Left 126kts WindRiver|Timing KLND Pattern|0:45 Taxi|2:00"},
+        { name: "2014 HWD Rally Leg 4", route: "KLND|Start Taxi|6:00 Runup|0:30 Taxi|1:00 Takeoff Climb|7500|10:00 Midwest Left Bill Right|+1 WY09 Left KCUT Left 126kts BUFF|Timing KRAP Pattern|0:45 Taxi|2:00"},
+        { name: "2014 HWD Rally Leg 5", route: "KRAP|Start Taxi|5:00 Runup|0:30 Taxi|3:00 Takeoff Climb|7500|9:00 MMNHS Left|+1 Tracks Left|+1 8D7 Left 5H3 Left 126kts Omega KMVE Pattern|0:45 Taxi|2:00"},
+        { name: "2014 HWD Rally Leg 6", route: "KMVE|Start Taxi|6:00 Runup|0:30 Taxi|2:00 Takeoff Climb|5500|6:00 1D6 Left 68Y Right|+1 Towers Left KCHU Left 126kts Paul|Timing KMSN Pattern|0:45 Taxi|2:00"},
+        { name: "2015 HWD Rally Leg 1", route: "KHWD|Start Taxi|6:00 Runup|0:30 Taxi|1:00 Takeoff Climb|5500|4:35 VPDUB Climb|5500|3:25 IsletonBridge Mystery15 Left|+1 71CL Left|+1 Paskenta Left|+1 O37 Left|+1 JELLYSFERRY HOWIE|Timing KRDD Pattern|0:45 Taxi|2:00"},
+        { name: "2015 HWD Rally Leg 2", route: "KRDD|Start Taxi|6:00 Runup|0:30 Taxi|2:00 Takeoff Climb|8500|1:20 REDDING.POND Climb|8500|7:40 A26 O81 Left 340@6 Bonanza Left|+1 Silverlake Left|+1 Millican 126kts Goering|Timing KBDN pattern|30 taxi|2:00"},
+        { name: "2016 HWD Rally Leg 1", route: "KHWD|Start Taxi|6:00 Runup|0:30 Taxi|1:00 Takeoff Climb|5500|4:35 VPDUB Climb|5500|3:25 65CN 3CN7 57CN Left|+1 2CL1 Left|+1 O37 Left|+1 JELLYSFERRY HOWIE|Timing KRDD Pattern|0:45 Taxi|2:00"},
+        { name: "2016 HWD Rally Leg 2", route: "KRDD|Start Taxi|6:00 Runup|0:30 Taxi|2:00 Takeoff Climb|8500|1:20 REDDING.POND Climb|8500|7:40 O89 KAAT Left 1Q2 KSVE Left H37 Left CONSTANTIA2 HALLELUJAH2|Timing KRTS pattern|30 taxi|2:00"},
+        { name: "2017 HWD Rally Leg 1", route: "KHWD|Start Taxi|6:00 Runup|0:30 Taxi|1:00 Takeoff Climb|4500|8:00 10@6 9CL9 63CL THUNDERHILL 60@10 90CL 0O4 350@10 126kts JELLYSFERRY 126kts HOWIE|Timing KRDD Pattern|0:45 Taxi|4:00" },
+        { name: "2017 HWD Rally Leg 2", route: "KRDD|Start Taxi|6:00 Runup|0:30 Taxi|2:00 Takeoff Climb|8500|6:40 CASCADEHIGHWAY Climb|8500|8:20 KLKV 210@2 EAGLEVILLE DUCKLAKEPASS 210@5 O39 209@8 AHC 148@6 126kts CONSTANTIA2 126kts Hallelujah2|Timing KRTS Pattern|0:30 Taxi|2:00" },
+        { name: "San Jose to San Diego", route: "KSJC LICKE SNS V25 REDIN KMYF" },
+        { name: "San Diego to San Jose", route: "KMYF JOPDO CARIF V23 LAX V299 VTU V25 PRB SARDO RANCK V485 LICKE KSJC" },
+        { name: "San Jose to Renton", route: "KSJC SUNOL RBL V23 SEA KRNT" },
+        { name: "Renton to Willows", route: "KRNT SEA V495 BTG V23 RBL KWLW" },
+        { name: "SJC to SEA #1", route: "ksjc sunol 135kts 300@12 rdd 0kts pdx ksea" },
+        { name: "SJC to SEA #2", route: "KSJC SJC V334 SAC V23 BTG V495 SEA KSEA" },
+        { name: "SJC to SEA #3", route: "KSJC SJC V334 SAC V23 FJS V495 SEA KSEA" },
+        { name: "Roseburg to San Jose", route: "KRBG RBG KOLER V495 FJS V23 RBL SUNOL KSJC" },
+        { name: "SAN to DEN", route: "KSAN HAILE V514 LYNSY V8 JNC V134 BINBE KDEN" },
+        { name: "Denver to Minneapolis", route: "KDEN DVV V8 AKO V80 FSD V148 RWF V412 FCM KMSP" },
+        { name: "Reno to Chicago", route: "KRNO FMG V6 LLC V32 CEVAR V200 STACO V32 FBR V6 MBW V100 RFD V171 SIMMN V172 DPA KORD" },
+        { name: "Denver to Oklahoma City", route: "KDEN AVNEW V366 HGO V263 LAA V304 LBL V507 MMB V17 IRW KOKC" },
+        { name: "Stockton to Hawthorne 1", route: "KSCK MOD V113 PXN V107 AVE V137 GMN V23 LAX KHHR" },
+        { name: "Stockton to Hawthorne 2", route: "ksck patyy v113 rom v485  exert v25 lax khhr" },
+        { name: "Long View to Corpus Christi", route: "KGGG PIPES V289 LFK V13 WORRY KCRP" },
+        { name: "Austin Exec to Beaumont 1", route: "KEDC HOOKK V306 TNV V574 IAH V222 SHINA KBPT" },
+        { name: "Austin Exec to Beaumont 2", route: "KEDC HOOKK V306 DAS KBPT" },
+        { name: "Austin Exec to Beaumont 3", route: "KEDC HOOKK V306 TNV DAS KBPT" },
+        { name: "Savannah to Daytona Beach", route: "KSAV KELER V437 COKES KDAB" },
+        { name: "Philly to Hartford 1", route: "KPNE ARD V276 DIXIE V16 JFK V229 SNIVL KHFD" },
+        { name: "Philly to Hartford 2", route: "KPNE ARD V276 MANTA V139 RICED MAD KHFD" },
+        { name: "Philly to Hartford 3", route: "KPNE DITCH V312 DRIFT V139 SARDI V308 ORW KHFD" },
+        { name: "Philly to Hartford 4", route: "KPNE ZIDET V479 ARD V433 LGA V99 YALER KHFD" },
+        { name: "West Georgie Regional to Frankfort, KY 1", route: "kctj noone nello v5 gqo kfft" },
+        { name: "West Georgie Regional to Frankfort, KY 2", route: "kctj felto v243 gqo v333 hyk v512 clegg kfft" },
+        { name: "West Georgie Regional to Frankfort, KY 3", route: "kctj rmg v333 hyk v512 clegg kfft" },
+        { name: "West Georgie Regional to Frankfort, KY 4", route: "kctj rmg v333 hch v51 lvt v493 hyk kfft" },
+        { name: "Raleigh / Durham to Baltimore Martin State 1", route: "KRDU aimhi  KMTN" },
+        { name: "Raleigh / Durham to Baltimore Martin State 2", route: "KRDU rdu v155 lvl ric ott KMTN" },
+        { name: "Raleigh / Durham to Baltimore Martin State 3", route: "KRDU rdu v155 mange v157 colin v33 ott v433 paleo KMTN" },
+        { name: "Raleigh / Durham to Baltimore Martin State 4", route: "KRDU rdu v155 LVL V157 RIC V16 PXT V93 GRACO KMTN" },
+        { name: "Roswell, NM to Longview, TX", route: "KROW Climb|9500|6:00 070@14 HOB V68 PIZON 050@16 V16 ABI V62 JEN V94 OTTIF KGGG" },
+        { name: "Lubbock to Longview 1", route: "KLBB JEN CQY KGGG" },
+        { name: "Lubbock to Longview 2", route: "KLBB ralls v102 gth v278 byp v114 awlar KGGG" },
+        { name: "Lubbock to Longview 3", route: "KLBB hydro v62 jen v94 ottif KGGG" },
+        { name: "Stockton, CA to North Las Vegas 1", route: "KSCK ECA V244 OAL V105 LUCKY KVGT" },
+        { name: "Stockton, CA to North Las Vegas 2", route: "KSCK ehf v197 pmd v12 basal v394 oasys KVGT" },
+        { name: "Bakersfield to Santa Rosa 1", route: "KBFL EHF V248 AVE OAK SAU KSTS" },
+        { name: "Bakersfield to Santa Rosa 2", route: "KBFL EHF V248 AVE PXN V301 SUNOL KSTS" },
+        { name: "Bakersfield to Santa Rosa 3", route: "KBFL SCRAP V248 AVE V107 OAK V195 CROIT V108 STS KSTS" },
+        { name: "Bakersfield to Santa Rosa 4", route: "KBFL EHF V23 SAC V494 SNUPY KSTS" },
+        { name: "Bakersfield to Santa Rosa 5", route: "KBFL EHF V248 AVE V137 SNS V230 SHOEY V27 PYE KSTS" },
+        { name: "Bakersfield to Santa Rosa 6", route: "KBFL EHF V23 CZQ MOD OAKEY KSTS" },
+        { name: "Bakersfield to Santa Rosa 7", route: "KBFL EHF V23 LIN CCR CROIT SGD KSTS" },
+        { name: "Bakersfield to Santa Rosa 8", route: "KBFL EHF V248 AVE V107 PXN SGD KSTS" },
+        { name: "Great Falls to Boeing King Field 1", route: "KGTF GTF V120 MLP V2 GEG V120 NORMY KBFI" },
+        { name: "Great Falls to Boeing King Field 2", route: "KGTF GTF V120 MLP J70 SEA KBFI" },
+        { name: "Great Falls to Boeing King Field 3", route: "KGTF GTF V187 ELN V2 SEA KBFI" },
+        { name: "Great Falls to Boeing King Field 4", route: "KGTF KEETA Q144 ZIRAN KBFI" },
+        { name: "Boise to Centenial 1", route: "KBOI BOI V4 LAR RAMMS NIWOT KAPA" },
+        { name: "Boise to Centenial 2", route: "KBOI ROARR PIH J20 OCS J154 AVVVS KAPA" },
+        { name: "Boise to Centenial 3", route: "KBOI CANEK V4 OCS V328 DOBEE V356 ELORE KAPA" },
+        { name: "Boise to Centenial 4", route: "KBOI BOI J54 PIH J20 OCS J52 FQF KAPA" },
+        { name: "St. Louis to Birmingham 1", route: "KSTL SPUDZ V125 DUEAS V540 CNG V67 SYI V321 BOAZE V115 COLIG KBHM" },
+        { name: "St. Louis to Birmingham 2", route: "KSTL ODUJY FAM CGI JKS MSL VUZ KBHM" },
+        { name: "Chattanoga to Augusta 1", route: "KCHA ODF AHN V417 MSTRS KAGS" },
+        { name: "Chattanoga to Augusta 2", route: "KCHA GQO NELLO CCATT T292 JACET KAGS" },
+        { name: "Chattanoga to Augusta 3", route: "KCHA GQO ATL ANNAN KAGS" },
+        { name: "Chattanoga to Augusta 4", route: "KCHA HOCHE V5 AHN V417 IRQ KAGS" },
+        { name: "Concord, NC to Richmond, VA 1", route: "KJQF SBV V20 RIC KRIC" },
+        { name: "Concord, NC to Richmond, VA 2", route: "KJQF GIZMO V143 GSO V266 SBV V20 RIC KRIC" },
+        { name: "Concord, NC to Richmond, VA 3", route: "KJQF GSO SBV V20 RIC KRIC" },
+        { name: "Concord, NC to Richmond, VA 4", route: "KJQF GIZMO V454 LVL V157 RIC KRIC" },
+        { name: "Buffalo, NY to Portland, ME 1", route: "KBUF BUF V2 UCA V496 NEETS V39 LIMER KPWM" },
+        { name: "Buffalo, NY to Portland, ME 2", route: "KBUF HANKK AUDIL PUPPY GFL KPWM" },
+        { name: "Buffalo, NY to Portland, ME 3", route: "KBUF BUF V14 GGT V428 UCA V496 ENE KPWM" },
+        { name: "Buffalo, NY to Portland, ME 4", route: "KBUF JOSSY Q935 PONCT ARIME CDOGG ENE KPWM" },
+        { name: "Moline, IL to Battle Creek, MI 1", route: "KMLI GENSO V8 NOMES V156 AZO KBTL" },
+        { name: "Moline, IL to Battle Creek, MI 2", route: "KMLI OBK J547 PMM KBTL" },
+        { name: "Moline, IL to Battle Creek, MI 3", route: "KMLI PLL OBK ELX KBTL" },
+        { name: "Moline, IL to Battle Creek, MI 4", route: "KMLI PLL RFD V100 ELX AZO KBTL" },
+        { name: "Green Bay, WI to Indianapolis, IN 1", route: "KGRB OKK V305 WELDO KIND" },
+        { name: "Green Bay, WI to Indianapolis, IN 2", route: "KGRB GRB J101 BAE J89 OBK EON V24 VHP KIND" },
+        { name: "Green Bay, WI to Indianapolis, IN 3", route: "KGRB WAFLE V7 BVT V399 ADVAY KIND" },
+        { name: "Green Bay, WI to Indianapolis, IN 4", route: "KGRB WAFLE V7 BVT VHP KIND" },
+        { name: "Anoka County, MN to Springfield, IL 1", route: "KANE KANAC V97 ODI V129 GROWL KSPI" },
+        { name: "Anoka County, MN to Springfield, IL 2", route: "KANE GEP PRIOR FGT V411 RST V67 ULAXY KSPI" },
+        { name: "Anoka County, MN to Springfield, IL 3", route: "