text:
"""
@package mi.instrument.rbr.xr_420_thermistor_24.test.test_driver
@file /Users/Bill/WorkSpace/marine-integrations/mi/instrument/rbr/xr_420_thermistor_24/driver.py
@author Bill Bollenbacher
@brief Test cases for xr_420 thermistor driver

USAGE:
 Make tests verbose and provide stdout
   * From the IDK
       $ bin/test_driver
       $ bin/test_driver -u
       $ bin/test_driver -i
       $ bin/test_driver -q

   * From pyon
       $ bin/nosetests -s -v /Users/Bill/WorkSpace/marine-integrations/mi/instrument/rbr/xr_420_thermistor_24
       $ bin/nosetests -s -v /Users/Bill/WorkSpace/marine-integrations/mi/instrument/rbr/xr_420_thermistor_24 -a UNIT
       $ bin/nosetests -s -v /Users/Bill/WorkSpace/marine-integrations/mi/instrument/rbr/xr_420_thermistor_24 -a INT
       $ bin/nosetests -s -v /Users/Bill/WorkSpace/marine-integrations/mi/instrument/rbr/xr_420_thermistor_24 -a QUAL
"""

__author__ = 'Bill Bollenbacher'
__license__ = 'Apache 2.0'

# Ensure the test class is monkey patched for gevent
from gevent import monkey
monkey.patch_all()
import gevent
from mock import Mock
import unittest

# Standard lib imports
import time
import calendar
import ntplib
import json

# 3rd party import
from nose.plugins.attrib import attr

# MI logger
from mi.core.log import get_logger
log = get_logger()
from mi.core.time_tools import timegm_to_float
from mi.core.instrument.instrument_driver import ResourceAgentEvent

from mi.core.instrument.instrument_driver import DriverAsyncEvent
from mi.core.instrument.instrument_driver import DriverConnectionState
from mi.core.instrument.instrument_driver import DriverParameter
from mi.core.instrument.instrument_driver import DriverProtocolState
from mi.core.instrument.instrument_driver import DriverEvent

from mi.core.instrument.data_particle import DataParticleKey
from mi.core.instrument.data_particle import DataParticleValue

from mi.core.exceptions import InstrumentCommandException
from mi.core.exceptions import SampleException

from mi.instrument.rbr.xr_420_thermistor_24.ooicore.driver import InstrumentDriver
from mi.instrument.rbr.xr_420_thermistor_24.ooicore.driver import DataParticleType
from mi.instrument.rbr.xr_420_thermistor_24.ooicore.driver import ProtocolStates
from mi.instrument.rbr.xr_420_thermistor_24.ooicore.driver import ProtocolEvent
from mi.instrument.rbr.xr_420_thermistor_24.ooicore.driver import InstrumentProtocol
from mi.instrument.rbr.xr_420_thermistor_24.ooicore.driver import InstrumentParameters
from mi.instrument.rbr.xr_420_thermistor_24.ooicore.driver import InstrumentCommands
from mi.instrument.rbr.xr_420_thermistor_24.ooicore.driver import Capability
from mi.instrument.rbr.xr_420_thermistor_24.ooicore.driver import ScheduledJob
from mi.instrument.rbr.xr_420_thermistor_24.ooicore.driver import InstrumentResponses
from mi.instrument.rbr.xr_420_thermistor_24.ooicore.driver import AdvancedFunctionsParameters
from mi.instrument.rbr.xr_420_thermistor_24.ooicore.driver import AdvancedFunctionsBits
from mi.instrument.rbr.xr_420_thermistor_24.ooicore.driver import XR_420EngineeringDataParticleKey
from mi.instrument.rbr.xr_420_thermistor_24.ooicore.driver import XR_420SampleDataParticleKey
from mi.instrument.rbr.xr_420_thermistor_24.ooicore.driver import XR_420SampleDataParticle
from mi.instrument.rbr.xr_420_thermistor_24.ooicore.driver import NEWLINE

from mi.idk.unit_test import InstrumentDriverTestCase
from mi.idk.unit_test import InstrumentDriverUnitTestCase
from mi.idk.unit_test import InstrumentDriverIntegrationTestCase
from mi.idk.unit_test import InstrumentDriverQualificationTestCase
from mi.idk.unit_test import InstrumentDriverPublicationTestCase
from mi.idk.unit_test import DriverTestMixin
from mi.idk.unit_test import ParameterTestConfigKey
from mi.idk.unit_test import DriverStartupConfigKey
from mi.idk.unit_test import AgentCapabilityType

from mi.core.instrument.chunker import StringChunker

# Initialize the test configuration
InstrumentDriverTestCase.initialize(
    driver_module='mi.instrument.rbr.xr_420_thermistor_24.ooicore.driver',
    driver_class="InstrumentDriver",

    instrument_agent_resource_id='rbr_xr_420_ooicore',
    instrument_agent_name='rbr_xr_420_ooicore_agent',
    instrument_agent_packet_config=DataParticleType(),

    driver_startup_config={
        DriverStartupConfigKey.PARAMETERS: {
            #InstrumentParameters.SYS_CLOCK: '3',
        },
    }
)

class UtilMixin(DriverTestMixin):
    """
    Mixin class used for storing data particle constants and common data assertion methods.
    """

    # Create some short names for the parameter test config
    TYPE = ParameterTestConfigKey.TYPE
    READONLY = ParameterTestConfigKey.READONLY
    STARTUP = ParameterTestConfigKey.STARTUP
    DA = ParameterTestConfigKey.DIRECT_ACCESS
    VALUE = ParameterTestConfigKey.VALUE
    REQUIRED = ParameterTestConfigKey.REQUIRED
    DEFAULT = ParameterTestConfigKey.DEFAULT
    STATES = ParameterTestConfigKey.STATES

    CLOCK_SYNC_TIME = '21 Feb 2002 11:18:42'
    TIME_IN_PAST    = '01 Jan 2000 12:23:00'
    TIME_IN_FUTURE  = '27 Dec 2023 01:10:59'

    ###
    #  Parameter and Type Definitions
    ###
    _driver_parameters = {
        InstrumentParameters.IDENTIFICATION : {TYPE: str, READONLY: True, DA: False, STARTUP: False, VALUE: 'RBR XR-420 6.810 021964'},
        InstrumentParameters.LOGGER_DATE_AND_TIME : {TYPE: str, READONLY: True, STARTUP: False, DA: False},
        InstrumentParameters.SAMPLE_INTERVAL : {TYPE: str, READONLY: False, DA: False, STARTUP: True, DEFAULT: '00:00:12'},
        InstrumentParameters.START_DATE_AND_TIME : {TYPE: str, READONLY: True, DA: False, STARTUP: True, DEFAULT: '01 Jan 2000 00:00:00', VALUE: '01 Jan 2000 00:00:00'},
        InstrumentParameters.END_DATE_AND_TIME : {TYPE: str, READONLY: True, DA: False, STARTUP: True, DEFAULT: '01 Jan 2050 00:00:00', VALUE: '01 Jan 2050 00:00:00'},
        InstrumentParameters.STATUS : {TYPE: str, READONLY: True, DA: False, STARTUP: False},
        InstrumentParameters.BATTERY_VOLTAGE : {TYPE: float, READONLY: True, DA: False, STARTUP: False},
        InstrumentParameters.POWER_ALWAYS_ON : {TYPE: int, READONLY: False, DA: False, STARTUP: True, DEFAULT: 1, VALUE: 1},
        InstrumentParameters.SIX_HZ_PROFILING_MODE : {TYPE: int, READONLY: True, DA: False, STARTUP: True, DEFAULT: 0, VALUE: 0},
        InstrumentParameters.OUTPUT_INCLUDES_SERIAL_NUMBER : {TYPE: int, READONLY: True, DA: True, STARTUP: True, DEFAULT: 1, VALUE: 1},
        InstrumentParameters.OUTPUT_INCLUDES_BATTERY_VOLTAGE : {TYPE: int, READONLY: True, DA: True, STARTUP: True, DEFAULT: 1, VALUE: 1},
        InstrumentParameters.SAMPLING_LED : {TYPE: int, READONLY: True, DA: False, STARTUP: True, DEFAULT: 0, VALUE: 0},
        InstrumentParameters.ENGINEERING_UNITS_OUTPUT : {TYPE: int, READONLY: True, DA: True, STARTUP: True, DEFAULT: 1, VALUE: 1},
        InstrumentParameters.AUTO_RUN : {TYPE: int, READONLY: True, DA: False, STARTUP: True, DEFAULT: 1, VALUE: 1},
        InstrumentParameters.INHIBIT_DATA_STORAGE : {TYPE: int, READONLY: False, DA: False, STARTUP: True, DEFAULT: 1, VALUE: 1},
        InstrumentParameters.CALIBRATION_COEFFICIENTS_CHANNEL_1 : {TYPE: list, READONLY: True, DA: False, STARTUP: False},
        InstrumentParameters.CALIBRATION_COEFFICIENTS_CHANNEL_2 : {TYPE: list, READONLY: True, DA: False, STARTUP: False},
        InstrumentParameters.CALIBRATION_COEFFICIENTS_CHANNEL_3 : {TYPE: list, READONLY: True, DA: False, STARTUP: False},
        InstrumentParameters.CALIBRATION_COEFFICIENTS_CHANNEL_4 : {TYPE: list, READONLY: True, DA: False, STARTUP: False},
        InstrumentParameters.CALIBRATION_COEFFICIENTS_CHANNEL_5 : {TYPE: list, READONLY: True, DA: False, STARTUP: False},
        InstrumentParameters.CALIBRATION_COEFFICIENTS_CHANNEL_6 : {TYPE: list, READONLY: True, DA: False, STARTUP: False},
        InstrumentParameters.CALIBRATION_COEFFICIENTS_CHANNEL_7 : {TYPE: list, READONLY: True, DA: False, STARTUP: False},
        InstrumentParameters.CALIBRATION_COEFFICIENTS_CHANNEL_8 : {TYPE: list, READONLY: True, DA: False, STARTUP: False},
        InstrumentParameters.CALIBRATION_COEFFICIENTS_CHANNEL_9 : {TYPE: list, READONLY: True, DA: False, STARTUP: False},
        InstrumentParameters.CALIBRATION_COEFFICIENTS_CHANNEL_10 : {TYPE: list, READONLY: True, DA: False, STARTUP: False},
        InstrumentParameters.CALIBRATION_COEFFICIENTS_CHANNEL_11 : {TYPE: list, READONLY: True, DA: False, STARTUP: False},
        InstrumentParameters.CALIBRATION_COEFFICIENTS_CHANNEL_12 : {TYPE: list, READONLY: True, DA: False, STARTUP: False},
        InstrumentParameters.CALIBRATION_COEFFICIENTS_CHANNEL_13 : {TYPE: list, READONLY: True, DA: False, STARTUP: False},
        InstrumentParameters.CALIBRATION_COEFFICIENTS_CHANNEL_14 : {TYPE: list, READONLY: True, DA: False, STARTUP: False},
        InstrumentParameters.CALIBRATION_COEFFICIENTS_CHANNEL_15 : {TYPE: list, READONLY: True, DA: False, STARTUP: False},
        InstrumentParameters.CALIBRATION_COEFFICIENTS_CHANNEL_16 : {TYPE: list, READONLY: True, DA: False, STARTUP: False},
        InstrumentParameters.CALIBRATION_COEFFICIENTS_CHANNEL_17 : {TYPE: list, READONLY: True, DA: False, STARTUP: False},
        InstrumentParameters.CALIBRATION_COEFFICIENTS_CHANNEL_18 : {TYPE: list, READONLY: True, DA: False, STARTUP: False},
        InstrumentParameters.CALIBRATION_COEFFICIENTS_CHANNEL_19 : {TYPE: list, READONLY: True, DA: False, STARTUP: False},
        InstrumentParameters.CALIBRATION_COEFFICIENTS_CHANNEL_20 : {TYPE: list, READONLY: True, DA: False, STARTUP: False},
        InstrumentParameters.CALIBRATION_COEFFICIENTS_CHANNEL_21 : {TYPE: list, READONLY: True, DA: False, STARTUP: False},
        InstrumentParameters.CALIBRATION_COEFFICIENTS_CHANNEL_22 : {TYPE: list, READONLY: True, DA: False, STARTUP: False},
        InstrumentParameters.CALIBRATION_COEFFICIENTS_CHANNEL_23 : {TYPE: list, READONLY: True, DA: False, STARTUP: False},
        InstrumentParameters.CALIBRATION_COEFFICIENTS_CHANNEL_24 : {TYPE: list, READONLY: True, DA: False, STARTUP: False},
    }

    _driver_capabilities = {
        # capabilities defined in the IOS
        Capability.DISCOVER: {STATES: [ProtocolStates.UNKNOWN]},
        Capability.ACQUIRE_STATUS : {STATES: [ProtocolStates.COMMAND, ProtocolStates.AUTOSAMPLE]},
        Capability.START_AUTOSAMPLE : {STATES: [ProtocolStates.COMMAND]},
        Capability.STOP_AUTOSAMPLE : {STATES: [ProtocolStates.AUTOSAMPLE]},
        Capability.CLOCK_SYNC : {STATES: [ProtocolStates.COMMAND]},
    }

    _raw_coefficients = {
        InstrumentParameters.BATTERY_VOLTAGE:  '8ABAT\r\n',
        InstrumentParameters.CALIBRATION_COEFFICIENTS_CHANNEL_1:  '4C02E5F8338B6C3F2EE9CCCCA56F30BF22757E403EB0C43EFF5CF27A032669BECAL\r\n',
        InstrumentParameters.CALIBRATION_COEFFICIENTS_CHANNEL_2:  'BE6B421617B56C3FD5784086847630BF905452AD92CCC43E085570CAF14B70BECAL\r\n',
        InstrumentParameters.CALIBRATION_COEFFICIENTS_CHANNEL_3:  '242263F451486C3F5AF6B89F195C30BFB79BE3E59B53C43EB008321DA84F71BECAL\r\n',
        InstrumentParameters.CALIBRATION_COEFFICIENTS_CHANNEL_4:  '891826C0BBE16C3FF6BCCDDAD77030BFEF6D8EAAA735C53EEAD71EBC6CB671BECAL\r\n',
        InstrumentParameters.CALIBRATION_COEFFICIENTS_CHANNEL_5:  'DB2BA620129C6C3FC06A17A5CE6830BF5EBF4750E2ACC43ED9C08996BF8671BECAL\r\n',
        InstrumentParameters.CALIBRATION_COEFFICIENTS_CHANNEL_6:  '9832B7EB936E6C3F97A33505556630BFC4C17691D551C43E28FAC2E315E467BECAL\r\n',
        InstrumentParameters.CALIBRATION_COEFFICIENTS_CHANNEL_7:  '9E067E30B5BE6C3FF579E335BB7B30BFA90F629A9910C53EBB2346D1E28467BECAL\r\n',
        InstrumentParameters.CALIBRATION_COEFFICIENTS_CHANNEL_8:  '05881C51EBB86C3FC7465FC2E47030BFED17ABD188B2C43E5927D2EC910671BECAL\r\n',
        InstrumentParameters.CALIBRATION_COEFFICIENTS_CHANNEL_9:  '056122D77F6A6C3FEB3E4825ED6030BFB79071014685C43E493A8785B48C70BECAL\r\n',
        InstrumentParameters.CALIBRATION_COEFFICIENTS_CHANNEL_10: 'CAF90420DD8C6C3FF05473B3867330BF46F93CFC3A71C43E8F029EDCE8A470BECAL\r\n',
        InstrumentParameters.CALIBRATION_COEFFICIENTS_CHANNEL_11: 'A718DC5CBD776C3F3499D9E3555F30BF6898FE4C1FC0C43E498718800D4D6BBECAL\r\n',
        InstrumentParameters.CALIBRATION_COEFFICIENTS_CHANNEL_12: 'FCAC137DCC5C6C3FE784F5DBC46130BFD3725AB17844C43EA0421314BF4771BECAL\r\n',
        InstrumentParameters.CALIBRATION_COEFFICIENTS_CHANNEL_13: '0D618D51A16A6C3F428D6D7DAA6E30BF2957DF907903C43EFF89ED2B0C296FBECAL\r\n',
        InstrumentParameters.CALIBRATION_COEFFICIENTS_CHANNEL_14: '53550E2075C36C3F87A2176B7F7330BF664CD355581CC53EE54C1B4B7A4E6DBECAL\r\n',
        InstrumentParameters.CALIBRATION_COEFFICIENTS_CHANNEL_15: '194554FC74456C3F3BE7497C9E5630BFCEF5601309A9C43E64C9B4A15A766CBECAL\r\n',
        InstrumentParameters.CALIBRATION_COEFFICIENTS_CHANNEL_16: 'E677D71494646C3F3C2B90A7136830BF5C9E8FE502D6C43EAF0199BE495667BECAL\r\n',
        InstrumentParameters.CALIBRATION_COEFFICIENTS_CHANNEL_17: '04C6AF97FEE46C3F2C51B20CD37630BF06EAFA626607C53EB8CD64294E5070BECAL\r\n',
        InstrumentParameters.CALIBRATION_COEFFICIENTS_CHANNEL_18: 'A571169A43FB6C3FFFAEE8F3097C30BF86E1E8BCCF27C53E832EC500513472BECAL\r\n',
        InstrumentParameters.CALIBRATION_COEFFICIENTS_CHANNEL_19: 'AB31AF4315F46C3F83F6A77BB88330BF4A91C3CAB7FCC43EC21A809AA3436CBECAL\r\n',
        InstrumentParameters.CALIBRATION_COEFFICIENTS_CHANNEL_20: '1257746962BD6C3F86B89412DC7630BFEA35F6B9C3B3C43E9270885A3A2D70BECAL\r\n',
        InstrumentParameters.CALIBRATION_COEFFICIENTS_CHANNEL_21: 'C3B12A617B066D3FC455D033A87530BF70459B83A260C53EAFEA58B2FBB670BECAL\r\n',
        InstrumentParameters.CALIBRATION_COEFFICIENTS_CHANNEL_22: '306A248B2E726C3FEB9788E93F5C30BFB08D70B2ADDFC43E7F8FFA4D5AC96CBECAL\r\n',
        InstrumentParameters.CALIBRATION_COEFFICIENTS_CHANNEL_23: 'A8A8D23B47876C3F08CCD99F676330BF849601A38FB8C43E3DCF7A08A8EA67BECAL\r\n',
        InstrumentParameters.CALIBRATION_COEFFICIENTS_CHANNEL_24: '13ED538DBED06C3F73B8DB10687030BF1014A4477326C53E8B9E285D3F586CBECAL\r\n',
    }

    _engineering_parameters = {
        XR_420EngineeringDataParticleKey.BATTERY_VOLTAGE: {TYPE: float, REQUIRED: False},
        XR_420EngineeringDataParticleKey.CALIBRATION_COEFFICIENTS: {
            TYPE: list,

            # Coefficients for S/N 021968 uncomment when testing with this specific instrument
            #VALUE: [
            #    [0.00348434592083916, -0.00025079534389118, 2.46625541318206e-06, -4.68427140350704e-08],
            #    [0.00350431927843206, -0.000251204828829799, 2.47944749760338e-06, -6.07097826319064e-08],
            #    [0.00345245367779891, -0.000249630218352203, 2.42311925467998e-06, -6.44890925539532e-08],
            #    [0.00352560682330522, -0.000250866602804003, 2.52838011189997e-06, -6.59845645057904e-08],
            #    [0.00349238911184589, -0.000250387621319053, 2.46469119446334e-06, -6.52907822336288e-08],
            #    [0.00347069636129611, -0.000250240094109838, 2.42229283361364e-06, -4.45003789108644e-08],
            #    [0.00350890530165844, -0.000251515584649114, 2.51112506349963e-06, -4.38077113777949e-08],
            #    [0.00350614509888292, -0.000250869607382059, 2.4673223724984e-06, -6.34255414457636e-08],
            #    [0.00346875161001148, -0.000249917885668956, 2.4462460817433e-06, -6.16521743719807e-08],
            #    [0.00348513782969848, -0.000251026521664712, 2.43691281012686e-06, -6.20043955328834e-08],
            #    [0.00347506508740299, -0.000249823064086735, 2.47364969392914e-06, -5.08520514692428e-08],
            #    [0.00346221865821905, -0.000249968110400968, 2.41607029745207e-06, -6.43739826056667e-08],
            #    [0.00346881396800936, -0.000250736831210758, 2.38580390197586e-06, -5.80406598258295e-08],
            #    [0.00351117015857009, -0.000251024826040815, 2.51659427750457e-06, -5.45877098086669e-08],
            #    [0.00345108841668974, -0.000249303524732281, 2.46289905716957e-06, -5.30152030837836e-08],
            #    [0.00346592828894553, -0.000250344084236676, 2.48384257560737e-06, -4.34686667325137e-08],
            #    [0.0035271618376036, -0.000251223111896753, 2.50684094979287e-06, -6.07732409715931e-08],
            #    [0.00353778079506935, -0.000251533918261812, 2.52193374386203e-06, -6.78165294521451e-08],
            #    [0.00353435662461817, -0.000251991786768581, 2.50186675120244e-06, -5.26462032302453e-08],
            #    [0.00350827427940715, -0.000251225212724367, 2.46789518571518e-06, -6.02627979813181e-08],
            #    [0.00354312989778391, -0.000251153531111239, 2.54839417555195e-06, -6.22674006461501e-08],
            #    [0.0034724148801051, -0.000249639133047429, 2.48834421114212e-06, -5.3619098270147e-08],
            #    [0.0034824744494318, -0.000250065611772488, 2.47012874159369e-06, -4.45481883026538e-08],
            #    [0.00351750580977995, -0.000250840574934303, 2.52129990230494e-06, -5.2796149358899e-08],
            #]

            # Coefficients for S/N 021964
            VALUE: [
                [0.00350351257503633, -0.000251016837008213, 2.50346349940003e-06, -7.03583240832029e-08],
                [0.00352734558932672, -0.000250806607039791, 2.52981232225823e-06, -6.9681632181742e-08],
                [0.00352908906242572, -0.000251527366676445, 2.55498317829155e-06, -7.22727455164041e-08],
                [0.0035106579008714, -0.000251451725838218, 2.51618864926975e-06, -6.37003888154981e-08],
                [0.00352043330655908, -0.000251319883389552, 2.52146924964957e-06, -7.95333725252667e-08],
                [0.00347203853074575, -0.000250010390734016, 2.46129147793677e-06, -7.12959689441277e-08],
                [0.00353004946255691, -0.000251247554226747, 2.52159304090808e-06, -7.79481130920587e-08],
                [0.00351399903159413, -0.000251445570503529, 2.50096227037833e-06, -7.60943129358672e-08],
                [0.00351653261740167, -0.000251051219607601, 2.53455190801056e-06, -8.13292184060405e-08],
                [0.00349296329304579, -0.000250559803337319, 2.47183987824423e-06, -8.12905755755912e-08],
                [0.00353707353809311, -0.000251970815662328, 2.57716626611678e-06, -7.51392864122071e-08],
                [0.00350165750293915, -0.000250961389511847, 2.54649892676099e-06, -7.46908408762439e-08],
                [0.00348026127523274, -0.000250548193988013, 2.51923384904865e-06, -5.67882019711713e-08],
                [0.00352136263866797, -0.00025136861700225, 2.54399944876075e-06, -7.08951737250939e-08],
                [0.00346059399256526, -0.000250438585788932, 2.4475005966701e-06, -6.5822082123344e-08],
                [0.00348305997117858, -0.000250508133431039, 2.50598190722111e-06, -5.80161431784478e-08],
                [0.00349025189639767, -0.000250309161843678, 2.5055791623668e-06, -7.25120915816188e-08],
                [0.00353877751299455, -0.000251807379744552, 2.55602860165318e-06, -6.5251264076325e-08],
                [0.00352973393792469, -0.000252011191704782, 2.54873468118718e-06, -6.14820327594475e-08],
                [0.00352310007997345, -0.000251300883481298, 2.52824482619229e-06, -6.74465833408085e-08],
                [0.00350603632611762, -0.000250897867392207, 2.54479746316057e-06, -7.41559532076147e-08],
                [0.00351995561219995, -0.000251784157910044, 2.56187105314808e-06, -6.56020154220122e-08],
                [0.00348834955133481, -0.00024929110242942, 2.76692656687453e-06, -6.84152614194907e-08],
                [0.00349851973435787, -0.000251264850202629, 2.47592261180165e-06, -6.64877670276299e-08]
            ]
        }
    }

    _sample_parameters = {
        XR_420SampleDataParticleKey.TIMESTAMP: {TYPE: float, VALUE: 3223633980.0},
        XR_420SampleDataParticleKey.TEMPERATURE01: {TYPE: float, VALUE: 21.4548},
        XR_420SampleDataParticleKey.TEMPERATURE02: {TYPE: float, VALUE: 21.0132},
        XR_420SampleDataParticleKey.TEMPERATURE03: {TYPE: float, VALUE: 20.9255},
        XR_420SampleDataParticleKey.TEMPERATURE04: {TYPE: float, VALUE: 21.1266},
        XR_420SampleDataParticleKey.TEMPERATURE05: {TYPE: float, VALUE: 21.1341},
        XR_420SampleDataParticleKey.TEMPERATURE06: {TYPE: float, VALUE: 21.5606},
        XR_420SampleDataParticleKey.TEMPERATURE07: {TYPE: float, VALUE: 21.2156},
        XR_420SampleDataParticleKey.TEMPERATURE08: {TYPE: float, VALUE: 21.4749},
        XR_420SampleDataParticleKey.TEMPERATURE09: {TYPE: float, VALUE: 21.3044},
        XR_420SampleDataParticleKey.TEMPERATURE10: {TYPE: float, VALUE: 21.1320},
        XR_420SampleDataParticleKey.TEMPERATURE11: {TYPE: float, VALUE: 21.1798},
        XR_420SampleDataParticleKey.TEMPERATURE12: {TYPE: float, VALUE: 21.2352},
        XR_420SampleDataParticleKey.TEMPERATURE13: {TYPE: float, VALUE: 21.3488},
        XR_420SampleDataParticleKey.TEMPERATURE14: {TYPE: float, VALUE: 21.1214},
        XR_420SampleDataParticleKey.TEMPERATURE15: {TYPE: float, VALUE: 21.6426},
        XR_420SampleDataParticleKey.TEMPERATURE16: {TYPE: float, VALUE: 21.1479},
        XR_420SampleDataParticleKey.TEMPERATURE17: {TYPE: float, VALUE: 21.0069},
        XR_420SampleDataParticleKey.TEMPERATURE18: {TYPE: float, VALUE: 21.5426},
        XR_420SampleDataParticleKey.TEMPERATURE19: {TYPE: float, VALUE: 21.3204},
        XR_420SampleDataParticleKey.TEMPERATURE20: {TYPE: float, VALUE: 21.2402},
        XR_420SampleDataParticleKey.TEMPERATURE21: {TYPE: float, VALUE: 21.3968},
        XR_420SampleDataParticleKey.TEMPERATURE22: {TYPE: float, VALUE: 21.4371},
        XR_420SampleDataParticleKey.TEMPERATURE23: {TYPE: float, VALUE: 21.0411},
        XR_420SampleDataParticleKey.TEMPERATURE24: {TYPE: float, VALUE: 21.4361},
        XR_420SampleDataParticleKey.BATTERY_VOLTAGE: {TYPE: float, VALUE: 11.5916},
        XR_420SampleDataParticleKey.SERIAL_NUMBER: {TYPE: unicode, VALUE: u"021964"},
    }

    SAMPLE = \
        "TIM 020225135300 " + \
        "21.4548 21.0132 20.9255 21.1266 21.1341 21.5606 21.2156 21.4749 " + \
        "21.3044 21.1320 21.1798 21.2352 21.3488 21.1214 21.6426 21.1479 " + \
        "21.0069 21.5426 21.3204 21.2402 21.3968 21.4371 21.0411 21.4361 " + \
        "BV: 11.5916 SN: 021964 FET"

    def assert_particle_sample(self, data_particle, verify_values=False):
        """
        Verify a take sample data particle
        @param data_particle:  data particle
        @param verify_values:  bool, should we verify parameter values
        """
        self.assert_data_particle_header(data_particle, DataParticleType.SAMPLE)
        self.assert_data_particle_parameters(data_particle, self._sample_parameters, verify_values)

    def assert_engineering_data_particle_header(self, data_particle, stream_name):
        # Verify a engineering data particle header is formatted properly w/o port agent timestamp
        # @param data_particle: version 1 data particle
        # @param stream_name: version 1 data particle

        sample_dict = self.convert_data_particle_to_dict(data_particle)
        log.debug("assert_engineering_data_particle_header: SAMPLEDICT = %s" % sample_dict)

        self.assertTrue(sample_dict[DataParticleKey.STREAM_NAME], stream_name)
        self.assertTrue(sample_dict[DataParticleKey.PKT_FORMAT_ID], DataParticleValue.JSON_DATA)
        self.assertTrue(sample_dict[DataParticleKey.PKT_VERSION], 1)
        self.assertIsInstance(sample_dict[DataParticleKey.VALUES], list)

        self.assertTrue(sample_dict.get(DataParticleKey.PREFERRED_TIMESTAMP))

        self.assertIsNotNone(sample_dict.get(DataParticleKey.DRIVER_TIMESTAMP))
        self.assertIsInstance(sample_dict.get(DataParticleKey.DRIVER_TIMESTAMP), float)

    def assert_particle_engineering(self, data_particle, verify_values=True):
        """
        Verify an engineering data particle
        @param data_particle:  status data particle
        @param verify_values:  bool, should we verify parameter values
        """
        self.assert_engineering_data_particle_header(data_particle, DataParticleType.ENGINEERING)
        self.assert_data_particle_parameters(data_particle, self._engineering_parameters, verify_values)

#################################### RULES ####################################
#                                                                             #
# Common capabilities in the base class                                       #
#                                                                             #
# Instrument specific stuff in the derived class                              #
#                                                                             #
# Generator spits out either stubs or comments describing test this here,     #
# test that there.                                                            #
#                                                                             #
# Qualification tests are driven through the instrument_agent                 #
#                                                                             #
###############################################################################

###############################################################################
#                                UNIT TESTS                                   #
#         Unit tests test the method calls and parameters using Mock.         #
###############################################################################

@attr('UNIT', group='mi')
class TestUNIT(InstrumentDriverUnitTestCase, UtilMixin):
    """Unit Test Container"""

    def setUp(self):
        InstrumentDriverUnitTestCase.setUp(self)

    def assert_engineering_particle_published(self, particle_assert_method, verify_values=False):
        """
        Verify that we can send data through the port agent and the the correct particles
        are generated.

        Create a port agent packet, send it through got_data, then finally grab the data particle
        from the data particle queue and verify it using the passed in assert method.
        @param particle_assert_method: assert method to validate the data particle.
        @param verify_values: Should we validate values?
        """
        # Find all particles of the correct data particle types (not raw)
        particles = []
        for p in self._data_particle_received:
            particle_dict = json.loads(p)
            stream_type = particle_dict.get('stream_name')
            self.assertIsNotNone(stream_type)
            if stream_type == DataParticleType.ENGINEERING:
                particles.append(p)

        log.debug("status particles: %s " % particles)
        self.assertEqual(len(particles), 1)

        # Verify the data particle
        particle_assert_method(particles.pop(), verify_values)

    def test_driver_enums(self):
        """
        Verify that all driver enumerations have no duplicate values that might cause confusion.  Also
        do a little extra validation for the Capabilities
        """
        self.assert_enum_has_no_duplicates(ScheduledJob())
        self.assert_enum_has_no_duplicates(DataParticleType())
        self.assert_enum_has_no_duplicates(InstrumentResponses())
        self.assert_enum_has_no_duplicates(InstrumentCommands())
        self.assert_enum_has_no_duplicates(ProtocolStates())
        self.assert_enum_has_no_duplicates(ProtocolEvent())
        self.assert_enum_has_no_duplicates(InstrumentParameters())
        self.assert_enum_has_no_duplicates(AdvancedFunctionsParameters())
        self.assert_enum_has_no_duplicates(AdvancedFunctionsBits())

        # Test capabilities for duplicates, then verify that capabilities is a subset of protocol events
        self.assert_enum_has_no_duplicates(Capability())
        self.assert_enum_complete(Capability(), ProtocolEvent())

    def test_driver_schema(self):
        """
        get the driver schema and verify it is configured properly
        """
        driver = InstrumentDriver(self._got_data_event_callback)
        self.assert_driver_schema(driver, self._driver_parameters, self._driver_capabilities)

    def test_chunker(self):
        """
        Test the chunker and verify the particles created.
        """
        chunker = StringChunker(InstrumentProtocol.chunker_sieve_function)

        self.assert_chunker_sample(chunker, self.SAMPLE)
        self.assert_chunker_sample_with_noise(chunker, self.SAMPLE)
        self.assert_chunker_fragmented_sample(chunker, self.SAMPLE)
        self.assert_chunker_combined_sample(chunker, self.SAMPLE)

    def test_corrupt_data_sample(self):
        # garbage is not okay
        particle = XR_420SampleDataParticle(self.SAMPLE.replace('020225135300', 'foobar'),
                                            port_timestamp=3558720820.531179)
        with self.assertRaises(SampleException):
            particle.generate()

    @unittest.skip("skip because calibration coefficients had been changed.")
    def test_engineering_particle(self):
        """
        Verify driver produces the correct engineering data particle
        """
        driver = InstrumentDriver(self._got_data_event_callback)
        self.assert_initialize_driver(driver, ProtocolStates.COMMAND)

        # mock the _update_params() method which tries to get parameters from an actual instrument
        _update_params_mock = Mock(spec="_update_params")
        driver._protocol._update_params = _update_params_mock

        # load the engineering parameter values
        pd = driver._protocol._param_dict
        for name in self._raw_coefficients.keys():
            pd.update(self._raw_coefficients[name], target_params=name)

        # clear out any old events
        self.clear_data_particle_queue()

        # call the method in the driver that generates and sends the status data particle
        driver._protocol._generate_status_event()

        # check that the status data particle was published
        self.assert_engineering_particle_published(self.assert_particle_engineering, verify_values=True)

    def test_got_data(self):
        """
        Verify sample data passed through the got data method produces the correct data particles
        """
        # Create and initialize the instrument driver with a mock port agent
        driver = InstrumentDriver(self._got_data_event_callback)
        self.assert_initialize_driver(driver)    # defaults to autosample mode, so sample generated

        self.assert_raw_particle_published(driver, True)

        # validate data particle
        self.assert_particle_published(driver, self.SAMPLE, self.assert_particle_sample, True)

    def test_protocol_filter_capabilities(self):
        """
        This tests driver filter_capabilities.
        Iterate through available capabilities, and verify that they can pass successfully through the filter.
        Test silly made up capabilities to verify they are blocked by filter.
        """
        my_event_callback = Mock(spec="UNKNOWN WHAT SHOULD GO HERE FOR evt_callback")
        protocol = InstrumentProtocol(InstrumentResponses, NEWLINE, my_event_callback)
        driver_capabilities = Capability().list()
        test_capabilities = Capability().list()

        # Add a bogus capability that will be filtered out.
        test_capabilities.append("BOGUS_CAPABILITY")

        # Verify "BOGUS_CAPABILITY was filtered out
        self.assertEquals(driver_capabilities, protocol._filter_capabilities(test_capabilities))

    def test_driver_parameters(self):
        """
        Verify the set of parameters known by the driver
        """
        driver = InstrumentDriver(self._got_data_event_callback)
        self.assert_initialize_driver(driver, ProtocolStates.COMMAND)

        expected_parameters = sorted(self._driver_parameters.keys())
        reported_parameters = sorted(driver.get_resource(InstrumentParameters.ALL))

        log.debug("Reported Parameters: %s" % reported_parameters)
        log.debug("Expected Parameters: %s" % expected_parameters)

        self.assertEqual(reported_parameters, expected_parameters)

        # Verify the parameter definitions
        self.assert_driver_parameter_definition(driver, self._driver_parameters)

    def test_capabilities(self):
        """
        Verify the FSM reports capabilities as expected.  All states defined in this dict must
        also be defined in the protocol FSM.
        """
        capabilities = {
            ProtocolStates.UNKNOWN: ['DRIVER_EVENT_DISCOVER',
                                     'DRIVER_EVENT_GET'],
            ProtocolStates.COMMAND: ['DRIVER_EVENT_ACQUIRE_STATUS',
                                     'DRIVER_EVENT_CLOCK_SYNC',
                                     'DRIVER_EVENT_GET',
                                     'DRIVER_EVENT_SET',
                                     'DRIVER_EVENT_START_AUTOSAMPLE',
                                     'DRIVER_EVENT_START_DIRECT'],
            ProtocolStates.AUTOSAMPLE: ['DRIVER_EVENT_STOP_AUTOSAMPLE',
                                        'PROTOCOL_EVENT_SCHEDULED_ACQUIRE_STATUS',
                                        'DRIVER_EVENT_SCHEDULED_CLOCK_SYNC',
                                        'DRIVER_EVENT_GET'],
            ProtocolStates.DIRECT_ACCESS: ['DRIVER_EVENT_STOP_DIRECT',
                                           'EXECUTE_DIRECT']
        }

        driver = InstrumentDriver(self._got_data_event_callback)
        self.assert_capabilities(driver, capabilities)

    def test_parse_status(self):
        status = "Logger status 00"

        driver = InstrumentDriver(self._got_data_event_callback)
        self.assert_initialize_driver(driver)

        driver._protocol._parse_status_response(status, None)

        config = driver._protocol._param_dict.get_all()
        log.debug(config)

###############################################################################
#                            INTEGRATION TESTS                                #
#     Integration test test the direct driver / instrument interaction        #
#     but making direct calls via zeromq.                                     #
#     - Common Integration tests test the driver through the instrument agent #
#     and common for all drivers (minimum requirement for ION ingestion)       #
###############################################################################

@attr('INT', group='mi')
class TestINT(InstrumentDriverIntegrationTestCase, UtilMixin):
    """Integration Test Container"""

    def _is_time_set(self, time_param, expected_time, time_format="%d %b %Y %H:%M:%S", tolerance=3):
        """
        Verify is what we expect it to be within a given tolerance
        @param time_param: driver parameter
        @param expected_time: what the time should be in seconds since unix epoch or formatted time string
        @param time_format: date time format
        @param tolerance: how close to the set time should the get be?
        """

        result_time = self.assert_get(time_param)
        result_time_struct = time.strptime(result_time, time_format)
        converted_time = (result_time_struct)

        if isinstance(expected_time, float):
            expected_time_struct = time.localtime(expected_time)
        else:
            # convert time struct to string and back again to get around DST issue so that
            # time is interpreted the same for both the instrument and test
            expected_time_struct = time.strptime(time.strftime(time_format, expected_time), time_format)

        log.debug("Current Time: %s, Expected Time: %s", time.strftime("%d %b %y %H:%M:%S", result_time_struct),
                  time.strftime("%d %b %y %H:%M:%S", expected_time_struct))

        log.debug("Current Time: %s, Expected Time: %s, Tolerance: %s",
                  converted_time, timegm_to_float(expected_time_struct), tolerance)

        # Verify the clock is set within the tolerance
        return abs(converted_time - timegm_to_float(expected_time_struct)) <= tolerance

    def assert_clock_set(self, time_param, sync_clock_cmd=DriverEvent.CLOCK_SYNC, timeout=20, tolerance=3):
        """
        Verify the clock is set to at least the current date
        """
        log.debug("verify clock is set to the current time")

        timeout_time = time.time() + timeout

        while not self._is_time_set(time_param, time.gmtime(), tolerance=tolerance):
            log.debug("time isn't current. sleep for a bit")
            time.sleep(2)

            # Run acquire status command to set clock parameter
            self.assert_driver_command(sync_clock_cmd)

            log.debug("T: %s T: %s", time.time(), timeout_time)
            self.assertLess(time.time(), timeout_time, msg="Timeout waiting for clock sync event")

    def assert_initialize_driver_unspecific(self):
        """
        Walk an uninitialized driver through it's initialize process.
        """
        # Test the driver is in state unconfigured.
        self.assert_current_state(DriverConnectionState.UNCONFIGURED)

        # Configure driver for comms and transition to disconnected.
        self.driver_client.cmd_dvr('configure', self.port_agent_comm_config())

        # Test the driver is configured for comms.
        self.assert_current_state(DriverConnectionState.DISCONNECTED)

        self.driver_client.cmd_dvr('connect')

        # Test the driver is in unknown state.
        self.assert_current_state(DriverProtocolState.UNKNOWN)

        self.driver_client.cmd_dvr('discover_state')

        state = self.driver_client.cmd_dvr('get_resource_state')
        log.debug("initialize final state: %s" % state)

    def _assert_parameters_on_initialization(self):
        self.assert_initialize_driver_unspecific()
        reply = self.driver_client.cmd_dvr('get_resource', InstrumentParameters.ALL)
        self.assert_parameters(reply, self._driver_parameters, True)
        return reply

    def test_instrument_wakeup(self):
        """
        @brief Test for instrument wakeup, expects instrument to be in 'command' state
        """
        self.assert_initialize_driver()

    def test_get_parameters(self):
        """
        Test driver parameters and verify their type.  Startup parameters also verify the parameter
        value.  This test confirms that parameters are being read/converted properly and that
        the startup has been applied.
        """
        reply = self._assert_parameters_on_initialization()
        for (name, value) in reply.iteritems():
            log.debug("test_get_parameters: name=%s, value=%s", name, str(value))

    def test_set_clock(self):
        """
        Test device clock, needs to be close but not an exact match.
        """
        self.assert_initialize_driver()
        self.assert_driver_command(ProtocolEvent.CLOCK_SYNC)

    def test_set(self):
        """
        Test device parameter access, needs to be an exact match.
        """
        self.assert_initialize_driver()

        # parameter values to test.
        test_values = {
            InstrumentParameters.SAMPLE_INTERVAL : '00:00:15',
            InstrumentParameters.POWER_ALWAYS_ON : 1,
            InstrumentParameters.INHIBIT_DATA_STORAGE : 1,
        }

        # Set parameters in bulk and verify.
        self.assert_set_bulk(test_values)

        # Verify single sets, we first set to the current value to verify
        # a config update event IS NOT sent.  Then change the value and
        # watch for an config update event.
        self.assert_set(InstrumentParameters.POWER_ALWAYS_ON, 1)
        self.assert_set(InstrumentParameters.POWER_ALWAYS_ON, 0)

        self.assert_set(InstrumentParameters.INHIBIT_DATA_STORAGE, 1)
        self.assert_set(InstrumentParameters.INHIBIT_DATA_STORAGE, 0)

        self.assert_set(InstrumentParameters.SAMPLE_INTERVAL, '01:00:15')
        self.assert_set(InstrumentParameters.SAMPLE_INTERVAL, '01:00:20')

    def test_set_errors(self):
        """
        Test error device parameter access.
        """
        self.assert_initialize_driver()

        # try a parameter that shouldn't exist
        self.assert_set_exception('bogus', 'nada')

        # try values that are not legitimate for each parameter
        self.assert_set_exception(InstrumentParameters.POWER_ALWAYS_ON, 'bad')
        self.assert_set_exception(InstrumentParameters.POWER_ALWAYS_ON, 2)

        self.assert_set_exception(InstrumentParameters.INHIBIT_DATA_STORAGE, 'bad')
        self.assert_set_exception(InstrumentParameters.INHIBIT_DATA_STORAGE, -1)

        self.assert_set_exception(InstrumentParameters.SIX_HZ_PROFILING_MODE, 'really bad')
        self.assert_set_exception(InstrumentParameters.SIX_HZ_PROFILING_MODE, -20)

        self.assert_set_exception(InstrumentParameters.SAMPLE_INTERVAL, '11:18:61')
        self.assert_set_exception(InstrumentParameters.SAMPLE_INTERVAL, '25:18:61')
        self.assert_set_exception(InstrumentParameters.SAMPLE_INTERVAL, '11:118:61')
        self.assert_set_exception(InstrumentParameters.SAMPLE_INTERVAL, 3)

    def test_read_only_parameters(self):
        self.assert_initialize_driver()

        self.assert_set_readonly(InstrumentParameters.STATUS)
        self.assert_set_readonly(InstrumentParameters.AUTO_RUN)
        self.assert_set_readonly(InstrumentParameters.IDENTIFICATION)
        self.assert_set_readonly(InstrumentParameters.BATTERY_VOLTAGE)
        self.assert_set_readonly(InstrumentParameters.LOGGER_DATE_AND_TIME)
        self.assert_set_readonly(InstrumentParameters.START_DATE_AND_TIME)
        self.assert_set_readonly(InstrumentParameters.END_DATE_AND_TIME)
        self.assert_set_readonly(InstrumentParameters.OUTPUT_INCLUDES_SERIAL_NUMBER)
        self.assert_set_readonly(InstrumentParameters.OUTPUT_INCLUDES_BATTERY_VOLTAGE)
        self.assert_set_readonly(InstrumentParameters.SAMPLING_LED)
        self.assert_set_readonly(InstrumentParameters.ENGINEERING_UNITS_OUTPUT)
        self.assert_set_readonly(InstrumentParameters.CALIBRATION_COEFFICIENTS_CHANNEL_1)
        self.assert_set_readonly(InstrumentParameters.CALIBRATION_COEFFICIENTS_CHANNEL_2)
        self.assert_set_readonly(InstrumentParameters.CALIBRATION_COEFFICIENTS_CHANNEL_3)
        self.assert_set_readonly(InstrumentParameters.CALIBRATION_COEFFICIENTS_CHANNEL_4)
        self.assert_set_readonly(InstrumentParameters.CALIBRATION_COEFFICIENTS_CHANNEL_5)
        self.assert_set_readonly(InstrumentParameters.CALIBRATION_COEFFICIENTS_CHANNEL_6)
        self.assert_set_readonly(InstrumentParameters.CALIBRATION_COEFFICIENTS_CHANNEL_7)
        self.assert_set_readonly(InstrumentParameters.CALIBRATION_COEFFICIENTS_CHANNEL_8)
        self.assert_set_readonly(InstrumentParameters.CALIBRATION_COEFFICIENTS_CHANNEL_9)
        self.assert_set_readonly(InstrumentParameters.CALIBRATION_COEFFICIENTS_CHANNEL_10)
        self.assert_set_readonly(InstrumentParameters.CALIBRATION_COEFFICIENTS_CHANNEL_11)
        self.assert_set_readonly(InstrumentParameters.CALIBRATION_COEFFICIENTS_CHANNEL_12)
        self.assert_set_readonly(InstrumentParameters.CALIBRATION_COEFFICIENTS_CHANNEL_13)
        self.assert_set_readonly(InstrumentParameters.CALIBRATION_COEFFICIENTS_CHANNEL_14)
        self.assert_set_readonly(InstrumentParameters.CALIBRATION_COEFFICIENTS_CHANNEL_15)
        self.assert_set_readonly(InstrumentParameters.CALIBRATION_COEFFICIENTS_CHANNEL_16)
        self.assert_set_readonly(InstrumentParameters.CALIBRATION_COEFFICIENTS_CHANNEL_17)
        self.assert_set_readonly(InstrumentParameters.CALIBRATION_COEFFICIENTS_CHANNEL_18)
        self.assert_set_readonly(InstrumentParameters.CALIBRATION_COEFFICIENTS_CHANNEL_19)
        self.assert_set_readonly(InstrumentParameters.CALIBRATION_COEFFICIENTS_CHANNEL_20)
        self.assert_set_readonly(InstrumentParameters.CALIBRATION_COEFFICIENTS_CHANNEL_21)
        self.assert_set_readonly(InstrumentParameters.CALIBRATION_COEFFICIENTS_CHANNEL_22)
        self.assert_set_readonly(InstrumentParameters.CALIBRATION_COEFFICIENTS_CHANNEL_23)
        self.assert_set_readonly(InstrumentParameters.CALIBRATION_COEFFICIENTS_CHANNEL_24)

    def test_startup_params(self):
        """
        Verify that startup parameters are applied correctly. Generally this
        happens in the driver discovery method.
        """

        # Change the values of these parameters to something before the
        # driver is re-initialized.  They should be blown away with startup values.
        new_values = {
            InstrumentParameters.SAMPLE_INTERVAL: '00:00:20',
            InstrumentParameters.POWER_ALWAYS_ON: 0,
            InstrumentParameters.INHIBIT_DATA_STORAGE: 0,
        }

        # test in command mode
        self._assert_parameters_on_initialization()

        # test in autosample mode
        # set parameters to something other than startup values
        self.assert_set_bulk(new_values)
        self.assert_driver_command(ProtocolEvent.START_AUTOSAMPLE, state=ProtocolStates.AUTOSAMPLE, delay=1)
        # Force a re-apply startup parameters
        self.driver_client.cmd_dvr('apply_startup_params')
        # Should be back to our startup parameters.
        reply = self.driver_client.cmd_dvr('get_resource', DriverParameter.ALL)
        self.assert_parameters(reply, self._driver_parameters, True)

    def test_commands(self):
        """
        Run instrument commands from both command and streaming mode.
        """
        self.assert_initialize_driver()

        ####
        # First test in command mode
        ####
        self.assert_driver_command(ProtocolEvent.CLOCK_SYNC)
        self.assert_driver_command(ProtocolEvent.ACQUIRE_STATUS)
        self.assert_driver_command(ProtocolEvent.START_AUTOSAMPLE, state=ProtocolStates.AUTOSAMPLE, delay=1)
        self.assert_driver_command(ProtocolEvent.STOP_AUTOSAMPLE, state=ProtocolStates.COMMAND, delay=1)

        ####
        # Test in streaming mode
        ####
        # Put us in streaming
        self.assert_driver_command(ProtocolEvent.START_AUTOSAMPLE, state=ProtocolStates.AUTOSAMPLE, delay=1)
        self.assert_driver_command(ProtocolEvent.CLOCK_SYNC)
        self.assert_driver_command(ProtocolEvent.ACQUIRE_STATUS)
        self.assert_driver_command(ProtocolEvent.STOP_AUTOSAMPLE, state=ProtocolStates.COMMAND, delay=1)

        ####
        # Test a bad command
        ####
        self.assert_driver_command_exception('ima_bad_command', exception_class=InstrumentCommandException)

    def test_instrument_start_stop_autosample(self):
        """
        @brief Test for start/stop of instrument autosample, puts instrument in 'command' state first
        """
        self.assert_initialize_driver()

        log.debug('test_instrument_start_stop_autosample: starting autosample')
        # start auto-sample.
        self.driver_client.cmd_dvr('execute_resource', ProtocolEvent.START_AUTOSAMPLE)

        # Test the driver is in autosample mode.
        state = self.driver_client.cmd_dvr('get_resource_state')
        self.assertEqual(state, ProtocolStates.AUTOSAMPLE)
        log.debug('test_instrument_start_stop_autosample: autosample started')

        log.debug('test_instrument_start_stop_autosample: stopping autosample')
        # stop auto-sample.
        self.driver_client.cmd_dvr('execute_resource', ProtocolEvent.STOP_AUTOSAMPLE)

        # Test the driver is in command mode.
        state = self.driver_client.cmd_dvr('get_resource_state')
        self.assertEqual(state, ProtocolStates.COMMAND)
        log.debug('test_instrument_start_stop_autosample: autosample stopped')

    def test_instrument_autosample_samples(self):
        """
        @brief Test for putting instrument in 'auto-sample' state and receiving samples
        """
        self.assert_initialize_driver()

        # command the instrument to auto-sample mode.
        self.driver_client.cmd_dvr('execute_resource', ProtocolEvent.START_AUTOSAMPLE)

        self.assert_current_state(ProtocolStates.AUTOSAMPLE)

        # wait for some samples to be generated
        log.debug('test_instrument_start_stop_autosample: waiting 45 seconds for samples')
        gevent.sleep(45)

        # Verify we received at least 2 samples.
        sample_events = [evt for evt in self.events if evt['type'] == DriverAsyncEvent.SAMPLE]
        log.debug('test_instrument_start_stop_autosample: # 0f samples = %d', len(sample_events))
        for sample in sample_events:
            if sample['value'].find(DataParticleType.SAMPLE) != -1:
                log.debug('parsed sample=%s\n', sample)
                sample_dict = eval(sample['value'])     # turn string into dictionary
                values = sample_dict['values']          # get particle dictionary
                # pull timestamp out of particle
                ntp_timestamp = [item for item in values if item["value_id"] == "timestamp"][0]['value']
                float_timestamp = ntplib.ntp_to_system_time(ntp_timestamp)
                log.debug('dt=%s', time.ctime(float_timestamp))
        self.assertTrue(len(sample_events) >= 2)

        # stop autosample and return to command mode
        self.driver_client.cmd_dvr('execute_resource', ProtocolEvent.STOP_AUTOSAMPLE)

        self.assert_current_state(ProtocolStates.COMMAND)

    def test_command_autosample(self):
        """
        Verify autosample command and events.
        1. initialize the instrument to COMMAND state
        2. command the instrument to AUTOSAMPLE state
        3. verify the particle coming in and the sampling is continuous (gather several samples)
        4. stop AUTOSAMPLE
        """
        self.assert_initialize_driver(ProtocolStates.COMMAND)
        self.assert_driver_command(ProtocolEvent.START_AUTOSAMPLE, state=ProtocolStates.AUTOSAMPLE, delay=1)
        self.assert_async_particle_generation(DataParticleType.SAMPLE, self.assert_particle_sample,
                                              particle_count=2, timeout=60)

        self.assert_driver_command(ProtocolEvent.STOP_AUTOSAMPLE, state=ProtocolStates.COMMAND, delay=10)

    def test_polled_particle_generation(self):
        """
        Test that we can generate particles with commands
        """
        self.assert_initialize_driver()

        self.assert_particle_generation(ProtocolEvent.ACQUIRE_STATUS, DataParticleType.ENGINEERING, self.assert_particle_engineering, delay=10)

    ###
    #   Test scheduled events
    ###

    def assert_acquire_status(self):
        """
        Verify a status particle was generated
        """
        self.clear_events()
        self.assert_async_particle_generation(DataParticleType.ENGINEERING, self.assert_particle_engineering, timeout=120)

    def test_scheduled_device_status_command(self):
        """
        Verify the device status command can be triggered and run in command
        """
        self.assert_scheduled_event(ScheduledJob.ACQUIRE_STATUS, self.assert_acquire_status, delay=30)
        self.assert_current_state(ProtocolStates.COMMAND)

    def test_scheduled_device_status_autosample(self):
        """
        Verify the device status command can be triggered and run in autosample
        """
        self.assert_scheduled_event(ScheduledJob.ACQUIRE_STATUS, self.assert_acquire_status,
                                    autosample_command=ProtocolEvent.START_AUTOSAMPLE, delay=60)
        self.assert_current_state(ProtocolStates.AUTOSAMPLE)
        self.assert_driver_command(ProtocolEvent.STOP_AUTOSAMPLE)

    def test_scheduled_clock_sync_command(self):
        """
        Verify the scheduled clock sync is triggered and functions as expected
        """
        timeout = 85
        self.assert_scheduled_event(ScheduledJob.CLOCK_SYNC, delay=timeout)
        self.assert_current_state(ProtocolStates.COMMAND)

        # Check the clock until it is set correctly (by a scheduled event)
        self.assert_clock_set(InstrumentParameters.LOGGER_DATE_AND_TIME)

    def test_scheduled_clock_sync_autosample(self):
        """
        Verify the scheduled clock sync is triggered and functions as expected
        """
        timeout = 240
        self.assert_scheduled_event(ScheduledJob.CLOCK_SYNC, delay=timeout)
        self.assert_current_state(ProtocolStates.COMMAND)

        self.assert_driver_command(ProtocolEvent.START_AUTOSAMPLE)

        # Check the clock until it is set correctly (by a scheduled event)
        self.assert_clock_set(InstrumentParameters.LOGGER_DATE_AND_TIME)
        self.assert_driver_command(ProtocolEvent.STOP_AUTOSAMPLE)

###############################################################################
#                            QUALIFICATION TESTS                              #
# Device specific qualification tests are for                                 #
# testing device specific capabilities                                        #
###############################################################################

@attr('QUAL', group='mi')
class TestQUAL(InstrumentDriverQualificationTestCase, UtilMixin):
    """Qualification Test Container"""

    # Qualification tests live in the base class.  This class is extended
    # here so that when running this test from 'nosetests' all tests
    # (UNIT, INT, and QUAL) are run.

    def test_direct_access_telnet_mode(self):
        """
        Test that we can connect to the instrument via direct access.  Also
        verify that direct access parameters are reset on exit.
        """
        self.assert_enter_command_mode()

        # go into direct access, and muck up a setting.
        self.assert_direct_access_start_telnet(timeout=600)
        self.assertTrue(self.tcp_client)
        self.tcp_client.send_data("AA")
        self.assertTrue(self.tcp_client.expect("RBR XR-420 6.810 021964"))

        self.assert_direct_access_stop_telnet()

    def test_direct_access_exit_from_autosample(self):
        """
        Test that we can connect to the instrument via direct access, then exit
        after the instrument goes into autosample mode.
        """
        self.assert_enter_command_mode()

        # go into direct access, and muck up a setting.
        self.assert_direct_access_start_telnet(timeout=600)
        self.assertTrue(self.tcp_client)
        self.tcp_client.send_data("")

        self.assert_direct_access_stop_telnet()

    def test_parameter_enum(self):
        """
        @ brief InstrumentParameters enum test

            1. test that InstrumentParameters matches the expected enums from DriverParameter.
            2. test that multiple distinct parameters do not resolve back to the same string.
        """

        self.assertEqual(InstrumentParameters.ALL, DriverParameter.ALL)

        self.assert_enum_has_no_duplicates(DriverParameter)
        self.assert_enum_has_no_duplicates(InstrumentParameters)

    def test_protocol_state_enum(self):
        """
        @ brief ProtocolState enum test

            1. test that ProtocolState matches the expected enums from DriverProtocolState.
            2. test that multiple distinct states do not resolve back to the same string.

        """

        self.assertEqual(ProtocolStates.UNKNOWN, DriverProtocolState.UNKNOWN)
        self.assertEqual(ProtocolStates.COMMAND, DriverProtocolState.COMMAND)
        self.assertEqual(ProtocolStates.AUTOSAMPLE, DriverProtocolState.AUTOSAMPLE)
        self.assertEqual(ProtocolStates.DIRECT_ACCESS, DriverProtocolState.DIRECT_ACCESS)

        self.assert_enum_has_no_duplicates(DriverProtocolState)
        self.assert_enum_has_no_duplicates(ProtocolStates)

    def test_protocol_event_enum(self):
        """
        @brief ProtocolEvent enum test

            1. test that ProtocolEvent matches the expected enums from DriverProtocolState.
            2. test that multiple distinct events do not resolve back to the same string.
        """

        self.assertEqual(ProtocolEvent.ENTER, DriverEvent.ENTER)
        self.assertEqual(ProtocolEvent.EXIT, DriverEvent.EXIT)
        self.assertEqual(ProtocolEvent.GET, DriverEvent.GET)
        self.assertEqual(ProtocolEvent.SET, DriverEvent.SET)
        self.assertEqual(ProtocolEvent.DISCOVER, DriverEvent.DISCOVER)
        self.assertEqual(ProtocolEvent.START_AUTOSAMPLE, DriverEvent.START_AUTOSAMPLE)
        self.assertEqual(ProtocolEvent.STOP_AUTOSAMPLE, DriverEvent.STOP_AUTOSAMPLE)
        self.assertEqual(ProtocolEvent.EXECUTE_DIRECT, DriverEvent.EXECUTE_DIRECT)
        self.assertEqual(ProtocolEvent.START_DIRECT, DriverEvent.START_DIRECT)
        self.assertEqual(ProtocolEvent.STOP_DIRECT, DriverEvent.STOP_DIRECT)

        self.assert_enum_has_no_duplicates(DriverEvent)
        self.assert_enum_has_no_duplicates(ProtocolEvent)

    def test_get_capabilities(self):
        """
        @brief Verify that the correct capabilities are returned from get_capabilities
        at various driver/agent states.
        """
        ##################
        #  Command Mode
        ##################

        capabilities = {
            AgentCapabilityType.AGENT_COMMAND: [
                ResourceAgentEvent.CLEAR,
                ResourceAgentEvent.RESET,
                ResourceAgentEvent.GO_DIRECT_ACCESS,
                ResourceAgentEvent.GO_INACTIVE,
                ResourceAgentEvent.PAUSE
            ],
            AgentCapabilityType.AGENT_PARAMETER: self._common_agent_parameters(),
            AgentCapabilityType.RESOURCE_COMMAND: [
                DriverEvent.CLOCK_SYNC,
                DriverEvent.ACQUIRE_STATUS,
                DriverEvent.START_AUTOSAMPLE,
            ],
            AgentCapabilityType.RESOURCE_INTERFACE: None,
            AgentCapabilityType.RESOURCE_PARAMETER: self._driver_parameters.keys()
        }

        self.assert_enter_command_mode()
        self.assert_capabilities(capabilities)

        ##################
        #  Streaming Mode
        ##################

        capabilities[AgentCapabilityType.AGENT_COMMAND] = [ResourceAgentEvent.RESET, ResourceAgentEvent.GO_INACTIVE]
        capabilities[AgentCapabilityType.RESOURCE_COMMAND] = [
            DriverEvent.CLOCK_SYNC,
            DriverEvent.ACQUIRE_STATUS,
            DriverEvent.STOP_AUTOSAMPLE,
        ]

        self.assert_start_autosample()
        self.assert_capabilities(capabilities)
        self.assert_stop_autosample()

        #######################
        #  Uninitialized Mode
        #######################

        capabilities[AgentCapabilityType.AGENT_COMMAND] = [ResourceAgentEvent.INITIALIZE]
        capabilities[AgentCapabilityType.RESOURCE_COMMAND] = []
        capabilities[AgentCapabilityType.RESOURCE_INTERFACE] = []
        capabilities[AgentCapabilityType.RESOURCE_PARAMETER] = []

        self.assert_reset()
        self.assert_capabilities(capabilities)

    def test_sample_autosample(self):
        self.assert_enter_command_mode()
        self.assert_start_autosample()

        self.assert_sample_async(self.assert_particle_sample, DataParticleType.SAMPLE, timeout=30, sample_count=1)

    def test_poll(self):
        """
        Verify that we can poll for an engineering particle.
        """
        self.assert_enter_command_mode()

        self.assert_particle_polled(ProtocolEvent.ACQUIRE_STATUS, self.assert_particle_engineering, DataParticleType.ENGINEERING, timeout=30)

###############################################################################
#                             PUBLICATION TESTS                               #
# Device specific publication tests are for                                    #
# testing device specific capabilities                                        #
###############################################################################
@attr('PUB', group='mi')
class TestPublish(InstrumentDriverPublicationTestCase, UtilMixin):
    def test_granule_generation(self):
        self.assert_initialize_driver()

        # Currently these tests only verify that the data granule is generated, but the values
        # are not tested.  We will eventually need to replace log.debug with a better callback
        # function that actually tests the granule.
        self.assert_sample_async("raw data", log.debug, DataParticleType.RAW, timeout=10)

        self.assert_sample_async(self.SAMPLE, log.debug, DataParticleType.SAMPLE, timeout=10)


text:
<!DOCTYPE html>

    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="description" content="">
    <meta name="author" content="">

    <title>Maria Schettino</title>

    <link href="css/bootstrap.min.css" rel="stylesheet">

    <link href="css/grayscale.css" rel="stylesheet">

    <link href="font-awesome-4.2.0/css/font-awesome.min.css" rel="stylesheet" type="text/css">
    <link href="http://fonts.googleapis.com/css?family=Lora:400,700,400italic,700italic" rel="stylesheet" type="text/css">
    <link href="http://fonts.googleapis.com/css?family=Montserrat:400,700" rel="stylesheet" type="text/css">

                <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-main-collapse">

                </button>

                      MARIA SCHETTINO

                        About

                        Drums

                        Music

                        Contact

About

Classically trained as a percussionist, Maria has been playing for more than twenty years. She studied Music Technology at NYU, ultimately focusing her attention on the kit and forming the rock band, Object.
As a private instructor, her teaching style emphasizes technical fundamentals and encourages creativity behind the kit.

Currently Maria is teaching in Brooklyn, NY

Play Maria's Drums

Music

Crawling<audio id="TheEvilUs" src="audio/Crawling.mp3"></audio>

Dead End<audio id="Psychic Fits"src="audio/deadend.mp3"></audio>

Tomorrowland<audio id="Object" src="audio/Tomorrowland.mp3"></audio>

                            Psychic Fits
                            Catskills
                            The Evil Us
                            Object

Contact

                    <input id="name-input" class="form-control contact-form" placeholder="NAME"></input>
                    <input id="email-input" class="form-control contact-form" placeholder="EMAIL"></input>

                    <textarea type="text" id="message-input" class="form-control message" placeholder="MESSAGE"></textarea>
                    <button id="contact-submit" class="btn btn-default">Submit</button>

                        mariatschettino@gmail.com

redpajama_set_name: RedPajamaGithub


text:
package org.brackit.server.tx.impl;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;

import org.brackit.server.tx.Tx;
import org.brackit.server.tx.TxID;

/**
 * Thread-safe transaction table for the ARIES restart procedure.
 *
 * @author Sebastian Baechle
 *
 */
class TxTable {
	private HashMap<TxID, TX> entries;

	private TaMgrImpl taMgr;

	TxTable(TaMgrImpl taMgr) {
		this.entries = new HashMap<TxID, TX>();
		this.taMgr = taMgr;
	}

	synchronized void remove(TxID txID) {
		entries.remove(txID);
	}

	synchronized void put(TxID txID, TX transaction) {
		TX current = entries.put(txID, transaction);

		if (current != null) {
			entries.put(txID, current);
			throw new RuntimeException(String.format(
					"A transaction with ID %s already exists.", txID));
		}
	}

	synchronized TX get(TxID txID) {
		return entries.get(txID);
	}

	synchronized TX getNextTransactionForUndo() {
		TX transaction = null;
		long nextUndoLSN = -1;

		for (TX entry : entries.values()) {
			if (entry.checkPrevLSN() > nextUndoLSN) {
				nextUndoLSN = entry.checkPrevLSN();
				transaction = entry;
			}
		}

		return transaction;
	}

	synchronized Collection<TX> getRolledbackLosers() {
		ArrayList<TX> rolledBackLosers = new ArrayList<TX>();

		for (TX entry : entries.values()) {
			if (entry.checkPrevLSN() == -1) {
				rolledBackLosers.add(entry);
			}
		}

		return rolledBackLosers;
	}

	synchronized Collection<TX> getTransactions() {
		return new ArrayList<TX>(entries.values());
	}

	public synchronized TxID getMaxTxID() {
		TxID maxTxID = null;

		for (TX entry : entries.values()) {
			if ((maxTxID == null) || entry.getID().compareTo(maxTxID) > 0) {
				maxTxID = entry.getID();
			}
		}

		return maxTxID;
	}

	public synchronized void clear() {
		entries.clear();
	}

	@Override
	public String toString() {
		StringBuffer out = new StringBuffer();
		for (Tx tx : getTransactions()) {
			out.append(tx);
			out.append("\n");
		}
		return out.toString();
	}
}


text:
function f(...args: any[]): void {
}

f `
\

`;

//// [taggedTemplateStringsWithMultilineTemplate.js]
var __makeTemplateObject = (this && this.__makeTemplateObject) || function (cooked, raw) {
    if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; }
    return cooked;
};
function f() {
    var args = [];
    for (var _i = 0; _i < arguments.length; _i++) {
        args[_i] = arguments[_i];
    }
}
f(__makeTemplateObject(["\n\n"], ["\n\\\n\n"]));


text:
<ns0:eml xmlns:ns0="eml://ecoinformatics.org/eml-2.1.0" xmlns:ns2="http://www.xml-cml.org/schema/stmml-1.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" packageId="knb-lter-ntl.25.8" system="https://pasta.lternet.edu" xsi:schemaLocation="eml://ecoinformatics.org/eml-2.1.0  http://nis.lternet.edu/schemas/EML/eml-2.1.0/eml.xsd">
  <access authSystem="https://pasta.lternet.edu/authentication" order="allowFirst" scope="document" system="https://pasta.lternet.edu">
    <allow>
      <principal>uid=NTL,o=LTER,dc=ecoinformatics,dc=org</principal>
      <permission>all</permission>
    </allow>
    <allow>
      <principal>public</principal>
      <permission>read</permission>
    </allow>
  </access>
  <dataset>
    <alternateIdentifier system="NTL-DEIMS">5717</alternateIdentifier>
    <shortName>NTLMP05</shortName>
    <title>North Temperate Lakes LTER: Macrophyte Biomass in Trout Lake Summary 1983 -
			current</title>
    <creator>
      <positionName>NTL LTER Lead PI</positionName>
      <organizationName>Center for Limnology</organizationName>
      <address>
        <deliveryPoint>680 North Park Str.</deliveryPoint>
        <city>Madison</city>
        <administrativeArea>WI</administrativeArea>
        <postalCode>53706</postalCode>
        <country>United States</country>
      </address>
      <electronicMailAddress>leadpi@lter.limnology.wisc.edu</electronicMailAddress>
    </creator>
    <creator>
      <organizationName>NTL LTER</organizationName>
      <address>
        <deliveryPoint>680 North Park Str.</deliveryPoint>
        <city>Madison</city>
        <administrativeArea>WI</administrativeArea>
        <postalCode>53706</postalCode>
        <country>United States</country>
      </address>
      <electronicMailAddress>infomgr@lter.limnology.wisc.edu</electronicMailAddress>
    </creator>
    <metadataProvider>
      <organizationName>North Temperate Lakes LTER</organizationName>
      <address>
        <deliveryPoint>Center for Limnology, UW Madison</deliveryPoint>
        <city>Madison</city>
        <administrativeArea>WI</administrativeArea>
        <postalCode>53706</postalCode>
        <country>United States</country>
      </address>
      <electronicMailAddress>infomgr@lter.limnology.wisc.edu</electronicMailAddress>
    </metadataProvider>
    <pubDate>2010</pubDate>
    <language>english</language>
    <abstract>
      <para>These data are collected to document and characterize the submersed macrophytes of Trout
				Lake, to evaluate the long-term stability of this component, and to interface with
				investigations of other compartments of the ecosystem. Four sites along the shoreline of
				Trout Lake have been sampled annually in August along permanent line transects. This dataset
				includes biomass per m2 for individual species summarized by depth along the transect.
				Derived data include the mean and standard deviation of macrophyte biomass. These data are
				useful in determining the annual variability of the submersed macrophytes and providing
				information on the effects of the invasion of an introduced crayfish. Sampling Frequency:
				annually during summer Number of sites: 4 </para>
    </abstract>
    <keywordSet>
      <keyword>biomass</keyword>
      <keyword>primary production</keyword>
      <keyword>species composition</keyword>
      <keywordThesaurus>LTER Keywords</keywordThesaurus>
    </keywordSet>
    <keywordSet>
      <keyword>NTL LTER</keyword>
      <keyword>North Temperate Lakes - LTER</keyword>
      <keyword>aquatic macroflora</keyword>
      <keyword>aquatic plant</keyword>
      <keyword>littoral zone</keyword>
      <keyword>macrophytes</keyword>
      <keywordThesaurus>NTL Keywords</keywordThesaurus>
    </keywordSet>
    <intellectualRights>

        <title>Data Policies</title>
        <para>Copyright Board of Regents, University of Wisconsin, Madison. This information is
					released to the public and may be used for academic, educational, or commercial purposes
					subject to the following restrictions: The Data User must realize that these data sets are
					being actively used by others for ongoing research and that coordination may be necessary
					to prevent duplicate publication. The Data User is urged to contact the NTL lead Principal
					Investigator, leadpi@lter.limnology.wisc.edu, to check on other uses of the data. Where
					appropriate, the Data User may be encouraged to consider collaboration and/or
					co-authorship with original investigators.</para>
        <para>The Data User must realize that the data may be misinterpreted if taken out of
					context. We request that you provide the NTL lead Principal Investigator, ATTN: Data
					Access, Center for Limnology, University of Wisconsin-Madison, 680 North Park St.,
					Madison, WI 53706 with a copy of any manuscript using the data so that it may be reviewed
					and comments provided on the presentation of our data.</para>
        <para>The Data User must acknowledge use of the data by an appropriate citation (see
					Citation) of the NTL-LTER database. A generic citation for our databases is: name of data
					set, North Temperate Lakes Long Term Ecological Research program, NSF, contact person for
					data set, Center for Limnology, University of Wisconsin-Madison. The data set name and
					contact person for each data set can be found in the metadata header of the online data
					sets.</para>
        <para>The Data User must send two reprints of any publications resulting from use of the
					data to the address above. We would like to include such manuscripts in our LTER
					publications list.</para>
        <para>The Data User must not redistribute original data and documentation without permission
					from Emily Stanley, lead Principal Investigator, (ehstanley@wisc.edu).</para>
        <para>While substantial efforts are made to ensure the accuracy of data and documentation,
					complete accuracy of data sets cannot be guaranteed. All data are made available "as is".
					The North Temperate Lakes LTER shall not be liable for damages resulting from any use or
					misinterpretation of data sets. Data users should be aware that we periodically update
					data sets.</para>
        <para>Our goal is to release all long term data associated with core research areas within 2
					years of collection. These data and accompanying metadata will be available for download
					from the NTL-LTER web site.</para>
        <para>By using these data, the Data User agrees to abide by the terms of this agreement.
					Thank you for your cooperation. </para>

    </intellectualRights>
    <distribution>
      <online>
        <url function="information">http://lter.limnology.wisc.edu/node/5717</url>
      </online>
    </distribution>
    <coverage>
      <geographicCoverage>
        <geographicDescription>Trout Lake, Vilas County, WI, USA </geographicDescription>
        <boundingCoordinates>
          <westBoundingCoordinate>-89.704</westBoundingCoordinate>
          <eastBoundingCoordinate>-89.647</eastBoundingCoordinate>
          <northBoundingCoordinate>46.079</northBoundingCoordinate>
          <southBoundingCoordinate>46.013</southBoundingCoordinate>
        </boundingCoordinates>
      </geographicCoverage>
      <temporalCoverage>
        <rangeOfDates>
          <beginDate>
            <calendarDate>1983-08-01</calendarDate>
          </beginDate>
          <endDate>
            <calendarDate>2009-12-31</calendarDate>
          </endDate>
        </rangeOfDates>
      </temporalCoverage>
    </coverage>
    <maintenance>
      <description>
        <para>ongoing </para>
      </description>
    </maintenance>
    <contact>
      <organizationName>LTER Network Office</organizationName>
      <positionName>LNO Information Manager</positionName>
    </contact>
    <contact>
      <positionName>NTL LTER Information Manager</positionName>
      <organizationName>University of Wisconsin</organizationName>
      <address>
        <deliveryPoint>680 North Park Street</deliveryPoint>
        <city>Madison</city>
        <administrativeArea>WI</administrativeArea>
        <postalCode>53706</postalCode>
        <country>United States</country>
      </address>
      <electronicMailAddress>infomgr@lter.limnology.wisc.edu</electronicMailAddress>
    </contact>
    <contact>
      <positionName>NTL LTER Lead PI</positionName>
      <organizationName>Center for Limnology</organizationName>
      <address>
        <deliveryPoint>680 North Park Str.</deliveryPoint>
        <city>Madison</city>
        <administrativeArea>WI</administrativeArea>
        <postalCode>53706</postalCode>
        <country>United States</country>
      </address>
      <electronicMailAddress>leadpi@lter.limnology.wisc.edu</electronicMailAddress>
    </contact>
    <publisher>
      <organizationName>North Temperate Lakes LTER</organizationName>
      <address>
        <deliveryPoint>Center for Limnology, UW Madison</deliveryPoint>
        <city>Madison</city>
        <administrativeArea>WI</administrativeArea>
        <postalCode>53706</postalCode>
        <country>United States</country>
      </address>
      <electronicMailAddress>infomgr@lter.limnology.wisc.edu</electronicMailAddress>
    </publisher>
    <pubPlace>North Temperate Lakes</pubPlace>
    <methods>
      <methodStep>
        <description>

            <para>I Site Locations Sites are designated according to the LTER numbering scheme
							established for the shoreline of the south basin of Trout Lake and its islands (see
							fig. 1). The four sites used by the macrophyte component are also used in the LTER
							fish and crayfish sampling and the descriptions that follow make reference to the
							shore stakes set for the fish sampling crews. Appendix A details their placement. In
							addition, photos have been included to identify the landmarks used. Each site
							establishes a transect line from a proximal shore landmark to a distal shore landmark
							on a specified compass heading. Site 7 Rocky Reef Bay: Landmarks: Proximal - Large
							birch with a spike nailed one foot above the base. Also at fish sampling stake D.
							Distal - The Rocky Reef Resort main building located in line with the north end of
							Rocky Reef Island. Compass Heading: 280degree Site 31 Channel Mouth Island: Landmarks:
							Proximal - White Birch at fish sampling stake B Distal - A distant pine (approx. 1
							mi.) standing above the canopy in the skyline facing east. Pine is at peak where the
							landscape shows a rise. Compass Heading: 83degree Site 50 - Southwest Bay of South
							Trout: Landmarks: Proximal - Large White Pine in clearing between fish sampling stake
							C and D. About 9 meters east of stake D. Distal - The west tip of Haunted Island.
							Compass Heading: 13degree Site 56 - Mouth of Mann Creek: Landmarks: Proximal - Large
							White Cedar with spike nailed 1 foot above base. Distal - The west tip of Millers
							Island. Compass Heading: 41degree. II Line Transects The site descriptions specify a
							transect line along which presenceorabsence data is recorded for all macrophyte
							species. A 0.25 M2 ring placed at 1 meter intervals (except site 7 - 0.5 to 1 M depth
							where the ring is placed at 2 meter intervals) along transect designates the sampling
							quadrat. Using SCUBA, species data are recorded along with the total number of
							quadrats encountered between the following depth intervals: 0.5-1 M, 1-2 M, 2-3 M and
							3-5 M. These depth intervals have been permanently established with markers consisting
							of a commercial Earth Anchor set in the lake bottom with 2 floats secured to it near
							the bottom. Large boat bumpers are used on the anchors at 3 and 5 meters. The other
							floats are small polybottles. Between 28 and 52 quadrats are examined within each
							depth interval at each site. The paths over which the quadrats are laid are shown on
							the site maps (Figs. 2-5). A species list is given in appendix B. III Biomass
							Harvesting. Five replicate quadrats (0.25 M2) are harvested for all above ground
							biomass at each site at each of three nominal depths: 1.5 M, 2.5 M and 4 M. Samples
							are removed along a line parallel to shore - located midway between each of the 1, 2,
							3 and 5 M anchors. Figures 2-5 show the distribution of the replicates. Four sites
							with 3 depths and 5 replicates yields 60 samples. A sample may be empty. In the lab,
							samples are separated by species, placed in labeled paper bags (LABEL:
							SpeciesorSiteorDepthorRepnumber ), oven dried, and weights recorded. Paper bags used
							for drying should be purchased in groups to allow the plant weights to be determined
							by difference using an average tare for a group of bags. Paper bags for determining
							average tare should be wetted and oven dried in the same manor as the bags containing
							plant samples. IV Additional Comments. A. Pre-1987 Data. In 1987, permanent line
							transects were established at each of the sites. Biomass samples and line transects
							observed before 1987 were set by more general descriptions at the site and were not
							identical year to year. B. Biomass Weights. Starting in 1989, biomass weights were
							determined by weighing dried plants in paper bags and using an average tare for the
							bags. Consequently, values in the data base can be negative and should be considered
							as present in very small amounts. </para>

        </description>
      </methodStep>
    </methods>
    <project>
      <title>North Temperate Lakes LTER</title>
      <personnel>
        <positionName>NTL LTER Lead PI</positionName>
        <organizationName>Center for Limnology</organizationName>
        <address>
          <deliveryPoint>680 North Park Str.</deliveryPoint>
          <city>Madison</city>
          <administrativeArea>WI</administrativeArea>
          <postalCode>53706</postalCode>
          <country>United States</country>
        </address>
        <electronicMailAddress>leadpi@lter.limnology.wisc.edu</electronicMailAddress>
        <role>project personnel</role>
      </personnel>
      <abstract>
        <para>North Temperate Lakes Long Term Ecological Research studies the ecology of lakes as
					one of a network of sites established by the National Science Foundation. We are
					interested in how biophysical setting, climate, and changing land use and cover interact
					to shape lake characteristics and dynamics over time (past, present, future). Our primary
					study sites include a set of seven northern Wisconsin and four southern Wisconsin lakes
					and their surrounding landscapes. The project, which started in 1981, is administered by
					the Center for Limnology at the University of Wisconsin-Madison. Perception of Long-Term
					Change: How and why have the lake districts changed, and how will they change in the
					future? Climatic Forcing of Change: What are the major ecological and social responses of
					lake districts to climate change? Interacting Drivers, Scales of Space and Time, and
					Regional Change: How do multiple interacting drivers affect regional change in lake
					districts at multiple scales? Ecosystem Services: Past, Present and Future: What are the
					magnitudes, interactions and potential future flows of ecosystem services in lake
					districts? </para>
      </abstract>
    </project>
    <dataTable>
      <entityName>macrophyte_biomass_tr_sumview</entityName>
      <entityDescription>North Temperate Lakes LTER: Macrophyte Biomass in Trout Lake
				Summary</entityDescription>
      <physical>
        <objectName>macrophytebiomasstrsumview</objectName>
        <dataFormat>
          <textFormat>
            <numHeaderLines>1</numHeaderLines>
            <recordDelimiter>\r\n</recordDelimiter>
            <attributeOrientation>column</attributeOrientation>
            <simpleDelimited>
              <fieldDelimiter>,</fieldDelimiter>
              <quoteCharacter>"</quoteCharacter>
            </simpleDelimited>
          </textFormat>
        </dataFormat>
        <distribution>
          <online>
            <url function="download">https://pasta.lternet.edu/package/data/eml/knb-lter-ntl/25/8/eb346bf6bc41f73dcdece85b7ce98cdd</url>
          </online>
        </distribution>
      </physical>
      <coverage>
        <geographicCoverage>
          <geographicDescription>Location: Trout Lake is located within the Northern
						Highland-American Legion State Forest, Vilas County. It is a drainage lake with
						predominantly gravel and sand substrate. It has a surface area of 1607.9 hectare, 25.9
						kilometers of mostly undeveloped shoreline and a maximum depth of 35.7 meters. </geographicDescription>
          <boundingCoordinates>
            <westBoundingCoordinate>-89.665017</westBoundingCoordinate>
            <eastBoundingCoordinate>-89.665017</eastBoundingCoordinate>
            <northBoundingCoordinate>46.029267</northBoundingCoordinate>
            <southBoundingCoordinate>46.029267</southBoundingCoordinate>
          </boundingCoordinates>
        </geographicCoverage>
      </coverage>
      <attributeList>
        <attribute>
          <attributeName>lakeid</attributeName>
          <attributeLabel>lake name abbreviation</attributeLabel>
          <attributeDefinition>lake name abbreviation</attributeDefinition>
          <storageType>string</storageType>
          <measurementScale>
            <nominal>
              <nonNumericDomain>
                <enumeratedDomain>
                  <codeDefinition>
                    TR
                    <definition>Trout Lake</definition>
                  </codeDefinition>
                </enumeratedDomain>
              </nonNumericDomain>
            </nominal>
          </measurementScale>
        </attribute>
        <attribute>
          <attributeName>year4</attributeName>
          <attributeLabel>year</attributeLabel>
          <attributeDefinition>year</attributeDefinition>
          <storageType>float</storageType>
          <measurementScale>
            <ratio>
              <unit>
                <standardUnit>nominalYear</standardUnit>
              </unit>
              <precision>1</precision>
              <numericDomain>
                <numberType>real</numberType>
              </numericDomain>
            </ratio>
          </measurementScale>
        </attribute>
        <attribute>
          <attributeName>site</attributeName>
          <attributeLabel>site</attributeLabel>
          <attributeDefinition>site</attributeDefinition>
          <storageType>string</storageType>
          <measurementScale>
            <nominal>
              <nonNumericDomain>
                <textDomain>
                  <definition>site</definition>
                </textDomain>
              </nonNumericDomain>
            </nominal>
          </measurementScale>
        </attribute>
        <attribute>
          <attributeName>depth</attributeName>
          <attributeLabel>sample depth meter</attributeLabel>
          <attributeDefinition>depth at which the sample or measurement was
						taken</attributeDefinition>
          <storageType>float</storageType>
          <measurementScale>
            <ratio>
              <unit>
                <standardUnit>meter</standardUnit>
              </unit>
              <numericDomain>
                <numberType>real</numberType>
              </numericDomain>
            </ratio>
          </measurementScale>
        </attribute>
        <attribute>
          <attributeName>species_name</attributeName>
          <attributeLabel>species of macrophyte</attributeLabel>
          <attributeDefinition>species of macrophyte</attributeDefinition>
          <storageType>string</storageType>
          <measurementScale>
            <nominal>
              <nonNumericDomain>
                <textDomain>
                  <definition>species of macrophyte</definition>
                </textDomain>
              </nonNumericDomain>
            </nominal>
          </measurementScale>
        </attribute>
        <attribute>
          <attributeName>nreps</attributeName>
          <attributeLabel>number of replicate samples</attributeLabel>
          <attributeDefinition>number of replicate samples</attributeDefinition>
          <storageType>float</storageType>
          <measurementScale>
            <ratio>
              <unit>
                <standardUnit>number</standardUnit>
              </unit>
              <numericDomain>
                <numberType>real</numberType>
              </numericDomain>
            </ratio>
          </measurementScale>
        </attribute>
        <attribute>
          <attributeName>avg_dryweight_g</attributeName>
          <attributeLabel>mean of dryweight from reps</attributeLabel>
          <attributeDefinition>mean of dryweight from replicate samples</attributeDefinition>
          <storageType>float</storageType>
          <measurementScale>
            <ratio>
              <unit>
                <customUnit>gramPer_pt25MeterSquared</customUnit>
              </unit>
              <numericDomain>
                <numberType>real</numberType>
              </numericDomain>
            </ratio>
          </measurementScale>
        </attribute>
        <attribute>
          <attributeName>stdev_dryweight_g</attributeName>
          <attributeLabel>stdev of dryweights from reps</attributeLabel>
          <attributeDefinition>standard deviation of dryweight from replicate
						samples</attributeDefinition>
          <storageType>float</storageType>
          <measurementScale>
            <ratio>
              <unit>
                <customUnit>gramPer_pt25MeterSquared</customUnit>
              </unit>
              <numericDomain>
                <numberType>real</numberType>
              </numericDomain>
            </ratio>
          </measurementScale>
        </attribute>
      </attributeList>
    </dataTable>
  </dataset>
  <additionalMetadata>
    <metadata>
      <ns2:unitList xsi:schemaLocation="http://www.xml-cml.org/schema/stmml-1.1     http://nis.lternet.edu/schemas/EML/eml-2.1.0/stmml.xsd">
        <ns2:unit id="gramPer_pt25MeterSquared" />
      </ns2:unitList>
    </metadata>
  </additionalMetadata>
</ns0:eml>


text:
import javax.swing.*;

public class DoubleJSlider extends JSlider{

  static final double DOUBLE_MINIMUM = 0.0;
  static final double DOUBLE_MAXIMUM = 100.0;
  static final double DOUBLE_MIDDLE = 50.0;
  static final int PRECISION_MULTIPLIER  = 100;
  /**
   * Constructor - initializes with 0.0,100.0,50.0
   */
  public DoubleJSlider(){
    super();
    setDoubleMinimum(DOUBLE_MINIMUM);
    setDoubleMaximum(DOUBLE_MAXIMUM);
    setDoubleValue(DOUBLE_MIDDLE);
  }

  /**
   * Constructor
   */
  public DoubleJSlider(double min, double max, double val){
    super();
    setDoubleMinimum(min);
    setDoubleMaximum(max);
    setDoubleValue(val);
  }

  /**
   * returns Maximum in double precision
   */
  public double getDoubleMaximum() {
    return( getMaximum()/DOUBLE_MAXIMUM );
  }

  /**
   * returns Minimum in double precision
   */
  public double getDoubleMinimum() {
    return( getMinimum()/DOUBLE_MAXIMUM );
  }

  /**
   * returns Value in double precision
   */
  public double getDoubleValue() {
    return(getValue()/DOUBLE_MAXIMUM);
  }

  /**
   * sets Maximum in double precision
   */
  public void setDoubleMaximum(double max) {
    setMaximum((int)(max*PRECISION_MULTIPLIER));
  }

  /**
   * sets Minimum in double precision
   */
  public void setDoubleMinimum(double min) {
    setMinimum((int)(min*PRECISION_MULTIPLIER));
  }

  /**
   * sets Value in double precision
   */
  public void setDoubleValue(double val) {
    setValue((int)(val*PRECISION_MULTIPLIER));
    setToolTipText(Double.toString(val));
  }

}


text:
package net.tascalate.async.tools.core;

import java.io.PrintWriter;
import java.io.StringWriter;

import net.tascalate.asmx.ClassReader;
import net.tascalate.asmx.ClassVisitor;
import net.tascalate.asmx.Opcodes;
import net.tascalate.asmx.tree.ClassNode;
import net.tascalate.asmx.tree.FieldInsnNode;
import net.tascalate.asmx.tree.MethodInsnNode;
import net.tascalate.asmx.tree.MethodNode;
import net.tascalate.asmx.tree.VarInsnNode;
import net.tascalate.asmx.util.Textifier;
import net.tascalate.asmx.util.TraceClassVisitor;
import net.tascalate.asmx.util.TraceMethodVisitor;

/**
 * @author
 */
class BytecodeTraceUtil {

    public static String toString(byte[] clazz) {
        StringWriter strOut = new StringWriter();
        PrintWriter out = new PrintWriter(strOut);
        ClassVisitor cv = new TraceClassVisitor(out);

        ClassReader cr = new ClassReader(clazz);
        cr.accept(cv, Opcodes.ASM5);

        strOut.flush();
        return strOut.toString();
    }

    public static String toString(ClassNode cn) {
        StringWriter strOut = new StringWriter();
        PrintWriter out = new PrintWriter(strOut);

        cn.accept(new TraceClassVisitor(out));

        strOut.flush();
        return strOut.toString();
    }

    public static String toString(MethodNode mn) {
         Textifier t = new Textifier();
         TraceMethodVisitor tmv = new TraceMethodVisitor(t);
         mn.accept(tmv);
         return t.toString();
    }

    public static String toString(VarInsnNode vin) {
        return vin.getOpcode() + " " + vin.var;
    }

    public static String toString(MethodInsnNode min) {
        return min.getOpcode() + " " + min.owner + " " + min.name + " " + min.desc;
    }

    public static String toString(FieldInsnNode fin) {
        return fin.getOpcode() + " " + fin.owner + " " + fin.name + " " + fin.desc;
    }
}


text:
package db_models

import (
	"time"
)

type Blocker struct {
	Id              int64     `xorm:"'id' pk autoincr"`
	BlockerType     string    `xorm:"'blocker_type' not null"`
	Capacity        int       `xorm:"'capacity' not null"`
	Load            int       `xorm:"'load' not null index(idx_load)"`
	Created         time.Time `xorm:"created"`
	Updated         time.Time `xorm:"updated"`
}


text:
<?php
    if(!empty($status)){
        echo "

 $status

        ";
    }
?>

<form role="form" enctype="multipart/form-data" action="<?php echo site_url("insertmarker/add_marker"); ?>"
      method='post' id="form_insert">

        Koordinat
        <input type="text" class="form-control" name="lokasi" required
               placeholder="Example : -7.569125, 110.829693">

        Nama Lokasi
        <input type="text" class="form-control" name="nama_lokasi" required
               placeholder="Example : Prambanan Temple">

        Subtitle
        <input type="text" class="form-control" name="subtitle" required
               placeholder="Example : keterangan / History">

         Alamat
        <textarea class="form-control" name="alamat" required></textarea>

        Nomer Tlp
        <input type="text" class="form-control" name="nomer_tlp" required
               placeholder="Example : 085728909xxx">

         Info
        <textarea class="form-control" name="info" required></textarea>

        Icon input
        <input type="file" name="icon" required>

icon untuk map.

        Image Upload
        <input type="file" name="image" required>

upload image.

    <button type="submit" class="btn btn-primary"> Submit</button>
</form>


text:
import os
import shutil
import re

def handle_files(fct_file_path, url, test_file_path=None):
    if os.path.normpath(fct_file_path) != os.path.normpath(url + '.fct'):
        shutil.copy(os.path.normpath(fct_file_path),os.path.normpath(url + '.fct'));

    if test_file_path and os.path.normpath(test_file_path) != os.path.normpath(url + '.test'):
        shutil.copy(os.path.normpath(test_file_path), os.path.normpath(url + '.test'));

    if not os.path.isfile(os.path.normpath(url + '.fct')) or not os.path.isfile(os.path.normpath(url + '.prd')):
        raise Exception('Prd or fct file missing')

def create_attribute_list(attribute_str):
    if attribute_str: # e.g. : '  col1    5  eqb , col2 6 eqb   '
        attribute_str = ' '.join(attribute_str.split()) # e.g. : 'col1 5 eqb , col2 6 eqb'
        attribute_list = attribute_str.split(',') # e.g. : ['col1 5 eqb ',' col2 6 eqb']
        if attribute_list:
            #map & strip e.g. : ['-d col1 5 eqb','-d col2 6 eqb']
            #join e.g. : '-d col1 5 eqb -d col2 6 eqb'
            res = check_attributes(' '.join(['-d ' + str(field).strip() for field in attribute_list]))
            if res is None:
                return ''
            else:
                #split e.g. : ['-d','col1','5','eqb','-d','col2','6','eqb']
                return res.split(' ')
    return ''

def check_attributes(attribute_str):
    print(attribute_str)
    if re.search('^(-d \w+ \d+ (eqb|sdm))( -d \w+ \d+ (eqb|sdm))*$',attribute_str):
        return attribute_str
    else :
        raise Exception('Attribute list is not correct')
    return None


text:
package direct

import (
	"io"
	"net"
	"net/url"
	"sync"
	"time"

	"github.com/yinqiwen/gsnova/common/channel"
	"github.com/yinqiwen/gsnova/common/dns"
	"github.com/yinqiwen/gsnova/common/helper"
	"github.com/yinqiwen/gsnova/common/hosts"
	"github.com/yinqiwen/gsnova/common/logger"
	"github.com/yinqiwen/gsnova/common/mux"
	"github.com/yinqiwen/gsnova/common/netx"
)

type directStream struct {
	net.Conn
	conf         *channel.ProxyChannelConfig
	addr         string
	session      *directMuxSession
	proxyServer  string
	latestIOTime time.Time
}

func (tc *directStream) SetReadDeadline(t time.Time) error {
	if nil == tc.Conn {
		return io.EOF
	}
	return tc.Conn.SetReadDeadline(t)
}
func (tc *directStream) SetWriteDeadline(t time.Time) error {
	if nil == tc.Conn {
		return io.EOF
	}
	return tc.Conn.SetWriteDeadline(t)
}

func (tc *directStream) Auth(req *mux.AuthRequest) *mux.AuthResponse {
	return &mux.AuthResponse{Code: mux.AuthOK}
}

func (tc *directStream) Connect(network string, addr string, opt mux.StreamOptions) error {
	host, port, _ := net.SplitHostPort(addr)
	//log.Printf("Session:%d enter direct with host %s & event:%T", ev.GetId(), host, ev)

	if len(tc.conf.SNIProxy) > 0 && port == "443" && network == "tcp" && hosts.InHosts(tc.conf.SNIProxy) {
		host = tc.conf.SNIProxy
	}
	isIP := net.ParseIP(host) != nil
	if !isIP {
		host = hosts.GetHost(host)
	}

	var proxyURL *url.URL
	if nil == tc.conf.ProxyURL() && len(tc.proxyServer) == 0 {
		addr = host + ":" + port
	} else {
		if nil != tc.conf.ProxyURL() {
			addr = tc.conf.ProxyURL().Host
			proxyURL = tc.conf.ProxyURL()
		} else {
			u, err := url.Parse(tc.proxyServer)
			if nil != err {
				return err
			}
			addr = u.Host
			proxyURL = u
		}
	}
	connectHost, connectPort, _ := net.SplitHostPort(addr)
	if net.ParseIP(connectHost) == nil {
		iphost, err := dns.DnsGetDoaminIP(connectHost)
		if nil != err {
			return err
		}
		addr = net.JoinHostPort(iphost, connectPort)
	}
	//dailTimeout := tc.conf.DialTimeout
	if 0 == opt.DialTimeout {
		opt.DialTimeout = 5000
	}
	//log.Printf("Session:%d connect %s:%s for %s %T %v %v %s", ev.GetId(), network, addr, host, ev, needHttpsConnect, conf.ProxyURL(), net.JoinHostPort(host, port))
	c, err := netx.DialTimeout(network, addr, time.Duration(opt.DialTimeout)*time.Millisecond)
	if nil != proxyURL && nil == err {
		switch proxyURL.Scheme {
		case "http_proxy":
			fallthrough
		case "http":
			err = helper.HTTPProxyConnect(tc.conf.ProxyURL(), c, "https://"+net.JoinHostPort(host, port))
		case "socks":
			fallthrough
		case "socks4":
			fallthrough
		case "socks5":
			err = helper.Socks5ProxyConnect(tc.conf.ProxyURL(), c, net.JoinHostPort(host, port))
		}
	}
	if nil != err {
		logger.Error("Failed to connect %s for %s with error:%v", addr, host, err)
		return err
	}

	tc.Conn = c
	tc.addr = addr
	return nil
}

func (tc *directStream) StreamID() uint32 {
	return 0
}

func (s *directStream) LatestIOTime() time.Time {
	return s.latestIOTime
}

func (tc *directStream) Read(p []byte) (int, error) {
	if nil == tc.Conn {
		return 0, io.EOF
	}
	tc.latestIOTime = time.Now()
	return tc.Conn.Read(p)
}
func (tc *directStream) Write(p []byte) (int, error) {
	if nil == tc.Conn {
		return 0, io.EOF
	}
	tc.latestIOTime = time.Now()
	return tc.Conn.Write(p)
}

func (tc *directStream) Close() error {
	conn := tc.Conn
	if nil != conn {
		conn.Close()
		tc.Conn = nil
	}
	tc.session.closeStream(tc)
	return nil
}

type directMuxSession struct {
	conf         *channel.ProxyChannelConfig
	streams      map[*directStream]bool
	streamsMutex sync.Mutex
	proxyServer  string
}

func (s *directMuxSession) RemoteAddr() net.Addr {
	return nil
}
func (s *directMuxSession) LocalAddr() net.Addr {
	return nil
}

func (tc *directMuxSession) closeStream(s *directStream) {
	tc.streamsMutex.Lock()
	defer tc.streamsMutex.Unlock()
	delete(tc.streams, s)
}

func (tc *directMuxSession) CloseStream(stream mux.MuxStream) error {
	//stream.Close()
	return nil
}

func (tc *directMuxSession) OpenStream() (mux.MuxStream, error) {
	tc.streamsMutex.Lock()
	defer tc.streamsMutex.Unlock()
	stream := &directStream{
		conf:        tc.conf,
		session:     tc,
		proxyServer: tc.proxyServer,
	}
	return stream, nil
}
func (tc *directMuxSession) AcceptStream() (mux.MuxStream, error) {
	return nil, channel.ErrNotSupportedOperation
}

func (tc *directMuxSession) NumStreams() int {
	tc.streamsMutex.Lock()
	defer tc.streamsMutex.Unlock()
	return len(tc.streams)
}
func (tc *directMuxSession) Ping() (time.Duration, error) {
	return 0, nil
}

func (tc *directMuxSession) Close() error {
	tc.streamsMutex.Lock()
	defer tc.streamsMutex.Unlock()
	for stream := range tc.streams {
		stream.Close()
	}
	tc.streams = make(map[*directStream]bool)
	return nil
}

type DirectProxy struct {
	proxyType string
}

func (p *DirectProxy) CreateMuxSession(server string, conf *channel.ProxyChannelConfig) (mux.MuxSession, error) {
	ps := server
	if len(p.proxyType) == 0 {
		ps = ""
	}
	session := &directMuxSession{
		conf:        conf,
		streams:     make(map[*directStream]bool),
		proxyServer: ps,
	}
	return session, nil
}

func (p *DirectProxy) Features() channel.FeatureSet {
	return channel.FeatureSet{
		AutoExpire: false,
		Pingable:   false,
	}
}

func init() {
	channel.RegisterLocalChannelType(channel.DirectChannelName, &DirectProxy{})
	channel.RegisterLocalChannelType("socks", &DirectProxy{"socks5"})
	channel.RegisterLocalChannelType("socks4", &DirectProxy{"socks4"})
	channel.RegisterLocalChannelType("socks5", &DirectProxy{"socks5"})
	channel.RegisterLocalChannelType("http_proxy", &DirectProxy{"http_proxy"})
}