text:
"""
To do:
- split off application dependent code, as done for ZI_HDAWG8.py

Notes:

Changelog:

20190113 WJV
- started Changelog
- addressed many warnings identified by PyCharm
- started adding type annotations
- split of stuff into _add_node_pars()
- made some properties 'private'

20190219 WJV
- tagged some dead code with FIXM.

20190219:
- made _array_to_combined_vector_string() a @staticmethod

20190417 WJV
- merged branch 'develop' into 'feature/cc', changes:
    spec_mode_on
    spec_mode_off

20190429 WJV
- merged branch 'QCC_testing' into 'feature/cc', changes:
    load_default_settings(): awgs_0_dio_strobe_index changed from 31 (CCL) to 15 (QCC)

20190612 WJV
- merged branch 'QCC_testing' into 'feature/cc', changes:
    adds awg_sequence_acquisition_and_DIO_RED_test()

20190618 WJV
- merged branch 'develop' into 'feature/cc', changes:

20190813 NH
- merged branch 'develop' into 'feature/ZIupdateDrivers'
- Updated driver to use new UHFQA nodes
- Updated to support dynamic waveform upload properly. The AWG is configured when start() is called and the
    driver then chooses whether it is necessary to recompile the AWG program. The program will be recompiled
    if waveform lengths have changed. Otherwise, if waveforms have been updated they will just be downloaded
    directly to the instrument.

20200214 WJV
- removed unused parameter repetitions from _find_valid_delays()
- also removed parameter repetitions from calibrate_CC_dio_protocol()
- split off calibrate_dio_protocol() from calibrate_CC_dio_protocol() to allow standalone use

20200217 WJV
- moved DIO calibration helpers to their respective drivers
- we now implement new interface CalInterface
- removed self._dio_calibration_mask and added parameter dio_mask where appropriate

"""

import time
import logging
import inspect
import numpy as np
from typing import Tuple,List

import pycqed.instrument_drivers.physical_instruments.ZurichInstruments.ZI_base_instrument as zibase
import pycqed.instrument_drivers.physical_instruments.ZurichInstruments.UHFQA_core as uhf
import pycqed.instrument_drivers.library.DIO as DIO

from qcodes.utils import validators
from qcodes.utils.helpers import full_class

log = logging.getLogger(__name__)

##########################################################################
# Exceptions
##########################################################################

##########################################################################
# Class
##########################################################################

class UHFQC(uhf.UHFQA_core, DIO.CalInterface):
    """
    This is the PycQED driver for the 1.8 Gsample/s UHFQA developed
    by Zurich Instruments.

    Requirements:
    Installation instructions for Zurich Instrument Libraries.
    1. install ziPython 3.5/3.6 ucs4 19.05 for 64bit Windows from
        http://www.zhinst.com/downloads, https://people.zhinst.com/~niels/
    2. upload the latest firmware to the UHFQA using the LabOne GUI
    """

    # Constants definitions from "node_doc_UHFQA.json"
    DIOS_0_MODE_MANUAL = 0  # "0": "Manual setting of the DIO output value.",
    DIOS_0_MODE_AWG_SEQ = 1  # "1": "Enables setting of DIO output values by AWG sequencer commands.",
    DIOS_0_MODE_AWG_WAV = 2  # "2": "Enables the output of AWG waveform data as digital pattern on the DIO connector." FIXME: LabOne says: "QA result"
    # FIXME: comments in this file state: QuExpress thresholds on DIO (mode == 2)

    DIOS_0_EXTCLK_50MHZ = 2  # FIXME: not in "node_doc_UHFQA.json"

    AWGS_0_DIO_VALID_POLARITY_NONE = 0  # "0": "None: VALID bit is ignored.",
    AWGS_0_DIO_VALID_POLARITY_HIGH = 1  # "1": "High: VALID bit must be logical high.",
    AWGS_0_DIO_VALID_POLARITY_LOW = 2  # "2": "Low: VALID bit must be logical zero.",
    AWGS_0_DIO_VALID_POLARITY_BOTH = 3  # "3": "Both: VALID bit may be logical high or zero."

    ##########################################################################
    # 'public' functions: device control
    ##########################################################################

    def __init__(self,
                 name,
                 device:                  str,
                 interface:               str = 'USB',
                 address:                 str = '127.0.0.1',
                 port:                    int = 8004,
                 use_dio:                 bool = True,
                 nr_integration_channels: int = 10,
                 server:                  str = '',
                 **kw) -> None:
        """
        Input arguments:
            name:           (str) name of the instrument
            device          (str) the name of the device e.g., "dev8008"
            interface       (str) the name of the interface to use ('1GbE' or 'USB')
            address         (str) the host where the ziDataServer is running (for compatibility)
            port            (int) the port to connect to for the ziDataServer (don't change)
            use_dio         (bool) assert to enable the DIO interface
            nr_integration_channels (int) the number of integration channels to use (max 10)
            server:         (str) the host where the ziDataServer is running (if not '' then used instead of address)
        """
        t0 = time.time()

        self._use_dio = use_dio

        # Used for extra DIO output to CC for debugging
        self._diocws = None

        # Holds the DIO calibration delay
        self._dio_calibration_delay = 0

        # Holds the number of configured cases
        self._cases = None

        super().__init__(name=name, device=device, interface=interface, address=address,
                         server=server, port=port, nr_integration_channels=nr_integration_channels,
                         **kw)

        t1 = time.time()
        log.info(f'{self.devname}: Initialized UHFQC in {t1 - t0:.3f}s')

    ##########################################################################
    # 'public' overrides for UHFQA_core
    ##########################################################################

    def load_default_settings(self, upload_sequence=True) -> None:
        super().load_default_settings()

        # Load an AWG program
        if upload_sequence:
            self.awg_sequence_acquisition()

        # Configure the codeword protocol
        if self._use_dio:
            self.dios_0_mode(self.DIOS_0_MODE_AWG_WAV)  # QuExpress thresholds on DIO (mode == 2), AWG control of DIO (mode == 1)
            self.dios_0_drive(0x3)  # Drive DIO bits 15 to 0
            self.dios_0_extclk(self.DIOS_0_EXTCLK_50MHZ)  # 50 MHz clocking of the DIO
            self.awgs_0_dio_strobe_slope(0)  # no edge, replaced by dios_0_extclk(2)
            self.awgs_0_dio_strobe_index(15)  # NB: 15 for QCC (was 31 for CCL). Irrelevant now we use 50 MHz clocking
            self.awgs_0_dio_valid_polarity(2)  # high polarity FIXME: does not match AWGS_0_DIO_VALID_POLARITY_HIGH
            self.awgs_0_dio_valid_index(16)

        # No rotation on the output of the weighted integration unit, i.e. take
        # real part of result
        for i in range(0, self._nr_integration_channels):
            self.set('qas_0_rotations_{}'.format(i), 1.0 + 0.0j)
            # remove offsets to weight function
            self.set('qas_0_trans_offset_weightfunction_{}'.format(i), 0.0)

    ##########################################################################
    # 'public' functions: generic AWG/waveform support
    ##########################################################################

    def load_awg_program_from_file(self, filename) -> None:
        """
        Loads an awg sequence onto the UHFQA from a text file.
        File needs to obey formatting specified in the manual.
        Only provided for backwards compatibility purposes.
        """
        print(filename)
        with open(filename, 'r') as awg_file:
            self._awg_program[0] = awg_file.read()
            self._awg_needs_configuration[0] = True

    def _do_set_AWG_file(self, filename) -> None:
        self.load_awg_program_from_file('UHFLI_AWG_sequences/'+filename)

    def awg_file(self, filename) -> None:
        """Only provided for backwards compatibility purposes."""
        self.load_awg_program_from_file(filename)

    def awg_update_waveform(self, index, data) -> None:
        raise NotImplementedError(
            'Method not implemented! Please use the corresponding waveform parameters \'wave_chN_cwM\' to update waveforms!')

    ##########################################################################
    # 'public' functions: DIO support
    ##########################################################################

    def plot_dio(self, bits=range(32), line_length=64) -> None:
        data = self.getv('awgs/0/dio/data')
        zibase.plot_timing_diagram(data, bits, line_length)

    ##########################################################################
    # 'public' functions: weight & matrix function helpers
    ##########################################################################

    def prepare_SSB_weight_and_rotation(
            self,
            IF,
            weight_chI=0,
            weight_chQ=1,
            rotation_angle=0,
            length=4096 / 1.8e9,
            scaling_factor=1
    ) -> None:
        """
        Sets default integration weights for SSB modulation, beware does not
        load pulses or prepare the UFHQC progarm to do data acquisition
        """
        trace_length = 4096
        tbase = np.arange(0, trace_length / 1.8e9, 1 / 1.8e9)
        cosI = np.array(np.cos(2 * np.pi * IF * tbase + rotation_angle))
        sinI = np.array(np.sin(2 * np.pi * IF * tbase + rotation_angle))
        if length < 4096 / 1.8e9:
            max_sample = int(length * 1.8e9)
            # setting the samples beyond the length to 0
            cosI[max_sample:] = 0
            sinI[max_sample:] = 0
        self.set(f'qas_0_integration_weights_{weight_chI}_real', np.array(cosI))
        self.set(f'qas_0_integration_weights_{weight_chI}_imag', np.array(sinI))
        self.set(f'qas_0_rotations_{weight_chI}', scaling_factor * (1.0 + 1.0j))
        if weight_chQ != None:
            self.set(f'qas_0_integration_weights_{weight_chQ}_real', np.array(sinI))
            self.set(f'qas_0_integration_weights_{weight_chQ}_imag', np.array(cosI))
            self.set(f'qas_0_rotations_{weight_chQ}', scaling_factor * (1.0 - 1.0j))

    def prepare_DSB_weight_and_rotation(
            self,
            IF,
            weight_chI=0,
            weight_chQ=1
    ) -> None:
        trace_length = 4096
        tbase = np.arange(0, trace_length/1.8e9, 1/1.8e9)
        cosI = np.array(np.cos(2 * np.pi*IF*tbase))
        sinI = np.array(np.sin(2 * np.pi*IF*tbase))
        self.set(f'qas_0_integration_weights_{weight_chI}_real', np.array(cosI))
        self.set(f'qas_0_integration_weights_{weight_chQ}_real', np.array(sinI))
        # the factor 2 is needed so that scaling matches SSB downconversion
        self.set(f'qas_0_rotations_{weight_chI}', 2.0 + 0.0j)
        self.set(f'qas_0_rotations_{weight_chQ}', 2.0 + 0.0j)

    ##########################################################################
    # Overriding private ZI_base_instrument methods
    ##########################################################################

    def _add_extra_parameters(self) -> None:
        """
        We add a few additional custom parameters on top of the ones defined in the device files. These are:
          AWG_file - allows the user to configure the AWG with a SeqC program from a specific file.
            Provided only because the old version of the driver had this parameter. It is discouraged to use
            it.
          wait_dly - a parameter that enables the user to set a delay in AWG clocks cycles (4.44 ns) to be
            applied between when the AWG starts playing the readout waveform, and when it triggers the
            actual readout.
          cases - a parameter that can be used to define which combination of readout waveforms to actually
            download to the instrument. As the instrument has a limited amount of memory available, it is
            not currently possible to store all 1024 possible combinations of readout waveforms that would
            be required to address the maximum number of qubits supported by the instrument (10). Therefore,
            the 'cases' mechanism is used to reduce that number to the combinations actually needed by
            an experiment.
          dio_calibration_delay - the delay that is programmed on the DIO lines as part of the DIO calibration
            process in order for the instrument to reliably sample data from the CC. Can be used to detect
            unexpected changes in timing of the entire system. The parameter can also be used to force a specific
            delay to be used on the DIO although that is not generally recommended.
        """
        super()._add_extra_parameters()

        self.add_parameter(
            'AWG_file',
            set_cmd=self._do_set_AWG_file,
            docstring='Configures the AWG with a SeqC program from a specific file. '
            'Provided only for backwards compatibility. It is discouraged to use '
            'this parameter unless you know what you are doing',
            vals=validators.Anything())

        self.add_parameter(
            'cases',
            set_cmd=self._set_cases,
            get_cmd=self._get_cases,
            docstring='Configures which combination of readout waveforms to actually '
            'download to the instrument. As the instrument has a limited amount of memory available, it is '
            'not currently possible to store all 1024 possible combinations of readout waveforms that would '
            'be required to address the maximum number of qubits supported by the instrument (10). Therefore, '
            'the \'cases\' mechanism is used to reduce that number to the combinations actually needed by '
            'an experiment. The parameter must be set to a list of integers. The list defines the codewords '
            'to be handled by the AWG program. For example, setting the parameter to [1, 5, 7] would result in '
            'an AWG program that handles only codewords 1, 5 and 7. When running, if the AWG receives a codeword '
            'that is not part of this list, an error will be triggered.',
            vals=validators.Lists())

        self.add_parameter('dio_calibration_delay',
            set_cmd=self._set_dio_calibration_delay,
            get_cmd=self._get_dio_calibration_delay,
            unit='',
            label='DIO Calibration delay',
            docstring='Configures the internal delay in 300 MHz cycles (3.3 ns) '
            'to be applied on the DIO interface in order to achieve reliable sampling '
            'of the codewords. The valid range is 0 to 15.',
            vals=validators.Ints())

    def _codeword_table_preamble(self, awg_nr) -> str:
        """
        Defines a snippet of code to use in the beginning of an AWG program in order to define the waveforms.
        The generated code depends on the instrument type. For the UHF-QA we simply define the raw waveforms.
        """
        program = ''

        # If the program doesn't need waveforms, just return here
        if not self._awg_program_features['waves']:
            return program

        # If the program needs cases, but none are defined, flag it as an error
        if self._awg_program_features['cases'] and self._cases is None:
            raise zibase.ziConfigurationError(
                'Missing definition of cases for AWG program!')

        wf_table = self._get_waveform_table(awg_nr)
        for dio_cw, (wf_l, wf_r) in enumerate(wf_table):
            csvname_l = self.devname + '_' + wf_l
            csvname_r = self.devname + '_' + wf_r
            program += 'wave {} = "{}";\n'.format(
                wf_l, csvname_l)
            program += 'wave {} = "{}";\n'.format(
                wf_r, csvname_r)
        return program

    def plot_dio_snapshot(self, bits=range(32)):
        zibase.plot_timing_diagram(self.getv('awgs/0/dio/data'), bits, 64)

    ##########################################################################
    # Overriding Qcodes InstrumentBase methods
    ##########################################################################

    def snapshot_base(self, update: bool=False,
                      params_to_skip_update =None,
                      params_to_exclude = None ):
        """
        State of the instrument as a JSON-compatible dict.
        Args:
            update: If True, update the state by querying the
                instrument. If False, just use the latest values in memory.
            params_to_skip_update: List of parameter names that will be skipped
                in update even if update is True. This is useful if you have
                parameters that are slow to update but can be updated in a
                different way (as in the qdac)
        Returns:
            dict: base snapshot
        """

        if params_to_exclude is None:
            params_to_exclude = self._params_to_exclude

        snap = {
            "functions": {name: func.snapshot(update=update)
                          for name, func in self.functions.items()},
            "submodules": {name: subm.snapshot(update=update)
                           for name, subm in self.submodules.items()},
            "__class__": full_class(self)
        }

        snap['parameters'] = {}
        for name, param in self.parameters.items():
            if params_to_exclude and name in params_to_exclude:
                pass
            elif params_to_skip_update and name in params_to_skip_update:
                update_par = False
            else:
                update_par = update
                try:
                    snap['parameters'][name] = param.snapshot(update=update_par)
                except:
                    logging.info("Snapshot: Could not update parameter: {}".format(name))
                    snap['parameters'][name] = param.snapshot(update=False)

        for attr in set(self._meta_attrs):
            if hasattr(self, attr):
                snap[attr] = getattr(self, attr)
        return snap

    ##########################################################################
    # Private methods
    ##########################################################################

    def _reset_awg_program_features(self) -> None:
        """
        Resets the self._awg_program_features to disable all features. The UHFQC can be configured with a number
        of application-specific AWG programs using this driver. However, all the programs share some characteristics that
        are described in the _awg_program_features dictionary. For example, all of the programs include a main loop
        that runs for a number of iterations given by a user register. This feature is indicated by the 'loop_cnt'
        item in the dictionary. In contrast, not all program include an extra loop for the number of averages that
        should be done. Therefore, the 'awg_cnt' item in the dictionary is not automatically set. The driver
        uses these features to keep track of what the current AWG program can do. It then raises errors in case
        the user tries to do something that is not supported.
        """
        self._awg_program_features = {
            'loop_cnt': False,
            'avg_cnt': False,
            'wait_dly': False,
            'waves': False,
            'cases': False,
            'diocws': False}

    def _set_dio_calibration_delay(self, value) -> None:
        # Sanity check the value
        if value < 0 or value > 15:
            raise zibase.ziValueError(
                'Trying to set DIO calibration delay to invalid value! Expected value in range 0 to 15. Got {}.'.format(
                    value))

        log.info(f"{self.devname}: Setting DIO calibration delay to {value}")
        # Store the value
        self._dio_calibration_delay = value

        # And configure the delays
        self.setd('raw/dios/0/delay', self._dio_calibration_delay)

    def _get_dio_calibration_delay(self):
        return self._dio_calibration_delay

    def _set_wait_dly(self, value) -> None:
        self.set('awgs_0_userregs_{}'.format(UHFQC.USER_REG_WAIT_DLY), value)

    def _get_wait_dly(self):
        return self.get('awgs_0_userregs_{}'.format(UHFQC.USER_REG_WAIT_DLY))

    def _set_cases(self, value) -> None:
        # Generate error if we don't have an AWG program that supports cases
        if not self._awg_program_features['cases']:
            raise zibase.ziValueError(
                'Trying to define cases for an AWG program that does not support them!')

        # Check against number of codewords
        if len(value) > self._num_codewords:
            raise zibase.ziValueError('Trying to define a number of cases ({}) greater than configured number of codewords ({})!'.format(
                len(value), self._num_codewords))

        self._cases = value
        self._cw_mask = 0
        for case in self._cases:
            self._cw_mask |= case

        if self._awg_program_features['diocws'] and self._diocws is None:
            raise zibase.ziValueError(
                'AWG program defines DIO output, but no output values have been defined!')

        self._awg_program[0] = \
            awg_sequence_acquisition_preamble() + """
// Mask for selecting our codeword bits
const CW_MASK = (0x1ff << 17);
// Counts wrong codewords
var err_cnt = 0;
""".format(self._cw_mask)

        if self._awg_program_features['diocws']:
            self._awg_program[0] += \
                _array2vect(self._diocws, "diocws") + """
// Loop once for each DIO codeword to output
for (cvar i = 0; i < {}; i = i + 1) {{""".format(len(self._diocws))
        else:
            self._awg_program[0] += """
// Loop for all measurements
repeat (loop_cnt) {"""

        self._awg_program[0] += """
    waitDIOTrigger();
    // Get codeword and apply mask
    var cw = getDIOTriggered() & CW_MASK;
    // Generate waveforms based on codeword output
    switch (cw) {"""
        # Add each of the cases
        # FIXME: note that the actual wave timing (i.e. trigger latency) depends on the number of cases, because the
        #  switch statement generates a tree of if's internally. Consequentially, the maximum repetition rate also depends
        #  on the number of cases.
        for case in self._cases:
            self._awg_program[0] += """
        case 0x{:08x}: playWave({}, {});""".format(case << 17, zibase.gen_waveform_name(0, case), zibase.gen_waveform_name(1, case))

        # Add a default for ensuring we see something when the other cases fail
        self._awg_program[0] += """
        default: playWave(ones(32), ones(32)); err_cnt += 1;
    }
    wait(wait_dly);"""

        if self._awg_program_features['diocws']:
            self._awg_program[0] += """
    setDIO(diocws[i]);
"""
        self._awg_program[0] += """
    setTrigger(ro_trig);
    setTrigger(ro_arm);
}
wait(300);
setTrigger(0);
setUserReg(4, err_cnt);"""

        self._awg_needs_configuration[0] = True

    def _get_cases(self):
        return self._cases

    def _get_waveform_table(self, awg_nr: int) -> list:
        """
        Returns the waveform table.

        The waveform table determines the mapping of waveforms to DIO codewords.
        The index of the table corresponds to the DIO codeword.
        The entry is a tuple of waveform names.

        Example:
            ["wave_ch7_cw000", "wave_ch8_cw000",
            "wave_ch7_cw001", "wave_ch8_cw001",
            "wave_ch7_cw002", "wave_ch8_cw002"]

        The waveform table generated depends on the awg_nr and the codeword
        protocol.
        """
        ch = awg_nr*2
        wf_table = []
        if self.cases() is not None:
            for case in self.cases():
                wf_table.append((zibase.gen_waveform_name(ch, case),
                                 zibase.gen_waveform_name(ch+1, case)))
        return wf_table

    ##########################################################################
    ##########################################################################
    # Application dependent code starts here:
    # - dedicated sequence programs
    # - DIO support
    # FIXME: move to separate class
    ##########################################################################
    ##########################################################################

    ##########################################################################
    # 'public' functions: sequencer functions
    ##########################################################################
    """
    Before acquisition can take place one of "awg_sequence_acquisition_and_"
    has to be called. These take care that the right program is uploaded.
    The variants are:
        awg_sequence_acquisition
            start acquisition after receiving a trigger, play no pulse
        awg_sequence_acquisition_and_pulse
            start acquisition after receiving a trigger,
            play the specified pulse
        awg_sequence_acquisition_and_pulse_SSB
            start acquisition after receiving a trigger,
            play an SSB pulse based on specified parameters
        awg_sequence_acquisition_and_DIO_triggered_pulse
            start acquisition after receiving a DIO trigger,
            play the pulse specified by the received DIO codeword
            cases argument specifies what codewords are supported.
        awg_sequence_acquisition_and_DIO_RED_test
            special DIO acquisition for testing real time error correction.
    """

    def awg_sequence_acquisition_and_DIO_triggered_pulse(
            self, Iwaves=None, Qwaves=None, cases=None, acquisition_delay=0, timeout=5) -> None:
        """
        Loads the program for DIO acquisition on the AWG of the UHFQC.

        Arguments:
            Iwaves list of I waveforms (arrays) used (historical).
            Qwaves list of Q waveforms (arrays) used (historical).
            cases list of cases to include in the program.

        Uploads and compiles the AWG sequencer program.

        """
        # setting the acquisition delay samples
        delay_samples = int(acquisition_delay*1.8e9/8)
        self.wait_dly(delay_samples)

        # If no cases are defined, then we simply create all possible cases
        if cases is None:
            cases = np.arange(self._num_codewords)
        else:
            if len(cases) > self._num_codewords:
                raise zibase.ziConfigurationError('More cases ({}) defined than available codewords ({})!'.format(
                    len(cases), len(self._num_codewords)))

            # There is probably a more efficient way of doing this
            for case in cases:
                if (case < 0) or (case >= self._num_codewords):
                    raise zibase.ziConfigurationError(
                        'Case {} is out of range defined by the available codewords ({})!'.format(case, len(self._num_codewords)))

        # Sanity check on the parameters
        if Iwaves is not None and (len(Iwaves) != len(cases)):
            raise uhf.ziUHFQCSeqCError(
                'Number of I channel waveforms ({}) does not match number of cases ({})!'.format(len(Iwaves), len(cases)))

        if Qwaves is not None and (len(Qwaves) != len(cases)):
            raise uhf.ziUHFQCSeqCError(
                'Number of Q channel waveforms ({}) does not match number of cases ({})!'.format(len(Iwaves), len(cases)))

        # Sanity check on I channel waveforms
        if Iwaves is not None:
            for i, Iwave in enumerate(Iwaves):
                if np.max(Iwave) > 1.0 or np.min(Iwave) < -1.0:
                    raise KeyError(
                        "exceeding AWG range for I channel, all values should be within +/-1")
                if len(Iwave) > 16384:
                    raise KeyError(
                        "exceeding max AWG wave length of 16384 samples for I channel, trying to upload {} samples".format(len(Iwave)))

                # Update waveform table
                self.set(zibase.gen_waveform_name(0, cases[i]), Iwave)

        # Sanity check on Q channel waveforms
        if Qwaves is not None:
            for i, Qwave in enumerate(Qwaves):
                if np.max(Qwave) > 1.0 or np.min(Qwave) < -1.0:
                    raise KeyError(
                        "exceeding AWG range for Q channel, all values should be within +/-1")
                if len(Qwave) > 16384:
                    raise KeyError(
                        "exceeding max AWG wave length of 16384 samples for I channel, trying to upload {} samples".format(len(Qwave)))

                # Update waveform table
                self.set(zibase.gen_waveform_name(1, cases[i]), Qwave)

        # Define the behavior of our program
        self._reset_awg_program_features()
        self._awg_program_features['loop_cnt'] = True
        self._awg_program_features['wait_dly'] = True
        self._awg_program_features['waves'] = True
        self._awg_program_features['cases'] = True

        # Updating cases will cause our AWG program to update
        self.cases(cases)

    def awg_sequence_acquisition_and_DIO_RED_test(
            self, Iwaves=None, Qwaves=None, cases=None, acquisition_delay=0,
            dio_out_vect=None, timeout=5):

        # setting the acquisition delay samples
        delay_samples = int(acquisition_delay*1.8e9/8)
        # setting the delay in the instrument
        self.awgs_0_userregs_2(delay_samples)
        sequence = (
            'var wait_delay = getUserReg(2);\n' +
            'cvar i = 0;\n'+
            'const length = {};\n'.format(len(dio_out_vect))
            )
        sequence = sequence + _array2vect(dio_out_vect, "dio_out_vect")
        # starting the loop
        sequence = sequence +(
            'setDIO(2048); // FIXME: workaround because we cannot use setDIO(0)\n'+
            'for (i = 0; i < length; i = i + 1) {\n'
            ' var dio_out =  dio_out_vect[i];\n'+
            ' waitDIOTrigger();\n' +
            ' setDIO(dio_out);\n'+
            ' wait(wait_delay);\n' +
            ' setDIO(2048);\n'+
            '}\n'
            )

        # Define the behavior of our program
        self._reset_awg_program_features()
        self._awg_program[0] = sequence
        self._awg_needs_configuration[0] = True

    def awg_sequence_test_pattern(
            self,
            dio_out_vect=None):

        # setting the acquisition delay samples
        sequence = f"""
        cvar i = 0;
        const length = {len(dio_out_vect)};
        """
        sequence = sequence + _array2vect(dio_out_vect, "dio_out_vect")
        # starting the loop
        sequence = sequence + """
        setDIO(2048); // FIXME: workaround because we cannot use setDIO(0), still required in UHF firmware:65939
        for (i = 0; i < length; i = i + 1) {
          var dio_out =  dio_out_vect[i];
          waitDIOTrigger();
          setDIO(dio_out);
          wait(3);      // ~20 ns pulse time
          setDIO(2048);
        }
        """

        # Define the behavior of our program
        self._reset_awg_program_features()
        self._awg_program[0] = inspect.cleandoc(sequence)
        self._awg_needs_configuration[0] = True

    def awg_sequence_acquisition_and_pulse(self, Iwave=None, Qwave=None, acquisition_delay=0, dig_trigger=True) -> None:
        if Iwave is not None and (np.max(Iwave) > 1.0 or np.min(Iwave) < -1.0):
            raise KeyError(
                "exceeding AWG range for I channel, all values should be within +/-1")

        if Qwave is not None and (np.max(Qwave) > 1.0 or np.min(Qwave) < -1.0):
            raise KeyError(
                "exceeding AWG range for Q channel, all values should be within +/-1")

        if Iwave is not None and (len(Iwave) > 16384):
            raise KeyError(
                "exceeding max AWG wave length of 16384 samples for I channel, trying to upload {} samples".format(len(Iwave)))

        if Qwave is not None and (len(Qwave) > 16384):
            raise KeyError(
                "exceeding max AWG wave length of 16384 samples for Q channel, trying to upload {} samples".format(len(Qwave)))

        # Check the we have sufficient codewords defined
        if self._num_codewords < 1:
            raise zibase.ziConfigurationError(
                'Insufficient number of codewords defined! Need at least 1 codeword.')

        # Configure the actual waveforms
        if Iwave is not None:
            self.set(zibase.gen_waveform_name(0, 0), Iwave)

        if Qwave is not None:
            self.set(zibase.gen_waveform_name(1, 0), Qwave)

        # Configure the delay
        self.set('awgs_0_userregs_{}'.format(UHFQC.USER_REG_WAIT_DLY),
                 int(acquisition_delay*1.8e9/8))

        delay_string = """
    wait(wait_dly);
"""

        playWave_string = """
    playWave({}, {});
        """.format(zibase.gen_waveform_name(0, 0), zibase.gen_waveform_name(1, 0))

        if dig_trigger:
            loop_start = """
repeat (loop_cnt) {
    waitDigTrigger(1, 1);
"""
        else:
            loop_start = """
repeat (loop_cnt) {
"""
        loop_end = """
    setTrigger(ro_trig);
    setTrigger(ro_arm);
    waitWave();
    wait(4000);
}
setTrigger(0);
"""

        self._reset_awg_program_features()
        self._awg_program_features['loop_cnt'] = True
        self._awg_program_features['wait_dly'] = True
        self._awg_program_features['waves'] = True

        self._awg_program[0] = \
            awg_sequence_acquisition_preamble() + \
            loop_start + \
            playWave_string + \
            delay_string + \
            loop_end

        self._awg_needs_configuration[0] = True

    def awg_sequence_acquisition(self):
        self._reset_awg_program_features()
        self._awg_program_features['loop_cnt'] = True

        self._awg_program[0] = awg_sequence_acquisition_preamble() + """
repeat (loop_cnt) {
    waitDigTrigger(1, 1);
    setTrigger(ro_trig);
    setTrigger(ro_arm);
}
setTrigger(0);
"""
        # Reset delay
        self.wait_dly(0)
        self._awg_needs_configuration[0] = True

    def awg_debug_acquisition(self, dly=0):
        self._reset_awg_program_features()
        self._awg_program_features['avg_cnt']  = True
        self._awg_program_features['loop_cnt'] = True
        self._awg_program_features['wait_dly'] = True

        self._awg_program[0] = awg_sequence_acquisition_preamble() + """
repeat (avg_cnt) {
  repeat (loop_cnt) {
      setTrigger(ro_trig);
      setTrigger(ro_arm);
      wait(wait_dly);
  }
}
setTrigger(0);
"""
        # Reset delay
        self.wait_dly(dly)
        self._awg_needs_configuration[0] = True

    def awg_sequence_acquisition_and_pulse_SSB(
            self, f_RO_mod, RO_amp, RO_pulse_length, acquisition_delay, dig_trigger=True) -> None:
        f_sampling = 1.8e9
        samples = RO_pulse_length*f_sampling
        array = np.arange(int(samples))
        sinwave = RO_amp * np.sin(2 * np.pi*array*f_RO_mod/f_sampling)
        coswave = RO_amp * np.cos(2 * np.pi*array*f_RO_mod/f_sampling)
        Iwave = (coswave+sinwave) / np.sqrt(2)
        Qwave = (coswave-sinwave) / np.sqrt(2)
        self.awg_sequence_acquisition_and_pulse(
            Iwave, Qwave, acquisition_delay, dig_trigger=dig_trigger)

    def spec_mode_on(self, acq_length=1/1500, IF=20e6, ro_amp=0.1, wint_length=2**14) -> None:
        self._reset_awg_program_features()
        self._awg_program_features['loop_cnt'] = True
        self._awg_program_features['avg_cnt'] = True
        self._awg_program_features['waves'] = True

        # Reset delay
        self.wait_dly(0)

        # Check the we have sufficient codewords defined
        if self._num_codewords < 1:
            raise zibase.ziConfigurationError(
                'Insufficient number of codewords defined! Need at least 1 codeword.')

        # Define number of samples
        N = 16

        # Define alpha parameter
        alpha = 0.2

        # Define support parameters
        a0 = (1-alpha)/2
        a1 = 1/2
        a2 = alpha/2

        # Generate window function
        w = a0 - \
            a1 * np.cos(2 * np.pi * np.arange(N)/(N-1)) + \
            a2 * np.cos(4 * np.pi * np.arange(N)/(N-1))

        # Configure the actual waveforms
        self.set(zibase.gen_waveform_name(0, 0), w)
        self.set(zibase.gen_waveform_name(1, 0), w)

        playWave_string = """
    playWave({}, {});
        """.format(zibase.gen_waveform_name(0, 0), zibase.gen_waveform_name(1, 0))

        wait_string = """
    waitQAResultTrigger();
    wait(16);
        """

        self._awg_program[0] = awg_sequence_acquisition_preamble() + """
repeat (avg_cnt) {
  var wait_time = 0;

  repeat(loop_cnt) {
    wait_time = wait_time + 1;
    setTrigger(ro_trig);
    setTrigger(ro_arm);
    wait(wait_time);
""" + playWave_string + wait_string + """
  }
}
setTrigger(0);
"""

        # Also added by us
        self.awgs_0_outputs_0_mode(1)
        self.awgs_0_outputs_1_mode(1)

        # setting the internal oscillator to the IF
        self.oscs_0_freq(IF)

        self.sigouts_0_on(1)
        self.sigouts_1_on(1)

        # QuExpress thresholds on DIO (mode == 2), AWG control of DIO (mode == 1)
        self.dios_0_mode(self.DIOS_0_MODE_AWG_WAV)
        # Drive DIO bits 31 to 16
        self.dios_0_drive(0xc)

        # setting the integration path to use the oscillator instead of
        # integration functions. Should be done before modifying the length.
        self.qas_0_integration_mode(1)

        self.qas_0_deskew_rows_0_cols_0(1.0)
        self.qas_0_deskew_rows_0_cols_1(0.0)
        self.qas_0_deskew_rows_1_cols_0(0.0)
        self.qas_0_deskew_rows_1_cols_1(1.0)
        self.qas_0_integration_length(wint_length)
        self.qas_0_delay(0)

        # Copy from the manual
        self.qas_0_rotations_0(1.0 + 0.0j)
        self.qas_0_rotations_1(0.0 + 1.0j)

        for i in range(0, 10):
            for j in range(0, 10):
                self.set('qas_0_crosstalk_rows_{0}_cols_{1}'.format(
                    i, j), 1.0*(i == j))

        # Configure some thresholds
        for i in range(0, 10):
            self.set('qas_0_thresholds_{}_level'.format(i), 0.01)

        # Also adder by us
        # result_source 0 => lin_trans readout(includes crosstalk corr)
        self.qas_0_result_source(0)
        self.qas_0_result_enable(1)
        self.qas_0_result_statistics_enable(0)

        self._awg_needs_configuration[0] = True

    def spec_mode_off(self) -> None:
        # Resetting To regular Mode
        # changing int length
        self.qas_0_integration_mode(0)

        # Default settings copied
        self.qas_0_rotations_0(1.0 + 0.0j)
        self.qas_0_rotations_1(1.0 + 0.0j)

        # setting to DSB by default
        self.qas_0_deskew_rows_0_cols_0(1.0)
        self.qas_0_deskew_rows_0_cols_1(0.0)
        self.qas_0_deskew_rows_1_cols_0(0.0)
        self.qas_0_deskew_rows_1_cols_1(1.0)

        # switching off the modulation tone
        self.awgs_0_outputs_0_mode(0)
        self.awgs_0_outputs_1_mode(0)

    ##########################################################################
    # DIO calibration helpers
    ##########################################################################

    def _ensure_activity(self, awg_nr, mask_value: int, timeout=5):
        """
        Record DIO data and test whether there is activity on the bits activated in the DIO protocol for the given AWG.
        """
        log.debug(f"{self.devname}: Testing DIO activity for AWG {awg_nr}")

        vld_mask     = 1 << self.geti('awgs/{}/dio/valid/index'.format(awg_nr))
        vld_polarity = self.geti('awgs/{}/dio/valid/polarity'.format(awg_nr))
        strb_mask    = (1 << self.geti('awgs/{}/dio/strobe/index'.format(awg_nr)))
        strb_slope   = self.geti('awgs/{}/dio/strobe/slope'.format(awg_nr))

        cw_mask = mask_value  # FIXME: changed parameter to define mask that's already shifted in place << 17

        for i in range(timeout):
            valid = True

            data = self.getv('awgs/0/dio/data')
            if data is None:
                raise zibase.ziValueError('Failed to get DIO snapshot!')

            vld_activity = 0
            strb_activity = 0
            cw_activity = 0
            for d in data:
                cw_activity |= (d & cw_mask)
                vld_activity |= (d & vld_mask)
                strb_activity |= (d & strb_mask)

            if cw_activity != cw_mask:
                log.warning(f"{self.devname}: Did not see all codeword bits toggle! Got 0x{cw_activity:08x}, expected 0x{cw_mask:08x}.")
                valid = False

            if vld_polarity != 0 and vld_activity != vld_mask:
                log.warning("{self.devname}: Did not see valid bit toggle!")
                valid = False

            if strb_slope != 0 and strb_activity != strb_mask:
                log.warning("{self.devname}: Did not see strobe bit toggle!")
                valid = False

            if valid:
                return True

        return False

    def _get_awg_dio_data(self, awg):
        data = self.getv('awgs/' + str(awg) + '/dio/data')
        ts = len(data)*[0]
        cw = len(data)*[0]
        for n, d in enumerate(data):
            ts[n] = d >> 10
            cw[n] = (d & ((1 << 10)-1))
        return (ts, cw)

    def _find_valid_delays(self, awg_nr, mask_value: int):
        """Finds valid DIO delay settings for a given AWG by testing all allowed delay settings for timing violations on the
        configured bits. In addition, it compares the recorded DIO codewords to an expected sequence to make sure that no
        codewords are sampled incorrectly."""
        log.debug("{self.devname}: Finding valid delays")

        vld_mask     = 1 << self.geti('awgs/{}/dio/valid/index'.format(awg_nr))
        vld_polarity = self.geti('awgs/{}/dio/valid/polarity'.format(awg_nr))
        strb_mask    = (1 << self.geti('awgs/{}/dio/strobe/index'.format(awg_nr)))
        strb_slope   = self.geti('awgs/{}/dio/strobe/slope'.format(awg_nr))

        cw_mask = mask_value << 17

        combined_mask = cw_mask
        if vld_polarity != 0:
            combined_mask |= vld_mask
        if strb_slope != 0:
            combined_mask |= strb_mask
        log.debug(f"{self.devname}:   Using a mask value of 0x{combined_mask:08x}")

        valid_delays= []
        for delay in range(12):  # NB: 16 steps are available, but 2 periods of 20 ns should suffice
            log.debug(f'{self.devname}:    Testing delay {delay}')
            self.setd('raw/dios/0/delay', delay)  # in 1/300 MHz = 3.33 ns steps
            try:
                # LabOne 22.02 and higher: clear the sticky timing error detection bits
                self.setd('raw/dios/0/error/timingclear', 0xffffffff)
            except RuntimeError:
                # no timingclear node available
                pass
            time.sleep(0.5)
            valid_sequence = True
            for awg in [0]:
                try:
                    # LabOne 22.02 and higher: read out timing errors that accumulated since the last call to "timingclear"
                    error_timing = self.geti('raw/dios/0/error/timingsticky')
                except RuntimeError:
                    error_timing = self.geti('raw/dios/0/error/timing')
                if error_timing & combined_mask != 0:
                    valid_sequence = False

            if valid_sequence:
                valid_delays.append(delay)

        return set(valid_delays)

    ##########################################################################
    # overrides for CalInterface interface
    ##########################################################################

    def output_dio_calibration_data(self, dio_mode: str, port: int=0) -> Tuple[int, List]:
        # NB: ignoring dio_mode and port, because we have single mode only
        program = """
        // program: triggered upstream DIO calibration program
        const period = 18;          // 18*4.44 ns = 80 ns, NB: 40 ns is not attainable
        const n1 = 3;               // ~20 ns high time
        const n2 = period-n1-2-1;   // penalties: 2*setDIO, 1*loop
        waitDIOTrigger();
        while (1) {
            setDIO(0x000003FF);     // DV=0x0001, RSLT[8:0]=0x03FE.
            wait(n1);
            setDIO(0x00000000);
            wait(n2);
        }
        """
        self.configure_awg_from_string(0, program)
        # FIXME: set uhfqa0.dios_0_mode(uhfqa0.DIOS_0_MODE_AWG_SEQ), but reset after the calibration is done
        self.seti('awgs/0/enable', 1)  # FIXME: check success, use start()?

        dio_mask = 0x000003FF
        expected_sequence = []
        return dio_mask,expected_sequence

    def calibrate_dio_protocol(self, dio_mask: int, expected_sequence: List, port: int=0):
        log.info(f"{self.devname}: Calibrating DIO protocol")
        self.assure_ext_clock()

        # Get the integration length and result enable settings to be able to
        # restore them later
        integration_length = self.get('qas_0_integration_length')
        result_enable = self.get('qas_0_result_enable')
        monitor_enable = self.get('qas_0_monitor_enable')
        awg_enable = self.get('awgs_0_enable')

        try:
          self.set('qas_0_integration_length', 4)
          self.set('qas_0_result_enable', 0)
          self.set('qas_0_monitor_enable', 0)
          self.set('awgs_0_enable', 0)

          for awg in [0]:
              if not self._ensure_activity(awg, mask_value=dio_mask):
                  raise uhf.ziUHFQCDIOActivityError('No or insufficient activity found on the DIO bits associated with AWG {}'.format(awg))

          valid_delays = self._find_valid_delays(awg, mask_value=dio_mask)
          if len(valid_delays) == 0:
              raise uhf.ziUHFQCDIOCalibrationError('DIO calibration failed! No valid delays found')

          # Find center of first valid region
          subseq = [[]]
          for e in valid_delays:
              if not subseq[-1] or subseq[-1][-1] == e - 1:
                  subseq[-1].append(e)
              else:
                  subseq.append([e])

          subseq = max(subseq, key=len)
          delay = len(subseq)//2 + subseq[0]

          # Print information
          log.info(f"{self.devname}: Valid delays are {valid_delays}")

          # And configure the delays
          self._set_dio_calibration_delay(delay)

          # Clear all detected errors (caused by DIO timing calibration)
          self.check_errors(errors_to_ignore=['AWGDIOTIMING'])

        finally:
          # Restore settings either in case of an exception or if the DIO
          # routine finishes correctly
          self.set('qas_0_integration_length', integration_length)
          self.set('qas_0_result_enable', result_enable)
          self.set('qas_0_monitor_enable', monitor_enable)
          self.set('awgs_0_enable', awg_enable)

    ##########################################################################
    # DIO calibration functions for *CC*
    ##########################################################################

    def calibrate_CC_dio_protocol(self, CC, feedline=None, verbose=False) -> None:
        raise DeprecationWarning("calibrate_CC_dio_protocol is deprecated, use instrument_drivers.library.DIO.calibrate")

##########################################################################
# Module level functions
##########################################################################

def awg_sequence_acquisition_preamble():
    """
    This function defines a standard AWG program preamble, which is used
    regardless of the specific acquisition mode. The preamble defines standard
    functionality of the user registers, which are used for dynamically
    controlling e.g. number of iterations in a loop, etc.
    The preamble also defines a standard way of selecting between triggering
    the readout units or the time-domain input monitor.
    """
    preamble = """
// Reset error counter
setUserReg(4, 0);

// Define standard variables
var loop_cnt = getUserReg(0);
var ro_mode  = getUserReg(1);
var wait_dly = getUserReg(2);
var avg_cnt  = getUserReg(3);
var ro_arm;
var ro_trig;

// Configure readout mode
if (ro_mode) {
  ro_arm  = AWG_INTEGRATION_ARM;
  ro_trig = AWG_MONITOR_TRIGGER + AWG_INTEGRATION_ARM + AWG_INTEGRATION_TRIGGER;
} else {
  ro_arm  = AWG_INTEGRATION_ARM;
  ro_trig = AWG_INTEGRATION_ARM + AWG_INTEGRATION_TRIGGER;
}"""
    return preamble

def _array2vect(array, name):
    # this function cuts up arrays into several vectors of maximum length 1024 that are joined.
    # this is to avoid python crashes (was found to crash for vectors of
    # length> 1490)
    if len(array) > 1024:
        splitted_array = np.array_split(array, len(array) // 1024)
        string_array = ['\nvect(' + ','.join(['{:.8f}'.format(x)
                                              for x in sub_array]) + ')' for sub_array in splitted_array]
        return 'wave ' + name + ' = join(' + ','.join(string_array) + ');\n'
    else:
        return 'wave ' + name + ' = ' + 'vect(' + ','.join(['{:.8f}'.format(x) for x in array]) + ');\n'


text:
<?php

/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */

/**
 * Main template engine file
 *
 * PHP version 5
 *
 * LICENSE: Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
 * of the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 * @category  Templates
 * @package   Bandar
 * @author    Yani Iliev <yani@iliev.me>
 * @copyright 2013 Yani Iliev
 * @license   https://raw.github.com/yani-/bandar/master/LICENSE The MIT License (MIT)
 * @version   GIT: 3.0.0
 * @link      https://github.com/yani-/bandar/
 */

/**
 * Define EOL for CLI and Web
 */
if (!defined('BANDAR_EOL')) {
    define('BANDAR_EOL', php_sapi_name() === 'cli' ? PHP_EOL : '<br />');
}

/**
 * Include exceptions
 */
require_once
    dirname(__FILE__) .
    DIRECTORY_SEPARATOR .
    'Exceptions' .
    DIRECTORY_SEPARATOR .
    'TemplateDoesNotExistException.php';

/**
 * Bandar Main class
 *
 * @category  Templates
 * @package   Bandar
 * @author    Yani Iliev <yani@iliev.me>
 * @copyright 2013 Yani Iliev
 * @license   https://raw.github.com/yani-/bandar/master/LICENSE The MIT License (MIT)
 * @version   Release: 2.0.1
 * @link      https://github.com/yani-/bandar/
 */
class Bandar
{
    /**
     * Path to template files
     *
     * @var string|null
     */
    public static $templatesPath = null;

    /**
     * Template file to output
     * @var string|null
     */
    public static $template = null;

    /**
     * Outputs the passed string if Bandar is in debug mode
     *
     * @param string $str Debug string to output
     *
     * @return void
     */
    public static function debug($str)
    {
        /**
         * if debug flag is on, output the string
         */
        if (defined('BANDAR_DEBUG') && BANDAR_DEBUG) {
            echo $str;
        }
    }

    /**
     * Retrieves templatesPath from BANDAR_TEMPLATES_PATH constant
     *
     * @throws TemplatesPathNotSetException If BANDAR_TEMPLATES_PATH is not defined
     *
     * @return string|null Templates path
     */
    public static function getTemplatesPathFromConstant()
    {
        self::debug(
            'Calling getTemplatesPathFromConstant' . BANDAR_EOL
        );
        if (defined('BANDAR_TEMPLATES_PATH')) {
            return realpath(BANDAR_TEMPLATES_PATH) . DIRECTORY_SEPARATOR;
        }
        return null;
    }

    /**
     * Setter for template
     *
     * @param string $template Template file
     *
     * @throws TemplateDoesNotExistException If template file is not found
     *
     * @return null
     */
    public static function setTemplate($template, $path = false)
    {
        self::debug(
            'Calling setTemplate with' . BANDAR_EOL .
            '$template = ' . $template . BANDAR_EOL .
            'type of $template is ' . gettype($template) . BANDAR_EOL
        );

        if ($path) {
            $template = realpath($path) . DIRECTORY_SEPARATOR . $template;
        } else {
            $template = self::getTemplatesPathFromConstant() . $template;
        }

        $template = realpath($template . '.php');
        /**
         * Check if passed template exist
         */
        if (self::templateExists($template)) {
            self::$template = $template;
        } else {
            throw new TemplateDoesNotExistException;
        }
    }

    /**
     * Checks if template exists by using file_exists
     *
     * @param string $template Template file
     *
     * @return boolean
     */
    public static function templateExists($template)
    {
        self::debug(
            'Calling templateExists with ' . BANDAR_EOL .
            '$template = ' . $template . BANDAR_EOL .
            'type of $template is ' . gettype($template) . BANDAR_EOL
        );
        return (!is_dir($template) && is_readable($template));
    }

    /**
     * Renders a passed template
     *
     * @param string $template Template name
     * @param array  $args     Variables to pass to the template file
     *
     * @return string Contents of the template
     */
    public static function render($template, $args=array(), $path = false)
    {
        self::debug(
            'Calling render with' .
            '$template = ' . $template . BANDAR_EOL .
            'type of $template is ' . gettype($template) . BANDAR_EOL .
            '$args = ' . print_r($args, true) . BANDAR_EOL .
            'type of $args is ' . gettype($args) . BANDAR_EOL
        );
        self::setTemplate($template, $path);
        /**
         * Extracting passed aguments
         */
        extract($args);
        ob_start();
        /**
         * Including the view
         */
        include self::$template;

        return ob_get_flush();
    }

    /**
     * Returns the content of a passed template
     *
     * @param string $template Template name
     * @param array  $args     Variables to pass to the template file
     *
     * @return string Contents of the template
     */
    public static function getTemplateContent($template, $args=array(), $path = false)
    {
        self::debug(
            'Calling render with' .
            '$template = ' . $template . BANDAR_EOL .
            'type of $template is ' . gettype($template) . BANDAR_EOL .
            '$args = ' . print_r($args, true) . BANDAR_EOL .
            'type of $args is ' . gettype($args) . BANDAR_EOL
        );
        self::setTemplate($template, $path);
        /**
         * Extracting passed aguments
         */
        extract($args);
        ob_start();
        /**
         * Including the view
         */
        include self::$template;

        $content = ob_get_contents();
        ob_end_clean();

        return $content;
    }
}

redpajama_set_name: RedPajamaGithub


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">
    <title> passthegas v0.0</title>

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

basic web app yo


text:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

    <meta http-equiv="content-type" content="text/html; charset=utf-8"/>
    <title>Statistics of Number in UD_Faroese-OFT</title>
    <link rel="root" href=""/>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css">
    <link rel="stylesheet" type="text/css" href="../../css/jquery-ui-redmond.css"/>
    <link rel="stylesheet" type="text/css" href="../../css/style.css"/>
    <link rel="stylesheet" type="text/css" href="../../css/style-vis.css"/>
    <link rel="stylesheet" type="text/css" href="../../css/hint.css"/>

          home

          edit page
          issue tracker

          <gcse:search></gcse:search>

        This page pertains to UD version 2.

            It appears that you have Javascript disabled.
            Please consider enabling Javascript for this page to see the visualizations.

Treebank Statistics: UD_Faroese-OFT: Features: Number

This feature is universal.
It occurs with 2 different values: Plur, Sing.

5754 tokens (58%) have a non-empty value of Number.
2758 types (88%) occur at least once with a non-empty value of Number.
1992 lemmas (83%) occur at least once with a non-empty value of Number.
The feature is used with 9 part-of-speech tags: <tt>NOUN</tt> (2435; 24% instances), <tt>AUX</tt> (949; 9% instances), <tt>PROPN</tt> (802; 8% instances), <tt>ADJ</tt> (713; 7% instances), <tt>VERB</tt> (390; 4% instances), <tt>PRON</tt> (243; 2% instances), <tt>DET</tt> (184; 2% instances), <tt>NUM</tt> (34; 0% instances), <tt>ADV</tt> (4; 0% instances).

NOUN

2435 <tt>NOUN</tt> tokens (98% of all NOUN tokens) have a non-empty value of Number.

The most frequent other feature values with which NOUN and Number co-occurred: <tt>Definite</tt><tt>=Ind</tt> (1497; 61%), <tt>Case</tt><tt>=Nom</tt> (1468; 60%).

NOUN tokens may have the following values of Number:

Plur (559; 23% of non-empty Number): fólk, kommunur, býnum, døgum, ferðir, Føturnir, býir, indiánar, minuttir, muslimar

Sing (1876; 77% of non-empty Number): býur, høvuðsstaður, býurin, høvuðsstaðurin, kommuna, fólkinum, landslutinum, partur, týdning, Meginparturin

EMPTY (62): USA, ES, t.d., uml., mió, A, á.Kr., FLOT, FU, FUR

Paradigm býur	<tt>Sing</tt>	<tt>Plur</tt>

<tt><tt>Case</tt><tt>=Acc</tt>|<tt>Definite</tt><tt>=Def</tt></tt>	býin	býirnar

<tt><tt>Case</tt><tt>=Acc</tt>|<tt>Definite</tt><tt>=Ind</tt></tt>	bý

<tt><tt>Case</tt><tt>=Dat</tt>|<tt>Definite</tt><tt>=Def</tt></tt>	býinum	býnum

<tt><tt>Case</tt><tt>=Dat</tt>|<tt>Definite</tt><tt>=Ind</tt></tt>		býum

<tt><tt>Case</tt><tt>=Nom</tt>|<tt>Definite</tt><tt>=Def</tt></tt>	býurin

<tt><tt>Case</tt><tt>=Nom</tt>|<tt>Definite</tt><tt>=Ind</tt></tt>	býur	býir

Number seems to be lexical feature of NOUN. 92% lemmas (1061) occur only with one value of Number.

AUX

949 <tt>AUX</tt> tokens (98% of all AUX tokens) have a non-empty value of Number.

The most frequent other feature values with which AUX and Number co-occurred: <tt>Mood</tt><tt>=Ind</tt> (949; 100%), <tt>Tense</tt><tt>=Pres</tt> (797; 84%), <tt>Person</tt><tt>=3</tt> (701; 74%).

AUX tokens may have the following values of Number:

Plur (243; 26% of non-empty Number): eru, vóru, hava, kunnu, skulu, máttu, mugu, verða

Sing (706; 74% of non-empty Number): er, var, hevur, verður, varð, kann, skal, skuldi, havi, hevði

EMPTY (18): verið, vera

Paradigm vera	<tt>Sing</tt>	<tt>Plur</tt>

<tt><tt>Person</tt><tt>=3</tt>|<tt>Tense</tt><tt>=Past</tt></tt>	var

<tt><tt>Person</tt><tt>=3</tt>|<tt>Tense</tt><tt>=Pres</tt></tt>	er, varir

<tt><tt>Tense</tt><tt>=Past</tt></tt>		vóru

<tt><tt>Tense</tt><tt>=Pres</tt></tt>		eru

PROPN

802 <tt>PROPN</tt> tokens (100% of all PROPN tokens) have a non-empty value of Number.

The most frequent other feature values with which PROPN and Number co-occurred: <tt>Definite</tt><tt>=EMPTY</tt> (554; 69%), <tt>Gender</tt><tt>=EMPTY</tt> (473; 59%), <tt>Case</tt><tt>=Nom</tt> (460; 57%).

PROPN tokens may have the following values of Number:

Plur (79; 10% of non-empty Number): Føroyum, Føroya, Føroyar, Niðurlondum, Niðurlond, Hellurnar

Sing (723; 90% of non-empty Number): Noregi, Danmark, Kanada, Amerika, Kina, Fraklandi, Italia, Keypmannahavn, New, Nigeria

EMPTY (3): Belis, Eyguni, Søgur

Number seems to be lexical feature of PROPN. 100% lemmas (425) occur only with one value of Number.

ADJ

713 <tt>ADJ</tt> tokens (94% of all ADJ tokens) have a non-empty value of Number.

The most frequent other feature values with which ADJ and Number co-occurred: <tt>Degree</tt><tt>=EMPTY</tt> (608; 85%), <tt>Case</tt><tt>=Nom</tt> (522; 73%), <tt>Definite</tt><tt>=Ind</tt> (485; 68%), <tt>Gender</tt><tt>=Masc</tt> (408; 57%).

ADJ tokens may have the following values of Number:

Plur (243; 34% of non-empty Number): nógv, fleiri, nógvar, mong, Flestu, stórir, aðrar, aðrir, mangir, stór

Sing (470; 66% of non-empty Number): størsti, størsta, stórur, stóran, nógvur, stórt, føroyskur, sama, amerikanska, stór

EMPTY (47): 2., 1., 18., 19., annað, onnur, 11., 12., 16., 17.

Paradigm stórur	<tt>Sing</tt>	<tt>Plur</tt>

<tt><tt>Case</tt><tt>=Acc</tt>|<tt>Definite</tt><tt>=Def</tt>|<tt>Degree</tt><tt>=Sup</tt>|<tt>Gender</tt><tt>=Masc</tt></tt>		Størstu

<tt><tt>Case</tt><tt>=Acc</tt>|<tt>Definite</tt><tt>=Ind</tt>|<tt>Gender</tt><tt>=Masc</tt></tt>	stóran	stórar

<tt><tt>Case</tt><tt>=Acc</tt>|<tt>Definite</tt><tt>=Ind</tt>|<tt>Gender</tt><tt>=Fem</tt></tt>	stóra

<tt><tt>Case</tt><tt>=Acc</tt>|<tt>Definite</tt><tt>=Ind</tt>|<tt>Gender</tt><tt>=Neut</tt></tt>	stórt	stór

<tt><tt>Case</tt><tt>=Dat</tt>|<tt>Definite</tt><tt>=Def</tt>|<tt>Degree</tt><tt>=Sup</tt>|<tt>Gender</tt><tt>=Masc</tt></tt>	størsta	størstu

<tt><tt>Case</tt><tt>=Dat</tt>|<tt>Definite</tt><tt>=Def</tt>|<tt>Gender</tt><tt>=Neut</tt></tt>		stóru

<tt><tt>Case</tt><tt>=Dat</tt>|<tt>Definite</tt><tt>=Ind</tt>|<tt>Gender</tt><tt>=Masc</tt></tt>	stórum	stórum

<tt><tt>Case</tt><tt>=Dat</tt>|<tt>Definite</tt><tt>=Ind</tt>|<tt>Gender</tt><tt>=Fem</tt></tt>		stórum

<tt><tt>Case</tt><tt>=Dat</tt>|<tt>Definite</tt><tt>=Ind</tt>|<tt>Gender</tt><tt>=Neut</tt></tt>	stórum

<tt><tt>Case</tt><tt>=Nom</tt>|<tt>Definite</tt><tt>=Def</tt>|<tt>Degree</tt><tt>=Sup</tt>|<tt>Gender</tt><tt>=Masc</tt></tt>	størsti

<tt><tt>Case</tt><tt>=Nom</tt>|<tt>Definite</tt><tt>=Def</tt>|<tt>Degree</tt><tt>=Sup</tt>|<tt>Gender</tt><tt>=Fem</tt></tt>	størsta

<tt><tt>Case</tt><tt>=Nom</tt>|<tt>Definite</tt><tt>=Def</tt>|<tt>Degree</tt><tt>=Sup</tt>|<tt>Gender</tt><tt>=Neut</tt></tt>	størsta	Størstu

<tt><tt>Case</tt><tt>=Nom</tt>|<tt>Definite</tt><tt>=Def</tt>|<tt>Gender</tt><tt>=Masc</tt></tt>	stóri

<tt><tt>Case</tt><tt>=Nom</tt>|<tt>Definite</tt><tt>=Ind</tt>|<tt>Gender</tt><tt>=Masc</tt></tt>	stórur	stórir

<tt><tt>Case</tt><tt>=Nom</tt>|<tt>Definite</tt><tt>=Ind</tt>|<tt>Gender</tt><tt>=Fem</tt></tt>	stór	stórar

<tt><tt>Case</tt><tt>=Nom</tt>|<tt>Definite</tt><tt>=Ind</tt>|<tt>Gender</tt><tt>=Neut</tt></tt>	stórt, størri	stór

VERB

390 <tt>VERB</tt> tokens (68% of all VERB tokens) have a non-empty value of Number.

The most frequent other feature values with which VERB and Number co-occurred: <tt>VerbForm</tt><tt>=EMPTY</tt> (383; 98%), <tt>Mood</tt><tt>=Ind</tt> (374; 96%), <tt>Person</tt><tt>=3</tt> (239; 61%), <tt>Tense</tt><tt>=Pres</tt> (210; 54%).

VERB tokens may have the following values of Number:

Plur (73; 19% of non-empty Number): eru, búgva, doyðu, búsettust, búðu, hava, hjálpa, tala, vórðu, Drívið

Sing (317; 81% of non-empty Number): býr, hevur, kom, liggur, Sí, fer, varð, fór, er, stendur

EMPTY (183): síggja, sæst, fáa, gera, koma, byggja, eta, gjørt, hava, kent

Paradigm hava	<tt>Sing</tt>	<tt>Plur</tt>

<tt><tt>Person</tt><tt>=3</tt>|<tt>Tense</tt><tt>=Pres</tt></tt>	hevur

<tt><tt>Tense</tt><tt>=Past</tt></tt>	hevði

<tt><tt>Tense</tt><tt>=Pres</tt></tt>		hava

PRON

243 <tt>PRON</tt> tokens (83% of all PRON tokens) have a non-empty value of Number.

The most frequent other feature values with which PRON and Number co-occurred: <tt>PronType</tt><tt>=Prs</tt> (201; 83%), <tt>Case</tt><tt>=Nom</tt> (199; 82%), <tt>Person</tt><tt>=3</tt> (190; 78%).

PRON tokens may have the following values of Number:

Plur (30; 12% of non-empty Number): teir, tey, vit, nakrir, Allir, Báðir, Summir, hesir, okkara, okkum

Sing (213; 88% of non-empty Number): hon, hann, tað, hetta, hansara, henni, honum, eg, hennara, Hatta

EMPTY (49): sum, seg, ið, sær

Paradigm tað	<tt>Sing</tt>	<tt>Plur</tt>

<tt><tt>Case</tt><tt>=Acc</tt></tt>	tað	tey

<tt><tt>Case</tt><tt>=Nom</tt></tt>	tað	tey

DET

184 <tt>DET</tt> tokens (99% of all DET tokens) have a non-empty value of Number.

The most frequent other feature values with which DET and Number co-occurred: <tt>Case</tt><tt>=Nom</tt> (144; 78%), <tt>Gender</tt><tt>=Masc</tt> (94; 51%).

DET tokens may have the following values of Number:

Plur (12; 7% of non-empty Number): allir, Summir, Allar, mínir, síni, Øll

Sing (172; 93% of non-empty Number): ein, eitt, einum, eina, allan, sínum, øll, allur, eini, sína

EMPTY (2): alt, annað

Paradigm allur	<tt>Sing</tt>	<tt>Plur</tt>

<tt><tt>Case</tt><tt>=Acc</tt>|<tt>Gender</tt><tt>=Masc</tt></tt>	allan	allir

<tt><tt>Case</tt><tt>=Dat</tt>|<tt>Gender</tt><tt>=Fem</tt></tt>	allari

<tt><tt>Case</tt><tt>=Nom</tt>|<tt>Gender</tt><tt>=Masc</tt></tt>	allur	allir

<tt><tt>Case</tt><tt>=Nom</tt>|<tt>Gender</tt><tt>=Fem</tt></tt>	øll	Allar

<tt><tt>Case</tt><tt>=Nom</tt>|<tt>Gender</tt><tt>=Neut</tt></tt>		Øll

NUM

34 <tt>NUM</tt> tokens (14% of all NUM tokens) have a non-empty value of Number.

The most frequent other feature values with which NUM and Number co-occurred: <tt>Case</tt><tt>=Nom</tt> (27; 79%), <tt>Gender</tt><tt>=Fem</tt> (23; 68%).

NUM tokens may have the following values of Number:

Sing (34; 100% of non-empty Number): ein, tveir, trý, tvær, trimum, tríggjar, tveimum, tvey

EMPTY (205): %, 2005, 2011, 10, 2010, 4, 18, 20, 2008, 26

ADV

4 <tt>ADV</tt> tokens (1% of all ADV tokens) have a non-empty value of Number.

ADV tokens may have the following values of Number:

Plur (4; 100% of non-empty Number): vanliga, størsta, veldiga

EMPTY (422): eisini, ikki, har, nú, so, enn, tó, tá, fyrr, ofta

Relations with Agreement in Number

The 10 most frequent relations where parent and child node agree in Number:
<tt>NOUN –[<tt>amod</tt>]–> ADJ</tt> (541; 89%),
<tt>NOUN –[<tt>cop</tt>]–> AUX</tt> (465; 79%),
<tt>NOUN –[<tt>nsubj</tt>]–> NOUN</tt> (206; 67%),
<tt>VERB –[<tt>nsubj</tt>]–> NOUN</tt> (204; 75%),
<tt>NOUN –[<tt>det</tt>]–> DET</tt> (183; 99%),
<tt>NOUN –[<tt>nsubj</tt>]–> PROPN</tt> (145; 90%),
<tt>NOUN –[<tt>conj</tt>]–> NOUN</tt> (136; 91%),
<tt>NOUN –[<tt>nmod</tt>]–> NOUN</tt> (102; 63%),
<tt>ADJ –[<tt>cop</tt>]–> AUX</tt> (90; 95%),
<tt>NOUN –[<tt>obl</tt>]–> PROPN</tt> (82; 84%).

© 2014–2021
            Universal Dependencies contributors.
            Site powered by Annodoc and brat
.


text:
<?php

namespace Symfony\Component\Validator\Tests\Constraints;

use PHPUnit\Framework\TestCase;
use Symfony\Component\Validator\Constraints\Regex;
use Symfony\Component\Validator\Exception\InvalidArgumentException;
use Symfony\Component\Validator\Mapping\ClassMetadata;
use Symfony\Component\Validator\Mapping\Loader\AnnotationLoader;

/**
 * @author Bernhard Schussek <bschussek@gmail.com>
 */
class RegexTest extends TestCase
{
    public function testConstraintGetDefaultOption()
    {
        $constraint = new Regex('/^[0-9]+$/');

        $this->assertSame('/^[0-9]+$/', $constraint->pattern);
    }

    public function provideHtmlPatterns()
    {
        return [
            // HTML5 wraps the pattern in ^(?:pattern)$
            ['/^[0-9]+$/', '[0-9]+'],
            ['/[0-9]+$/', '.*[0-9]+'],
            ['/^[0-9]+/', '[0-9]+.*'],
            ['/[0-9]+/', '.*[0-9]+.*'],
            // We need a smart way to allow matching of patterns that contain
            // ^ and $ at various sub-clauses of an or-clause
            // .*(pattern).* seems to work correctly
            ['/[0-9]$|[a-z]+/', '.*([0-9]$|[a-z]+).*'],
            ['/[0-9]$|^[a-z]+/', '.*([0-9]$|^[a-z]+).*'],
            ['/^[0-9]|[a-z]+$/', '.*(^[0-9]|[a-z]+$).*'],
            // Unescape escaped delimiters
            ['/^[0-9]+\/$/', '[0-9]+/'],
            ['#^[0-9]+\#$#', '[0-9]+#'],
            // Cannot be converted
            ['/^[0-9]+$/i', null],

            // Inverse matches are simple, just wrap in
            // ((?!pattern).)*
            ['/^[0-9]+$/', '((?!^[0-9]+$).)*', false],
            ['/[0-9]+$/', '((?![0-9]+$).)*', false],
            ['/^[0-9]+/', '((?!^[0-9]+).)*', false],
            ['/[0-9]+/', '((?![0-9]+).)*', false],
            ['/[0-9]$|[a-z]+/', '((?![0-9]$|[a-z]+).)*', false],
            ['/[0-9]$|^[a-z]+/', '((?![0-9]$|^[a-z]+).)*', false],
            ['/^[0-9]|[a-z]+$/', '((?!^[0-9]|[a-z]+$).)*', false],
            ['/^[0-9]+\/$/', '((?!^[0-9]+/$).)*', false],
            ['#^[0-9]+\#$#', '((?!^[0-9]+#$).)*', false],
            ['/^[0-9]+$/i', null, false],
        ];
    }

    /**
     * @dataProvider provideHtmlPatterns
     */
    public function testGetHtmlPattern($pattern, $htmlPattern, $match = true)
    {
        $constraint = new Regex([
            'pattern' => $pattern,
            'match' => $match,
        ]);

        $this->assertSame($pattern, $constraint->pattern);
        $this->assertSame($htmlPattern, $constraint->getHtmlPattern());
    }

    public function testGetCustomHtmlPattern()
    {
        $constraint = new Regex([
            'pattern' => '((?![0-9]$|[a-z]+).)*',
            'htmlPattern' => 'foobar',
        ]);

        $this->assertSame('((?![0-9]$|[a-z]+).)*', $constraint->pattern);
        $this->assertSame('foobar', $constraint->getHtmlPattern());
    }

    public function testNormalizerCanBeSet()
    {
        $regex = new Regex(['pattern' => '/^[0-9]+$/', 'normalizer' => 'trim']);

        $this->assertEquals('trim', $regex->normalizer);
    }

    public function testInvalidNormalizerThrowsException()
    {
        $this->expectException(InvalidArgumentException::class);
        $this->expectExceptionMessage('The "normalizer" option must be a valid callable ("string" given).');
        new Regex(['pattern' => '/^[0-9]+$/', 'normalizer' => 'Unknown Callable']);
    }

    public function testInvalidNormalizerObjectThrowsException()
    {
        $this->expectException(InvalidArgumentException::class);
        $this->expectExceptionMessage('The "normalizer" option must be a valid callable ("stdClass" given).');
        new Regex(['pattern' => '/^[0-9]+$/', 'normalizer' => new \stdClass()]);
    }

    public function testAttributes()
    {
        $metadata = new ClassMetadata(RegexDummy::class);
        $loader = new AnnotationLoader();
        self::assertTrue($loader->loadClassMetadata($metadata));

        [$aConstraint] = $metadata->properties['a']->getConstraints();
        self::assertSame('/^[0-9]+$/', $aConstraint->pattern);
        self::assertTrue($aConstraint->match);
        self::assertNull($aConstraint->normalizer);

        [$bConstraint] = $metadata->properties['b']->getConstraints();
        self::assertSame('myMessage', $bConstraint->message);
        self::assertSame('/^[0-9]+$/', $bConstraint->pattern);
        self::assertSame('[0-9]+', $bConstraint->htmlPattern);
        self::assertFalse($bConstraint->match);
        self::assertSame(['Default', 'RegexDummy'], $bConstraint->groups);

        [$cConstraint] = $metadata->properties['c']->getConstraints();
        self::assertSame(['my_group'], $cConstraint->groups);
        self::assertSame('some attached data', $cConstraint->payload);
    }
}

class RegexDummy
{
    #[Regex('/^[0-9]+$/')]
    private $a;

    #[Regex(message: 'myMessage', pattern: '/^[0-9]+$/', htmlPattern: '[0-9]+', match: false, normalizer: 'trim')]
    private $b;

    #[Regex('/^[0-9]+$/', groups: ['my_group'], payload: 'some attached data')]
    private $c;
}


text:
<?php
namespace Demo\Appointment\DomainEvent;

use Demo\Appointment\Entity\Appointment;

class AppointmentBooked
{
    /**
     * @var Appointment
     */
    private $appointment;

    /**
     * @param Appointment $appointment
     */
    public function __construct(Appointment $appointment)
    {
        $this->appointment = $appointment;
    }

    /**
     * @return Appointment
     */
    public function getAppointment()
    {
        return $this->appointment;
    }
}


text:
/*	$NetBSD: postscreen_state.c,v 1.1.1.4 2014/07/06 19:27:54 tron Exp $	*/

/*++
/* NAME
/*	postscreen_state 3
/* SUMMARY
/*	postscreen session state and queue length management
/* SYNOPSIS
/*	#include <postscreen.h>
/*
/*	PSC_STATE *psc_new_session_state(stream, client_addr, client_port,
/*						server_addr, server_port)
/*	VSTREAM *stream;
/*	const char *client_addr;
/*	const char *client_port;
/*	const char *server_addr;
/*	const char *server_port;
/*
/*	void	psc_free_session_state(state)
/*	PSC_STATE *state;
/*
/*	char	*psc_print_state_flags(flags, context)
/*	int	flags;
/*	const char *context;
/*
/*	void	PSC_ADD_SERVER_STATE(state, server_fd)
/*	PSC_STATE *state;
/*	int	server_fd;
/*
/*	void	PSC_DEL_CLIENT_STATE(state)
/*	PSC_STATE *state;
/*
/*	void	PSC_DROP_SESSION_STATE(state, final_reply)
/*	PSC_STATE *state;
/*	const char *final_reply;
/*
/*	void	PSC_ENFORCE_SESSION_STATE(state, rcpt_reply)
/*	PSC_STATE *state;
/*	const char *rcpt_reply;
/*
/*	void	PSC_PASS_SESSION_STATE(state, testname, pass_flag)
/*	PSC_STATE *state;
/*	const char *testname;
/*	int	pass_flag;
/*
/*	void	PSC_FAIL_SESSION_STATE(state, fail_flag)
/*	PSC_STATE *state;
/*	int	fail_flag;
/*
/*	void	PSC_UNFAIL_SESSION_STATE(state, fail_flag)
/*	PSC_STATE *state;
/*	int	fail_flag;
/* DESCRIPTION
/*	This module maintains per-client session state, and two
/*	global file descriptor counters:
/* .IP psc_check_queue_length
/*	The total number of remote SMTP client sockets.
/* .IP psc_post_queue_length
/*	The total number of server file descriptors that are currently
/*	in use for client file descriptor passing. This number
/*	equals the number of client file descriptors in transit.
/* .PP
/*	psc_new_session_state() creates a new session state object
/*	for the specified client stream, and increments the
/*	psc_check_queue_length counter.  The flags and per-test time
/*	stamps are initialized with PSC_INIT_TESTS().  The addr and
/*	port arguments are null-terminated strings with the remote
/*	SMTP client endpoint. The _reply members are set to
/*	polite "try again" SMTP replies. The protocol member is set
/*	to "SMTP".
/*
/*	The psc_stress variable is set to non-zero when
/*	psc_check_queue_length passes over a high-water mark.
/*
/*	psc_free_session_state() destroys the specified session state
/*	object, closes the applicable I/O channels, and decrements
/*	the applicable file descriptor counters: psc_check_queue_length
/*	and psc_post_queue_length.
/*
/*	The psc_stress variable is reset to zero when psc_check_queue_length
/*	passes under a low-water mark.
/*
/*	psc_print_state_flags() converts per-session flags into
/*	human-readable form. The context is for error reporting.
/*	The result is overwritten upon each call.
/*
/*	PSC_ADD_SERVER_STATE() updates the specified session state
/*	object with the specified server file descriptor, and
/*	increments the global psc_post_queue_length file descriptor
/*	counter.
/*
/*	PSC_DEL_CLIENT_STATE() updates the specified session state
/*	object, closes the client stream, and decrements the global
/*	psc_check_queue_length file descriptor counter.
/*
/*	PSC_DROP_SESSION_STATE() updates the specified session state
/*	object and closes the client stream after sending the
/*	specified SMTP reply.
/*
/*	PSC_ENFORCE_SESSION_STATE() updates the specified session
/*	state object. It arranges that the built-in SMTP engine
/*	logs sender/recipient information and rejects all RCPT TO
/*	commands with the specified SMTP reply.
/*
/*	PSC_PASS_SESSION_STATE() sets the specified "pass" flag.
/*	The testname is used for debug logging.
/*
/*	PSC_FAIL_SESSION_STATE() sets the specified "fail" flag.
/*
/*	PSC_UNFAIL_SESSION_STATE() unsets the specified "fail" flag.
/* LICENSE
/* .ad
/* .fi
/*	The Secure Mailer license must be distributed with this software.
/* AUTHOR(S)
/*	Wietse Venema
/*	IBM T.J. Watson Research
/*	P.O. Box 704
/*	Yorktown Heights, NY 10598, USA
/*--*/

/* System library. */

#include <sys_defs.h>

/* Utility library. */

#include <msg.h>
#include <mymalloc.h>
#include <name_mask.h>
#include <htable.h>

/* Global library. */

#include <mail_proto.h>

/* Master server protocols. */

#include <mail_server.h>

/* Application-specific. */

#include <postscreen.h>

/* psc_new_session_state - fill in connection state for event processing */

PSC_STATE *psc_new_session_state(VSTREAM *stream,
				         const char *client_addr,
				         const char *client_port,
				         const char *server_addr,
				         const char *server_port)
{
    PSC_STATE *state;
    HTABLE_INFO *ht;

    state = (PSC_STATE *) mymalloc(sizeof(*state));
    PSC_INIT_TESTS(state);
    if ((state->smtp_client_stream = stream) != 0)
	psc_check_queue_length++;
    state->smtp_server_fd = (-1);
    state->smtp_client_addr = mystrdup(client_addr);
    state->smtp_client_port = mystrdup(client_port);
    state->smtp_server_addr = mystrdup(server_addr);
    state->smtp_server_port = mystrdup(server_port);
    state->send_buf = vstring_alloc(100);
    state->test_name = "TEST NAME HERE";
    state->dnsbl_reply = 0;
    state->final_reply = "421 4.3.2 Service currently unavailable\r\n";
    state->rcpt_reply = "450 4.3.2 Service currently unavailable\r\n";
    state->command_count = 0;
    state->protocol = MAIL_PROTO_SMTP;
    state->helo_name = 0;
    state->sender = 0;
    state->cmd_buffer = 0;
    state->read_state = 0;
    state->ehlo_discard_mask = 0;		/* XXX Should be ~0 */
    state->expand_buf = 0;
    state->where = PSC_SMTPD_CMD_CONNECT;

    /*
     * Update the stress level.
     */
    if (psc_stress == 0
	&& psc_check_queue_length >= psc_hiwat_check_queue_length) {
	psc_stress = 1;
	msg_info("entering STRESS mode with %d connections",
		 psc_check_queue_length);
    }

    /*
     * Update the per-client session count.
     */
    if ((ht = htable_locate(psc_client_concurrency, client_addr)) == 0)
	ht = htable_enter(psc_client_concurrency, client_addr, (char *) 0);
    ht->value += 1;
    state->client_concurrency = CAST_CHAR_PTR_TO_INT(ht->value);

    return (state);
}

/* psc_free_session_state - destroy connection state including connections */

void    psc_free_session_state(PSC_STATE *state)
{
    const char *myname = "psc_free_session_state";
    HTABLE_INFO *ht;

    /*
     * Update the per-client session count.
     */
    if ((ht = htable_locate(psc_client_concurrency,
			    state->smtp_client_addr)) == 0)
	msg_panic("%s: unknown client address: %s",
		  myname, state->smtp_client_addr);
    if (--(ht->value) == 0)
	htable_delete(psc_client_concurrency, state->smtp_client_addr,
		      (void (*) (char *)) 0);

    if (state->smtp_client_stream != 0) {
	event_server_disconnect(state->smtp_client_stream);
	psc_check_queue_length--;
    }
    if (state->smtp_server_fd >= 0) {
	close(state->smtp_server_fd);
	psc_post_queue_length--;
    }
    if (state->send_buf != 0)
	state->send_buf = vstring_free(state->send_buf);
    myfree(state->smtp_client_addr);
    myfree(state->smtp_client_port);
    myfree(state->smtp_server_addr);
    myfree(state->smtp_server_port);
    if (state->dnsbl_reply)
	vstring_free(state->dnsbl_reply);
    if (state->helo_name)
	myfree(state->helo_name);
    if (state->sender)
	myfree(state->sender);
    if (state->cmd_buffer)
	vstring_free(state->cmd_buffer);
    if (state->expand_buf)
	vstring_free(state->expand_buf);
    myfree((char *) state);

    if (psc_check_queue_length < 0 || psc_post_queue_length < 0)
	msg_panic("bad queue length: check_queue=%d, post_queue=%d",
		  psc_check_queue_length, psc_post_queue_length);

    /*
     * Update the stress level.
     */
    if (psc_stress != 0
	&& psc_check_queue_length <= psc_lowat_check_queue_length) {
	psc_stress = 0;
	msg_info("leaving STRESS mode with %d connections",
		 psc_check_queue_length);
    }
}

/* psc_print_state_flags - format state flags */

const char *psc_print_state_flags(int flags, const char *context)
{
    static const NAME_MASK flags_mask[] = {
	"NOFORWARD", PSC_STATE_FLAG_NOFORWARD,
	"USING_TLS", PSC_STATE_FLAG_USING_TLS,
	"NEW", PSC_STATE_FLAG_NEW,
	"BLIST_FAIL", PSC_STATE_FLAG_BLIST_FAIL,
	"HANGUP", PSC_STATE_FLAG_HANGUP,
	/* unused */
	"WLIST_FAIL", PSC_STATE_FLAG_WLIST_FAIL,

	"PREGR_FAIL", PSC_STATE_FLAG_PREGR_FAIL,
	"PREGR_PASS", PSC_STATE_FLAG_PREGR_PASS,
	"PREGR_TODO", PSC_STATE_FLAG_PREGR_TODO,
	"PREGR_DONE", PSC_STATE_FLAG_PREGR_DONE,

	"DNSBL_FAIL", PSC_STATE_FLAG_DNSBL_FAIL,
	"DNSBL_PASS", PSC_STATE_FLAG_DNSBL_PASS,
	"DNSBL_TODO", PSC_STATE_FLAG_DNSBL_TODO,
	"DNSBL_DONE", PSC_STATE_FLAG_DNSBL_DONE,

	"PIPEL_FAIL", PSC_STATE_FLAG_PIPEL_FAIL,
	"PIPEL_PASS", PSC_STATE_FLAG_PIPEL_PASS,
	"PIPEL_TODO", PSC_STATE_FLAG_PIPEL_TODO,
	"PIPEL_SKIP", PSC_STATE_FLAG_PIPEL_SKIP,

	"NSMTP_FAIL", PSC_STATE_FLAG_NSMTP_FAIL,
	"NSMTP_PASS", PSC_STATE_FLAG_NSMTP_PASS,
	"NSMTP_TODO", PSC_STATE_FLAG_NSMTP_TODO,
	"NSMTP_SKIP", PSC_STATE_FLAG_NSMTP_SKIP,

	"BARLF_FAIL", PSC_STATE_FLAG_BARLF_FAIL,
	"BARLF_PASS", PSC_STATE_FLAG_BARLF_PASS,
	"BARLF_TODO", PSC_STATE_FLAG_BARLF_TODO,
	"BARLF_SKIP", PSC_STATE_FLAG_BARLF_SKIP,
	0,
    };

    return (str_name_mask_opt((VSTRING *) 0, context, flags_mask, flags,
			      NAME_MASK_PIPE | NAME_MASK_NUMBER));
}


text:
from __future__ import absolute_import, unicode_literals

import logging

from django import template
from django.conf import settings

from feincms.utils import get_singleton, get_singleton_url

register = template.Library()

def _render_content(content, **kwargs):
    # Track current render level and abort if we nest too deep. Avoids
    # crashing in recursive page contents (eg. a page list that contains
    # itself or similar).
    request = kwargs.get('request')
    if request is not None:
        level = getattr(request, 'feincms_render_level', 0)
        if level > 10:
            logging.getLogger('feincms').error(
                'Refusing to render %r, render level is already %s' % (
                    content, level))
            return
        setattr(request, 'feincms_render_level', level + 1)

    r = content.render(**kwargs)

    if request is not None:
        level = getattr(request, 'feincms_render_level', 1)
        setattr(request, 'feincms_render_level', max(level - 1, 0))

    return r

@register.simple_tag(takes_context=True)
def feincms_render_region(context, feincms_object, region, request=None):
    """
    {% feincms_render_region feincms_page "main" request %}
    """
    return ''.join(
        _render_content(content, request=request, context=context)
        for content in getattr(feincms_object.content, region))

@register.simple_tag(takes_context=True)
def feincms_render_content(context, content, request=None):
    """
    {% feincms_render_content content request %}
    """
    return _render_content(content, request=request, context=context)

@register.assignment_tag
def feincms_load_singleton(template_key, cls=None):
    """
    {% feincms_load_singleton template_key %} -- return a FeinCMS
    Base object which uses a Template with singleton=True.
    """
    return get_singleton(template_key, cls, raise_exception=settings.DEBUG)

@register.simple_tag
def feincms_singleton_url(template_key, cls=None):
    """
    {% feincms_singleton_url template_key %} -- return the URL of a FeinCMS
    Base object which uses a Template with singleton=True.
    """
    return get_singleton_url(template_key, cls, raise_exception=settings.DEBUG)


text:
'''
embeddings.py -- functionality for working with non-trivial NLP embeddings

In particular, functionality for reshaping a 2D temporal tensor (integer lookups)
into a 5D tensor across multi-sentence embeddings.
'''

from keras.layers.containers import Graph as SubGraph
from keras.layers.core import Permute, Reshape
from keras.layers.embeddings import Embedding
from keras.constraints import Constraint
import keras.backend as K
from .version import KERAS_BACKEND

class ConstNorm(Constraint):
    def __init__(self, s=3, skip=True):
        self.skip = skip
        self.s = K.variable(s, name='s_constraint')
    def __call__(self, p):
        if self.skip:
            return self.s * (p / K.clip(K.sqrt(K.sum(K.square(p), axis=-1, keepdims=True)), 0.5, 100))
        return self.s * (p / K.sqrt(K.sum(K.square(p), axis=-1, keepdims=True)))

    def get_config(self):
        return {"name": self.__class__.__name__,
                "skip": self.skip,
                "s" : self.s}

def make_embedding(vocab_size, wv_size, init=None, fixed=False, constraint=ConstNorm(3.0, True), **kwargs):
    '''
    Takes parameters and makes a word vector embedding

    Args:
    ------
        vocab_size: integer -- how many words in your vocabulary

        wv_size: how big do you want the word vectors

        init: initial word vectors -- defaults to None. If you specify initial word vectors,
                needs to be an np.array of shape (vocab_size, wv_size)

        fixed: boolean -- do you want the word vectors fixed or not?

    Returns:
    ---------

        a Keras Embedding layer
    '''
    if (init is not None) and len(init.shape) == 2:
        emb = Embedding(vocab_size, wv_size, weights=[init], W_constraint=constraint) # keras needs a list for initializations
    else:
        emb = Embedding(vocab_size, wv_size, W_constraint=constraint) # keras needs a list for initializations
    if fixed:
        emb.trainable = False
        # emb.params = []
    return emb

def sentence_embedding(sentence_len, wv_params, wv_size,
                       input_name='sentence_embedding', output_name='vector_embedding'):
    '''
    Creates an embedding of word vectors into a sentence image.

    Args:
    -----
        sentence_len: length of sentences to be passed

        wv_params: a dict of the following format

                        wv_params = {
                            'fixed_wv' :
                            {
                                'vocab_size' : 1000,
                                'init' : None,
                                'fixed' : True
                            },
                            'floating_wv' :
                            {
                                'vocab_size' : 1000,
                                'init' : None,
                                'fixed' : False
                            }
                        }
            the keys of the dictionary are the names in the keras graph model, and
            you can have any number of word vector layers encoded.

        input_name: the name of the input node for the graph

        output_name: the name of the output node for the graph

    Returns:
    --------

        a keras container that takes as input an integer array with shape (n_samples, n_words), and returns
        shape (n_samples, wv_channels, len_sentence, wv_dim)!
    '''
    # -- output is (n_samples, n_channels, n_words, wv_dim)
    g = SubGraph()

    if KERAS_BACKEND:
        g.add_input(input_name, (sentence_len, ), dtype='int')
    else:
        g.add_input(input_name, (-1, ), dtype='int')

    for name, params in wv_params.iteritems():
        # g.add_input(params['input_name'], (-1, ), dtype='int')
        g.add_node(make_embedding(wv_size=wv_size, **params), name=name, input=input_name)

    g.add_node(Reshape((sentence_len, len(wv_params), wv_size)), name='reshape',
               inputs=wv_params.keys(), merge_mode='concat')
    g.add_node(Permute(dims=(2, 1, 3)), name='permute', input='reshape')

    # -- output is of shape (nb_samples, nb_wv_channels, len_sentence, wv_dim)
    g.add_output(name=output_name, input='permute')
    return g

def paragraph_embedding(paragraph_len, sentence_len, wv_params, wv_size,
        input_name='paragraph_embedding',  output_name='vector_embedding'):
    '''
    Creates an embedding of word vectors into a sequence of sentence images.

    Args:
    -----
        sentence_len: length of sentences to be passed

        wv_params: a dict of the following format

                        wv_params = {
                            'fixed_wv' :
                            {
                                'vocab_size' : 1000,
                                'init' : None,
                                'fixed' : True
                            },
                            'floating_wv' :
                            {
                                'vocab_size' : 1000,
                                'init' : None,
                                'fixed' : False
                            }
                        }
            the keys of the dictionary are the names in the keras graph model, and
            you can have any number of word vector layers encoded.

        input_name: the name of the input node for the graph

        output_name: the name of the output node for the graph

    Returns:
    --------

        a keras container that takes as input an integer array with shape (n_samples, n_words), where
        n_words is the number of words in the paragraph. ***NOTE*** that n_words should be organized
        such that n_words = n_sentences * len_sentence! I.e., if you have a len_sentence of 3, and your
        input is [2, 1, 5, 0, 9, 3, 2, 4, 5], it WILL ASSUME that

            [[2, 1, 5],
             [0, 9, 3],
             [2, 4, 5]]
        are all sentences in a paragraph.

        This returns a shape (n_samples, n_sentences, wv_channels, len_sentence, wv_dim)!
    '''
    # -- output is (n_samples, n_sentences, n_channels, n_words, wv_dim)
    g = SubGraph()

    # -- fix for new keras backend

    if KERAS_BACKEND:
        g.add_input(input_name, (sentence_len * paragraph_len, ), dtype='int')
    else:
        g.add_input(input_name, (-1, ), dtype='int')

    for name, params in wv_params.iteritems():
        # g.add_input(params['input_name'], (-1, ), dtype='int')
        g.add_node(make_embedding(wv_size=wv_size, **params), name=name, input=input_name)

    if len(wv_params.keys()) > 1:
        # -- removal for backend compatibility
        if KERAS_BACKEND:
            g.add_node(Reshape((paragraph_len, sentence_len, len(wv_params), wv_size)),
                       name='reshape', inputs=wv_params.keys(), merge_mode='concat')
        else:
            g.add_node(Reshape((-1, sentence_len, len(wv_params), wv_size)),
                name='reshape', inputs=wv_params.keys(), merge_mode='concat')

    else:
        # -- removal for backend compatibility
        if KERAS_BACKEND:
            g.add_node(Reshape((paragraph_len, sentence_len, len(wv_params), wv_size)),
                       name='reshape', input=wv_params.keys()[0])
        else:
            g.add_node(Reshape((-1, sentence_len, len(wv_params), wv_size)),
                    name='reshape', inputs=wv_params.keys(), merge_mode='concat')

    g.add_node(Permute(dims=(1, 3, 2, 4)), name='permute', input='reshape')

    # -- output is of shape (nb_samples, nb_wv_channels, len_sentence, wv_dim)
    g.add_output(name=output_name, input='permute')
    return g


text:
-- phpMyAdmin SQL Dump
-- version 4.1.14
-- http://www.phpmyadmin.net
--
-- Host: 127.0.0.1
-- Generation Time: Oct 16, 2015 at 05:24 PM
-- Server version: 5.6.17
-- PHP Version: 5.5.12

SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
SET time_zone = "+00:00";

/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;

--
-- Database: `eagle`
--

-- --------------------------------------------------------

--
-- Table structure for table `permissions`
--

CREATE TABLE IF NOT EXISTS `permissions` (
  `permission_id` int(11) NOT NULL AUTO_INCREMENT,
  `permission_name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `permission_mca` varchar(255) COLLATE utf8_unicode_ci NOT NULL COMMENT 'Module_Controller_Action',
  `permission_active` tinyint(3) unsigned NOT NULL DEFAULT '0',
  PRIMARY KEY (`permission_id`),
  UNIQUE KEY `permission_data` (`permission_mca`),
  KEY `permission_active` (`permission_active`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=5 ;

--
-- Dumping data for table `permissions`
--

INSERT INTO `permissions` (`permission_id`, `permission_name`, `permission_mca`, `permission_active`) VALUES
(1, 'User can Login', 'auth_index_index', 1),
(2, 'User can view the home page', 'frontend_index_index', 1),
(3, 'God Permission', '*_*_*', 0),
(4, 'Just A test Permission', 'auth_index_exit', 0);

-- --------------------------------------------------------

--
-- Table structure for table `roles`
--

CREATE TABLE IF NOT EXISTS `roles` (
  `role_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `role_name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `role_active` tinyint(3) unsigned NOT NULL DEFAULT '0',
  PRIMARY KEY (`role_id`),
  UNIQUE KEY `role_name` (`role_name`),
  KEY `role_active` (`role_active`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=3 ;

--
-- Dumping data for table `roles`
--

INSERT INTO `roles` (`role_id`, `role_name`, `role_active`) VALUES
(0, 'guest', 1),
(1, 'god', 1),
(2, 'administrator', 1);

-- --------------------------------------------------------

--
-- Table structure for table `roles_permissions`
--

CREATE TABLE IF NOT EXISTS `roles_permissions` (
  `role_id` int(10) unsigned NOT NULL,
  `permission_id` int(10) unsigned NOT NULL,
  PRIMARY KEY (`role_id`,`permission_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

--
-- Dumping data for table `roles_permissions`
--

INSERT INTO `roles_permissions` (`role_id`, `permission_id`) VALUES
(0, 1),
(0, 2),
(1, 3);

-- --------------------------------------------------------

--
-- Table structure for table `users`
--

CREATE TABLE IF NOT EXISTS `users` (
  `user_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `user_name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `user_email` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `user_password` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `user_active` tinyint(3) unsigned NOT NULL DEFAULT '0',
  `user_created` int(10) unsigned NOT NULL,
  PRIMARY KEY (`user_id`),
  UNIQUE KEY `user_name` (`user_name`),
  UNIQUE KEY `user_email` (`user_email`),
  KEY `user_active` (`user_active`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=3 ;

--
-- Dumping data for table `users`
--

INSERT INTO `users` (`user_id`, `user_name`, `user_email`, `user_password`, `user_active`, `user_created`) VALUES
(0, 'guest', 'guest', '', 0, 0),
(1, 'ionut', 'marcel.toma@endava.com', '$2a$08$JcLm1IONh99AlUCnHfuzZukb82QEvFZoFLTEwSYzJr5gb4MjC5PaS', 1, 0);

-- --------------------------------------------------------

--
-- Table structure for table `users_permissions`
--

CREATE TABLE IF NOT EXISTS `users_permissions` (
  `user_id` int(11) NOT NULL,
  `permission_id` int(11) NOT NULL,
  `user_permission_type` tinyint(4) NOT NULL DEFAULT '0' COMMENT '0 - remove from the role, 1 - add to the user',
  PRIMARY KEY (`user_id`,`permission_id`),
  KEY `user_permission_type` (`user_permission_type`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

--
-- Dumping data for table `users_permissions`
--

INSERT INTO `users_permissions` (`user_id`, `permission_id`, `user_permission_type`) VALUES
(1, 4, 1);

-- --------------------------------------------------------

--
-- Table structure for table `users_roles`
--

CREATE TABLE IF NOT EXISTS `users_roles` (
  `user_id` int(10) unsigned NOT NULL,
  `role_id` int(10) unsigned NOT NULL,
  PRIMARY KEY (`user_id`,`role_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

--
-- Dumping data for table `users_roles`
--

INSERT INTO `users_roles` (`user_id`, `role_id`) VALUES
(0, 0),
(1, 1);

/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;


text:
- Install dependencies: `npm i`
- Start dev environment: `npm start`
- Build project to production: `npm run build`
- Deploy: `npm run deploy` and `now alias [output url] heydev`

________________

Credits: https://startbootstrap.com/template-categories/landing-pages/


text:
<?php
//
// Copyright (c) 2020-2022 Grigore Stefan <g_stefan@yahoo.com>
// Created by Grigore Stefan <g_stefan@yahoo.com>
//
// MIT License (MIT) <http://opensource.org/licenses/MIT>
//

defined("XYO_CLOUD") or die("Access is denied");

if($this->xyo_module_id>0) {

	foreach($this->items as $item) {
		if(!is_null($item["name"])){
			$this->processComponent($item["type"],array_merge(array("element" =>$item["name"]),$item["parameters"]));
			$this->ds->clear();
			$this->ds->xyo_module_id=$this->xyo_module_id;
			$this->ds->name=$item["name"];
			$this->ds->tryLoad(0,1);
			$this->ds->value=$this->getElementValueString($item["name"],$item["default_value"]);
			$this->ds->save();
		};
	};

};


text:
package org.apache.tomcat.maven.plugin.tomcat6;

import org.apache.maven.plugins.annotations.Mojo;

/**
 * Redeploy a WAR in Tomcat without forking the package lifecycle.
 * (Alias for the deploy-only goal with its update parameter set to true.)
 *
 * @since 2.1
 */
@Mojo( name = "redeploy-only", threadSafe = true )
public class RedeployOnlyMojo
    extends DeployOnlyMojo
{
    /**
     * {@inheritDoc}
     */
    @Override
    protected boolean isUpdate()
    {
        return true;
    }
}