text:
package org.simplity.kernel.db;

import org.simplity.kernel.ApplicationError;
import org.simplity.kernel.comp.Component;
import org.simplity.kernel.comp.ComponentManager;
import org.simplity.kernel.comp.ComponentType;
import org.simplity.kernel.comp.ValidationContext;
import org.simplity.kernel.data.DataSheet;
import org.simplity.kernel.data.FieldsInterface;
import org.simplity.kernel.dm.Record;
import org.simplity.service.ServiceContext;

/**
 * A stored procedure that can be invoked from app layer.
 *
 * @author simplity.org
 *
 */
public class StoredProcedure implements Component {
	private static final ComponentType MY_TYPE = ComponentType.SP;
	/**
	 * unique within a module. this is the name of this component, and not the
	 * actual name of procedure in the RDBMS
	 */
	String name;

	/**
	 * module + name is unique
	 */
	String moduleName;

	/**
	 * actual name of the procedure, using which it can be invoked
	 */
	String procedureName;

	/**
	 * parameters in the same order as in the actual definition. Note that their
	 * name is meant to pick up values, and need not match the name as in db
	 * design.
	 */
	ProcedureParameter[] parameters;

	/**
	 * if you are going to use the returned value, then it should be the first
	 * in in parameters list
	 */
	boolean firstParameterIsForReturnedValue;

	/**
	 * output records, in case you are returning one or more record sets from
	 * this stored procedure
	 */
	String[] outputRecordNames;
	/**
	 * we need the pseudo prepared statement for this store procedure of the
	 * form {call ProcedureName(?,?,...)}
	 */
	private String sql;

	/**
	 *
	 * @return unqualified name
	 */
	@Override
	public String getSimpleName() {
		return this.name;
	}

	/**
	 *
	 * @return fully qualified name typically module.name
	 */
	@Override
	public String getQualifiedName() {
		return this.moduleName + '.' + this.name;
	}

	/**
	 *
	 * @param inSheet
	 * @param outSheet
	 * @param driver
	 * @param ctx
	 * @return outputSheets
	 */
	public DataSheet[] execute(FieldsInterface inSheet,
			FieldsInterface outSheet, DbDriver driver, ServiceContext ctx) {
		DataSheet[] outSheets = null;
		int nbrSheets = this.getNbrOutputRecords();
		if (nbrSheets > 0) {
			outSheets = new DataSheet[nbrSheets];
			for (int i = 0; i < nbrSheets; i++) {
				Record record = ComponentManager
						.getRecord(this.outputRecordNames[i]);
				outSheets[i] = record.createSheet(false, false);
			}
		}
		driver.executeSp(this.sql, inSheet, outSheet, this.parameters,
				outSheets, ctx);
		return outSheets;
	}

	@Override
	public void getReady() {
		int totalParms = 0;
		if (this.parameters != null) {
			totalParms = this.parameters.length;
			int i = 0;
			for (ProcedureParameter p : this.parameters) {
				i++;
				p.getReady(i);
			}
		}
		StringBuilder sbf = new StringBuilder("{");
		if (this.firstParameterIsForReturnedValue) {
			if (this.parameters == null) {
				throw new ApplicationError(
						"Stored Procedure "
								+ this.getQualifiedName()
								+ " sets firstParameterIsForReturnedValue=true but no parameters are specified. Ensure that first parameter is defined as an output parameter");
			}
			if (this.parameters[0].inOutType != InOutType.OUTPUT) {
				throw new ApplicationError(
						"Stored Procedure "
								+ this.getQualifiedName()
								+ " sets firstParameterIsForReturnedValue=true but the first parameter is not of type OUTPUT");
			}
			sbf.append("? = ");
			totalParms--;
		}
		sbf.append("call ");
		sbf.append(this.procedureName).append('(');
		if (totalParms > 0) {
			sbf.append('?');
			while (--totalParms > 0) {
				sbf.append(",?");
			}
		}
		sbf.append(")}");
		this.sql = sbf.toString();

	}

	/**
	 * @return number of result sets that this sp returns
	 */
	public int getNbrOutputRecords() {
		if (this.outputRecordNames != null) {
			return this.outputRecordNames.length;
		}
		return 0;
	}

	/**
	 * @return sheet names based on default sheet names of output records
	 */
	public String[] getDefaultSheetNames() {
		String[] names = null;
		int nbrSheets = this.getNbrOutputRecords();
		if (nbrSheets > 0) {
			names = new String[nbrSheets];
			for (int i = 0; i < nbrSheets; i++) {
				Record record = ComponentManager
						.getRecord(this.outputRecordNames[i]);
				names[i] = record.getDefaultSheetName();
			}
		}
		return names;
	}

	@Override
	public int validate(ValidationContext ctx) {
		ctx.beginValidation(MY_TYPE, this.getQualifiedName());
		try{
		int count = 0;
		if (this.procedureName != null) {
			ctx.addError("Procedure name is required.");
			count++;
		}

		if (this.outputRecordNames != null) {
			for (String rec : this.outputRecordNames) {
				count += ctx
						.checkRecordExistence(rec, "outputRecordName", true);
			}
		}

		if (this.parameters != null) {
			for (ProcedureParameter param : this.parameters) {
				count += param.validate(ctx);
			}
		}
		return count;
		}finally{
			ctx.endValidation();
		}
	}

	@Override
	public ComponentType getComponentType() {
		return MY_TYPE;
	}
}


text:
$script:resourceModulePath = Split-Path -Path (Split-Path -Path $PSScriptRoot -Parent) -Parent
$script:modulesFolderPath = Join-Path -Path $script:resourceModulePath -ChildPath 'Modules'
$script:localizationModulePath = Join-Path -Path $script:modulesFolderPath -ChildPath 'xWebAdministration.Common'

Import-Module -Name (Join-Path -Path $script:localizationModulePath -ChildPath 'xWebAdministration.Common.psm1')

# Import Localization Strings
$script:localizedData = Get-LocalizedData -ResourceName 'MSFT_xIisFeatureDelegation'

<#
    .SYNOPSIS
        This will return a hashtable of results

    .PARAMETER Filter
        Specifies the IIS configuration section to lock or unlock.

    .PARAMETER Path
        Specifies the configuration path. This can be either an IIS configuration path in the format
        computer machine/webroot/apphost, or the IIS module path in this format IIS:\sites\Default Web Site.

    .PARAMETER OverrideMode
        Determines whether to lock or unlock the specified section.
#>
function Get-TargetResource
{
    [CmdletBinding()]
    [OutputType([Hashtable])]
    param
    (
        [Parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [String]
        $Filter,

        [Parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [ValidateSet('Allow', 'Deny')]
        [String]
        $OverrideMode,

        [Parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [String]
        $Path
    )

    [String] $currentOverrideMode = Get-OverrideMode -Filter $Filter -Path $Path

    Write-Verbose -Message $script:localizedData.VerboseGetTargetResource

    return @{
        Path         = $Path
        Filter       = $Filter
        OverrideMode = $currentOverrideMode
    }
}

<#
    .SYNOPSIS
        This will set the resource to the desired state.

    .PARAMETER Filter
        Specifies the IIS configuration section to lock or unlock.

    .PARAMETER Path
        Specifies the configuration path. This can be either an IIS configuration path in the format
        computer machine/webroot/apphost, or the IIS module path in this format IIS:\sites\Default Web Site.

    .PARAMETER OverrideMode
        Determines whether to lock or unlock the specified section.
#>
function Set-TargetResource
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [String]
        $Filter,

        [Parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [ValidateSet('Allow', 'Deny')]
        [String]
        $OverrideMode,

        [Parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [String]
        $Path
    )

     Write-Verbose -Message ( $script:localizedData.VerboseSetTargetResource -f $Filter, $OverrideMode )

     Set-WebConfiguration -Filter $Filter -PsPath $Path -Metadata 'overrideMode' -Value $OverrideMode
}

<#
    .SYNOPSIS
        This will return whether the resource is in desired state.

    .PARAMETER Filter
        Specifies the IIS configuration section to lock or unlock.

    .PARAMETER OverrideMode
        Determines whether to lock or unlock the specified section.

    .PARAMETER Path
        Specifies the configuration path. This can be either an IIS configuration path in the format
        computer machine/webroot/apphost, or the IIS module path in this format IIS:\sites\Default Web Site.

#>
function Test-TargetResource
{
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSDSCUseVerboseMessageInDSCResource", "",
        Justification = 'Verbose messaging in helper function')]
    [CmdletBinding()]
    [OutputType([System.Boolean])]
    param
    (
        [Parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [String]
        $Filter,

        [Parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [ValidateSet('Allow', 'Deny')]
        [String]
        $OverrideMode,

        [Parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [String]
        $Path
    )

    [String] $currentOverrideMode = Get-OverrideMode -Filter $Filter -Path $Path

    if ($currentOverrideMode -eq $OverrideMode)
    {
        return $true
    }

    return $false
}

#region Helper functions
<#
    .SYNOPSIS
        This will return the current override mode for the specified configsection.

    .PARAMETER Filter
        Specifies the IIS configuration section.

    .PARAMETER Path
        Specifies the configuration path. This can be either an IIS configuration path in the format
        computer machine/webroot/apphost, or the IIS module path in this format IIS:\sites\Default Web Site.

#>
function Get-OverrideMode
{
    [CmdletBinding()]
    [OutputType([System.String])]
    param
    (
        [Parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [String]
        $Filter,

        [Parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [String]
        $Path
    )

    Assert-Module

    Write-Verbose -Message ( $script:localizedData.GetOverrideMode -f $Filter )

    $webConfig = Get-WebConfiguration -PsPath $Path -Filter $Filter -Metadata

    $currentOverrideMode = $webConfig.Metadata.effectiveOverrideMode

    if ($currentOverrideMode -notmatch "^(Allow|Deny)$")
    {
        $errorMessage = $($script:localizedData.UnableToGetConfig) -f $Filter
        New-TerminatingError -ErrorId UnableToGetConfig `
                             -ErrorMessage $errorMessage `
                             -ErrorCategory:InvalidResult
    }

    return $currentOverrideMode
}
#endregion

Export-ModuleMember -function *-TargetResource

redpajama_set_name: RedPajamaGithub


text:
var Settings = require('settings');

Settings.config(
  { url: 'https://pebble-transit.herokuapp.com/' },
  function(e) {
  },
  function(e) {
    if (!e.failed && e.options) {
      Settings.option('journeys', e.options.journeys);
    } else {
      console.log('Save failed');
    }
  }
);


text:
	添加附件

			<notempty name="file_list">
				<volist name="file_list" id="file">

							删除
							{$file.size|reunit}
							 {$file.name}

				</volist>
			</notempty>


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

using Quasar.HabboHotel.Quests;
using Quasar.HabboHotel.GameClients;

namespace Quasar.Communication.Packets.Outgoing.Quests
{
    class QuestCompletedComposer : ServerPacket
    {
        public QuestCompletedComposer(GameClient Session, Quest Quest)
            : base(ServerPacketHeader.QuestCompletedMessageComposer)
        {
            int AmountInCat = QuasarEnvironment.GetGame().GetQuestManager().GetAmountOfQuestsInCategory(Quest.Category);
            int Number = Quest == null ? AmountInCat : Quest.Number;
            int UserProgress = Quest == null ? 0 : Session.GetHabbo().GetQuestProgress(Quest.Id);

           base.WriteString(Quest.Category);
            base.WriteInteger(Number); // Quest progress in this cat
            base.WriteInteger((Quest.Name.Contains("xmas2012")) ? 1 : AmountInCat); // Total quests in this cat
            base.WriteInteger(Quest == null ? 3 : Quest.RewardType); // Reward type (1 = Snowflakes, 2 = Love hearts, 3 = Pixels, 4 = Seashells, everything else is pixels
            base.WriteInteger(Quest == null ? 0 : Quest.Id); // Quest id
            base.WriteBoolean(Quest == null ? false : Session.GetHabbo().GetStats().QuestID == Quest.Id); // Quest started
           base.WriteString(Quest == null ? string.Empty : Quest.ActionName);
           base.WriteString(Quest == null ? string.Empty : Quest.DataBit);
            base.WriteInteger(Quest == null ? 0 : Quest.Reward);
           base.WriteString(Quest == null ? string.Empty : Quest.Name);
            base.WriteInteger(UserProgress); // Current progress
            base.WriteInteger(Quest == null ? 0 : Quest.GoalData); // Target progress
            base.WriteInteger(Quest == null ? 0 : Quest.TimeUnlock); // "Next quest available countdown" in seconds
           base.WriteString("");
           base.WriteString("");
            base.WriteBoolean(true); // ?
            base.WriteBoolean(true); // Activate next quest..
        }
    }
}


text:
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
// Code generated by Microsoft (R) AutoRest Code Generator.

package com.azure.messaging.servicebus.implementation.models;

import com.azure.core.annotation.Fluent;
import com.azure.messaging.servicebus.administration.models.AccessRights;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;

import java.time.OffsetDateTime;
import java.util.ArrayList;
import java.util.List;

/** The AuthorizationRule model. */
@JacksonXmlRootElement(
        localName = "AuthorizationRule",
        namespace = "http://schemas.microsoft.com/netservices/2010/10/servicebus/connect")
@Fluent
public final class AuthorizationRuleImpl {
    /*
     * The authorization type.
     */
    @JacksonXmlProperty(localName = "type", namespace = "http://www.w3.org/2001/XMLSchema-instance",
        isAttribute = true)
    private String type;

    /*
     * The claim type.
     */
    @JacksonXmlProperty(
            localName = "ClaimType",
            namespace = "http://schemas.microsoft.com/netservices/2010/10/servicebus/connect")
    private String claimType;

    /*
     * The claim value.
     */
    @JacksonXmlProperty(
            localName = "ClaimValue",
            namespace = "http://schemas.microsoft.com/netservices/2010/10/servicebus/connect")
    private String claimValue;

    private static final class RightsWrapper {
        @JacksonXmlProperty(localName = "AccessRights",
            namespace = "http://schemas.microsoft.com/netservices/2010/10/servicebus/connect")
        private final List<AccessRights> items;

        @JsonCreator
        private RightsWrapper(@JacksonXmlProperty(localName = "AccessRights",
            namespace = "http://schemas.microsoft.com/netservices/2010/10/servicebus/connect")
            List<AccessRights> items) {
            this.items = items;
        }
    }

    /*
     * Access rights of the entity. Values are 'Send', 'Listen', or 'Manage'
     */
    @JacksonXmlProperty(
            localName = "Rights",
            namespace = "http://schemas.microsoft.com/netservices/2010/10/servicebus/connect")
    private RightsWrapper rights;

    /*
     * The date and time when the authorization rule was created.
     */
    @JacksonXmlProperty(
            localName = "CreatedTime",
            namespace = "http://schemas.microsoft.com/netservices/2010/10/servicebus/connect")
    private OffsetDateTime createdTime;

    /*
     * The date and time when the authorization rule was modified.
     */
    @JacksonXmlProperty(
            localName = "ModifiedTime",
            namespace = "http://schemas.microsoft.com/netservices/2010/10/servicebus/connect")
    private OffsetDateTime modifiedTime;

    /*
     * The authorization rule key name
     */
    @JacksonXmlProperty(
            localName = "KeyName",
            namespace = "http://schemas.microsoft.com/netservices/2010/10/servicebus/connect")
    private String keyName;

    /*
     * The primary key of the authorization rule
     */
    @JacksonXmlProperty(
            localName = "PrimaryKey",
            namespace = "http://schemas.microsoft.com/netservices/2010/10/servicebus/connect")
    private String primaryKey;

    /*
     * The primary key of the authorization rule
     */
    @JacksonXmlProperty(
            localName = "SecondaryKey",
            namespace = "http://schemas.microsoft.com/netservices/2010/10/servicebus/connect")
    private String secondaryKey;

    /**
     * Get the type property: The authorization type.
     *
     * @return the type value.
     */
    public String getType() {
        return this.type;
    }

    /**
     * Set the type property: The authorization type.
     *
     * @param type the type value to set.
     * @return the AuthorizationRule object itself.
     */
    public AuthorizationRuleImpl setType(String type) {
        this.type = type;
        return this;
    }

    /**
     * Get the claimType property: The claim type.
     *
     * @return the claimType value.
     */
    public String getClaimType() {
        return this.claimType;
    }

    /**
     * Set the claimType property: The claim type.
     *
     * @param claimType the claimType value to set.
     * @return the AuthorizationRule object itself.
     */
    public AuthorizationRuleImpl setClaimType(String claimType) {
        this.claimType = claimType;
        return this;
    }

    /**
     * Get the claimValue property: The claim value.
     *
     * @return the claimValue value.
     */
    public String getClaimValue() {
        return this.claimValue;
    }

    /**
     * Set the claimValue property: The claim value.
     *
     * @param claimValue the claimValue value to set.
     * @return the AuthorizationRule object itself.
     */
    public AuthorizationRuleImpl setClaimValue(String claimValue) {
        this.claimValue = claimValue;
        return this;
    }

    /**
     * Get the rights property: Access rights of the entity. Values are 'Send', 'Listen', or 'Manage'.
     *
     * @return the rights value.
     */
    public List<AccessRights> getRights() {
        if (this.rights == null) {
            this.rights = new RightsWrapper(new ArrayList<AccessRights>());
        }
        return this.rights.items;
    }

    /**
     * Set the rights property: Access rights of the entity. Values are 'Send', 'Listen', or 'Manage'.
     *
     * @param rights the rights value to set.
     * @return the AuthorizationRule object itself.
     */
    public AuthorizationRuleImpl setRights(List<AccessRights> rights) {
        this.rights = new RightsWrapper(rights);
        return this;
    }

    /**
     * Get the createdTime property: The date and time when the authorization rule was created.
     *
     * @return the createdTime value.
     */
    public OffsetDateTime getCreatedTime() {
        return this.createdTime;
    }

    /**
     * Set the createdTime property: The date and time when the authorization rule was created.
     *
     * @param createdTime the createdTime value to set.
     * @return the AuthorizationRule object itself.
     */
    public AuthorizationRuleImpl setCreatedTime(OffsetDateTime createdTime) {
        this.createdTime = createdTime;
        return this;
    }

    /**
     * Get the modifiedTime property: The date and time when the authorization rule was modified.
     *
     * @return the modifiedTime value.
     */
    public OffsetDateTime getModifiedTime() {
        return this.modifiedTime;
    }

    /**
     * Set the modifiedTime property: The date and time when the authorization rule was modified.
     *
     * @param modifiedTime the modifiedTime value to set.
     * @return the AuthorizationRule object itself.
     */
    public AuthorizationRuleImpl setModifiedTime(OffsetDateTime modifiedTime) {
        this.modifiedTime = modifiedTime;
        return this;
    }

    /**
     * Get the keyName property: The authorization rule key name.
     *
     * @return the keyName value.
     */
    public String getKeyName() {
        return this.keyName;
    }

    /**
     * Set the keyName property: The authorization rule key name.
     *
     * @param keyName the keyName value to set.
     * @return the AuthorizationRule object itself.
     */
    public AuthorizationRuleImpl setKeyName(String keyName) {
        this.keyName = keyName;
        return this;
    }

    /**
     * Get the primaryKey property: The primary key of the authorization rule.
     *
     * @return the primaryKey value.
     */
    public String getPrimaryKey() {
        return this.primaryKey;
    }

    /**
     * Set the primaryKey property: The primary key of the authorization rule.
     *
     * @param primaryKey the primaryKey value to set.
     * @return the AuthorizationRule object itself.
     */
    public AuthorizationRuleImpl setPrimaryKey(String primaryKey) {
        this.primaryKey = primaryKey;
        return this;
    }

    /**
     * Get the secondaryKey property: The primary key of the authorization rule.
     *
     * @return the secondaryKey value.
     */
    public String getSecondaryKey() {
        return this.secondaryKey;
    }

    /**
     * Set the secondaryKey property: The primary key of the authorization rule.
     *
     * @param secondaryKey the secondaryKey value to set.
     * @return the AuthorizationRule object itself.
     */
    public AuthorizationRuleImpl setSecondaryKey(String secondaryKey) {
        this.secondaryKey = secondaryKey;
        return this;
    }
}


text:
local c;
local player = Var "Player";
local playerPrefs = ProfilePrefs.Read(GetProfileIDForPlayer(player))

local env = GAMESTATE:Env();
local OLDMIX = env.OLDMIX == true;

--disable bias in starter mode
local showBias = playerPrefs.bias and (not OLDMIX)

local JudgeCmds = {
	TapNoteScore_W1 = THEME:GetMetric( "Judgment", "JudgmentW1Command" );
	TapNoteScore_W2 = THEME:GetMetric( "Judgment", "JudgmentW2Command" );
	TapNoteScore_W3 = THEME:GetMetric( "Judgment", "JudgmentW3Command" );
	TapNoteScore_W4 = THEME:GetMetric( "Judgment", "JudgmentW4Command" );
	TapNoteScore_W5 = THEME:GetMetric( "Judgment", "JudgmentW5Command" );
	TapNoteScore_Miss = THEME:GetMetric( "Judgment", "JudgmentMissCommand" );
};

local OLDJudgeCmds = {
	TapNoteScore_W1 = THEME:GetMetric( "Judgment", "JudgmentW2Command" );
	TapNoteScore_W2 = THEME:GetMetric( "Judgment", "JudgmentW2Command" );
	TapNoteScore_W3 = THEME:GetMetric( "Judgment", "JudgmentW3Command" );
	TapNoteScore_W4 = THEME:GetMetric( "Judgment", "JudgmentW4Command" );
	TapNoteScore_W5 = THEME:GetMetric( "Judgment", "JudgmentW5Command" );
	TapNoteScore_Miss = THEME:GetMetric( "Judgment", "JudgmentMissCommand" );
};

local BiasCmd = THEME:GetMetric("Judgment", "JudgmentBiasCommand");

local TNSFrames = {
	TapNoteScore_W1 = 0;
	TapNoteScore_W2 = 1;
	TapNoteScore_W3 = 2;
	TapNoteScore_W4 = 3;
	TapNoteScore_W5 = 4;
	TapNoteScore_Miss = 5;
};

--frame 1 is the Early frame, 2 is the Late frame and doesn't appear in the table
--it is added by code downstream
local OLDTNSFrames = {
	TapNoteScore_W1 = 0;
	TapNoteScore_W2 = 0;
	TapNoteScore_W3 = 1;
	TapNoteScore_W4 = 2;
	TapNoteScore_W5 = 3;
	TapNoteScore_Miss = 4;
};

local activeFrames = OLDMIX and OLDTNSFrames or TNSFrames;
local activeCmds = OLDMIX and OLDJudgeCmds or JudgeCmds;

local t = Def.ActorFrame {

	InitCommand = function(self)
		c = self:GetChildren();
	end;

	JudgmentMessageCommand=function(self, param)
		if param.Player ~= player then return end;
		if param.HoldNoteScore then return end;

		local iNumStates = c.Judgment:GetNumStates();
		local iFrame = activeFrames[param.TapNoteScore];
		if not iFrame then return end

		local iTapNoteOffset = param.TapNoteOffset;
		local late = iTapNoteOffset and (iTapNoteOffset > 0);

		self:playcommand("Reset");

		c.Judgment:setstate( iFrame );
		c.Judgment:visible( true );
		activeCmds[param.TapNoteScore](c.Judgment);
		if showBias then
			---XXX: don't hardcode this
			if param.TapNoteScore ~= 'TapNoteScore_W1' and
				param.TapNoteScore ~= 'TapNoteScore_Miss' then
				c.Bias:visible(true);
				c.Bias:setstate( late and 2 or 1 );
				BiasCmd(c.Bias);
			else
				c.Bias:visible(false);
			end
		end
	end;
};

t[#t+1] = LoadActor(THEME:GetPathG("Judgment",OLDMIX and "2ndMIX" or "Normal")) .. {
	Name="Judgment";
	InitCommand=cmd(pause;visible,false);
	OnCommand=THEME:GetMetric("Judgment","JudgmentOnCommand");
	ResetCommand=cmd(finishtweening;stopeffect;visible,false);
};

if showBias then
	t[#t+1] = LoadActor(THEME:GetPathG("Judgment","Starter")) .. {
		Name="Bias";
		InitCommand=cmd(pause;visible,false);
		OnCommand=THEME:GetMetric("Judgment","JudgmentBiasOnCommand");
		ResetCommand=cmd(finishtweening;stopeffect;visible,false);
	};
end

return t;


text:
package org.easybatch.core.processor;

import org.easybatch.core.api.ComputationalRecordProcessor;

import java.util.ArrayList;
import java.util.List;

/**
 * Convenient processor that collects records.
 *
 * @param <T> the type of collected records
 * @author Mahmoud Ben Hassine (mahmoud@benhassine.fr)
 */
public class RecordCollector<T> implements ComputationalRecordProcessor<T, T, List<T>> {

    private List<T> items = new ArrayList<T>();

    @Override
    public T processRecord(T item) {
        items.add(item);
        return item;
    }

    @Override
    public List<T> getComputationResult() {
        return items;
    }

}


text:
@interface View4Controller ()

@end

@implementation View4Controller

- (void)loadView
{
    [super loadView];

    self.view.backgroundColor = [UIColor whiteColor];

    view1 = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    view1.frame = CGRectMake(20, 70, 280, 44);
    [view1 setTitle:@"view 1 in tabbar index 0" forState:UIControlStateNormal];
    [view1 addTarget:self action:@selector(buttonView1) forControlEvents:UIControlEventTouchUpInside];

    [self.view addSubview:view1];

    view2 = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    view2.frame = CGRectMake(20, 120, 280, 44);
    [view2 setTitle:@"view 5 in tabbar index 1" forState:UIControlStateNormal];
    [view2 addTarget:self action:@selector(buttonView2) forControlEvents:UIControlEventTouchUpInside];

    [self.view addSubview:view2];

    view3 = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    view3.frame = CGRectMake(20, 170, 280, 44);
    [view3 setTitle:@"view 2 in tabbar index 1" forState:UIControlStateNormal];
    [view3 addTarget:self action:@selector(buttonView3) forControlEvents:UIControlEventTouchUpInside];

    [self.view addSubview:view3];
}

- (void)buttonView1
{
    [[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"routertabbar://view1"]];
}

- (void)buttonView2
{
    [[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"routertabbar://view5"]];
}

- (void)buttonView3
{
    [[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"routertabbar://view6"]];
}

@end


text: serve-markdown


text:
package de.tototec.cmdoption;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.MissingResourceException;
import java.util.ResourceBundle;

public class DefaultUsageFormatter implements UsageFormatter {

	private final I18n i18n = I18nFactory.getI18n(DefaultUsageFormatter.class);

	private final boolean withCommandDetails;

	private int lineLength;
	private int colSpace = 2;
	private int col1Prefix = 2;

	public DefaultUsageFormatter(final boolean withCommandDetails) {
		this(withCommandDetails, 80);
	}

	public DefaultUsageFormatter(final boolean withCommandDetails, final int lineLength) {
		this.withCommandDetails = withCommandDetails;
		this.lineLength = lineLength;
	}

	protected String translate(final ResourceBundle resourceBundle, final String string) {
		if (resourceBundle != null) {
			try {
				return resourceBundle.getString(string);
			} catch (final MissingResourceException e) {
				// no translation available
			}
		}
		return string;
	}

	protected String[] translate(final ResourceBundle resourceBundle, final String[] strings) {
		final String[] translated = new String[strings.length];
		for (int i = 0; i < strings.length; ++i) {
			translated[i] = translate(resourceBundle, strings[i]);
		}
		return translated;
	}

	public void format(final StringBuilder output, final CmdlineModel cmdlineModel) {

		final ArrayList<OptionHandle> sortedOptions = new ArrayList<OptionHandle>(cmdlineModel.getOptions());
		for (final Iterator<OptionHandle> it = sortedOptions.iterator(); it.hasNext();) {
			if (it.next().isHidden()) {
				it.remove();
			}
		}
		Collections.sort(sortedOptions, new OptionHandle.OptionHandleComparator());

		final ArrayList<CommandHandle> sortedCommands = new ArrayList<CommandHandle>(cmdlineModel.getCommands());
		for (final Iterator<CommandHandle> it = sortedCommands.iterator(); it.hasNext();) {
			if (it.next().isHidden()) {
				it.remove();
			}
		}
		Collections.sort(sortedCommands, new CommandHandle.CommandHandleComparator());

		// About
		if (cmdlineModel.getAboutLine() != null && cmdlineModel.getAboutLine().length() > 0) {
			output.append(translate(cmdlineModel.getResourceBundle(), cmdlineModel.getAboutLine())).append("\n\n");
		}

		// Usage
		output.append(i18n.tr("Usage:")).append(" ");
		output.append(cmdlineModel.getProgramName() == null ? i18n.tr("program") : cmdlineModel.getProgramName());
		if (!sortedOptions.isEmpty()) {
			output.append(" ").append(i18n.tr("[options]"));
		}
		if (cmdlineModel.getParameter() != null) {
			output.append(" ").append(i18n.tr("[parameter]"));
		}
		if (!sortedCommands.isEmpty()) {
			output.append(" ").append(i18n.tr("[command]"));
			boolean cmdsHaveOptions = false;
			boolean cmdsHaveParameter = false;
			for (final CommandHandle cmd : sortedCommands) {
				cmdsHaveOptions |= !cmd.getCmdlineParser().getCmdlineModel().getOptions().isEmpty();
				cmdsHaveParameter |= cmd.getCmdlineParser().getCmdlineModel().getParameter() != null;
			}
			if (cmdsHaveOptions) {
				output.append(" ").append(i18n.tr("[command options]"));
			}
			if (cmdsHaveParameter) {
				output.append(" ").append(i18n.tr("[command parameters]"));
			}
		}
		output.append("\n");

		formatOptions(output, sortedOptions, "\n" + i18n.tr("Options:"), cmdlineModel.getResourceBundle());

		formatCommands(output, sortedCommands, "\n" + i18n.tr("Commands:"), cmdlineModel.getResourceBundle());

		if (withCommandDetails) {
			for (final CommandHandle command : sortedCommands) {
				final ArrayList<OptionHandle> commandOptions = new ArrayList<OptionHandle>(command.getCmdlineParser()
						.getCmdlineModel().getOptions());
				for (final Iterator<OptionHandle> it = commandOptions.iterator(); it.hasNext();) {
					if (it.next().isHidden()) {
						it.remove();
					}
				}
				Collections.sort(commandOptions, new OptionHandle.OptionHandleComparator());

				formatOptions(
						output,
						commandOptions,
						"\n" + i18n.tr("Options for command:") + " "
								+ Util.mkString(command.getNames(), null, ", ", null), cmdlineModel.getResourceBundle());

				formatParameter(
						output,
						command.getCmdlineParser().getCmdlineModel().getParameter(),
						"\n" + i18n.tr("Parameter for command:") + " "
								+ Util.mkString(command.getNames(), null, ", ", null), cmdlineModel.getResourceBundle());
			}
		}

		// Parameter
		formatParameter(output, cmdlineModel.getParameter(), "\n" + i18n.tr("Parameter:"),
				cmdlineModel.getResourceBundle());
	}

	protected void formatParameter(final StringBuilder output, final OptionHandle parameter, final String title,
			final ResourceBundle resourceBundle) {
		if (parameter == null) {
			return;
		}

		output.append(title).append("\n");
		mkSpace(output, col1Prefix);
		output.append(Util.mkString(translate(resourceBundle, parameter.getArgs()), null, " ", null));
		if (parameter.getDescription() != null) {
			mkSpace(output, colSpace);
			output.append(translate(resourceBundle, parameter.getDescription()));
		}
		output.append("\n");
	}

	protected void formatOptions(final StringBuilder output, final List<OptionHandle> options, final String title,
			final ResourceBundle resourceBundle) {
		if (options == null || options.isEmpty()) {
			return;
		}

		final LinkedList<String[]> optionsToFormat = new LinkedList<String[]>();
		boolean hasOptions = false;
		for (final OptionHandle option : options) {
			if (option.isHidden()) {
				continue;
			}
			hasOptions = true;
			final String optionNames = Util.mkString(option.getNames(), null, ",", null);
			final String argNames = Util.mkString(translate(resourceBundle, option.getArgs()), null, " ", null);
			optionsToFormat.add(new String[] { optionNames + (argNames.length() == 0 ? "" : (" " + argNames)),
					translate(resourceBundle, option.getDescription()) });
		}

		if (!hasOptions) {
			return;
		}

		if (title != null) {
			output.append(title).append("\n");
		}

		formatTable(output, optionsToFormat, col1Prefix, colSpace, lineLength);
	}

	protected void formatCommands(final StringBuilder output, final List<CommandHandle> commands, final String title,
			final ResourceBundle resourceBundle) {
		if (commands == null || commands.isEmpty()) {
			return;
		}

		if (title != null) {
			output.append(title).append("\n");
		}

		final LinkedList<String[]> commandsToFormat = new LinkedList<String[]>();
		for (final CommandHandle option : commands) {
			final String commandNames = Util.mkString(option.getNames(), null, ",", null);
			commandsToFormat.add(new String[] { commandNames, translate(resourceBundle, option.getDescription()) });
		}

		formatTable(output, commandsToFormat, col1Prefix, colSpace, lineLength);
	}

	public static void mkSpace(final StringBuilder output, final int space) {
		for (int i = 0; i < space; ++i) {
			output.append(" ");
		}
	}

	public static void formatTable(final StringBuilder output, final List<String[]> twoColData, final int prefix,
			final int space, final int maxLineLength) {
		// Calc first col width
		int firstColSize = 2;
		for (final String[] col : twoColData) {
			if (col.length > 0 && col[0] != null) {
				firstColSize = Math.max(firstColSize, col[0].length());
			}
		}

		final boolean secondColInNewLine = ((prefix + space + firstColSize + 10) > maxLineLength);

		// Write output
		for (final String[] col : twoColData) {
			if (col.length > 0) {
				// first col
				mkSpace(output, prefix);
				int cursor = prefix;

				if (col[0] != null) {
					output.append(col[0]);
					cursor += col[0].length();
				}

				// fill space to next col
				if (secondColInNewLine) {
					output.append("\n");
				} else {
					mkSpace(output, prefix + firstColSize + space - cursor);
				}

				// second col
				if (col[1] != null) {
					if (secondColInNewLine) {
						wrap(output, col[1], prefix + space, maxLineLength - prefix - space);
					} else {
						wrap(output, col[1], prefix + space + firstColSize, maxLineLength - prefix - space
								- firstColSize);
					}
				}
			}
			output.append("\n");
		}

	}

	public static void wrap(final StringBuilder output, String text, final int nextLinePrefix, final int lineLength) {
		text = text.trim();

		if (text.length() <= lineLength) {
			output.append(text);
		} else {

			int bestWrap = -1;

			if (" ".equals(text.substring(lineLength, lineLength + 1))) {
				bestWrap = lineLength;
			} else {
				bestWrap = text.substring(0, lineLength).lastIndexOf(" ");
			}

			if (bestWrap == -1) {
				bestWrap = text.indexOf(" ");
			}

			if (bestWrap > 0) {
				output.append(text.substring(0, bestWrap)).append("\n");
				for (int i = 0; i < nextLinePrefix; ++i) {
					output.append(" ");
				}
				wrap(output, text.substring(bestWrap), nextLinePrefix, lineLength);
			} else {
				output.append(text);
			}

		}
	}
}


text:
layout: page
categories: articles
title: "Galvanostatic simulations: Simulation walkthrough"
description: A tutorial on galvanostatic simulations
---

## UNDER CONSTRUCTION

In this post, I'll explain the
[cyclic voltammetry simulation](/cyclic_voltammetry_simulation/index.html)
I've created in greater detail.
I've chosen to document this simulation with MATLAB code since its syntax is
easy to follow.
You can find the full MATLAB script file
[here](/cyclic_voltammetry_simulation/code.html).

~~~~matlab
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% CVsim.m - Cyclic voltammetry simulation
% Peter Attia
% Based on Bard and Faulkner, Appendix B
% EC mechanism
% Updated September 24, 2017
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

clear, clc, close all
~~~~

Again, this simulation is well-described in Bard and Faulkner, Appendix B.
Highly recommended for all the details.
This walkthrough is designed to serve as a "practical" guide to performing these
simulations, as well as to make Bard and Faulkner's
occasionally dense writing style more accessible.

### Set independent variables

~~~~matlab
%% INDEPENDENT VARIABLES %%
C      = 1.0;    % [=] mol/cm^3, initial concentration of O. Default = 1.0
D      = 1E-5;   % [=] cm^2/s, O & R diffusion coefficient. Default = 1E-5
etai   = +0.2;   % [=] V, initial overpotential (relative to redox potential). Default = +0.2
etaf   = -0.2;   % [=] V, final overpotential (relative to redox potential). Default = -0.2
v      = 1E-3;   % [=] V/s, sweep rate. Default = 1E-3
n      = 1.0;    % [=] number of electrons transfered. Default = 1
alpha  = 0.5;    % [=] dimensionless charge-transfer coefficient. Default = 0.5
k0     = 1E-2;   % [=] cm/s, electrochemical rate constant. Default = 1E-2
k1     = 1E-3;   % [=] 1/s, chemical rate constant. Default = 1E-3
T      = 298.15; % [=] K, temperature. Default = 298.15
~~~~

These variables are the "adjustable" parameters in this simulation.
These parameters should be straightforward to someone interested in cyclic
voltammetry simulations. I'll note that $ k_0 $ is the electrochemical rate constant,
with units of $ \text{cm/s} $ , and $ k_1 $ is the chemical rate constant,
with units of $ \text{1/s} $.
You can read more about these terms on the
[fundamentals](/cyclic_voltammetry_simulation/fundamentals.html) page.

### Set physical constants

~~~~matlab
%% PHYSICAL CONSTANTS %%
F      = 96485;   % [=] C/mol, Faraday's constant
R      = 8.3145;  % [=] J/mol-K, ideal gas constant
f      = F/(R*T); % [=] 1/V, normalized Faraday's constant at room temperature
~~~~

These variables are fundamental physical constants.
The [Faraday constant](https://en.wikipedia.org/wiki/Faraday_constant)
is often normalized by $ RT $.

In my work, I don't consider temperatures other than room temperature.
If your work involves variable temperature, you can move $ T $ from "constants"
to "independent variables".

### Set simulation variables

~~~~matlab
%% SIMULATION VARIABLES %%
L      = 500;    % [=] number of iterations per t_k (pg 790). Default = 500
DM     = 0.45;   % [=] model diffusion coefficient (pg 788). Default = 0.45
~~~~

$ L $ and $ D_M $ are two intrinsic simulation variables.

$ L $ is the *number of timesteps* in our simulation.
Our experiment will take some amount of real time ($ t_k $, as discussed below).
For a trivial example, if we sweep from $ +1 \text{V} $ to
$ -1 \text{V} $ and back at a rate of $ 1 \text{ V/s} $, we are simulating a total
time of $ 4\text{ s} $. If $ L = 500 $, each timestep will be
$ 4000 \text{ ms / } 500 = 8 \text{ ms} $.

Two notes on $ L $:
- $ L $ controls the resolution of our experiment. A low value of $ L $ will
  lead to "choppiness" in the output; a high value of $ L $ is computationally
  expensive. Bard and Faulkner recommend $ L $ to be between 100 and 1000.
  However, "computationally expensive" in 2001 (the publication year
  of Bard and Faulkner) is different than "computationally expensive" today.
  My 2014 MacBook Air ran this simulation with $ L = 10000 $ in 0.4s.
  This simulation is an analytical form of a set of differential equations,
  so it's already computationally inexpensive relative to its
  original differential form.
  In my experience, $ L = 500 $ produces smooth curves.

- Changing $ L $ will change the magnitude of dimensionless current, so don't
  change $ L $ when comparing two simulations - unless, of course, you're
  interested in understanding the effect of $ L $ 😉.

$ D_M $ is the *model diffusion coefficient*.
$ D_M $ is defined as $ D\Delta t / \Delta x^2 $.
A "model diffusion coefficient" is used to ensure that one implicit
assumption is satisfied: within a single timestep, material can only diffuse
between nearest-neighbor boxes.
If $ \Delta x $ is too small for a given $ \Delta t $, the simulation becomes
unphysical. For example, if $ D_M = 0.5 $, a mass-transfer operation between a
full box and an empty box will leave both boxes half-full, which violates
Fick's laws.
Thus, we must satisfy the condition that $ D_M < 0.5 $.
Bard and Faulkner recommend $ D_M = 0.45 $, which we retain here.

Since we've already defined $ D $ and $ \Delta t $ is controlled by $ L $, $ D_M $
specifies $ \Delta x $. The implication of this definition is that while $ x $
and $ t $ are physically independent, $ \Delta x $ and $ \Delta t $ are
*dependent* in this analytical simulation.
In other words, the spatial resolution is a function of the temporal resolution.

### Calculate temporal and spatial step size

~~~~matlab
%% DERIVED CONSTANTS %%
tk  = 2*(etai-etaf)/v;    % [=] s, characteristic exp. time (pg 790). In this case, total time of fwd and rev scans
Dt  = tk/L;               % [=] s, delta time (Eqn B.1.10, pg 790)
Dx  = sqrt(D*Dt/DM);      % [=] cm, delta x (Eqn B.1.13, pg 791)
j   = ceil(4.2*L^0.5)+5;  % number of boxes (pg 792-793). If L~200, j=65
~~~~

This section shows the derived constants. I'll walk through each of them
individually:
- $ t_k $ (`tk`) is the total experiment time, or a "characteristic experimental
  duration". $ t_k $ is calculated from multiplying the total voltage swept by
  a scan in [one direction](https://en.wikipedia.org/wiki/One_Direction) by two
  (to account for both sweeps) and dividing by the voltage sweep rate.

- $ \Delta t $ (`dt`) is the size of each timestep, given the total experiment
  time and the number of timesteps we desire, $ L $.

- $ \Delta x $ (`dx`) is the width of each box. It's controlled by $ D_M $, as
  discussed above.

- $ j $ (`j`) is the number of 'finite elements', or 'boxes', in the length dimension.
  The size of each box, $ \Delta x $, is already set, but we
  can calculate the number of boxes required by estimating the
  diffusion layer length in units of boxes.
  3D diffusion proceeds as $ 6(Dt)^{0.5} $. In units of 'boxes',
  we need $ j_{max} = 6(Dt)^{1/2}/\Delta x + 1 $. With some algebra, we find
  that $ j_{max} < 4.2 L^{1/2} $. I added the `+5` since it can't hurt.

### Calculate reversibility parameters

~~~~matlab
%% REVERSIBILITY PARAMETERS %%
ktk    = k1*tk              % dimensionless kinetic parameter (Eqn B.3.7, pg 797)
km     = ktk/L              % normalized dimensionless kinetic parameter (see bottom of pg 797)
Lambda = k0/(D*f*v)^0.5     % dimensionless reversibility parameter (Eqn 6.4.4, pg. 236-239)
~~~~

These parameters control the extent of chemical and electrochemical reversibility.
We can estimate the shape of the *I-V* curve just by knowing the values
of these parameters.
I discuss chemical and electrochemical reversibility
[here](/cyclic_voltammetry_simulation/index.html).

- $ k_1 t_k $ (`ktk`) is the dimensionless kinetic parameter. Specifically, it
  is the dimensionless *chemical* kinetic parameter, capturing the effect of
  the $R \overset{k_c}{\rightarrow} Z $ reaction.
  $ k_1 t_k $ controls the extent of chemical reversibility.

- $ k_m $ (`km`) is the normalized dimensionless chemical kinetic parameter.
  This value is convenient in future calculations.

- $ \Lambda $ (`Lambda`) is the dimensionless electrochemical reversibility
  parameter, defined by $ \frac{k_0}{(Dfv)^{0.5}} $. $ \Lambda $ is an indicator of the ratio between the rates of
  charge transfer and mass transfer.

### Send warnings to user

~~~~matlab
%% CHEMICAL REVERSIBILITY WARNING %%
if km>0.1
    warning(['k_c*t_k/l equals ' num2str(km) ...
        ', which exceeds the upper limit of 0.1 (see B&F, pg 797)'])
end
~~~~

In my experience, this simulation only breaks under one condition,
documented by Bard and Faulkner (pg 797).
One limitation of the choice of a finite-element model is that the
approximation breaks down at extreme conditions.
In this case, if $ k_1 $ is too large, the rate of chemical reaction significantly
exceeds the time resolution of the simulation, $ t_k/L = \Delta t $.
For example, if $ k_1 = 10 \text{ s}^{-1} $ and $ \Delta t = 0.1 \text{ s} $,
we turn over product faster than we can compute the changes in concentration.
This condition leads to numerical instabilities.

According to the text, the limit is $ k_1 t_k/L > 0.1 $.
My code warns you about this, but allows you to proceed.
If this condition is not satisfied, you may see
infinite current "spikes" when you run the simulation.
To study a system with a high value of $ k_1 $, increase $ L $.

### Pre-initialize variables

Almost there. The next section is mostly pre-initialization:
~~~~matlab
%% PRE-INITIALIZATION %%
k = 0:L;                % time index vector
t = Dt * k;             % time vector
eta1 = etai - v*t;      % overpotential vector, negative scan
eta2 = etaf + v*t;      % overpotential vector, positive scan
eta = [eta1(eta1>etaf) eta2(eta2<=etai)]'; % overpotential scan, both directions
Enorm = eta*f;          % normalized overpotential
kf = k0.*exp(  -alpha *n*Enorm); % [=] cm/s, fwd rate constant (pg 799)
kb = k0.*exp((1-alpha)*n*Enorm); % [=] cm/s, rev rate constant (pg 799)

O = C*ones(L+1,j); % [=] mol/cm^3, concentration of O
R = zeros(L+1,j);  % [=] mol/cm^3, concentration of R
JO = zeros(1,L+1); % [=] mol/cm^2-s, flux of O at the surface
~~~~

Again, I'll walk through the variables:
- $ k $ (`k`) is the time index. `k` is a vector. Since `k = 0:L` (inclusive),
  we require $ L + 1 $ boxes, instead of $ L $ boxes.

- $ t $ (`t`) is the simulation step time, in seconds. `t` is a vector.

- $ \eta_1 $ (`eta1`) and $ \eta_2 $ (`eta2`) combine to form $ \eta $ (`eta`),
  which is a vector of the overpotential. We plot `eta` at the end.

- $ E_{norm} $ (`Enorm`) is a vector of the dimensionless overpotential in volts.
  This form is convenient for Butler-Volmer expressions.

- $ k_f $ (`kf`) and $ k_b $ (`kb`) are the forward and reverse
  electrochemical rate constants, given by the
  [Butler-Volmer equation](https://en.wikipedia.org/wiki/Butler–Volmer_equation).
  `kf` and `kb` are vectors, with values that change with `Enorm`.
  The rate constants have units of $ \text{cm/s} $.

- `O` and `R` are the concentrations of $ O $ and $ R $, respectively.
  The initial concentration of $ O $ is $ C $, and t
  he initial concentration of $ R $ is $ 0 $.
  The `O` and `R` arrays have $ L + 1 $ rows (time steps)
  and $ j $ columns (length steps).
  `O` and `R` are indexed as `O(k,j)` and `R(k,j)`, or
  $ \text{(time, length)} $.
  Note that this convention switches the rows and columns in Bard & Faulkner's
  convention. I find mine more intuitive to work with in MATLAB.

- `J` is a vector representing the flux of species $ O $ ($ mol/cm^2s $).
  We need $ L + 1 $ columns (time steps).

### Run main simulation

And finally, we run the simulation. We cycle through all possible times;
within each timestep, we cycle through all lengths.

~~~~matlab
%% START SIMULATION %%
% i1 = time index. i2 = distance index
for i1 = 1:L
    % Update bulk concentrations of O and R
    for i2 = 2:j-1
        O(i1+1,i2) = O(i1,i2) + DM*(O(i1,i2+1)+O(i1,i2-1)-2*O(i1,i2));

        R(i1+1,i2) = R(i1,i2) + DM*(R(i1,i2+1)+R(i1,i2-1)-2*R(i1,i2)) ...
            - km * R(i1,i2);
    end

    % Update flux
    JO(i1+1)   = ( kf(i1+1).*O(i1+1,2) - kb(i1+1).*R(i1+1,2) ) ./ (1 + Dx/D*(kf(i1+1) + kb(i1+1)) );

    % Update surface concentrations
    O(i1+1,1) = O(i1+1,2) - JO(i1+1)*(Dx/D);
    R(i1+1,1) = R(i1+1,2) + JO(i1+1)*(Dx/D) - km*R(i1+1,1);
end

% Calculate current density, Z, from flux of O
Z = -n.*F.*JO/10; % [=] A/m^2 -> mA/cm^2, current density
~~~~

I found Bard and Faulkner's derivations opaque, since I was always mentally
converting between dimenional and dimensionless variables.
Additionally, the use of dimensionless current hides
important subtleties in the simulation results.
I much prefered the derivation published by Brown
[in this paper](https://dx.doi.org/10.1021/acs.jchemed.5b00225),
which is written with dimensional variables.
In this part of the walkthrough, I'll primarily follow Brown's derivations, and
reference equations in Bard & Faulkner when appropriate.

#### Bulk concentrations

The bulk concentrations of $ O $ and $ R $ change due to diffusion and, in the case of $ R $,
the subsequent chemical reaction.
We start with Fick's combined 1st and 2nd laws:

$$ \frac{\partial C(x,t)}{\partial t} = D\frac{\partial C^2(x,t)}{\partial x^2} $$

We apply a discrete approximation to arrive at Eqn B.1.6:

$$ C(x,t+\Delta t) = C(x,t) + \frac{D\Delta t}{\Delta x^2}\big(C(x+\Delta x,t) - 2C(x,t) + C(x-\Delta x, t) \big) $$

We substitute simulation variables to arrive at an expression for $ O $.
The bulk concentration of $ O $ changes only by diffusion (Eqn B.1.9):

$$ O(k+1,j) = O(k,j) + D_M\big[ O(k,j+1) - 2O(k,j) + O(k,j-1)\big] $$

The dynamics of the bulk concentration of $ R $ are identical,
except we also need to add the subsequent chemical reaction (Eqn B.3.5):

$$ R(k+1,j) = R(k,j) + D_M\big[ R(k,j+1) - 2R(k,j) + R(k,j-1)\big] - \big(k_1 \Delta t \big) R(k,j) $$

Every timestep, $ k_1 \Delta t $ molecules of $ R $ convert into the chemical product.

#### Current

Bard and Faulkner write an equation for current in Eqn B.4.9:

$$ \frac{i(t)}{nFA} = k_fO(x=0,t) - k_rR(x=0,t) $$

However, I find the Bard and Faulkner sign convention confusing.
I prefer negative currents for negative overpotential
(potentials less than the redox potential).
I switch the current convention below.
If you prefer the Bard and Faulkner convention,
you can simply change `plot(eta,Z)` to `plot(eta,-Z)` with no loss of fidelity.

With my preferred current convention, the above equation becomes:

$$ \frac{i(t)}{nFA} = -k_fO(x=0,t) + k_rR(x=0,t) $$

We can translate these physical varaibles into simulation variables:

$$ \frac{i(k)}{nFA} = -k_f(k)O(k,j=1) + k_r(k)R(k,j=1) $$

Here, $ O(k,j=1) $ and $ R(k,j=1) $ are the concentrations of $ O $ and $ R $
at timestep $ k $ in box $ 1 $, which we take to be the surface.
To calculate the current, then, we need to know $ O(k,j=1) $ and $ R(k,j=1) $.
We can obtain these using four equations for flux, $ J $.
The first two come from Fick's first law:

$$ J_O(x,t) = -D_O\frac{\partial C_O(x,t)}{\partial x} $$

$$ J_R(x,t) = -D_R\frac{\partial C_R(x,t)}{\partial x} $$

Again, we assume $ D_O = D_R = D $.
For box 1 ($ j = 1 $), we can translate these equations using simulation terms:

$$ J_O(k,1) = -D\frac{O(k,2) - O(k,1)}{\Delta x} \Rightarrow
O(k,1) = O(k,2) - J_O\frac{\Delta x}{D} $$

$$ J_R(k,1) = -D\frac{R(k,2) - R(k,1)}{\Delta x} \Rightarrow
R(k,1) = R(k,2) - J_R\frac{\Delta x}{D} $$

At the surface, we can define the current by the flux of $ O $ (pg 792 & B.4.19).
This relationship gives us another equation for the electrode-electrolyte interface:

$$ \frac{i(k)}{nFA} = -J_O(k) = -k_f(k)O(k,j=1) + k_r(k)R(k,j=1) $$

Lastly, at the interface, the flux of $ O $ is equal and opposite to the flux of
$ R $:

$$ J_O(k) = -J_R(k) $$

We can now substitute variables into the third equation:

$$ -J_O(k) = -k_f(k)\left( O(k,2) - J_O\frac{\Delta x}{D} \right)
+ k_r(k)\left( R(k,2) - J_R\frac{\Delta x}{D} \right) $$

$$ J_O(k) = k_f(k)O(k,2) - k_f(k)J_O\frac{\Delta x}{D}
- k_r(k)R(k,2) - k_r(k)J_O\frac{\Delta x}{D} $$

$$ J_O(k)\left(1 + k_f(k)\frac{\Delta x}{D} + k_r(k)\frac{\Delta x}{D}\right)
= k_f(k)O(k,2) - k_r(k)R(k,2) $$

With one more rearrangement, we obtain:

$$ J_O(k) = \frac{k_f(k)O(k,2) - k_r(k)R(k,2)}
{1 + k_f(k)\frac{\Delta x}{D} + k_r(k)\frac{\Delta x}{D}} $$

That's a lot of $ k $'s! We use this equation to calculate the surface flux of $ O $.

At the end, we calculate current density, $ Z $, from flux:

$$ \frac{i(k)}{A} = -nFJ_O $$

#### Surface concentrations

We derived equations for the surface (box 1) concentrations of $ O $ and $ R $
in the previous section from a discrete approximation of Fick's first law.
We account for changes in concentration due to diffusion, electrochemical reaction,
and, in the case of $ R $, the subsequent chemical reaction.

$$ J_O(k,1) = -D\frac{O(k,2) - O(k,1)}{\Delta x} \Rightarrow
O(k,1) = O(k,2) - J_O\frac{\Delta x}{D} $$

$$ J_R(k,1) = -D\frac{R(k,2) - R(k,1)}{\Delta x} \Rightarrow
R(k,1) = R(k,2) + J_O\frac{\Delta x}{D} - \left( k_1 \Delta t \right) R(k-1,1)$$

### Plot results

~~~~matlab
%% PLOT RESULTS %%
% Sometimes length(eta) = length(Z) + 1. If this is the case, truncate last value
if length(eta) > length(Z)
    eta = eta(1:end-1);
end

plot(eta,Z)
xlabel('Overpotential (V)'), ylabel('Current density (mA/cm^2)')
~~~~

Under some conditions of `etai` and `etaj`, `eta` is one element larger than
`Z`. If so, we chop off the last value of `eta`.
For $ L = 500 $, this operation will have a negligible effect on the output.

With that, we're done! Plot `eta` vs `Z` to see the final result.
The Bard and Faulkner current convention is counterintuitive to me, so
I plot `-Z` instead of `Z`.

The results of a simulation using the default values is below:


text:
<?xml version="1.0" encoding="ISO-8859-1" standalone="no"?>
<DebitNote
    xmlns="urn:oasis:names:specification:ubl:schema:xsd:DebitNote-2"
    xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2"
    xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2"
    xmlns:ccts="urn:un:unece:uncefact:documentation:2"
    xmlns:ds="http://www.w3.org/2000/09/xmldsig#"
    xmlns:ext="urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2"
    xmlns:qdt="urn:oasis:names:specification:ubl:schema:xsd:QualifiedDatatypes-2"
    xmlns:sac="urn:sunat:names:specification:ubl:peru:schema:xsd:SunatAggregateComponents-1"
    xmlns:udt="urn:un:unece:uncefact:data:specification:UnqualifiedDataTypesSchemaModule:2"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <ext:UBLExtensions>
        <ext:UBLExtension>
            <ext:ExtensionContent>
                <sac:AdditionalInformation>
                  <sac:AdditionalMonetaryTotal>
                    <cbc:ID>1001</cbc:ID>
                    <cbc:PayableAmount currencyID="PEN">8305.08</cbc:PayableAmount>
                  </sac:AdditionalMonetaryTotal>
                </sac:AdditionalInformation>
            </ext:ExtensionContent>
        </ext:UBLExtension>
        <ext:UBLExtension>
            <ext:ExtensionContent></ext:ExtensionContent>
        </ext:UBLExtension>
    </ext:UBLExtensions>
    <cbc:UBLVersionID>2.0</cbc:UBLVersionID>
    <cbc:CustomizationID>1.0</cbc:CustomizationID>
    <cbc:ID>F001-0005</cbc:ID>
    <cbc:IssueDate>2016-03-23</cbc:IssueDate>
    <cbc:DocumentCurrencyCode>PEN</cbc:DocumentCurrencyCode>
    <cac:DiscrepancyResponse>
      <cbc:ReferenceID>F001-4355</cbc:ReferenceID>
      <cbc:ResponseCode>02</cbc:ResponseCode>
      <cbc:Description>Ampliación garantía de memoria DDR-3 B1333 Kingston</cbc:Description>
    </cac:DiscrepancyResponse>
    <cac:BillingReference>
      <cac:InvoiceDocumentReference>
        <cbc:ID>F001-4355</cbc:ID>
        <cbc:DocumentTypeCode>01</cbc:DocumentTypeCode>
      </cac:InvoiceDocumentReference>
    </cac:BillingReference>
    <cac:Signature>
        <cbc:ID>IDSignSP</cbc:ID>
        <cac:SignatoryParty>
            <cac:PartyIdentification>
                <cbc:ID>20600995805</cbc:ID>
            </cac:PartyIdentification>
            <cac:PartyName>
                <cbc:Name><![CDATA[INTELIGENCIA DE VENTAS SAC]]></cbc:Name>
            </cac:PartyName>
        </cac:SignatoryParty>
        <cac:DigitalSignatureAttachment>
            <cac:ExternalReference>
                <cbc:URI>#SignatureSP</cbc:URI>
            </cac:ExternalReference>
        </cac:DigitalSignatureAttachment>
    </cac:Signature>
    <cac:AccountingSupplierParty>
        <cbc:CustomerAssignedAccountID>20600995805</cbc:CustomerAssignedAccountID>
        <cbc:AdditionalAccountID>6</cbc:AdditionalAccountID>
        <cac:Party>
            <cac:PostalAddress>
                <cbc:ID>150111</cbc:ID>
                <cbc:StreetName>AV. LOS PRECURSORES #1245</cbc:StreetName>
                <cbc:CitySubdivisionName>URB. MIGUEL GRAU</cbc:CitySubdivisionName>
                <cbc:CityName>LIMA</cbc:CityName>
                <cbc:CountrySubentity>LIMA</cbc:CountrySubentity>
                <cbc:District>EL AGUSTINO</cbc:District>
                <cac:Country>
                    <cbc:IdentificationCode>PE</cbc:IdentificationCode>
                </cac:Country>
            </cac:PostalAddress>
            <cac:PartyLegalEntity>
                <cbc:RegistrationName><![CDATA[INTELIGENCIA DE VENTAS SAC]]></cbc:RegistrationName>
            </cac:PartyLegalEntity>
        </cac:Party>
    </cac:AccountingSupplierParty>
    <cac:AccountingCustomerParty>
      <cbc:CustomerAssignedAccountID>20587896411</cbc:CustomerAssignedAccountID>
      <cbc:AdditionalAccountID>6</cbc:AdditionalAccountID>
      <cac:Party>
        <cac:PartyLegalEntity>
          <cbc:RegistrationName>SERVICABINAS S.A.</cbc:RegistrationName>
        </cac:PartyLegalEntity>
      </cac:Party>
    </cac:AccountingCustomerParty>
    <cac:RequestedMonetaryTotal>
     <cbc:PayableAmount currencyID="PEN">1250.00</cbc:PayableAmount>
    </cac:RequestedMonetaryTotal>

    <cac:DebitNoteLine>
      <cbc:ID>1</cbc:ID>
      <cbc:DebitedQuantity unitCode="ZZ">1</cbc:DebitedQuantity>
      <cbc:LineExtensionAmount currencyID="PEN">1250.00</cbc:LineExtensionAmount>
      <cac:PricingReference>
        <cac:AlternativeConditionPrice>
          <cbc:PriceAmount currencyID="PEN">5.00</cbc:PriceAmount>
          <cbc:PriceTypeCode>01</cbc:PriceTypeCode>
        </cac:AlternativeConditionPrice>
      </cac:PricingReference>
      <cac:TaxTotal>
        <cbc:TaxAmount currencyID="PEN">0.00</cbc:TaxAmount>
        <cac:TaxSubtotal>
          <cbc:TaxAmount currencyID="PEN">0.00</cbc:TaxAmount>
          <cac:TaxCategory>
            <cbc:TaxExemptionReasonCode>20</cbc:TaxExemptionReasonCode>
            <cac:TaxScheme>
              <cbc:ID>1000</cbc:ID>
              <cbc:Name>IGV</cbc:Name>
              <cbc:TaxTypeCode>VAT</cbc:TaxTypeCode>
            </cac:TaxScheme>
          </cac:TaxCategory>
        </cac:TaxSubtotal>
      </cac:TaxTotal>
      <cac:Item>
        <cbc:Description>
          Ampliación de garantía de 6 a 12 meses de Memoria DDR-3 B1333 Kingston
        </cbc:Description>
        <cac:SellersItemIdentification>
          <cbc:ID/>
        </cac:SellersItemIdentification>
      </cac:Item>
      <cac:Price>
        <cbc:PriceAmount currencyID="PEN">5.00</cbc:PriceAmount>
      </cac:Price>
    </cac:DebitNoteLine>
</DebitNote>


text:
.container {
  display: grid;
  grid-gap: 5px;
  grid-template-columns: repeat(auto-fit, 100px);
  grid-template-rows: repeat(2, 100px);
}


text:
The javadocs for this application are found in $WRAPPER_HOME/jdoc.tar.gz.  Please extract this
archive into the $WRAPPER_HOME directory.
The javadocs could not be included directly in the
original tar distribution due to a lack of support for long path names in some tar implementations.


text:
using System;
using System.Collections.Generic;
using System.Runtime.Serialization;

namespace ChordsKaraoke.Editor.Models
{
    [Serializable]
    [DataContract]
    public class TimestampTextModel : Model
    {
        private uint _timestamp;
        private uint _length;
        private string _text;

        public TimestampTextModel()
            : this(0, 15)
        {
        }

        public TimestampTextModel(uint timestamp)
            : this(timestamp, 15)
        {
        }
        public TimestampTextModel(uint timestamp, uint lenght)
        {
            _timestamp = timestamp;
            _length = lenght;
        }

        [DataMember]
        public uint Timestamp
        {
            get { return _timestamp; }
            set { SetProperty(ref _timestamp, value); }
        }

        [DataMember]
        public uint Length
        {
            get { return _length; }
            set { SetProperty(ref _length, value); }
        }

        [DataMember]
        public string Text
        {
            get { return _text; }
            set { SetProperty(ref _text, value); }
        }

        public class TimestampTextModelComparer : IComparer<TimestampTextModel>
        {
            public int Compare(TimestampTextModel x, TimestampTextModel y)
            {
                return (x.Timestamp + x.Length).CompareTo(y.Timestamp + y.Length);
            }
        }
    }
}


text:
go_path = "/home/#{node[:login_user]}/Code/go-workspace"
go_root = '/usr/lib/go'
go_package_install_command = <<-GO_INSTALL
  export GOPATH="#{go_path}"
  export GOROOT="#{go_root}"
  export PATH="#{go_root}/bin:${PATH}"
GO_INSTALL

define :go_get, repository: nil do
  name = params[:name]
  repository = params[:repository] if params[:repository]

  unless repository.nil?
    execute "Installing golang package #{name}" do
      command("#{go_package_install_command} go get -u #{repository}")
      user node[:login_user]
      not_if "test -x #{go_path}/bin/#{name}"
    end
  end
end


text:
Reports members being declared protected in
classes that are declared final. Such members may be declared private
or package-visible instead.


text:
package de.adorsys.oauth.server;

import com.nimbusds.oauth2.sdk.*;
import com.nimbusds.oauth2.sdk.http.HTTPResponse;
import com.nimbusds.oauth2.sdk.http.ServletUtils;
import com.nimbusds.oauth2.sdk.token.BearerAccessToken;
import com.nimbusds.openid.connect.sdk.claims.UserInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

/**
 * AuthzResource
 */
@SuppressWarnings("unused")
@WebServlet("/api/auth")
@ApplicationScoped
public class AuthResource extends HttpServlet {

    private static final Logger LOG = LoggerFactory.getLogger(AuthResource.class);

    private static final String CLIENT_ID_STR = "client_id";

    @Inject
    private UserInfoFactory userInfoFactory;

    @Inject
    private TokenStore tokenStore;

    private long tokenLifetime;

    @Override
    public void init(ServletConfig config) throws ServletException {
    	try {
    		tokenLifetime = Long.valueOf(config.getServletContext().getInitParameter("lifetime"));
    	} catch (Exception e) {
    		tokenLifetime = 8 * 3600;
    	}

    	LOG.info("token lifetime {}", tokenLifetime);
    }

    @Override
    protected void doPost(HttpServletRequest servletRequest, HttpServletResponse resp) throws ServletException, IOException {

        authorize(servletRequest, resp);
    }

	private void authorize(HttpServletRequest servletRequest, HttpServletResponse resp) throws IOException {
		AuthorizationRequest request;
		try {
			request = resolveAuthorizationRequest(servletRequest);
		} catch (ParseException e) {
			ServletUtils.applyHTTPResponse(
                    new TokenErrorResponse(OAuth2Error.INVALID_REQUEST).toHTTPResponse(), resp);
			return;
		}

        URI redirectionURI = request.getRedirectionURI();
        if (redirectionURI == null) {
        	ServletUtils.applyHTTPResponse(new AuthorizationErrorResponse(request.getEndpointURI(), OAuth2Error.INVALID_REQUEST, request.getState(), request.getResponseMode()).toHTTPResponse(), resp);
        	return;
        }

        if (servletRequest.getUserPrincipal() == null) {
        	ServletUtils.applyHTTPResponse(
                    new AuthorizationErrorResponse(redirectionURI, OAuth2Error.UNAUTHORIZED_CLIENT, request.getState(), request.getResponseMode()).toHTTPResponse(), resp);
        	return;
        }

        if (request.getClientID() == null) {
        	ServletUtils.applyHTTPResponse(
                    new AuthorizationErrorResponse(redirectionURI, OAuth2Error.INVALID_CLIENT, request.getState(), request.getResponseMode()).toHTTPResponse(), resp);
        }

        if (request.getResponseType() == null) {
        	ServletUtils.applyHTTPResponse(
                    new AuthorizationErrorResponse(redirectionURI, OAuth2Error.UNSUPPORTED_RESPONSE_TYPE, request.getState(), request.getResponseMode()).toHTTPResponse(), resp);
        }

        LoginSessionToken loginSession = (LoginSessionToken) servletRequest.getAttribute("loginSession");
		// rememberme cookie exists and login session invalid => destroy
		if (loginSession != null //
				&& RememberMeCookieUtil.getCookieToken(servletRequest, request.getClientID()) != null //
				&& !tokenStore.isValid(loginSession)) {
			servletRequest.removeAttribute("loginSession");
			tokenStore.removeLoginSession(loginSession);
			HTTPResponse httpResponse = new HTTPResponse(303);
			httpResponse.setLocation(request.toURI());
			ServletUtils.applyHTTPResponse(httpResponse, resp);
			return;
		}

		UserInfo userInfo;
        if (loginSession != null) {
        	userInfo = tokenStore.loadUserInfoFromLoginSession(loginSession);
        	if (userInfo == null) {
        		userInfo = userInfoFactory.createUserInfo(servletRequest);
       			tokenStore.addLoginSession(loginSession, userInfo);
        	}
        } else {
    		userInfo = userInfoFactory.createUserInfo(servletRequest);
        }

        LOG.debug(userInfo.toJSONObject().toJSONString());

        BearerAccessToken accessToken = new BearerAccessToken(tokenLifetime, request.getScope());

		HTTPResponse response;
		if (request.getResponseType().impliesCodeFlow()) {
        	AuthorizationCode authCode = new AuthorizationCode();
            LOG.debug("impliesCodeFlow {}", authCode.toJSONString());
			tokenStore.addAuthCode(authCode, userInfo, request.getClientID(), loginSession, redirectionURI);

			response = new AuthorizationSuccessResponse(redirectionURI, authCode, null, request.getState(), request.getResponseMode()).toHTTPResponse();

        } else {
            LOG.debug("impliesTokenFlow {}", accessToken.toJSONString());
            tokenStore.addAccessToken(accessToken, userInfo, request.getClientID(), null);

            URI cleanUrl = getCleanUrl(redirectionURI);
            response = new LoginSessionAuthorizationSuccessResponse(cleanUrl, null, accessToken, request.getState(), request.getResponseMode(), loginSession, redirectionURI.getFragment()).toHTTPResponse();
        }

        LOG.debug("location {}", response.getHeader("location"));

        ServletUtils.applyHTTPResponse(response, resp);
	}

    private URI getCleanUrl(URI redirectionURI) {
        String fragmentsOfSpa = redirectionURI.getFragment();
        URI cleanUrl;
        try {
            cleanUrl = new URI(redirectionURI.toString().replace("#" + fragmentsOfSpa, ""));
        } catch (URISyntaxException e) {
            throw new OAuthException("clean url cant be parsed", null);
        }
        return cleanUrl;
    }

	@Override
	protected void doGet(HttpServletRequest servletRequest, HttpServletResponse resp) throws ServletException, IOException {
	   authorize(servletRequest, resp);
	}

    /**
     * resolveAuthorizationRequest
     */
    private AuthorizationRequest resolveAuthorizationRequest(HttpServletRequest servletRequest) throws ParseException {

        if (isNotBlank(servletRequest.getParameter(CLIENT_ID_STR))) {
			return AuthorizationRequest.parse(extractURI(servletRequest), requestParameters(servletRequest));
    	}

    	if ((contains(servletRequest.getQueryString(), CLIENT_ID_STR))) {
    		return AuthorizationRequest.parse(extractURI(servletRequest),servletRequest.getQueryString());
    	}

    	// if we are dealing with a returning SAMLREsponse we might consider parsing the relayState
    	if (servletRequest.getParameter("SAMLResponse") != null && servletRequest.getParameter("RelayState") != null){
    		try {
    			URL url = new URL(servletRequest.getParameter("RelayState"));
    			if (contains(url.getQuery(), CLIENT_ID_STR)){
    				return AuthorizationRequest.parse(url.getQuery());
    			}
    		} catch (Exception ex){
    			// Noop
    		}
    	}

        throw  new ParseException(String.format("unable to resolve AuthorizationRequest from %s", servletRequest.getRequestURI()));
    }

    private boolean contains(String queryString, String searchStr) {
        return queryString != null && queryString.contains(searchStr);
    }

	private boolean isNotBlank(String parameter) {
        return parameter != null && parameter.trim().length() > 0;
    }

	public Map<String, String> requestParameters(HttpServletRequest servletRequest){
		Enumeration<String> parameterNames = servletRequest.getParameterNames();
		Map<String, String> params = new HashMap<>();
		while (parameterNames.hasMoreElements()) {
			String param = parameterNames.nextElement();
			String value = servletRequest.getParameter(param);
            params.put(param, value);
        }
		return params;
	}

    private URI extractURI(HttpServletRequest request) {
        try {
            String query = request.getQueryString() == null ? "" : "?" + request.getQueryString();
            return new URL(request.getScheme(), request.getServerName(), request.getServerPort(), request.getRequestURI()).toURI();
        } catch (Exception e) {
            LOG.warn("Error extracting auth/ URI: " + e.getMessage());
            return null;
        }
    }
}


text:
#include "tscore/ink_config.h"
#include "tscore/ink_defs.h"
#include "ts/ts.h"

#include <dirent.h>
#include <getopt.h>
#include <inttypes.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>

#ifdef HAVE_SYS_SYSINFO_H
#include <sys/sysinfo.h>
#endif

#include <limits.h>

#define PLUGIN_NAME "system_stats"
#define DEBUG_TAG PLUGIN_NAME

// Time in MS to grab the system stats
#define SYSTEM_STATS_TIMEOUT 5000

// Load Average Strings
#define LOAD_AVG_ONE_MIN "plugin." PLUGIN_NAME ".loadavg.one"
#define LOAD_AVG_FIVE_MIN "plugin." PLUGIN_NAME ".loadavg.five"
#define LOAD_AVG_TEN_MIN "plugin." PLUGIN_NAME ".loadavg.ten"

// Process Strings
#define CURRENT_PROCESSES "plugin." PLUGIN_NAME ".current_processes"

// Base net stats name, full name needs to populated
// with NET_STATS.infname.RX/TX.standard_net_stats field
#define NET_STATS "plugin." PLUGIN_NAME ".net."

#define NET_STATS_DIR "/sys/class/net"
#define STATISTICS_DIR "statistics"

static int
statAdd(const char *name, TSRecordDataType record_type, TSMutex create_mutex)
{
  int stat_id = -1;

  TSMutexLock(create_mutex);

  if (TS_ERROR == TSStatFindName(name, &stat_id)) {
    stat_id = TSStatCreate(name, record_type, TS_STAT_NON_PERSISTENT, TS_STAT_SYNC_SUM);
    if (stat_id == TS_ERROR) {
      TSDebug(DEBUG_TAG, "Error creating stat_name: %s", name);
    } else {
      TSDebug(DEBUG_TAG, "Created stat_name: %s stat_id: %d", name, stat_id);
    }
  }

  TSMutexUnlock(create_mutex);

  return stat_id;
}

static int
getFile(const char *filename, char *buffer, int bufferSize)
{
  TSFile f = 0;
  size_t s = 0;

  f = TSfopen(filename, "r");
  if (!f) {
    buffer[0] = 0;
    // Return -1 to indicate read err
    return -1;
  }

  s = TSfread(f, buffer, bufferSize);
  if (s > 0) {
    buffer[s] = 0;
  } else {
    buffer[0] = 0;
  }

  TSfclose(f);

  return s;
}

static void
statSet(const char *name, int value, TSMutex stat_creation_mutex)
{
  int stat_id = statAdd(name, TS_RECORDDATATYPE_INT, stat_creation_mutex);
  if (stat_id != TS_ERROR) {
    TSStatIntSet(stat_id, value);
  }
}

static void
setNetStat(TSMutex stat_creation_mutex, const char *interface, const char *entry, const char *subdir)
{
  char sysfs_name[PATH_MAX];
  char stat_name[255];
  char data[255];

  memset(&stat_name[0], 0, sizeof(stat_name));
  memset(&sysfs_name[0], 0, sizeof(sysfs_name));
  memset(&data[0], 0, sizeof(data));

  if ((interface == NULL) || (entry == NULL)) {
    TSError("%s: NULL subdir or entry", DEBUG_TAG);
    return;
  }

  // Generate the ATS stats name
  snprintf(&stat_name[0], sizeof(stat_name), "%s%s.%s", NET_STATS, interface, entry);

  // Determine if this is a toplevel netdev stat, or one from statistics.
  if (subdir == NULL) {
    snprintf(&sysfs_name[0], sizeof(sysfs_name), "%s/%s/%s", NET_STATS_DIR, interface, entry);
  } else {
    snprintf(&sysfs_name[0], sizeof(sysfs_name), "%s/%s/%s/%s", NET_STATS_DIR, interface, subdir, entry);
  }

  if (getFile(&sysfs_name[0], &data[0], sizeof(data)) < 0) {
    TSDebug(DEBUG_TAG, "Error reading file %s", sysfs_name);
  } else {
    statSet(stat_name, atoi(data), stat_creation_mutex);
  }
}

static int
netStatsInfo(TSMutex stat_creation_mutex)
{
  struct dirent *dent;
  DIR *srcdir = opendir(NET_STATS_DIR);

  if (srcdir == NULL) {
    return 0;
  }

  while ((dent = readdir(srcdir)) != NULL) {
    if (strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0 || strcmp(dent->d_name, "lo") == 0) {
      continue;
    }

    setNetStat(stat_creation_mutex, dent->d_name, "speed", NULL);
    setNetStat(stat_creation_mutex, dent->d_name, "collisions", STATISTICS_DIR);
    setNetStat(stat_creation_mutex, dent->d_name, "multicast", STATISTICS_DIR);
    setNetStat(stat_creation_mutex, dent->d_name, "rx_bytes", STATISTICS_DIR);
    setNetStat(stat_creation_mutex, dent->d_name, "rx_compressed", STATISTICS_DIR);
    setNetStat(stat_creation_mutex, dent->d_name, "rx_crc_errors", STATISTICS_DIR);
    setNetStat(stat_creation_mutex, dent->d_name, "rx_dropped", STATISTICS_DIR);
    setNetStat(stat_creation_mutex, dent->d_name, "rx_errors", STATISTICS_DIR);
    setNetStat(stat_creation_mutex, dent->d_name, "rx_fifo_errors", STATISTICS_DIR);
    setNetStat(stat_creation_mutex, dent->d_name, "rx_frame_errors", STATISTICS_DIR);
    setNetStat(stat_creation_mutex, dent->d_name, "rx_length_errors", STATISTICS_DIR);
    setNetStat(stat_creation_mutex, dent->d_name, "rx_missed_errors", STATISTICS_DIR);
    setNetStat(stat_creation_mutex, dent->d_name, "rx_nohandler", STATISTICS_DIR);
    setNetStat(stat_creation_mutex, dent->d_name, "rx_over_errors", STATISTICS_DIR);
    setNetStat(stat_creation_mutex, dent->d_name, "rx_packets", STATISTICS_DIR);
    setNetStat(stat_creation_mutex, dent->d_name, "tx_aborted_errors", STATISTICS_DIR);
    setNetStat(stat_creation_mutex, dent->d_name, "tx_bytes", STATISTICS_DIR);
    setNetStat(stat_creation_mutex, dent->d_name, "tx_carrier_errors", STATISTICS_DIR);
    setNetStat(stat_creation_mutex, dent->d_name, "tx_compressed", STATISTICS_DIR);
    setNetStat(stat_creation_mutex, dent->d_name, "tx_dropped", STATISTICS_DIR);
    setNetStat(stat_creation_mutex, dent->d_name, "tx_errors", STATISTICS_DIR);
    setNetStat(stat_creation_mutex, dent->d_name, "tx_fifo_errors", STATISTICS_DIR);
    setNetStat(stat_creation_mutex, dent->d_name, "tx_heartbeat_errors", STATISTICS_DIR);
    setNetStat(stat_creation_mutex, dent->d_name, "tx_packets", STATISTICS_DIR);
    setNetStat(stat_creation_mutex, dent->d_name, "tx_window_errors", STATISTICS_DIR);
  }

  closedir(srcdir);

  return 0;
}

static void
getStats(TSMutex stat_creation_mutex)
{
#ifdef HAVE_SYS_SYSINFO_H
  struct sysinfo info;

  sysinfo(&info);

  statSet(LOAD_AVG_ONE_MIN, info.loads[0], stat_creation_mutex);
  statSet(LOAD_AVG_FIVE_MIN, info.loads[1], stat_creation_mutex);
  statSet(LOAD_AVG_TEN_MIN, info.loads[2], stat_creation_mutex);
  statSet(CURRENT_PROCESSES, info.procs, stat_creation_mutex);
#endif // #ifdef HAVE_SYS_SYSINFO_H
  netStatsInfo(stat_creation_mutex);

  return;
}

static int
systemStatsContCB(TSCont cont, TSEvent event ATS_UNUSED, void *edata)
{
  TSMutex stat_creation_mutex;

  TSDebug(DEBUG_TAG, "entered %s", __FUNCTION__);

  stat_creation_mutex = TSContMutexGet(cont);
  getStats(stat_creation_mutex);

  TSContScheduleOnPool(cont, SYSTEM_STATS_TIMEOUT, TS_THREAD_POOL_TASK);
  TSDebug(DEBUG_TAG, "finished %s", __FUNCTION__);

  return 0;
}

void
TSPluginInit(int argc, const char *argv[])
{
  TSPluginRegistrationInfo info;
  TSCont stats_cont;

  info.plugin_name   = PLUGIN_NAME;
  info.vendor_name   = "Apache Software Foundation";
  info.support_email = "dev@trafficserver.apache.org";

  if (TSPluginRegister(&info) != TS_SUCCESS) {
    TSError("[%s] Plugin registration failed", DEBUG_TAG);
    return;
  } else {
    TSDebug(DEBUG_TAG, "Plugin registration succeeded");
  }

  stats_cont = TSContCreate(systemStatsContCB, TSMutexCreate());
  TSContDataSet(stats_cont, NULL);

  // We want our first hit immediate to populate the stats,
  // Subsequent schedules done within the function will be for
  // 5 seconds.
  TSContScheduleOnPool(stats_cont, 0, TS_THREAD_POOL_TASK);

  TSDebug(DEBUG_TAG, "Init complete");
}