/*
  Simple DirectMedia Layer
  Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>

  This software is provided 'as-is', without any express or implied
  warranty.  In no event will the authors be held liable for any damages
  arising from the use of this software.

  Permission is granted to anyone to use this software for any purpose,
  including commercial applications, and to alter it and redistribute it
  freely, subject to the following restrictions:

  1. The origin of this software must not be misrepresented; you must not
     claim that you wrote the original software. If you use this software
     in a product, an acknowledgment in the product documentation would be
     appreciated but is not required.
  2. Altered source versions must be plainly marked as such, and must not be
     misrepresented as being the original software.
  3. This notice may not be removed or altered from any source distribution.
*/

/**
 *  \file SDL_haptic.h
 *
 *  \brief The SDL Haptic subsystem allows you to control haptic (force feedback)
 *         devices.
 *
 *  The basic usage is as follows:
 *   - Initialize the Subsystem (::SDL_INIT_HAPTIC).
 *   - Open a Haptic Device.
 *    - SDL_HapticOpen() to open from index.
 *    - SDL_HapticOpenFromJoystick() to open from an existing joystick.
 *   - Create an effect (::SDL_HapticEffect).
 *   - Upload the effect with SDL_HapticNewEffect().
 *   - Run the effect with SDL_HapticRunEffect().
 *   - (optional) Free the effect with SDL_HapticDestroyEffect().
 *   - Close the haptic device with SDL_HapticClose().
 *
 * \par Simple rumble example:
 * \code
 *    SDL_Haptic *haptic;
 *
 *    // Open the device
 *    haptic = SDL_HapticOpen( 0 );
 *    if (haptic == NULL)
 *       return -1;
 *
 *    // Initialize simple rumble
 *    if (SDL_HapticRumbleInit( haptic ) != 0)
 *       return -1;
 *
 *    // Play effect at 50% strength for 2 seconds
 *    if (SDL_HapticRumblePlay( haptic, 0.5, 2000 ) != 0)
 *       return -1;
 *    SDL_Delay( 2000 );
 *
 *    // Clean up
 *    SDL_HapticClose( haptic );
 * \endcode
 *
 * \par Complete example:
 * \code
 * int test_haptic( SDL_Joystick * joystick ) {
 *    SDL_Haptic *haptic;
 *    SDL_HapticEffect effect;
 *    int effect_id;
 *
 *    // Open the device
 *    haptic = SDL_HapticOpenFromJoystick( joystick );
 *    if (haptic == NULL) return -1; // Most likely joystick isn't haptic
 *
 *    // See if it can do sine waves
 *    if ((SDL_HapticQuery(haptic) & SDL_HAPTIC_SINE)==0) {
 *       SDL_HapticClose(haptic); // No sine effect
 *       return -1;
 *    }
 *
 *    // Create the effect
 *    memset( &effect, 0, sizeof(SDL_HapticEffect) ); // 0 is safe default
 *    effect.type = SDL_HAPTIC_SINE;
 *    effect.periodic.direction.type = SDL_HAPTIC_POLAR; // Polar coordinates
 *    effect.periodic.direction.dir[0] = 18000; // Force comes from south
 *    effect.periodic.period = 1000; // 1000 ms
 *    effect.periodic.magnitude = 20000; // 20000/32767 strength
 *    effect.periodic.length = 5000; // 5 seconds long
 *    effect.periodic.attack_length = 1000; // Takes 1 second to get max strength
 *    effect.periodic.fade_length = 1000; // Takes 1 second to fade away
 *
 *    // Upload the effect
 *    effect_id = SDL_HapticNewEffect( haptic, &effect );
 *
 *    // Test the effect
 *    SDL_HapticRunEffect( haptic, effect_id, 1 );
 *    SDL_Delay( 5000); // Wait for the effect to finish
 *
 *    // We destroy the effect, although closing the device also does this
 *    SDL_HapticDestroyEffect( haptic, effect_id );
 *
 *    // Close the device
 *    SDL_HapticClose(haptic);
 *
 *    return 0; // Success
 * }
 * \endcode
 */

#ifndef _SDL_haptic_h
#define _SDL_haptic_h

#include "SDL_stdinc.h"
#include "SDL_error.h"
#include "SDL_joystick.h"

#include "begin_code.h"
/* Set up for C function definitions, even when using C++ */
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */

/**
 *  \typedef SDL_Haptic
 *
 *  \brief The haptic structure used to identify an SDL haptic.
 *
 *  \sa SDL_HapticOpen
 *  \sa SDL_HapticOpenFromJoystick
 *  \sa SDL_HapticClose
 */
struct _SDL_Haptic;
typedef struct _SDL_Haptic SDL_Haptic;

/**
 *  \name Haptic features
 *
 *  Different haptic features a device can have.
 */
/* @{ */

/**
 *  \name Haptic effects
 */
/* @{ */

/**
 *  \brief Constant effect supported.
 *
 *  Constant haptic effect.
 *
 *  \sa SDL_HapticCondition
 */
#define SDL_HAPTIC_CONSTANT   (1u<<0)

/**
 *  \brief Sine wave effect supported.
 *
 *  Periodic haptic effect that simulates sine waves.
 *
 *  \sa SDL_HapticPeriodic
 */
#define SDL_HAPTIC_SINE       (1u<<1)

/**
 *  \brief Left/Right effect supported.
 *
 *  Haptic effect for direct control over high/low frequency motors.
 *
 *  \sa SDL_HapticLeftRight
 * \warning this value was SDL_HAPTIC_SQUARE right before 2.0.0 shipped. Sorry,
 *          we ran out of bits, and this is important for XInput devices.
 */
#define SDL_HAPTIC_LEFTRIGHT     (1u<<2)

/* !!! FIXME: put this back when we have more bits in 2.1 */
/* #define SDL_HAPTIC_SQUARE     (1<<2) */

/**
 *  \brief Triangle wave effect supported.
 *
 *  Periodic haptic effect that simulates triangular waves.
 *
 *  \sa SDL_HapticPeriodic
 */
#define SDL_HAPTIC_TRIANGLE   (1u<<3)

/**
 *  \brief Sawtoothup wave effect supported.
 *
 *  Periodic haptic effect that simulates saw tooth up waves.
 *
 *  \sa SDL_HapticPeriodic
 */
#define SDL_HAPTIC_SAWTOOTHUP (1u<<4)

/**
 *  \brief Sawtoothdown wave effect supported.
 *
 *  Periodic haptic effect that simulates saw tooth down waves.
 *
 *  \sa SDL_HapticPeriodic
 */
#define SDL_HAPTIC_SAWTOOTHDOWN (1u<<5)

/**
 *  \brief Ramp effect supported.
 *
 *  Ramp haptic effect.
 *
 *  \sa SDL_HapticRamp
 */
#define SDL_HAPTIC_RAMP       (1u<<6)

/**
 *  \brief Spring effect supported - uses axes position.
 *
 *  Condition haptic effect that simulates a spring.  Effect is based on the
 *  axes position.
 *
 *  \sa SDL_HapticCondition
 */
#define SDL_HAPTIC_SPRING     (1u<<7)

/**
 *  \brief Damper effect supported - uses axes velocity.
 *
 *  Condition haptic effect that simulates dampening.  Effect is based on the
 *  axes velocity.
 *
 *  \sa SDL_HapticCondition
 */
#define SDL_HAPTIC_DAMPER     (1u<<8)

/**
 *  \brief Inertia effect supported - uses axes acceleration.
 *
 *  Condition haptic effect that simulates inertia.  Effect is based on the axes
 *  acceleration.
 *
 *  \sa SDL_HapticCondition
 */
#define SDL_HAPTIC_INERTIA    (1u<<9)

/**
 *  \brief Friction effect supported - uses axes movement.
 *
 *  Condition haptic effect that simulates friction.  Effect is based on the
 *  axes movement.
 *
 *  \sa SDL_HapticCondition
 */
#define SDL_HAPTIC_FRICTION   (1u<<10)

/**
 *  \brief Custom effect is supported.
 *
 *  User defined custom haptic effect.
 */
#define SDL_HAPTIC_CUSTOM     (1u<<11)

/* @} *//* Haptic effects */

/* These last few are features the device has, not effects */

/**
 *  \brief Device can set global gain.
 *
 *  Device supports setting the global gain.
 *
 *  \sa SDL_HapticSetGain
 */
#define SDL_HAPTIC_GAIN       (1u<<12)

/**
 *  \brief Device can set autocenter.
 *
 *  Device supports setting autocenter.
 *
 *  \sa SDL_HapticSetAutocenter
 */
#define SDL_HAPTIC_AUTOCENTER (1u<<13)

/**
 *  \brief Device can be queried for effect status.
 *
 *  Device can be queried for effect status.
 *
 *  \sa SDL_HapticGetEffectStatus
 */
#define SDL_HAPTIC_STATUS     (1u<<14)

/**
 *  \brief Device can be paused.
 *
 *  \sa SDL_HapticPause
 *  \sa SDL_HapticUnpause
 */
#define SDL_HAPTIC_PAUSE      (1u<<15)

/**
 * \name Direction encodings
 */
/* @{ */

/**
 *  \brief Uses polar coordinates for the direction.
 *
 *  \sa SDL_HapticDirection
 */
#define SDL_HAPTIC_POLAR      0

/**
 *  \brief Uses cartesian coordinates for the direction.
 *
 *  \sa SDL_HapticDirection
 */
#define SDL_HAPTIC_CARTESIAN  1

/**
 *  \brief Uses spherical coordinates for the direction.
 *
 *  \sa SDL_HapticDirection
 */
#define SDL_HAPTIC_SPHERICAL  2

/* @} *//* Direction encodings */

/* @} *//* Haptic features */

/*
 * Misc defines.
 */

/**
 * \brief Used to play a device an infinite number of times.
 *
 * \sa SDL_HapticRunEffect
 */
#define SDL_HAPTIC_INFINITY   4294967295U

/**
 *  \brief Structure that represents a haptic direction.
 *
 *  This is the direction where the force comes from,
 *  instead of the direction in which the force is exerted.
 *
 *  Directions can be specified by:
 *   - ::SDL_HAPTIC_POLAR : Specified by polar coordinates.
 *   - ::SDL_HAPTIC_CARTESIAN : Specified by cartesian coordinates.
 *   - ::SDL_HAPTIC_SPHERICAL : Specified by spherical coordinates.
 *
 *  Cardinal directions of the haptic device are relative to the positioning
 *  of the device.  North is considered to be away from the user.
 *
 *  The following diagram represents the cardinal directions:
 *  \verbatim
                 .--.
                 |__| .-------.
                 |=.| |.-----.|
                 |--| ||     ||
                 |  | |'-----'|
                 |__|~')_____('
                   [ COMPUTER ]

                     North (0,-1)
                         ^
                         |
                         |
   (-1,0)  West <----[ HAPTIC ]----> East (1,0)
                         |
                         |
                         v
                      South (0,1)

                      [ USER ]
                        \|||/
                        (o o)
                  ---ooO-(_)-Ooo---
    \endverbatim
 *
 *  If type is ::SDL_HAPTIC_POLAR, direction is encoded by hundredths of a
 *  degree starting north and turning clockwise.  ::SDL_HAPTIC_POLAR only uses
 *  the first \c dir parameter.  The cardinal directions would be:
 *   - North: 0 (0 degrees)
 *   - East: 9000 (90 degrees)
 *   - South: 18000 (180 degrees)
 *   - West: 27000 (270 degrees)
 *
 *  If type is ::SDL_HAPTIC_CARTESIAN, direction is encoded by three positions
 *  (X axis, Y axis and Z axis (with 3 axes)).  ::SDL_HAPTIC_CARTESIAN uses
 *  the first three \c dir parameters.  The cardinal directions would be:
 *   - North:  0,-1, 0
 *   - East:   1, 0, 0
 *   - South:  0, 1, 0
 *   - West:  -1, 0, 0
 *
 *  The Z axis represents the height of the effect if supported, otherwise
 *  it's unused.  In cartesian encoding (1, 2) would be the same as (2, 4), you
 *  can use any multiple you want, only the direction matters.
 *
 *  If type is ::SDL_HAPTIC_SPHERICAL, direction is encoded by two rotations.
 *  The first two \c dir parameters are used.  The \c dir parameters are as
 *  follows (all values are in hundredths of degrees):
 *   - Degrees from (1, 0) rotated towards (0, 1).
 *   - Degrees towards (0, 0, 1) (device needs at least 3 axes).
 *
 *
 *  Example of force coming from the south with all encodings (force coming
 *  from the south means the user will have to pull the stick to counteract):
 *  \code
 *  SDL_HapticDirection direction;
 *
 *  // Cartesian directions
 *  direction.type = SDL_HAPTIC_CARTESIAN; // Using cartesian direction encoding.
 *  direction.dir[0] = 0; // X position
 *  direction.dir[1] = 1; // Y position
 *  // Assuming the device has 2 axes, we don't need to specify third parameter.
 *
 *  // Polar directions
 *  direction.type = SDL_HAPTIC_POLAR; // We'll be using polar direction encoding.
 *  direction.dir[0] = 18000; // Polar only uses first parameter
 *
 *  // Spherical coordinates
 *  direction.type = SDL_HAPTIC_SPHERICAL; // Spherical encoding
 *  direction.dir[0] = 9000; // Since we only have two axes we don't need more parameters.
 *  \endcode
 *
 *  \sa SDL_HAPTIC_POLAR
 *  \sa SDL_HAPTIC_CARTESIAN
 *  \sa SDL_HAPTIC_SPHERICAL
 *  \sa SDL_HapticEffect
 *  \sa SDL_HapticNumAxes
 */
typedef struct SDL_HapticDirection
{
    Uint8 type;         /**< The type of encoding. */
    Sint32 dir[3];      /**< The encoded direction. */
} SDL_HapticDirection;

/**
 *  \brief A structure containing a template for a Constant effect.
 *
 *  The struct is exclusive to the ::SDL_HAPTIC_CONSTANT effect.
 *
 *  A constant effect applies a constant force in the specified direction
 *  to the joystick.
 *
 *  \sa SDL_HAPTIC_CONSTANT
 *  \sa SDL_HapticEffect
 */
typedef struct SDL_HapticConstant
{
    /* Header */
    Uint16 type;            /**< ::SDL_HAPTIC_CONSTANT */
    SDL_HapticDirection direction;  /**< Direction of the effect. */

    /* Replay */
    Uint32 length;          /**< Duration of the effect. */
    Uint16 delay;           /**< Delay before starting the effect. */

    /* Trigger */
    Uint16 button;          /**< Button that triggers the effect. */
    Uint16 interval;        /**< How soon it can be triggered again after button. */

    /* Constant */
    Sint16 level;           /**< Strength of the constant effect. */

    /* Envelope */
    Uint16 attack_length;   /**< Duration of the attack. */
    Uint16 attack_level;    /**< Level at the start of the attack. */
    Uint16 fade_length;     /**< Duration of the fade. */
    Uint16 fade_level;      /**< Level at the end of the fade. */
} SDL_HapticConstant;

/**
 *  \brief A structure containing a template for a Periodic effect.
 *
 *  The struct handles the following effects:
 *   - ::SDL_HAPTIC_SINE
 *   - ::SDL_HAPTIC_LEFTRIGHT
 *   - ::SDL_HAPTIC_TRIANGLE
 *   - ::SDL_HAPTIC_SAWTOOTHUP
 *   - ::SDL_HAPTIC_SAWTOOTHDOWN
 *
 *  A periodic effect consists in a wave-shaped effect that repeats itself
 *  over time.  The type determines the shape of the wave and the parameters
 *  determine the dimensions of the wave.
 *
 *  Phase is given by hundredth of a degree meaning that giving the phase a value
 *  of 9000 will displace it 25% of its period.  Here are sample values:
 *   -     0: No phase displacement.
 *   -  9000: Displaced 25% of its period.
 *   - 18000: Displaced 50% of its period.
 *   - 27000: Displaced 75% of its period.
 *   - 36000: Displaced 100% of its period, same as 0, but 0 is preferred.
 *
 *  Examples:
 *  \verbatim
    SDL_HAPTIC_SINE
      __      __      __      __
     /  \    /  \    /  \    /
    /    \__/    \__/    \__/

    SDL_HAPTIC_SQUARE
     __    __    __    __    __
    |  |  |  |  |  |  |  |  |  |
    |  |__|  |__|  |__|  |__|  |

    SDL_HAPTIC_TRIANGLE
      /\    /\    /\    /\    /\
     /  \  /  \  /  \  /  \  /
    /    \/    \/    \/    \/

    SDL_HAPTIC_SAWTOOTHUP
      /|  /|  /|  /|  /|  /|  /|
     / | / | / | / | / | / | / |
    /  |/  |/  |/  |/  |/  |/  |

    SDL_HAPTIC_SAWTOOTHDOWN
    \  |\  |\  |\  |\  |\  |\  |
     \ | \ | \ | \ | \ | \ | \ |
      \|  \|  \|  \|  \|  \|  \|
    \endverbatim
 *
 *  \sa SDL_HAPTIC_SINE
 *  \sa SDL_HAPTIC_LEFTRIGHT
 *  \sa SDL_HAPTIC_TRIANGLE
 *  \sa SDL_HAPTIC_SAWTOOTHUP
 *  \sa SDL_HAPTIC_SAWTOOTHDOWN
 *  \sa SDL_HapticEffect
 */
typedef struct SDL_HapticPeriodic
{
    /* Header */
    Uint16 type;        /**< ::SDL_HAPTIC_SINE, ::SDL_HAPTIC_LEFTRIGHT,
                             ::SDL_HAPTIC_TRIANGLE, ::SDL_HAPTIC_SAWTOOTHUP or
                             ::SDL_HAPTIC_SAWTOOTHDOWN */
    SDL_HapticDirection direction;  /**< Direction of the effect. */

    /* Replay */
    Uint32 length;      /**< Duration of the effect. */
    Uint16 delay;       /**< Delay before starting the effect. */

    /* Trigger */
    Uint16 button;      /**< Button that triggers the effect. */
    Uint16 interval;    /**< How soon it can be triggered again after button. */

    /* Periodic */
    Uint16 period;      /**< Period of the wave. */
    Sint16 magnitude;   /**< Peak value; if negative, equivalent to 180 degrees extra phase shift. */
    Sint16 offset;      /**< Mean value of the wave. */
    Uint16 phase;       /**< Positive phase shift given by hundredth of a degree. */

    /* Envelope */
    Uint16 attack_length;   /**< Duration of the attack. */
    Uint16 attack_level;    /**< Level at the start of the attack. */
    Uint16 fade_length; /**< Duration of the fade. */
    Uint16 fade_level;  /**< Level at the end of the fade. */
} SDL_HapticPeriodic;

/**
 *  \brief A structure containing a template for a Condition effect.
 *
 *  The struct handles the following effects:
 *   - ::SDL_HAPTIC_SPRING: Effect based on axes position.
 *   - ::SDL_HAPTIC_DAMPER: Effect based on axes velocity.
 *   - ::SDL_HAPTIC_INERTIA: Effect based on axes acceleration.
 *   - ::SDL_HAPTIC_FRICTION: Effect based on axes movement.
 *
 *  Direction is handled by condition internals instead of a direction member.
 *  The condition effect specific members have three parameters.  The first
 *  refers to the X axis, the second refers to the Y axis and the third
 *  refers to the Z axis.  The right terms refer to the positive side of the
 *  axis and the left terms refer to the negative side of the axis.  Please
 *  refer to the ::SDL_HapticDirection diagram for which side is positive and
 *  which is negative.
 *
 *  \sa SDL_HapticDirection
 *  \sa SDL_HAPTIC_SPRING
 *  \sa SDL_HAPTIC_DAMPER
 *  \sa SDL_HAPTIC_INERTIA
 *  \sa SDL_HAPTIC_FRICTION
 *  \sa SDL_HapticEffect
 */
typedef struct SDL_HapticCondition
{
    /* Header */
    Uint16 type;            /**< ::SDL_HAPTIC_SPRING, ::SDL_HAPTIC_DAMPER,
                                 ::SDL_HAPTIC_INERTIA or ::SDL_HAPTIC_FRICTION */
    SDL_HapticDirection direction;  /**< Direction of the effect - Not used ATM. */

    /* Replay */
    Uint32 length;          /**< Duration of the effect. */
    Uint16 delay;           /**< Delay before starting the effect. */

    /* Trigger */
    Uint16 button;          /**< Button that triggers the effect. */
    Uint16 interval;        /**< How soon it can be triggered again after button. */

    /* Condition */
    Uint16 right_sat[3];    /**< Level when joystick is to the positive side; max 0xFFFF. */
    Uint16 left_sat[3];     /**< Level when joystick is to the negative side; max 0xFFFF. */
    Sint16 right_coeff[3];  /**< How fast to increase the force towards the positive side. */
    Sint16 left_coeff[3];   /**< How fast to increase the force towards the negative side. */
    Uint16 deadband[3];     /**< Size of the dead zone; max 0xFFFF: whole axis-range when 0-centered. */
    Sint16 center[3];       /**< Position of the dead zone. */
} SDL_HapticCondition;

/**
 *  \brief A structure containing a template for a Ramp effect.
 *
 *  This struct is exclusively for the ::SDL_HAPTIC_RAMP effect.
 *
 *  The ramp effect starts at start strength and ends at end strength.
 *  It augments in linear fashion.  If you use attack and fade with a ramp
 *  the effects get added to the ramp effect making the effect become
 *  quadratic instead of linear.
 *
 *  \sa SDL_HAPTIC_RAMP
 *  \sa SDL_HapticEffect
 */
typedef struct SDL_HapticRamp
{
    /* Header */
    Uint16 type;            /**< ::SDL_HAPTIC_RAMP */
    SDL_HapticDirection direction;  /**< Direction of the effect. */

    /* Replay */
    Uint32 length;          /**< Duration of the effect. */
    Uint16 delay;           /**< Delay before starting the effect. */

    /* Trigger */
    Uint16 button;          /**< Button that triggers the effect. */
    Uint16 interval;        /**< How soon it can be triggered again after button. */

    /* Ramp */
    Sint16 start;           /**< Beginning strength level. */
    Sint16 end;             /**< Ending strength level. */

    /* Envelope */
    Uint16 attack_length;   /**< Duration of the attack. */
    Uint16 attack_level;    /**< Level at the start of the attack. */
    Uint16 fade_length;     /**< Duration of the fade. */
    Uint16 fade_level;      /**< Level at the end of the fade. */
} SDL_HapticRamp;

/**
 * \brief A structure containing a template for a Left/Right effect.
 *
 * This struct is exclusively for the ::SDL_HAPTIC_LEFTRIGHT effect.
 *
 * The Left/Right effect is used to explicitly control the large and small
 * motors, commonly found in modern game controllers. One motor is high
 * frequency, the other is low frequency.
 *
 * \sa SDL_HAPTIC_LEFTRIGHT
 * \sa SDL_HapticEffect
 */
typedef struct SDL_HapticLeftRight
{
    /* Header */
    Uint16 type;            /**< ::SDL_HAPTIC_LEFTRIGHT */

    /* Replay */
    Uint32 length;          /**< Duration of the effect. */

    /* Rumble */
    Uint16 large_magnitude; /**< Control of the large controller motor. */
    Uint16 small_magnitude; /**< Control of the small controller motor. */
} SDL_HapticLeftRight;

/**
 *  \brief A structure containing a template for the ::SDL_HAPTIC_CUSTOM effect.
 *
 *  A custom force feedback effect is much like a periodic effect, where the
 *  application can define its exact shape.  You will have to allocate the
 *  data yourself.  Data should consist of channels * samples Uint16 samples.
 *
 *  If channels is one, the effect is rotated using the defined direction.
 *  Otherwise it uses the samples in data for the different axes.
 *
 *  \sa SDL_HAPTIC_CUSTOM
 *  \sa SDL_HapticEffect
 */
typedef struct SDL_HapticCustom
{
    /* Header */
    Uint16 type;            /**< ::SDL_HAPTIC_CUSTOM */
    SDL_HapticDirection direction;  /**< Direction of the effect. */

    /* Replay */
    Uint32 length;          /**< Duration of the effect. */
    Uint16 delay;           /**< Delay before starting the effect. */

    /* Trigger */
    Uint16 button;          /**< Button that triggers the effect. */
    Uint16 interval;        /**< How soon it can be triggered again after button. */

    /* Custom */
    Uint8 channels;         /**< Axes to use, minimum of one. */
    Uint16 period;          /**< Sample periods. */
    Uint16 samples;         /**< Amount of samples. */
    Uint16 *data;           /**< Should contain channels*samples items. */

    /* Envelope */
    Uint16 attack_length;   /**< Duration of the attack. */
    Uint16 attack_level;    /**< Level at the start of the attack. */
    Uint16 fade_length;     /**< Duration of the fade. */
    Uint16 fade_level;      /**< Level at the end of the fade. */
} SDL_HapticCustom;

/**
 *  \brief The generic template for any haptic effect.
 *
 *  All values max at 32767 (0x7FFF).  Signed values also can be negative.
 *  Time values unless specified otherwise are in milliseconds.
 *
 *  You can also pass ::SDL_HAPTIC_INFINITY to length instead of a 0-32767
 *  value.  Neither delay, interval, attack_length nor fade_length support
 *  ::SDL_HAPTIC_INFINITY.  Fade will also not be used since effect never ends.
 *
 *  Additionally, the ::SDL_HAPTIC_RAMP effect does not support a duration of
 *  ::SDL_HAPTIC_INFINITY.
 *
 *  Button triggers may not be supported on all devices, it is advised to not
 *  use them if possible.  Buttons start at index 1 instead of index 0 like
 *  the joystick.
 *
 *  If both attack_length and fade_level are 0, the envelope is not used,
 *  otherwise both values are used.
 *
 *  Common parts:
 *  \code
 *  // Replay - All effects have this
 *  Uint32 length;        // Duration of effect (ms).
 *  Uint16 delay;         // Delay before starting effect.
 *
 *  // Trigger - All effects have this
 *  Uint16 button;        // Button that triggers effect.
 *  Uint16 interval;      // How soon before effect can be triggered again.
 *
 *  // Envelope - All effects except condition effects have this
 *  Uint16 attack_length; // Duration of the attack (ms).
 *  Uint16 attack_level;  // Level at the start of the attack.
 *  Uint16 fade_length;   // Duration of the fade out (ms).
 *  Uint16 fade_level;    // Level at the end of the fade.
 *  \endcode
 *
 *
 *  Here we have an example of a constant effect evolution in time:
 *  \verbatim
    Strength
    ^
    |
    |    effect level -->  _________________
    |                     /                 \
    |                    /                   \
    |                   /                     \
    |                  /                       \
    | attack_level --> |                        \
    |                  |                        |  <---  fade_level
    |
    +--------------------------------------------------> Time
                       [--]                 [---]
                       attack_length        fade_length

    [------------------][-----------------------]
    delay               length
    \endverbatim
 *
 *  Note either the attack_level or the fade_level may be above the actual
 *  effect level.
 *
 *  \sa SDL_HapticConstant
 *  \sa SDL_HapticPeriodic
 *  \sa SDL_HapticCondition
 *  \sa SDL_HapticRamp
 *  \sa SDL_HapticLeftRight
 *  \sa SDL_HapticCustom
 */
typedef union SDL_HapticEffect
{
    /* Common for all force feedback effects */
    Uint16 type;                    /**< Effect type. */
    SDL_HapticConstant constant;    /**< Constant effect. */
    SDL_HapticPeriodic periodic;    /**< Periodic effect. */
    SDL_HapticCondition condition;  /**< Condition effect. */
    SDL_HapticRamp ramp;            /**< Ramp effect. */
    SDL_HapticLeftRight leftright;  /**< Left/Right effect. */
    SDL_HapticCustom custom;        /**< Custom effect. */
} SDL_HapticEffect;

/* Function prototypes */
/**
 *  \brief Count the number of haptic devices attached to the system.
 *
 *  \return Number of haptic devices detected on the system.
 */
extern DECLSPEC int SDLCALL SDL_NumHaptics(void);

/**
 *  \brief Get the implementation dependent name of a Haptic device.
 *
 *  This can be called before any joysticks are opened.
 *  If no name can be found, this function returns NULL.
 *
 *  \param device_index Index of the device to get its name.
 *  \return Name of the device or NULL on error.
 *
 *  \sa SDL_NumHaptics
 */
extern DECLSPEC const char *SDLCALL SDL_HapticName(int device_index);

/**
 *  \brief Opens a Haptic device for usage.
 *
 *  The index passed as an argument refers to the N'th Haptic device on this
 *  system.
 *
 *  When opening a haptic device, its gain will be set to maximum and
 *  autocenter will be disabled.  To modify these values use
 *  SDL_HapticSetGain() and SDL_HapticSetAutocenter().
 *
 *  \param device_index Index of the device to open.
 *  \return Device identifier or NULL on error.
 *
 *  \sa SDL_HapticIndex
 *  \sa SDL_HapticOpenFromMouse
 *  \sa SDL_HapticOpenFromJoystick
 *  \sa SDL_HapticClose
 *  \sa SDL_HapticSetGain
 *  \sa SDL_HapticSetAutocenter
 *  \sa SDL_HapticPause
 *  \sa SDL_HapticStopAll
 */
extern DECLSPEC SDL_Haptic *SDLCALL SDL_HapticOpen(int device_index);

/**
 *  \brief Checks if the haptic device at index has been opened.
 *
 *  \param device_index Index to check to see if it has been opened.
 *  \return 1 if it has been opened or 0 if it hasn't.
 *
 *  \sa SDL_HapticOpen
 *  \sa SDL_HapticIndex
 */
extern DECLSPEC int SDLCALL SDL_HapticOpened(int device_index);

/**
 *  \brief Gets the index of a haptic device.
 *
 *  \param haptic Haptic device to get the index of.
 *  \return The index of the haptic device or -1 on error.
 *
 *  \sa SDL_HapticOpen
 *  \sa SDL_HapticOpened
 */
extern DECLSPEC int SDLCALL SDL_HapticIndex(SDL_Haptic * haptic);

/**
 *  \brief Gets whether or not the current mouse has haptic capabilities.
 *
 *  \return SDL_TRUE if the mouse is haptic, SDL_FALSE if it isn't.
 *
 *  \sa SDL_HapticOpenFromMouse
 */
extern DECLSPEC int SDLCALL SDL_MouseIsHaptic(void);

/**
 *  \brief Tries to open a haptic device from the current mouse.
 *
 *  \return The haptic device identifier or NULL on error.
 *
 *  \sa SDL_MouseIsHaptic
 *  \sa SDL_HapticOpen
 */
extern DECLSPEC SDL_Haptic *SDLCALL SDL_HapticOpenFromMouse(void);

/**
 *  \brief Checks to see if a joystick has haptic features.
 *
 *  \param joystick Joystick to test for haptic capabilities.
 *  \return 1 if the joystick is haptic, 0 if it isn't
 *          or -1 if an error ocurred.
 *
 *  \sa SDL_HapticOpenFromJoystick
 */
extern DECLSPEC int SDLCALL SDL_JoystickIsHaptic(SDL_Joystick * joystick);

/**
 *  \brief Opens a Haptic device for usage from a Joystick device.
 *
 *  You must still close the haptic device separately.  It will not be closed
 *  with the joystick.
 *
 *  When opening from a joystick you should first close the haptic device before
 *  closing the joystick device.  If not, on some implementations the haptic
 *  device will also get unallocated and you'll be unable to use force feedback
 *  on that device.
 *
 *  \param joystick Joystick to create a haptic device from.
 *  \return A valid haptic device identifier on success or NULL on error.
 *
 *  \sa SDL_HapticOpen
 *  \sa SDL_HapticClose
 */
extern DECLSPEC SDL_Haptic *SDLCALL SDL_HapticOpenFromJoystick(SDL_Joystick *
                                                               joystick);

/**
 *  \brief Closes a Haptic device previously opened with SDL_HapticOpen().
 *
 *  \param haptic Haptic device to close.
 */
extern DECLSPEC void SDLCALL SDL_HapticClose(SDL_Haptic * haptic);

/**
 *  \brief Returns the number of effects a haptic device can store.
 *
 *  On some platforms this isn't fully supported, and therefore is an
 *  approximation.  Always check to see if your created effect was actually
 *  created and do not rely solely on SDL_HapticNumEffects().
 *
 *  \param haptic The haptic device to query effect max.
 *  \return The number of effects the haptic device can store or
 *          -1 on error.
 *
 *  \sa SDL_HapticNumEffectsPlaying
 *  \sa SDL_HapticQuery
 */
extern DECLSPEC int SDLCALL SDL_HapticNumEffects(SDL_Haptic * haptic);

/**
 *  \brief Returns the number of effects a haptic device can play at the same
 *         time.
 *
 *  This is not supported on all platforms, but will always return a value.
 *  Added here for the sake of completeness.
 *
 *  \param haptic The haptic device to query maximum playing effects.
 *  \return The number of effects the haptic device can play at the same time
 *          or -1 on error.
 *
 *  \sa SDL_HapticNumEffects
 *  \sa SDL_HapticQuery
 */
extern DECLSPEC int SDLCALL SDL_HapticNumEffectsPlaying(SDL_Haptic * haptic);

/**
 *  \brief Gets the haptic device's supported features in bitwise manner.
 *
 *  Example:
 *  \code
 *  if (SDL_HapticQuery(haptic) & SDL_HAPTIC_CONSTANT) {
 *      printf("We have constant haptic effect!");
 *  }
 *  \endcode
 *
 *  \param haptic The haptic device to query.
 *  \return Haptic features in bitwise manner (OR'd).
 *
 *  \sa SDL_HapticNumEffects
 *  \sa SDL_HapticEffectSupported
 */
extern DECLSPEC unsigned int SDLCALL SDL_HapticQuery(SDL_Haptic * haptic);

/**
 *  \brief Gets the number of haptic axes the device has.
 *
 *  \sa SDL_HapticDirection
 */
extern DECLSPEC int SDLCALL SDL_HapticNumAxes(SDL_Haptic * haptic);

/**
 *  \brief Checks to see if effect is supported by haptic.
 *
 *  \param haptic Haptic device to check on.
 *  \param effect Effect to check to see if it is supported.
 *  \return SDL_TRUE if effect is supported, SDL_FALSE if it isn't or -1 on error.
 *
 *  \sa SDL_HapticQuery
 *  \sa SDL_HapticNewEffect
 */
extern DECLSPEC int SDLCALL SDL_HapticEffectSupported(SDL_Haptic * haptic,
                                                      SDL_HapticEffect *
                                                      effect);

/**
 *  \brief Creates a new haptic effect on the device.
 *
 *  \param haptic Haptic device to create the effect on.
 *  \param effect Properties of the effect to create.
 *  \return The id of the effect on success or -1 on error.
 *
 *  \sa SDL_HapticUpdateEffect
 *  \sa SDL_HapticRunEffect
 *  \sa SDL_HapticDestroyEffect
 */
extern DECLSPEC int SDLCALL SDL_HapticNewEffect(SDL_Haptic * haptic,
                                                SDL_HapticEffect * effect);

/**
 *  \brief Updates the properties of an effect.
 *
 *  Can be used dynamically, although behaviour when dynamically changing
 *  direction may be strange.  Specifically the effect may reupload itself
 *  and start playing from the start.  You cannot change the type either when
 *  running SDL_HapticUpdateEffect().
 *
 *  \param haptic Haptic device that has the effect.
 *  \param effect Effect to update.
 *  \param data New effect properties to use.
 *  \return 0 on success or -1 on error.
 *
 *  \sa SDL_HapticNewEffect
 *  \sa SDL_HapticRunEffect
 *  \sa SDL_HapticDestroyEffect
 */
extern DECLSPEC int SDLCALL SDL_HapticUpdateEffect(SDL_Haptic * haptic,
                                                   int effect,
                                                   SDL_HapticEffect * data);

/**
 *  \brief Runs the haptic effect on its associated haptic device.
 *
 *  If iterations are ::SDL_HAPTIC_INFINITY, it'll run the effect over and over
 *  repeating the envelope (attack and fade) every time.  If you only want the
 *  effect to last forever, set ::SDL_HAPTIC_INFINITY in the effect's length
 *  parameter.
 *
 *  \param haptic Haptic device to run the effect on.
 *  \param effect Identifier of the haptic effect to run.
 *  \param iterations Number of iterations to run the effect. Use
 *         ::SDL_HAPTIC_INFINITY for infinity.
 *  \return 0 on success or -1 on error.
 *
 *  \sa SDL_HapticStopEffect
 *  \sa SDL_HapticDestroyEffect
 *  \sa SDL_HapticGetEffectStatus
 */
extern DECLSPEC int SDLCALL SDL_HapticRunEffect(SDL_Haptic * haptic,
                                                int effect,
                                                Uint32 iterations);

/**
 *  \brief Stops the haptic effect on its associated haptic device.
 *
 *  \param haptic Haptic device to stop the effect on.
 *  \param effect Identifier of the effect to stop.
 *  \return 0 on success or -1 on error.
 *
 *  \sa SDL_HapticRunEffect
 *  \sa SDL_HapticDestroyEffect
 */
extern DECLSPEC int SDLCALL SDL_HapticStopEffect(SDL_Haptic * haptic,
                                                 int effect);

/**
 *  \brief Destroys a haptic effect on the device.
 *
 *  This will stop the effect if it's running.  Effects are automatically
 *  destroyed when the device is closed.
 *
 *  \param haptic Device to destroy the effect on.
 *  \param effect Identifier of the effect to destroy.
 *
 *  \sa SDL_HapticNewEffect
 */
extern DECLSPEC void SDLCALL SDL_HapticDestroyEffect(SDL_Haptic * haptic,
                                                     int effect);

/**
 *  \brief Gets the status of the current effect on the haptic device.
 *
 *  Device must support the ::SDL_HAPTIC_STATUS feature.
 *
 *  \param haptic Haptic device to query the effect status on.
 *  \param effect Identifier of the effect to query its status.
 *  \return 0 if it isn't playing, 1 if it is playing or -1 on error.
 *
 *  \sa SDL_HapticRunEffect
 *  \sa SDL_HapticStopEffect
 */
extern DECLSPEC int SDLCALL SDL_HapticGetEffectStatus(SDL_Haptic * haptic,
                                                      int effect);

/**
 *  \brief Sets the global gain of the device.
 *
 *  Device must support the ::SDL_HAPTIC_GAIN feature.
 *
 *  The user may specify the maximum gain by setting the environment variable
 *  SDL_HAPTIC_GAIN_MAX which should be between 0 and 100.  All calls to
 *  SDL_HapticSetGain() will scale linearly using SDL_HAPTIC_GAIN_MAX as the
 *  maximum.
 *
 *  \param haptic Haptic device to set the gain on.
 *  \param gain Value to set the gain to, should be between 0 and 100.
 *  \return 0 on success or -1 on error.
 *
 *  \sa SDL_HapticQuery
 */
extern DECLSPEC int SDLCALL SDL_HapticSetGain(SDL_Haptic * haptic, int gain);

/**
 *  \brief Sets the global autocenter of the device.
 *
 *  Autocenter should be between 0 and 100.  Setting it to 0 will disable
 *  autocentering.
 *
 *  Device must support the ::SDL_HAPTIC_AUTOCENTER feature.
 *
 *  \param haptic Haptic device to set autocentering on.
 *  \param autocenter Value to set autocenter to, 0 disables autocentering.
 *  \return 0 on success or -1 on error.
 *
 *  \sa SDL_HapticQuery
 */
extern DECLSPEC int SDLCALL SDL_HapticSetAutocenter(SDL_Haptic * haptic,
                                                    int autocenter);

/**
 *  \brief Pauses a haptic device.
 *
 *  Device must support the ::SDL_HAPTIC_PAUSE feature.  Call
 *  SDL_HapticUnpause() to resume playback.
 *
 *  Do not modify the effects nor add new ones while the device is paused.
 *  That can cause all sorts of weird errors.
 *
 *  \param haptic Haptic device to pause.
 *  \return 0 on success or -1 on error.
 *
 *  \sa SDL_HapticUnpause
 */
extern DECLSPEC int SDLCALL SDL_HapticPause(SDL_Haptic * haptic);

/**
 *  \brief Unpauses a haptic device.
 *
 *  Call to unpause after SDL_HapticPause().
 *
 *  \param haptic Haptic device to unpause.
 *  \return 0 on success or -1 on error.
 *
 *  \sa SDL_HapticPause
 */
extern DECLSPEC int SDLCALL SDL_HapticUnpause(SDL_Haptic * haptic);

/**
 *  \brief Stops all the currently playing effects on a haptic device.
 *
 *  \param haptic Haptic device to stop.
 *  \return 0 on success or -1 on error.
 */
extern DECLSPEC int SDLCALL SDL_HapticStopAll(SDL_Haptic * haptic);

/**
 *  \brief Checks to see if rumble is supported on a haptic device.
 *
 *  \param haptic Haptic device to check to see if it supports rumble.
 *  \return SDL_TRUE if effect is supported, SDL_FALSE if it isn't or -1 on error.
 *
 *  \sa SDL_HapticRumbleInit
 *  \sa SDL_HapticRumblePlay
 *  \sa SDL_HapticRumbleStop
 */
extern DECLSPEC int SDLCALL SDL_HapticRumbleSupported(SDL_Haptic * haptic);

/**
 *  \brief Initializes the haptic device for simple rumble playback.
 *
 *  \param haptic Haptic device to initialize for simple rumble playback.
 *  \return 0 on success or -1 on error.
 *
 *  \sa SDL_HapticOpen
 *  \sa SDL_HapticRumbleSupported
 *  \sa SDL_HapticRumblePlay
 *  \sa SDL_HapticRumbleStop
 */
extern DECLSPEC int SDLCALL SDL_HapticRumbleInit(SDL_Haptic * haptic);

/**
 *  \brief Runs simple rumble on a haptic device
 *
 *  \param haptic Haptic device to play rumble effect on.
 *  \param strength Strength of the rumble to play as a 0-1 float value.
 *  \param length Length of the rumble to play in milliseconds.
 *  \return 0 on success or -1 on error.
 *
 *  \sa SDL_HapticRumbleSupported
 *  \sa SDL_HapticRumbleInit
 *  \sa SDL_HapticRumbleStop
 */
extern DECLSPEC int SDLCALL SDL_HapticRumblePlay(SDL_Haptic * haptic, float strength, Uint32 length );

/**
 *  \brief Stops the simple rumble on a haptic device.
 *
 *  \param haptic Haptic to stop the rumble on.
 *  \return 0 on success or -1 on error.
 *
 *  \sa SDL_HapticRumbleSupported
 *  \sa SDL_HapticRumbleInit
 *  \sa SDL_HapticRumblePlay
 */
extern DECLSPEC int SDLCALL SDL_HapticRumbleStop(SDL_Haptic * haptic);

/* Ends C function definitions when using C++ */
#ifdef __cplusplus
}
#endif
#include "close_code.h"

#endif /* _SDL_haptic_h */

/* vi: set ts=4 sw=4 expandtab: */


.. currentmodule:: machine
.. _machine.TimerWiPy:

class TimerWiPy -- control hardware timers
==========================================

.. note::

    This class is a non-standard Timer implementation for the WiPy.
    It is available simply as ``machine.Timer`` on the WiPy but is named in the
    documentation below as ``machine.TimerWiPy`` to distinguish it from the
    more general :ref:`machine.Timer <machine.Timer>` class.

Hardware timers deal with timing of periods and events. Timers are perhaps
the most flexible and heterogeneous kind of hardware in MCUs and SoCs,
differently greatly from a model to a model. MicroPython's Timer class
defines a baseline operation of executing a callback with a given period
(or once after some delay), and allow specific boards to define more
non-standard behavior (which thus won't be portable to other boards).

See discussion of :ref:`important constraints <machine_callbacks>` on
Timer callbacks.

.. note::

    Memory can't be allocated inside irq handlers (an interrupt) and so
    exceptions raised within a handler don't give much information.  See
    :func:`micropython.alloc_emergency_exception_buf` for how to get around this
    limitation.

Constructors
------------

.. class:: TimerWiPy(id, ...)

   Construct a new timer object of the given id. Id of -1 constructs a
   virtual timer (if supported by a board).

Methods
-------

.. method:: TimerWiPy.init(mode, *, width=16)

   Initialise the timer. Example::

       tim.init(Timer.PERIODIC)             # periodic 16-bit timer
       tim.init(Timer.ONE_SHOT, width=32)   # one shot 32-bit timer

   Keyword arguments:

     - ``mode`` can be one of:

       - ``TimerWiPy.ONE_SHOT`` - The timer runs once until the configured
         period of the channel expires.
       - ``TimerWiPy.PERIODIC`` - The timer runs periodically at the configured
         frequency of the channel.
       - ``TimerWiPy.PWM``      - Output a PWM signal on a pin.

     - ``width`` must be either 16 or 32 (bits). For really low frequencies < 5Hz
       (or large periods), 32-bit timers should be used. 32-bit mode is only available
       for ``ONE_SHOT`` AND ``PERIODIC`` modes.

.. method:: TimerWiPy.deinit()

   Deinitialises the timer. Stops the timer, and disables the timer peripheral.

.. method:: TimerWiPy.channel(channel, **, freq, period, polarity=TimerWiPy.POSITIVE, duty_cycle=0)

   If only a channel identifier passed, then a previously initialized channel
   object is returned (or ``None`` if there is no previous channel).

   Otherwise, a TimerChannel object is initialized and returned.

   The operating mode is is the one configured to the Timer object that was used to
   create the channel.

   - ``channel`` if the width of the timer is 16-bit, then must be either ``TIMER.A``, ``TIMER.B``.
     If the width is 32-bit then it **must be** ``TIMER.A | TIMER.B``.

   Keyword only arguments:

     - ``freq`` sets the frequency in Hz.
     - ``period`` sets the period in microseconds.

     .. note::

        Either ``freq`` or ``period`` must be given, never both.

     - ``polarity`` this is applicable for ``PWM``, and defines the polarity of the duty cycle
     - ``duty_cycle`` only applicable to ``PWM``. It's a percentage (0.00-100.00). Since the WiPy
       doesn't support floating point numbers the duty cycle must be specified in the range 0-10000,
       where 10000 would represent 100.00, 5050 represents 50.50, and so on.

   .. note::

      When the channel is in PWM mode, the corresponding pin is assigned automatically, therefore
      there's no need to assign the alternate function of the pin via the ``Pin`` class. The pins which
      support PWM functionality are the following:

      - ``GP24`` on Timer 0 channel A.
      - ``GP25`` on Timer 1 channel A.
      - ``GP9``  on Timer 2 channel B.
      - ``GP10`` on Timer 3 channel A.
      - ``GP11`` on Timer 3 channel B.

class TimerChannel --- setup a channel for a timer
==================================================

Timer channels are used to generate/capture a signal using a timer.

TimerChannel objects are created using the Timer.channel() method.

Methods
-------

.. method:: timerchannel.irq(*, trigger, priority=1, handler=None)

    The behavior of this callback is heavily dependent on the operating
    mode of the timer channel:

        - If mode is ``TimerWiPy.PERIODIC`` the callback is executed periodically
          with the configured frequency or period.
        - If mode is ``TimerWiPy.ONE_SHOT`` the callback is executed once when
          the configured timer expires.
        - If mode is ``TimerWiPy.PWM`` the callback is executed when reaching the duty
          cycle value.

    The accepted params are:

        - ``priority`` level of the interrupt. Can take values in the range 1-7.
          Higher values represent higher priorities.
        - ``handler`` is an optional function to be called when the interrupt is triggered.
        - ``trigger`` must be ``TimerWiPy.TIMEOUT`` when the operating mode is either ``TimerWiPy.PERIODIC`` or
          ``TimerWiPy.ONE_SHOT``. In the case that mode is ``TimerWiPy.PWM`` then trigger must be equal to
          ``TimerWiPy.MATCH``.

    Returns a callback object.

.. method:: timerchannel.freq([value])

   Get or set the timer channel frequency (in Hz).

.. method:: timerchannel.period([value])

   Get or set the timer channel period (in microseconds).

.. method:: timerchannel.duty_cycle([value])

   Get or set the duty cycle of the PWM signal. It's a percentage (0.00-100.00). Since the WiPy
   doesn't support floating point numbers the duty cycle must be specified in the range 0-10000,
   where 10000 would represent 100.00, 5050 represents 50.50, and so on.

Constants
---------

.. data:: TimerWiPy.ONE_SHOT
.. data:: TimerWiPy.PERIODIC

   Timer operating mode.


> 作者：冬瓜

> 原文链接：[Guardia · 瓜地](https://desgard.com/SDWebImage1/)

# SDWebImage Source Probe: WebCache

最近两天，在完成工作业务之余，除了看书，自己也要开始深入的阅读经典的源码。来完善我的 [iOS 源码探求](https://desgard.com/iOS-Source-Probe/) 系列文章。

对源码的阅读是一个长久的学习过程，我会将业务中最常用的一些经典三方库拿出来进行学习。这一点我很敬佩 [@Draveness](http://draveness.me/) 的精神，并向他看齐。

## SDWebImage 简单介绍

[SDWebImage](https://github.com/rs/SDWebImage) 根据官方文档，其实就是提供了以下功能：

> Asynchronous image downloader with cache support with an UIImageView category.

一个异步下载图片并且带有 `UIImageView` Category 的缓存库。其好用的原因还在于其简介的接口。话不多说，开始主要内容。本系列文章使用的 SDWebImage 版本为 `v3.8.1`。

## 多重入口委托构造器

在使用 SD 库的时候，最常调用的方法如下：

```c
[self.imageView sd_setImageWithURL:[NSURL URLWithString:@"url"]
				placeholderImage:[UIImage imageNamed:@"placeholder.png"]];
```

由此，对 `UIImageView` 的图片一部加载完成了。进入到该方法内部，在其 `.h` 的文件中看到以下接口：

```c
- (void)sd_setImageWithURL:(NSURL *)url;
- (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder;
- (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options;
...
- (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletionBlock)completedBlock;
```

作为 SD 的入口函数，在 sd_setImageWithURL 方法中采用了多种参数灵活搭配的同名方法。而内部实质，都在向最后一个 sd_setImageWithURL 传入参数最多的方法进行调用处理。

在 c++ 0x 中，这种方式被广泛的使用在系统库的 class 中作为类的委托构造器（Delegate Constructor）。这样做的好处是，**可以清晰的梳理函数构造逻辑，减轻代码编写量**。

## setImageWithURL 处理流程

```c
// 委托构造器最高级入口
- (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletionBlock)completedBlock {
	// 【要点 1】取消该 UIImageView 的下载队列
    [self sd_cancelCurrentImageLoad];

    // 【要点 2】对应的 UIImageView 增加一个对应的 url 属性
    objc_setAssociatedObject(self, &imageURLKey, url, OBJC_ASSOCIATION_RETAIN_NONATOMIC);

	// 根据参数条件，是一个 optional 执行块
	// 在未发送请求过去网络图片之前，增加 placeHolder
	// 如果有 delay 延迟标记
    if (!(options & SDWebImageDelayPlaceholder)) {
    	// 创建主线程异步队列来更新 UI
        dispatch_main_async_safe(^{
            self.image = placeholder;
        });
    }

    // 判断 url 是否为空
    if (url) {
        // 是否展示 ActivityIndicator
        if ([self showActivityIndicatorView]) {
            [self addActivityIndicator];
        }
		// 防止 block 的 retain cycle，进行弱引用转换
        __weak __typeof(self)wself = self;
        // 使用图片 download 方法，并完成 callback 回调
        id <SDWebImageOperation> operation = [SDWebImageManager.sharedManager downloadImageWithURL:url options:options progress:progressBlock completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
	        // 停止 ActivityIndicator 转动
            [wself removeActivityIndicator];
            if (!wself) return;
            dispatch_main_sync_safe(^{
                if (!wself) return;
                // 图片是否使用了默认参数
                if (image && (options & SDWebImageAvoidAutoSetImage) && completedBlock)
                {
                	// 【要点 3】对 download 中的 completedBlock 成员传参
                    completedBlock(image, error, cacheType, url);
                    return;
                }
                else if (image) {
                	// 更新图片，需要重新进行 layout 布局，主动调用 setNeedsLayout 方法
                    wself.image = image;
                    [wself setNeedsLayout];
                } else {
                    if ((options & SDWebImageDelayPlaceholder)) {
                        wself.image = placeholder;
                        [wself setNeedsLayout];
                    }
                }
                // 判断 finished 标记，传入 block 方法参数
                if (completedBlock && finished) {
                    completedBlock(image, error, cacheType, url);
                }
            });
        }];
        // 将上面的 operation 添加到字典中，key 为 UIImageViewImageLoad
        [self sd_setImageLoadOperation:operation forKey:@"UIImageViewImageLoad"];
    } else {
    	// 处理 url 为 nil 的状态
    	// 保证在主线程中处理，因为涉及到 UI
        dispatch_main_async_safe(^{
            [self removeActivityIndicator];
            if (completedBlock) {
                NSError *error = [NSError errorWithDomain:SDWebImageErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey : @"Trying to load a nil url"}];
                completedBlock(nil, error, SDImageCacheTypeNone, url);
            }
        });
    }
}
```

下面来看深入看一下上述代码注释中的 3 个要点。

* [self sd_cancelCurrentImageLoad]

进入函数内层是以下代码：

```c
- (void)sd_cancelCurrentImageLoad {
	// 通过 key 来取消操作
    [self sd_cancelImageLoadOperationWithKey:@"UIImageViewImageLoad"];
}
```

```c
// UIView+WebCacheOperation.m

- (void)sd_cancelImageLoadOperationWithKey:(NSString *)key {
    // Cancel in progress downloader from queue
    // 取消正在下载的队列
    NSMutableDictionary *operationDictionary = [self operationDictionary];
    id operations = [operationDictionary objectForKey:key];
    // 如果 operationDictionary 可以取到 key，则可以得到与该视图相关的操作
    // 并根据 key 从字典中取消这些操作
    if (operations) {
    	// 检查 operations 是否为 array ，防止重名
        if ([operations isKindOfClass:[NSArray class]]) {
        	// 比那里当中所有遵循给定代理的对象，对其下载任务进行取消
            for (id <SDWebImageOperation> operation in operations) {
                if (operation) {
                    [operation cancel];
                }
            }
        // 如果不是集合，那么可能是一个下载对象
        } else if ([operations conformsToProtocol:@protocol(SDWebImageOperation)]){
            [(id<SDWebImageOperation>) operations cancel];
        }
        // 所有元素已过滤，删除 key
        [operationDictionary removeObjectForKey:key];
    }
}
```

从代码中，可以看出：SD 使用 `NSDictionary` 来管理满足 `SDWebImageOperation` 代理的实例。通过对代理实例的判断，以及使用键值查询 operation 的方式，SD 可以有效、迅速的管理所有下载任务。

* objc_setAssociatedObject(self, &imageURLKey, url, OBJC_ASSOCIATION_RETAIN_NONATOMIC);

这里是使用关联对象（Associated Object）（如果这里陌生，可以查阅 *[浅谈Associated Objects](https://desgard.com/Associated-Objects/)* 这篇博文），来对 UIImageView 做了一个关联值。在第二个参数上，一般是关联对象的唯一标记，在 *UIImageView_WebCache.m* 中使用了一个静态量地址来作为这个 key。

```c
static char imageURLKey;
```

增加这个 url 属性便于在其他地方迅速访问。在获取时候，只需要调用 `- (NSURL *)sd_imageURL` 便可以直接通过关联对象迅速查询。这个 url 的访问在其他地方会有多次调用。

* completedBlock(image, error, cacheType, url);

默认情况下，SD 会等 image 完全从网络下载完成之后，直接替换 UIImageView 中的 image 。如果想在获取图片之后，手动处理之后的所有事情，则需要设置此方法。

这个方法是将会在 `SDWebImageManager.h` 出现。

## setAnimationImagesWithURLs 图片组

在这个 Category 中，还有对于动画组图的设置。观看源码可知，这个方法在实现上是将多个图片的 URL 打包成 array，传入 `sd_setImageLoadOperation` 方法来增加图片加载的 Operation 。而在打包中，相当于多次执行了 `sd_setImageWithURL` （其中的处理细节是一样的）。唯一不同的是，`setAnimationImagesWithURLs` 没有去设置关联对象。因为在展示中，我不需要对其做任何的控制，所以也就没有提供访问的快捷方法。

## UIImageView+WebCache.m 源码解读总结

对于常用的 `setImageWithURL` 方法，可以总结成以下流程：

![UIImageView+WebCache](http://7xwh85.com1.z0.glb.clouddn.com/UIImageView+WebCache.png)

从最常用的 `setImageWithURL` 可以看出，其实 SDWebImage 的逻辑很清晰，其源码阅读起来可读性也很高。

在阅读三方库源码的同时，也可以感受到作者的代码经验所在。如同委托构造的方式，也是经验的积累总结。所以在学习代码的同时，也可以学习编码思想。

## 延伸阅读

[cocoadocs SDWebImage](http://cocoadocs.org/docsets/SDWebImage/3.7.0/Categories/UIImageView+WebCache.html#//api/name/sd_setAnimationImagesWithURLs:)

[iOS 源代码分析----SDWebImage](http://draveness.me/ios-yuan-dai-ma-jie-xi-sdwebimage/)

> 若想查看更多的iOS Source Probe文章，收录在这个[Github仓库中](https://github.com/Desgard/iOS-Source-Probe)。


// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build !gccgo

#include "textflag.h"

//
// System call support for AMD64, DragonFly
//

// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.

TEXT	·Syscall(SB),NOSPLIT,$0-56
	JMP	syscall·Syscall(SB)

TEXT	·Syscall6(SB),NOSPLIT,$0-80
	JMP	syscall·Syscall6(SB)

TEXT	·Syscall9(SB),NOSPLIT,$0-104
	JMP	syscall·Syscall9(SB)

TEXT ·RawSyscall(SB),NOSPLIT,$0-56
	JMP	syscall·RawSyscall(SB)

TEXT	·RawSyscall6(SB),NOSPLIT,$0-80
	JMP	syscall·RawSyscall6(SB)


{
  "./helper.swift": {
    "object": "./helper.o",
    "swift-dependencies": "./helper.swiftdeps",
  },
  "./main.swift": {
    "object": "./main.o",
    "swift-dependencies": "./main.swiftdeps",
  },
  "": {
    "swift-dependencies": "./main~buildrecord.swiftdeps"
  }
}


%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!126 &1
NavMeshProjectSettings:
  m_ObjectHideFlags: 0
  serializedVersion: 2
  areas:
  - name: Walkable
    cost: 1
  - name: Not Walkable
    cost: 1
  - name: Jump
    cost: 2
  - name:
    cost: 1
  - name:
    cost: 1
  - name:
    cost: 1
  - name:
    cost: 1
  - name:
    cost: 1
  - name:
    cost: 1
  - name:
    cost: 1
  - name:
    cost: 1
  - name:
    cost: 1
  - name:
    cost: 1
  - name:
    cost: 1
  - name:
    cost: 1
  - name:
    cost: 1
  - name:
    cost: 1
  - name:
    cost: 1
  - name:
    cost: 1
  - name:
    cost: 1
  - name:
    cost: 1
  - name:
    cost: 1
  - name:
    cost: 1
  - name:
    cost: 1
  - name:
    cost: 1
  - name:
    cost: 1
  - name:
    cost: 1
  - name:
    cost: 1
  - name:
    cost: 1
  - name:
    cost: 1
  - name:
    cost: 1
  - name:
    cost: 1
  m_LastAgentTypeID: -887442657
  m_Settings:
  - serializedVersion: 2
    agentTypeID: 0
    agentRadius: 0.5
    agentHeight: 2
    agentSlope: 45
    agentClimb: 0.75
    ledgeDropHeight: 0
    maxJumpAcrossDistance: 0
    minRegionArea: 2
    manualCellSize: 0
    cellSize: 0.16666667
    manualTileSize: 0
    tileSize: 256
    accuratePlacement: 0
    debug:
      m_Flags: 0
  m_SettingNames:
  - Humanoid


#include "io.h"

int main(void)
{
    long long rt, rs, dsp;
    long long achi, acli;
    long long acho, aclo;
    long long resulth, resultl;

    achi = 0x05;
    acli = 0xB4CB;
    rs  = 0x98765432FF060000;
    rt  = 0xfdeca987CB000000;
    resulth = 0x05;
    resultl = 0x18278587;

    __asm
        ("mthi %2, $ac1\n\t"
         "mtlo %3, $ac1\n\t"
         "maq_s.l.pwl $ac1, %4, %5\n\t"
         "mfhi %0, $ac1\n\t"
         "mflo %1, $ac1\n\t"
         : "=r"(acho), "=r"(aclo)
         : "r"(achi), "r"(acli), "r"(rs), "r"(rt)
        );
    if ((resulth != acho) || (resultl != aclo)) {
        printf("maq_s_l.w.pwl wrong 1\n");

        return -1;
    }

    achi = 0x05;
    acli = 0xB4CB;
    rs  = 0x80000000FF060000;
    rt  = 0x80000000CB000000;
    resulth = 0x05;
    resultl = 0xb4ca;

    __asm
        ("mthi %3, $ac1\n\t"
         "mtlo %4, $ac1\n\t"
         "maq_s.l.pwl $ac1, %5, %6\n\t"
         "mfhi %0, $ac1\n\t"
         "mflo %1, $ac1\n\t"
         "rddsp %2\n\t"
         : "=r"(acho), "=r"(aclo), "=r"(dsp)
         : "r"(achi), "r"(acli), "r"(rs), "r"(rt)
        );
    dsp = (dsp >> 17) & 0x1;
    if ((dsp != 0x1) || (resulth != acho) || (resultl != aclo)) {
        printf("maq_s_l.w.pwl wrong 2\n");

        return -1;
    }
    return 0;
}


A1	A2	N	SNP	Z
A	G	10000.000	rs0	0.449
A	G	10000.000	rs1	-3.962
A	G	10000.000	rs2	-1.240
A	G	10000.000	rs3	-0.423
A	G	10000.000	rs4	-3.259
A	G	10000.000	rs5	2.938
A	G	10000.000	rs6	-1.675
A	G	10000.000	rs7	3.328
A	G	10000.000	rs8	1.069
A	G	10000.000	rs9	-0.457
A	G	10000.000	rs10	-3.069
A	G	10000.000	rs11	0.120
A	G	10000.000	rs12	1.102
A	G	10000.000	rs13	2.774
A	G	10000.000	rs14	1.614
A	G	10000.000	rs15	-2.951
A	G	10000.000	rs16	4.083
A	G	10000.000	rs17	-1.918
A	G	10000.000	rs18	1.884
A	G	10000.000	rs19	2.867
A	G	10000.000	rs20	-4.546
A	G	10000.000	rs21	-2.374
A	G	10000.000	rs22	0.578
A	G	10000.000	rs23	4.832
A	G	10000.000	rs24	1.908
A	G	10000.000	rs25	2.612
A	G	10000.000	rs26	-1.877
A	G	10000.000	rs27	-1.398
A	G	10000.000	rs28	3.190
A	G	10000.000	rs29	-2.898
A	G	10000.000	rs30	3.001
A	G	10000.000	rs31	2.153
A	G	10000.000	rs32	1.998
A	G	10000.000	rs33	-8.787
A	G	10000.000	rs34	6.704
A	G	10000.000	rs35	2.742
A	G	10000.000	rs36	-5.605
A	G	10000.000	rs37	2.166
A	G	10000.000	rs38	1.881
A	G	10000.000	rs39	0.013
A	G	10000.000	rs40	-1.480
A	G	10000.000	rs41	2.893
A	G	10000.000	rs42	3.738
A	G	10000.000	rs43	-1.380
A	G	10000.000	rs44	-0.898
A	G	10000.000	rs45	2.194
A	G	10000.000	rs46	1.612
A	G	10000.000	rs47	1.117
A	G	10000.000	rs48	0.996
A	G	10000.000	rs49	-0.716
A	G	10000.000	rs50	2.434
A	G	10000.000	rs51	-1.948
A	G	10000.000	rs52	3.642
A	G	10000.000	rs53	-9.236
A	G	10000.000	rs54	3.359
A	G	10000.000	rs55	-1.131
A	G	10000.000	rs56	2.645
A	G	10000.000	rs57	-5.134
A	G	10000.000	rs58	-2.006
A	G	10000.000	rs59	-1.177
A	G	10000.000	rs60	-2.424
A	G	10000.000	rs61	-2.765
A	G	10000.000	rs62	-3.452
A	G	10000.000	rs63	5.309
A	G	10000.000	rs64	-0.247
A	G	10000.000	rs65	-0.543
A	G	10000.000	rs66	-4.371
A	G	10000.000	rs67	-6.097
A	G	10000.000	rs68	-0.983
A	G	10000.000	rs69	5.844
A	G	10000.000	rs70	-4.353
A	G	10000.000	rs71	-7.367
A	G	10000.000	rs72	7.265
A	G	10000.000	rs73	3.749
A	G	10000.000	rs74	1.594
A	G	10000.000	rs75	-5.275
A	G	10000.000	rs76	4.543
A	G	10000.000	rs77	3.457
A	G	10000.000	rs78	-5.072
A	G	10000.000	rs79	-3.635
A	G	10000.000	rs80	-1.328
A	G	10000.000	rs81	5.566
A	G	10000.000	rs82	0.746
A	G	10000.000	rs83	-1.103
A	G	10000.000	rs84	0.538
A	G	10000.000	rs85	-3.040
A	G	10000.000	rs86	-0.455
A	G	10000.000	rs87	-1.040
A	G	10000.000	rs88	0.664
A	G	10000.000	rs89	0.609
A	G	10000.000	rs90	4.351
A	G	10000.000	rs91	2.413
A	G	10000.000	rs92	-2.624
A	G	10000.000	rs93	0.269
A	G	10000.000	rs94	2.505
A	G	10000.000	rs95	-0.159
A	G	10000.000	rs96	3.645
A	G	10000.000	rs97	-4.898
A	G	10000.000	rs98	-0.391
A	G	10000.000	rs99	1.240
A	G	10000.000	rs100	0.453
A	G	10000.000	rs101	-1.640
A	G	10000.000	rs102	0.884
A	G	10000.000	rs103	3.761
A	G	10000.000	rs104	-2.736
A	G	10000.000	rs105	0.074
A	G	10000.000	rs106	-5.103
A	G	10000.000	rs107	1.814
A	G	10000.000	rs108	0.733
A	G	10000.000	rs109	-4.117
A	G	10000.000	rs110	1.714
A	G	10000.000	rs111	0.189
A	G	10000.000	rs112	1.806
A	G	10000.000	rs113	-0.023
A	G	10000.000	rs114	3.580
A	G	10000.000	rs115	-0.768
A	G	10000.000	rs116	-0.450
A	G	10000.000	rs117	3.013
A	G	10000.000	rs118	-5.167
A	G	10000.000	rs119	-3.345
A	G	10000.000	rs120	0.137
A	G	10000.000	rs121	-2.033
A	G	10000.000	rs122	-2.890
A	G	10000.000	rs123	-0.210
A	G	10000.000	rs124	6.660
A	G	10000.000	rs125	4.717
A	G	10000.000	rs126	2.214
A	G	10000.000	rs127	-5.218
A	G	10000.000	rs128	0.323
A	G	10000.000	rs129	1.349
A	G	10000.000	rs130	1.031
A	G	10000.000	rs131	-1.523
A	G	10000.000	rs132	2.139
A	G	10000.000	rs133	-9.665
A	G	10000.000	rs134	1.262
A	G	10000.000	rs135	5.738
A	G	10000.000	rs136	7.826
A	G	10000.000	rs137	0.619
A	G	10000.000	rs138	1.947
A	G	10000.000	rs139	-1.976
A	G	10000.000	rs140	1.311
A	G	10000.000	rs141	-1.719
A	G	10000.000	rs142	-0.389
A	G	10000.000	rs143	0.079
A	G	10000.000	rs144	-0.063
A	G	10000.000	rs145	-3.531
A	G	10000.000	rs146	-1.691
A	G	10000.000	rs147	-0.638
A	G	10000.000	rs148	-5.165
A	G	10000.000	rs149	-1.436
A	G	10000.000	rs150	-2.267
A	G	10000.000	rs151	-1.606
A	G	10000.000	rs152	4.035
A	G	10000.000	rs153	7.292
A	G	10000.000	rs154	-3.520
A	G	10000.000	rs155	3.549
A	G	10000.000	rs156	5.795
A	G	10000.000	rs157	-0.045
A	G	10000.000	rs158	-0.251
A	G	10000.000	rs159	0.041
A	G	10000.000	rs160	2.157
A	G	10000.000	rs161	-0.606
A	G	10000.000	rs162	1.143
A	G	10000.000	rs163	2.416
A	G	10000.000	rs164	-4.134
A	G	10000.000	rs165	-1.855
A	G	10000.000	rs166	3.592
A	G	10000.000	rs167	4.276
A	G	10000.000	rs168	1.415
A	G	10000.000	rs169	0.348
A	G	10000.000	rs170	-2.237
A	G	10000.000	rs171	3.613
A	G	10000.000	rs172	-0.907
A	G	10000.000	rs173	2.924
A	G	10000.000	rs174	0.207
A	G	10000.000	rs175	0.102
A	G	10000.000	rs176	-3.607
A	G	10000.000	rs177	-2.408
A	G	10000.000	rs178	-0.374
A	G	10000.000	rs179	-2.534
A	G	10000.000	rs180	-4.297
A	G	10000.000	rs181	5.350
A	G	10000.000	rs182	-0.490
A	G	10000.000	rs183	-3.228
A	G	10000.000	rs184	-8.929
A	G	10000.000	rs185	2.900
A	G	10000.000	rs186	-2.732
A	G	10000.000	rs187	4.859
A	G	10000.000	rs188	2.881
A	G	10000.000	rs189	-4.348
A	G	10000.000	rs190	1.754
A	G	10000.000	rs191	0.309
A	G	10000.000	rs192	5.039
A	G	10000.000	rs193	2.705
A	G	10000.000	rs194	-0.695
A	G	10000.000	rs195	1.150
A	G	10000.000	rs196	3.941
A	G	10000.000	rs197	-0.173
A	G	10000.000	rs198	3.899
A	G	10000.000	rs199	-4.992
A	G	10000.000	rs200	2.047
A	G	10000.000	rs201	-7.055
A	G	10000.000	rs202	0.813
A	G	10000.000	rs203	-2.715
A	G	10000.000	rs204	0.555
A	G	10000.000	rs205	-1.941
A	G	10000.000	rs206	-0.871
A	G	10000.000	rs207	2.362
A	G	10000.000	rs208	0.065
A	G	10000.000	rs209	6.314
A	G	10000.000	rs210	-0.608
A	G	10000.000	rs211	3.534
A	G	10000.000	rs212	10.828
A	G	10000.000	rs213	0.502
A	G	10000.000	rs214	3.862
A	G	10000.000	rs215	-1.340
A	G	10000.000	rs216	2.503
A	G	10000.000	rs217	-0.375
A	G	10000.000	rs218	-3.270
A	G	10000.000	rs219	-0.783
A	G	10000.000	rs220	1.113
A	G	10000.000	rs221	-3.673
A	G	10000.000	rs222	7.549
A	G	10000.000	rs223	-0.350
A	G	10000.000	rs224	6.960
A	G	10000.000	rs225	-1.802
A	G	10000.000	rs226	-3.597
A	G	10000.000	rs227	1.693
A	G	10000.000	rs228	3.098
A	G	10000.000	rs229	-6.646
A	G	10000.000	rs230	-6.884
A	G	10000.000	rs231	1.913
A	G	10000.000	rs232	-3.995
A	G	10000.000	rs233	-3.464
A	G	10000.000	rs234	-2.024
A	G	10000.000	rs235	-10.056
A	G	10000.000	rs236	0.091
A	G	10000.000	rs237	3.048
A	G	10000.000	rs238	3.196
A	G	10000.000	rs239	-4.254
A	G	10000.000	rs240	0.377
A	G	10000.000	rs241	2.616
A	G	10000.000	rs242	5.779
A	G	10000.000	rs243	-10.003
A	G	10000.000	rs244	-0.963
A	G	10000.000	rs245	2.598
A	G	10000.000	rs246	2.795
A	G	10000.000	rs247	-0.386
A	G	10000.000	rs248	0.672
A	G	10000.000	rs249	0.662
A	G	10000.000	rs250	-4.312
A	G	10000.000	rs251	-0.245
A	G	10000.000	rs252	-4.506
A	G	10000.000	rs253	-0.570
A	G	10000.000	rs254	6.495
A	G	10000.000	rs255	3.789
A	G	10000.000	rs256	-1.958
A	G	10000.000	rs257	-3.887
A	G	10000.000	rs258	7.471
A	G	10000.000	rs259	1.162
A	G	10000.000	rs260	-3.429
A	G	10000.000	rs261	-2.242
A	G	10000.000	rs262	2.023
A	G	10000.000	rs263	-2.511
A	G	10000.000	rs264	-2.952
A	G	10000.000	rs265	0.684
A	G	10000.000	rs266	1.172
A	G	10000.000	rs267	-2.698
A	G	10000.000	rs268	-0.530
A	G	10000.000	rs269	-4.553
A	G	10000.000	rs270	1.136
A	G	10000.000	rs271	3.214
A	G	10000.000	rs272	-3.184
A	G	10000.000	rs273	3.916
A	G	10000.000	rs274	0.367
A	G	10000.000	rs275	1.905
A	G	10000.000	rs276	2.711
A	G	10000.000	rs277	-3.008
A	G	10000.000	rs278	-2.552
A	G	10000.000	rs279	5.696
A	G	10000.000	rs280	0.962
A	G	10000.000	rs281	-3.774
A	G	10000.000	rs282	-0.130
A	G	10000.000	rs283	-1.685
A	G	10000.000	rs284	5.398
A	G	10000.000	rs285	2.552
A	G	10000.000	rs286	7.235
A	G	10000.000	rs287	1.053
A	G	10000.000	rs288	-0.458
A	G	10000.000	rs289	-4.346
A	G	10000.000	rs290	2.542
A	G	10000.000	rs291	-1.083
A	G	10000.000	rs292	0.037
A	G	10000.000	rs293	-1.565
A	G	10000.000	rs294	-1.016
A	G	10000.000	rs295	1.643
A	G	10000.000	rs296	4.865
A	G	10000.000	rs297	-2.141
A	G	10000.000	rs298	-2.884
A	G	10000.000	rs299	2.346
A	G	10000.000	rs300	2.135
A	G	10000.000	rs301	3.596
A	G	10000.000	rs302	3.724
A	G	10000.000	rs303	-0.678
A	G	10000.000	rs304	-7.942
A	G	10000.000	rs305	1.146
A	G	10000.000	rs306	-6.038
A	G	10000.000	rs307	0.079
A	G	10000.000	rs308	5.350
A	G	10000.000	rs309	7.536
A	G	10000.000	rs310	1.486
A	G	10000.000	rs311	3.880
A	G	10000.000	rs312	-0.991
A	G	10000.000	rs313	2.092
A	G	10000.000	rs314	3.242
A	G	10000.000	rs315	-1.028
A	G	10000.000	rs316	-0.765
A	G	10000.000	rs317	-0.402
A	G	10000.000	rs318	3.918
A	G	10000.000	rs319	-2.734
A	G	10000.000	rs320	-1.471
A	G	10000.000	rs321	2.379
A	G	10000.000	rs322	-1.969
A	G	10000.000	rs323	-6.698
A	G	10000.000	rs324	1.511
A	G	10000.000	rs325	0.134
A	G	10000.000	rs326	-6.795
A	G	10000.000	rs327	1.187
A	G	10000.000	rs328	-2.557
A	G	10000.000	rs329	1.368
A	G	10000.000	rs330	3.389
A	G	10000.000	rs331	2.093
A	G	10000.000	rs332	2.007
A	G	10000.000	rs333	2.264
A	G	10000.000	rs334	-1.756
A	G	10000.000	rs335	1.678
A	G	10000.000	rs336	1.081
A	G	10000.000	rs337	2.000
A	G	10000.000	rs338	2.513
A	G	10000.000	rs339	1.159
A	G	10000.000	rs340	-4.528
A	G	10000.000	rs341	-3.771
A	G	10000.000	rs342	-1.523
A	G	10000.000	rs343	-1.102
A	G	10000.000	rs344	1.641
A	G	10000.000	rs345	4.552
A	G	10000.000	rs346	0.950
A	G	10000.000	rs347	-0.084
A	G	10000.000	rs348	-2.350
A	G	10000.000	rs349	-3.067
A	G	10000.000	rs350	-3.363
A	G	10000.000	rs351	-1.070
A	G	10000.000	rs352	2.500
A	G	10000.000	rs353	2.589
A	G	10000.000	rs354	4.289
A	G	10000.000	rs355	-0.599
A	G	10000.000	rs356	1.786
A	G	10000.000	rs357	-0.416
A	G	10000.000	rs358	1.010
A	G	10000.000	rs359	-0.454
A	G	10000.000	rs360	0.666
A	G	10000.000	rs361	0.200
A	G	10000.000	rs362	2.091
A	G	10000.000	rs363	4.273
A	G	10000.000	rs364	-3.686
A	G	10000.000	rs365	5.913
A	G	10000.000	rs366	3.490
A	G	10000.000	rs367	0.576
A	G	10000.000	rs368	-2.507
A	G	10000.000	rs369	-5.401
A	G	10000.000	rs370	2.003
A	G	10000.000	rs371	2.366
A	G	10000.000	rs372	-0.397
A	G	10000.000	rs373	1.948
A	G	10000.000	rs374	0.264
A	G	10000.000	rs375	0.038
A	G	10000.000	rs376	1.632
A	G	10000.000	rs377	1.622
A	G	10000.000	rs378	0.068
A	G	10000.000	rs379	2.299
A	G	10000.000	rs380	1.203
A	G	10000.000	rs381	-6.113
A	G	10000.000	rs382	0.493
A	G	10000.000	rs383	3.143
A	G	10000.000	rs384	-0.579
A	G	10000.000	rs385	-4.558
A	G	10000.000	rs386	-0.057
A	G	10000.000	rs387	-0.506
A	G	10000.000	rs388	-4.587
A	G	10000.000	rs389	2.791
A	G	10000.000	rs390	8.187
A	G	10000.000	rs391	6.538
A	G	10000.000	rs392	0.812
A	G	10000.000	rs393	0.074
A	G	10000.000	rs394	-0.008
A	G	10000.000	rs395	4.556
A	G	10000.000	rs396	-0.836
A	G	10000.000	rs397	2.894
A	G	10000.000	rs398	0.513
A	G	10000.000	rs399	-4.194
A	G	10000.000	rs400	-1.475
A	G	10000.000	rs401	-2.765
A	G	10000.000	rs402	-2.457
A	G	10000.000	rs403	-0.174
A	G	10000.000	rs404	1.525
A	G	10000.000	rs405	-2.415
A	G	10000.000	rs406	4.043
A	G	10000.000	rs407	-3.582
A	G	10000.000	rs408	-0.849
A	G	10000.000	rs409	-0.061
A	G	10000.000	rs410	6.675
A	G	10000.000	rs411	-0.475
A	G	10000.000	rs412	-0.760
A	G	10000.000	rs413	-2.322
A	G	10000.000	rs414	-3.356
A	G	10000.000	rs415	-4.102
A	G	10000.000	rs416	-2.299
A	G	10000.000	rs417	-2.556
A	G	10000.000	rs418	0.024
A	G	10000.000	rs419	1.136
A	G	10000.000	rs420	-0.515
A	G	10000.000	rs421	-0.320
A	G	10000.000	rs422	-6.435
A	G	10000.000	rs423	2.825
A	G	10000.000	rs424	-1.673
A	G	10000.000	rs425	1.506
A	G	10000.000	rs426	-1.416
A	G	10000.000	rs427	-1.720
A	G	10000.000	rs428	-1.274
A	G	10000.000	rs429	1.659
A	G	10000.000	rs430	-0.228
A	G	10000.000	rs431	-5.499
A	G	10000.000	rs432	0.091
A	G	10000.000	rs433	1.437
A	G	10000.000	rs434	-0.999
A	G	10000.000	rs435	0.919
A	G	10000.000	rs436	-2.275
A	G	10000.000	rs437	1.463
A	G	10000.000	rs438	-0.647
A	G	10000.000	rs439	4.504
A	G	10000.000	rs440	-3.875
A	G	10000.000	rs441	-0.604
A	G	10000.000	rs442	-0.638
A	G	10000.000	rs443	-0.366
A	G	10000.000	rs444	4.646
A	G	10000.000	rs445	-3.431
A	G	10000.000	rs446	-0.735
A	G	10000.000	rs447	-4.228
A	G	10000.000	rs448	-0.413
A	G	10000.000	rs449	-1.351
A	G	10000.000	rs450	-1.653
A	G	10000.000	rs451	-3.842
A	G	10000.000	rs452	-1.204
A	G	10000.000	rs453	-2.318
A	G	10000.000	rs454	4.889
A	G	10000.000	rs455	1.836
A	G	10000.000	rs456	-2.730
A	G	10000.000	rs457	1.457
A	G	10000.000	rs458	-2.808
A	G	10000.000	rs459	1.225
A	G	10000.000	rs460	-3.678
A	G	10000.000	rs461	3.222
A	G	10000.000	rs462	1.364
A	G	10000.000	rs463	2.115
A	G	10000.000	rs464	0.269
A	G	10000.000	rs465	-3.741
A	G	10000.000	rs466	2.152
A	G	10000.000	rs467	4.087
A	G	10000.000	rs468	3.437
A	G	10000.000	rs469	-0.351
A	G	10000.000	rs470	4.452
A	G	10000.000	rs471	3.582
A	G	10000.000	rs472	1.545
A	G	10000.000	rs473	1.294
A	G	10000.000	rs474	-0.654
A	G	10000.000	rs475	-2.625
A	G	10000.000	rs476	1.086
A	G	10000.000	rs477	0.399
A	G	10000.000	rs478	-0.130
A	G	10000.000	rs479	0.357
A	G	10000.000	rs480	-3.418
A	G	10000.000	rs481	1.159
A	G	10000.000	rs482	-0.139
A	G	10000.000	rs483	-5.066
A	G	10000.000	rs484	-1.904
A	G	10000.000	rs485	1.060
A	G	10000.000	rs486	0.561
A	G	10000.000	rs487	-3.104
A	G	10000.000	rs488	-1.781
A	G	10000.000	rs489	2.749
A	G	10000.000	rs490	0.101
A	G	10000.000	rs491	-2.657
A	G	10000.000	rs492	3.191
A	G	10000.000	rs493	1.389
A	G	10000.000	rs494	-0.175
A	G	10000.000	rs495	2.119
A	G	10000.000	rs496	-3.827
A	G	10000.000	rs497	0.902
A	G	10000.000	rs498	-3.922
A	G	10000.000	rs499	2.260
A	G	10000.000	rs500	9.734
A	G	10000.000	rs501	-0.086
A	G	10000.000	rs502	0.952
A	G	10000.000	rs503	2.020
A	G	10000.000	rs504	7.402
A	G	10000.000	rs505	-2.363
A	G	10000.000	rs506	-0.148
A	G	10000.000	rs507	0.227
A	G	10000.000	rs508	2.028
A	G	10000.000	rs509	-0.503
A	G	10000.000	rs510	2.220
A	G	10000.000	rs511	2.837
A	G	10000.000	rs512	-2.687
A	G	10000.000	rs513	-0.877
A	G	10000.000	rs514	0.562
A	G	10000.000	rs515	-0.215
A	G	10000.000	rs516	-2.977
A	G	10000.000	rs517	2.044
A	G	10000.000	rs518	0.195
A	G	10000.000	rs519	1.570
A	G	10000.000	rs520	2.073
A	G	10000.000	rs521	4.954
A	G	10000.000	rs522	0.416
A	G	10000.000	rs523	-4.578
A	G	10000.000	rs524	-0.954
A	G	10000.000	rs525	3.244
A	G	10000.000	rs526	-1.121
A	G	10000.000	rs527	0.688
A	G	10000.000	rs528	6.014
A	G	10000.000	rs529	0.170
A	G	10000.000	rs530	-3.360
A	G	10000.000	rs531	-2.016
A	G	10000.000	rs532	1.815
A	G	10000.000	rs533	-3.930
A	G	10000.000	rs534	9.994
A	G	10000.000	rs535	1.543
A	G	10000.000	rs536	-1.345
A	G	10000.000	rs537	8.525
A	G	10000.000	rs538	1.820
A	G	10000.000	rs539	-2.465
A	G	10000.000	rs540	-1.560
A	G	10000.000	rs541	-0.610
A	G	10000.000	rs542	-4.070
A	G	10000.000	rs543	2.987
A	G	10000.000	rs544	-0.968
A	G	10000.000	rs545	-0.544
A	G	10000.000	rs546	1.537
A	G	10000.000	rs547	1.172
A	G	10000.000	rs548	2.785
A	G	10000.000	rs549	1.487
A	G	10000.000	rs550	-0.765
A	G	10000.000	rs551	0.795
A	G	10000.000	rs552	-4.969
A	G	10000.000	rs553	-1.117
A	G	10000.000	rs554	1.529
A	G	10000.000	rs555	3.915
A	G	10000.000	rs556	-0.767
A	G	10000.000	rs557	-1.999
A	G	10000.000	rs558	-0.950
A	G	10000.000	rs559	-1.916
A	G	10000.000	rs560	0.769
A	G	10000.000	rs561	2.359
A	G	10000.000	rs562	3.061
A	G	10000.000	rs563	0.612
A	G	10000.000	rs564	1.084
A	G	10000.000	rs565	4.466
A	G	10000.000	rs566	2.830
A	G	10000.000	rs567	4.310
A	G	10000.000	rs568	-1.465
A	G	10000.000	rs569	0.982
A	G	10000.000	rs570	11.950
A	G	10000.000	rs571	1.584
A	G	10000.000	rs572	-2.145
A	G	10000.000	rs573	4.249
A	G	10000.000	rs574	-3.859
A	G	10000.000	rs575	1.337
A	G	10000.000	rs576	-4.823
A	G	10000.000	rs577	3.078
A	G	10000.000	rs578	3.374
A	G	10000.000	rs579	0.780
A	G	10000.000	rs580	5.355
A	G	10000.000	rs581	0.682
A	G	10000.000	rs582	4.030
A	G	10000.000	rs583	0.751
A	G	10000.000	rs584	-4.093
A	G	10000.000	rs585	-1.498
A	G	10000.000	rs586	-3.025
A	G	10000.000	rs587	-3.899
A	G	10000.000	rs588	2.135
A	G	10000.000	rs589	0.505
A	G	10000.000	rs590	0.614
A	G	10000.000	rs591	-1.176
A	G	10000.000	rs592	-0.135
A	G	10000.000	rs593	-3.617
A	G	10000.000	rs594	2.047
A	G	10000.000	rs595	-0.576
A	G	10000.000	rs596	1.408
A	G	10000.000	rs597	-1.028
A	G	10000.000	rs598	-3.936
A	G	10000.000	rs599	2.093
A	G	10000.000	rs600	3.421
A	G	10000.000	rs601	-1.939
A	G	10000.000	rs602	2.830
A	G	10000.000	rs603	2.312
A	G	10000.000	rs604	-1.055
A	G	10000.000	rs605	5.609
A	G	10000.000	rs606	-0.154
A	G	10000.000	rs607	0.356
A	G	10000.000	rs608	-0.213
A	G	10000.000	rs609	1.995
A	G	10000.000	rs610	-2.712
A	G	10000.000	rs611	1.419
A	G	10000.000	rs612	-0.101
A	G	10000.000	rs613	6.442
A	G	10000.000	rs614	-0.890
A	G	10000.000	rs615	1.754
A	G	10000.000	rs616	-0.576
A	G	10000.000	rs617	5.193
A	G	10000.000	rs618	-1.358
A	G	10000.000	rs619	-0.775
A	G	10000.000	rs620	-0.546
A	G	10000.000	rs621	3.593
A	G	10000.000	rs622	-3.445
A	G	10000.000	rs623	-4.679
A	G	10000.000	rs624	1.409
A	G	10000.000	rs625	-4.669
A	G	10000.000	rs626	0.528
A	G	10000.000	rs627	6.203
A	G	10000.000	rs628	-0.280
A	G	10000.000	rs629	2.531
A	G	10000.000	rs630	-1.054
A	G	10000.000	rs631	-0.616
A	G	10000.000	rs632	0.605
A	G	10000.000	rs633	2.917
A	G	10000.000	rs634	-5.942
A	G	10000.000	rs635	1.824
A	G	10000.000	rs636	1.884
A	G	10000.000	rs637	-0.388
A	G	10000.000	rs638	1.138
A	G	10000.000	rs639	2.877
A	G	10000.000	rs640	-4.580
A	G	10000.000	rs641	0.862
A	G	10000.000	rs642	0.217
A	G	10000.000	rs643	0.373
A	G	10000.000	rs644	-5.299
A	G	10000.000	rs645	-0.209
A	G	10000.000	rs646	4.326
A	G	10000.000	rs647	-1.782
A	G	10000.000	rs648	-4.730
A	G	10000.000	rs649	-0.306
A	G	10000.000	rs650	0.004
A	G	10000.000	rs651	2.140
A	G	10000.000	rs652	-2.653
A	G	10000.000	rs653	3.804
A	G	10000.000	rs654	1.863
A	G	10000.000	rs655	3.288
A	G	10000.000	rs656	-1.622
A	G	10000.000	rs657	5.712
A	G	10000.000	rs658	4.331
A	G	10000.000	rs659	1.698
A	G	10000.000	rs660	-2.492
A	G	10000.000	rs661	0.203
A	G	10000.000	rs662	-2.718
A	G	10000.000	rs663	-1.716
A	G	10000.000	rs664	-1.066
A	G	10000.000	rs665	-1.043
A	G	10000.000	rs666	-6.999
A	G	10000.000	rs667	-1.467
A	G	10000.000	rs668	4.366
A	G	10000.000	rs669	1.509
A	G	10000.000	rs670	-5.482
A	G	10000.000	rs671	-0.728
A	G	10000.000	rs672	-0.899
A	G	10000.000	rs673	-3.334
A	G	10000.000	rs674	4.785
A	G	10000.000	rs675	-2.384
A	G	10000.000	rs676	0.795
A	G	10000.000	rs677	-6.091
A	G	10000.000	rs678	2.767
A	G	10000.000	rs679	-1.782
A	G	10000.000	rs680	-1.172
A	G	10000.000	rs681	-1.121
A	G	10000.000	rs682	4.314
A	G	10000.000	rs683	0.566
A	G	10000.000	rs684	2.021
A	G	10000.000	rs685	1.851
A	G	10000.000	rs686	-0.675
A	G	10000.000	rs687	-1.444
A	G	10000.000	rs688	1.413
A	G	10000.000	rs689	1.448
A	G	10000.000	rs690	-5.752
A	G	10000.000	rs691	4.629
A	G	10000.000	rs692	7.669
A	G	10000.000	rs693	1.783
A	G	10000.000	rs694	-1.975
A	G	10000.000	rs695	-1.847
A	G	10000.000	rs696	1.033
A	G	10000.000	rs697	4.384
A	G	10000.000	rs698	0.983
A	G	10000.000	rs699	-3.873
A	G	10000.000	rs700	-0.005
A	G	10000.000	rs701	2.978
A	G	10000.000	rs702	-2.296
A	G	10000.000	rs703	1.826
A	G	10000.000	rs704	-0.110
A	G	10000.000	rs705	-1.972
A	G	10000.000	rs706	-4.291
A	G	10000.000	rs707	-1.982
A	G	10000.000	rs708	2.069
A	G	10000.000	rs709	6.445
A	G	10000.000	rs710	0.164
A	G	10000.000	rs711	-0.081
A	G	10000.000	rs712	-0.705
A	G	10000.000	rs713	1.639
A	G	10000.000	rs714	3.227
A	G	10000.000	rs715	-1.651
A	G	10000.000	rs716	3.667
A	G	10000.000	rs717	3.024
A	G	10000.000	rs718	-1.668
A	G	10000.000	rs719	-6.526
A	G	10000.000	rs720	-0.881
A	G	10000.000	rs721	7.623
A	G	10000.000	rs722	5.650
A	G	10000.000	rs723	3.916
A	G	10000.000	rs724	-5.846
A	G	10000.000	rs725	-0.200
A	G	10000.000	rs726	-2.034
A	G	10000.000	rs727	1.167
A	G	10000.000	rs728	1.397
A	G	10000.000	rs729	2.811
A	G	10000.000	rs730	-4.416
A	G	10000.000	rs731	-0.262
A	G	10000.000	rs732	-0.131
A	G	10000.000	rs733	-0.091
A	G	10000.000	rs734	3.385
A	G	10000.000	rs735	-5.765
A	G	10000.000	rs736	-3.731
A	G	10000.000	rs737	1.563
A	G	10000.000	rs738	-0.120
A	G	10000.000	rs739	-0.792
A	G	10000.000	rs740	0.379
A	G	10000.000	rs741	2.112
A	G	10000.000	rs742	-1.799
A	G	10000.000	rs743	2.678
A	G	10000.000	rs744	-7.701
A	G	10000.000	rs745	5.401
A	G	10000.000	rs746	-0.698
A	G	10000.000	rs747	1.125
A	G	10000.000	rs748	-1.610
A	G	10000.000	rs749	2.824
A	G	10000.000	rs750	-0.434
A	G	10000.000	rs751	-0.844
A	G	10000.000	rs752	-2.102
A	G	10000.000	rs753	-0.626
A	G	10000.000	rs754	3.114
A	G	10000.000	rs755	-0.592
A	G	10000.000	rs756	-6.150
A	G	10000.000	rs757	-1.091
A	G	10000.000	rs758	3.380
A	G	10000.000	rs759	-1.818
A	G	10000.000	rs760	2.674
A	G	10000.000	rs761	2.760
A	G	10000.000	rs762	0.727
A	G	10000.000	rs763	-3.407
A	G	10000.000	rs764	-1.367
A	G	10000.000	rs765	-5.104
A	G	10000.000	rs766	-0.864
A	G	10000.000	rs767	0.548
A	G	10000.000	rs768	4.999
A	G	10000.000	rs769	0.922
A	G	10000.000	rs770	-0.179
A	G	10000.000	rs771	3.527
A	G	10000.000	rs772	-1.365
A	G	10000.000	rs773	-6.360
A	G	10000.000	rs774	6.212
A	G	10000.000	rs775	3.385
A	G	10000.000	rs776	-2.778
A	G	10000.000	rs777	1.663
A	G	10000.000	rs778	3.797
A	G	10000.000	rs779	0.103
A	G	10000.000	rs780	-1.603
A	G	10000.000	rs781	-5.361
A	G	10000.000	rs782	0.306
A	G	10000.000	rs783	0.906
A	G	10000.000	rs784	-3.325
A	G	10000.000	rs785	-3.664
A	G	10000.000	rs786	3.917
A	G	10000.000	rs787	-5.312
A	G	10000.000	rs788	-1.231
A	G	10000.000	rs789	2.496
A	G	10000.000	rs790	4.258
A	G	10000.000	rs791	-1.633
A	G	10000.000	rs792	0.282
A	G	10000.000	rs793	-1.882
A	G	10000.000	rs794	0.581
A	G	10000.000	rs795	-6.827
A	G	10000.000	rs796	0.883
A	G	10000.000	rs797	-2.507
A	G	10000.000	rs798	0.011
A	G	10000.000	rs799	-0.268
A	G	10000.000	rs800	-0.560
A	G	10000.000	rs801	5.213
A	G	10000.000	rs802	3.125
A	G	10000.000	rs803	3.164
A	G	10000.000	rs804	-5.041
A	G	10000.000	rs805	-0.952
A	G	10000.000	rs806	-0.432
A	G	10000.000	rs807	4.210
A	G	10000.000	rs808	-0.153
A	G	10000.000	rs809	1.221
A	G	10000.000	rs810	-1.619
A	G	10000.000	rs811	-1.210
A	G	10000.000	rs812	3.455
A	G	10000.000	rs813	3.200
A	G	10000.000	rs814	4.288
A	G	10000.000	rs815	8.401
A	G	10000.000	rs816	4.016
A	G	10000.000	rs817	4.375
A	G	10000.000	rs818	0.670
A	G	10000.000	rs819	-1.638
A	G	10000.000	rs820	2.807
A	G	10000.000	rs821	0.852
A	G	10000.000	rs822	0.710
A	G	10000.000	rs823	0.010
A	G	10000.000	rs824	1.119
A	G	10000.000	rs825	2.322
A	G	10000.000	rs826	0.874
A	G	10000.000	rs827	2.491
A	G	10000.000	rs828	4.769
A	G	10000.000	rs829	0.378
A	G	10000.000	rs830	-7.523
A	G	10000.000	rs831	-1.655
A	G	10000.000	rs832	-0.313
A	G	10000.000	rs833	1.591
A	G	10000.000	rs834	-3.753
A	G	10000.000	rs835	0.331
A	G	10000.000	rs836	4.912
A	G	10000.000	rs837	-5.872
A	G	10000.000	rs838	-1.717
A	G	10000.000	rs839	3.483
A	G	10000.000	rs840	-0.926
A	G	10000.000	rs841	0.853
A	G	10000.000	rs842	1.107
A	G	10000.000	rs843	2.844
A	G	10000.000	rs844	-2.358
A	G	10000.000	rs845	3.213
A	G	10000.000	rs846	-3.936
A	G	10000.000	rs847	-2.300
A	G	10000.000	rs848	-2.144
A	G	10000.000	rs849	-4.342
A	G	10000.000	rs850	0.573
A	G	10000.000	rs851	4.204
A	G	10000.000	rs852	3.332
A	G	10000.000	rs853	-2.553
A	G	10000.000	rs854	4.618
A	G	10000.000	rs855	0.338
A	G	10000.000	rs856	-1.864
A	G	10000.000	rs857	-5.242
A	G	10000.000	rs858	-2.027
A	G	10000.000	rs859	-2.778
A	G	10000.000	rs860	-1.642
A	G	10000.000	rs861	-2.525
A	G	10000.000	rs862	-2.834
A	G	10000.000	rs863	0.272
A	G	10000.000	rs864	-0.329
A	G	10000.000	rs865	1.581
A	G	10000.000	rs866	2.802
A	G	10000.000	rs867	-2.959
A	G	10000.000	rs868	4.561
A	G	10000.000	rs869	0.825
A	G	10000.000	rs870	2.543
A	G	10000.000	rs871	0.119
A	G	10000.000	rs872	1.919
A	G	10000.000	rs873	1.053
A	G	10000.000	rs874	1.430
A	G	10000.000	rs875	-0.314
A	G	10000.000	rs876	0.935
A	G	10000.000	rs877	1.910
A	G	10000.000	rs878	-1.538
A	G	10000.000	rs879	2.218
A	G	10000.000	rs880	2.230
A	G	10000.000	rs881	-3.733
A	G	10000.000	rs882	3.026
A	G	10000.000	rs883	1.435
A	G	10000.000	rs884	-0.057
A	G	10000.000	rs885	1.920
A	G	10000.000	rs886	8.466
A	G	10000.000	rs887	3.301
A	G	10000.000	rs888	3.797
A	G	10000.000	rs889	2.479
A	G	10000.000	rs890	-1.802
A	G	10000.000	rs891	1.096
A	G	10000.000	rs892	4.989
A	G	10000.000	rs893	-4.856
A	G	10000.000	rs894	0.058
A	G	10000.000	rs895	-0.054
A	G	10000.000	rs896	-2.158
A	G	10000.000	rs897	-0.272
A	G	10000.000	rs898	1.309
A	G	10000.000	rs899	2.891
A	G	10000.000	rs900	0.182
A	G	10000.000	rs901	-1.505
A	G	10000.000	rs902	-5.480
A	G	10000.000	rs903	4.400
A	G	10000.000	rs904	-4.234
A	G	10000.000	rs905	2.161
A	G	10000.000	rs906	1.263
A	G	10000.000	rs907	-3.921
A	G	10000.000	rs908	-6.443
A	G	10000.000	rs909	1.062
A	G	10000.000	rs910	-1.070
A	G	10000.000	rs911	-3.929
A	G	10000.000	rs912	-1.086
A	G	10000.000	rs913	-0.850
A	G	10000.000	rs914	-0.492
A	G	10000.000	rs915	6.045
A	G	10000.000	rs916	-3.426
A	G	10000.000	rs917	6.074
A	G	10000.000	rs918	0.380
A	G	10000.000	rs919	-2.516
A	G	10000.000	rs920	0.142
A	G	10000.000	rs921	-2.527
A	G	10000.000	rs922	4.882
A	G	10000.000	rs923	-2.450
A	G	10000.000	rs924	3.765
A	G	10000.000	rs925	5.721
A	G	10000.000	rs926	1.701
A	G	10000.000	rs927	-2.946
A	G	10000.000	rs928	-2.277
A	G	10000.000	rs929	-0.283
A	G	10000.000	rs930	0.665
A	G	10000.000	rs931	4.037
A	G	10000.000	rs932	2.275
A	G	10000.000	rs933	-1.827
A	G	10000.000	rs934	-1.994
A	G	10000.000	rs935	-7.763
A	G	10000.000	rs936	4.743
A	G	10000.000	rs937	2.354
A	G	10000.000	rs938	0.047
A	G	10000.000	rs939	-3.356
A	G	10000.000	rs940	0.517
A	G	10000.000	rs941	-4.539
A	G	10000.000	rs942	-0.584
A	G	10000.000	rs943	0.729
A	G	10000.000	rs944	-2.301
A	G	10000.000	rs945	2.810
A	G	10000.000	rs946	0.091
A	G	10000.000	rs947	-0.545
A	G	10000.000	rs948	0.139
A	G	10000.000	rs949	-2.275
A	G	10000.000	rs950	-8.674
A	G	10000.000	rs951	0.655
A	G	10000.000	rs952	-3.886
A	G	10000.000	rs953	-2.448
A	G	10000.000	rs954	3.543
A	G	10000.000	rs955	4.743
A	G	10000.000	rs956	-4.671
A	G	10000.000	rs957	0.640
A	G	10000.000	rs958	1.901
A	G	10000.000	rs959	-1.355
A	G	10000.000	rs960	0.051
A	G	10000.000	rs961	2.646
A	G	10000.000	rs962	-2.547
A	G	10000.000	rs963	1.611
A	G	10000.000	rs964	-2.731
A	G	10000.000	rs965	-1.689
A	G	10000.000	rs966	0.977
A	G	10000.000	rs967	-3.247
A	G	10000.000	rs968	-2.500
A	G	10000.000	rs969	7.343
A	G	10000.000	rs970	-0.292
A	G	10000.000	rs971	1.971
A	G	10000.000	rs972	-2.911
A	G	10000.000	rs973	1.139
A	G	10000.000	rs974	1.574
A	G	10000.000	rs975	-0.451
A	G	10000.000	rs976	7.667
A	G	10000.000	rs977	5.636
A	G	10000.000	rs978	2.636
A	G	10000.000	rs979	-1.764
A	G	10000.000	rs980	1.135
A	G	10000.000	rs981	-5.151
A	G	10000.000	rs982	-2.590
A	G	10000.000	rs983	-3.572
A	G	10000.000	rs984	5.056
A	G	10000.000	rs985	-1.780
A	G	10000.000	rs986	-3.325
A	G	10000.000	rs987	1.139
A	G	10000.000	rs988	5.116
A	G	10000.000	rs989	0.252
A	G	10000.000	rs990	-4.505
A	G	10000.000	rs991	-1.638
A	G	10000.000	rs992	2.892
A	G	10000.000	rs993	6.403
A	G	10000.000	rs994	-0.094
A	G	10000.000	rs995	2.665
A	G	10000.000	rs996	-0.001
A	G	10000.000	rs997	-3.162
A	G	10000.000	rs998	-6.768
A	G	10000.000	rs999	4.703


/*
    Plugin-SDK (Grand Theft Auto San Andreas) header file
    Authors: GTA Community. See more here
    https://github.com/DK22Pac/plugin-sdk
    Do not delete this comment block. Respect others' work!
*/
#pragma once

#include "PluginBase.h"
#include "CSetPiece.h"

extern unsigned int MAX_SET_PIECES; // default 210

class PLUGIN_API CSetPieces {
public:
    static void AddOne(unsigned char type, CVector2D cornerA, CVector2D cornerB, CVector2D spawnCoord1, CVector2D targetCoord1, CVector2D spawnCoord2, CVector2D targetCoord2);
    static void Init();
    static bool Load();
    static bool Save();
    static void Update();

    static bool &bDebug;
    static unsigned int &NumSetPieces;
    static CSetPiece *aSetPieces; // static CSetPiece aSetPieces[MAX_SET_PIECES]
};


/*=============================================================================
    Copyright (c) 2001-2011 Joel de Guzman

    Distributed under the Boost Software License, Version 1.0. (See accompanying
    file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

    This is an auto-generated file. Do not edit!
==============================================================================*/
namespace boost { namespace fusion
{
    struct void_;
    template <
        typename T0 = void_ , typename T1 = void_ , typename T2 = void_ , typename T3 = void_ , typename T4 = void_ , typename T5 = void_ , typename T6 = void_ , typename T7 = void_ , typename T8 = void_ , typename T9 = void_ , typename T10 = void_ , typename T11 = void_ , typename T12 = void_ , typename T13 = void_ , typename T14 = void_ , typename T15 = void_ , typename T16 = void_ , typename T17 = void_ , typename T18 = void_ , typename T19 = void_
    >
    struct list;
}}


/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.nifi.documentation;

import org.apache.nifi.bundle.Bundle;
import org.apache.nifi.bundle.BundleCoordinate;
import org.apache.nifi.components.ConfigurableComponent;
import org.apache.nifi.controller.ControllerService;
import org.apache.nifi.documentation.html.HtmlDocumentationWriter;
import org.apache.nifi.documentation.html.HtmlProcessorDocumentationWriter;
import org.apache.nifi.nar.ExtensionManager;
import org.apache.nifi.nar.ExtensionMapping;
import org.apache.nifi.processor.Processor;
import org.apache.nifi.reporting.InitializationException;
import org.apache.nifi.reporting.ReportingTask;
import org.apache.nifi.util.NiFiProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Set;

/**
 * Uses the ExtensionManager to get a list of Processor, ControllerService, and
 * Reporting Task classes that were loaded and generate documentation for them.
 *
 *
 */
public class DocGenerator {

    private static final Logger logger = LoggerFactory.getLogger(DocGenerator.class);

    /**
     * Generates documentation into the work/docs dir specified by
     * NiFiProperties.
     *
     * @param properties to lookup nifi properties
     * @param extensionMapping extension mapping
     */
    public static void generate(final NiFiProperties properties, final ExtensionManager extensionManager, final ExtensionMapping extensionMapping) {
        final File explodedNiFiDocsDir = properties.getComponentDocumentationWorkingDirectory();

        logger.debug("Generating documentation for: " + extensionMapping.size() + " components in: " + explodedNiFiDocsDir);

        documentConfigurableComponent(extensionManager.getExtensions(Processor.class), explodedNiFiDocsDir, extensionManager);
        documentConfigurableComponent(extensionManager.getExtensions(ControllerService.class), explodedNiFiDocsDir, extensionManager);
        documentConfigurableComponent(extensionManager.getExtensions(ReportingTask.class), explodedNiFiDocsDir, extensionManager);
    }

    /**
     * Documents a type of configurable component.
     *
     * @param extensionClasses types of a configurable component
     * @param explodedNiFiDocsDir base directory of component documentation
     */
    public static void documentConfigurableComponent(final Set<Class> extensionClasses, final File explodedNiFiDocsDir, final ExtensionManager extensionManager) {
        for (final Class<?> extensionClass : extensionClasses) {
            if (ConfigurableComponent.class.isAssignableFrom(extensionClass)) {
                final String extensionClassName = extensionClass.getCanonicalName();

                final Bundle bundle = extensionManager.getBundle(extensionClass.getClassLoader());
                if (bundle == null) {
                    logger.warn("No coordinate found for {}, skipping...", new Object[] {extensionClassName});
                    continue;
                }
                final BundleCoordinate coordinate = bundle.getBundleDetails().getCoordinate();

                final String path = coordinate.getGroup() + "/" + coordinate.getId() + "/" + coordinate.getVersion() + "/" + extensionClassName;
                final File componentDirectory = new File(explodedNiFiDocsDir, path);
                componentDirectory.mkdirs();

                final Class<? extends ConfigurableComponent> componentClass = extensionClass.asSubclass(ConfigurableComponent.class);
                try {
                    logger.debug("Documenting: " + componentClass);
                    document(extensionManager, componentDirectory, componentClass, coordinate);
                } catch (Exception e) {
                    logger.warn("Unable to document: " + componentClass, e);
                }
            }
        }
    }

    /**
     * Generates the documentation for a particular configurable component. Will
     * check to see if an "additionalDetails.html" file exists and will link
     * that from the generated documentation.
     *
     * @param componentDocsDir the component documentation directory
     * @param componentClass the class to document
     * @throws InstantiationException ie
     * @throws IllegalAccessException iae
     * @throws IOException ioe
     * @throws InitializationException ie
     */
    private static void document(final ExtensionManager extensionManager,
                                 final File componentDocsDir,
                                 final Class<? extends ConfigurableComponent> componentClass,
                                 final BundleCoordinate bundleCoordinate)
            throws InstantiationException, IllegalAccessException, IOException, InitializationException {

        // use temp components from ExtensionManager which should always be populated before doc generation
        final String classType = componentClass.getCanonicalName();
        final ConfigurableComponent component = extensionManager.getTempComponent(classType, bundleCoordinate);

        final DocumentationWriter writer = getDocumentWriter(extensionManager, componentClass);

        final File baseDocumentationFile = new File(componentDocsDir, "index.html");
        if (baseDocumentationFile.exists()) {
            logger.warn(baseDocumentationFile + " already exists, overwriting!");
        }

        try (final OutputStream output = new BufferedOutputStream(new FileOutputStream(baseDocumentationFile))) {
            writer.write(component, output, hasAdditionalInfo(componentDocsDir));
        }
    }

    /**
     * Returns the DocumentationWriter for the type of component. Currently
     * Processor, ControllerService, and ReportingTask are supported.
     *
     * @param componentClass the class that requires a DocumentationWriter
     * @return a DocumentationWriter capable of generating documentation for
     * that specific type of class
     */
    private static DocumentationWriter getDocumentWriter(final ExtensionManager extensionManager,
                                                                  final Class<? extends ConfigurableComponent> componentClass) {
        if (Processor.class.isAssignableFrom(componentClass)) {
            return new HtmlProcessorDocumentationWriter(extensionManager);
        } else if (ControllerService.class.isAssignableFrom(componentClass)) {
            return new HtmlDocumentationWriter(extensionManager);
        } else if (ReportingTask.class.isAssignableFrom(componentClass)) {
            return new HtmlDocumentationWriter(extensionManager);
        }

        return null;
    }

    /**
     * Checks to see if a directory to write to has an additionalDetails.html in
     * it already.
     *
     * @param directory to check
     * @return true if additionalDetails.html exists, false otherwise.
     */
    private static boolean hasAdditionalInfo(File directory) {
        return directory.list(new FilenameFilter() {

            @Override
            public boolean accept(File dir, String name) {
                return name.equalsIgnoreCase(HtmlDocumentationWriter.ADDITIONAL_DETAILS_HTML);
            }

        }).length > 0;
    }
}


GOSAT-2 - Orbit Track & Time

reference/orbits/OrbitTracks_GOSAT-2_Ascending


/*
 * This file is part of KubeSphere Console.
 * Copyright (C) 2019 The KubeSphere Console Authors.
 *
 * KubeSphere Console is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * KubeSphere Console is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with KubeSphere Console.  If not, see <https://www.gnu.org/licenses/>.
 */

import React, { Component } from 'react'
import { Icon, Tooltip } from '@pitrix/lego-ui'
import { Button } from 'components/Base'

import { isEmpty } from 'lodash'

import styles from './index.scss'

export default class Ports extends Component {
  render() {
    const { detail, gateway } = this.props

    if (isEmpty(detail.ports)) {
      return null
    }

    return (

        {detail.ports.map((port, index) => (

            <Icon name="pod" size={40} />

                {port.targetPort}

{t('Container Port')}

→ {port.protocol} →

            <Icon name="network-router" size={40} />

                {port.port}

{t('Service Port')}

            {port.nodePort && (
              <>

→ {port.protocol} →

                <Icon name="nodes" size={40} />

                    {port.nodePort}

                    {t('Node Port')}
                    <Tooltip
                      content={t('SERVICE_NODE_PORT_DESC')}
                      trigger="hover"
                    >
                      <Icon name="information" />
                    </Tooltip>

                {gateway.defaultIngress && (
                  <a
                    href={`http://${gateway.defaultIngress}:${port.nodePort}`}
                    target="_blank"
                    rel="noreferrer noopener"
                  >
                    <Button className={styles.access} noShadow>
                      {t('Click to visit')}
                    </Button>

                )}
              </>
            )}

        ))}

    )
  }
}