/// <summary>
        /// Runs the code example.
        /// </summary>
        /// <param name="user">The AdWords user.</param>
        public void Run(AdWordsUser user)
        {
            using (BatchJobService batchJobService =
                       (BatchJobService)user.GetService(AdWordsService.v201806.BatchJobService))
            {
                try
                {
                    // Create a BatchJob.
                    BatchJobOperation addOp = new BatchJobOperation()
                    {
                        @operator = Operator.ADD,
                        operand   = new BatchJob()
                    };

                    BatchJob batchJob = batchJobService.mutate(new BatchJobOperation[]
                    {
                        addOp
                    }).value[0];

                    // Get the upload URL from the new job.
                    string uploadUrl = batchJob.uploadUrl.url;

                    Console.WriteLine(
                        "Created BatchJob with ID {0}, status '{1}' and upload URL {2}.",
                        batchJob.id, batchJob.status, batchJob.uploadUrl.url);

                    BatchJobUtilities batchJobUploadHelper = new BatchJobUtilities(user);

                    // Create a resumable Upload URL to upload the operations.
                    string resumableUploadUrl =
                        batchJobUploadHelper.GetResumableUploadUrl(uploadUrl);

                    BatchUploadProgress uploadProgress =
                        batchJobUploadHelper.BeginStreamUpload(resumableUploadUrl);

                    // Create and add an operation to create a new budget.
                    BudgetOperation budgetOperation = BuildBudgetOperation();

                    uploadProgress = batchJobUploadHelper.StreamUpload(uploadProgress,
                                                                       new List <Operation>()
                    {
                        budgetOperation
                    });

                    // Create and add operations to create new campaigns.
                    List <Operation> campaignOperations = new List <Operation>();
                    campaignOperations.AddRange(
                        BuildCampaignOperations(budgetOperation.operand.budgetId));

                    uploadProgress =
                        batchJobUploadHelper.StreamUpload(uploadProgress, campaignOperations);

                    // Create and add operations to create new ad groups.
                    List <Operation> adGroupOperations = new List <Operation>();
                    foreach (CampaignOperation campaignOperation in campaignOperations)
                    {
                        adGroupOperations.AddRange(
                            BuildAdGroupOperations(campaignOperation.operand.id));
                    }

                    uploadProgress =
                        batchJobUploadHelper.StreamUpload(uploadProgress, adGroupOperations);

                    // Create and add operations to create new ad group ads (expanded text ads).
                    List <Operation> adOperations = new List <Operation>();
                    foreach (AdGroupOperation adGroupOperation in adGroupOperations)
                    {
                        adOperations.AddRange(
                            BuildAdGroupAdOperations(adGroupOperation.operand.id));
                    }

                    uploadProgress =
                        batchJobUploadHelper.StreamUpload(uploadProgress, adOperations);

                    // Create and add operations to create new ad group criteria (keywords).
                    List <Operation> keywordOperations = new List <Operation>();
                    foreach (AdGroupOperation adGroupOperation in adGroupOperations)
                    {
                        keywordOperations.AddRange(
                            BuildAdGroupCriterionOperations(adGroupOperation.operand.id));
                    }

                    uploadProgress =
                        batchJobUploadHelper.StreamUpload(uploadProgress, keywordOperations);

                    // Mark the upload as complete.
                    batchJobUploadHelper.EndStreamUpload(uploadProgress);

                    bool isCompleted = batchJobUploadHelper.WaitForPendingJob(batchJob.id,
                                                                              TIME_TO_WAIT_FOR_COMPLETION,
                                                                              delegate(BatchJob waitBatchJob, long timeElapsed)
                    {
                        Console.WriteLine("[{0} seconds]: Batch job ID {1} has status '{2}'.",
                                          timeElapsed / 1000, waitBatchJob.id, waitBatchJob.status);
                        batchJob = waitBatchJob;
                        return(false);
                    });

                    if (!isCompleted)
                    {
                        throw new TimeoutException(
                                  "Job is still in pending state after waiting for " +
                                  TIME_TO_WAIT_FOR_COMPLETION + " seconds.");
                    }

                    if (batchJob.processingErrors != null)
                    {
                        foreach (BatchJobProcessingError processingError in batchJob
                                 .processingErrors)
                        {
                            Console.WriteLine("  Processing error: {0}, {1}, {2}, {3}, {4}",
                                              processingError.ApiErrorType, processingError.trigger,
                                              processingError.errorString, processingError.fieldPath,
                                              processingError.reason);
                        }
                    }

                    if (batchJob.downloadUrl != null && batchJob.downloadUrl.url != null)
                    {
                        BatchJobMutateResponse mutateResponse =
                            batchJobUploadHelper.Download(batchJob.downloadUrl.url);
                        Console.WriteLine("Downloaded results from {0}.", batchJob.downloadUrl.url);
                        foreach (MutateResult mutateResult in mutateResponse.rval)
                        {
                            string outcome = mutateResult.errorList == null ? "SUCCESS" : "FAILURE";
                            Console.WriteLine("  Operation [{0}] - {1}", mutateResult.index,
                                              outcome);
                        }
                    }
                }
                catch (Exception e)
                {
                    throw new System.ApplicationException(
                              "Failed to add campaigns using batch job.", e);
                }
            }
        }
        /// <summary>
        /// Runs the code example.
        /// </summary>
        /// <param name="user">The AdWords user.</param>
        /// <param name="adGroupId">Id of the ad groups to which keywords are
        /// added.</param>
        public void Run(AdWordsUser user, long adGroupId)
        {
            using (BatchJobService batchJobService = (BatchJobService)user.GetService(
                       AdWordsService.v201708.BatchJobService)) {
                BatchJobOperation addOp = new BatchJobOperation()
                {
                    @operator = Operator.ADD,
                    operand   = new BatchJob()
                };

                try {
                    BatchJob batchJob = batchJobService.mutate(new BatchJobOperation[] { addOp }).value[0];

                    Console.WriteLine("Created BatchJob with ID {0}, status '{1}' and upload URL {2}.",
                                      batchJob.id, batchJob.status, batchJob.uploadUrl.url);

                    List <AdGroupCriterionOperation> operations = CreateOperations(adGroupId);

                    // Create a BatchJobUtilities instance for uploading operations. Use a
                    // chunked upload.
                    BatchJobUtilities batchJobUploadHelper = new BatchJobUtilities(user, true, CHUNK_SIZE);

                    // Create a resumable Upload URL to upload the operations.
                    string resumableUploadUrl = batchJobUploadHelper.GetResumableUploadUrl(
                        batchJob.uploadUrl.url);

                    // Use the BatchJobUploadHelper to upload all operations.
                    batchJobUploadHelper.Upload(resumableUploadUrl, operations.ToArray());

                    // A flag to determine if the job was requested to be cancelled. This
                    // typically comes from the user.
                    bool wasCancelRequested = false;

                    bool isComplete = batchJobUploadHelper.WaitForPendingJob(batchJob.id,
                                                                             TIME_TO_WAIT_FOR_COMPLETION, delegate(BatchJob waitBatchJob, long timeElapsed) {
                        Console.WriteLine("[{0} seconds]: Batch job ID {1} has status '{2}'.",
                                          timeElapsed / 1000, waitBatchJob.id, waitBatchJob.status);
                        batchJob = waitBatchJob;
                        return(wasCancelRequested);
                    });

                    // Optional: Cancel the job if it has not completed after waiting for
                    // TIME_TO_WAIT_FOR_COMPLETION.
                    bool shouldWaitForCancellation = false;
                    if (!isComplete && wasCancelRequested)
                    {
                        BatchJobError cancellationError = null;
                        try {
                            batchJobUploadHelper.TryToCancelJob(batchJob.id);
                        } catch (AdWordsApiException e) {
                            cancellationError = GetBatchJobError(e);
                        }
                        if (cancellationError == null)
                        {
                            Console.WriteLine("Successfully requested job cancellation.");
                            shouldWaitForCancellation = true;
                        }
                        else
                        {
                            Console.WriteLine("Job cancellation failed. Error says: {0}.",
                                              cancellationError.reason);
                        }

                        if (shouldWaitForCancellation)
                        {
                            isComplete = batchJobUploadHelper.WaitForPendingJob(batchJob.id,
                                                                                TIME_TO_WAIT_FOR_COMPLETION, delegate(BatchJob waitBatchJob, long timeElapsed) {
                                Console.WriteLine("[{0} seconds]: Batch job ID {1} has status '{2}'.",
                                                  timeElapsed / 1000, waitBatchJob.id, waitBatchJob.status);
                                batchJob = waitBatchJob;
                                return(false);
                            });
                        }
                    }

                    if (!isComplete)
                    {
                        throw new TimeoutException("Job is still in pending state after waiting for " +
                                                   TIME_TO_WAIT_FOR_COMPLETION + " seconds.");
                    }

                    if (batchJob.processingErrors != null)
                    {
                        foreach (BatchJobProcessingError processingError in batchJob.processingErrors)
                        {
                            Console.WriteLine("  Processing error: {0}, {1}, {2}, {3}, {4}",
                                              processingError.ApiErrorType, processingError.trigger,
                                              processingError.errorString, processingError.fieldPath,
                                              processingError.reason);
                        }
                    }

                    if (batchJob.downloadUrl != null && batchJob.downloadUrl.url != null)
                    {
                        BatchJobMutateResponse mutateResponse = batchJobUploadHelper.Download(
                            batchJob.downloadUrl.url);
                        Console.WriteLine("Downloaded results from {0}.", batchJob.downloadUrl.url);
                        foreach (MutateResult mutateResult in mutateResponse.rval)
                        {
                            String outcome = mutateResult.errorList == null ? "SUCCESS" : "FAILURE";
                            Console.WriteLine("  Operation [{0}] - {1}", mutateResult.index, outcome);
                        }
                    }
                    else
                    {
                        Console.WriteLine("No results available for download.");
                    }
                } catch (Exception e) {
                    throw new System.ApplicationException("Failed to create keywords using batch job.", e);
                }
            }
        }