jmri.implementation
Class AbstractTurnout

Show UML class diagram
java.lang.Object
  extended by jmri.implementation.AbstractNamedBean
      extended by jmri.implementation.AbstractTurnout
All Implemented Interfaces:
PropertyChangeListener, Serializable, EventListener, NamedBean, Turnout
Direct Known Subclasses:
AcelaTurnout, CbusTurnout, EasyDccTurnout, EcosTurnout, JMRIClientTurnout, LnTurnout, MarklinTurnout, MrcTurnout, Mx1Turnout, NceTurnout, OlcbTurnout, SerialTurnout, SerialTurnout, SerialTurnout, SerialTurnout, SerialTurnout, SerialTurnout, SerialTurnout, SprogCSTurnout, SprogTurnout, SRCPTurnout, TamsTurnout, XBeeTurnout, XNetTurnout, XpaTurnout

public abstract class AbstractTurnout
extends AbstractNamedBean
implements Turnout, Serializable, PropertyChangeListener

Abstract base for the Turnout interface.

Implements basic feedback modes:

If you want to implement some other feedback, override and modify setCommandedState() here.

Implements the parameter binding support.

Note that we consider it an error for there to be more than one object that corresponds to a particular physical turnout on the layout.

Turnout system names are always upper case.

See Also:
Serialized Form

Field Summary
protected  int _activeFeedbackType
           
protected  boolean _cabLockout
           
protected  String _decoderName
           
(package private)  String _divergeSpeed
           
protected  boolean _enableCabLockout
           
protected  boolean _enablePushButtonLockout
           
protected  boolean _inverted
           
protected  boolean _pushButtonLockout
           
protected  boolean _reportLocked
           
(package private)  String _straightSpeed
           
protected  String[] _validDecoderNames
          Valid stationary decoder names
protected  int[] _validFeedbackModes
           
protected  String[] _validFeedbackNames
           
protected  int _validFeedbackTypes
           
protected  boolean binaryOutput
           
protected  boolean inhibitOperation
           
(package private) static org.slf4j.Logger log
           
protected  TurnoutOperator myOperator
           
protected  TurnoutOperation myTurnoutOperation
           
 
Fields inherited from class jmri.implementation.AbstractNamedBean
listenerRefs, mSystemName, mUserName, parameters, pcs, register
 
Fields inherited from interface jmri.Turnout
CABLOCKOUT, CLOSED, DIRECT, EXACT, INDIRECT, LOCKED, MONITORING, ONESENSOR, PUSHBUTTONLOCKOUT, SIGNAL, THROWN, TWOSENSOR, UNLOCKED
 
Fields inherited from interface jmri.NamedBean
INCONSISTENT, UNKNOWN
 
Constructor Summary
protected AbstractTurnout(String systemName)
           
protected AbstractTurnout(String systemName, String userName)
           
 
Method Summary
 boolean canInvert()
          Determine if the turnouts can be inverted.
 boolean canLock(int turnoutLockout)
          Determine if turnout can be locked.
 void dispose()
          Deactivate this object, so that it releases as many resources as possible and no longer effects others.
 void enableLockOperation(int turnoutLockout, boolean enabled)
          Enable turnout lock operators.
protected  void forwardCommandChangeToLayout()
           
protected abstract  void forwardCommandChangeToLayout(int s)
          Handle a request to change state, typically by sending a message to the layout in some child class.
 String getBeanType()
          For instances in the code where we are dealing with just a bean and a message needs to be passed to the user or in a log.
 int getCommandedState()
          Query the commanded state.
 int getControlType()
          Get control type.
 TurnoutOperator getCurrentOperator()
           
 String getDecoderName()
          Get a human readable representation of the decoder type for this turnout.
 float getDivergingLimit()
           
 String getDivergingSpeed()
           
 int getFeedbackMode()
          Get the feedback mode in machine readable form.
protected  int getFeedbackModeForOperation()
          Allow an actual turnout class to transform private feedback types into ones that the generic turnout operations know about
 String getFeedbackModeName()
          Get the feedback mode in human readable form.
 NamedBeanHandle<Sensor> getFirstNamedSensor()
          Get the first sensor, if defined.
 Sensor getFirstSensor()
          Get the first sensor, if defined.
 boolean getInhibitOperation()
          Get the indicator for whether automatic operation (retry) has been inhibited for this turnout
 boolean getInverted()
          Get the turnout inverted state.
 int getKnownState()
          Query the known state.
 boolean getLocked(int turnoutLockout)
          Determine if turnout is locked.
 int getNumberOutputBits()
          Get number of output bits.
 boolean getReportLocked()
          When true, report to console anytime a cab attempts to change the state of a turnout on the layout.
 NamedBeanHandle<Sensor> getSecondNamedSensor()
          Get the first sensor, if defined.
 Sensor getSecondSensor()
          Get the Second sensor, if defined.
 int getState()
          Implement a shorter name for getKnownState.
 float getStraightLimit()
           
 String getStraightSpeed()
           
 TurnoutOperation getTurnoutOperation()
           
protected  TurnoutOperator getTurnoutOperator()
          find the TurnoutOperation class for this turnout, and get an instance of the corresponding operator Override this function if you want another way to choose the operation
 String[] getValidDecoderNames()
          Get a human readable representation of the decoder types.
 String[] getValidFeedbackNames()
          Get a human readable representation of the feedback type.
 int getValidFeedbackTypes()
          Get a representation of the feedback type.
 boolean isConsistentState()
          Show whether state is one you can safely run trains over
protected  void newCommandedState(int s)
          Sets a new Commanded state, if need be notifying the listeners, but does NOT send the command downstream.
protected  void newKnownState(int s)
          Add a protected newKnownState() for use by implementations.
protected  void operationPropertyChange(PropertyChangeEvent evt)
           
 void propertyChange(PropertyChangeEvent evt)
          React to sensor changes by changing the KnownState if using an appropriate sensor mode
 void provideFirstFeedbackNamedSensor(NamedBeanHandle<Sensor> s)
           
 void provideFirstFeedbackSensor(String pName)
          Provide Sensor objects needed for some feedback types.
 void provideSecondFeedbackNamedSensor(NamedBeanHandle<Sensor> s)
           
 void provideSecondFeedbackSensor(String pName)
           
protected  void sensorPropertyChange(PropertyChangeEvent evt)
           
 void setBinaryOutput(boolean state)
          Turn this object into just a binary output.
 void setCommandedState(int s)
          Public access to changing turnout state.
 void setControlType(int num)
          Set control type.
 void setDecoderName(String decoderName)
          Set a human readable representation of the decoder type for this turnout.
 void setDivergingSpeed(String s)
           
 void setFeedbackMode(int mode)
          Set the feedback mode from a integer.
 void setFeedbackMode(String mode)
          Set the feedback mode from a human readable name.
 void setInhibitOperation(boolean io)
          Change the value of the inhibit operation indicator
 void setInitialKnownStateFromFeedback()
          Sets the initial known state (CLOSED,THROWN,UNKNOWN) from feedback information, if appropriate.
 void setInverted(boolean inverted)
          Set turnout inverted If true commands are reversed to layout.
(package private)  void setKnownStateToCommanded()
          The name pretty much says it.
 void setLocked(int turnoutLockout, boolean locked)
          Turnouts that are locked should only respond to JMRI commands to change state.
 void setNumberOutputBits(int num)
          Set number of output bits.
 void setReportLocked(boolean reportLocked)
          When true, report to console anytime a cab attempts to change the state of a turnout on the layout.
 void setState(int s)
          Implement a shorter name for setCommandedState.
 void setStraightSpeed(String s)
           
 void setTurnoutOperation(TurnoutOperation toper)
          set current automation class
protected  void turnoutPushbuttonLockout()
           
protected abstract  void turnoutPushbuttonLockout(boolean locked)
           
 void vetoableChange(PropertyChangeEvent evt)
           
 
Methods inherited from class jmri.implementation.AbstractNamedBean
addPropertyChangeListener, addPropertyChangeListener, firePropertyChange, getComment, getDisplayName, getFullyFormattedDisplayName, getListenerRef, getListenerRefs, getNumPropertyChangeListeners, getProperty, getPropertyChangeListeners, getPropertyChangeListeners, getPropertyKeys, getSystemName, getUserName, removeProperty, removePropertyChangeListener, setComment, setProperty, setUserName, updateListenerRef
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 
Methods inherited from interface jmri.NamedBean
addPropertyChangeListener, addPropertyChangeListener, getComment, getDisplayName, getFullyFormattedDisplayName, getListenerRef, getListenerRefs, getNumPropertyChangeListeners, getProperty, getPropertyChangeListeners, getPropertyKeys, getSystemName, getUserName, removeProperty, removePropertyChangeListener, setComment, setProperty, setUserName, updateListenerRef
 

Field Detail

_validFeedbackNames

protected String[] _validFeedbackNames

_validFeedbackModes

protected int[] _validFeedbackModes

_validFeedbackTypes

protected int _validFeedbackTypes

_activeFeedbackType

protected int _activeFeedbackType

_inverted

protected boolean _inverted

_cabLockout

protected boolean _cabLockout

_pushButtonLockout

protected boolean _pushButtonLockout

_enableCabLockout

protected boolean _enableCabLockout

_enablePushButtonLockout

protected boolean _enablePushButtonLockout

_reportLocked

protected boolean _reportLocked

_validDecoderNames

protected String[] _validDecoderNames
Valid stationary decoder names


_decoderName

protected String _decoderName

myOperator

protected TurnoutOperator myOperator

myTurnoutOperation

protected TurnoutOperation myTurnoutOperation

inhibitOperation

protected boolean inhibitOperation

binaryOutput

protected boolean binaryOutput

_divergeSpeed

String _divergeSpeed

_straightSpeed

String _straightSpeed

log

static org.slf4j.Logger log
Constructor Detail

AbstractTurnout

protected AbstractTurnout(String systemName)

AbstractTurnout

protected AbstractTurnout(String systemName,
                          String userName)
Method Detail

getBeanType

public String getBeanType()
Description copied from interface: NamedBean
For instances in the code where we are dealing with just a bean and a message needs to be passed to the user or in a log.

Specified by:
getBeanType in interface NamedBean
Returns:
a string of the bean type, eg Turnout, Sensor etc

forwardCommandChangeToLayout

protected abstract void forwardCommandChangeToLayout(int s)
Handle a request to change state, typically by sending a message to the layout in some child class. Public version (used by TurnoutOperator) sends the current commanded state without changing it.

Parameters:
s - new state value

forwardCommandChangeToLayout

protected void forwardCommandChangeToLayout()

newCommandedState

protected void newCommandedState(int s)
Sets a new Commanded state, if need be notifying the listeners, but does NOT send the command downstream. This is used when a new commanded state is noticed from another command.


getKnownState

public int getKnownState()
Description copied from interface: Turnout
Query the known state. This is a bound parameter, so you can also register a listener to be informed of changes. A result is always returned; if no other feedback method is available, the commanded state will be used.

Specified by:
getKnownState in interface Turnout

setCommandedState

public void setCommandedState(int s)
Public access to changing turnout state. Sets the commanded state and, if appropriate starts a TurnoutOperator to do its thing. If there is no TurnoutOperator (not required or nothing suitable) then just tell the layout and hope for the best.

Specified by:
setCommandedState in interface Turnout

getCommandedState

public int getCommandedState()
Description copied from interface: Turnout
Query the commanded state. This is a bound parameter, so you can also register a listener to be informed of changes.

Specified by:
getCommandedState in interface Turnout

newKnownState

protected void newKnownState(int s)
Add a protected newKnownState() for use by implementations.

Use this to update internal information when a state change is detected outside the Turnout object, e.g. via feedback from sensors on the layout.

If the layout status of the Turnout is observed to change to THROWN or CLOSED, this also sets the commanded state, because it's assumed that somebody somewhere commanded that move. If it's observed to change to UNKNOWN or INCONSISTENT, that's perhaps either an error or a move in progress, and no change is made to the commanded state.

This implementation sends a command to the layout for the new state if going to THROWN or CLOSED, because there may be others listening to network state.

Not intended for general use, e.g. for users to set the KnownState.

Parameters:
s - New state value

isConsistentState

public boolean isConsistentState()
Show whether state is one you can safely run trains over

Specified by:
isConsistentState in interface Turnout
Returns:
true iff state is a valid one and the known state is the same as commanded

setKnownStateToCommanded

void setKnownStateToCommanded()
The name pretty much says it.

Triggers all listeners, etc. For use by the TurnoutOperator classes.


setState

public void setState(int s)
Implement a shorter name for setCommandedState.

This generally shouldn't be used by Java code; use setCommandedState instead. The is provided to make Jython script access easier to read.

Note that getState() and setState(int) are not symmetric: getState is the known state, and set state modifies the commanded state.

Specified by:
setState in interface NamedBean

getState

public int getState()
Implement a shorter name for getKnownState.

This generally shouldn't be used by Java code; use getKnownState instead. The is provided to make Jython script access easier to read.

Note that getState() and setState(int) are not symmetric: getState is the known state, and set state modifies the commanded state.

Specified by:
getState in interface NamedBean

getNumberOutputBits

public int getNumberOutputBits()
Description copied from interface: Turnout
Get number of output bits.

Currently must be one or two.

Specified by:
getNumberOutputBits in interface Turnout

setNumberOutputBits

public void setNumberOutputBits(int num)
Description copied from interface: Turnout
Set number of output bits.

Currently must be one or two.

Specified by:
setNumberOutputBits in interface Turnout

getControlType

public int getControlType()
Description copied from interface: Turnout
Get control type.

Currently must be either 0 for steady state, or n for pulse for n time units.

Specified by:
getControlType in interface Turnout

setControlType

public void setControlType(int num)
Description copied from interface: Turnout
Set control type.

Currently must be either 0 for steady state, or n for pulse for n time units.

Specified by:
setControlType in interface Turnout

getValidFeedbackTypes

public int getValidFeedbackTypes()
Description copied from interface: Turnout
Get a representation of the feedback type. This is the OR of possible values: DIRECT, EXACT, etc. The valid combinations depend on the implemented system.

Specified by:
getValidFeedbackTypes in interface Turnout

getValidFeedbackNames

public String[] getValidFeedbackNames()
Description copied from interface: Turnout
Get a human readable representation of the feedback type. The values depend on the implemented system.

Specified by:
getValidFeedbackNames in interface Turnout

setFeedbackMode

public void setFeedbackMode(String mode)
                     throws IllegalArgumentException
Description copied from interface: Turnout
Set the feedback mode from a human readable name. This must be one of the names defined in a previous Turnout.getValidFeedbackNames() call.

Specified by:
setFeedbackMode in interface Turnout
Throws:
IllegalArgumentException

setFeedbackMode

public void setFeedbackMode(int mode)
                     throws IllegalArgumentException
Description copied from interface: Turnout
Set the feedback mode from a integer. This must be one of the bit values defined in a previous Turnout.getValidFeedbackTypes() call. Having more than one bit set is an error.

Specified by:
setFeedbackMode in interface Turnout
Throws:
IllegalArgumentException

getFeedbackMode

public int getFeedbackMode()
Description copied from interface: Turnout
Get the feedback mode in machine readable form. This will be one of the bits defined in a Turnout.getValidFeedbackTypes() call.

Specified by:
getFeedbackMode in interface Turnout

getFeedbackModeName

public String getFeedbackModeName()
Description copied from interface: Turnout
Get the feedback mode in human readable form. This will be one of the names defined in a Turnout.getValidFeedbackNames() call.

Specified by:
getFeedbackModeName in interface Turnout

setInverted

public void setInverted(boolean inverted)
Description copied from interface: Turnout
Set turnout inverted

If true commands are reversed to layout.

Changing this changes the known state from CLOSED to THROWN and vice-versa, with notifications; UNKNOWN and INCONSISTENT are left unchanged, as is the commanded state.

Specified by:
setInverted in interface Turnout

getInverted

public final boolean getInverted()
Get the turnout inverted state. If true, commands sent to the layout are reversed. Thrown becomes Closed, and Closed becomes Thrown.

Used in polling loops in system-specific code, so made final to allow optimization.

Specified by:
getInverted in interface Turnout

canInvert

public boolean canInvert()
Determine if the turnouts can be inverted. If true inverted turnouts supported.

Specified by:
canInvert in interface Turnout

setLocked

public void setLocked(int turnoutLockout,
                      boolean locked)
Turnouts that are locked should only respond to JMRI commands to change state. We simulate a locked turnout by monitoring the known state (turnout feedback is required) and if we detect that the known state has changed, negate it by forcing the turnout to return to the commanded state. Turnout that have local buttons can also be locked if their decoder supports it.

Specified by:
setLocked in interface Turnout
Parameters:
locked -

getLocked

public boolean getLocked(int turnoutLockout)
Determine if turnout is locked. Returns true if turnout is locked. There are two types of locks, cab lockout, and pushbutton lockout.

Specified by:
getLocked in interface Turnout

canLock

public boolean canLock(int turnoutLockout)
Description copied from interface: Turnout
Determine if turnout can be locked. Must specify the type of lock.

If true turnouts can be locked.

Specified by:
canLock in interface Turnout

enableLockOperation

public void enableLockOperation(int turnoutLockout,
                                boolean enabled)
Description copied from interface: Turnout
Enable turnout lock operators.

If true the type of lock specified is enabled.

Specified by:
enableLockOperation in interface Turnout

setReportLocked

public void setReportLocked(boolean reportLocked)
When true, report to console anytime a cab attempts to change the state of a turnout on the layout. When a turnout is cab locked, only JMRI is allowed to change the state of a turnout.

Specified by:
setReportLocked in interface Turnout

getReportLocked

public boolean getReportLocked()
When true, report to console anytime a cab attempts to change the state of a turnout on the layout. When a turnout is cab locked, only JMRI is allowed to change the state of a turnout.

Specified by:
getReportLocked in interface Turnout

getValidDecoderNames

public String[] getValidDecoderNames()
Description copied from interface: Turnout
Get a human readable representation of the decoder types.

Specified by:
getValidDecoderNames in interface Turnout

getDecoderName

public String getDecoderName()
Description copied from interface: Turnout
Get a human readable representation of the decoder type for this turnout.

Specified by:
getDecoderName in interface Turnout

setDecoderName

public void setDecoderName(String decoderName)
Description copied from interface: Turnout
Set a human readable representation of the decoder type for this turnout.

Specified by:
setDecoderName in interface Turnout

turnoutPushbuttonLockout

protected abstract void turnoutPushbuttonLockout(boolean locked)

turnoutPushbuttonLockout

protected void turnoutPushbuttonLockout()

getCurrentOperator

public TurnoutOperator getCurrentOperator()

getTurnoutOperation

public TurnoutOperation getTurnoutOperation()
Specified by:
getTurnoutOperation in interface Turnout
Returns:
current operation automation class

setTurnoutOperation

public void setTurnoutOperation(TurnoutOperation toper)
Description copied from interface: Turnout
set current automation class

Specified by:
setTurnoutOperation in interface Turnout
Parameters:
toper - TurnoutOperation subclass instance

operationPropertyChange

protected void operationPropertyChange(PropertyChangeEvent evt)

getInhibitOperation

public boolean getInhibitOperation()
Description copied from interface: Turnout
Get the indicator for whether automatic operation (retry) has been inhibited for this turnout

Specified by:
getInhibitOperation in interface Turnout

setInhibitOperation

public void setInhibitOperation(boolean io)
Description copied from interface: Turnout
Change the value of the inhibit operation indicator

Specified by:
setInhibitOperation in interface Turnout

getTurnoutOperator

protected TurnoutOperator getTurnoutOperator()
find the TurnoutOperation class for this turnout, and get an instance of the corresponding operator Override this function if you want another way to choose the operation

Returns:
newly-instantiated TurnoutOPerator, or null if nothing suitable

getFeedbackModeForOperation

protected int getFeedbackModeForOperation()
Allow an actual turnout class to transform private feedback types into ones that the generic turnout operations know about

Returns:
apparent feedback mode for operation lookup

provideFirstFeedbackSensor

public void provideFirstFeedbackSensor(String pName)
                                throws JmriException
Description copied from interface: Turnout
Provide Sensor objects needed for some feedback types. Since we defined two feeedback methods that require monitoring, we provide these methods to define those sensors to the Turnout.

The second sensor can be null if needed.

Sensor-based feedback will not function until these sensors have been provided.

Specified by:
provideFirstFeedbackSensor in interface Turnout
Throws:
JmriException

provideFirstFeedbackNamedSensor

public void provideFirstFeedbackNamedSensor(NamedBeanHandle<Sensor> s)

getFirstSensor

public Sensor getFirstSensor()
Description copied from interface: Turnout
Get the first sensor, if defined.

Returns null if no Sensor recorded.

Specified by:
getFirstSensor in interface Turnout

getFirstNamedSensor

public NamedBeanHandle<Sensor> getFirstNamedSensor()
Description copied from interface: Turnout
Get the first sensor, if defined.

Returns null if no Sensor recorded.

Specified by:
getFirstNamedSensor in interface Turnout

provideSecondFeedbackSensor

public void provideSecondFeedbackSensor(String pName)
                                 throws JmriException
Specified by:
provideSecondFeedbackSensor in interface Turnout
Throws:
JmriException

provideSecondFeedbackNamedSensor

public void provideSecondFeedbackNamedSensor(NamedBeanHandle<Sensor> s)

getSecondSensor

public Sensor getSecondSensor()
Description copied from interface: Turnout
Get the Second sensor, if defined.

Returns null if no Sensor recorded.

Specified by:
getSecondSensor in interface Turnout

getSecondNamedSensor

public NamedBeanHandle<Sensor> getSecondNamedSensor()
Description copied from interface: Turnout
Get the first sensor, if defined.

Returns null if no Sensor recorded.

Specified by:
getSecondNamedSensor in interface Turnout

setInitialKnownStateFromFeedback

public void setInitialKnownStateFromFeedback()
Description copied from interface: Turnout
Sets the initial known state (CLOSED,THROWN,UNKNOWN) from feedback information, if appropriate.

This method is designed to be called only when Turnouts are loaded and when a new Turnout is defined in the Turnout table.

No change to known state is made if feedback information is not available. If feedback information is inconsistent, or if sensor definition is missing in ONESENSOR and TWOSENSOR feedback, turnout state is set to UNKNOWN.

Specified by:
setInitialKnownStateFromFeedback in interface Turnout

propertyChange

public void propertyChange(PropertyChangeEvent evt)
React to sensor changes by changing the KnownState if using an appropriate sensor mode

Specified by:
propertyChange in interface PropertyChangeListener

sensorPropertyChange

protected void sensorPropertyChange(PropertyChangeEvent evt)

setBinaryOutput

public void setBinaryOutput(boolean state)
Description copied from interface: Turnout
Turn this object into just a binary output.

Specified by:
setBinaryOutput in interface Turnout

dispose

public void dispose()
Description copied from interface: NamedBean
Deactivate this object, so that it releases as many resources as possible and no longer effects others.

For example, if this object has listeners, after a call to this method it should no longer notify those listeners. Any native or system-wide resources it maintains should be released, including threads, files, etc.

It is an error to invoke any other methods on this object once dispose() has been called. Note, however, that there is no guarantee about behavior in that case.

Afterwards, references to this object may still exist elsewhere, preventing its garbage collection. But it's formally dead, and shouldn't be keeping any other objects alive. Therefore, this method should null out any references to other objects that this NamedBean contained.

Specified by:
dispose in interface NamedBean
Overrides:
dispose in class AbstractNamedBean

getDivergingLimit

public float getDivergingLimit()
Specified by:
getDivergingLimit in interface Turnout

getDivergingSpeed

public String getDivergingSpeed()
Specified by:
getDivergingSpeed in interface Turnout

setDivergingSpeed

public void setDivergingSpeed(String s)
                       throws JmriException
Specified by:
setDivergingSpeed in interface Turnout
Throws:
JmriException

getStraightLimit

public float getStraightLimit()
Specified by:
getStraightLimit in interface Turnout

getStraightSpeed

public String getStraightSpeed()
Specified by:
getStraightSpeed in interface Turnout

setStraightSpeed

public void setStraightSpeed(String s)
                      throws JmriException
Specified by:
setStraightSpeed in interface Turnout
Throws:
JmriException

vetoableChange

public void vetoableChange(PropertyChangeEvent evt)
                    throws PropertyVetoException
Specified by:
vetoableChange in interface NamedBean
Overrides:
vetoableChange in class AbstractNamedBean
Throws:
PropertyVetoException


Copyright © 1997-2014 JMRI Community.
JMRI, DecoderPro, PanelPro, SoundPro, DispatcherPro and associated logos are our trademarks.

Additional information on copyright, trademarks and licenses is linked here.
Site hosted by: Get JMRI Model Railroad Interface at SourceForge.net. Fast, secure and Free Open Source software downloads