text:
package org.hisp.dhis.validation;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hisp.dhis.DhisTest;
import org.hisp.dhis.dataelement.*;
import org.hisp.dhis.dataset.DataSet;
import org.hisp.dhis.dataset.DataSetService;
import org.hisp.dhis.datavalue.DataValue;
import org.hisp.dhis.datavalue.DataValueService;
import org.hisp.dhis.datavalue.DataValueStore;
import org.hisp.dhis.expression.Expression;
import org.hisp.dhis.expression.ExpressionService;
import org.hisp.dhis.mock.MockCurrentUserService;
import org.hisp.dhis.organisationunit.OrganisationUnit;
import org.hisp.dhis.organisationunit.OrganisationUnitService;
import org.hisp.dhis.period.*;
import org.hisp.dhis.system.util.MathUtils;
import org.hisp.dhis.user.CurrentUserService;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.*;

import static junit.framework.TestCase.assertFalse;
import static junit.framework.TestCase.assertTrue;
import static org.hisp.dhis.expression.Expression.SEPARATOR;
import static org.hisp.dhis.expression.ExpressionService.SYMBOL_DAYS;
import static org.hisp.dhis.expression.MissingValueStrategy.NEVER_SKIP;
import static org.hisp.dhis.expression.Operator.*;

/**
 * @author Jim Grace
 */
public class ValidationServiceTest
    extends DhisTest
{
    private static final Log log = LogFactory.getLog( ValidationServiceTest.class );

    @Autowired
    private ValidationService validationService;

    @Autowired
    private ValidationRuleService validationRuleService;

    @Autowired
    private DataElementService dataElementService;

    @Autowired
    private DataElementCategoryService categoryService;

    @Autowired
    private ExpressionService expressionService;

    @Autowired
    private DataSetService dataSetService;

    @Autowired
    private DataValueService dataValueService;

    @Autowired
    private DataValueStore dataValueStore;

    @Autowired
    private OrganisationUnitService organisationUnitService;

    @Autowired
    private PeriodService periodService;

    private DataElement dataElementA;
    private DataElement dataElementB;
    private DataElement dataElementC;
    private DataElement dataElementD;
    private DataElement dataElementE;

    private Set<DataElementCategoryOptionCombo> optionCombos;

    private DataElementCategoryOptionCombo optionCombo;

    private Expression expressionA;
    private Expression expressionB;
    private Expression expressionC;
    private Expression expressionD;
    private Expression expressionE;
    private Expression expressionF;
    private Expression expressionG;
    private Expression expressionH;
    private Expression expressionI;
    private Expression expressionJ;
    private Expression expressionK;
    private Expression expressionL;
    private Expression expressionP;
    private Expression expressionQ;

    private DataSet dataSetWeekly;

    private DataSet dataSetMonthly;

    private DataSet dataSetYearly;

    private Period periodA;
    private Period periodB;
    private Period periodY;

    private int dayInPeriodA;
    private int dayInPeriodB;
    private int dayInPeriodY;

    private OrganisationUnit sourceA;
    private OrganisationUnit sourceB;
    private OrganisationUnit sourceC;
    private OrganisationUnit sourceD;
    private OrganisationUnit sourceE;
    private OrganisationUnit sourceF;
    private OrganisationUnit sourceG;

    private List<OrganisationUnit> sourcesA = new ArrayList<>();

    private Set<OrganisationUnit> allSources = new HashSet<>();

    private ValidationRule validationRuleA;
    private ValidationRule validationRuleB;
    private ValidationRule validationRuleC;
    private ValidationRule validationRuleD;
    private ValidationRule validationRuleE;
    private ValidationRule validationRuleF;
    private ValidationRule validationRuleG;
    private ValidationRule validationRuleP;
    private ValidationRule validationRuleQ;
    private ValidationRule validationRuleX;

    private ValidationRuleGroup group;

    private PeriodType periodTypeWeekly;
    private PeriodType periodTypeMonthly;
    private PeriodType periodTypeYearly;

    private DataElementCategoryOptionCombo defaultCombo;

    // -------------------------------------------------------------------------
    // Fixture
    // -------------------------------------------------------------------------

    @Override
    public void setUpTest()
        throws Exception
    {
        CurrentUserService currentUserService = new MockCurrentUserService( allSources, null );
        setDependency( validationService, "currentUserService", currentUserService, CurrentUserService.class );

        periodTypeWeekly = new WeeklyPeriodType();
        periodTypeMonthly = new MonthlyPeriodType();
        periodTypeYearly = new YearlyPeriodType();

        dataElementA = createDataElement( 'A' );
        dataElementB = createDataElement( 'B' );
        dataElementC = createDataElement( 'C' );
        dataElementD = createDataElement( 'D' );
        dataElementE = createDataElement( 'E' );

        dataElementService.addDataElement( dataElementA );
        dataElementService.addDataElement( dataElementB );
        dataElementService.addDataElement( dataElementC );
        dataElementService.addDataElement( dataElementD );
        dataElementService.addDataElement( dataElementE );

        optionCombo = categoryService.getDefaultDataElementCategoryOptionCombo();

        String suffix = SEPARATOR + optionCombo.getUid();

        optionCombos = new HashSet<>();
        optionCombos.add( optionCombo );

        expressionA = new Expression(
            "#{" + dataElementA.getUid() + suffix + "} + #{" + dataElementB.getUid() + suffix + "}", "expressionA" );
        expressionB = new Expression(
            "#{" + dataElementC.getUid() + suffix + "} - #{" + dataElementD.getUid() + suffix + "}", "expressionB" );
        expressionC = new Expression( "#{" + dataElementB.getUid() + suffix + "} * 2", "expressionC" );
        expressionD = new Expression( "#{" + dataElementB.getUid() + suffix + "}", "expressionD" );
        expressionE = new Expression( "AVG(#{" + dataElementB.getUid() + suffix + "} * 1.5)", "expressionE" );
        expressionF = new Expression( "#{" + dataElementB.getUid() + suffix + "} / #{" + dataElementE.getUid() + suffix + "}", "expressionF" );
        expressionG = new Expression( "AVG(#{" + dataElementB.getUid() + suffix + "} * 1.5 / #{" + dataElementE.getUid() + suffix + "})", "expressionG" );
        expressionH = new Expression( "AVG(#{" + dataElementB.getUid() + suffix + "}) + 1.5*STDDEV(#{" + dataElementB.getUid() + suffix + "})", "expressionH" );
        expressionI = new Expression( "#{" + dataElementA.getUid() + suffix + "}", "expressionI" );
        expressionJ = new Expression( "#{" + dataElementB.getUid() + suffix + "}", "expressionJ" );
        expressionK = new Expression( "#{" + dataElementC.getUid() + "}", "expressionK", NEVER_SKIP );
        expressionL = new Expression( "#{" + dataElementD.getUid() + "}", "expressionL", NEVER_SKIP );
        expressionP = new Expression( SYMBOL_DAYS, "expressionP", NEVER_SKIP );
        expressionQ = new Expression( "#{" + dataElementE.getUid() + "}", "expressionQ", NEVER_SKIP );

        expressionService.addExpression( expressionA );
        expressionService.addExpression( expressionB );
        expressionService.addExpression( expressionC );
        expressionService.addExpression( expressionD );
        expressionService.addExpression( expressionE );
        expressionService.addExpression( expressionF );
        expressionService.addExpression( expressionG );
        expressionService.addExpression( expressionH );
        expressionService.addExpression( expressionI );
        expressionService.addExpression( expressionJ );
        expressionService.addExpression( expressionK );
        expressionService.addExpression( expressionL );
        expressionService.addExpression( expressionP );
        expressionService.addExpression( expressionQ );

        periodA = createPeriod( periodTypeMonthly, getDate( 2000, 3, 1 ), getDate( 2000, 3, 31 ) );
        periodB = createPeriod( periodTypeMonthly, getDate( 2000, 4, 1 ), getDate( 2000, 4, 30 ) );
        periodY = createPeriod( periodTypeYearly, getDate( 2000, 1, 1 ), getDate( 2000, 12, 31 ) );

        dayInPeriodA = periodService.getDayInPeriod( periodA, new Date() );
        dayInPeriodB = periodService.getDayInPeriod( periodB, new Date() );
        dayInPeriodY = periodService.getDayInPeriod( periodY, new Date() );

        dataSetWeekly = createDataSet( 'W', periodTypeWeekly );
        dataSetMonthly = createDataSet( 'M', periodTypeMonthly );
        dataSetYearly = createDataSet( 'Y', periodTypeYearly );

        sourceA = createOrganisationUnit( 'A' );
        sourceB = createOrganisationUnit( 'B' );
        sourceC = createOrganisationUnit( 'C', sourceB );
        sourceD = createOrganisationUnit( 'D', sourceB );
        sourceE = createOrganisationUnit( 'E', sourceD );
        sourceF = createOrganisationUnit( 'F', sourceD );
        sourceG = createOrganisationUnit( 'G' );

        sourcesA.add( sourceA );
        sourcesA.add( sourceB );

        allSources.add( sourceA );
        allSources.add( sourceB );
        allSources.add( sourceC );
        allSources.add( sourceD );
        allSources.add( sourceE );
        allSources.add( sourceF );
        allSources.add( sourceG );

        dataSetMonthly.addOrganisationUnit( sourceA );
        dataSetMonthly.addOrganisationUnit( sourceB );
        dataSetMonthly.addOrganisationUnit( sourceC );
        dataSetMonthly.addOrganisationUnit( sourceD );
        dataSetMonthly.addOrganisationUnit( sourceE );
        dataSetMonthly.addOrganisationUnit( sourceF );

        dataSetWeekly.addOrganisationUnit( sourceB );
        dataSetWeekly.addOrganisationUnit( sourceC );
        dataSetWeekly.addOrganisationUnit( sourceD );
        dataSetWeekly.addOrganisationUnit( sourceE );
        dataSetWeekly.addOrganisationUnit( sourceF );
        dataSetWeekly.addOrganisationUnit( sourceG );

        dataSetYearly.addOrganisationUnit( sourceB );
        dataSetYearly.addOrganisationUnit( sourceC );
        dataSetYearly.addOrganisationUnit( sourceD );
        dataSetYearly.addOrganisationUnit( sourceE );
        dataSetYearly.addOrganisationUnit( sourceF );

        organisationUnitService.addOrganisationUnit( sourceA );
        organisationUnitService.addOrganisationUnit( sourceB );
        organisationUnitService.addOrganisationUnit( sourceC );
        organisationUnitService.addOrganisationUnit( sourceD );
        organisationUnitService.addOrganisationUnit( sourceE );
        organisationUnitService.addOrganisationUnit( sourceF );
        organisationUnitService.addOrganisationUnit( sourceG );

        dataSetMonthly.addDataSetElement( dataElementA );
        dataSetMonthly.addDataSetElement( dataElementB );
        dataSetMonthly.addDataSetElement( dataElementC );
        dataSetMonthly.addDataSetElement( dataElementD );

        dataSetWeekly.addDataSetElement( dataElementE );

        dataSetYearly.addDataSetElement( dataElementE );

        dataSetService.addDataSet( dataSetWeekly );
        dataSetService.addDataSet( dataSetMonthly );
        dataSetService.addDataSet( dataSetYearly );

        dataElementService.updateDataElement( dataElementA );
        dataElementService.updateDataElement( dataElementB );
        dataElementService.updateDataElement( dataElementC );
        dataElementService.updateDataElement( dataElementD );
        dataElementService.updateDataElement( dataElementE );

        validationRuleA = createValidationRule( "A", equal_to, expressionA, expressionB, periodTypeMonthly ); // deA + deB = deC - deD
        validationRuleB = createValidationRule( "B", greater_than, expressionB, expressionC, periodTypeMonthly ); // deC - deD > deB * 2
        validationRuleC = createValidationRule( "C", less_than_or_equal_to, expressionB, expressionA, periodTypeMonthly ); // deC - deD <= deA + deB
        validationRuleD = createValidationRule( "D", less_than, expressionA, expressionC, periodTypeMonthly ); // deA + deB < deB * 2
        validationRuleE = createValidationRule( "E", compulsory_pair, expressionI, expressionJ, periodTypeMonthly ); // deA [Compulsory pair] deB
        validationRuleF = createValidationRule( "F", exclusive_pair, expressionI, expressionJ, periodTypeMonthly ); // deA [Exclusive pair] deB
        validationRuleG = createValidationRule( "G", equal_to, expressionK, expressionL, periodTypeMonthly ); // deC = deD
        validationRuleP = createValidationRule( "P", equal_to, expressionI, expressionP, periodTypeMonthly ); // deA = [days]
        validationRuleQ = createValidationRule( "Q", equal_to, expressionQ, expressionP, periodTypeYearly ); // deE = [days]
        validationRuleX = createValidationRule( "X", equal_to, expressionA, expressionC, periodTypeMonthly ); // deA + deB = deB * 2
        group = createValidationRuleGroup( 'A' );

        defaultCombo = categoryService.getDefaultDataElementCategoryOptionCombo();
    }

    @Override
    public boolean emptyDatabaseAfterTest()
    {
        return true;
    }

    // -------------------------------------------------------------------------
    // Local convenience methods
    // -------------------------------------------------------------------------

    private ValidationResult createValidationResult( ValidationRule validationRule, Period period, OrganisationUnit orgUnit,
        DataElementCategoryOptionCombo catCombo, double ls, double rs, int dayInPeriod )
    {
        ValidationResult vr = new ValidationResult( validationRule, period, orgUnit, catCombo, ls, rs, dayInPeriod );

        return vr;
    }

    /**
     * Returns a naturally ordered list of ValidationResults.
     *

     * When comparing two collections, this assures that all the items are in
     * the same order for comparison. It also means that when there are
     * different values for the same period/rule/source, etc., the results are
     * more likely to be in the same order to make it easier to see the
     * difference.
     *

     * By making this a List instead of, say a TreeSet, duplicate values (if any
     * should exist by mistake!) are preserved.
     *
     * @param results collection of ValidationResult to order.
     * @return ValidationResults in their natural order.
     */
    private List<ValidationResult> orderedList( Collection<ValidationResult> results )
    {
        List<ValidationResult> resultList = new ArrayList<>( results );
        Collections.sort( resultList );
        return resultList;
    }

    /**
     * Asserts that a collection of ValidationResult is empty.
     *
     * @param results collection of ValidationResult to test.
     */
    private void assertResultsEmpty( Collection<ValidationResult> results )
    {
        assertResultsEquals( new HashSet<ValidationResult>(), results );
    }

    /**
     * Asserts that a collection of ValidationResult matches a reference
     * collection. If it doesn't, log some extra diagnostic information.
     *

     * This method was written in response to intermittent test failures.
     * The extra diagnostic information is an attempt to further investigate
     * the nature of the failures.
     *

     * A partial stack trace is logged (just within this file), so when the
     * test is working, the check inequality can be commented out and the
     * tester can generate a reference of expected vales for each call.
     *

     * Also tests to be sure that each result expression was evaluated
     * correctly.
     *
     * @param reference the reference collection of ValidationResult.
     * @param results collection of ValidationResult to test.
     */
    private void assertResultsEquals( Collection<ValidationResult> reference, Collection<ValidationResult> results )
    {
        List<ValidationResult> referenceList = orderedList( reference );
        List<ValidationResult> resultsList = orderedList( results );

        if ( !referenceList.equals( resultsList ) )
        {
            StringBuilder sb = new StringBuilder();

            StackTraceElement[] e = Thread.currentThread().getStackTrace();

            for ( int i = 1; i < e.length && e[ i ].getFileName().equals( e[ 1 ].getFileName() ); i++ )
            {
                sb.append("  at " ).append( e[ i ].getMethodName() )
                    .append( "(" ).append( e[ i ].getFileName() )
                    .append( ":" ).append( e[ i ].getLineNumber() ).append( ")\n" );
            }

            sb.append( formatResultsList( "Expected", referenceList ) )
                .append( formatResultsList ( "But was", resultsList ) )
                .append( getAllDataValues() )
                .append( getAllValidationRules() );

            log.error( sb.toString() );
        }

        assertTrue( referenceList.equals( resultsList ) );

        for ( ValidationResult result : results )
        {
            assertFalse( MathUtils.expressionIsTrue( result.getLeftsideValue(),
                result.getValidationRule().getOperator(), result.getRightsideValue() ) );
        }
    }

    private String formatResultsList( String label, List<ValidationResult> results )
    {
        StringBuilder sb = new StringBuilder( label + " (" + results.size() + "):\n" );

        results.forEach( r -> sb.append( "  " ).append( r.toString() ).append( "\n" ) );

        return sb.toString();
    }

    private String getAllDataValues()
    {
        List<DataValue> allDataValues = dataValueStore.getAllDataValues();

        StringBuilder sb = new StringBuilder( "All data values (" + allDataValues.size() + "):\n" );

        allDataValues.forEach( d -> sb.append( "  " ).append( d.toString() ).append( "\n" ) );

        return sb.toString();
    }

    private String getAllValidationRules()
    {
        List<ValidationRule> allValidationRules = validationRuleService.getAllValidationRules();

        StringBuilder sb = new StringBuilder( "All validation rules (" + allValidationRules.size() + "):\n" );

        allValidationRules.forEach( v -> sb
            .append( "  " ).append( v.getName() )
            .append(": ").append( v.getLeftSide().getExpression() )
            .append(" [").append( v.getOperator() ).append("] ")
            .append( v.getRightSide().getExpression() )
            .append( "\n" ) );

        return sb.toString();
    }

    private void useDataValue( DataElement e, Period p, OrganisationUnit s, String value )
    {
        dataValueService.addDataValue( createDataValue( e, p, s, value, optionCombo, optionCombo ) );
    }

    private void useDataValue( DataElement e, Period p, OrganisationUnit s, String value,
        DataElementCategoryOptionCombo oc1, DataElementCategoryOptionCombo oc2 )
    {
        dataValueService.addDataValue( createDataValue( e, p, s, value, oc1, oc2 ) );
    }

    // -------------------------------------------------------------------------
    // Business logic tests
    // -------------------------------------------------------------------------

    @Test
    public void testValidateDateDateSources()
    {
        useDataValue( dataElementA, periodA, sourceA, "1" );
        useDataValue( dataElementB, periodA, sourceA, "2" );
        useDataValue( dataElementC, periodA, sourceA, "3" );
        useDataValue( dataElementD, periodA, sourceA, "4" );

        useDataValue( dataElementA, periodB, sourceA, "1" );
        useDataValue( dataElementB, periodB, sourceA, "2" );
        useDataValue( dataElementC, periodB, sourceA, "3" );
        useDataValue( dataElementD, periodB, sourceA, "4" );

        useDataValue( dataElementA, periodA, sourceB, "1" );
        useDataValue( dataElementB, periodA, sourceB, "2" );
        useDataValue( dataElementC, periodA, sourceB, "3" );
        useDataValue( dataElementD, periodA, sourceB, "4" );

        useDataValue( dataElementA, periodB, sourceB, "1" );
        useDataValue( dataElementB, periodB, sourceB, "2" );
        useDataValue( dataElementC, periodB, sourceB, "3" );
        useDataValue( dataElementD, periodB, sourceB, "4" );

        validationRuleService.saveValidationRule( validationRuleA ); // Invalid
        validationRuleService.saveValidationRule( validationRuleB ); // Invalid
        validationRuleService.saveValidationRule( validationRuleC ); // Valid
        validationRuleService.saveValidationRule( validationRuleD ); // Valid

        // Note: in this and subsequent tests we insert the validation results
        // collection into a new HashSet. This
        // insures that if they are the same as the reference results, they will
        // appear in the same order.

        Collection<ValidationResult> results = validationService.startInteractiveValidationAnalysis( getDate( 2000, 2, 1 ),
            getDate( 2000, 6, 1 ), sourcesA, false, null, null, false, null );

        Collection<ValidationResult> reference = new HashSet<>();

        reference.add( createValidationResult( validationRuleA, periodA, sourceA, defaultCombo, 3.0, -1.0, dayInPeriodA ) );
        reference.add( createValidationResult( validationRuleA, periodB, sourceA, defaultCombo, 3.0, -1.0, dayInPeriodB ) );
        reference.add( createValidationResult( validationRuleA, periodA, sourceB, defaultCombo, 3.0, -1.0, dayInPeriodA ) );
        reference.add( createValidationResult( validationRuleA, periodB, sourceB, defaultCombo, 3.0, -1.0, dayInPeriodB ) );

        reference.add( createValidationResult( validationRuleB, periodA, sourceA, defaultCombo, -1.0, 4.0, dayInPeriodA ) );
        reference.add( createValidationResult( validationRuleB, periodB, sourceA, defaultCombo, -1.0, 4.0, dayInPeriodB ) );
        reference.add( createValidationResult( validationRuleB, periodA, sourceB, defaultCombo, -1.0, 4.0, dayInPeriodA ) );
        reference.add( createValidationResult( validationRuleB, periodB, sourceB, defaultCombo, -1.0, 4.0, dayInPeriodB ) );

        assertResultsEquals( reference, results );
    }

    @Test
    public void testValidateDateDateSourcesGroup()
    {
        useDataValue( dataElementA, periodA, sourceA, "1" );
        useDataValue( dataElementB, periodA, sourceA, "2" );
        useDataValue( dataElementC, periodA, sourceA, "3" );
        useDataValue( dataElementD, periodA, sourceA, "4" );

        useDataValue( dataElementA, periodB, sourceA, "1" );
        useDataValue( dataElementB, periodB, sourceA, "2" );
        useDataValue( dataElementC, periodB, sourceA, "3" );
        useDataValue( dataElementD, periodB, sourceA, "4" );

        useDataValue( dataElementA, periodA, sourceB, "1" );
        useDataValue( dataElementB, periodA, sourceB, "2" );
        useDataValue( dataElementC, periodA, sourceB, "3" );
        useDataValue( dataElementD, periodA, sourceB, "4" );

        useDataValue( dataElementA, periodB, sourceB, "1" );
        useDataValue( dataElementB, periodB, sourceB, "2" );
        useDataValue( dataElementC, periodB, sourceB, "3" );
        useDataValue( dataElementD, periodB, sourceB, "4" );

        validationRuleService.saveValidationRule( validationRuleA ); // Invalid
        validationRuleService.saveValidationRule( validationRuleB ); // Invalid
        validationRuleService.saveValidationRule( validationRuleC ); // Valid
        validationRuleService.saveValidationRule( validationRuleD ); // Valid

        group.getMembers().add( validationRuleA );
        group.getMembers().add( validationRuleC );

        validationRuleService.addValidationRuleGroup( group );

        Collection<ValidationResult> results = validationService.startInteractiveValidationAnalysis( getDate( 2000, 2, 1 ),
            getDate( 2000, 6, 1 ), sourcesA, false, null, group, false, null );

        Collection<ValidationResult> reference = new HashSet<>();

        reference.add( new ValidationResult( validationRuleA, periodA, sourceA, defaultCombo, 3.0, -1.0, dayInPeriodA ) );
        reference.add( new ValidationResult( validationRuleA, periodB, sourceA, defaultCombo, 3.0, -1.0, dayInPeriodB ) );
        reference.add( new ValidationResult( validationRuleA, periodA, sourceB, defaultCombo, 3.0, -1.0, dayInPeriodA ) );
        reference.add( new ValidationResult( validationRuleA, periodB, sourceB, defaultCombo, 3.0, -1.0, dayInPeriodB ) );

        assertResultsEquals( reference, results );
    }

    @Test
    public void testValidateDataSetPeriodSource()
    {
        useDataValue( dataElementA, periodA, sourceA, "1" );
        useDataValue( dataElementB, periodA, sourceA, "2" );
        useDataValue( dataElementC, periodA, sourceA, "3" );
        useDataValue( dataElementD, periodA, sourceA, "4" );

        validationRuleService.saveValidationRule( validationRuleA );
        validationRuleService.saveValidationRule( validationRuleB );
        validationRuleService.saveValidationRule( validationRuleC );
        validationRuleService.saveValidationRule( validationRuleD );

        Collection<ValidationResult> results = validationService.startInteractiveValidationAnalysis( dataSetMonthly, periodA, sourceA, null );

        Collection<ValidationResult> reference = new HashSet<>();

        reference.add( new ValidationResult( validationRuleA, periodA, sourceA, defaultCombo, 3.0, -1.0, dayInPeriodA ) );
        reference.add( new ValidationResult( validationRuleB, periodA, sourceA, defaultCombo, -1.0, 4.0, dayInPeriodA ) );

        assertResultsEquals( reference, results );
    }

    @Test
    public void testValidateDays()
    {
        useDataValue( dataElementA, periodA, sourceA, "1111" );
        useDataValue( dataElementE, periodY, sourceB, "2222" );

        validationRuleService.saveValidationRule( validationRuleP );
        validationRuleService.saveValidationRule( validationRuleQ );

        Collection<ValidationResult> results = validationService.startInteractiveValidationAnalysis( dataSetMonthly, periodA, sourceA, null );

        Collection<ValidationResult> reference = new HashSet<>();

        reference.add( new ValidationResult( validationRuleP, periodA, sourceA, defaultCombo, 1111.0, 31.0, dayInPeriodA ) );

        assertResultsEquals( reference, results );

        results = validationService.startInteractiveValidationAnalysis( dataSetYearly, periodY, sourceB, null );

        reference = new HashSet<>();

        reference.add( new ValidationResult( validationRuleQ, periodY, sourceB, defaultCombo, 2222.0, 366.0, dayInPeriodY ) );

        assertResultsEquals( reference, results );
    }

    @Test
    public void testValidateMissingValues00()
    {
        validationRuleService.saveValidationRule( validationRuleG );

        Collection<ValidationResult> results = validationService.startInteractiveValidationAnalysis( dataSetMonthly, periodA, sourceA, null );

        assertResultsEmpty( results );
    }

    @Test
    public void testValidateMissingValues01()
    {
        useDataValue( dataElementD, periodA, sourceA, "1" );

        validationRuleService.saveValidationRule( validationRuleG );

        Collection<ValidationResult> reference = new HashSet<>();

        Collection<ValidationResult> results = validationService.startInteractiveValidationAnalysis( dataSetMonthly, periodA, sourceA, null );

        reference.add( new ValidationResult( validationRuleG, periodA, sourceA, defaultCombo, 0.0, 1.0, dayInPeriodA ) );

        assertResultsEquals( reference, results );
    }

    @Test
    public void testValidateMissingValues10()
    {
        useDataValue( dataElementC, periodA, sourceA, "1" );

        validationRuleService.saveValidationRule( validationRuleG );

        Collection<ValidationResult> reference = new HashSet<>();

        Collection<ValidationResult> results = validationService.startInteractiveValidationAnalysis( dataSetMonthly, periodA, sourceA, null );

        reference.add( new ValidationResult( validationRuleG, periodA, sourceA, defaultCombo, 1.0, 0.0, dayInPeriodA ) );

        assertResultsEquals( reference, results );
    }

    @Test
    public void testValidateMissingValues11()
    {
        useDataValue( dataElementC, periodA, sourceA, "1" );
        useDataValue( dataElementD, periodA, sourceA, "1" );

        Collection<ValidationResult> results = validationService.startInteractiveValidationAnalysis( dataSetMonthly, periodA, sourceA, null );

        assertResultsEmpty( results );
    }

    @Test
    public void testValidateCompulsoryPair00()
    {
        validationRuleService.saveValidationRule( validationRuleE );

        Collection<ValidationResult> results = validationService.startInteractiveValidationAnalysis( dataSetMonthly, periodA, sourceA, null );

        assertResultsEmpty( results );
    }

    @Test
    public void testValidateCompulsoryPair01()
    {
        useDataValue( dataElementB, periodA, sourceA, "1" );

        validationRuleService.saveValidationRule( validationRuleE );

        Collection<ValidationResult> results = validationService.startInteractiveValidationAnalysis( dataSetMonthly, periodA, sourceA, null );

        Collection<ValidationResult> reference = new HashSet<>();

        reference.add( new ValidationResult( validationRuleE, periodA, sourceA, defaultCombo, 0.0, 1.0, dayInPeriodA ) );

        assertResultsEquals( reference, results );
    }

    @Test
    public void testValidateCompulsoryPair10()
    {
        useDataValue( dataElementA, periodA, sourceA, "1" );

        validationRuleService.saveValidationRule( validationRuleE );

        Collection<ValidationResult> results = validationService.startInteractiveValidationAnalysis( dataSetMonthly, periodA, sourceA, null );

        Collection<ValidationResult> reference = new HashSet<>();

        reference.add( new ValidationResult( validationRuleE, periodA, sourceA, defaultCombo, 1.0, 0.0, dayInPeriodA ) );

        assertResultsEquals( reference, results );
    }

    @Test
    public void testValidateCompulsoryPair11()
    {
        useDataValue( dataElementA, periodA, sourceA, "1" );
        useDataValue( dataElementB, periodA, sourceA, "1" );

        validationRuleService.saveValidationRule( validationRuleE );

        Collection<ValidationResult> results = validationService.startInteractiveValidationAnalysis( dataSetMonthly, periodA, sourceA, null );

        assertResultsEmpty( results );
    }

    @Test
    public void testValidateExclusivePairWithOtherData00()
    {
        useDataValue( dataElementC, periodA, sourceA, "96" );
        validationRuleService.saveValidationRule( validationRuleG );

        validationRuleService.saveValidationRule( validationRuleF );

        Collection<ValidationResult> results = validationService.startInteractiveValidationAnalysis( dataSetMonthly, periodA, sourceA, null );

        Collection<ValidationResult> reference = new HashSet<>();

        reference.add( new ValidationResult( validationRuleG, periodA, sourceA, defaultCombo, 96.0, 0.0, dayInPeriodA ) );

        assertResultsEquals( reference, results );
    }

    @Test
    public void testValidateExclusivePairWithOtherData01()
    {
        useDataValue( dataElementC, periodA, sourceA, "97" );
        validationRuleService.saveValidationRule( validationRuleG );

        useDataValue( dataElementB, periodA, sourceA, "1" );

        validationRuleService.saveValidationRule( validationRuleF );

        Collection<ValidationResult> results = validationService.startInteractiveValidationAnalysis( dataSetMonthly, periodA, sourceA, null );

        Collection<ValidationResult> reference = new HashSet<>();

        reference.add( new ValidationResult( validationRuleG, periodA, sourceA, defaultCombo, 97.0, 0.0, dayInPeriodA ) );

        assertResultsEquals( reference, results );
    }

    @Test
    public void testValidateExclusivePairWithOtherData10()
    {
        useDataValue( dataElementC, periodA, sourceA, "98" );
        validationRuleService.saveValidationRule( validationRuleG );

        useDataValue( dataElementA, periodA, sourceA, "1" );

        validationRuleService.saveValidationRule( validationRuleF );

        Collection<ValidationResult> results = validationService.startInteractiveValidationAnalysis( dataSetMonthly, periodA, sourceA, null );

        Collection<ValidationResult> reference = new HashSet<>();

        reference.add( new ValidationResult( validationRuleG, periodA, sourceA, defaultCombo, 98.0, 0.0, dayInPeriodA ) );

        assertResultsEquals( reference, results );
    }

    @Test
    public void testValidateExclusivePairWithOtherData11()
    {
        useDataValue( dataElementC, periodA, sourceA, "99" );
        validationRuleService.saveValidationRule( validationRuleG );

        useDataValue( dataElementA, periodA, sourceA, "1" );
        useDataValue( dataElementB, periodA, sourceA, "2" );

        validationRuleService.saveValidationRule( validationRuleF );

        Collection<ValidationResult> results = validationService.startInteractiveValidationAnalysis( dataSetMonthly, periodA, sourceA, null );

        Collection<ValidationResult> reference = new HashSet<>();

        reference.add( new ValidationResult( validationRuleF, periodA, sourceA, defaultCombo, 1.0, 2.0, dayInPeriodA ) );
        reference.add( new ValidationResult( validationRuleG, periodA, sourceA, defaultCombo, 99.0, 0.0, dayInPeriodA ) );

        assertResultsEquals( reference, results );
    }

    @Test
    public void testValidateExclusivePair00()
    {
        validationRuleService.saveValidationRule( validationRuleF );

        Collection<ValidationResult> results = validationService.startInteractiveValidationAnalysis( dataSetMonthly, periodA, sourceA, null );

        assertResultsEmpty( results );
    }

    @Test
    public void testValidateExclusivePair01()
    {
        useDataValue( dataElementB, periodA, sourceA, "1" );

        validationRuleService.saveValidationRule( validationRuleF );

        Collection<ValidationResult> results = validationService.startInteractiveValidationAnalysis( dataSetMonthly, periodA, sourceA, null );

        assertResultsEmpty( results );
    }

    @Test
    public void testValidateExclusivePair10()
    {
        useDataValue( dataElementA, periodA, sourceA, "1" );

        validationRuleService.saveValidationRule( validationRuleF );

        Collection<ValidationResult> results = validationService.startInteractiveValidationAnalysis( dataSetMonthly, periodA, sourceA, null );

        assertResultsEmpty( results );
    }

    @Test
    public void testValidateExclusivePair11()
    {
        useDataValue( dataElementA, periodA, sourceA, "1" );
        useDataValue( dataElementB, periodA, sourceA, "2" );

        validationRuleService.saveValidationRule( validationRuleF );

        Collection<ValidationResult> results = validationService.startInteractiveValidationAnalysis( dataSetMonthly, periodA, sourceA, null );

        Collection<ValidationResult> reference = new HashSet<>();

        reference.add( new ValidationResult( validationRuleF, periodA, sourceA, defaultCombo, 1.0, 2.0, dayInPeriodA ) );

        assertResultsEquals( reference, results );
    }

    @Test
    public void testValidateWithAttributeOptions()
    {
        DataElementCategoryOption optionA = new DataElementCategoryOption( "CategoryOptionA" );
        DataElementCategoryOption optionB = new DataElementCategoryOption( "CategoryOptionB" );
        DataElementCategoryOption optionC = new DataElementCategoryOption( "CategoryOptionC" );

        categoryService.addDataElementCategoryOption( optionA );
        categoryService.addDataElementCategoryOption( optionB );
        categoryService.addDataElementCategoryOption( optionC );

        DataElementCategory categoryA = createDataElementCategory( 'A', optionA, optionB );
        DataElementCategory categoryB = createDataElementCategory( 'B', optionC );
        categoryA.setDataDimension( true );
        categoryB.setDataDimension( true );

        categoryService.addDataElementCategory( categoryA );
        categoryService.addDataElementCategory( categoryB );

        DataElementCategoryCombo categoryComboAB = createCategoryCombo( 'A', categoryA, categoryB );

        categoryService.addDataElementCategoryCombo( categoryComboAB );

        DataElementCategoryOptionCombo optionComboAC = createCategoryOptionCombo( 'A', categoryComboAB, optionA,
            optionC );
        DataElementCategoryOptionCombo optionComboBC = createCategoryOptionCombo( 'A', categoryComboAB, optionB,
            optionC );

        categoryService.addDataElementCategoryOptionCombo( optionComboAC );
        categoryService.addDataElementCategoryOptionCombo( optionComboBC );

        useDataValue( dataElementA, periodA, sourceA, "4", optionCombo, optionComboAC );
        useDataValue( dataElementB, periodA, sourceA, "3", optionCombo, optionComboAC );

        useDataValue( dataElementA, periodA, sourceA, "2", optionCombo, optionComboBC );
        useDataValue( dataElementB, periodA, sourceA, "1", optionCombo, optionComboBC );

        validationRuleService.saveValidationRule( validationRuleD ); // deA + deB < deB * 2
        validationRuleService.saveValidationRule( validationRuleX ); // deA + deB = deB * 2

        //
        // optionComboAC
        //
        Collection<ValidationResult> results = validationService.startInteractiveValidationAnalysis( dataSetMonthly, periodA, sourceA,
            optionComboAC );

        Collection<ValidationResult> reference = new HashSet<>();

        reference.add( new ValidationResult( validationRuleD, periodA, sourceA, optionComboAC, 7.0, 6.0, dayInPeriodA ) );
        reference.add( new ValidationResult( validationRuleX, periodA, sourceA, optionComboAC, 7.0, 6.0, dayInPeriodA ) );

        assertResultsEquals( reference, results );

        //
        // All optionCombos
        //
        results = validationService.startInteractiveValidationAnalysis( dataSetMonthly, periodA, sourceA, null );

        reference = new HashSet<>();

        reference.add( new ValidationResult( validationRuleD, periodA, sourceA, optionComboAC, 7.0, 6.0, dayInPeriodA ) );
        reference.add( new ValidationResult( validationRuleX, periodA, sourceA, optionComboAC, 7.0, 6.0, dayInPeriodA ) );
        reference.add( new ValidationResult( validationRuleD, periodA, sourceA, optionComboBC, 3.0, 2.0, dayInPeriodA ) );
        reference.add( new ValidationResult( validationRuleX, periodA, sourceA, optionComboBC, 3.0, 2.0, dayInPeriodA ) );

        assertResultsEquals( reference, results );

        //
        // Default optionCombo
        //
        results = validationService.startInteractiveValidationAnalysis( dataSetMonthly, periodA, sourceA, optionCombo );

        assertResultsEmpty( results );
    }
}


text:
#ifndef simpleColorCode_H_
#define simpleColorCode_H_
#include "robotBlocksGeneric.h"

static const int BROADCAST_MSG=1001;
static const int ACK_MSG=1002;

using namespace RobotBlocks;

class SimpleColorCode : public RobotBlocksGeneric {
private:
    int distance;
    int nbWaitedAnswers;
    P2PNetworkInterface *parent;
public :
	SimpleColorCode(RobotBlocksBlock *host):RobotBlocksGeneric(host) {};
	~SimpleColorCode() {};

	void startup();
	void myBroadcastFunc(const MessageOf<int>*msg,P2PNetworkInterface *sender);
	void myAckFunc(const MessageOf<int>*msg,P2PNetworkInterface *sender);

/*****************************************************************************/
/** needed to associate code to module                                      **/
	static RobotBlocksBlockCode *buildNewBlockCode(RobotBlocksBlock *host) {
	    return(new SimpleColorCode(host));
	};
/*****************************************************************************/
};
	void _myBroadcastFunc(RobotBlocksGeneric *,MessagePtr,P2PNetworkInterface *sender);
	void _myAckFunc(RobotBlocksGeneric *,MessagePtr,P2PNetworkInterface *sender);
#endif /* simpleColorCode_H_ */

redpajama_set_name: RedPajamaGithub


text:
<!DOCTYPE html>

    <meta charset="utf-8" />
		<meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Test Cordova API</title>
		<link rel="stylesheet" href="lib/jquery.mobile.min.css" />
		<link rel="stylesheet" href="css/index.css" />

Home

Detecting cordova plugins...

Exit

			Tests

Test Cordova API

			Launch Cordova

Cordova API Test Suite

This is a set of manual tests for the Cordova API. The list of tests depends on which plugins are found.


text:
.class Landroid/support/v4/view/ViewGroupCompat$ViewGroupCompatStubImpl;
.super Ljava/lang/Object;
.source "ViewGroupCompat.java"

# interfaces
.implements Landroid/support/v4/view/ViewGroupCompat$ViewGroupCompatImpl;

# annotations
.annotation system Ldalvik/annotation/EnclosingClass;
    value = Landroid/support/v4/view/ViewGroupCompat;
.end annotation

.annotation system Ldalvik/annotation/InnerClass;
    accessFlags = 0x8
    name = "ViewGroupCompatStubImpl"
.end annotation

# direct methods
.method constructor <init>()V
    .locals 0

    .prologue
    .line 37
    invoke-direct {p0}, Ljava/lang/Object;-><init>()V

    return-void
.end method

# virtual methods
.method public onRequestSendAccessibilityEvent(Landroid/view/ViewGroup;Landroid/view/View;Landroid/view/accessibility/AccessibilityEvent;)Z
    .locals 1
    .parameter "group"
    .parameter "child"
    .parameter "event"

    .prologue
    .line 40
    const/4 v0, 0x1

    return v0
.end method

.method public setMotionEventSplittingEnabled(Landroid/view/ViewGroup;Z)V
    .locals 0
    .parameter "group"
    .parameter "split"

    .prologue
    .line 45
    return-void
.end method


text:
<?php

namespace Pterodactyl\Tests\Integration\Services\Schedules;

use Mockery;
use Exception;
use Carbon\CarbonImmutable;
use Pterodactyl\Models\Task;
use InvalidArgumentException;
use Pterodactyl\Models\Schedule;
use Illuminate\Support\Facades\Bus;
use Illuminate\Contracts\Bus\Dispatcher;
use Pterodactyl\Jobs\Schedule\RunTaskJob;
use Pterodactyl\Exceptions\DisplayException;
use Pterodactyl\Tests\Integration\IntegrationTestCase;
use Pterodactyl\Services\Schedules\ProcessScheduleService;

class ProcessScheduleServiceTest extends IntegrationTestCase
{
    /**
     * Test that a schedule with no tasks registered returns an error.
     */
    public function testScheduleWithNoTasksReturnsException()
    {
        $server = $this->createServerModel();
        $schedule = Schedule::factory()->create(['server_id' => $server->id]);

        $this->expectException(DisplayException::class);
        $this->expectExceptionMessage('Cannot process schedule for task execution: no tasks are registered.');

        $this->getService()->handle($schedule);
    }

    /**
     * Test that an error during the schedule update is not persisted to the database.
     */
    public function testErrorDuringScheduleDataUpdateDoesNotPersistChanges()
    {
        $server = $this->createServerModel();

        /** @var \Pterodactyl\Models\Schedule $schedule */
        $schedule = Schedule::factory()->create([
            'server_id' => $server->id,
            'cron_minute' => 'hodor', // this will break the getNextRunDate() function.
        ]);

        /** @var \Pterodactyl\Models\Task $task */
        $task = Task::factory()->create(['schedule_id' => $schedule->id, 'sequence_id' => 1]);

        $this->expectException(InvalidArgumentException::class);

        $this->getService()->handle($schedule);

        $this->assertDatabaseMissing('schedules', ['id' => $schedule->id, 'is_processing' => true]);
        $this->assertDatabaseMissing('tasks', ['id' => $task->id, 'is_queued' => true]);
    }

    /**
     * Test that a job is dispatched as expected using the initial delay.
     *
     * @param bool $now
     * @dataProvider dispatchNowDataProvider
     */
    public function testJobCanBeDispatchedWithExpectedInitialDelay($now)
    {
        Bus::fake();

        $server = $this->createServerModel();

        /** @var \Pterodactyl\Models\Schedule $schedule */
        $schedule = Schedule::factory()->create(['server_id' => $server->id]);

        /** @var \Pterodactyl\Models\Task $task */
        $task = Task::factory()->create(['schedule_id' => $schedule->id, 'time_offset' => 10, 'sequence_id' => 1]);

        $this->getService()->handle($schedule, $now);

        Bus::assertDispatched(RunTaskJob::class, function ($job) use ($now, $task) {
            $this->assertInstanceOf(RunTaskJob::class, $job);
            $this->assertSame($task->id, $job->task->id);
            // Jobs using dispatchNow should not have a delay associated with them.
            $this->assertSame($now ? null : 10, $job->delay);

            return true;
        });

        $this->assertDatabaseHas('schedules', ['id' => $schedule->id, 'is_processing' => true]);
        $this->assertDatabaseHas('tasks', ['id' => $task->id, 'is_queued' => true]);
    }

    /**
     * Test that even if a schedule's task sequence gets messed up the first task based on
     * the ascending order of tasks is used.
     *
     * @see https://github.com/pterodactyl/panel/issues/2534
     */
    public function testFirstSequenceTaskIsFound()
    {
        Bus::fake();

        $server = $this->createServerModel();
        /** @var \Pterodactyl\Models\Schedule $schedule */
        $schedule = Schedule::factory()->create(['server_id' => $server->id]);

        /** @var \Pterodactyl\Models\Task $task */
        $task2 = Task::factory()->create(['schedule_id' => $schedule->id, 'sequence_id' => 4]);
        $task = Task::factory()->create(['schedule_id' => $schedule->id, 'sequence_id' => 2]);
        $task3 = Task::factory()->create(['schedule_id' => $schedule->id, 'sequence_id' => 3]);

        $this->getService()->handle($schedule);

        Bus::assertDispatched(RunTaskJob::class, function (RunTaskJob $job) use ($task) {
            return $task->id === $job->task->id;
        });

        $this->assertDatabaseHas('schedules', ['id' => $schedule->id, 'is_processing' => true]);
        $this->assertDatabaseHas('tasks', ['id' => $task->id, 'is_queued' => true]);
        $this->assertDatabaseHas('tasks', ['id' => $task2->id, 'is_queued' => false]);
        $this->assertDatabaseHas('tasks', ['id' => $task3->id, 'is_queued' => false]);
    }

    /**
     * Tests that a task's processing state is reset correctly if using "dispatchNow" and there is
     * an exception encountered while running it.
     *
     * @see https://github.com/pterodactyl/panel/issues/2550
     */
    public function testTaskDispatchedNowIsResetProperlyIfErrorIsEncountered()
    {
        $this->swap(Dispatcher::class, $dispatcher = Mockery::mock(Dispatcher::class));

        $server = $this->createServerModel();
        /** @var \Pterodactyl\Models\Schedule $schedule */
        $schedule = Schedule::factory()->create(['server_id' => $server->id, 'last_run_at' => null]);
        /** @var \Pterodactyl\Models\Task $task */
        $task = Task::factory()->create(['schedule_id' => $schedule->id, 'sequence_id' => 1]);

        $dispatcher->expects('dispatchNow')->andThrows(new Exception('Test thrown exception'));

        $this->expectException(Exception::class);
        $this->expectExceptionMessage('Test thrown exception');

        $this->getService()->handle($schedule, true);

        $this->assertDatabaseHas('schedules', [
            'id' => $schedule->id,
            'is_processing' => false,
            'last_run_at' => CarbonImmutable::now()->toAtomString(),
        ]);

        $this->assertDatabaseHas('tasks', ['id' => $task->id, 'is_queued' => false]);
    }

    public function dispatchNowDataProvider(): array
    {
        return [[true], [false]];
    }

    /**
     * @return \Pterodactyl\Services\Schedules\ProcessScheduleService
     */
    private function getService()
    {
        return $this->app->make(ProcessScheduleService::class);
    }
}


text:
<?php

namespace app\Config\Bridge;

use app\config\Interfaces\Loadable;
use Silex;

abstract class Router implements Loadable
{

    /**
     *
     * @var Silex\Application
     */
    protected $_app;

    /**
     * @param \Silex\Application $app
     */
    public function __construct(Silex\Application $app)
    {
        $this->_app = $app;
    }

}


text:
'use strict'
 /**
 * @private
 * @namespace {object} Intern
 */
function Intern () {}

/**
* @private
* @function Intern#emitAsync
*
* Emit event after queing to the end of the event loop
*/
Intern.emitAsync = function (eventName, err, data) {
  if (this.constructor.name === 'Function') {
    throw new Error('Caller must be an emitter')
  }

  setImmediate(function emitNextTick () {
    this.emit(eventName, err, data)
  }.bind(this))
}

/**
* Handle the string or undefined, default to true for 'undefined'
* @private
* @function Intern#isTrueOrUndefined
*/
Intern.isTrueOrUndefined = function (val) {
  return (typeof val === 'undefined') || ('' + val) === 'true'
}

/**
* Merge in new object properties, without overwriting the existing
* @private
* @function Intern#addOptions
*/
Intern.addOptions = function (existingObj, newProps) {
  for (let propName in newProps) {
    // AWS option properties always start with upper case
    let newPropName = propName.charAt(0).toUpperCase() + propName.substr(1)

    // never overwrite an existing property & never insert 'undefined'
    if (existingObj.hasOwnProperty(newPropName)) continue
    if (typeof newProps[propName] === 'undefined') continue

    existingObj[newPropName] = newProps[propName]
  }

  return existingObj
}

/**
* @typedef {namespace} Const
* @private
*/
const Const = {
  // Event names

  // To the callers
  EVENT_INITIALIZED: 'initialized',
  EVENT_PRICED: 'priced',
  EVENT_LAUNCHED: 'launched',
  EVENT_INSTANCES: 'instances',
  EVENT_SPOTS: 'spots',
  EVENT_TERMINATED: 'terminated',
  EVENT_CANCELED: 'canceled'
}

/**
* @description Helper for AwsSpotter
*/
module.exports = {
  Intern: Intern,
  Const: Const
}


text:
'use strict';

var $npm = {
    utils: require('../utils'),
    PS: require('./prepared'),
    PQ: require('./parameterized')
};

// istanbul ignore next;
function ExternalQuery() {
}

ExternalQuery.prototype.inspect = function () {
    return this.toString();
};

$npm.utils.inherits($npm.PS, ExternalQuery);
$npm.utils.inherits($npm.PQ, ExternalQuery);

module.exports = {
    ExternalQuery: ExternalQuery,
    PreparedStatement: $npm.PS,
    ParameterizedQuery: $npm.PQ
};


text:
#include <aws/resiliencehub/model/RecommendationTemplate.h>
#include <aws/core/utils/json/JsonSerializer.h>

#include <utility>

using namespace Aws::Utils::Json;
using namespace Aws::Utils;

namespace Aws
{
namespace ResilienceHub
{
namespace Model
{

RecommendationTemplate::RecommendationTemplate() :
    m_appArnHasBeenSet(false),
    m_assessmentArnHasBeenSet(false),
    m_endTimeHasBeenSet(false),
    m_format(TemplateFormat::NOT_SET),
    m_formatHasBeenSet(false),
    m_messageHasBeenSet(false),
    m_nameHasBeenSet(false),
    m_needsReplacements(false),
    m_needsReplacementsHasBeenSet(false),
    m_recommendationIdsHasBeenSet(false),
    m_recommendationTemplateArnHasBeenSet(false),
    m_recommendationTypesHasBeenSet(false),
    m_startTimeHasBeenSet(false),
    m_status(RecommendationTemplateStatus::NOT_SET),
    m_statusHasBeenSet(false),
    m_tagsHasBeenSet(false),
    m_templatesLocationHasBeenSet(false)
{
}

RecommendationTemplate::RecommendationTemplate(JsonView jsonValue) :
    m_appArnHasBeenSet(false),
    m_assessmentArnHasBeenSet(false),
    m_endTimeHasBeenSet(false),
    m_format(TemplateFormat::NOT_SET),
    m_formatHasBeenSet(false),
    m_messageHasBeenSet(false),
    m_nameHasBeenSet(false),
    m_needsReplacements(false),
    m_needsReplacementsHasBeenSet(false),
    m_recommendationIdsHasBeenSet(false),
    m_recommendationTemplateArnHasBeenSet(false),
    m_recommendationTypesHasBeenSet(false),
    m_startTimeHasBeenSet(false),
    m_status(RecommendationTemplateStatus::NOT_SET),
    m_statusHasBeenSet(false),
    m_tagsHasBeenSet(false),
    m_templatesLocationHasBeenSet(false)
{
  *this = jsonValue;
}

RecommendationTemplate& RecommendationTemplate::operator =(JsonView jsonValue)
{
  if(jsonValue.ValueExists("appArn"))
  {
    m_appArn = jsonValue.GetString("appArn");

    m_appArnHasBeenSet = true;
  }

  if(jsonValue.ValueExists("assessmentArn"))
  {
    m_assessmentArn = jsonValue.GetString("assessmentArn");

    m_assessmentArnHasBeenSet = true;
  }

  if(jsonValue.ValueExists("endTime"))
  {
    m_endTime = jsonValue.GetDouble("endTime");

    m_endTimeHasBeenSet = true;
  }

  if(jsonValue.ValueExists("format"))
  {
    m_format = TemplateFormatMapper::GetTemplateFormatForName(jsonValue.GetString("format"));

    m_formatHasBeenSet = true;
  }

  if(jsonValue.ValueExists("message"))
  {
    m_message = jsonValue.GetString("message");

    m_messageHasBeenSet = true;
  }

  if(jsonValue.ValueExists("name"))
  {
    m_name = jsonValue.GetString("name");

    m_nameHasBeenSet = true;
  }

  if(jsonValue.ValueExists("needsReplacements"))
  {
    m_needsReplacements = jsonValue.GetBool("needsReplacements");

    m_needsReplacementsHasBeenSet = true;
  }

  if(jsonValue.ValueExists("recommendationIds"))
  {
    Aws::Utils::Array<JsonView> recommendationIdsJsonList = jsonValue.GetArray("recommendationIds");
    for(unsigned recommendationIdsIndex = 0; recommendationIdsIndex < recommendationIdsJsonList.GetLength(); ++recommendationIdsIndex)
    {
      m_recommendationIds.push_back(recommendationIdsJsonList[recommendationIdsIndex].AsString());
    }
    m_recommendationIdsHasBeenSet = true;
  }

  if(jsonValue.ValueExists("recommendationTemplateArn"))
  {
    m_recommendationTemplateArn = jsonValue.GetString("recommendationTemplateArn");

    m_recommendationTemplateArnHasBeenSet = true;
  }

  if(jsonValue.ValueExists("recommendationTypes"))
  {
    Aws::Utils::Array<JsonView> recommendationTypesJsonList = jsonValue.GetArray("recommendationTypes");
    for(unsigned recommendationTypesIndex = 0; recommendationTypesIndex < recommendationTypesJsonList.GetLength(); ++recommendationTypesIndex)
    {
      m_recommendationTypes.push_back(RenderRecommendationTypeMapper::GetRenderRecommendationTypeForName(recommendationTypesJsonList[recommendationTypesIndex].AsString()));
    }
    m_recommendationTypesHasBeenSet = true;
  }

  if(jsonValue.ValueExists("startTime"))
  {
    m_startTime = jsonValue.GetDouble("startTime");

    m_startTimeHasBeenSet = true;
  }

  if(jsonValue.ValueExists("status"))
  {
    m_status = RecommendationTemplateStatusMapper::GetRecommendationTemplateStatusForName(jsonValue.GetString("status"));

    m_statusHasBeenSet = true;
  }

  if(jsonValue.ValueExists("tags"))
  {
    Aws::Map<Aws::String, JsonView> tagsJsonMap = jsonValue.GetObject("tags").GetAllObjects();
    for(auto& tagsItem : tagsJsonMap)
    {
      m_tags[tagsItem.first] = tagsItem.second.AsString();
    }
    m_tagsHasBeenSet = true;
  }

  if(jsonValue.ValueExists("templatesLocation"))
  {
    m_templatesLocation = jsonValue.GetObject("templatesLocation");

    m_templatesLocationHasBeenSet = true;
  }

  return *this;
}

JsonValue RecommendationTemplate::Jsonize() const
{
  JsonValue payload;

  if(m_appArnHasBeenSet)
  {
   payload.WithString("appArn", m_appArn);

  }

  if(m_assessmentArnHasBeenSet)
  {
   payload.WithString("assessmentArn", m_assessmentArn);

  }

  if(m_endTimeHasBeenSet)
  {
   payload.WithDouble("endTime", m_endTime.SecondsWithMSPrecision());
  }

  if(m_formatHasBeenSet)
  {
   payload.WithString("format", TemplateFormatMapper::GetNameForTemplateFormat(m_format));
  }

  if(m_messageHasBeenSet)
  {
   payload.WithString("message", m_message);

  }

  if(m_nameHasBeenSet)
  {
   payload.WithString("name", m_name);

  }

  if(m_needsReplacementsHasBeenSet)
  {
   payload.WithBool("needsReplacements", m_needsReplacements);

  }

  if(m_recommendationIdsHasBeenSet)
  {
   Aws::Utils::Array<JsonValue> recommendationIdsJsonList(m_recommendationIds.size());
   for(unsigned recommendationIdsIndex = 0; recommendationIdsIndex < recommendationIdsJsonList.GetLength(); ++recommendationIdsIndex)
   {
     recommendationIdsJsonList[recommendationIdsIndex].AsString(m_recommendationIds[recommendationIdsIndex]);
   }
   payload.WithArray("recommendationIds", std::move(recommendationIdsJsonList));

  }

  if(m_recommendationTemplateArnHasBeenSet)
  {
   payload.WithString("recommendationTemplateArn", m_recommendationTemplateArn);

  }

  if(m_recommendationTypesHasBeenSet)
  {
   Aws::Utils::Array<JsonValue> recommendationTypesJsonList(m_recommendationTypes.size());
   for(unsigned recommendationTypesIndex = 0; recommendationTypesIndex < recommendationTypesJsonList.GetLength(); ++recommendationTypesIndex)
   {
     recommendationTypesJsonList[recommendationTypesIndex].AsString(RenderRecommendationTypeMapper::GetNameForRenderRecommendationType(m_recommendationTypes[recommendationTypesIndex]));
   }
   payload.WithArray("recommendationTypes", std::move(recommendationTypesJsonList));

  }

  if(m_startTimeHasBeenSet)
  {
   payload.WithDouble("startTime", m_startTime.SecondsWithMSPrecision());
  }

  if(m_statusHasBeenSet)
  {
   payload.WithString("status", RecommendationTemplateStatusMapper::GetNameForRecommendationTemplateStatus(m_status));
  }

  if(m_tagsHasBeenSet)
  {
   JsonValue tagsJsonMap;
   for(auto& tagsItem : m_tags)
   {
     tagsJsonMap.WithString(tagsItem.first, tagsItem.second);
   }
   payload.WithObject("tags", std::move(tagsJsonMap));

  }

  if(m_templatesLocationHasBeenSet)
  {
   payload.WithObject("templatesLocation", m_templatesLocation.Jsonize());

  }

  return payload;
}

} // namespace Model
} // namespace ResilienceHub
} // namespace Aws


text:
"""List subnets."""
# :license: MIT, see LICENSE for more details.

import SoftLayer
from SoftLayer.CLI import environment
from SoftLayer.CLI import formatting
from SoftLayer import utils

import click

@click.command()
@click.option('--sortby',
              help='Column to sort by',
              type=click.Choice(['id',
                                 'identifier',
                                 'type',
                                 'datacenter',
                                 'vlan_id',
                                 'IPs',
                                 'hardware',
                                 'vs']))
@click.option('--datacenter', '-d',
              help="Filter by datacenter shortname (sng01, dal05, ...)")
@click.option('--identifier', help="Filter by network identifier")
@click.option('--subnet-type', '-t', help="Filter by subnet type")
@click.option('--v4', '--ipv4', is_flag=True, help="Display only IPv4 subnets")
@click.option('--v6', '--ipv6', is_flag=True, help="Display only IPv6 subnets")
@environment.pass_env
def cli(env, sortby, datacenter, identifier, subnet_type, ipv4, ipv6):
    """List subnets."""

    mgr = SoftLayer.NetworkManager(env.client)

    table = formatting.Table([
        'id', 'identifier', 'type', 'datacenter', 'vlan_id', 'IPs',
        'hardware', 'vs',
    ])
    table.sortby = sortby

    version = 0
    if ipv4:
        version = 4
    elif ipv6:
        version = 6

    subnets = mgr.list_subnets(
        datacenter=datacenter,
        version=version,
        identifier=identifier,
        subnet_type=subnet_type,
    )

    for subnet in subnets:
        table.add_row([
            subnet['id'],
            '%s/%s' % (subnet['networkIdentifier'], str(subnet['cidr'])),
            subnet.get('subnetType', formatting.blank()),
            utils.lookup(subnet, 'datacenter', 'name',) or formatting.blank(),
            subnet['networkVlanId'],
            subnet['ipAddressCount'],
            len(subnet['hardware']),
            len(subnet['virtualGuests']),
        ])

    env.fout(table)


text:
Wait For Page Loaded Modifier waits until the page is loaded (all DOM elements are loaded) or a fixed amount of time is up. The idea of waiting for the page is to count the amount of elements [by `findElements(By.xpath("//*"))`] on the current page state in the loop. If the number of elements has increased since the last checkout, continue the loop (or break if the timeout is reached). Else if the number of elements is still, assume the page has been loaded and finish waiting.

Module name: **wait-for-page-loaded**

##### Parameters

No parameters.

| ! Important information |
|:----------------------- |
| Timeout for waiting is 10000 milliseconds.

 The Page is checked every 1000 milliseconds. |

##### Sample Usage

```xml
<?xml version="1.0" encoding="UTF-8" ?>
<suite name="test-suite" company="cognifide" project="project">
    <test name="wait-for-page-loaded-test">
        <collect>
            ...
            <open />
            ...
            <wait-for-page-loaded />
            ...
        </collect>
        <compare>
            ...
        </compare>
        <urls>
        ...
        </urls>
    </test>
    ...
    <reports>
        ...
    </reports>
</suite>
```


text:
<form action="http://www.feel3.de:10100/sendjob" method="post">
	<input type="hidden" name="testval" value="nur ein test" />
	<label for="_customer">Customer:</label>
	<input type="text" name="customer" id="_customer" />
	<input type="submit" value="Send">
</form>


text:
from cinder.api import extensions

class Extended_services(extensions.ExtensionDescriptor):
    """Extended services support."""

    name = "ExtendedServices"
    alias = "os-extended-services"
    updated = "2014-01-10T00:00:00-00:00"


text:
package com.interface21.validation;

import java.beans.PropertyChangeListener;
import java.beans.PropertyEditor;
import java.beans.VetoableChangeListener;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.interface21.beans.ErrorCodedPropertyVetoException;
import com.interface21.beans.PropertyValue;
import com.interface21.beans.PropertyValues;
import com.interface21.beans.PropertyVetoExceptionsException;

/**
 * Binder that allows for binding property values to a target object.
 * Supports property change listeners and vetoable change listeners.
 * @author Rod Johnson
 * @version 1.0
 */
public class DataBinder extends BindException {

	public static final String MISSING_FIELD_ERROR_CODE = "required";

	protected static final Log logger = LogFactory.getLog(DataBinder.class);

	private String[] requiredFields;

	/**
	 * Create a new DataBinder instance.
	 * @param target target object to bind onto
	 * @param name name of the target object
	 */
	public DataBinder(Object target, String name) {
		super(target, name);
	}

	/**
	 * Register fields that are required for each binding process.
	 * @param requiredFields array of field names
	 */
	public void setRequiredFields(String[] requiredFields) {
		this.requiredFields = requiredFields;
	}

	/**
	 * Return the fields that are required for each binding process.
	 * @return array of field names
	 */
	protected String[] getRequiredFields() {
		return requiredFields;
	}

	/**
	 * Add a VetoableChangeListener that will be notified of property updates.
	 */
	public void addVetoableChangeListener(VetoableChangeListener vcl) {
		getBeanWrapper().setEventPropagationEnabled(true);
		getBeanWrapper().addVetoableChangeListener(vcl);
	}

	/**
	 * Add a PropertyChangeListener that will be notified of property updates.
	 */
	public void addPropertyChangeListener(PropertyChangeListener pcl) {
		getBeanWrapper().setEventPropagationEnabled(true);
		getBeanWrapper().addPropertyChangeListener(pcl);
	}

	/**
	 * Register the given custom property editor for the given type and
	 * field, or for all fields of the given type.
	 * @param requiredType type of the property, can be null if a field is
	 * given but should be specified in any case for consistency checking
	 * @param field name of the field (can also be a nested path), or
	 * null if registering an editor for all fields of the given type
	 * @param propertyEditor editor to register
	 */
	public void registerCustomEditor(Class requiredType, String field, PropertyEditor propertyEditor) {
		getBeanWrapper().registerCustomEditor(requiredType, field, propertyEditor);
	}

	/**
	 * Register the given custom property editor for all properties
	 * of the given type.
	 * @param requiredType type of the property
	 * @param propertyEditor editor to register
	 */
	public void registerCustomEditor(Class requiredType, PropertyEditor propertyEditor) {
		registerCustomEditor(requiredType, null, propertyEditor);
	}

	/**
	 * Render the field value with a custom editor, if applicable.
	 */
	public Object getFieldValue(String field) {
		Object value = super.getFieldValue(field);
		if (value != null && !hasFieldErrors(field)) {
			PropertyEditor customEditor = getBeanWrapper().findCustomEditor(null, field);
			if (customEditor != null) {
				customEditor.setValue(value);
				return customEditor.getAsText();
			}
		}
		return value;
	}

	/**
	 * Bind the given property values to this binder's target.
	 * This call can create field errors, representing basic binding
	 * errors like a required field (code "required"), or type mismatch
	 * between value and bean property (code "typeMismatch").
	 * @param pvs property values to bind
	 */
	public void bind(PropertyValues pvs) {
		// Check for missing fields
		if (requiredFields != null) {
			for (int i = 0; i < requiredFields.length; i++) {
				PropertyValue pv = pvs.getPropertyValue(requiredFields[i]);
				if (pv == null || "".equals(pv.getValue())) {
					logger.debug("Required field '" + requiredFields[i] + "' is missing or empty");
					// create field error with code "required"
					addFieldError(new FieldError(getObjectName(), requiredFields[i], "", MISSING_FIELD_ERROR_CODE, new Object[] {requiredFields[i]}, "Field '" + requiredFields[i] + "' is required"));
				}
			}
		}
		try {
			// Bind request parameters onto params
			// We ignore unknown properties
			getBeanWrapper().setPropertyValues(pvs, true, null);
		}
		catch (PropertyVetoExceptionsException ex) {
			ErrorCodedPropertyVetoException[] exs = ex.getPropertyVetoExceptions();
			for (int i = 0; i < exs.length; i++) {
				// create field with the exceptions's code, e.g. "typeMismatch"
				addFieldError(new FieldError(getObjectName(), exs[i].getPropertyChangeEvent().getPropertyName(), exs[i].getPropertyChangeEvent().getNewValue(), exs[i].getErrorCode(), null, exs[i].getLocalizedMessage()));
			}
		}
	}

	/**
	 * Close this DataBinder, which may result in throwing
	 * a BindException if it encountered any errors
	 * @throws BindException if there were any errors in the bind operation
	 */
	public Map close() throws BindException {
		if (hasErrors()) {
			throw this;
		}
		return getModel();
	}

}


text:
<?php

return array(
    'router' => array(
        'routes' => array(
            'room' => array(
                'type' => 'Segment',
                'options' => array(
                    'route' => '/room/:rid',
                    'defaults' => array(
                        'controller' => 'Room\Controller\Index',
                        'action' => 'index',
                    ),
                ),
            ),
        ),
    ),

    'controllers' => array(
        'invokables' => array(
            'Room\Controller\Index' => 'Room\Controller\IndexController',
        ),
    ),

    'service_manager' => array(
        'factories' => array(
            'Room\Manager\RoomManager' => 'Room\Manager\RoomManagerFactory',

            'Room\Table\RoomTable' => 'Room\Table\RoomTableFactory',
            'Room\Table\RoomMetaTable' => 'Room\Table\RoomMetaTableFactory',
        ),
    ),

    'view_helpers' => array(
        'invokables' => array(
            'RoomPreview' => 'Room\View\Helper\RoomPreview',
        ),
    ),

    'view_manager' => array(
        'template_path_stack' => array(
            __DIR__ . '/../view',
        ),
    ),
);


text:
package Paws::Lambda::CreateFunction;
  use Moose;
  has Code => (is => 'ro', isa => 'Paws::Lambda::FunctionCode', required => 1);
  has DeadLetterConfig => (is => 'ro', isa => 'Paws::Lambda::DeadLetterConfig');
  has Description => (is => 'ro', isa => 'Str');
  has Environment => (is => 'ro', isa => 'Paws::Lambda::Environment');
  has FunctionName => (is => 'ro', isa => 'Str', required => 1);
  has Handler => (is => 'ro', isa => 'Str', required => 1);
  has KMSKeyArn => (is => 'ro', isa => 'Str');
  has MemorySize => (is => 'ro', isa => 'Int');
  has Publish => (is => 'ro', isa => 'Bool');
  has Role => (is => 'ro', isa => 'Str', required => 1);
  has Runtime => (is => 'ro', isa => 'Str', required => 1);
  has Tags => (is => 'ro', isa => 'Paws::Lambda::Tags');
  has Timeout => (is => 'ro', isa => 'Int');
  has TracingConfig => (is => 'ro', isa => 'Paws::Lambda::TracingConfig');
  has VpcConfig => (is => 'ro', isa => 'Paws::Lambda::VpcConfig');

  use MooseX::ClassAttribute;

  class_has _api_call => (isa => 'Str', is => 'ro', default => 'CreateFunction');
  class_has _api_uri  => (isa => 'Str', is => 'ro', default => '/2015-03-31/functions');
  class_has _api_method  => (isa => 'Str', is => 'ro', default => 'POST');
  class_has _returns => (isa => 'Str', is => 'ro', default => 'Paws::Lambda::FunctionConfiguration');
  class_has _result_key => (isa => 'Str', is => 'ro');
1;

### main pod documentation begin ###

=head1 NAME

Paws::Lambda::CreateFunction - Arguments for method CreateFunction on Paws::Lambda

=head1 DESCRIPTION

This class represents the parameters used for calling the method CreateFunction on the
AWS Lambda service. Use the attributes of this class
as arguments to method CreateFunction.

You shouldn't make instances of this class. Each attribute should be used as a named argument in the call to CreateFunction.

As an example:

  $service_obj->CreateFunction(Att1 => $value1, Att2 => $value2, ...);

Values for attributes that are native types (Int, String, Float, etc) can passed as-is (scalar values). Values for complex Types (objects) can be passed as a HashRef. The keys and values of the hashref will be used to instance the underlying object.

=head1 ATTRIBUTES

=head2 B<REQUIRED> Code => L<Paws::Lambda::FunctionCode>

The code for the Lambda function.

=head2 DeadLetterConfig => L<Paws::Lambda::DeadLetterConfig>

The parent object that contains the target ARN (Amazon Resource Name)
of an Amazon SQS queue or Amazon SNS topic.

=head2 Description => Str

A short, user-defined function description. Lambda does not use this
value. Assign a meaningful description as you see fit.

=head2 Environment => L<Paws::Lambda::Environment>

=head2 B<REQUIRED> FunctionName => Str

The name you want to assign to the function you are uploading. The
function names appear in the console and are returned in the
ListFunctions API. Function names are used to specify functions to
other AWS Lambda API operations, such as Invoke. Note that the length
constraint applies only to the ARN. If you specify only the function
name, it is limited to 64 characters in length.

=head2 B<REQUIRED> Handler => Str

The function within your code that Lambda calls to begin execution. For
Node.js, it is the I<module-name>.I<export> value in your function. For
Java, it can be C<package.class-name::handler> or
C<package.class-name>. For more information, see Lambda Function
Handler (Java).

=head2 KMSKeyArn => Str

The Amazon Resource Name (ARN) of the KMS key used to encrypt your
function's environment variables. If not provided, AWS Lambda will use
a default service key.

=head2 MemorySize => Int

The amount of memory, in MB, your Lambda function is given. Lambda uses
this memory size to infer the amount of CPU and memory allocated to
your function. Your function use-case determines your CPU and memory
requirements. For example, a database operation might need less memory
compared to an image processing function. The default value is 128 MB.
The value must be a multiple of 64 MB.

=head2 Publish => Bool

This boolean parameter can be used to request AWS Lambda to create the
Lambda function and publish a version as an atomic operation.

=head2 B<REQUIRED> Role => Str

The Amazon Resource Name (ARN) of the IAM role that Lambda assumes when
it executes your function to access any other Amazon Web Services (AWS)
resources. For more information, see AWS Lambda: How it Works.

=head2 B<REQUIRED> Runtime => Str

The runtime environment for the Lambda function you are uploading.

To use the Python runtime v3.6, set the value to "python3.6". To use
the Python runtime v2.7, set the value to "python2.7". To use the
Node.js runtime v6.10, set the value to "nodejs6.10". To use the
Node.js runtime v4.3, set the value to "nodejs4.3".

Node v0.10.42 is currently marked as deprecated. You must migrate
existing functions to the newer Node.js runtime versions available on
AWS Lambda (nodejs4.3 or nodejs6.10) as soon as possible. You can
request a one-time extension until June 30, 2017 by going to the Lambda
console and following the instructions provided. Failure to do so will
result in an invalid parmaeter error being returned. Note that you will
have to follow this procedure for each region that contains functions
written in the Node v0.10.42 runtime.

Valid values are: C<"nodejs">, C<"nodejs4.3">, C<"nodejs6.10">, C<"java8">, C<"python2.7">, C<"python3.6">, C<"dotnetcore1.0">, C<"nodejs4.3-edge">

=head2 Tags => L<Paws::Lambda::Tags>

The list of tags (key-value pairs) assigned to the new function.

=head2 Timeout => Int

The function execution time at which Lambda should terminate the
function. Because the execution time has cost implications, we
recommend you set this value based on your expected execution time. The
default is 3 seconds.

=head2 TracingConfig => L<Paws::Lambda::TracingConfig>

The parent object that contains your function's tracing settings.

=head2 VpcConfig => L<Paws::Lambda::VpcConfig>

If your Lambda function accesses resources in a VPC, you provide this
parameter identifying the list of security group IDs and subnet IDs.
These must belong to the same VPC. You must provide at least one
security group and one subnet ID.

=head1 SEE ALSO

This class forms part of L<Paws>, documenting arguments for method CreateFunction in L<Paws::Lambda>

=head1 BUGS and CONTRIBUTIONS

The source code is located here: https://github.com/pplu/aws-sdk-perl

Please report bugs to: https://github.com/pplu/aws-sdk-perl/issues

=cut


text:
package org.deeplearning4j.nn.modelimport.keras.utils;

import lombok.extern.slf4j.Slf4j;
import org.deeplearning4j.nn.conf.layers.Layer;
import org.deeplearning4j.nn.modelimport.keras.KerasLayer;
import org.deeplearning4j.nn.modelimport.keras.config.KerasLayerConfiguration;
import org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.layers.KerasInput;
import org.deeplearning4j.nn.modelimport.keras.layers.advanced.activations.KerasLeakyReLU;
import org.deeplearning4j.nn.modelimport.keras.layers.convolutional.*;
import org.deeplearning4j.nn.modelimport.keras.layers.core.*;
import org.deeplearning4j.nn.modelimport.keras.layers.embeddings.KerasEmbedding;
import org.deeplearning4j.nn.modelimport.keras.layers.normalization.KerasBatchNormalization;
import org.deeplearning4j.nn.modelimport.keras.layers.pooling.KerasGlobalPooling;
import org.deeplearning4j.nn.modelimport.keras.layers.pooling.KerasPooling1D;
import org.deeplearning4j.nn.modelimport.keras.layers.pooling.KerasPooling2D;
import org.deeplearning4j.nn.modelimport.keras.layers.recurrent.KerasLstm;

import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * Utility functionality to import keras models
 *
 * @author Max Pumperla
 */
@Slf4j
public class KerasLayerUtils {

    /**
     * Checks whether layer config contains unsupported options.
     *
     * @param layerConfig           dictionary containing Keras layer configuration
     * @param enforceTrainingConfig
     * @throws UnsupportedKerasConfigurationException
     * @throws InvalidKerasConfigurationException
     */
    public static void checkForUnsupportedConfigurations(Map<String, Object> layerConfig, boolean enforceTrainingConfig,
                                                  KerasLayerConfiguration conf)
            throws UnsupportedKerasConfigurationException, InvalidKerasConfigurationException {
        getBiasL1RegularizationFromConfig(layerConfig, enforceTrainingConfig, conf);
        getBiasL2RegularizationFromConfig(layerConfig, enforceTrainingConfig, conf);
        Map<String, Object> innerConfig = KerasLayerUtils.getInnerLayerConfigFromConfig(layerConfig, conf);
        if (innerConfig.containsKey(conf.getLAYER_FIELD_W_REGULARIZER()))
            checkForUnknownRegularizer((Map<String, Object>) innerConfig.get(conf.getLAYER_FIELD_W_REGULARIZER()),
                    enforceTrainingConfig, conf);
        if (innerConfig.containsKey(conf.getLAYER_FIELD_B_REGULARIZER()))
            checkForUnknownRegularizer((Map<String, Object>) innerConfig.get(conf.getLAYER_FIELD_B_REGULARIZER()),
                    enforceTrainingConfig, conf);
    }

    /**
     * Get L1 bias regularization (if any) from Keras bias regularization configuration.
     *
     * @param layerConfig dictionary containing Keras layer configuration
     * @return L1 regularization strength (0.0 if none)
     */
    public static double getBiasL1RegularizationFromConfig(Map<String, Object> layerConfig, boolean willBeTrained,
                                                    KerasLayerConfiguration conf)
            throws UnsupportedKerasConfigurationException, InvalidKerasConfigurationException {
        Map<String, Object> innerConfig = KerasLayerUtils.getInnerLayerConfigFromConfig(layerConfig, conf);
        if (innerConfig.containsKey(conf.getLAYER_FIELD_B_REGULARIZER())) {
            Map<String, Object> regularizerConfig =
                    (Map<String, Object>) innerConfig.get(conf.getLAYER_FIELD_B_REGULARIZER());
            if (regularizerConfig != null && regularizerConfig.containsKey(conf.getREGULARIZATION_TYPE_L1()))
                throw new UnsupportedKerasConfigurationException("L1 regularization for bias parameter not supported");
        }
        return 0.0;
    }

    /**
     * Get L2 bias regularization (if any) from Keras bias regularization configuration.
     *
     * @param layerConfig dictionary containing Keras layer configuration
     * @return L1 regularization strength (0.0 if none)
     */
    private static double getBiasL2RegularizationFromConfig(Map<String, Object> layerConfig, boolean willBeTrained,
                                                     KerasLayerConfiguration conf)
            throws UnsupportedKerasConfigurationException, InvalidKerasConfigurationException {
        Map<String, Object> innerConfig = KerasLayerUtils.getInnerLayerConfigFromConfig(layerConfig, conf);
        if (innerConfig.containsKey(conf.getLAYER_FIELD_B_REGULARIZER())) {
            Map<String, Object> regularizerConfig =
                    (Map<String, Object>) innerConfig.get(conf.getLAYER_FIELD_B_REGULARIZER());
            if (regularizerConfig != null && regularizerConfig.containsKey(conf.getREGULARIZATION_TYPE_L2()))
                throw new UnsupportedKerasConfigurationException("L2 regularization for bias parameter not supported");
        }
        return 0.0;
    }

    /**
     * Check whether Keras weight regularization is of unknown type. Currently prints a warning
     * since main use case for model import is inference, not further training. Unlikely since
     * standard Keras weight regularizers are L1 and L2.
     *
     * @param regularizerConfig Map containing Keras weight reguarlization configuration
     * @return L1 regularization strength (0.0 if none)
     */
    private static void checkForUnknownRegularizer(Map<String, Object> regularizerConfig, boolean enforceTrainingConfig,
                                            KerasLayerConfiguration conf)
            throws UnsupportedKerasConfigurationException {
        if (regularizerConfig != null) {
            for (String field : regularizerConfig.keySet()) {
                if (!field.equals(conf.getREGULARIZATION_TYPE_L1()) && !field.equals(conf.getREGULARIZATION_TYPE_L2())
                        && !field.equals(conf.getLAYER_FIELD_NAME())) {
                    if (enforceTrainingConfig)
                        throw new UnsupportedKerasConfigurationException("Unknown regularization field " + field);
                    else
                        log.warn("Ignoring unknown regularization field " + field);
                }
            }
        }
    }

    /**
     * Build KerasLayer from a Keras layer configuration.
     *
     * @param layerConfig map containing Keras layer properties
     * @return KerasLayer
     * @see Layer
     */
    public static KerasLayer getKerasLayerFromConfig(Map<String, Object> layerConfig,
                                              KerasLayerConfiguration conf,
                                              Map<String, Class<? extends KerasLayer>> customLayers)
            throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
        return getKerasLayerFromConfig(layerConfig, false, conf, customLayers);
    }

    /**
     * Build KerasLayer from a Keras layer configuration. Building layer with
     * enforceTrainingConfig=true will throw exceptions for unsupported Keras
     * options related to training (e.g., unknown regularizers). Otherwise
     * we only generate warnings.
     *
     * @param layerConfig           map containing Keras layer properties
     * @param enforceTrainingConfig whether to enforce training-only configurations
     * @return KerasLayer
     * @see Layer
     */
    public static KerasLayer getKerasLayerFromConfig(Map<String, Object> layerConfig, boolean enforceTrainingConfig,
                                              KerasLayerConfiguration conf,
                                              Map<String, Class<? extends KerasLayer>> customLayers)
            throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
        String layerClassName = getClassNameFromConfig(layerConfig, conf);
        if (layerClassName.equals(conf.getLAYER_CLASS_NAME_TIME_DISTRIBUTED())) {
            layerConfig = getTimeDistributedLayerConfig(layerConfig, conf);
            layerClassName = getClassNameFromConfig(layerConfig, conf);
        }

        KerasLayer layer;
        if (layerClassName.equals(conf.getLAYER_CLASS_NAME_ACTIVATION())) {
            layer = new KerasActivation(layerConfig, enforceTrainingConfig);
        } else if (layerClassName.equals(conf.getLAYER_CLASS_NAME_LEAKY_RELU())) {
            layer = new KerasLeakyReLU(layerConfig, enforceTrainingConfig);
        } else if (layerClassName.equals(conf.getLAYER_CLASS_NAME_DROPOUT())) {
            layer = new KerasDropout(layerConfig, enforceTrainingConfig);
        } else if (layerClassName.equals(conf.getLAYER_CLASS_NAME_DENSE()) ||
                layerClassName.equals(conf.getLAYER_CLASS_NAME_TIME_DISTRIBUTED_DENSE())) {
            layer = new KerasDense(layerConfig, enforceTrainingConfig);
        } else if (layerClassName.equals(conf.getLAYER_CLASS_NAME_LSTM())) {
            layer = new KerasLstm(layerConfig, enforceTrainingConfig);
        } else if (layerClassName.equals(conf.getLAYER_CLASS_NAME_CONVOLUTION_2D())) {
            layer = new KerasConvolution2D(layerConfig, enforceTrainingConfig);
        } else if (layerClassName.equals(conf.getLAYER_CLASS_NAME_CONVOLUTION_1D())) {
            layer = new KerasConvolution1D(layerConfig, enforceTrainingConfig);
        } else if (layerClassName.equals(conf.getLAYER_CLASS_NAME_ATROUS_CONVOLUTION_2D())) {
            layer = new KerasAtrousConvolution2D(layerConfig, enforceTrainingConfig);
        } else if (layerClassName.equals(conf.getLAYER_CLASS_NAME_ATROUS_CONVOLUTION_1D())) {
            layer = new KerasAtrousConvolution1D(layerConfig, enforceTrainingConfig);
        } else if (layerClassName.equals(conf.getLAYER_CLASS_NAME_MAX_POOLING_2D()) ||
                layerClassName.equals(conf.getLAYER_CLASS_NAME_AVERAGE_POOLING_2D())) {
            layer = new KerasPooling2D(layerConfig, enforceTrainingConfig);
        }  else if (layerClassName.equals(conf.getLAYER_CLASS_NAME_MAX_POOLING_1D()) ||
                layerClassName.equals(conf.getLAYER_CLASS_NAME_AVERAGE_POOLING_1D())) {
            layer = new KerasPooling1D(layerConfig, enforceTrainingConfig);
        }else if (layerClassName.equals(conf.getLAYER_CLASS_NAME_GLOBAL_AVERAGE_POOLING_1D()) ||
                layerClassName.equals(conf.getLAYER_CLASS_NAME_GLOBAL_AVERAGE_POOLING_2D()) ||
                layerClassName.equals(conf.getLAYER_CLASS_NAME_GLOBAL_MAX_POOLING_1D()) ||
                layerClassName.equals(conf.getLAYER_CLASS_NAME_GLOBAL_MAX_POOLING_2D())) {
            layer = new KerasGlobalPooling(layerConfig, enforceTrainingConfig);
        } else if (layerClassName.equals(conf.getLAYER_CLASS_NAME_BATCHNORMALIZATION())) {
            layer = new KerasBatchNormalization(layerConfig, enforceTrainingConfig);
        } else if (layerClassName.equals(conf.getLAYER_CLASS_NAME_EMBEDDING())) {
            layer = new KerasEmbedding(layerConfig, enforceTrainingConfig);
        } else if (layerClassName.equals(conf.getLAYER_CLASS_NAME_INPUT())) {
            layer = new KerasInput(layerConfig, enforceTrainingConfig);
        } else if (layerClassName.equals(conf.getLAYER_CLASS_NAME_MERGE())) {
            layer = new KerasMerge(layerConfig, enforceTrainingConfig);
        } else if (layerClassName.equals(conf.getLAYER_CLASS_NAME_FLATTEN())) {
            layer = new KerasFlatten(layerConfig, enforceTrainingConfig);
        } else if (layerClassName.equals(conf.getLAYER_CLASS_NAME_RESHAPE())) {
            layer = new KerasReshape(layerConfig, enforceTrainingConfig);
        } else if (layerClassName.equals(conf.getLAYER_CLASS_NAME_ZERO_PADDING_2D())) {
            layer = new KerasZeroPadding2D(layerConfig, enforceTrainingConfig);
        } else if (layerClassName.equals(conf.getLAYER_CLASS_NAME_UPSAMPLING_2D())) {
            layer = new KerasUpsampling2D(layerConfig, enforceTrainingConfig);
        } else {
            // check if user registered a custom config
            Class<? extends KerasLayer> customConfig = customLayers.get(layerClassName);

            if (customConfig == null)
                throw new UnsupportedKerasConfigurationException("Unsupported keras layer type " + layerClassName);
            try {
                Constructor constructor = customConfig.getConstructor(Map.class);
                layer = (KerasLayer) constructor.newInstance(layerConfig);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
        return layer;
    }

    /**
     * Get Keras layer class name from Keras layer configuration.
     *
     * @param layerConfig dictionary containing Keras layer configuration
     * @return
     * @throws InvalidKerasConfigurationException
     */
    public static String getClassNameFromConfig(Map<String, Object> layerConfig, KerasLayerConfiguration conf)
            throws InvalidKerasConfigurationException {
        if (!layerConfig.containsKey(conf.getLAYER_FIELD_CLASS_NAME()))
            throw new InvalidKerasConfigurationException(
                    "Field " + conf.getLAYER_FIELD_CLASS_NAME() + " missing from layer config");
        return (String) layerConfig.get(conf.getLAYER_FIELD_CLASS_NAME());
    }

    /**
     * Extract inner layer config from TimeDistributed configuration and merge
     * it into the outer config.
     *
     * @param layerConfig dictionary containing Keras TimeDistributed configuration
     * @return
     * @throws InvalidKerasConfigurationException
     */
    public static Map<String, Object> getTimeDistributedLayerConfig(Map<String, Object> layerConfig,
                                                             KerasLayerConfiguration conf)
            throws InvalidKerasConfigurationException {
        if (!layerConfig.containsKey(conf.getLAYER_FIELD_CLASS_NAME()))
            throw new InvalidKerasConfigurationException(
                    "Field " + conf.getLAYER_FIELD_CLASS_NAME() + " missing from layer config");
        if (!layerConfig.get(conf.getLAYER_FIELD_CLASS_NAME()).equals(conf.getLAYER_CLASS_NAME_TIME_DISTRIBUTED()))
            throw new InvalidKerasConfigurationException("Expected " + conf.getLAYER_CLASS_NAME_TIME_DISTRIBUTED()
                    + " layer, found " + (String) layerConfig.get(conf.getLAYER_FIELD_CLASS_NAME()));
        if (!layerConfig.containsKey(conf.getLAYER_FIELD_CONFIG()))
            throw new InvalidKerasConfigurationException("Field "
                    + conf.getLAYER_FIELD_CONFIG() + " missing from layer config");
        Map<String, Object> outerConfig = getInnerLayerConfigFromConfig(layerConfig, conf);
        Map<String, Object> innerLayer = (Map<String, Object>) outerConfig.get(conf.getLAYER_FIELD_LAYER());
        layerConfig.put(conf.getLAYER_FIELD_CLASS_NAME(), innerLayer.get(conf.getLAYER_FIELD_CLASS_NAME()));
        layerConfig.put(conf.getLAYER_FIELD_NAME(), innerLayer.get(conf.getLAYER_FIELD_CLASS_NAME()));
        Map<String, Object> innerConfig = (Map<String, Object>) getInnerLayerConfigFromConfig(innerLayer, conf);
        outerConfig.putAll(innerConfig);
        outerConfig.remove(conf.getLAYER_FIELD_LAYER());
        return layerConfig;
    }

    /**
     * Get inner layer config from Keras layer configuration.
     *
     * @param layerConfig dictionary containing Keras layer configuration
     * @return
     * @throws InvalidKerasConfigurationException
     */
    public static Map<String, Object> getInnerLayerConfigFromConfig(Map<String, Object> layerConfig, KerasLayerConfiguration conf)
            throws InvalidKerasConfigurationException {
        if (!layerConfig.containsKey(conf.getLAYER_FIELD_CONFIG()))
            throw new InvalidKerasConfigurationException("Field "
                    + conf.getLAYER_FIELD_CONFIG() + " missing from layer config");
        return (Map<String, Object>) layerConfig.get(conf.getLAYER_FIELD_CONFIG());
    }

    /**
     * Get layer name from Keras layer configuration.
     *
     * @param layerConfig dictionary containing Keras layer configuration
     * @return
     * @throws InvalidKerasConfigurationException
     */
    public static String getLayerNameFromConfig(Map<String, Object> layerConfig,
                                                KerasLayerConfiguration conf)
            throws InvalidKerasConfigurationException {
        Map<String, Object> innerConfig = KerasLayerUtils.getInnerLayerConfigFromConfig(layerConfig, conf);
        if (!innerConfig.containsKey(conf.getLAYER_FIELD_NAME()))
            throw new InvalidKerasConfigurationException("Field " + conf.getLAYER_FIELD_NAME()
                    + " missing from layer config");
        return (String) innerConfig.get(conf.getLAYER_FIELD_NAME());
    }

    /**
     * Get Keras input shape from Keras layer configuration.
     *
     * @param layerConfig dictionary containing Keras layer configuration
     * @return input shape array
     */
    public static int[] getInputShapeFromConfig(Map<String, Object> layerConfig,
                                                KerasLayerConfiguration conf)
            throws InvalidKerasConfigurationException {
        Map<String, Object> innerConfig = KerasLayerUtils.getInnerLayerConfigFromConfig(layerConfig, conf);
        if (!innerConfig.containsKey(conf.getLAYER_FIELD_BATCH_INPUT_SHAPE()))
            return null;
        List<Integer> batchInputShape = (List<Integer>) innerConfig.get(conf.getLAYER_FIELD_BATCH_INPUT_SHAPE());
        int[] inputShape = new int[batchInputShape.size() - 1];
        for (int i = 1; i < batchInputShape.size(); i++) {
            inputShape[i - 1] = batchInputShape.get(i) != null ? batchInputShape.get(i) : 0;
        }
        return inputShape;
    }

    /**
     * Get Keras (backend) dimension order from Keras layer configuration.
     *
     * @param layerConfig dictionary containing Keras layer configuration
     * @return Dimension order
     */
    public static KerasLayer.DimOrder getDimOrderFromConfig(Map<String, Object> layerConfig,
                                                      KerasLayerConfiguration conf)
            throws InvalidKerasConfigurationException {
        Map<String, Object> innerConfig = KerasLayerUtils.getInnerLayerConfigFromConfig(layerConfig, conf);
        KerasLayer.DimOrder dimOrder = KerasLayer.DimOrder.NONE;
        if (innerConfig.containsKey(conf.getLAYER_FIELD_DIM_ORDERING())) {
            String dimOrderStr = (String) innerConfig.get(conf.getLAYER_FIELD_DIM_ORDERING());
            if (dimOrderStr.equals(conf.getDIM_ORDERING_TENSORFLOW())) {
                dimOrder = KerasLayer.DimOrder.TENSORFLOW;
            } else if (dimOrderStr.equals(conf.getDIM_ORDERING_THEANO())) {
                dimOrder = KerasLayer.DimOrder.THEANO;
            } else {
                log.warn("Keras layer has unknown Keras dimension order: " + dimOrder);
            }
        }
        return dimOrder;
    }

    /**
     * Get list of inbound layers from Keras layer configuration.
     *
     * @param layerConfig dictionary containing Keras layer configuration
     * @return List of inbound layer names
     */
    public static List<String> getInboundLayerNamesFromConfig(Map<String, Object> layerConfig, KerasLayerConfiguration conf) {
        List<String> inboundLayerNames = new ArrayList<>();
        if (layerConfig.containsKey(conf.getLAYER_FIELD_INBOUND_NODES())) {
            List<Object> inboundNodes = (List<Object>) layerConfig.get(conf.getLAYER_FIELD_INBOUND_NODES());
            if (inboundNodes.size() > 0) {
                inboundNodes = (List<Object>) inboundNodes.get(0);
                for (Object o : inboundNodes) {
                    String nodeName = (String) ((List<Object>) o).get(0);
                    inboundLayerNames.add(nodeName);
                }
            }
        }
        return inboundLayerNames;
    }

    /**
     * Get number of outputs from Keras layer configuration.
     *
     * @param layerConfig dictionary containing Keras layer configuration
     * @return
     * @throws InvalidKerasConfigurationException
     */
    public static int getNOutFromConfig(Map<String, Object> layerConfig,
                                 KerasLayerConfiguration conf) throws InvalidKerasConfigurationException {
        Map<String, Object> innerConfig = KerasLayerUtils.getInnerLayerConfigFromConfig(layerConfig, conf);
        int nOut;
        if (innerConfig.containsKey(conf.getLAYER_FIELD_OUTPUT_DIM()))
            /* Most feedforward layers: Dense, RNN, etc. */
            nOut = (int) innerConfig.get(conf.getLAYER_FIELD_OUTPUT_DIM());
        else if (innerConfig.containsKey(conf.getLAYER_FIELD_EMBEDDING_OUTPUT_DIM()))
            /* Embedding layers. */
            nOut = (int) innerConfig.get(conf.getLAYER_FIELD_EMBEDDING_OUTPUT_DIM());
        else if (innerConfig.containsKey(conf.getLAYER_FIELD_NB_FILTER()))
            /* Convolutional layers. */
            nOut = (int) innerConfig.get(conf.getLAYER_FIELD_NB_FILTER());
        else
            throw new InvalidKerasConfigurationException("Could not determine number of outputs for layer: no "
                    + conf.getLAYER_FIELD_OUTPUT_DIM() + " or " + conf.getLAYER_FIELD_NB_FILTER() + " field found");
        return nOut;
    }

    /**
     * Get dropout from Keras layer configuration.
     *
     * @param layerConfig dictionary containing Keras layer configuration
     * @return
     * @throws InvalidKerasConfigurationException
     */
    public static double getDropoutFromConfig(Map<String, Object> layerConfig,
                                          KerasLayerConfiguration conf) throws InvalidKerasConfigurationException {
        Map<String, Object> innerConfig = KerasLayerUtils.getInnerLayerConfigFromConfig(layerConfig, conf);
        /* NOTE: Keras "dropout" parameter determines dropout probability,
         * while DL4J "dropout" parameter determines retention probability.
         */
        double dropout = 1.0;
        if (innerConfig.containsKey(conf.getLAYER_FIELD_DROPOUT())) {
            /* For most feedforward layers. */
            dropout = 1.0 - (double) innerConfig.get(conf.getLAYER_FIELD_DROPOUT());
        } else if (innerConfig.containsKey(conf.getLAYER_FIELD_DROPOUT_W())) {
            /* For LSTMs. */
            dropout = 1.0 - (double) innerConfig.get(conf.getLAYER_FIELD_DROPOUT_W());
        }
        return dropout;
    }

    /**
     * Determine if layer should be instantiated with bias
     *
     * @param layerConfig dictionary containing Keras layer configuration
     * @return
     * @throws InvalidKerasConfigurationException
     */
    public static boolean getHasBiasFromConfig(Map<String, Object> layerConfig,
                                                  KerasLayerConfiguration conf)
            throws InvalidKerasConfigurationException {
        Map<String, Object> innerConfig = KerasLayerUtils.getInnerLayerConfigFromConfig(layerConfig, conf);
        boolean hasBias = true;
        if (innerConfig.containsKey(conf.getLAYER_FIELD_USE_BIAS())){
            hasBias = (boolean) innerConfig.get(conf.getLAYER_FIELD_USE_BIAS());
        }
        return hasBias;
    }

    /**
     * Get zero masking flag
     *
     * @param layerConfig dictionary containing Keras layer configuration
     * @return if masking to zeros or not
     * @throws InvalidKerasConfigurationException Invalid Keras configuration
     */
    public static boolean getZeroMaskingFromConfig(Map<String, Object> layerConfig,
                                                   KerasLayerConfiguration conf)
            throws InvalidKerasConfigurationException {
        Map<String, Object> innerConfig = KerasLayerUtils.getInnerLayerConfigFromConfig(layerConfig, conf);
        boolean hasZeroMasking = true;
        if (innerConfig.containsKey(conf.getLAYER_FIELD_MASK_ZERO())) {
            hasZeroMasking = (boolean) innerConfig.get(conf.getLAYER_FIELD_MASK_ZERO());
        }
        return hasZeroMasking;
    }

}