GithubHelp home page GithubHelp logo

authorizenet / sdk-dotnet Goto Github PK

View Code? Open in Web Editor NEW
149.0 47.0 200.0 6.9 MB

.Net SDK for Authorize.Net API

License: Other

C# 96.46% HTML 0.63% Batchfile 2.91%
payment payment-gateway payments payment-integration payment-module payment-processing payment-service payment-methods authorizenet visa

sdk-dotnet's People

Contributors

adavidw avatar akankaria avatar anuragg29 avatar arktseytlin avatar ashtru avatar baluveer avatar baluveermukkamala avatar billboyde avatar brianmc avatar cforbesywam avatar csantero avatar dthurman avatar gnongsie avatar katterisharath avatar khaaldrogo avatar kikmak42 avatar leniency avatar mmikirtumov avatar namanbansal avatar ncpga avatar rahulrnitc avatar ramittal avatar rburgstaler avatar sapbasu15 avatar spurama avatar sudhirkumar2018 avatar suezhu avatar vijayabraj avatar xianwang423 avatar zalak1612 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

sdk-dotnet's Issues

Fix CreateCustomer method in CustomerGateway

Allow passing of merchantCustomerId. This works and I have implemented it in one of my projects.

public Customer CreateCustomer(string email, string description, string merchantCustomerId)
    {
        //use the XSD class to create the profile
       var newCustomer = new customerProfileType();
       newCustomer.description = description;
       newCustomer.email = email;
       newCustomer.merchantCustomerId = merchantCustomerId;

       var req = new createCustomerProfileRequest();

       req.profile = newCustomer;

       //serialize and send
       var response = (createCustomerProfileResponse)_gateway.Send(req);

       //set the profile ID
       return new Customer {
           Email = email,
           Description = description,
           ProfileID = response.customerProfileId,
           ID = merchantCustomerId
       };
    }

Error in updateSubscriptions Request

The updateSubscription Request makes use of a function called "ToUpdateableAPI" to apparently remove elements that would conflict with the update request. This function procludes some updatedable fields such as description and invoice. It also includes some elements that can't be changed such as schedule, occurences, and amount.

Amounts are converted to string using enviroment culture. But invariant culture should be used

for example in CardPresentPriorAuthCapture.cs file (and in many other places) there is a code line:
this.Queue(ApiFields.Amount, amount.ToString());

So, if in your environment decimal separator is ",", then decimal 5.5M is converted to string "5,5".

it should be:
this.Queue(ApiFields.Amount, amount.ToString(CultureInfo.InvariantCulture));

Because in AIM_guide.pdf documentation field x_amount description says:
Value: Amount of the transaction.
Format: 15 digit-maximum, with a decimal point (no dollar symbol). For
example, 8.95.
Notes: This is the total amount and must include tax, shipping, and any
other charges.

Invalid values returned from AuthorizeAndCapture (Test)

In test mode (and could be production), the AuthorizeAndCapture method of CIM returns null/0 for all properties. I would assume that it isn't parsing the returned data correctly. A valid transaction returns Approved = false and AuthorizationCode/Amount to null.

            var response = gateway.AuthorizeAndCapture(order);

            if (!response.Approved){
                throw new AuthorizeNetException("The transaction was not approved.");
            }

            var payment = new Payment{
                DateTime = DateTime.Now,
                Type = PaymentType.CreditCard,
                AuthorizationCode = response.AuthorizationCode,
                Amount = response.Amount
            };

response.ResponseCode = "OkI00001Successful."
response.Approved = false
response.CAVResponse = "Blank or not present = CAVV not validated"

Environment class Poorly Named

The new Environment (Environment.cs) class causes collisions with the System.Environment class, with the result that references to either class must be fully defined.
Change class name to something that does not cause collisions.

Controller: Create Profile from transaction

This works well, except that when the profile is created the original transaction is not associated to the new profile. Also the system creates the billing address as a new shipto address which is not something I would personally desire as it may be a billing address only.

Allow ValidationMode for AddCreditCard

Because we do not want to validate by charging the customer to create a payment profile, it would be beneficial to be able to set this.
I changed it on my local as below:

public string AddCreditCard(string profileID, string cardNumber, int expirationMonth, int expirationYear, string cardCode, Address billToAddress,validationModeEnum validationMode) {

        // Get the expiration date.

        DateTime dt; // = DateTime.Parse(expirationMonth.ToString() + "-1-" + expirationYear.ToString());
        if (!CommonFunctions.ParseDateTime(expirationYear, expirationMonth, 1, out dt))
        { throw new Exception("Invalid credit card expiration date"); }

        DateTime expDate = new DateTime(dt.Year, dt.Month, 1).AddMonths(1).AddDays(-1);
        string sExpDate = expDate.ToString("yyyy-MM");
        // Make sure the card has not expired.
        if (expDate <= DateTime.Now)
            throw new Exception("The credit card expiration date \"" + sExpDate + "\" is expired.");

        var req = new createCustomerPaymentProfileRequest();


        req.customerProfileId = profileID;
        req.paymentProfile = new customerPaymentProfileType();
        req.paymentProfile.payment = new paymentType();
        req.validationMode=validationMode;
        req.validationModeSpecified=true;
        var card = new creditCardType();
        if (!String.IsNullOrEmpty(cardCode)) card.cardCode = cardCode;
        card.cardNumber = cardNumber;
        card.expirationDate = sExpDate;
        req.paymentProfile.payment.Item = card;

        if (billToAddress != null)
            req.paymentProfile.billTo = billToAddress.ToAPIType();

        req.validationModeSpecified = true;
        req.validationMode = this._mode;

        var response = (createCustomerPaymentProfileResponse)_gateway.Send(req);

        return response.customerPaymentProfileId;
    }

Reporting Api missing x_response_reason_code

We have been relying on the silent-postback process data to check our ARB transactions for quite a while as that was the only place we could get the subscription information, but once in a while we have come up with some missing record from the postback process.

To handle this we started looking for the missing transaction with the reporting API (now that you have the subscriptionid in there its MUCH easier, THANK YOU).

One piece that is still missing is the x_response_reason_code, and we use that to detect if the card expired or its just a failed transaction, so we can send a appropriate response to the card holder.

We have tried using the x_response_reason_text, but the postback version and the reporting version don't seem to be coming from the same place. See example below:
REPORTING: "Approval"
POSTBACK: "This transaction has been approved."

Is there any chance you could add x_response_reason_code to the API and in the mean time post a list of the response_reason_text returned returned form the reporting API so we can make a look up on that for now? I looked through the API SDK and could only find table for:
CAVVResponse, CardResponse, AVSResponse, TransactionStatus

Just as an FYI while your in there, these fields are also missing ;)
x_subscription_paynum
x_cvv2_resp_code
x_md5_hash
x_freight

Thanks again for your help!

GBY.
-R

CIM Credit Card AVS Fail does not return meaningful error

Anytime we have an AVS mismatch (where zip/street is a no match) the system simply returns an e0027 and nothing else. There are no errors in the transactions nor anywhere else.
E0027 is not very specific and does not help.
This is specific to CIM.

Method not found

Hi

When I try to use ARB payment and when I call PopulateSubscription, its throwing a error as first value i am set in that function.

Method not found: 'Void AuthorizeNet.APICore.ARBSubscriptionType.set_name(System.String)'.

Method not found: 'Void AuthorizeNet.APICore.creditCardSimpleType.set_cardNumber(System.String)'.

Please help.

Thanks,
Jaffer

HttpXmlUtility.Send() is not thread-safe.

Because _xmlDoc is a class-level variable, HttpXmlUtility.Send() is not thread-safe. As an example, if I attempt to call ReportingGateway.GetTransactionDetails in parallel for multiple transaction Ids, I get strange behavior like null reference exceptions because multiple threads are using the same XmlDocument instance. Would suggest moving _xmlDoc inside the 'Send' method.

Illegal child notes when rendering profileTransAuthCapture via CIM

STR:

        var gateway = new CustomerGateway(_apiLogin, _transactionKey, _serviceMode);

        var order = new Order(_customerProfileId, _paymentProfileId, null)
        {
            Amount = amount,
            Description = placeholder
        };

        IGatewayResponse response = null;

        switch (_authType)
        {
            case "AUTH_CAPTURE":
                response = gateway.AuthorizeAndCapture(order);
                break;
            default:
                throw new NotImplementedException("derp.");
        }

Result:

"exceptionMessage": "Error processing request: E00003 - The element 'profileTransAuthCapture' in namespace 'AnetApi/xml/v1/schema/AnetApiSchema.xsd' has invalid child element 'customerPaymentProfileId' in namespace 'AnetApi/xml/v1/schema/AnetApiSchema.xsd'. List of possible elements expected: 'tax, shipping, duty, lineItems, customerProfileId' in namespace 'AnetApi/xml/v1/schema/AnetApiSchema.xsd'.",

Refund transaction returns error code E0027, no details

I am testing code to perform a refund transaction, and it is failing with this same E0027 error as described here: #73.

I am using a sandbox account and the "Controller" method for accessing the API. I am able to submit test AuthorizeAndCapture charges and Void them, getting correct responses. However, when I go to a refundTransaction against an existing unsettled charge, I am getting this E0027 error with absolutely no additional detail: all fields of transactionResponse are null, and there is no text description on the message.

In the issue I linked to, the suspected cause of the problem is an AVS validation error. However, for testing purposes I tried disabling both AVS and CCV filtering entirely on my sandbox account, and the error persists.

Here is a version of the code I am using, edited for clarity:

var request = new createTransactionRequest {
    transactionRequest = new transactionRequestType {
        transactionType = transactionTypeEnum.refundTransaction.ToString(),
        refTransId = transaction.TransactionID,
        amount = amount.Value,
        profile = new customerProfilePaymentType {
            customerProfileId = transaction.CreditCardProfile.Profile.AuthNetCustomerID,
            paymentProfile = new paymentProfile {
                paymentProfileId = transaction.CreditCardProfile.AuthNetPaymentID,
                cardCode = transaction.CreditCardProfile.CCV,
            }
        },
    }
};
var response = MakeRequest( request );

The MakeRequest() method shown ultimately does something like this:

var controller = new transactionRequestController( request );
var response = controller.ExecuteWithApiResponse( Environment );

Then the following statements hold true for the returned response:
response.transactionResponse.* == null
response.messages.resultCode == messageTypeEnum.Error
response.messages.message[0].code == "E0027"
response.messages.message[0].text == null

No support for AIM Prior_Auth_Capture

GatewayRequest.cs maps capture to prior_auth_Capture. There are multiple places in the SDK where Capture_Only is confused with Prior_Auth_Capture, so these should probably all be reviewed.

HttpXMLUtility.CheckForErrors Method in the C# Library doesn't parse Response Correctly

I've been working with the .Net SDK for Authorize.Net API from GitHub (version 1.8.3) and it seems that the CheckForErrors method in HttpXMLUtility is returning the incorrect response. It seemed as if the response was being altered and the response parameters like AuthCode and ResponseCode are missing.

This is being called from HttpXMLUtility.Send whether I do an Auth or a Capture. Both cases don't return an AuthCode.

In debugging it looks like the XML Response has 2 Child.Child level nodes. One is "messages" and the other is "directReponse". The way it is coded messages is the first Child.Child node, so it sets thingy.directReponse to the message and it never grabs the directReponse. (See current code below)

    void CheckForErrors(ANetApiResponse response) {

        if (response.GetType() == typeof(createCustomerProfileTransactionResponse)) {
            //there's a directResponse we need to find...
            var thingy = (createCustomerProfileTransactionResponse)response;
            thingy.directResponse = null;
            for (var i = 0; i <= 1; i++)
            {
                if (null != _xmlDoc && null != _xmlDoc.ChildNodes[i])
                {
                    for (var j = 0; j <= 1; j++)
                    {
                        if (null != _xmlDoc.ChildNodes[i].ChildNodes[j])
                        {
                            thingy.directResponse = _xmlDoc.ChildNodes[i].ChildNodes[j].InnerText;
                        }
                        if (null != thingy.directResponse) { break; }
                    }
                }
                if (null != thingy.directResponse) { break; }
            }
            response = thingy;
        } else {

            if (response.messages.message.Length > 0) {

                if (response.messages.resultCode == messageTypeEnum.Error) {
                    StringBuilder sb = new StringBuilder();
                    for (int i = 0; i < response.messages.message.Length; i++) {
                        sb.AppendFormat("Error processing request: {0} - {1}", response.messages.message[i].code, response.messages.message[i].text);
                    }
                    throw new InvalidOperationException(sb.ToString());
                }

            }
        }
    }

Should this inner look not be checking specifically for the directReponse node if there are more than one Child.Child node?

Perhaps it should be modified as so:

    void CheckForErrors(ANetApiResponse response) {

        if (response.GetType() == typeof(createCustomerProfileTransactionResponse)) {
            //there's a directResponse we need to find...
            var thingy = (createCustomerProfileTransactionResponse)response;
            thingy.directResponse = null;
            for (var i = 0; i <= 1; i++)
            {
                if (null != _xmlDoc && null != _xmlDoc.ChildNodes[i])
                {
                    for (var j = 0; j <= 1; j++)
                    {
                        if (null != _xmlDoc.ChildNodes[i].ChildNodes[j])
                        {
                            if (_xmlDoc.ChildNodes[i].ChildNodes[j].Name == "directResponse")
                            {
                                thingy.directResponse = _xmlDoc.ChildNodes[i].ChildNodes[j].InnerText;
                            }
                        }
                        if (null != thingy.directResponse) { break; }
                    }
                }
                if (null != thingy.directResponse) { break; }
            }
            response = thingy;
        } else {

            if (response.messages.message.Length > 0) {

                if (response.messages.resultCode == messageTypeEnum.Error) {
                    StringBuilder sb = new StringBuilder();
                    for (int i = 0; i < response.messages.message.Length; i++) {
                        sb.AppendFormat("Error processing request: {0} - {1}", response.messages.message[i].code, response.messages.message[i].text);
                    }
                    throw new InvalidOperationException(sb.ToString());
                }

            }
        }
    }

Looking to get some feedback in case I'm not on the right track.

Strong Name Assembly

Is there anyway that you can give a strong name to the AuthorizeNet.dll assembly that is officially released? I pull it down from NuGet as new versions are released and I cannot give any assemblies that use it a strong name.

The assembly with display name 'AuthorizeNet.XmlSerializers' failed to load in the 'LoadFrom' binding context

Using the Authorize.net SDK C# System.xml 4.5 on VS 2012 from nuget, attempts at sending a request to add a credit card to an existing customer profile fails with following error:

The assembly with display name 'AuthorizeNet.XmlSerializers' failed to load in the 'LoadFrom' binding context of the AppDomain with ID 17. The cause of the failure was: System.IO.FileNotFoundException: Could not load file or assembly 'AuthorizeNet.XmlSerializers, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.

After adding the HttpXMLUtility.cs to my project, I was able to determine it was failing at line 65 "var serializer = new XmlSerializer(type);" in ANetApiResponse.Send. I figured that I was missing the AuthorizeNet.XmlSerializer, but after searching no such library exists.

This library is exactly what I need to add a paymentprofile to an existing customerprofile. To no avail, I have been unable to find a substitute.

AuthorizationRequest is performing AuthAndCapture

All the transactions performed using Gateway and AuthorizationRequest are performing authorization and capture and my assumption is based on two reasons.

  1. When I request PriorAuthCapture its not able to find transaction.
  2. When unsettled transactions pulled using transactiondetail API they show a status of capturedPendingSettlement.
  3. On Transaction Report page for unsettled transaction also shows the same.

I was looking for Auth_Only request and AuthorizationRequest is not doing it. Please assist me.

Thanks,
Kashyap

CustomerAddress Missing "City"

In the AIM IGatewayRequest AddCustomer method, there is not way to enter the customers city. This is also the case for the AddShipping method.

some GatewayResponse values are wrong if Order.Description contains a comma

Here's my specific use case:

decimal amount = 159m;
orderDesc = "Some text, with a comma";
AuthorizeNet.Order order = new AuthorizeNet.Order(profileId, paymentProfileId, shippingAddress)
{
    Amount = amount,
    Description = orderDesc
};

IGatewayResponse authorizeNetResp  = customerGateway.AuthorizeAndCapture(order);

// authorizeNetResp.Amount is 0 but should be 159

This is probably happening in a lot of scenarios (if address or shipping fields contain commas) because the response contains those fields, and just does a .Split(",") to parse out all the values. If the request has a description (or address or shipping field) that contains a comma, all the values after that in the response are messed up.

As a workaround for now, I am just removing commas from the description.

AuthorizeNet.Helpers

What happened to this assembly? I was using it from version 1.7.1 of the nuget package and after upgrading to 1.8.2 it is no longer part of the nuget package. I need it to construct the response in my Payment Relay Endpoint in a Direct Post configuration. Please advise.

CIM AuthorizeAndCapture: Successful ResponseCode but Approved is false, with no errors

When trying to AuthorizeAndCapture using CIM, I am receiving a successful ResponseCode, but Approved is false. I tried the Unit Test from github and received the same message.

Someone else is also experiencing this posted on the forums: https://community.developer.authorize.net/t5/Integration-and-Testing/CIM-AuthorizeAndCapture-Approved-flag-set-to-false/m-p/49633#M25180

There are no error messages and am at a loss right now as to solve the problem.

x_cust_ip should be x_customer_ip

This was probably mistakenly entered due to confusion between x_cust_id and x_customer_ip. But the IP address is not being sent correctly because of it.

The error is in ApiFields.cs

API. Create Transaction AuthCApture

Every call into this using an existing customer profile returns an e0027 error in production. Using older SDK, things are fine and in sandbox everything is fine. The message says test transaction failed. I am setting the environment to product and all other calls work fine. The customer is created, the payment profile is created as well. It seems to be only when I try to charge a profile using the API as documented.
IT seems that in most of this SDK that charging a CIM customer is failing at some point. The old methods do not work an longer and new methods fail in production. I would greatly appreciate some feed back as this will cause us business loss.

Free Trial is not possible

Hello,

trying to create a free trial using ISubscriptionRequest.SetTrialPeriod method

subscription.SetTrialPeriod(1, 0); // the trial amount is zero dollars

but I am getting this error
Error processing request: E00026 - Both Trial Amount and Trial Occurrences are required.

The code checks if the TrialAmount is greater than Zero and only then sets ".hasTrialAmount". To workaround this I am doing something like this:

subscription.SetTrialPeriod(1, new Decimal(0.0001))

and I am not sure if that is a "Free Trial" anyway.

So, my current plan is to set StartDate to the date after the trial period ends and not use TrialAmount and TrialOccurencies properties at all.

Please advise.

No way to set the CIM validationMode Parameter

Hey guys! Thanks for the great work.

I am a high volume authorize.net customer and do not want to validate a customer payment profile each time a new one is added. It basically doubles my costs if the system automatically submits two transactions per order. Having the ability to set the parameter to validationMode.none, would save me a ton of money.

I appreciate your consideration.

How to pass value of the parameter ' x_duplicate_window '?

I have been using AuthorizeNet.dll for last 6 months, it is working great! Recently I am getting following error for few transactions :
"A duplicate transaction has been submitted"
I do research online and found the following link that explain nicely
https://support.authorize.net/authkb/index?page=content&id=A425&actp=LIST

My question is: How can I pass value for the parameter 'x_duplicate_window' once I call the following method, CustomerGateway.cs -> public IGatewayResponse AuthorizeAndCapture(Order order)?
Or do I need to modify something inside the AuthorizeAndCapture method?
Or do I need to modify something inside the HttpXmlUtility.cs->ANetApiResponse Send(ANetApiRequest apiRequest)

I appreciate any help. Thanks

Error response codes are not available with Subscription requests.

Currently, if there is an error, an Invalid Operation Exception is being thrown, with message like: Error processing request: E00013 - Credit Card Number is invalid.

The error codes are not available in a strongly typed manner. The above message is not really user friendly and I would have to parse it to get the error code, which is error prone.

Can you add a strongly typed response for Subscription request instead of throwing an Exception? Our web site is multilanguage, so we need to translate the error codes.

Thanks!

NullReferenceException on GetTransactionDetails

This issue occurs completely random. I pass a valid transaction id string to GetTransactionDetails and CheckForErrors throws a NullReferenceException.

Stack Trace:

at AuthorizeNet.HttpXmlUtility.CheckForErrors(ANetApiResponse response) in c:\Users\dwoodfor\Downloads\sdk-dotnet-master\sdk-dotnet-master\Authorize.NET\Utility\HttpXmlUtility.cs:line 99
at AuthorizeNet.HttpXmlUtility.Send(ANetApiRequest apiRequest) in c:\Users\dwoodfor\Downloads\sdk-dotnet-master\sdk-dotnet-master\Authorize.NET\Utility\HttpXmlUtility.cs:line 80
at AuthorizeNet.ReportingGateway.GetTransactionDetails(String transactionID) in c:\Users\dwoodfor\Downloads\sdk-dotnet-master\sdk-dotnet-master\Authorize.NET\Reporting\ReportingGateway.cs:line 121
at NutraCardWeb.Controllers.TransactionController.Get(String id) in c:\Users\dwoodfor\Documents\Visual Studio 2012\Projects\NutraCardWeb\NutraCardWeb\Controllers\TransactionController.cs:line 30
at lambda_method(Closure , Object , Object[] )
at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.<>c__DisplayClass10.b__9(Object instance, Object[] methodParameters)
at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.Execute(Object instance, Object[] arguments)
at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ExecuteAsync(HttpControllerContext controllerContext, IDictionary`2 arguments, CancellationToken cancellationToken)

Bug: CIM Authorize/Capture returns approved false every call

I have tried multiple times and each time I do an authorize/Capture using a customer profile and Authorize.order object, the response comes back as approved=false although in the sandbox I show a transaction approval. When I charge the card through AIM, it works fine.
This seems specific to CIM

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.