refactoring: better dependency control

This commit is contained in:
rusefi 2020-06-25 20:03:48 -04:00
parent 2a92b21c49
commit 02c1485ffb
23 changed files with 75 additions and 55 deletions

View File

@ -35,7 +35,7 @@ public class AutoTest {
static int currentEngineType;
private static String criticalError;
static void mainTestBody() throws Exception {
static void mainTestBody(LinkManager linkManager) throws Exception {
MessagesCentral.getInstance().addListener(new MessagesCentral.MessageListener() {
@Override
public void onMessage(Class clazz, String message) {
@ -44,7 +44,8 @@ public class AutoTest {
}
});
BinaryProtocol bp = LinkManager.getCurrentStreamState();
BinaryProtocol bp = linkManager.getCurrentStreamState();
// let's make sure 'burn' command works since sometimes it does not
bp.burn(Logger.CONSOLE);
@ -538,8 +539,9 @@ public class AutoTest {
boolean failed = false;
try {
IoUtil.connectToSimulator(startSimulator);
mainTestBody();
LinkManager linkManager = new LinkManager();
IoUtil.connectToSimulator(linkManager, startSimulator);
mainTestBody(linkManager);
} catch (Throwable e) {
e.printStackTrace();
failed = true;

View File

@ -108,7 +108,7 @@ public class IoUtil {
FileLog.MAIN.logLine("Got first signal in " + (System.currentTimeMillis() - waitStart));
}
static void connectToSimulator(boolean startProcess) throws InterruptedException {
static void connectToSimulator(LinkManager linkManager, boolean startProcess) throws InterruptedException {
if (startProcess) {
if (!TcpConnector.getAvailablePorts().isEmpty())
throw new IllegalStateException("Port already binded on startup?");
@ -136,8 +136,8 @@ public class IoUtil {
/**
* TCP connector is blocking
*/
LinkManager.startAndConnect("" + TcpConnector.DEFAULT_PORT, ConnectionStateListener.VOID);
LinkManager.engineState.registerStringValueAction(Fields.PROTOCOL_VERSION_TAG, (EngineState.ValueCallback<String>) EngineState.ValueCallback.VOID);
linkManager.startAndConnect("" + TcpConnector.DEFAULT_PORT, ConnectionStateListener.VOID);
linkManager.engineState.registerStringValueAction(Fields.PROTOCOL_VERSION_TAG, (EngineState.ValueCallback<String>) EngineState.ValueCallback.VOID);
waitForFirstResponse();
}

View File

@ -84,6 +84,6 @@ public class RealHwTest {
private static void runRealHardwareTest(String port) throws Exception {
IoUtil.realHardwareConnect(port);
mainTestBody();
mainTestBody(new LinkManager());
}
}

View File

@ -57,7 +57,12 @@ public class LinkManager {
return result;
}
public static BinaryProtocol getCurrentStreamState() {
public static BinaryProtocol getCurrentStreamStateStatic() {
Objects.requireNonNull(connector, "connector");
return connector.getBinaryProtocol();
}
public BinaryProtocol getCurrentStreamState() {
Objects.requireNonNull(connector, "connector");
return connector.getBinaryProtocol();
}

View File

@ -27,7 +27,7 @@ public class BinaryProtocolServer implements BinaryProtocolCommands {
private static final int PROXY_PORT = 2390;
private static final String TS_OK = "\0";
public static void start() {
public static void start(LinkManager linkManager) {
FileLog.MAIN.logLine("BinaryProtocolServer on " + PROXY_PORT);
Runnable runnable = new Runnable() {
@SuppressWarnings("InfiniteLoopStatement")
@ -50,7 +50,7 @@ public class BinaryProtocolServer implements BinaryProtocolCommands {
@Override
public void run() {
try {
runProxy(clientSocket);
runProxy(linkManager, clientSocket);
} catch (IOException e) {
FileLog.MAIN.logLine("proxy connection: " + e);
}
@ -66,7 +66,7 @@ public class BinaryProtocolServer implements BinaryProtocolCommands {
}
@SuppressWarnings("InfiniteLoopStatement")
private static void runProxy(Socket clientSocket) throws IOException {
private static void runProxy(LinkManager linkManager, Socket clientSocket) throws IOException {
DataInputStream in = new DataInputStream(clientSocket.getInputStream());
while (true) {
@ -110,13 +110,13 @@ public class BinaryProtocolServer implements BinaryProtocolCommands {
} else if (command == Fields.TS_GET_FIRMWARE_VERSION) {
stream.sendPacket((TS_OK + "rusEFI proxy").getBytes(), FileLog.LOGGER);
} else if (command == COMMAND_CRC_CHECK_COMMAND) {
handleCrc(stream);
handleCrc(linkManager, stream);
} else if (command == COMMAND_PAGE) {
stream.sendPacket(TS_OK.getBytes(), FileLog.LOGGER);
} else if (command == COMMAND_READ) {
handleRead(dis, stream);
handleRead(linkManager, dis, stream);
} else if (command == Fields.TS_CHUNK_WRITE_COMMAND) {
handleWrite(packet, dis, stream);
handleWrite(linkManager, packet, dis, stream);
} else if (command == Fields.TS_BURN_COMMAND) {
stream.sendPacket(new byte[]{TS_RESPONSE_BURN_OK}, FileLog.LOGGER);
} else if (command == Fields.TS_OUTPUT_COMMAND) {
@ -126,7 +126,7 @@ public class BinaryProtocolServer implements BinaryProtocolCommands {
byte[] response = new byte[1 + count];
response[0] = (byte) TS_OK.charAt(0);
BinaryProtocol bp = LinkManager.getCurrentStreamState();
BinaryProtocol bp = linkManager.getCurrentStreamState();
byte[] currentOutputs = bp.currentOutputs;
if (currentOutputs != null)
System.arraycopy(currentOutputs, 1 + offset , response, 1, count);
@ -138,17 +138,17 @@ public class BinaryProtocolServer implements BinaryProtocolCommands {
}
}
private static void handleWrite(byte[] packet, DataInputStream dis, TcpIoStream stream) throws IOException {
private static void handleWrite(LinkManager linkManager, byte[] packet, DataInputStream dis, TcpIoStream stream) throws IOException {
dis.readShort(); // page
int offset = swap16(dis.readShort());
int count = swap16(dis.readShort());
FileLog.MAIN.logLine("TS_CHUNK_WRITE_COMMAND: offset=" + offset + " count=" + count);
BinaryProtocol bp = LinkManager.getCurrentStreamState();
BinaryProtocol bp = linkManager.getCurrentStreamState();
bp.setRange(packet, 7, offset, count);
stream.sendPacket(TS_OK.getBytes(), FileLog.LOGGER);
}
private static void handleRead(DataInputStream dis, TcpIoStream stream) throws IOException {
private static void handleRead(LinkManager linkManager, DataInputStream dis, TcpIoStream stream) throws IOException {
short page = dis.readShort();
int offset = swap16(dis.readShort());
int count = swap16(dis.readShort());
@ -156,7 +156,7 @@ public class BinaryProtocolServer implements BinaryProtocolCommands {
FileLog.MAIN.logLine("Error: negative read request " + offset + "/" + count);
} else {
System.out.println("read " + page + "/" + offset + "/" + count);
BinaryProtocol bp = LinkManager.getCurrentStreamState();
BinaryProtocol bp = linkManager.getCurrentStreamState();
byte[] response = new byte[1 + count];
response[0] = (byte) TS_OK.charAt(0);
System.arraycopy(bp.getControllerConfiguration().getContent(), offset, response, 1, count);
@ -164,9 +164,9 @@ public class BinaryProtocolServer implements BinaryProtocolCommands {
}
}
private static void handleCrc(TcpIoStream stream) throws IOException {
private static void handleCrc(LinkManager linkManager, TcpIoStream stream) throws IOException {
System.out.println("CRC check");
BinaryProtocol bp = LinkManager.getCurrentStreamState();
BinaryProtocol bp = linkManager.getCurrentStreamState();
byte[] content = bp.getControllerConfiguration().getContent();
int result = IoHelper.getCrc32(content);
ByteArrayOutputStream response = new ByteArrayOutputStream();

View File

@ -41,6 +41,6 @@ class BinaryProtocolServerSandbox {
});
bp.setController(new ConfigurationImage(new byte[Fields.TOTAL_CONFIG_SIZE]));
bp.currentOutputs = new byte[1 + Fields.TS_OUTPUT_SIZE];
BinaryProtocolServer.start();
BinaryProtocolServer.start(new LinkManager());
}
}

View File

@ -7,6 +7,7 @@ import com.rusefi.tracing.Entry;
import com.rusefi.tracing.JsonOutput;
import com.rusefi.ui.MessagesView;
import com.rusefi.ui.RpmModel;
import com.rusefi.ui.UIContext;
import com.rusefi.ui.util.UiUtils;
import org.jetbrains.annotations.NotNull;
@ -24,8 +25,10 @@ import static com.rusefi.binaryprotocol.IoHelper.checkResponseCode;
public class BenchTestPane {
private final JPanel content = new JPanel(new GridLayout(2, 5));
private final UIContext uiContext;
public BenchTestPane() {
public BenchTestPane(UIContext uiContext) {
this.uiContext = uiContext;
content.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
content.add(grabPerformanceTrace());
@ -57,7 +60,7 @@ public class BenchTestPane {
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
BinaryProtocol bp = LinkManager.getCurrentStreamState();
BinaryProtocol bp = uiContext.getLinkManager().getCurrentStreamState();
bp.executeCommand(new byte[]{Fields.TS_PERF_TRACE_BEGIN}, "begin trace");
try {

View File

@ -48,7 +48,7 @@ public class ConsoleUI {
private final MainFrame mainFrame;
private final UIContext uiContext = new UIContext();
public final UIContext uiContext = new UIContext();
/**
* We can listen to tab activation event if we so desire
@ -73,7 +73,7 @@ public class ConsoleUI {
LinkManager.start(port);
engineSnifferPanel = new EngineSnifferPanel(getConfig().getRoot().getChild("digital_sniffer"));
engineSnifferPanel = new EngineSnifferPanel(uiContext, getConfig().getRoot().getChild("digital_sniffer"));
if (!LinkManager.isLogViewerMode(port))
engineSnifferPanel.setOutpinListener(LinkManager.engineState);
@ -95,10 +95,10 @@ public class ConsoleUI {
tabbedPaneAdd("Messages", messagesPane.getContent(), messagesPane.getTabSelectedListener());
}
if (!LinkManager.isLogViewer()) {
tabbedPane.addTab("Bench Test", new BenchTestPane().getContent());
tabbedPane.addTab("Bench Test", new BenchTestPane(uiContext).getContent());
if (tabbedPane.paneSettings.showEtbPane)
tabbedPane.addTab("ETB", new ETBPane().getContent());
tabbedPane.addTab("Presets", new PresetsPane().getContent());
tabbedPane.addTab("ETB", new ETBPane(uiContext).getContent());
tabbedPane.addTab("Presets", new PresetsPane(uiContext).getContent());
}
tabbedPaneAdd("Engine Sniffer", engineSnifferPanel.getPanel(), engineSnifferPanel.getTabSelectedListener());

View File

@ -2,6 +2,7 @@ package com.rusefi;
import com.rusefi.core.Sensor;
import com.rusefi.ui.GaugesGridElement;
import com.rusefi.ui.UIContext;
import com.rusefi.ui.etb.CalibrationPanel;
import com.rusefi.ui.etb.EtbCommandsPanel;
@ -18,15 +19,15 @@ import static com.rusefi.config.generated.Fields.CMD_ETB_DUTY;
public class ETBPane {
private final JPanel content = new JPanel(new BorderLayout());
public ETBPane() {
public ETBPane(UIContext uiContext) {
JPanel centerPanel = new JPanel(new GridLayout(3, 1));
centerPanel.add(GaugesGridElement.create(Sensor.PPS));
centerPanel.add(GaugesGridElement.create(Sensor.ETB_CONTROL_QUALITY));
centerPanel.add(GaugesGridElement.create(Sensor.TPS));
content.add(new EtbCommandsPanel().getContent(), BorderLayout.WEST);
content.add(new EtbCommandsPanel(uiContext).getContent(), BorderLayout.WEST);
content.add(centerPanel, BorderLayout.CENTER);
content.add(new CalibrationPanel().getContent(), BorderLayout.EAST);
content.add(new CalibrationPanel(uiContext).getContent(), BorderLayout.EAST);
}
public JPanel getContent() {

View File

@ -2,6 +2,7 @@ package com.rusefi;
import com.rusefi.config.generated.Fields;
import com.rusefi.io.CommandQueue;
import com.rusefi.ui.UIContext;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
@ -19,7 +20,7 @@ public class PresetsPane {
private JPanel content = new JPanel(new GridLayout(2, 4));
public PresetsPane() {
public PresetsPane(UIContext uiContext) {
content.add(new SetEngineTypeCommandControl("Frankenso Miata NA6 Stage 0", "/engines/miata_na.png", Fields.ET_FRANKENSO_MIATA_NA6_VAF).getContent());
content.add(new SetEngineTypeCommandControl("Frankenso Miata NA6 Stage 1", "/engines/miata_na.png", Fields.ET_FRANKENSO_MIATA_NA6).getContent());
content.add(new SetEngineTypeCommandControl("Frankenso Miata NB2", "/engines/miata_nb.png", Fields.ET_FRANKENSO_MIATA_NB2).getContent());

View File

@ -14,8 +14,9 @@ import java.awt.*;
import static com.romraider.editor.ecu.ECUEditorManager.getECUEditor;
public class RomEditorPane extends JPanel {
public class RomEditorPane extends JPanel {
/*
private final UIContext uiContext;
public RomEditorPane(UIContext uiContext) {
@ -36,7 +37,7 @@ public class RomEditorPane extends JPanel {
add(editor.getContent());
BinaryProtocol instance = LinkManager.getCurrentStreamState();
BinaryProtocol instance = LinkManager.getCurrentStreamStateStatic();
if (instance == null)
throw new NullPointerException("instance");
ConfigurationImage image = instance.getControllerConfiguration();
@ -47,4 +48,6 @@ public class RomEditorPane extends JPanel {
}
UiUtils.trueLayout(this);
}
*/
}

View File

@ -45,7 +45,7 @@ public class PlainTextSensorLog implements SensorLog {
logFile.write("Captured " + FileLog.getDate() + "\r\n");
int debugMode = -1;
BinaryProtocol bp = LinkManager.getCurrentStreamState();
BinaryProtocol bp = LinkManager.getCurrentStreamStateStatic();
if (bp != null) {
ConfigurationImage ci = bp.getControllerConfiguration();
if (ci != null) {

View File

@ -195,10 +195,11 @@ public class ConsoleTools {
System.err.println("rusEFI not detected");
return;
}
LinkManager.startAndConnect(autoDetectedPort, new ConnectionStateListener() {
LinkManager linkManager = new LinkManager();
linkManager.startAndConnect(autoDetectedPort, new ConnectionStateListener() {
@Override
public void onConnectionEstablished() {
BinaryProtocolServer.start();
BinaryProtocolServer.start(linkManager);
}
@Override

View File

@ -17,7 +17,6 @@ import com.rusefi.config.generated.Fields;
import com.rusefi.core.ISensorCentral;
import com.rusefi.core.Sensor;
import com.rusefi.core.SensorCentral;
import com.rusefi.io.LinkManager;
import com.rusefi.ui.storage.Node;
import javax.swing.*;

View File

@ -28,7 +28,7 @@ public abstract class BaseConfigField {
}
private void processInitialValue(Field field) {
BinaryProtocol bp = LinkManager.getCurrentStreamState();
BinaryProtocol bp = LinkManager.getCurrentStreamStateStatic();
if (bp == null)
return;
ConfigurationImage ci = bp.getControllerConfiguration();

View File

@ -5,6 +5,7 @@ import com.rusefi.config.Field;
import com.rusefi.config.FieldCommandResponse;
import com.rusefi.config.generated.Fields;
import com.rusefi.core.MessagesCentral;
import com.rusefi.ui.UIContext;
import javax.swing.*;
import java.awt.event.ActionEvent;
@ -14,7 +15,7 @@ public class BitConfigField extends BaseConfigField {
private final JCheckBox view = new JCheckBox();
private boolean ec;
public BitConfigField(final Field field, String caption) {
public BitConfigField(UIContext uiContext, final Field field, String caption) {
super(field);
createUi(caption, view);
requestInitialValue(field); // this is not in base constructor so that view is created by the time we invoke it

View File

@ -79,7 +79,7 @@ public class MainFrame {
tabbedPane.settingsTab.showContent();
tabbedPane.logsManager.showContent();
tabbedPane.fuelTunePane.showContent();
BinaryProtocolServer.start();
BinaryProtocolServer.start(consoleUI.uiContext.getLinkManager());
}
});
@ -112,7 +112,7 @@ public class MainFrame {
root.setProperty(ConsoleUI.TAB_INDEX, tabbedPane.tabbedPane.getSelectedIndex());
GaugesPanel.DetachedRepository.INSTANCE.saveConfig();
getConfig().save();
BinaryProtocol bp = LinkManager.getCurrentStreamState();
BinaryProtocol bp = LinkManager.getCurrentStreamStateStatic();
if (bp != null && !bp.isClosed)
bp.close(); // it could be that serial driver wants to be closed explicitly
System.exit(0);

View File

@ -7,6 +7,7 @@ import com.rusefi.config.FieldType;
import com.rusefi.config.FieldsMap;
import com.rusefi.config.generated.Fields;
import com.rusefi.ui.RecentCommands;
import com.rusefi.ui.UIContext;
import com.rusefi.ui.config.*;
import com.rusefi.ui.util.UiUtils;
@ -29,8 +30,10 @@ public class SettingsTab {
private final JPanel panel = new JPanel(new GridLayout(1, 3));
private final JButton dialog = new JButton();
private final JPanel dialogBody = new JPanel();
private final UIContext uiContext;
public SettingsTab() {
public SettingsTab(UIContext uiContext) {
this.uiContext = uiContext;
UiUtils.showLoadingMessage(content);
}
@ -146,7 +149,7 @@ public class SettingsTab {
JComponent control;
if (field.getType() == FieldType.BIT) {
control = new BitConfigField(field, f.getUiName()).getContent();
control = new BitConfigField(uiContext, field, f.getUiName()).getContent();
} else if (field.getOptions() != null) {
control = new EnumConfigField(field, f.getUiName()).getContent();
} else {

View File

@ -62,7 +62,7 @@ public class TabbedPanel {
});
fuelTunePane = new FuelTunePane(uiContext, getConfig().getRoot().getChild("fueltune"));
// romEditorPane = new RomEditorPane(uiContext);
settingsTab = new SettingsTab();
settingsTab = new SettingsTab(uiContext);
}
public void addTab(String title, Component component) {

View File

@ -73,7 +73,7 @@ public class EngineSnifferPanel {
private boolean isPaused;
public EngineSnifferPanel(Node config) {
public EngineSnifferPanel(UIContext uiContext, Node config) {
statusPanel.setTimeAxisTranslator(crank.createTranslator());
final JButton pauseButton = UiUtils.createPauseButton();
@ -132,8 +132,8 @@ public class EngineSnifferPanel {
if (!LinkManager.isLogViewer()) {
JPanel lowerButtons = new JPanel(new FlowLayout(FlowLayout.RIGHT, 5, 0));
lowerButtons.add(new ConfigField(Fields.GLOBALTRIGGERANGLEOFFSET, "Trigger Offset").getContent());
lowerButtons.add(new BitConfigField(Fields.VERBOSETRIGGERSYNCHDETAILS, "Verbose trigger Sync").getContent());
lowerButtons.add(new BitConfigField(Fields.ISENGINECHARTENABLED, "Collect Engine Data").getContent());
lowerButtons.add(new BitConfigField(uiContext, Fields.VERBOSETRIGGERSYNCHDETAILS, "Verbose trigger Sync").getContent());
lowerButtons.add(new BitConfigField(uiContext, Fields.ISENGINECHARTENABLED, "Collect Engine Data").getContent());
lowerButtons.add(new ConfigField(Fields.SENSORCHARTFREQUENCY, "Frequency").getContent());
lowerButtons.add(new ConfigField(Fields.ENGINECHARTSIZE, "Engine Sniffer size").getContent());
lowerButtons.add(new ConfigField(Fields.ENGINESNIFFERRPMTHRESHOLD, "RPM threashold").getContent());

View File

@ -2,6 +2,7 @@ package com.rusefi.ui.etb;
import com.rusefi.config.generated.Fields;
import com.rusefi.io.CommandQueue;
import com.rusefi.ui.UIContext;
import org.jetbrains.annotations.NotNull;
import org.putgemin.VerticalFlowLayout;
@ -14,7 +15,7 @@ import java.awt.event.ActionEvent;
public class CalibrationPanel {
private final JPanel content = new JPanel(new VerticalFlowLayout());
public CalibrationPanel() {
public CalibrationPanel(UIContext uiContext) {
content.setBorder(BorderFactory.createTitledBorder("Calibration"));
content.add(createCommandButton("Grab TPS#1 fully closed", "calibrate_tps_1_closed"));
content.add(createCommandButton("Grab TPS#1 Wide Open", "calibrate_tps_1_wot"));

View File

@ -3,6 +3,7 @@ package com.rusefi.ui.etb;
import com.rusefi.config.generated.Fields;
import com.rusefi.core.Sensor;
import com.rusefi.ldmp.generated.ElectronicThrottleMeta;
import com.rusefi.ui.UIContext;
import com.rusefi.ui.config.BitConfigField;
import com.rusefi.ui.config.ConfigField;
import com.rusefi.ui.config.EnumConfigField;
@ -24,7 +25,7 @@ import static com.rusefi.config.generated.Fields.CMD_ETB_DUTY;
public class EtbCommandsPanel {
private final JPanel content = new JPanel(new VerticalFlowLayout());
public EtbCommandsPanel() {
public EtbCommandsPanel(UIContext uiContext) {
content.add(new DirectDrivePanel().getContent());
JPanel testParameters = new JPanel(new VerticalFlowLayout());
@ -41,7 +42,7 @@ public class EtbCommandsPanel {
testParameters.add(new JLabel("For example:"));
testParameters.add(new JLabel("set etb_p 1.1"));
testParameters.add(new BitConfigField(Fields.PAUSEETBCONTROL, "Pause").getContent());
testParameters.add(new BitConfigField(uiContext, Fields.PAUSEETBCONTROL, "Pause").getContent());
testParameters.add(new ConfigField(Fields.ETB_PFACTOR, "pFactor").getContent());
testParameters.add(new ConfigField(Fields.ETB_IFACTOR, "iFactor").getContent());
testParameters.add(new ConfigField(Fields.ETB_DFACTOR, "dFactor").getContent());

View File

@ -1,7 +1,6 @@
package com.rusefi.ui.test;
import com.rusefi.config.generated.Fields;
import com.rusefi.ui.engine.NameUtil;
import com.rusefi.ui.util.FrameHelper;
import com.rusefi.ui.engine.EngineSnifferPanel;
import com.rusefi.ui.storage.PersistentConfiguration;
@ -17,7 +16,7 @@ import java.lang.reflect.InvocationTargetException;
public class WavePanelSandbox {
public WavePanelSandbox() {
EngineSnifferPanel wp = new EngineSnifferPanel(PersistentConfiguration.getConfig().getRoot());
EngineSnifferPanel wp = new EngineSnifferPanel(null, PersistentConfiguration.getConfig().getRoot());
String report = "t1!u_9504!31000!t2!d_9505!31096!t2!u_9506!31532!t2!d_9507!31951!t2!u_9508!32349!t2!d_9509!32809!t2!u_9510!33185!t2!d_9511!33683!t2!u_9512!34087!t1!d_9513!34091!t2!d_9514!36081!t2!u_9515!36401!t2!d_9516!36775!t2!u_9517!37086!t2!d_9518!37447!t2!u_9519!37749!t2!d_9520!38114!t2!u_9521!38419!t2!d_9522!38787!t2!u_9523!39085!t2!d_9524!39476!t2!u_9525!39836!t2!d_9526!40191!t2!u_9527!40517!t2!d_9528!40941!t2!u_9529!41289!t2!d_9530!41747!t2!u_9531!42152!t2!d_9532!42599!t2!u_9533!42956!t2!d_9534!43386!t2!u_9535!43750!t2!d_9536!44203!t2!u_9537!44572!t1!u_9538!44764!t2!d_9539!45040!t2!u_9540!45404!t2!d_9541!45875!t2!u_9542!46253!t2!d_9543!46746!t2!u_9544!47127!t2!d_9545!47602!t2!u_9546!47986!t1!d_9547!48321!t2!d_9548!48388!t2!u_9549!50288!t2!d_9550!50739!t1!u_9551!50785!t2!u_9552!51035!t2!d_9553!51418!t2!u_9554!51759!t2!d_9555!52090!t2!u_9556!52400!t2!d_9557!52769!t2!u_9558!53090!t2!d_9559!53464!t1!d_9560!53565!t2!u_9561!53773!t2!d_9562!54187!t2!u_9563!54529!t2!d_9564!54946!t2!u_9565!55284!t2!d_9566!55755!t1!u_9567!56041!t2!u_9568!56158!t2!d_9569!56599!t2!u_9570!56965!t2!d_9571!57377!t2!u_9572!57753!t2!d_9573!58201!t2!u_9574!58589!t2!d_9575!59025!t1!d_9576!59229!t2!u_9577!59388!t2!d_9578!59866!t2!u_9579!60244!t2!d_9580!60723!t2!u_9581!61085!t2!d_9582!61585!t2!u_9583!61980!t1!u_9584!62170!t2!d_9585!63992!t2!u_9586!64329!t2!d_9587!64694!t2!u_9588!64993!t2!d_9589!65376!t2!u_9590!65707!t2!d_9591!66055!t2!u_9592!66378!t2!d_9593!66745!t2!u_9594!67049!t2!d_9595!67452!t2!u_9596!67799!t2!d_9597!68190!t2!u_9598!68515!t2!d_9599!68967!t2!u_9600!69412!t2!d_9601!69803!t2!u_9602!70196!t2!d_9603!70629!t2!u_9604!70963!t2!d_9605!71415!t2!u_9606!71862!t2!d_9607!72252!t2!u_9608!72636!t2!d_9609!73068!t2!u_9610!73423!t1!d_9611!73453!t2!d_9612!73923!t2!u_9613!74303!t2!d_9614!74780!t2!u_9615!75160!t2!d_9616!75646!t2!u_9617!76090!t2!d_9618!76424!t1!u_9619!76624!t2!u_9620!78352!t2!d_9621!78744!t2!u_9622!79047!t1!d_9623!79265!t2!d_9624!79422!t2!u_9625!79752!t2!d_9626!80096!t2!u_9627!80393!t2!d_9628!80781!t2!u_9629!81089!t2!d_9630!81483!t1!u_9631!81634!t2!u_9632!81861!t2!d_9633!82216!t2!u_9634!82544!t2!d_9635!82988!t2!u_9636!83335!t2!d_9637!83814!t2!u_9638!84194!t1!d_9639!84534!t2!d_9640!84646!t2!u_9641!84990!t2!d_9642!85429!t2!u_9643!85801!t2!d_9644!86260!t2!u_9645!86621!t1!u_9646!87022!t2!d_9647!87080!t2!u_9648!87435!t2!d_9649!87935!t2!u_9650!88312!t2!d_9651!88789!t2!u_9652!89183!t2!d_9653!89663!t2!u_9654!90043!t1!d_9655!90125!";