///<remarks>
        /// END user configurable fields
        ///</remarks>

        /// <summary>
        /// the entry point for smart contract execution
        /// </summary>
        /// <param name="operation">string to determine execution operation performed</param>
        /// <param name="args">optional arguments, context specific depending on operation</param>
        /// <returns></returns>
        public static object Main(string operation, params object[] args)
        {
            if (Runtime.Trigger == TriggerType.Application)
            {
                //Only allow InitSmartContract if contract not initialized and not calling whitelist/KYC operations
                if(!Helpers.ContractInitialised() && ((operation != "admin" && (string) args[0] != "InitSmartContract") && operation != "AddAddress" && operation != "RevokeAddress" && operation != "GetGroupNumber" && operation != "crowdsale_status"))
                {
                    Runtime.Log("Smart Contract not Initialised");
                    return false;
                }

                if (operation == "admin" && Helpers.VerifyIsAdminAccount())
                {
                    // allow access to administration methods
                    string adminOperation = (string)args[0];
                    foreach (string adminMethod in Administration.GetAdministrationMethods())
                    {
                        if (adminMethod == adminOperation)
                        {
                            return Administration.HandleAdministrationOperation(adminOperation, args);
                        }
                    }
                    return false;
                }

                // test if a nep5 method is being invoked
                foreach (string nepMethod in NEP5.GetNEP5Methods())
                {
                    if (nepMethod == operation)
                    {
                        return NEP5.HandleNEP5Operation(operation, args, ExecutionEngine.CallingScriptHash, ExecutionEngine.EntryScriptHash);
                    }
                }

                // test if a kyc method is being invoked
                foreach (string kycMethod in KYC.GetKYCMethods())
                {
                    if (kycMethod == operation)
                    {
                        return KYC.HandleKYCOperation(operation, args);
                    }
                }

                // test if a helper/misc method is being invoked
                foreach (string helperMethod in Helpers.GetHelperMethods())
                {
                    if (helperMethod == operation)
                    {
                        return Helpers.HandleHelperOperation(operation, args);
                    }
                }

                //If MintTokensEth operation
                if(operation == "MintTokensEth")
                {
                    // Method can only be called by the ETH contributions listener account
                    if (Helpers.VerifyWitness(ICOTemplate.EthContributionListenerKey) && Helpers.RequireArgumentLength(args,3))
                    {
                        return EthSale.MintTokensEth((string)args[0], (byte[])args[1], (ulong)args[2]);
                    }
                }

            }
            else if (Runtime.Trigger == TriggerType.Verification)
            {
                if (Helpers.VerifyIsAdminAccount())
                {
                    return true;
                }

                // test if this transaction is allowed
                object[] transactionData = Helpers.GetTransactionAndSaleData();
                return TokenSale.CanUserParticipateInSale(transactionData);
            }

            return false;
        }