text:
var TIERS = [];

$(document).ready(function() {
    //js code to hide form options
    //@todo: can change to a jquery plugin and move to base js
    $('.more-options').click(function(){
        var id = $(this).attr('ref');
        var div = $('#'+id);
        div.toggle('fast');
        console.log(div.css('display'));
        if(div.css('display') == 'none'){
        }
        else{
        }
        // return false to prevent page going up
        return false;
    });

    $("select[name='editTier']").change(function() {
        // multipleValues will be an array
        var multipleValues = $(this).val() || [];
        var countLength = $('#tiersCollection').length;
        if (countLength == 0) {

            $('<input>').attr('type', 'hidden')
                    .attr('name', 'tiersCollection')
                    .attr('id', 'tiersCollection')
                    .attr('value', multipleValues)
                    .appendTo('#editAPIForm');
        } else {
            $('#tiersCollection').attr('value', multipleValues);

        }

    });

    $('.default_version_check').change(function(){
        if($(this).is(":checked")){
            $(default_version_checked).val($(this).val());
        }else{
            $(default_version_checked).val("");
        }
    });

    $('.transports_check_http').change(function(){
        if($(this).is(":checked")){
            $(http_checked).val($(this).val());
        }else{
            $(http_checked).val("");
        }
    });

    $('.transports_check_https').change(function(){
            if($(this).is(":checked")){
                $(https_checked).val($(this).val());
            }else{
                $(https_checked).val("");
            }
        });

    $('.storeCheck').change(function () {
        var checkedStores = $('#externalAPIStores').val();
        if (checkedStores == "REMOVEALL") {
            checkedStores = "";
        }
        if ($(this).is(":checked")) {
            $('#externalAPIStores').val(checkedStores + "::" + $(this).val());
        } else {
            var storeValsWithoutUnchecked = "";
            var checkStoresArray = checkedStores.split("::");
            for (var k = 0; k < checkStoresArray.length; k++) {
                if (!(checkStoresArray[k] == $(this).val())) {
                    storeValsWithoutUnchecked += checkStoresArray[k] + "::";
                }
            }
            if (storeValsWithoutUnchecked == "") {
                storeValsWithoutUnchecked = "REMOVEALL";
            }
            $('#externalAPIStores').val(storeValsWithoutUnchecked);
        }
    });

    $("#clearThumb").on("click", function () {
        $('#apiThumb-container').html('<input type="file" class="input-xlarge" name="apiThumb" />');
    });

    enableDisableButtons();
    $('#context').change(function() {
        getContextValue();
    });
    $('#uriTemplate').click(function() {
        $('#resourceTableError').hide('fast');
    });

            createHiddenForm();
    $('#resourceTable tr.resourceRow').each(function(){
        $('input',this).unbind('change');
        $('input:checkbox',this).change(function(){
            createHiddenForm();
            validateResourceTable();
        });

        $('input:text',this).change(function(){
            createHiddenForm();
            validateResourceTable();
        });

        $('select',this).change(function(){
            createHiddenForm();
            validateResourceTable();
        });
    });

    loadInSequences();
    loadOutSequences();
    loadFaultSequences();

    $('.js_hidden_section_title').click(function(){
           var $next = $(this).next();
           var $i = $('i',this);
           if($next.is(":visible")){
               $next.hide();
               $i.removeClass('icon-chevron-down');
               $i.addClass('icon-chevron-right');
           }else{
               $next.show();
               $i.removeClass('icon-chevron-right');
               $i.addClass('icon-chevron-down');
           }
       });
});

function loadTiers() {
    var target = document.getElementById("editTier");
    jagg.post("/site/blocks/item-add/ajax/add.jag", { action:"getTiers" },
        function (result) {
            if (!result.error) {
                var arr = [];
                var row = '#resourceRow';
                for (var i = 0; i < result.tiers.length; i++) {
                    // arr.push(result.tiers[i].tierName);
                    var k = result.tiers.length - i -1;
                    $('.getThrottlingTier',row).append($('<option value="'+result.tiers[k].tierName+'" title="'+result.tiers[k].tierDescription+'">'+result.tiers[k].tierDisplayName+'</option>'));
                    $('.putThrottlingTier',row).append($('<option value="'+result.tiers[k].tierName+'" title="'+result.tiers[k].tierDescription+'">'+result.tiers[k].tierDisplayName+'</option>'));
                    $('.postThrottlingTier',row).append($('<option value="'+result.tiers[k].tierName+'" title="'+result.tiers[k].tierDescription+'">'+result.tiers[k].tierDisplayName+'</option>'));
                    $('.deleteThrottlingTier',row).append($('<option value="'+result.tiers[k].tierName+'" title="'+result.tiers[k].tierDescription+'">'+result.tiers[k].tierDisplayName+'</option>'));
                    $('.optionsThrottlingTier',row).append($('<option value="'+result.tiers[k].tierName+'" title="'+result.tiers[k].tierDescription+'">'+result.tiers[k].tierDisplayName+'</option>'));
                }

                TIERS = result.tiers;
                $("#resource_view").trigger("draw");

                for (var i = 0; i < result.tiers.length; i++) {
                    arr.push(result.tiers[i].tierName);
                }

                for (var j = 0; j < arr.length; j++) {
                    option = new Option(arr[j], arr[j]);
                    target.options[j] = option;
                    target.options[j].text = result.tiers[j].tierDisplayName;
                    target.options[j].title = result.tiers[j].tierDescription;
                }
                addSelectedTiers(target);

            }
            $('#saveMessage').hide(); $('#saveButtons').show();

        }, "json");
}

var addResourcesToApi = function () {
    $('#resourceRow').clone().addClass('resourceRow').insertAfter($('#resourceRow')).show();
    enableDisableButtons();
    $('#resourceTable tr.resourceRow').each(function(){
        $('input',this).unbind('change');
        $('input:checkbox',this).change(function(){
            createHiddenForm();
            validateResourceTable();
        });

        $('input:text',this).change(function(){
            createHiddenForm();
            validateResourceTable();
        });

        $('select',this).change(function(){
            createHiddenForm();
            validateResourceTable();
        });
    });
};
var enableDisableButtons = function(){
   $('#resourceTable tr').each(function(index){
        var allRows = $('#resourceTable tr');
        if(index > 0){
            if(index == 2){
                    $('.upButton',this).attr('disabled','disabled');
                    $('.downButton',this).removeAttr('disabled');
            }
            if(index > 2 && allRows.length-1 > index){
                    $('.downButton',this).removeAttr('disabled');
                    $('.upButton',this).removeAttr('disabled');
            }
            if(allRows.length-1 == index){
                $('.deleteButton',this).removeAttr('disabled','disabled');
                if(index != 2){
                    $('.upButton',this).removeAttr('disabled');
                }else {
                    $('.upButton',this).attr('disabled','disabled');
                    $('.deleteButton',this).attr('disabled','disabled');
                }
                $('.downButton',this).attr('disabled','disabled');
            }
        }
    });
};
var moveMe = function(moveButton){
    var action = "move-up";
    if($(moveButton).hasClass('downButton')){
        action = "move-down";
    }

    if(action == "move-up"){
        $(moveButton).parent().parent().insertBefore($(moveButton).parent().parent().prev());
    }
    if(action == "move-down"){
        $(moveButton).parent().parent().insertAfter($(moveButton).parent().parent().next());
    }

    enableDisableButtons();
    createHiddenForm();
    validateResourceTable();
};
var createHiddenForm = function(){
    $('#hiddenFormElements input').remove();

    $('#resourceTable tr').each(function(index){
        var resourcesCount = index - 2;
        var resourceMethodValues = "";
        var resourceMethodAuthValues = "";
        var resourceThrottlingTierValues = "";
        var tr = this;
        //read the checkbox values

        if($('.resource-get',tr).is(':checked')){
            if(resourceMethodValues == ""){resourceMethodValues += "GET"}else{resourceMethodValues += ",GET"}
            var selectedValue = $('.getAuthType',tr).val();
            if(resourceMethodAuthValues == ""){resourceMethodAuthValues += selectedValue }else{resourceMethodAuthValues += ","+selectedValue}

            var selectedValueThrottling = $('.getThrottlingTier',tr).val();
            if(resourceThrottlingTierValues == ""){resourceThrottlingTierValues += selectedValueThrottling }else{resourceThrottlingTierValues += ","+selectedValueThrottling}

        }
        if($('.resource-put',tr).is(':checked')){
            if(resourceMethodValues == ""){resourceMethodValues += "PUT"}else{resourceMethodValues += ",PUT"}
            var selectedValue = $('.putAuthType',tr).val();
            if(resourceMethodAuthValues == ""){resourceMethodAuthValues += selectedValue }else{resourceMethodAuthValues += ","+selectedValue}

            var selectedValueThrottling = $('.putThrottlingTier',tr).val();
            console.log(selectedValueThrottling);
            if(resourceThrottlingTierValues == ""){resourceThrottlingTierValues += selectedValueThrottling }else{resourceThrottlingTierValues += ","+selectedValueThrottling}

        }
        if($('.resource-post',tr).is(':checked')){
            if(resourceMethodValues == ""){resourceMethodValues += "POST"}else{resourceMethodValues += ",POST"}
            var selectedValue = $('.postAuthType',tr).val();
            if(resourceMethodAuthValues == ""){resourceMethodAuthValues += selectedValue }else{resourceMethodAuthValues += ","+selectedValue }

            var selectedValueThrottling = $('.postThrottlingTier',tr).val();
            console.log(selectedValueThrottling);
            if(resourceThrottlingTierValues == ""){resourceThrottlingTierValues += selectedValueThrottling }else{resourceThrottlingTierValues += ","+selectedValueThrottling}

        }
        if($('.resource-delete',tr).is(':checked')){
            if(resourceMethodValues == ""){resourceMethodValues += "DELETE"}else{resourceMethodValues += ",DELETE"}
            var selectedValue = $('.deleteAuthType',tr).val();
            if(resourceMethodAuthValues == ""){resourceMethodAuthValues += selectedValue }else{resourceMethodAuthValues += ","+selectedValue}

            var selectedValueThrottling = $('.deleteThrottlingTier',tr).val();
            console.log(selectedValueThrottling);
            if(resourceThrottlingTierValues == ""){resourceThrottlingTierValues += selectedValueThrottling }else{resourceThrottlingTierValues += ","+selectedValueThrottling}

        }
        if($('.resource-patch',tr).is(':checked')){
            if(resourceMethodValues == ""){resourceMethodValues += "PATCH"}else{resourceMethodValues += ",PATCH"}
            var selectedValue = $('.patchAuthType',tr).val();
            if(resourceMethodAuthValues == ""){resourceMethodAuthValues += selectedValue }else{resourceMethodAuthValues += ","+selectedValue}

            var selectedValueThrottling = $('.patchThrottlingTier',tr).val();
            console.log(selectedValueThrottling);
            if(resourceThrottlingTierValues == ""){resourceThrottlingTierValues += selectedValueThrottling }else{resourceThrottlingTierValues += ","+selectedValueThrottling}

        }
        if($('.resource-options',tr).is(':checked')){
            if(resourceMethodValues == ""){resourceMethodValues += "OPTIONS"}else{resourceMethodValues += ",OPTIONS"}
            var selectedValue = $('.optionsAuthType',tr).val();
            if(resourceMethodAuthValues == ""){resourceMethodAuthValues += selectedValue }else{resourceMethodAuthValues += ","+selectedValue}

            var selectedValueThrottling = $('.optionsThrottlingTier',tr).val();
            console.log(selectedValueThrottling);
            if(resourceThrottlingTierValues == ""){resourceThrottlingTierValues += selectedValueThrottling }else{resourceThrottlingTierValues += ","+selectedValueThrottling}

        }

        if(resourcesCount >= 0){
            $('<input>').attr('type', 'hidden')
                .attr('name', 'uriTemplate-' + resourcesCount).attr('id', 'uriTemplate-' + resourcesCount).attr('value', $('.resourceTemplate',tr).val())
                .appendTo('#hiddenFormElements');

            $('<input>').attr('type', 'hidden')
                .attr('name', 'resourceMethod-' + resourcesCount).attr('id', 'resourceMethod-' + resourcesCount).attr('value', resourceMethodValues)
                .appendTo('#hiddenFormElements');

            $('<input>').attr('type', 'hidden')
                .attr('name', 'resourceMethodAuthType-' + resourcesCount).attr('id', 'resourceMethodAuthType-' + resourcesCount).attr('value', resourceMethodAuthValues)
                .appendTo('#hiddenFormElements');

            $('<input>').attr('type', 'hidden')
                .attr('name', 'resourceMethodThrottlingTier-' + resourcesCount).attr('id', 'resourceMethodThrottlingTier-' + resourcesCount).attr('value', resourceThrottlingTierValues)
                .appendTo('#hiddenFormElements');

        }
    });
    $('#resourceCount').val($('#resourceTable tr').length-2);
};
var deleteResource = function (deleteButton) {
    var count=$('#resourceTable tr').length;
    //Check whether only one defined resource remains before delete operation
    if(count==3){
        $('#resourceTableError').show('fast');
        $('#resourceTableError').html( i18n.t('errorMsgs.apiResource')+'
');
        return;
    }
    $('#resourceTableError').hide('fast');
    $(deleteButton).parent().parent().remove();

    enableDisableButtons();
    createHiddenForm();
};

var validateResourceTable = function(){
    var errors = "";

    $('.resourceRow input.resourceTemplate').each(function(){
        var myVal = $(this).val();
        var foundMyVal = 0;
        $('.resourceRow input.resourceTemplate').each(function(){
            if($(this).val()==myVal){
                foundMyVal++;
            }
        });
        if(foundMyVal > 1){
            errors +=  i18n.t('errorMsgs.uniqueUrlPattern')+"" + myVal + ""+ i18n.t('errorMsgs.duplicateUrlPattern') +"
";
        }
        if(myVal == ""){
            errors += i18n.t('errorMsgs.emptyUrlPattern')+"
";
        }
    });

    var allRowsHas_at_least_one_check = true;
    $('.resourceRow').each(function(){
        var tr = this;
        var noneChecked = true;
        $('input:checkbox',tr).each(function(){
            if($(this).is(":checked")){
                noneChecked = false;
            }
        });

        if(noneChecked){
            allRowsHas_at_least_one_check = false;
        }
    });

    if(!allRowsHas_at_least_one_check){
        errors += i18n.t('errorMsgs.emptyVerb')+"
";
    }
    if(errors != ""){
        $('#resourceTableError').show('fast');
        $('#resourceTableError').html(errors);
        $('#updateButton').attr('disabled','disabled');
    }else{
        $('#resourceTableError').hide('fast');
        $('#updateButton').removeAttr('disabled');
    }
    return errors;
};

function getContextValue() {
    var context = $('#context').val();
    var version = $('#apiVersion').val();

    if (context == "" && version != "") {
        $('#contextForUrl').html("/{context}/" + version);
        $('#contextForUrlDefault').html("/{context}/" + version);
    }
    if (context != "" && version == "") {
        if (context.charAt(0) != "/") {
            context = "/" + context;
        }
        $('#contextForUrl').html(context + "/{version}");
        $('#contextForUrlDefault').html(context + "/{version}");
    }
    if (context != "" && version != "") {
        if (context.charAt(0) != "/") {
            context = "/" + context;
        }
        $('.contextForUrl').html(context + "/" + version);
    }
}
function showHideRoles(){
    var visibility = $('#visibility').find(":selected").val();
    if (visibility == "public" || visibility == "private"){
		$('#rolesDiv').hide();
	} else{
		$('#rolesDiv').show();
	}
}

function showHideTenants(){
    var subscription = $('#subscriptions').find(":selected").val();

    if (subscription == "current_tenant" || subscription == "all_tenants"){
        $('#tenantsDiv').hide();
    } else{
        $('#tenantsDiv').show();
    }
}

function showUTProductionURL(){
	var endpointType = $('#endpointType').find(":selected").val();
    if (endpointType == "secured") {
        var endpointAuthType = $('#endpointAuthType').find(":selected").val();
        $('#endpointAuthType').show();
        $('#credentials').show();
    } else {
        $('#endpointAuthType').hide();
        $('#credentials').hide();
    }

}

function showCacheTimeout(){
    var cache = $('#responseCache').find(":selected").val();
    if(cache == "enabled"){
        $('#cacheTimeout').show();
    }
    else{
        $('#cacheTimeout').hide();
    }

}

function toggleSequence(checkbox){
	if($(checkbox).is(":checked")){
		$(checkbox).parent().next().show();
		loadInSequences();
		loadOutSequences();
		loadFaultSequences();
	}else{
		$(checkbox).parent().next().hide();
	}

}

function loadInSequences() {

    if(inSequencesLoaded){
        return;
    }

	jagg.post("/site/blocks/item-add/ajax/add.jag", {
		action : "getCustomInSequences"
	},
 	function(result) {
		if (!result.error) {
			var arr = [];
			if (result.sequences.length == 0) {
				var msg = "No defined sequences";
				$('<input>').
				attr('type', 'hidden').
				attr('name', 'inSeq').
				attr('id', 'inSeq').
				attr('value', msg).
				appendTo('#addAPIForm');
			} else {
				for ( var j = 0; j < result.sequences.length; j++) {
					arr.push(result.sequences[j]);
				}
				for ( var i = 0; i < arr.length; i++) {
				    if(result.sequences[i] == insequence){
                        $('#inSequence').append('<option value="'+result.sequences[i]+'" selected="selected">'+result.sequences[i]+'</option>');
				    }else{
				        $('#inSequence').append('<option value="'+result.sequences[i]+'">'+result.sequences[i]+'</option>');
				    }
					$('<input>').
					attr('type', 'hidden').
					attr('name', 'inSeq').
					attr('id', 'inSeq').
					attr('value', result.sequences[i]).
					appendTo('#addAPIForm');

				}
			}
			inSequencesLoaded = true;
		}
	}, "json");
}

function loadOutSequences() {

	if(outSequencesLoaded){
	    return;
	}

	jagg.post("/site/blocks/item-add/ajax/add.jag", {
		action : "getCustomOutSequences"
	},
			function(result) {
				if (!result.error) {
					var arr = [];
					if (result.sequences.length == 0) {
						var msg = "No defined sequences";
						$('<input>').
						attr('type', 'hidden').
						attr('name', 'outSeq').
						attr('id', 'outSeq').
						attr('value', msg).
						appendTo('#addAPIForm');
					}else {
						for ( var j = 0; j < result.sequences.length; j++) {
							arr.push(result.sequences[j]);
						}
						for(var i=0; i<arr.length; i++){
                            if(result.sequences[i] == outsequence){
                                $('#outSequence').append('<option value="'+result.sequences[i]+'" selected="selected">'+result.sequences[i]+'</option>');
                            }
                            else{
                                $('#outSequence').append('<option value="'+result.sequences[i]+'">'+result.sequences[i]+'</option>');
                            }
							$('<input>').
							attr('type', 'hidden').
							attr('name', 'outSeq').
							attr('id', 'outSeq').
							attr('value', result.sequences[i]).
							appendTo('#addAPIForm');

						}
					}
					outSequencesLoaded = true;
				}
			}, "json");
}

function loadFaultSequences() {

	if(faultSequencesLoaded){
	    return;
	}

	jagg.post("/site/blocks/item-add/ajax/add.jag", {
		action : "getCustomFaultSequences"
	},
			function(result) {
				if (!result.error) {
					var arr = [];
					if (result.sequences.length == 0) {
						var msg = "No defined sequences";
						$('<input>').
						attr('type', 'hidden').
						attr('name', 'faultSeq').
						attr('id', 'faultSeq').
						attr('value', msg).
						appendTo('#addAPIForm');
					}else {
						for ( var j = 0; j < result.sequences.length; j++) {
							arr.push(result.sequences[j]);
						}
						for(var i=0; i<arr.length; i++){
                            if(result.sequences[i] == faultsequence){
                                $('#faultSequence').append('<option value="'+result.sequences[i]+'" selected="selected">'+result.sequences[i]+'</option>');
                            }
                            else{
                                $('#faultSequence').append('<option value="'+result.sequences[i]+'">'+result.sequences[i]+'</option>');
                            }
							$('<input>').
							attr('type', 'hidden').
							attr('name', 'faultSeq').
							attr('id', 'faultSeq').
							attr('value', result.sequences[i]).
							appendTo('#addAPIForm');

						}
					}
					faultSequencesLoaded = true;
				}
			}, "json");
}


text:
<?php

l::set('uniform-filled-potty', 'Bos kalmasi gereken for alani doldurulmus. Spam-bot degilseniz lutfen bu formu bos birakip tekrar deneyin.');
l::set('uniform-fields-required', 'Lutfen doldurulmasi gereken formlarin hepsini doldurun.');
l::set('uniform-fields-not-valid', 'Bazi formlar olmasi gerektigi gibi doldurulmamis.');

l::set('uniform-email-subject', 'Web-form\'dan gelen mesaj');
l::set('uniform-email-success', 'Tesekkurler. Form basariyla gönderildi.');
l::set('uniform-email-error', 'Form gonderilirken bir hata olustu:');
l::set('uniform-email-copy', 'Kopyala:');

l::set('uniform-calc-plus', 'arti');

l::set('uniform-log-success', 'Log girisi basariyla olusturuldu.');
l::set('uniform-log-error', 'Log dosyasi olusturulurken hata olustu.');

l::set('uniform-login-error', 'Yanlis kullanici adi veya sifre.');
l::set('uniform-login-success', 'Giris basarili.');

l::set('uniform-webhook-success', 'Webhook basariyla cagirildi.');
l::set('uniform-webhook-error', 'Webhook cagirilirken bir hata olustu: ');

l::set('uniform-email-select-error', 'Gecersiz alici.');

redpajama_set_name: RedPajamaGithub


text:
ABI_VERSION=`echo $1 | sed 's/\./_/g'`
ABI_VERSION="abi$ABI_VERSION"
VERSIONED_ABI_PATH=versioned-abis/expoview-$ABI_VERSION
BUILD_GRADLE_PATH=$EXPO_ROOT_DIR/android/$VERSIONED_ABI_PATH/build.gradle
TOOLS_DIR=`pwd`

# Remove code that builds Reanimated from the new expoview-abiXX_X_X build.gradle
awk '
  /WHEN_PREPARING_REANIMATED_REMOVE_FROM_HERE/ { removing = 1 }
  /WHEN_PREPARING_REANIMATED_REMOVE_TO_HERE/ { stopRemoving = 1 }
  // { if (removing == 0) print $0 }
  // { if (stopRemoving == 1) removing = 0 }
  // { if (removing == 0) stopRemoving = 0 }
' $BUILD_GRADLE_PATH > tmp && mv tmp $BUILD_GRADLE_PATH


text:
#include <TMongoDriver>
#include <TMongoCursor>
#include <TBson>
#include <TSystemGlobal>
#include <QDateTime>
extern "C" {
#include "mongoc.h"
}

TMongoDriver::TMongoDriver()
    : mongoClient(nullptr), dbName(), mongoCursor(new TMongoCursor()), lastStatus(nullptr), errorCode(0), errorString()
{
    mongoc_init();
}

TMongoDriver::~TMongoDriver()
{
    close();
    delete mongoCursor;

    if (lastStatus) {
        delete lastStatus;
    }
}

bool TMongoDriver::open(const QString &db, const QString &user, const QString &password, const QString &host, quint16 port, const QString &options)
{
    if (isOpen()) {
        return true;
    }

    if (!port)
        port = MONGOC_DEFAULT_PORT;

    QString uri;
    if (!user.isEmpty()) {
        uri += user;
        if (!password.isEmpty()) {
            uri += ':';
            uri += password;
            uri += '@';
        }
    }
    uri += host;
    if (!options.isEmpty()) {
        uri += "/?";
        uri += options;
    }

    if (!uri.isEmpty()) {
        uri.prepend(QLatin1String("mongodb://"));
    }

    // connect
    mongoClient = mongoc_client_new(qPrintable(uri));
    if (mongoClient) {
        dbName = db;
    } else {
        tSystemError("MongoDB client create error");
    }
    return (bool)mongoClient;
}

void TMongoDriver::close()
{
    if (isOpen()) {
        mongoc_client_destroy(mongoClient);
        mongoClient = nullptr;
    }
}

bool TMongoDriver::isOpen() const
{
    return (bool)mongoClient;
}

bool TMongoDriver::find(const QString &collection, const QVariantMap &criteria, const QVariantMap &orderBy,
                        const QStringList &fields, int limit, int skip, int )
{
    if (!isOpen()) {
        return false;
    }

    errorCode = 0;
    errorString.clear();

    mongoc_collection_t *col = mongoc_client_get_collection(mongoClient, qPrintable(dbName), qPrintable(collection));
    mongoc_cursor_t *cursor = mongoc_collection_find(col, MONGOC_QUERY_NONE, skip, limit, 0,
                                                     (bson_t *)TBson::toBson(criteria, orderBy).data(),
                                                     (bson_t *)TBson::toBson(fields).data(),
                                                     nullptr); /* Read Prefs, nullptr for default */

    setLastCommandStatus(mongoc_collection_get_last_error(col));
    mongoc_collection_destroy(col);
    mongoCursor->setCursor(cursor);

    if (cursor) {
        bson_error_t error;
        if (mongoc_cursor_error(cursor, &error)) {
            errorCode = error.code;
            errorString = QLatin1String(error.message);
        }
    } else {
        tSystemError("MongoDB Cursor Error");
    }
    return (bool)cursor;
}

QVariantMap TMongoDriver::findOne(const QString &collection, const QVariantMap &criteria,
                                  const QStringList &fields)
{
    QVariantMap ret;

    bool res = find(collection, criteria, QVariantMap(), fields, 1, 0, 0);
    if (res && mongoCursor->next()) {
        ret = mongoCursor->value();
    }
    return ret;
}

bool TMongoDriver::insert(const QString &collection, const QVariantMap &object)
{
    if (!isOpen()) {
        return false;
    }

    errorCode = 0;
    errorString.clear();
    bson_error_t error;

    mongoc_collection_t *col = mongoc_client_get_collection(mongoClient, qPrintable(dbName), qPrintable(collection));
    bool res = mongoc_collection_insert(col, MONGOC_INSERT_NONE, (bson_t *)TBson::toBson(object).constData(),
                                        nullptr, &error);

    setLastCommandStatus(mongoc_collection_get_last_error(col));
    mongoc_collection_destroy(col);
    if (!res) {
        tSystemError("MongoDB Insert Error: %s", error.message);
        errorCode = error.code;
        errorString = QLatin1String(error.message);
    }
    return res;
}

bool TMongoDriver::remove(const QString &collection, const QVariantMap &object)
{
    if (!isOpen()) {
        return false;
    }

    errorCode = 0;
    errorString.clear();
    bson_error_t error;

    mongoc_collection_t *col = mongoc_client_get_collection(mongoClient, qPrintable(dbName), qPrintable(collection));
    bool res = mongoc_collection_remove(col, MONGOC_REMOVE_SINGLE_REMOVE,
                                        (bson_t *)TBson::toBson(object).constData(), nullptr, &error);

    setLastCommandStatus(mongoc_collection_get_last_error(col));
    mongoc_collection_destroy(col);

    if (!res) {
        tSystemError("MongoDB Remove Error: %s", error.message);
        errorCode = error.code;
        errorString = QLatin1String(error.message);
    }
    return res;
}

bool TMongoDriver::update(const QString &collection, const QVariantMap &criteria, const QVariantMap &object,
                          bool upsert)
{
    if (!isOpen()) {
        return false;
    }

    errorCode = 0;
    errorString.clear();
    bson_error_t error;

    mongoc_update_flags_t flag = (upsert) ? MONGOC_UPDATE_UPSERT : MONGOC_UPDATE_NONE;
    mongoc_collection_t *col = mongoc_client_get_collection(mongoClient, qPrintable(dbName), qPrintable(collection));
    bool res = mongoc_collection_update(col, flag, (bson_t *)TBson::toBson(criteria).data(),
                                        (bson_t *)TBson::toBson(object).data(), nullptr, &error);

    setLastCommandStatus(mongoc_collection_get_last_error(col));
    mongoc_collection_destroy(col);

    if (!res) {
        tSystemError("MongoDB Update Error: %s", error.message);
        errorCode = error.code;
        errorString = QLatin1String(error.message);
    }
    return res;
}

bool TMongoDriver::updateMulti(const QString &collection, const QVariantMap &criteria, const QVariantMap &object)
{
    if (!isOpen()) {
        return false;
    }

    errorCode = 0;
    errorString.clear();
    bson_error_t error;

    mongoc_collection_t *col = mongoc_client_get_collection(mongoClient, qPrintable(dbName), qPrintable(collection));
    bool res = mongoc_collection_update(col, MONGOC_UPDATE_MULTI_UPDATE,
                                        (bson_t *)TBson::toBson(criteria).data(),
                                        (bson_t *)TBson::toBson(object).data(), nullptr, &error);

    setLastCommandStatus(mongoc_collection_get_last_error(col));
    mongoc_collection_destroy(col);

    if (!res) {
        tSystemError("MongoDB UpdateMulti Error: %s", error.message);
        errorCode = error.code;
        errorString = QLatin1String(error.message);
    }
    return res;
}

int TMongoDriver::count(const QString &collection, const QVariantMap &criteria)
{
    if (!isOpen()) {
        return false;
    }

    errorCode = 0;
    errorString.clear();
    bson_error_t error;

    mongoc_collection_t *col = mongoc_client_get_collection(mongoClient, qPrintable(dbName), qPrintable(collection));
    int count = mongoc_collection_count(col, MONGOC_QUERY_NONE, (bson_t *)TBson::toBson(criteria).data(),
                                        0, 0, nullptr, &error);

    setLastCommandStatus(mongoc_collection_get_last_error(col));
    mongoc_collection_destroy(col);

    if (count < 0) {
        tSystemError("MongoDB Count Error: %s", error.message);
        errorCode = error.code;
        errorString = QLatin1String(error.message);
    }
    return count;
}

// QString TMongoDriver::lastErrorString() const
// {
//     return lastStatus->value("writeErrors").toStringList().value(0);
// }

QVariantMap TMongoDriver::getLastCommandStatus() const
{
    return TBson::fromBson(*lastStatus);
}

void TMongoDriver::setLastCommandStatus(const void *bson)
{
    if (lastStatus) {
        delete lastStatus;
    }
    lastStatus = new TBson((const TBsonObject *)bson);
}


text:
/* libhs - public domain
   Niels Martignène <niels.martignene@protonmail.com>
   https://koromix.dev/libhs

   This software is in the public domain. Where that dedication is not
   recognized, you are granted a perpetual, irrevocable license to copy,
   distribute, and modify this file as you see fit.

   See the LICENSE file for more details. */

#include "common_priv.h"
#include <CoreFoundation/CFRunLoop.h>
#include <IOKit/IOCFPlugIn.h>
#include <IOKit/hid/IOHIDDevice.h>
#include <poll.h>
#include <pthread.h>
#include <unistd.h>
#include "array.h"
#include "device_priv.h"
#include "hid.h"
#include "platform.h"

struct hid_report {
    size_t size;
    uint8_t *data;
};

struct _hs_hid_darwin {
    io_service_t service;
    union {
        IOHIDDeviceRef hid_ref;
    };

    uint8_t *read_buf;
    size_t read_size;

    pthread_mutex_t mutex;
    bool mutex_init;
    int poll_pipe[2];
    int thread_ret;

    _HS_ARRAY(struct hid_report) reports;

    pthread_t read_thread;
    pthread_cond_t cond;
    bool cond_init;

    CFRunLoopRef thread_loop;
    CFRunLoopSourceRef shutdown_source;
    bool device_removed;
};

#define MAX_REPORT_QUEUE_SIZE 128

static void fire_hid_poll_handle(struct _hs_hid_darwin *hid)
{
    char buf = '.';
    write(hid->poll_pipe[1], &buf, 1);
}

static void reset_hid_poll_handle(struct _hs_hid_darwin *hid)
{
    char buf;
    read(hid->poll_pipe[0], &buf, 1);
}

static void hid_removal_callback(void *ctx, IOReturn result, void *sender)
{
    _HS_UNUSED(result);
    _HS_UNUSED(sender);

    hs_port *port = (hs_port *)ctx;
    struct _hs_hid_darwin *hid = port->u.hid;

    pthread_mutex_lock(&hid->mutex);
    hid->device_removed = true;
    CFRunLoopSourceSignal(hid->shutdown_source);
    pthread_mutex_unlock(&hid->mutex);

    fire_hid_poll_handle(hid);
}

static void hid_report_callback(void *ctx, IOReturn result, void *sender,
                                IOHIDReportType report_type, uint32_t report_id,
                                uint8_t *report_data, CFIndex report_size)
{
    _HS_UNUSED(result);
    _HS_UNUSED(sender);

    if (report_type != kIOHIDReportTypeInput)
        return;

    hs_port *port = (hs_port *)ctx;
    struct _hs_hid_darwin *hid = port->u.hid;
    struct hid_report *report;
    bool was_empty;
    int r;

    pthread_mutex_lock(&hid->mutex);

    was_empty = !hid->reports.count;
    if (hid->reports.count == MAX_REPORT_QUEUE_SIZE) {
        r = 0;
        goto cleanup;
    }

    r = _hs_array_grow(&hid->reports, 1);
    if (r < 0)
        goto cleanup;
    report = hid->reports.values + hid->reports.count;
    if (!report->data) {
        // Don't forget the leading report ID
        report->data = (uint8_t *)malloc(hid->read_size + 1);
        if (!report->data) {
            r = hs_error(HS_ERROR_MEMORY, NULL);
            goto cleanup;
        }
    }

    /* You never know, even if hid->red_size is supposed to be the maximum
       input report size. */
    if (report_size > (CFIndex)hid->read_size)
        report_size = (CFIndex)hid->read_size;

    report->data[0] = (uint8_t)report_id;
    memcpy(report->data + 1, report_data, report_size);
    report->size = (size_t)report_size + 1;

    hid->reports.count++;

    r = 0;
cleanup:
    if (r < 0)
        hid->thread_ret = r;
    pthread_mutex_unlock(&hid->mutex);
    if (was_empty)
        fire_hid_poll_handle(hid);
}

static void *hid_read_thread(void *ptr)
{
    hs_port *port = (hs_port *)ptr;
    struct _hs_hid_darwin *hid = port->u.hid;
    CFRunLoopSourceContext shutdown_ctx = {0};
    int r;

    pthread_mutex_lock(&hid->mutex);

    hid->thread_loop = CFRunLoopGetCurrent();

    shutdown_ctx.info = hid->thread_loop;
    shutdown_ctx.perform = (void (*)(void *))CFRunLoopStop;
    /* close_hid_device() could be called before the loop is running, while this thread is between
       pthread_barrier_wait() and CFRunLoopRun(). That's the purpose of the shutdown source. */
    hid->shutdown_source = CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &shutdown_ctx);
    if (!hid->shutdown_source) {
        r = hs_error(HS_ERROR_SYSTEM, "CFRunLoopSourceCreate() failed");
        goto error;
    }

    CFRunLoopAddSource(hid->thread_loop, hid->shutdown_source, kCFRunLoopCommonModes);
    IOHIDDeviceScheduleWithRunLoop(hid->hid_ref, hid->thread_loop, kCFRunLoopCommonModes);

    // This thread is ready, open_hid_device() can carry on
    hid->thread_ret = 1;
    pthread_cond_signal(&hid->cond);
    pthread_mutex_unlock(&hid->mutex);

    CFRunLoopRun();

    IOHIDDeviceUnscheduleFromRunLoop(hid->hid_ref, hid->thread_loop, kCFRunLoopCommonModes);

    pthread_mutex_lock(&hid->mutex);
    hid->thread_loop = NULL;
    pthread_mutex_unlock(&hid->mutex);

    return NULL;

error:
    hid->thread_ret = r;
    pthread_cond_signal(&hid->cond);
    pthread_mutex_unlock(&hid->mutex);
    return NULL;
}

static bool get_hid_device_property_number(IOHIDDeviceRef ref, CFStringRef prop,
                                           CFNumberType type, void *rn)
{
    CFTypeRef data = IOHIDDeviceGetProperty(ref, prop);
    if (!data || CFGetTypeID(data) != CFNumberGetTypeID())
        return false;

    return CFNumberGetValue((CFNumberRef)data, type, rn);
}

int _hs_darwin_open_hid_port(hs_device *dev, hs_port_mode mode, hs_port **rport)
{
    hs_port *port;
    struct _hs_hid_darwin *hid;
    kern_return_t kret;
    int r;

    port = (hs_port *)calloc(1, _HS_ALIGN_SIZE_FOR_TYPE(sizeof(*port), struct _hs_hid_darwin) +
                                sizeof(struct _hs_hid_darwin));
    if (!port) {
        r = hs_error(HS_ERROR_MEMORY, NULL);
        goto error;
    }
    port->type = dev->type;
    port->u.hid = (struct _hs_hid_darwin *)((char *)port +
                                            _HS_ALIGN_SIZE_FOR_TYPE(sizeof(*port), struct _hs_hid_darwin));
    hid = port->u.hid;
    hid->poll_pipe[0] = -1;
    hid->poll_pipe[1] = -1;

    port->mode = mode;
    port->path = dev->path;
    port->dev = hs_device_ref(dev);

    hid->service = IORegistryEntryFromPath(kIOMasterPortDefault, dev->path);
    if (!hid->service) {
        r = hs_error(HS_ERROR_NOT_FOUND, "Device '%s' not found", dev->path);
        goto error;
    }

    hid->hid_ref = IOHIDDeviceCreate(kCFAllocatorDefault, hid->service);
    if (!hid->hid_ref) {
        r = hs_error(HS_ERROR_NOT_FOUND, "Device '%s' not found", dev->path);
        goto error;
    }

    kret = IOHIDDeviceOpen(hid->hid_ref, 0);
    if (kret != kIOReturnSuccess) {
        r = hs_error(HS_ERROR_SYSTEM, "Failed to open HID device '%s'", dev->path);
        goto error;
    }

    IOHIDDeviceRegisterRemovalCallback(hid->hid_ref, hid_removal_callback, port);

    if (mode & HS_PORT_MODE_READ) {
        r = get_hid_device_property_number(hid->hid_ref, CFSTR(kIOHIDMaxInputReportSizeKey),
                                           kCFNumberSInt32Type, &hid->read_size);
        if (!r) {
            r = hs_error(HS_ERROR_SYSTEM, "HID device '%s' has no valid report size key", dev->path);
            goto error;
        }
        hid->read_buf = (uint8_t *)malloc(hid->read_size);
        if (!hid->read_buf) {
            r = hs_error(HS_ERROR_MEMORY, NULL);
            goto error;
        }

        IOHIDDeviceRegisterInputReportCallback(hid->hid_ref, hid->read_buf,
                                               (CFIndex)hid->read_size, hid_report_callback, port);

        r = pipe(hid->poll_pipe);
        if (r < 0) {
            r = hs_error(HS_ERROR_SYSTEM, "pipe() failed: %s", strerror(errno));
            goto error;
        }
        fcntl(hid->poll_pipe[0], F_SETFL, fcntl(hid->poll_pipe[0], F_GETFL, 0) | O_NONBLOCK);
        fcntl(hid->poll_pipe[1], F_SETFL, fcntl(hid->poll_pipe[1], F_GETFL, 0) | O_NONBLOCK);

        r = pthread_mutex_init(&hid->mutex, NULL);
        if (r < 0) {
            r = hs_error(HS_ERROR_SYSTEM, "pthread_mutex_init() failed: %s", strerror(r));
            goto error;
        }
        hid->mutex_init = true;

        r = pthread_cond_init(&hid->cond, NULL);
        if (r < 0) {
            r = hs_error(HS_ERROR_SYSTEM, "pthread_cond_init() failed: %s", strerror(r));
            goto error;
        }
        hid->cond_init = true;

        pthread_mutex_lock(&hid->mutex);

        r = pthread_create(&hid->read_thread, NULL, hid_read_thread, port);
        if (r) {
            r = hs_error(HS_ERROR_SYSTEM, "pthread_create() failed: %s", strerror(r));
            goto error;
        }

        /* Barriers are great for this, but OSX doesn't have those... And since it's the only
           place we would use them, it's probably not worth it to have a custom implementation. */
        while (!hid->thread_ret)
            pthread_cond_wait(&hid->cond, &hid->mutex);
        r = hid->thread_ret;
        hid->thread_ret = 0;
        pthread_mutex_unlock(&hid->mutex);
        if (r < 0)
            goto error;
    }

    *rport = port;
    return 0;

error:
    hs_port_close(port);
    return r;
}

void _hs_darwin_close_hid_port(hs_port *port)
{
    if (port) {
        struct _hs_hid_darwin *hid = port->u.hid;

        if (hid->shutdown_source) {
            pthread_mutex_lock(&hid->mutex);

            if (hid->thread_loop) {
                CFRunLoopSourceSignal(hid->shutdown_source);
                CFRunLoopWakeUp(hid->thread_loop);
            }

            pthread_mutex_unlock(&hid->mutex);
            pthread_join(hid->read_thread, NULL);

            CFRelease(hid->shutdown_source);
        }

        if (hid->cond_init)
            pthread_cond_destroy(&hid->cond);
        if (hid->mutex_init)
            pthread_mutex_destroy(&hid->mutex);

        for (size_t i = 0; i < hid->reports.count; i++) {
            struct hid_report *report = &hid->reports.values[i];
            free(report->data);
        }
        _hs_array_release(&hid->reports);

        close(hid->poll_pipe[0]);
        close(hid->poll_pipe[1]);

        free(hid->read_buf);

        if (hid->hid_ref) {
            IOHIDDeviceClose(hid->hid_ref, 0);
            CFRelease(hid->hid_ref);
        }
        if (hid->service)
            IOObjectRelease(hid->service);

        hs_device_unref(port->dev);
    }

    free(port);
}

hs_handle _hs_darwin_get_hid_port_poll_handle(const hs_port *port)
{
    return port->u.hid->poll_pipe[0];
}

ssize_t hs_hid_read(hs_port *port, uint8_t *buf, size_t size, int timeout)
{
    assert(port);
    assert(port->type == HS_DEVICE_TYPE_HID);
    assert(port->mode & HS_PORT_MODE_READ);
    assert(buf);
    assert(size);

    struct _hs_hid_darwin *hid = port->u.hid;
    struct hid_report *report;
    ssize_t r;

    if (hid->device_removed)
        return hs_error(HS_ERROR_IO, "Device '%s' was removed", port->path);

    if (timeout) {
        struct pollfd pfd;
        uint64_t start;

        pfd.events = POLLIN;
        pfd.fd = hid->poll_pipe[0];

        start = hs_millis();
restart:
        r = poll(&pfd, 1, hs_adjust_timeout(timeout, start));
        if (r < 0) {
            if (errno == EINTR)
                goto restart;

            return hs_error(HS_ERROR_SYSTEM, "poll('%s') failed: %s", port->path, strerror(errno));
        }
        if (!r)
            return 0;
    }

    pthread_mutex_lock(&hid->mutex);

    if (hid->thread_ret < 0) {
        r = hid->thread_ret;
        hid->thread_ret = 0;
        goto cleanup;
    }
    if (!hid->reports.count) {
        r = 0;
        goto cleanup;
    }

    report = &hid->reports.values[0];
    if (size > report->size)
        size = report->size;
    memcpy(buf, report->data, size);
    r = (ssize_t)size;

    // Circular buffer would be more appropriate. Later.
    _hs_array_remove(&hid->reports, 0, 1);

cleanup:
    if (!hid->reports.count)
        reset_hid_poll_handle(hid);
    pthread_mutex_unlock(&hid->mutex);
    return r;
}

static ssize_t send_report(hs_port *port, IOHIDReportType type, const uint8_t *buf, size_t size)
{
    struct _hs_hid_darwin *hid = port->u.hid;
    uint8_t report;
    kern_return_t kret;

    if (hid->device_removed)
        return hs_error(HS_ERROR_IO, "Device '%s' was removed", port->path);

    if (size < 2)
        return 0;

    report = buf[0];
    if (!report) {
        buf++;
        size--;
    }

    /* FIXME: find a way drop out of IOHIDDeviceSetReport() after a reasonable time, because
       IOHIDDeviceSetReportWithCallback() is broken. Perhaps we can open the device twice and
       close the write side to drop out of IOHIDDeviceSetReport() after a few seconds? Or maybe
       we can call IOHIDDeviceSetReport() in another thread and kill it, but I don't trust OSX
       to behave well in that case. The HID API does like to crash OSX for no reason. */
    kret = IOHIDDeviceSetReport(hid->hid_ref, type, report, buf, (CFIndex)size);
    if (kret != kIOReturnSuccess)
        return hs_error(HS_ERROR_IO, "I/O error while writing to '%s'", port->path);

    return (ssize_t)size + !report;
}

ssize_t hs_hid_write(hs_port *port, const uint8_t *buf, size_t size)
{
    assert(port);
    assert(port->type == HS_DEVICE_TYPE_HID);
    assert(port->mode & HS_PORT_MODE_WRITE);
    assert(buf);

    return send_report(port, kIOHIDReportTypeOutput, buf, size);
}

ssize_t hs_hid_get_feature_report(hs_port *port, uint8_t report_id, uint8_t *buf, size_t size)
{
    assert(port);
    assert(port->type == HS_DEVICE_TYPE_HID);
    assert(port->mode & HS_PORT_MODE_READ);
    assert(buf);
    assert(size);

    struct _hs_hid_darwin *hid = port->u.hid;
    CFIndex len;
    kern_return_t kret;

    if (hid->device_removed)
        return hs_error(HS_ERROR_IO, "Device '%s' was removed", port->path);

    len = (CFIndex)size - 1;
    kret = IOHIDDeviceGetReport(hid->hid_ref, kIOHIDReportTypeFeature, report_id,
                                buf + 1, &len);
    if (kret != kIOReturnSuccess)
        return hs_error(HS_ERROR_IO, "IOHIDDeviceGetReport() failed on '%s'", port->path);

    buf[0] = report_id;
    return (ssize_t)len;
}

ssize_t hs_hid_send_feature_report(hs_port *port, const uint8_t *buf, size_t size)
{
    assert(port);
    assert(port->type == HS_DEVICE_TYPE_HID);
    assert(port->mode & HS_PORT_MODE_WRITE);
    assert(buf);

    return send_report(port, kIOHIDReportTypeFeature, buf, size);
}


text:
// Copyright 2020 Anapaya Systems
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cppki_test

import (
	"crypto/x509"
	"crypto/x509/pkix"
	"encoding/asn1"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"

	"github.com/scionproto/scion/go/lib/scrypto/cppki"
	"github.com/scionproto/scion/go/lib/xtest"
)

var updateNonDeterministic = xtest.UpdateNonDeterminsticGoldenFiles()

func updateCert(goldenCert string) ([]byte, error) {
	dir, cleanF := xtest.MustTempDir("", "safedir")
	defer cleanF()

	cmd := exec.Command("sh", "-c", "./testdata/update_certs.sh")
	cmd.Env = []string{
		"SAFEDIR=" + dir,
		"STARTDATE=20200624120000Z",
		"ENDDATE=20250624120000Z",
	}

	out, err := cmd.CombinedOutput()
	if err != nil {
		return out, err
	}

	src, dst := filepath.Join(dir, goldenCert), filepath.Join("./testdata", goldenCert)
	command := fmt.Sprintf("mv %s %s", src, dst)
	return exec.Command("sh", "-c", command).CombinedOutput()
}

type testCase struct {
	modify    func(*x509.Certificate) *x509.Certificate
	assertErr assert.ErrorAssertionFunc
}

var generalCases = map[string]testCase{
	"nil content": {
		modify:    func(c *x509.Certificate) *x509.Certificate { return nil },
		assertErr: assert.Error,
	},
	"valid": {
		modify:    func(c *x509.Certificate) *x509.Certificate { return c },
		assertErr: assert.NoError,
	},
	"invalid version": {
		modify: func(c *x509.Certificate) *x509.Certificate {
			c.Version = 2
			return c
		},
		assertErr: assert.Error,
	},
	"invalid no serial number": {
		modify: func(c *x509.Certificate) *x509.Certificate {
			c.SerialNumber = nil
			return c
		},
		assertErr: assert.Error,
	},
	"invalid signature algo": {
		modify: func(c *x509.Certificate) *x509.Certificate {
			c.SignatureAlgorithm = x509.DSAWithSHA1
			return c
		},
		assertErr: assert.Error,
	},
	"invalid no SubjectKeyId": {
		modify: func(c *x509.Certificate) *x509.Certificate {
			c.SubjectKeyId = []byte{}
			return c
		},
		assertErr: assert.Error,
	},
	"invalid subjectKeyId is critical": {
		modify: func(c *x509.Certificate) *x509.Certificate {
			m := []pkix.Extension{}
			for _, v := range c.Extensions {
				if v.Id.Equal(asn1.ObjectIdentifier{2, 5, 29, 14}) {
					v.Critical = true
				}
				m = append(m, v)
			}
			c.Extensions = m
			return c
		},
		assertErr: assert.Error,
	},
	"invalid if authorityKeyId exist and is critical": {
		modify: func(c *x509.Certificate) *x509.Certificate {
			m := []pkix.Extension{}
			oid := asn1.ObjectIdentifier{2, 5, 29, 35}
			found := false
			for _, v := range c.Extensions {
				if v.Id.Equal(oid) {
					v.Critical = true
					found = true
				}
				m = append(m, v)
			}
			if !found {
				m = append(m, pkix.Extension{Id: oid, Critical: true})
			}
			c.Extensions = m
			return c
		},
		assertErr: assert.Error,
	},
}

var commonCACases = map[string]testCase{
	"invalid keyUsage no CertSign": {
		modify: func(c *x509.Certificate) *x509.Certificate {
			t := c.KeyUsage &^ x509.KeyUsageCertSign
			c.KeyUsage = t
			return c
		},
		assertErr: assert.Error,
	},
	"valid keyUsage CRLSign": {
		modify: func(c *x509.Certificate) *x509.Certificate {
			t := c.KeyUsage | x509.KeyUsageCRLSign
			c.KeyUsage = t
			return c
		},
		assertErr: assert.NoError,
	},
	"valid keyUsage no CRLSign": {
		modify: func(c *x509.Certificate) *x509.Certificate {
			t := c.KeyUsage &^ x509.KeyUsageCRLSign
			c.KeyUsage = t
			return c
		},
		assertErr: assert.NoError,
	},
	"invalid digitalSignature is set": {
		modify: func(c *x509.Certificate) *x509.Certificate {
			t := c.KeyUsage | x509.KeyUsageDigitalSignature
			c.KeyUsage = t
			return c
		},
		assertErr: assert.Error,
	},
	"invalid ExtKeyUsage id-kp-serverAuth is set": {
		modify: func(c *x509.Certificate) *x509.Certificate {
			c.ExtKeyUsage = append(c.ExtKeyUsage, x509.ExtKeyUsageServerAuth)
			return c
		},
		assertErr: assert.Error,
	},
	"invalid ExtKeyUsage id-kp-clientAuth is set": {
		modify: func(c *x509.Certificate) *x509.Certificate {
			c.ExtKeyUsage = append(c.ExtKeyUsage, x509.ExtKeyUsageClientAuth)
			return c
		},
		assertErr: assert.Error,
	},
	"invalid BasicConstraints no CA": {
		modify: func(c *x509.Certificate) *x509.Certificate {
			c.IsCA = false
			return c
		},
		assertErr: assert.Error,
	},
	"invalid BasicConstraints not critical": {
		modify: func(c *x509.Certificate) *x509.Certificate {
			m := []pkix.Extension{}
			for _, v := range c.Extensions {
				// .19 is basicConstraints
				if v.Id.Equal(asn1.ObjectIdentifier{2, 5, 29, 19}) {
					v.Critical = false
				}
				m = append(m, v)
			}
			c.Extensions = m
			return c
		},
		assertErr: assert.Error,
	},
	"invalid no valid issuer IA": {
		modify: func(c *x509.Certificate) *x509.Certificate {
			v := []pkix.AttributeTypeAndValue{
				{Type: cppki.OIDNameIA},
			}
			for _, name := range c.Issuer.Names {
				if name.Type.Equal(cppki.OIDNameIA) {
					continue
				}
				v = append(v, name)
			}
			c.Issuer.Names = v
			return c
		},
		assertErr: assert.Error,
	},
	"invalid missing issuer IA": {
		modify: func(c *x509.Certificate) *x509.Certificate {
			for i, name := range c.Issuer.Names {
				if name.Type.Equal(cppki.OIDNameIA) {
					c.Issuer.Names = append(c.Issuer.Names[:i], c.Issuer.Names[i+1:]...)
				}
			}
			return c
		},
		assertErr: assert.Error,
	},
	"invalid no valid subject IA": {
		modify: func(c *x509.Certificate) *x509.Certificate {
			v := []pkix.AttributeTypeAndValue{
				{Type: cppki.OIDNameIA},
			}
			for _, name := range c.Subject.Names {
				if name.Type.Equal(cppki.OIDNameIA) {
					continue
				}
				v = append(v, name)
			}
			c.Subject.Names = v
			return c
		},
		assertErr: assert.Error,
	},
	"invalid missing subject IA": {
		modify: func(c *x509.Certificate) *x509.Certificate {
			for i, name := range c.Subject.Names {
				if name.Type.Equal(cppki.OIDNameIA) {
					c.Subject.Names = append(c.Subject.Names[:i], c.Subject.Names[i+1:]...)
				}
			}
			return c
		},
		assertErr: assert.Error,
	},
	"invalid invalid subject IA": {
		modify: func(c *x509.Certificate) *x509.Certificate {
			for i, name := range c.Subject.Names {
				if name.Type.Equal(cppki.OIDNameIA) {
					name.Value = "invalid"
					c.Subject.Names[i] = name
				}
			}
			return c
		},
		assertErr: assert.Error,
	},
}

func TestValidateRoot(t *testing.T) {
	goldenCert := "cp-root.crt"
	testF := cppki.ValidateRoot

	if *updateNonDeterministic {
		out, err := updateCert(goldenCert)
		require.NoError(t, err, string(out))
		t.Logf("git add ./testdata/%s", goldenCert)
		return
	}
	testCases := map[string]testCase{
		"invalid should be self signed": {
			modify: func(c *x509.Certificate) *x509.Certificate {
				c.AuthorityKeyId = []byte("other")
				return c
			},
			assertErr: assert.Error,
		},
		"invalid BasicConstraints MaxPathLen": {
			modify: func(c *x509.Certificate) *x509.Certificate {
				c.MaxPathLen = 0
				return c
			},
			assertErr: assert.Error,
		},
		"invalid ExtKeyUsage id-kp-root is not set": {
			modify: func(c *x509.Certificate) *x509.Certificate {
				m := []asn1.ObjectIdentifier{}
				for _, v := range c.UnknownExtKeyUsage {
					if v.Equal(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 55324, 1, 3, 3}) {
						continue
					}
					m = append(m, v)
				}
				c.UnknownExtKeyUsage = m
				return c
			},
			assertErr: assert.Error,
		},
	}

	for k, v := range generalCases {
		testCases[k] = v
	}

	for k, v := range commonCACases {
		testCases[k] = v
	}

	for name, tc := range testCases {
		name, tc := name, tc
		t.Run(name, func(t *testing.T) {
			t.Parallel()
			validCert, err := cppki.ReadPEMCerts(filepath.Join("./testdata", goldenCert))
			require.NoError(t, err)
			input := tc.modify(validCert[0])
			err = testF(input)
			tc.assertErr(t, err)
		})
	}

}

func TestValidateCA(t *testing.T) {
	testF := cppki.ValidateCA
	goldenCert := "cp-ca.crt"

	if *updateNonDeterministic {
		out, err := updateCert(goldenCert)
		require.NoError(t, err, string(out))
		t.Logf("git add ./testdata/%s", goldenCert)
		return
	}

	testCases := map[string]testCase{
		"invalid BasicConstraints MaxPathLen": {
			modify: func(c *x509.Certificate) *x509.Certificate {
				c.MaxPathLen = 1
				return c
			},
			assertErr: assert.Error,
		},
		"invalid AuthorityKeyId is no present": {
			modify: func(c *x509.Certificate) *x509.Certificate {
				c.AuthorityKeyId = []byte{}
				return c
			},
			assertErr: assert.Error,
		},
	}

	for k, v := range generalCases {
		testCases[k] = v
	}
	for k, v := range commonCACases {
		testCases[k] = v
	}

	for name, tc := range testCases {
		name, tc := name, tc
		t.Run(name, func(t *testing.T) {
			t.Parallel()
			validCert, err := cppki.ReadPEMCerts(filepath.Join("./testdata", goldenCert))
			require.NoError(t, err)
			input := tc.modify(validCert[0])
			err = testF(input)
			tc.assertErr(t, err)
		})
	}
}

func TestValidateAS(t *testing.T) {
	testF := cppki.ValidateAS
	goldenCert := "cp-as.crt"

	if *updateNonDeterministic {
		out, err := updateCert(goldenCert)
		require.NoError(t, err, string(out))
		t.Logf("git add ./testdata/%s", goldenCert)
		return
	}

	testCases := map[string]testCase{
		"invalid keyUsage CertSign is set": {
			modify: func(c *x509.Certificate) *x509.Certificate {
				t := c.KeyUsage | x509.KeyUsageCertSign
				c.KeyUsage = t
				return c
			},
			assertErr: assert.Error,
		},
		"invalid keyUsage no digitalSignature": {
			modify: func(c *x509.Certificate) *x509.Certificate {
				t := c.KeyUsage &^ x509.KeyUsageDigitalSignature
				c.KeyUsage = t
				return c
			},
			assertErr: assert.Error,
		},
		"invalid ExtKeyUsage id-kp-timeStamping is not set": {
			modify: func(c *x509.Certificate) *x509.Certificate {
				m := []x509.ExtKeyUsage{}
				for _, v := range c.ExtKeyUsage {
					if v == x509.ExtKeyUsageTimeStamping {
						continue
					}
					m = append(m, v)
				}
				c.ExtKeyUsage = m
				return c
			},
			assertErr: assert.Error,
		},
		"invalid BasicConstraints is present": {
			modify: func(c *x509.Certificate) *x509.Certificate {
				c.BasicConstraintsValid = true
				c.IsCA = true
				add := pkix.Extension{Id: asn1.ObjectIdentifier{2, 5, 29, 19}}
				c.Extensions = append(c.Extensions, add)
				return c
			},
			assertErr: assert.Error,
		},
		"invalid no valid IA": {
			modify: func(c *x509.Certificate) *x509.Certificate {
				v := []pkix.AttributeTypeAndValue{
					{Type: cppki.OIDNameIA},
				}
				for _, name := range c.Issuer.Names {
					if name.Type.Equal(cppki.OIDNameIA) {
						continue
					}
					v = append(v, name)
				}
				c.Issuer.Names = v
				return c
			},
			assertErr: assert.Error,
		},
		"invalid AuthorityKeyId is no present": {
			modify: func(c *x509.Certificate) *x509.Certificate {
				c.AuthorityKeyId = []byte{}
				return c
			},
			assertErr: assert.Error,
		},
	}

	for k, v := range generalCases {
		testCases[k] = v
	}

	for name, tc := range testCases {
		name, tc := name, tc
		t.Run(name, func(t *testing.T) {
			t.Parallel()
			validCert, err := cppki.ReadPEMCerts(filepath.Join("./testdata", goldenCert))
			require.NoError(t, err)
			input := tc.modify(validCert[0])
			err = testF(input)
			tc.assertErr(t, err)
		})
	}
}

var commonVotingCases = map[string]testCase{
	"invalid should be self signed": {
		modify: func(c *x509.Certificate) *x509.Certificate {
			c.AuthorityKeyId = []byte("other")
			return c
		},
		assertErr: assert.Error,
	},
	"invalid keyUsage CertSign is set": {
		modify: func(c *x509.Certificate) *x509.Certificate {
			t := c.KeyUsage | x509.KeyUsageCertSign
			c.KeyUsage = t
			return c
		},
		assertErr: assert.Error,
	},
	"invalid keyUsage digitalSignature is set": {
		modify: func(c *x509.Certificate) *x509.Certificate {
			t := c.KeyUsage | x509.KeyUsageDigitalSignature
			c.KeyUsage = t
			return c
		},
		assertErr: assert.Error,
	},
	"invalid ExtKeyUsage id-kp-timeStamping is not set": {
		modify: func(c *x509.Certificate) *x509.Certificate {
			m := []x509.ExtKeyUsage{}
			for _, v := range c.ExtKeyUsage {
				if v == x509.ExtKeyUsageTimeStamping {
					continue
				}
				m = append(m, v)
			}
			c.ExtKeyUsage = m
			return c
		},
		assertErr: assert.Error,
	},
	"invalid cert is a CA": {
		modify: func(c *x509.Certificate) *x509.Certificate {
			c.BasicConstraintsValid = true
			c.IsCA = true
			return c
		},
		assertErr: assert.Error,
	},
	"invalid ExtKeyUsage id-kp-serverAuth is set": {
		modify: func(c *x509.Certificate) *x509.Certificate {
			c.ExtKeyUsage = append(c.ExtKeyUsage, x509.ExtKeyUsageServerAuth)
			return c
		},
		assertErr: assert.Error,
	},
	"invalid ExtKeyUsage id-kp-clientAuth is set": {
		modify: func(c *x509.Certificate) *x509.Certificate {
			c.ExtKeyUsage = append(c.ExtKeyUsage, x509.ExtKeyUsageClientAuth)
			return c
		},
		assertErr: assert.Error,
	},
}

func TestValidateRegular(t *testing.T) {
	goldenCert := "regular-voting.crt"
	testF := cppki.ValidateRegular

	if *updateNonDeterministic {
		out, err := updateCert(goldenCert)
		require.NoError(t, err, out)
		t.Logf("git add ./testdata/%s", goldenCert)
		return
	}
	testCases := map[string]testCase{
		"invalid ExtKeyUsage id-kp-regular is not set": {
			modify: func(c *x509.Certificate) *x509.Certificate {
				m := []asn1.ObjectIdentifier{}
				for _, v := range c.UnknownExtKeyUsage {
					if v.Equal(cppki.OIDExtKeyUsageRegular) {
						continue
					}
					m = append(m, v)
				}
				c.UnknownExtKeyUsage = m
				return c
			},
			assertErr: assert.Error,
		},
		"multiple ExtKeyUsage set": {
			modify: func(c *x509.Certificate) *x509.Certificate {
				c.UnknownExtKeyUsage = append(c.UnknownExtKeyUsage, cppki.OIDExtKeyUsageSensitive)
				return c
			},
			assertErr: assert.Error,
		},
	}

	for k, v := range generalCases {
		testCases[k] = v
	}

	for k, v := range commonVotingCases {
		testCases[k] = v
	}

	for name, tc := range testCases {
		name, tc := name, tc
		t.Run(name, func(t *testing.T) {
			t.Parallel()
			validCert, err := cppki.ReadPEMCerts(filepath.Join("./testdata", goldenCert))
			require.NoError(t, err)
			input := tc.modify(validCert[0])
			err = testF(input)
			tc.assertErr(t, err)
		})
	}
}

func TestValidateSensitive(t *testing.T) {
	goldenCert := "sensitive-voting.crt"
	testF := cppki.ValidateSensitive

	if *updateNonDeterministic {
		out, err := updateCert(goldenCert)
		require.NoError(t, err, out)
		t.Logf("git add ./testdata/%s", goldenCert)
		return
	}
	testCases := map[string]testCase{
		"invalid ExtKeyUsage id-kp-sensitive is not set": {
			modify: func(c *x509.Certificate) *x509.Certificate {
				m := []asn1.ObjectIdentifier{}
				for _, v := range c.UnknownExtKeyUsage {
					if v.Equal(cppki.OIDExtKeyUsageSensitive) {
						continue
					}
					m = append(m, v)
				}
				c.UnknownExtKeyUsage = m
				return c
			},
			assertErr: assert.Error,
		},
		"multiple ExtKeyUsage set": {
			modify: func(c *x509.Certificate) *x509.Certificate {
				c.UnknownExtKeyUsage = append(c.UnknownExtKeyUsage, cppki.OIDExtKeyUsageRegular)
				return c
			},
			assertErr: assert.Error,
		},
	}

	for k, v := range generalCases {
		testCases[k] = v
	}

	for k, v := range commonVotingCases {
		testCases[k] = v
	}

	for name, tc := range testCases {
		name, tc := name, tc
		t.Run(name, func(t *testing.T) {
			t.Parallel()
			validCert, err := cppki.ReadPEMCerts(filepath.Join("./testdata", goldenCert))
			require.NoError(t, err)
			input := tc.modify(validCert[0])
			err = testF(input)
			tc.assertErr(t, err)
		})
	}
}

func TestValidateCert(t *testing.T) {
	testCases := map[string]struct {
		CertFile     string
		Modify       func(*x509.Certificate) *x509.Certificate
		ExpectedType cppki.CertType
		AssertErr    assert.ErrorAssertionFunc
	}{
		"as cert": {
			CertFile:     "cp-as.crt",
			ExpectedType: cppki.AS,
			AssertErr:    assert.NoError,
		},
		"ca cert": {
			CertFile:     "cp-ca.crt",
			ExpectedType: cppki.CA,
			AssertErr:    assert.NoError,
		},
		"root cert": {
			CertFile:     "cp-root.crt",
			ExpectedType: cppki.Root,
			AssertErr:    assert.NoError,
		},
		"regular voting cert": {
			CertFile:     "regular-voting.crt",
			ExpectedType: cppki.Regular,
			AssertErr:    assert.NoError,
		},
		"sensitive voting cert": {
			CertFile:     "sensitive-voting.crt",
			ExpectedType: cppki.Sensitive,
			AssertErr:    assert.NoError,
		},
		"nil cert": {
			CertFile:     "sensitive-voting.crt",
			Modify:       func(*x509.Certificate) *x509.Certificate { return nil },
			ExpectedType: cppki.Invalid,
			AssertErr:    assert.Error,
		},
		"invalid cert": {
			CertFile: "sensitive-voting.crt",
			Modify: func(c *x509.Certificate) *x509.Certificate {
				c.UnknownExtKeyUsage = nil
				return c
			},
			ExpectedType: cppki.Invalid,
			AssertErr:    assert.Error,
		},
	}
	for name, tc := range testCases {
		name, tc := name, tc
		t.Run(name, func(t *testing.T) {
			t.Parallel()
			validCert, err := cppki.ReadPEMCerts(filepath.Join("./testdata", tc.CertFile))
			require.NoError(t, err)
			input := validCert[0]
			if tc.Modify != nil {
				input = tc.Modify(input)
			}
			ct, err := cppki.ValidateCert(input)
			tc.AssertErr(t, err)
			assert.Equal(t, tc.ExpectedType, ct)
		})
	}
}

func TestValidateChain(t *testing.T) {
	validChainFile := "./testdata/verifychain/ISD1-ASff00_0_110.pem"
	testCases := map[string]struct {
		modify    func([]*x509.Certificate) []*x509.Certificate
		assertErr assert.ErrorAssertionFunc
	}{
		"invalid legth less than two": {
			modify: func(c []*x509.Certificate) []*x509.Certificate {
				return c[:1]
			},
			assertErr: assert.Error,
		},
		"invalid legth more than two": {
			modify: func(c []*x509.Certificate) []*x509.Certificate {
				c = append(c, c[0])
				return c
			},
			assertErr: assert.Error,
		},
		"invalid first cert": {
			modify: func(c []*x509.Certificate) []*x509.Certificate {
				c[0].KeyUsage = 0
				return c
			},
			assertErr: assert.Error,
		},
		"invalid type of first": {
			modify: func(c []*x509.Certificate) []*x509.Certificate {
				c[0] = c[1]
				return c
			},
			assertErr: assert.Error,
		},
		"invalid second cert": {
			modify: func(c []*x509.Certificate) []*x509.Certificate {
				c[1].KeyUsage = 0
				return c
			},
			assertErr: assert.Error,
		},
		"invalid type of second": {
			modify: func(c []*x509.Certificate) []*x509.Certificate {
				c[1] = c[0]
				return c
			},
			assertErr: assert.Error,
		},
		"invalid period": {
			modify: func(c []*x509.Certificate) []*x509.Certificate {
				c[1].NotBefore = c[0].NotBefore.Add(time.Minute)
				return c
			},
			assertErr: assert.Error,
		},
		"valid": {
			modify:    func(c []*x509.Certificate) []*x509.Certificate { return c },
			assertErr: assert.NoError,
		},
	}
	for name, tc := range testCases {
		name, tc := name, tc
		t.Run(name, func(t *testing.T) {
			t.Parallel()
			chain, err := cppki.ReadPEMCerts(validChainFile)
			require.NoError(t, err)
			input := tc.modify(chain)
			tc.assertErr(t, cppki.ValidateChain(input))
		})
	}
}

func TestVerifyChain(t *testing.T) {
	// testadata files generated with scion-pki:
	/*
		scion-pki testcrypto -t topology/default.topo -o gen
		cp gen/ISD1/ISD1-B1-S1.trc go/lib/scrypto/cppki/testdata/verifychain
		cp gen/ISD2/ISD2-B1-S1.trc go/lib/scrypto/cppki/testdata/verifychain
		cp gen/ISD1/ASff00_0_111/certs/ISD1-ASff00_0_111.pem \
			go/lib/scrypto/cppki/testdata/verifychain
		cp gen/ISD1/ASff00_0_110/certs/ISD1-ASff00_0_110.pem \
			go/lib/scrypto/cppki/testdata/verifychain
		cp gen/ISD2/ASff00_0_210/certs/ISD2-ASff00_0_210.pem \
			go/lib/scrypto/cppki/testdata/verifychain
	*/

	trc := loadTRC(t, "testdata/verifychain/ISD1-B1-S1.trc")
	trc2 := loadTRC(t, "testdata/verifychain/ISD2-B1-S1.trc")
	clientChain := xtest.LoadChain(t, "testdata/verifychain/ISD1-ASff00_0_111.pem")
	issuerChain := xtest.LoadChain(t, "testdata/verifychain/ISD1-ASff00_0_110.pem")
	isd2Chain := xtest.LoadChain(t, "testdata/verifychain/ISD2-ASff00_0_210.pem")
	invalidIntermediate := append([]*x509.Certificate{}, clientChain[0], isd2Chain[1])
	invalidTRC := trc
	invalidTRC.TRC.Certificates = append(trc.TRC.Certificates, &x509.Certificate{})

	testCases := map[string]struct {
		chain     []*x509.Certificate
		opts      cppki.VerifyOptions
		assertErr assert.ErrorAssertionFunc
	}{
		"valid client": {
			chain: clientChain,
			opts: cppki.VerifyOptions{
				TRC:         []*cppki.TRC{&trc.TRC},
				CurrentTime: clientChain[0].NotBefore.Add(time.Hour),
			},
			assertErr: assert.NoError,
		},
		"valid issuer": {
			chain: issuerChain,
			opts: cppki.VerifyOptions{
				TRC:         []*cppki.TRC{&trc.TRC},
				CurrentTime: issuerChain[0].NotBefore.Add(time.Hour),
			},
			assertErr: assert.NoError,
		},
		"missing TRC": {
			chain: clientChain,
			opts: cppki.VerifyOptions{
				CurrentTime: clientChain[0].NotBefore.Add(time.Hour),
			},
			assertErr: assert.Error,
		},
		"empty TRC slice": {
			chain: clientChain,
			opts: cppki.VerifyOptions{
				TRC:         []*cppki.TRC{},
				CurrentTime: clientChain[0].NotBefore.Add(time.Hour),
			},
			assertErr: assert.Error,
		},
		"zero TRC": {
			chain: clientChain,
			opts: cppki.VerifyOptions{
				TRC:         []*cppki.TRC{{}},
				CurrentTime: clientChain[0].NotBefore.Add(time.Hour),
			},
			assertErr: assert.Error,
		},
		"empty roots in TRC": {
			chain: clientChain,
			opts: cppki.VerifyOptions{
				TRC:         []*cppki.TRC{{Quorum: 2}},
				CurrentTime: clientChain[0].NotBefore.Add(time.Hour),
			},
			assertErr: assert.Error,
		},
		"invalid chain": {
			chain: clientChain[:1],
			opts: cppki.VerifyOptions{
				TRC:         []*cppki.TRC{&trc.TRC},
				CurrentTime: clientChain[0].NotBefore.Add(time.Hour),
			},
			assertErr: assert.Error,
		},
		"invalid TRC": {
			chain: clientChain,
			opts: cppki.VerifyOptions{
				TRC:         []*cppki.TRC{&invalidTRC.TRC},
				CurrentTime: clientChain[0].NotBefore.Add(time.Hour),
			},
			assertErr: assert.Error,
		},
		"valid and valid TRC": {
			chain: clientChain,
			opts: cppki.VerifyOptions{
				TRC:         []*cppki.TRC{&trc.TRC, &trc.TRC},
				CurrentTime: clientChain[0].NotBefore.Add(time.Hour),
			},
			assertErr: assert.NoError,
		},
		"valid and invalid TRC": {
			chain: clientChain,
			opts: cppki.VerifyOptions{
				TRC:         []*cppki.TRC{&trc.TRC, &invalidTRC.TRC},
				CurrentTime: clientChain[0].NotBefore.Add(time.Hour),
			},
			assertErr: assert.NoError,
		},
		"invalid and valid TRC": {
			chain: clientChain,
			opts: cppki.VerifyOptions{
				TRC:         []*cppki.TRC{&invalidTRC.TRC, &trc.TRC},
				CurrentTime: clientChain[0].NotBefore.Add(time.Hour),
			},
			assertErr: assert.NoError,
		},
		"invalid and invalid TRC": {
			chain: clientChain,
			opts: cppki.VerifyOptions{
				TRC:         []*cppki.TRC{&invalidTRC.TRC, &invalidTRC.TRC},
				CurrentTime: clientChain[0].NotBefore.Add(time.Hour),
			},
			assertErr: assert.Error,
		},
		"invalid time before": {
			chain: clientChain,
			opts: cppki.VerifyOptions{
				TRC:         []*cppki.TRC{&trc.TRC},
				CurrentTime: clientChain[0].NotBefore.Add(-time.Hour),
			},
			assertErr: assert.Error,
		},
		"invalid time after": {
			chain: clientChain,
			opts: cppki.VerifyOptions{
				TRC:         []*cppki.TRC{&trc.TRC},
				CurrentTime: clientChain[0].NotAfter.Add(time.Hour),
			},
			assertErr: assert.Error,
		},
		"wrong TRC": {
			chain: clientChain,
			opts: cppki.VerifyOptions{
				TRC:         []*cppki.TRC{&trc2.TRC},
				CurrentTime: clientChain[0].NotBefore.Add(time.Hour),
			},
			assertErr: assert.Error,
		},
		"invalid intermediate": {
			chain: invalidIntermediate,
			opts: cppki.VerifyOptions{
				TRC:         []*cppki.TRC{&trc.TRC},
				CurrentTime: invalidIntermediate[0].NotBefore.Add(time.Hour),
			},
			assertErr: assert.Error,
		},
	}
	for name, tc := range testCases {
		name, tc := name, tc
		t.Run(name, func(t *testing.T) {
			t.Parallel()
			err := cppki.VerifyChain(tc.chain, tc.opts)
			tc.assertErr(t, err)
		})
	}
}

func loadTRC(t *testing.T, file string) cppki.SignedTRC {
	t.Helper()
	rawTRC, err := os.ReadFile(file)
	require.NoError(t, err)
	trc, err := cppki.DecodeSignedTRC(rawTRC)
	require.NoError(t, err)
	return trc
}


text:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Q42.Mvc.XsltViewEngine
{
  internal static class DistinctByExtension
  {
    public static IEnumerable<TSource> DistinctBy<TSource, TKey>
     (this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
    {
      HashSet<TKey> knownKeys = new HashSet<TKey>();
      foreach (TSource element in source)
      {
        if (knownKeys.Add(keySelector(element)))
        {
          yield return element;
        }
      }
    }
  }
}


text:
const commentController = require('./comment')
const userController = require('./user')
const categoryController = require('./category')
const articleController = require('./article')

module.exports = {
  comment: commentController,
  user: userController,
  category: categoryController,
  article: articleController
}


text:
using System;
using System.Linq;
using System.Threading.Tasks;

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

using ExaminingEntityFramework.Lib;

using AppTypes = ExaminingEntityFramework.Lib.AppTypes;
using EntityTypes = ExaminingEntityFramework.Lib.EntityTypes;

namespace ExaminingEntityFramework
{
    public class Experiments
    {
        #region Static

        public static void SubMain(IServiceProvider serviceProvider)
        {
            var databaseContext = serviceProvider.GetRequiredService<DatabaseContext>();

            //MappingExperiments.SubMain(databaseContext);

            //Experiments.TestLogging(serviceProvider);
            //Experiments.DoesEFUpdateAllTouchedOrOnlyChangedFields(databaseContext).Wait();
            //Experiments.DoesLabelNeedAddingToContext(databaseContext).Wait();
            //Experiments.WillSubEntityBeFoundLocally(databaseContext);
            Experiments.InPlaceOrNew(databaseContext);
        }

        /// <summary>
        /// Result: Expected. The fluent API builds new IQueryable (query specification) instances, and does now work in place.
        /// Does using the fluent API for IQueryable result in in-place modifications to the IQueryable, or does it create new instances of the IQueryable?
        /// Expected: New instances.
        /// </summary>
        private static void InPlaceOrNew(DatabaseContext databaseContext)
        {
            var queryBase = databaseContext.EntityAs;

            var query1 = queryBase;
            query1.Where(x => x.Value2 == 5); // Resulting query is thrown away.

            var results1 = query1.ToList(); // No where clause!

            var query2 = queryBase.Where(x => x.Value2 == 5);

            var results2 = query2.ToList(); // Has where clause.
        }

        /// <summary>
        /// Result: Expected. Entities added locally are NOT found by querying the set!
        ///
        /// Expected: Entities that have been added locally will NOT be found by querying a set. Only entities that have been saved to the database will be found.
        /// </summary>
        /// <param name="databaseContext"></param>
        private static void WillSubEntityBeFoundLocally(DatabaseContext databaseContext)
        {
            databaseContext.ClearDatabase();

            var eventAName = @"EventA";

            var eventType = new EntityTypes.EventType()
            {
                Name = eventAName,
            };

            databaseContext.Add(eventType);

            var eventTypeA = databaseContext.EventTypes.Acquire(x => x.Name == eventAName, () =>
            {
                var newEventType = new EntityTypes.EventType()
                {
                    Name = eventAName,
                };
                return newEventType;
            });
        }

        /// <summary>
        /// Result: Expected. Addition entities must be added to the context.
        /// Does a label addition entity (an entity that references an entity) need to be added to the database context? Or is just referencing a tracked entity enough to make an entity tracked?
        /// Expected: No, the label is a separate entity and thus must be added to the context independently.
        /// </summary>
        private static async Task DoesLabelNeedAddingToContext(DatabaseContext databaseContext)
        {
            await databaseContext.ClearDatabaseAsync();

            var newA = new EntityTypes.EntityA()
            {
                GUID = Guid.NewGuid(),
                Value1 = @"Two",
                Value2 = 2,
            };

            //databaseContext.EntityAs.Add(newA); // Either works.
            databaseContext.Add(newA); // Either works. This is preferred because it is shorter!

            var newALabel = new EntityTypes.EntityALabel()
            {
                EntityA = newA,
            };

            databaseContext.Add(newALabel); // Required if you want the label entity to be added to the database. Note! Results in TWO queries being made to the DB.

            await databaseContext.SaveChangesAsync();
        }

        /// <summary>
        /// Result: FALSE! Only the modified field was updated in the databse.
        /// EF keeps track of changes that occurred to entities (as in, changes to the values of fields of entity objects).
        /// Upon SaveChanges(), EF updates all changed fields in the database.
        /// The question is, does it update ONLY fields that have been changed, or all fields that have been touched (changed).
        /// Expected: All touched fields.
        ///
        /// This is great, it means that only fields with changed values will be updated in the database.
        /// </summary>
        private static async Task DoesEFUpdateAllTouchedOrOnlyChangedFields(DatabaseContext databaseContext)
        {
            await databaseContext.ClearDatabaseAsync();

            var appType1 = new AppTypes.EntityA()
            {
                GUID = Guid.NewGuid(),
                Value1 = @"String",
                Value2 = 5,
            };

            var entityType1 = appType1.ToEntityType();

            databaseContext.Add(entityType1);
            await databaseContext.SaveChangesAsync();

            appType1.Value1 = @"New String";

            entityType1.UpdateFrom(appType1);

            await databaseContext.SaveChangesAsync(); // Information-level logging shows that only Value1 was included in the query!
        }

        private static void TestLogging(IServiceProvider serviceProvider)
        {
            var logger = serviceProvider.GetRequiredService<ILogger<Experiments>>();

            logger.LogDebug(@"Hello world!");
            logger.LogInformation(@"Hello world!");
            logger.LogWarning(@"Hello world!");

            System.Threading.Thread.Sleep(1000); // Required due to console logging being asynchronous on another thread.
        }

        #endregion
    }
}


text:
{% for child in item.children %}
  {% if child.visible %}

      {% if not "divider" in child.classes and not "dropdown-header" in child.classes %}

          {{ child.title }}

      {% else %}
        {{ child.title }}
      {% endif %}

  {% endif %}
{% endfor %}


text:
import { mount } from "@vue/test-utils";
import veTable from "@/ve-table";
import veIcon from "@/ve-table";
import { later } from "../util";

describe("veTable header filter", () => {
    const TABLE_DATA = [
        {
            name: "John",
            date: "1900-05-20",
            hobby: "coding and coding repeat",
            address: "No.1 Century Avenue, Shanghai",
            rowkey: 0,
        },
        {
            name: "Dickerson",
            date: "1910-06-20",
            hobby: "coding and coding repeat",
            address: "No.1 Century Avenue, Beijing",
            rowkey: 1,
        },
        {
            name: "Larsen",
            date: "2000-07-20",
            hobby: "coding and coding repeat",
            address: "No.1 Century Avenue, Chongqing",
            rowkey: 2,
        },
        {
            name: "Geneva",
            date: "2010-08-20",
            hobby: "coding and coding repeat",
            address: "No.1 Century Avenue, Xiamen",
            rowkey: 3,
        },
        {
            name: "Jami",
            date: "2020-09-20",
            hobby: "coding and coding repeat",
            address: "No.1 Century Avenue, Shenzhen",
            rowkey: 4,
        },
    ];

    const mockFilterFn = jest.fn();

    // filter single
    const TABLE_COLUMNS_FILTER_SINGLE = [
        {
            field: "name",
            key: "a",
            title: "Name",
            align: "left",
            width: "15%",
        },
        {
            field: "date",
            key: "b",
            title: "Date",
            align: "left",
            width: "15%",
            // filter
            filter: {
                filterList: [
                    { value: 0, label: "1900-05-20", selected: false },
                    { value: 1, label: "1910-06-20", selected: false },
                    { value: 2, label: "2000-07-20", selected: false },
                    { value: 3, label: "2010-08-20", selected: false },
                    { value: 4, label: "2020-09-20", selected: false },
                ],
                // filter confirm hook
                filterConfirm: (filterList) => {
                    mockFilterFn(filterList);
                },
                // filter reset hook
                filterReset: (filterList) => {
                    mockFilterFn(filterList);
                },
            },
        },
        {
            field: "hobby",
            key: "c",
            title: "Hobby",
            align: "center",
            width: "30%",
        },
        {
            field: "address",
            key: "d",
            title: "Address",
            align: "left",
            width: "40%",
        },
    ];

    // filter multiple
    const TABLE_COLUMNS_FILTER_MULTIPLE = [
        {
            field: "name",
            key: "a",
            title: "Name",
            align: "left",
            width: "15%",
            // filter
            filter: {
                filterList: [
                    { value: 0, label: "John", selected: true },
                    { value: 1, label: "Dickerson", selected: false },
                    { value: 2, label: "Larsen", selected: false },
                    { value: 3, label: "Geneva", selected: false },
                    { value: 4, label: "Jami", selected: false },
                ],
                isMultiple: true,
                // filter confirm hook
                filterConfirm: (filterList) => {
                    mockFilterFn(filterList);
                },
                // filter reset hook
                filterReset: (filterList) => {
                    mockFilterFn(filterList);
                },
                // max height
                maxHeight: 120,
            },
        },
        {
            field: "date",
            key: "b",
            title: "Date",
            align: "left",
            width: "15%",
        },
        {
            field: "hobby",
            key: "c",
            title: "Hobby",
            align: "center",
            width: "30%",
        },
        {
            field: "address",
            key: "d",
            title: "Address",
            align: "left",
            width: "40%",
        },
    ];

    // filter custom icon
    const TABLE_COLUMNS_CUSTOM_ICON = [
        {
            field: "name",
            key: "a",
            title: "Name",
            align: "left",
            width: "15%",
        },
        {
            field: "date",
            key: "b",
            title: "Date",
            align: "left",
            width: "15%",
            // filter
            filter: {
                filterList: [
                    { value: 0, label: "1900-05-20", selected: false },
                    { value: 1, label: "1910-06-20", selected: false },
                    { value: 2, label: "2000-07-20", selected: false },
                    { value: 3, label: "2010-08-20", selected: false },
                    { value: 4, label: "2020-09-20", selected: false },
                ],
                // filter confirm hook
                filterConfirm: (filterList) => {
                    const labels = filterList
                        .filter((x) => x.selected)
                        .map((x) => x.label);
                    this.searchByDateField(labels);
                },
                // filter reset hook
                filterReset: (filterList) => {
                    this.searchByDateField([]);
                },
                // custom filter icon
                filterIcon: (h) => {
                    return <veIcon name="search" />;
                },
            },
        },
        {
            field: "hobby",
            key: "c",
            title: "Hobby",
            align: "center",
            width: "30%",
        },
        {
            field: "address",
            key: "d",
            title: "Address",
            align: "left",
            width: "40%",
        },
    ];

    it("render single filter", () => {
        const wrapper = mount(veTable, {
            propsData: {
                columns: TABLE_COLUMNS_FILTER_SINGLE,
                tableData: TABLE_DATA,
                rowKeyFieldName: "rowkey",
            },
        });

        expect(wrapper.html()).toMatchSnapshot();
    });

    it("render multiple filter", () => {
        const wrapper = mount(veTable, {
            propsData: {
                columns: TABLE_COLUMNS_FILTER_MULTIPLE,
                tableData: TABLE_DATA,
                rowKeyFieldName: "rowkey",
            },
        });

        expect(wrapper.html()).toMatchSnapshot();
    });

    it("render filter custom icon", () => {
        const wrapper = mount(veTable, {
            propsData: {
                columns: TABLE_COLUMNS_CUSTOM_ICON,
                tableData: TABLE_DATA,
                rowKeyFieldName: "rowkey",
            },
        });

        expect(wrapper.html()).toMatchSnapshot();
    });

    it("single filter", async () => {
        const wrapper = mount(veTable, {
            propsData: {
                columns: TABLE_COLUMNS_FILTER_SINGLE,
                tableData: TABLE_DATA,
                rowKeyFieldName: "rowkey",
            },
        });

        const callBackConfirmData = [
            { value: 0, label: "1900-05-20", selected: true },
            { value: 1, label: "1910-06-20", selected: false },
            { value: 2, label: "2000-07-20", selected: false },
            { value: 3, label: "2010-08-20", selected: false },
            { value: 4, label: "2020-09-20", selected: false },
        ];

        const callBackResetData = [
            { value: 0, label: "1900-05-20", selected: false },
            { value: 1, label: "1910-06-20", selected: false },
            { value: 2, label: "2000-07-20", selected: false },
            { value: 3, label: "2010-08-20", selected: false },
            { value: 4, label: "2020-09-20", selected: false },
        ];

        // 改变选项
        wrapper.findAll(".ve-dropdown-items-li").at(0).trigger("click");

        await later();

        // confirm btn click
        wrapper.findAll(".ve-dropdown-operation-item").at(1).trigger("click");

        await later();

        expect(mockFilterFn).toBeCalled();
        expect(mockFilterFn).toHaveBeenCalledWith(callBackConfirmData);

        // reset btn click
        wrapper.findAll(".ve-dropdown-operation-item").at(0).trigger("click");

        await later();

        expect(mockFilterFn).toBeCalled();
        expect(mockFilterFn).toHaveBeenCalledWith(callBackResetData);
    });

    it("multiple filter", async () => {
        const wrapper = mount(veTable, {
            propsData: {
                columns: TABLE_COLUMNS_FILTER_MULTIPLE,
                tableData: TABLE_DATA,
                rowKeyFieldName: "rowkey",
            },
        });

        const callBackConfirmData = [
            { value: 0, label: "John", selected: true },
            { value: 1, label: "Dickerson", selected: true },
            { value: 2, label: "Larsen", selected: false },
            { value: 3, label: "Geneva", selected: false },
            { value: 4, label: "Jami", selected: false },
        ];

        const callBackResetData = [
            { value: 0, label: "John", selected: false },
            { value: 1, label: "Dickerson", selected: false },
            { value: 2, label: "Larsen", selected: false },
            { value: 3, label: "Geneva", selected: false },
            { value: 4, label: "Jami", selected: false },
        ];

        // 改变选项
        wrapper.findAll(".ve-checkbox").at(1).trigger("click");

        await later();

        // confirm btn click
        wrapper.findAll(".ve-dropdown-operation-item").at(1).trigger("click");

        await later();

        expect(mockFilterFn).toBeCalled();
        expect(mockFilterFn).toHaveBeenCalledWith(callBackConfirmData);

        // reset btn click
        wrapper.findAll(".ve-dropdown-operation-item").at(0).trigger("click");

        await later();

        expect(mockFilterFn).toBeCalled();
        expect(mockFilterFn).toHaveBeenCalledWith(callBackResetData);
    });
});


text:
export interface IDashboardCategory {
  hierarchy_number: string;
  id: number;
  parent: string;
  item_name: string;
  description?: string;
  keyword_content?: string[];
  query_string?: string;
  icon?: string;
  bg_icon?: string;
  children?: IDashboardCategory[];
}


text:
FROM openfaas/classic-watchdog:0.18.8 as watchdog

FROM node:6.9.1-alpine

COPY --from=watchdog /fwatchdog /usr/bin/fwatchdog
RUN chmod +x /usr/bin/fwatchdog

WORKDIR /application/

COPY package.json .

RUN npm i
COPY handler.js .

USER 1000

ENV fprocess="node handler.js"

HEALTHCHECK --interval=1s CMD [ -e /tmp/.lock ] || exit 1

CMD ["fwatchdog"]


text:
package com.amazonaws.services.ecs.model.transform;

import javax.annotation.Generated;

import com.amazonaws.SdkClientException;
import com.amazonaws.services.ecs.model.*;

import com.amazonaws.protocol.*;
import com.amazonaws.annotation.SdkInternalApi;

/**
 * EFSAuthorizationConfigMarshaller
 */
@Generated("com.amazonaws:aws-java-sdk-code-generator")
@SdkInternalApi
public class EFSAuthorizationConfigMarshaller {

    private static final MarshallingInfo<String> ACCESSPOINTID_BINDING = MarshallingInfo.builder(MarshallingType.STRING)
            .marshallLocation(MarshallLocation.PAYLOAD).marshallLocationName("accessPointId").build();
    private static final MarshallingInfo<String> IAM_BINDING = MarshallingInfo.builder(MarshallingType.STRING).marshallLocation(MarshallLocation.PAYLOAD)
            .marshallLocationName("iam").build();

    private static final EFSAuthorizationConfigMarshaller instance = new EFSAuthorizationConfigMarshaller();

    public static EFSAuthorizationConfigMarshaller getInstance() {
        return instance;
    }

    /**
     * Marshall the given parameter object.
     */
    public void marshall(EFSAuthorizationConfig eFSAuthorizationConfig, ProtocolMarshaller protocolMarshaller) {

        if (eFSAuthorizationConfig == null) {
            throw new SdkClientException("Invalid argument passed to marshall(...)");
        }

        try {
            protocolMarshaller.marshall(eFSAuthorizationConfig.getAccessPointId(), ACCESSPOINTID_BINDING);
            protocolMarshaller.marshall(eFSAuthorizationConfig.getIam(), IAM_BINDING);
        } catch (Exception e) {
            throw new SdkClientException("Unable to marshall request to JSON: " + e.getMessage(), e);
        }
    }

}


text:
package com.openxc.messages.formatters;

import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;

import com.openxc.BinaryMessages;
import com.openxc.messages.CanMessage;
import com.openxc.messages.Command;
import com.openxc.messages.CommandResponse;
import com.openxc.messages.DiagnosticRequest;
import com.openxc.messages.DiagnosticResponse;
import com.openxc.messages.EventedSimpleVehicleMessage;
import com.openxc.messages.NamedVehicleMessage;
import com.openxc.messages.SerializationException;
import com.openxc.messages.SimpleVehicleMessage;
import com.openxc.messages.VehicleMessage;

@RunWith(RobolectricTestRunner.class)
public abstract class AbstractFormatterTestBase {

    protected abstract void serializeDeserializeAndCheckEqual(
            VehicleMessage message);

    @Test
    public void serializeFailedDiagnosticResponse() {
        int id = 42;
        int bus = 1;
        int mode = 2;
        int pid = 4;
        byte[] payload = new byte[] { 1, 2, 3, 4, 5, 6, 7 };
        double value = 42.0;
        serializeDeserializeAndCheckEqual(new DiagnosticResponse(bus, id, mode,
                pid, payload, null, value));
    }

    @Test
    public void serializeDiagnosticResponse() {
        serializeDeserializeAndCheckEqual(new DiagnosticResponse(
                    1, 2, 3, 4,
                    new byte[]{1,2,3,4}, null, 0.0));
    }

    @Test
    public void serializeDiagnosticResponseWithValue() {
        serializeDeserializeAndCheckEqual(new DiagnosticResponse(
                    1, 2, 3, 4,
                    new byte[]{1,2,3,4}, null, 42.0));
    }

    @Test
    public void serializeCommandResponse() {
        serializeDeserializeAndCheckEqual(new CommandResponse(
                    Command.CommandType.DEVICE_ID, true, ""));
    }

    @Test
    public void serializeCommandResponseWithMessage() {
        serializeDeserializeAndCheckEqual(new CommandResponse(
                    Command.CommandType.DEVICE_ID, true, "bar"));
        serializeDeserializeAndCheckEqual(new CommandResponse(
                    Command.CommandType.VERSION, true, "bar"));
    }

    @Test
    public void serializeCommand() {
        serializeDeserializeAndCheckEqual(new Command(
                    Command.CommandType.VERSION));
    }

    @Test
    public void serializeCommandWithDiagnosticRequest() {
        DiagnosticRequest request = new DiagnosticRequest(1, 2, 3, 4);
        request.setFrequency(0.0);
        request.setName("");
        request.setPayload(new byte[0]);
        serializeDeserializeAndCheckEqual(new Command(request, "add"));
    }

    @Test
    public void serializeCommandWithDiagnosticRequestNoPid() {
        DiagnosticRequest request = new DiagnosticRequest(1, 2, 3, 0);
        request.setFrequency(0.0);
        request.setName("");
        request.setPayload(new byte[0]);
        serializeDeserializeAndCheckEqual(new Command(request, "add"));
    }

    @Test
    public void serializeCanMessage() {
        serializeDeserializeAndCheckEqual(new CanMessage(1, 2, new byte[]{1,2,3,4}));
    }

    @Test
    public void serializeSimpleMessage() {
        serializeDeserializeAndCheckEqual(new SimpleVehicleMessage("foo", "bar"));
        serializeDeserializeAndCheckEqual(new SimpleVehicleMessage("foo", false));
        serializeDeserializeAndCheckEqual(new SimpleVehicleMessage("foo", 42.0));
    }

    @Test
    public void serializeEventedSimpleMessage() {
        serializeDeserializeAndCheckEqual(new EventedSimpleVehicleMessage(
                    "foo", "bar", "baz"));
        serializeDeserializeAndCheckEqual(new EventedSimpleVehicleMessage(
                    "foo", "bar", false));
        serializeDeserializeAndCheckEqual(new EventedSimpleVehicleMessage(
                    "foo", "bar", 42.0));
    }

    @Test
    public void serializeNamedMessage() {
        serializeDeserializeAndCheckEqual(new NamedVehicleMessage("foo"));
    }

    @Test
    public void serializeDiagnosticRequestWithOptional() {
        DiagnosticRequest request = new DiagnosticRequest(1, 2, 3, 4);
        request.setPayload(new byte[]{1,2,3,4});
        request.setMultipleResponses(false);
        request.setFrequency(2.0);
        request.setName("foo");
        serializeDeserializeAndCheckEqual(new Command(request, "add"));
    }

    @Test(expected=SerializationException.class)
    public void serializeEmptyVehicleMessage()
            throws SerializationException {
        BinaryFormatter.serialize(new VehicleMessage());
    }
}


text:
'use strict';

// Transform styles with PostCSS
module.exports = function ($, config, gulp, merge) { return function () {
  var variables = require('../app/themes/' + config.appTheme + '/variables');
  var postcssApply = require('postcss-apply');
  var postcssAutoprefixer = require('autoprefixer');
  var postcssCssMqpacker = require('css-mqpacker');
  var postcssCustomMedia = require('postcss-custom-media');
  var postcssCustomProperties = require('postcss-custom-properties');
  var postcssDiscardEmpty = require('postcss-discard-empty');
  var postcssImport = require('postcss-import');
  var postcssNesting = require('postcss-nesting');
  var postcssReporter = require('postcss-reporter');
  var postcssSimpleVars = require('postcss-simple-vars');
  var postcssPlugins = [
    // Transform @import rules by inlining content
    postcssImport({
      path: [
        'app/elements',
        'app/themes/' + config.appTheme
      ]
    }),
    // Sass-like variables
    postcssSimpleVars({ variables: variables.global }),
    // Transform W3C CSS Custom Media Queries
    postcssCustomMedia(),
    // Unwrap nested rules, following CSS Nesting Module Level 3 specification
    postcssNesting(),
    // Pack same CSS media query rules into one media query rule
    postcssCssMqpacker(),
    // Add vendor prefixes to CSS rules using values from "Can I Use"
    postcssAutoprefixer(config.autoprefixer),
    // Remove empty rules, selectors & media queries
    postcssDiscardEmpty(),
    postcssReporter({
      clearMessages: true
    })
  ];

  var theme = gulp.src([
      'app/themes/' + config.appTheme + '/*.html',
      '!app/themes/' + config.appTheme + '/icons.html'
    ])
    .pipe($.plumber({
      handleError: function (error) {
        console.log(error);
        // For gulp.watch
        // http://blog.ibangspacebar.com/handling-errors-with-gulp-watch-and-gulp-plumber/
        this.emit('end');
      }
    }))
    .pipe($.sourcemaps.init())
    .pipe($.htmlPostcss(postcssPlugins))
    .pipe($.sourcemaps.write('.'))
    .pipe(gulp.dest('.tmp/themes/' + config.appTheme))
    .pipe($.size({title: 'Copy transformed styles to .tmp/themes dir:'}))
    .pipe(gulp.dest('dist/themes/' + config.appTheme))
    .pipe($.size({title: 'Copy transformed styles to dist/themes dir:'}));

  var elements = gulp.src([
      '.tmp/elements/**/*.html'
    ])
    .pipe($.plumber({
      handleError: function (error) {
        console.log(error);
        // For gulp.watch
        // http://blog.ibangspacebar.com/handling-errors-with-gulp-watch-and-gulp-plumber/
        this.emit('end');
      }
    }))
    .pipe($.sourcemaps.init())
    .pipe($.htmlPostcss(postcssPlugins))
    .pipe($.sourcemaps.write('.'))
    .pipe(gulp.dest('.tmp/elements'))
    .pipe($.size({title: 'Copy transformed styles to .tmp/elements dir:'}))
    .pipe(gulp.dest('dist/elements'))
    .pipe($.size({title: 'Copy transformed styles to dist/elements dir:'}));

    var index = gulp.src([
        '.tmp/index.html'
      ])
      .pipe($.plumber({
        handleError: function (error) {
          console.log(error);
          // For gulp.watch
          // http://blog.ibangspacebar.com/handling-errors-with-gulp-watch-and-gulp-plumber/
          this.emit('end');
        }
      }))
      .pipe($.sourcemaps.init())
      .pipe($.htmlPostcss([
        // Transform @import rules by inlining content
        postcssImport({
          path: [
            'app/themes/' + config.appTheme
          ]
        }),
        // Sass-like variables
        postcssSimpleVars({ variables: variables.global }),
        // Plugin enabling custom properties sets references - Polymer mixins
        postcssApply(),
        // Transform W3C CSS Custom Properties for variables syntax to more compatible CSS
        postcssCustomProperties(),
        // Transform W3C CSS Custom Media Queries
        postcssCustomMedia(),
        // Unwrap nested rules, following CSS Nesting Module Level 3 specification
        postcssNesting(),
        // Pack same CSS media query rules into one media query rule
        postcssCssMqpacker(),
        // Add vendor prefixes to CSS rules using values from "Can I Use"
        postcssAutoprefixer(config.autoprefixer),
        // Remove empty rules, selectors & media queries
        postcssDiscardEmpty(),
        postcssReporter({
          clearMessages: true
        })
      ]))
      .pipe($.sourcemaps.write('.'))
      .pipe(gulp.dest('.tmp'))
      .pipe($.size({title: 'Copy transformed styles to .tmp dir:'}))
      .pipe(gulp.dest('dist'))
      .pipe($.size({title: 'Copy transformed styles to dist dir:'}));

  return merge(theme, elements, index);
};};