text:
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package org.chromium.chrome.browser.payments;

import androidx.test.filters.MediumTest;

import org.junit.Assert;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;

import org.chromium.base.metrics.RecordHistogram;
import org.chromium.base.test.util.CommandLineFlags;
import org.chromium.base.test.util.Feature;
import org.chromium.base.test.util.FlakyTest;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.autofill.AutofillTestHelper;
import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
import org.chromium.chrome.browser.flags.ChromeSwitches;
import org.chromium.chrome.browser.payments.PaymentRequestTestRule.AppPresence;
import org.chromium.chrome.browser.payments.PaymentRequestTestRule.FactorySpeed;
import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
import org.chromium.components.payments.Event;
import org.chromium.ui.modaldialog.ModalDialogProperties;
import org.chromium.ui.test.util.DisableAnimationsTestRule;

import java.util.concurrent.TimeoutException;

/**
 * A payment integration test to validate the logging of Payment Request metrics.
 */
@RunWith(ChromeJUnit4ClassRunner.class)
@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
public class PaymentRequestJourneyLoggerTest implements MainActivityStartCallback {
    // Disable animations to reduce flakiness.
    @ClassRule
    public static DisableAnimationsTestRule sNoAnimationsRule = new DisableAnimationsTestRule();

    @Rule
    public PaymentRequestTestRule mPaymentRequestTestRule =
            new PaymentRequestTestRule("payment_request_metrics_test.html", this);

    @Override
    public void onMainActivityStarted() {}

    private void createTestData() throws TimeoutException {
        AutofillTestHelper mHelper = new AutofillTestHelper();
        // The user has a shipping address and a credit card associated with that address on disk.
        String mBillingAddressId = mHelper.setProfile(new AutofillProfile("", "https://example.com",
                true, "" /* honorific prefix */, "Jon Doe", "Google", "340 Main St", "CA",
                "Los Angeles", "", "90291", "", "US", "650-253-0000", "jondoe@email.com", "en-US"));
        mHelper.setCreditCard(new CreditCard("", "https://example.com", true, true, "Jon Doe",
                "4111111111111111", "1111", "12", "2050", "visa", R.drawable.visa_card,
                mBillingAddressId, "" /* serverId */));
        // The user also has an incomplete address and an incomplete card saved.
        String mIncompleteAddressId = mHelper.setProfile(new AutofillProfile("",
                "https://example.com", true, "" /* honorific prefix */, "In Complete", "Google",
                "344 Main St", "CA", "", "", "90291", "", "US", "650-253-0000", "", "en-US"));
        mHelper.setCreditCard(new CreditCard("", "https://example.com", true, true, "",
                "4111111111111111", "1111", "18", "2075", "visa", R.drawable.visa_card,
                mIncompleteAddressId, "" /* serverId */));
    }

    /**
     * Expect that the number of shipping address suggestions was logged properly.
     */
    @Test
    @MediumTest
    @FlakyTest(message = "crbug.com/1182234")
    @Feature({"Payments"})
    public void testNumberOfSuggestionsShown_ShippingAddress_Completed() throws TimeoutException {
        createTestData();

        // Complete a Payment Request with a credit card.
        mPaymentRequestTestRule.triggerUIAndWait("ccBuy", mPaymentRequestTestRule.getReadyToPay());
        mPaymentRequestTestRule.clickAndWait(
                R.id.button_primary, mPaymentRequestTestRule.getReadyForUnmaskInput());
        mPaymentRequestTestRule.setTextInCardUnmaskDialogAndWait(
                R.id.card_unmask_input, "123", mPaymentRequestTestRule.getReadyToUnmask());
        mPaymentRequestTestRule.clickCardUnmaskButtonAndWait(
                ModalDialogProperties.ButtonType.POSITIVE, mPaymentRequestTestRule.getDismissed());
        Assert.assertEquals(1,
                RecordHistogram.getHistogramTotalCountForTesting(
                        "PaymentRequest.TimeToCheckout.Completed"));
        Assert.assertEquals(1,
                RecordHistogram.getHistogramTotalCountForTesting(
                        "PaymentRequest.TimeToCheckout.Completed.Shown"));
        Assert.assertEquals(1,
                RecordHistogram.getHistogramTotalCountForTesting(
                        "PaymentRequest.TimeToCheckout.Completed.Shown.BasicCard"));

        // Make sure the right number of suggestions were logged.
        Assert.assertEquals(1,
                RecordHistogram.getHistogramValueCountForTesting(
                        "PaymentRequest.NumberOfSuggestionsShown.ShippingAddress.Completed", 2));
    }

    /**
     * Expect that the number of shipping address suggestions was logged properly.
     */
    @Test
    @MediumTest
    @FlakyTest(message = "crbug.com/1182234")
    @Feature({"Payments"})
    public void testNumberOfSuggestionsShown_ShippingAddress_AbortedByUser()
            throws InterruptedException, TimeoutException {
        createTestData();

        // Cancel the payment request.
        mPaymentRequestTestRule.triggerUIAndWait("ccBuy", mPaymentRequestTestRule.getReadyToPay());
        mPaymentRequestTestRule.clickAndWait(
                R.id.close_button, mPaymentRequestTestRule.getDismissed());

        // Wait for the histograms to be logged.
        Thread.sleep(200);

        Assert.assertEquals(1,
                RecordHistogram.getHistogramTotalCountForTesting(
                        "PaymentRequest.TimeToCheckout.UserAborted"));
        Assert.assertEquals(1,
                RecordHistogram.getHistogramTotalCountForTesting(
                        "PaymentRequest.TimeToCheckout.UserAborted.Shown"));

        // Make sure the right number of suggestions were logged.
        Assert.assertEquals(1,
                RecordHistogram.getHistogramValueCountForTesting(
                        "PaymentRequest.NumberOfSuggestionsShown.ShippingAddress.UserAborted", 2));
    }

    /**
     * Expect that the number of payment method suggestions was logged properly.
     */
    @Test
    @MediumTest
    @Feature({"Payments"})
    @CommandLineFlags.Add({"enable-features=PaymentRequestBasicCard"})
    public void testNumberOfSuggestionsShown_PaymentMethod_Completed_WithBasicCardEnabled()
            throws TimeoutException {
        // Add two credit cards.
        createTestData();

        // Add a complete payment app.
        mPaymentRequestTestRule.addPaymentAppFactory(
                AppPresence.HAVE_APPS, FactorySpeed.FAST_FACTORY);

        // Complete a Payment Request with the payment app.
        mPaymentRequestTestRule.triggerUIAndWait(
                "cardsAndBobPayBuy", mPaymentRequestTestRule.getReadyToPay());
        mPaymentRequestTestRule.clickAndWait(
                R.id.button_primary, mPaymentRequestTestRule.getDismissed());
        mPaymentRequestTestRule.expectResultContains(
                new String[] {"https://bobpay.com", "\"transaction\"", "1337"});

        // Make sure the right number of suggestions were logged.
        Assert.assertEquals(1,
                RecordHistogram.getHistogramValueCountForTesting(
                        "PaymentRequest.NumberOfSuggestionsShown.PaymentMethod.Completed", 3));
    }

    /**
     * Expect that the number of payment method suggestions was logged properly.
     */
    @Test
    @MediumTest
    @Feature({"Payments"})
    @CommandLineFlags.Add({"disable-features=PaymentRequestBasicCard"})
    public void testNumberOfSuggestionsShown_PaymentMethod_Completed() throws TimeoutException {
        mPaymentRequestTestRule.addPaymentAppFactory(
                "https://bobpay.com", AppPresence.HAVE_APPS, FactorySpeed.FAST_FACTORY);
        mPaymentRequestTestRule.addPaymentAppFactory(
                "https://kylepay.com/webpay", AppPresence.HAVE_APPS, FactorySpeed.FAST_FACTORY);

        createTestData();

        // Complete a Payment Request with the payment app.
        mPaymentRequestTestRule.triggerUIAndWait(
                "buyWithUrlMethods", mPaymentRequestTestRule.getReadyForInput());
        mPaymentRequestTestRule.clickAndWait(
                R.id.button_primary, mPaymentRequestTestRule.getDismissed());
        // Matches either "https://bobpay.com" or "https://kylepay.com/webpay"
        mPaymentRequestTestRule.expectResultContains(
                new String[] {"https://", "\"transaction\"", "1337"});

        Assert.assertEquals(1,
                RecordHistogram.getHistogramValueCountForTesting(
                        "PaymentRequest.NumberOfSuggestionsShown.PaymentMethod.Completed", 2));
    }

    /**
     * Expect that the number of payment method suggestions was logged properly.
     */
    @Test
    @MediumTest
    @Feature({"Payments"})
    @CommandLineFlags.Add({"enable-features=PaymentRequestBasicCard"})
    public void testNumberOfSuggestionsShown_PaymentMethod_AbortedByUser_WithBasicCardEnabled()
            throws InterruptedException, TimeoutException {
        // Add two credit cards.
        createTestData();

        // Add a complete payment app.
        mPaymentRequestTestRule.addPaymentAppFactory(
                AppPresence.HAVE_APPS, FactorySpeed.FAST_FACTORY);

        // Cancel the payment request.
        mPaymentRequestTestRule.triggerUIAndWait(
                "cardsAndBobPayBuy", mPaymentRequestTestRule.getReadyToPay());
        mPaymentRequestTestRule.clickAndWait(
                R.id.close_button, mPaymentRequestTestRule.getDismissed());

        // Wait for the histograms to be logged.
        Thread.sleep(200);

        // Make sure the right number of suggestions were logged.
        Assert.assertEquals(1,
                RecordHistogram.getHistogramValueCountForTesting(
                        "PaymentRequest.NumberOfSuggestionsShown.PaymentMethod.UserAborted", 3));
    }

    /**
     * Expect that the number of payment method suggestions was logged properly.
     */
    @Test
    @MediumTest
    @Feature({"Payments"})
    @CommandLineFlags.Add({"disable-features=PaymentRequestBasicCard"})
    public void testNumberOfSuggestionsShown_PaymentMethod_AbortedByUser()
            throws InterruptedException, TimeoutException {
        // Add two payment apps
        mPaymentRequestTestRule.addPaymentAppFactory(
                "https://bobpay.com", AppPresence.HAVE_APPS, FactorySpeed.FAST_FACTORY);
        mPaymentRequestTestRule.addPaymentAppFactory(
                "https://kylepay.com/webpay", AppPresence.HAVE_APPS, FactorySpeed.FAST_FACTORY);

        createTestData();

        // Cancel the payment request.
        mPaymentRequestTestRule.triggerUIAndWait(
                "buyWithUrlMethods", mPaymentRequestTestRule.getReadyForInput());
        mPaymentRequestTestRule.clickAndWait(
                R.id.close_button, mPaymentRequestTestRule.getDismissed());

        // Wait for the histograms to be logged.
        Thread.sleep(200);

        // Make sure the right number of suggestions were logged.
        Assert.assertEquals(1,
                RecordHistogram.getHistogramValueCountForTesting(
                        "PaymentRequest.NumberOfSuggestionsShown.PaymentMethod.UserAborted", 2));
    }

    /**
     * Expect that an incomplete payment app is not suggested to the user.
     */
    @Test
    @MediumTest
    @Feature({"Payments"})
    @CommandLineFlags.Add({"enable-features=PaymentRequestBasicCard"})
    public void testNumberOfSuggestionsShown_PaymentMethod_InvalidPaymentApp_WithBasicCardEnabled()
            throws InterruptedException, TimeoutException {
        // Add two credit cards.
        createTestData();

        // Add an incomplete payment app.
        mPaymentRequestTestRule.addPaymentAppFactory(
                AppPresence.NO_APPS, FactorySpeed.FAST_FACTORY);

        // Cancel the payment request.
        mPaymentRequestTestRule.triggerUIAndWait(
                "cardsAndBobPayBuy", mPaymentRequestTestRule.getReadyToPay());
        mPaymentRequestTestRule.clickAndWait(
                R.id.close_button, mPaymentRequestTestRule.getDismissed());

        Thread.sleep(200);

        // Make sure only the two credit card suggestions were logged.
        Assert.assertEquals(1,
                RecordHistogram.getHistogramValueCountForTesting(
                        "PaymentRequest.NumberOfSuggestionsShown.PaymentMethod.UserAborted", 2));
    }

    /**
     * Expect that an incomplete payment app is not suggested to the user.
     */
    @Test
    @MediumTest
    @Feature({"Payments"})
    @CommandLineFlags.Add({"disable-features=PaymentRequestBasicCard"})
    public void testNumberOfSuggestionsShown_PaymentMethod_InvalidPaymentApp()
            throws InterruptedException, TimeoutException {
        // Add an incomplete payment app.
        mPaymentRequestTestRule.addPaymentAppFactory(
                "https://bobpay.com", AppPresence.NO_APPS, FactorySpeed.FAST_FACTORY);
        mPaymentRequestTestRule.addPaymentAppFactory(
                "https://kylepay.com/webpay", AppPresence.HAVE_APPS, FactorySpeed.FAST_FACTORY);

        createTestData();

        // Cancel the payment request.
        mPaymentRequestTestRule.triggerUIAndWait(
                "buyWithUrlMethods", mPaymentRequestTestRule.getReadyToPay());
        mPaymentRequestTestRule.clickAndWait(
                R.id.close_button, mPaymentRequestTestRule.getDismissed());

        Thread.sleep(200);

        // Make sure only the one payment app suggestions was logged.
        Assert.assertEquals(1,
                RecordHistogram.getHistogramValueCountForTesting(
                        "PaymentRequest.NumberOfSuggestionsShown.PaymentMethod.UserAborted", 1));
    }

    /**
     * Expect that the number of contact info suggestions was logged properly.
     */
    @Test
    @MediumTest
    @FlakyTest(message = "crbug.com/1182234")
    @Feature({"Payments"})
    public void testNumberOfSuggestionsShown_ContactInfo_Completed() throws TimeoutException {
        createTestData();

        // Complete a Payment Request with a credit card.
        mPaymentRequestTestRule.triggerUIAndWait(
                "contactInfoBuy", mPaymentRequestTestRule.getReadyToPay());
        mPaymentRequestTestRule.clickAndWait(
                R.id.button_primary, mPaymentRequestTestRule.getReadyForUnmaskInput());
        mPaymentRequestTestRule.setTextInCardUnmaskDialogAndWait(
                R.id.card_unmask_input, "123", mPaymentRequestTestRule.getReadyToUnmask());
        mPaymentRequestTestRule.clickCardUnmaskButtonAndWait(
                ModalDialogProperties.ButtonType.POSITIVE, mPaymentRequestTestRule.getDismissed());

        // Make sure the right number of suggestions were logged.
        Assert.assertEquals(1,
                RecordHistogram.getHistogramValueCountForTesting(
                        "PaymentRequest.NumberOfSuggestionsShown.ContactInfo.Completed", 2));
    }

    /**
     * Expect that the number of contact info suggestions was logged properly.
     */
    @Test
    @MediumTest
    @Feature({"Payments"})
    @FlakyTest(message = "https://crbug.com/1197578")
    public void testNumberOfSuggestionsShown_ContactInfo_AbortedByUser()
            throws InterruptedException, TimeoutException {
        createTestData();

        // Cancel the payment request.
        mPaymentRequestTestRule.triggerUIAndWait(
                "contactInfoBuy", mPaymentRequestTestRule.getReadyToPay());
        mPaymentRequestTestRule.clickAndWait(
                R.id.close_button, mPaymentRequestTestRule.getDismissed());

        // Wait for the histograms to be logged.
        Thread.sleep(200);

        // Make sure the right number of suggestions were logged.
        Assert.assertEquals(1,
                RecordHistogram.getHistogramValueCountForTesting(
                        "PaymentRequest.NumberOfSuggestionsShown.ContactInfo.UserAborted", 2));
    }

    /**
     * Expect that the metric that records whether the user had complete suggestions for the
     * requested information is logged correctly.
     */
    @Test
    @MediumTest
    @FlakyTest(message = "crbug.com/1182234")
    @Feature({"Payments"})
    public void testUserHadCompleteSuggestions_ShippingAndPayment() throws TimeoutException {
        // Add two addresses and two cards.
        createTestData();

        // Cancel the payment request.
        mPaymentRequestTestRule.triggerUIAndWait("ccBuy", mPaymentRequestTestRule.getReadyToPay());
        mPaymentRequestTestRule.clickAndWait(
                R.id.close_button, mPaymentRequestTestRule.getDismissed());
        mPaymentRequestTestRule.expectResultContains(
                new String[] {"User closed the Payment Request UI."});

        // Make sure the events were logged correctly.
        int expectedSample = Event.SHOWN | Event.USER_ABORTED | Event.HAD_INITIAL_FORM_OF_PAYMENT
                | Event.HAD_NECESSARY_COMPLETE_SUGGESTIONS | Event.REQUEST_SHIPPING
                | Event.REQUEST_METHOD_BASIC_CARD | Event.AVAILABLE_METHOD_BASIC_CARD;
        Assert.assertEquals(1,
                RecordHistogram.getHistogramValueCountForTesting(
                        "PaymentRequest.Events", expectedSample));
    }

    /**
     * Expect that the metric that records whether the user had complete suggestions for the
     * requested information is logged correctly.
     */
    @Test
    @MediumTest
    @FlakyTest(message = "crbug.com/1182234")
    @Feature({"Payments"})
    public void testUserDidNotHaveCompleteSuggestions_ShippingAndPayment_IncompleteShipping()
            throws TimeoutException {
        // Add a card and an incomplete address (no region).
        AutofillTestHelper mHelper = new AutofillTestHelper();
        String mBillingAddressId = mHelper.setProfile(new AutofillProfile("", "https://example.com",
                true, "" /* honorific prefix */, "Jon Doe", "Google", "340 Main St", /*region=*/"",
                "Los Angeles", "", "90291", "", "US", "650-253-0000", "", "en-US"));
        mHelper.setCreditCard(new CreditCard("", "https://example.com", true, true, "Jon Doe",
                "4111111111111111", "1111", "12", "2050", "visa", R.drawable.visa_card,
                mBillingAddressId, "" /* serverId */));

        // Cancel the payment request.
        mPaymentRequestTestRule.triggerUIAndWait(
                "ccBuy", mPaymentRequestTestRule.getReadyForInput());
        mPaymentRequestTestRule.clickAndWait(
                R.id.close_button, mPaymentRequestTestRule.getDismissed());
        mPaymentRequestTestRule.expectResultContains(
                new String[] {"User closed the Payment Request UI."});

        // Make sure the events were logged correctly. Since the added credit card is using the same
        // incomplete profile for billing address, NEEDS_COMPLETION_PAYMENT is also set.
        int expectedSample = Event.SHOWN | Event.USER_ABORTED | Event.HAD_INITIAL_FORM_OF_PAYMENT
                | Event.REQUEST_SHIPPING | Event.REQUEST_METHOD_BASIC_CARD
                | Event.AVAILABLE_METHOD_BASIC_CARD | Event.NEEDS_COMPLETION_PAYMENT
                | Event.NEEDS_COMPLETION_SHIPPING;
        Assert.assertEquals(1,
                RecordHistogram.getHistogramValueCountForTesting(
                        "PaymentRequest.Events", expectedSample));
    }

    /**
     * Expect that the metric that records whether the user had complete suggestions for the
     * requested information is logged correctly.
     */
    @Test
    @MediumTest
    @FlakyTest(message = "crbug.com/1182234")
    @Feature({"Payments"})
    public void testUserDidNotHaveCompleteSuggestions_ShippingAndPayment_IncompleteCard()
            throws TimeoutException {
        // Add an incomplete card (no exp date) and an complete address.
        AutofillTestHelper mHelper = new AutofillTestHelper();
        String mBillingAddressId = mHelper.setProfile(new AutofillProfile("", "https://example.com",
                true, "" /* honorific prefix */, "Jon Doe", "Google", "340 Main St", "CA",
                "Los Angeles", "", "90291", "", "US", "650-253-0000", "", "en-US"));
        mHelper.setCreditCard(new CreditCard("", "https://example.com", true, true,
                /*cardholderName=*/"", "4111111111111111", "1111", "10", "2021", "visa",
                R.drawable.visa_card, mBillingAddressId, "" /* serverId */));

        // Cancel the payment request.
        mPaymentRequestTestRule.triggerUIAndWait(
                "ccBuy", mPaymentRequestTestRule.getReadyForInput());
        mPaymentRequestTestRule.clickAndWait(
                R.id.close_button, mPaymentRequestTestRule.getDismissed());
        mPaymentRequestTestRule.expectResultContains(
                new String[] {"User closed the Payment Request UI."});

        // Make sure the events were logged correctly.
        int expectedSample = Event.SHOWN | Event.USER_ABORTED | Event.HAD_INITIAL_FORM_OF_PAYMENT
                | Event.REQUEST_SHIPPING | Event.REQUEST_METHOD_BASIC_CARD
                | Event.AVAILABLE_METHOD_BASIC_CARD | Event.NEEDS_COMPLETION_PAYMENT;
        Assert.assertEquals(1,
                RecordHistogram.getHistogramValueCountForTesting(
                        "PaymentRequest.Events", expectedSample));
    }

    /**
     * Expect that the metric that records whether the user had complete suggestions for the
     * requested information is logged correctly.
     */
    @Test
    @MediumTest
    @FlakyTest(message = "crbug.com/1182234")
    @Feature({"Payments"})
    public void testUserDidNotHaveCompleteSuggestions_ShippingAndPayment_UnsupportedCard()
            throws TimeoutException {
        // Add an unsupported card (mastercard) and an complete address.
        AutofillTestHelper mHelper = new AutofillTestHelper();
        String mBillingAddressId = mHelper.setProfile(new AutofillProfile("", "https://example.com",
                true, "" /* honorific prefix */, "Jon Doe", "Google", "340 Main St", "CA",
                "Los Angeles", "", "90291", "", "US", "650-253-0000", "", "en-US"));
        mHelper.setCreditCard(new CreditCard("", "https://example.com", true, true, "Jon Doe",
                "5187654321098765", "8765", "10", "2021", "mastercard", R.drawable.visa_card,
                mBillingAddressId, "" /* serverId */));

        // Cancel the payment request.
        mPaymentRequestTestRule.triggerUIAndWait(
                "ccBuy", mPaymentRequestTestRule.getReadyForInput());
        mPaymentRequestTestRule.clickAndWait(
                R.id.close_button, mPaymentRequestTestRule.getDismissed());
        mPaymentRequestTestRule.expectResultContains(
                new String[] {"User closed the Payment Request UI."});

        // Make sure the events were logged correctly.
        int expectedSample = Event.SHOWN | Event.USER_ABORTED | Event.REQUEST_SHIPPING
                | Event.REQUEST_METHOD_BASIC_CARD | Event.NEEDS_COMPLETION_PAYMENT;
        Assert.assertEquals(1,
                RecordHistogram.getHistogramValueCountForTesting(
                        "PaymentRequest.Events", expectedSample));
    }

    /**
     * Expect that the metric that records whether the user had complete suggestions for the
     * requested information is logged correctly.
     */
    @Test
    @MediumTest
    @FlakyTest(message = "crbug.com/1182234")
    @Feature({"Payments"})
    public void testUserDidNotHaveCompleteSuggestions_ShippingAndPayment_OnlyPaymentApp()
            throws TimeoutException {
        // Add a complete address and a working payment app.
        AutofillTestHelper mHelper = new AutofillTestHelper();
        mHelper.setProfile(new AutofillProfile("", "https://example.com", true,
                "" /* honorific prefix */, "Jon Doe", "Google", "340 Main St", "CA", "Los Angeles",
                "", "90291", "", "US", "650-253-0000", "", "en-US"));
        mPaymentRequestTestRule.addPaymentAppFactory(
                AppPresence.HAVE_APPS, FactorySpeed.FAST_FACTORY);

        // Cancel the payment request.
        mPaymentRequestTestRule.triggerUIAndWait(
                "ccBuy", mPaymentRequestTestRule.getReadyForInput());
        mPaymentRequestTestRule.clickAndWait(
                R.id.close_button, mPaymentRequestTestRule.getDismissed());
        mPaymentRequestTestRule.expectResultContains(
                new String[] {"User closed the Payment Request UI."});

        // Make sure the events were logged correctly.
        int expectedSample = Event.SHOWN | Event.USER_ABORTED | Event.REQUEST_SHIPPING
                | Event.REQUEST_METHOD_BASIC_CARD | Event.NEEDS_COMPLETION_PAYMENT;
        Assert.assertEquals(1,
                RecordHistogram.getHistogramValueCountForTesting(
                        "PaymentRequest.Events", expectedSample));
    }

    /**
     * Expect that the metric that records whether the user had complete suggestions for the
     * requested information is logged correctly.
     */
    @Test
    @MediumTest
    @Feature({"Payments"})
    @CommandLineFlags.Add({"enable-features=PaymentRequestBasicCard"})
    public void testUserDidNotHaveCompleteSuggestions_PaymentApp_NoApps() throws TimeoutException {
        // Add an address and a factory without apps.
        AutofillTestHelper mHelper = new AutofillTestHelper();
        mHelper.setProfile(new AutofillProfile("", "https://example.com", true,
                "" /* honorific prefix */, "Jon Doe", "Google", "340 Main St", "CA", "Los Angeles",
                "", "90291", "", "US", "650-253-0000", "", "en-US"));
        mPaymentRequestTestRule.addPaymentAppFactory(
                AppPresence.NO_APPS, FactorySpeed.FAST_FACTORY);

        // Cancel the payment request.
        mPaymentRequestTestRule.triggerUIAndWait(
                "cardsAndBobPayBuy", mPaymentRequestTestRule.getReadyForInput());
        mPaymentRequestTestRule.clickAndWait(
                R.id.close_button, mPaymentRequestTestRule.getDismissed());
        mPaymentRequestTestRule.expectResultContains(
                new String[] {"User closed the Payment Request UI."});

        // Make sure the events were logged correctly.
        int expectedSample = Event.SHOWN | Event.USER_ABORTED | Event.REQUEST_SHIPPING
                | Event.REQUEST_METHOD_BASIC_CARD | Event.REQUEST_METHOD_OTHER
                | Event.NEEDS_COMPLETION_PAYMENT;
        Assert.assertEquals(1,
                RecordHistogram.getHistogramValueCountForTesting(
                        "PaymentRequest.Events", expectedSample));
    }

    /**
     * Expect that the metric that records whether the user had complete suggestions for the
     * requested information is logged correctly.
     */
    @Test
    @MediumTest
    @Feature({"Payments"})
    @CommandLineFlags.Add({"enable-features=PaymentRequestBasicCard"})
    public void testUserHadCompleteSuggestions_PaymentApp_HasValidPaymentApp_WithBasicCardEnabled()
            throws TimeoutException {
        // Add an address and a payment app on file.
        AutofillTestHelper mHelper = new AutofillTestHelper();
        mHelper.setProfile(new AutofillProfile("", "https://example.com", true,
                "" /* honorific prefix */, "Jon Doe", "Google", "340 Main St", "CA", "Los Angeles",
                "", "90291", "", "US", "650-253-0000", "", "en-US"));
        mPaymentRequestTestRule.addPaymentAppFactory(
                AppPresence.HAVE_APPS, FactorySpeed.FAST_FACTORY);

        // Cancel the payment request.
        mPaymentRequestTestRule.triggerUIAndWait(
                "cardsAndBobPayBuy", mPaymentRequestTestRule.getReadyForInput());
        mPaymentRequestTestRule.clickAndWait(
                R.id.close_button, mPaymentRequestTestRule.getDismissed());
        mPaymentRequestTestRule.expectResultContains(
                new String[] {"User closed the Payment Request UI."});

        // Make sure the events were logged correctly.
        int expectedSample = Event.SHOWN | Event.USER_ABORTED | Event.HAD_INITIAL_FORM_OF_PAYMENT
                | Event.HAD_NECESSARY_COMPLETE_SUGGESTIONS | Event.REQUEST_SHIPPING
                | Event.REQUEST_METHOD_BASIC_CARD | Event.REQUEST_METHOD_OTHER
                | Event.AVAILABLE_METHOD_OTHER;
        Assert.assertEquals(1,
                RecordHistogram.getHistogramValueCountForTesting(
                        "PaymentRequest.Events", expectedSample));
    }

    /**
     * Expect that the metric that records whether the user had complete suggestions for the
     * requested information is logged correctly.
     */
    @Test
    @MediumTest
    @Feature({"Payments"})
    @CommandLineFlags.Add({"disable-features=PaymentRequestBasicCard"})
    public void testUserHadCompleteSuggestions_PaymentApp_HasValidPaymentApp()
            throws TimeoutException {
        mPaymentRequestTestRule.addPaymentAppFactory(
                "https://bobpay.com", AppPresence.HAVE_APPS, FactorySpeed.FAST_FACTORY);
        mPaymentRequestTestRule.addPaymentAppFactory(
                "https://kylepay.com/webpay", AppPresence.HAVE_APPS, FactorySpeed.FAST_FACTORY);

        createTestData();

        // Cancel the payment request.
        mPaymentRequestTestRule.triggerUIAndWait(
                "buyWithUrlMethods", mPaymentRequestTestRule.getReadyForInput());
        mPaymentRequestTestRule.clickAndWait(
                R.id.close_button, mPaymentRequestTestRule.getDismissed());
        mPaymentRequestTestRule.expectResultContains(
                new String[] {"User closed the Payment Request UI."});

        // Make sure the events were logged correctly.
        int expectedSample = Event.SHOWN | Event.USER_ABORTED | Event.HAD_INITIAL_FORM_OF_PAYMENT
                | Event.HAD_NECESSARY_COMPLETE_SUGGESTIONS | Event.REQUEST_SHIPPING
                | Event.REQUEST_METHOD_OTHER | Event.AVAILABLE_METHOD_OTHER;
        Assert.assertEquals(1,
                RecordHistogram.getHistogramValueCountForTesting(
                        "PaymentRequest.Events", expectedSample));
    }

    /**
     * Expect that the metric that records whether the user had complete suggestions for the
     * requested information is logged correctly.
     */
    @Test
    @MediumTest
    @FlakyTest(message = "crbug.com/1182234")
    @Feature({"Payments"})
    public void testUserHadCompleteSuggestions_ShippingAndPaymentApp_HasInvalidShipping()
            throws TimeoutException {
        // Add a card and an incomplete address (no region).
        AutofillTestHelper mHelper = new AutofillTestHelper();
        String mBillingAddressId = mHelper.setProfile(new AutofillProfile("", "https://example.com",
                true, "" /* honorific prefix */, "Jon Doe", "Google", "340 Main St", /*region=*/"",
                "Los Angeles", "", "90291", "", "US", "650-253-0000", "", "en-US"));
        mHelper.setCreditCard(new CreditCard("", "https://example.com", true, true, "Jon Doe",
                "4111111111111111", "1111", "12", "2050", "visa", R.drawable.visa_card,
                mBillingAddressId, "" /* serverId */));

        // Cancel the payment request.
        mPaymentRequestTestRule.triggerUIAndWait(
                "cardsAndBobPayBuy", mPaymentRequestTestRule.getReadyForInput());
        mPaymentRequestTestRule.clickAndWait(
                R.id.close_button, mPaymentRequestTestRule.getDismissed());
        mPaymentRequestTestRule.expectResultContains(
                new String[] {"User closed the Payment Request UI."});

        // Make sure the events were logged correctly. Since the added credit card is using the same
        // incomplete profile, NEEDS_COMPLETION_PAYMENT is also set.
        int expectedSample = Event.SHOWN | Event.USER_ABORTED | Event.HAD_INITIAL_FORM_OF_PAYMENT
                | Event.REQUEST_SHIPPING | Event.REQUEST_METHOD_BASIC_CARD
                | Event.REQUEST_METHOD_OTHER | Event.NEEDS_COMPLETION_PAYMENT
                | Event.AVAILABLE_METHOD_BASIC_CARD | Event.NEEDS_COMPLETION_SHIPPING;
        Assert.assertEquals(1,
                RecordHistogram.getHistogramValueCountForTesting(
                        "PaymentRequest.Events", expectedSample));
    }

    /**
     * Expect that the UserHadCompleteSuggestions histogram gets logged properly when the user has
     * at least one credit card on file.
     */
    @Test
    @MediumTest
    @FlakyTest(message = "crbug.com/1182234")
    @Feature({"Payments"})
    public void testUserHadCompleteSuggestions_AcceptsCardsAndApps_UserHasOnlyCard()
            throws TimeoutException {
        // Add an address and a credit card on file.
        AutofillTestHelper mHelper = new AutofillTestHelper();
        String mBillingAddressId = mHelper.setProfile(new AutofillProfile("", "https://example.com",
                true, "" /* honorific prefix */, "Jon Doe", "Google", "340 Main St", "CA",
                "Los Angeles", "", "90291", "", "US", "650-253-0000", "", "en-US"));
        mHelper.setCreditCard(new CreditCard("", "https://example.com", true, true, "Jon Doe",
                "4111111111111111", "1111", "12", "2050", "visa", R.drawable.visa_card,
                mBillingAddressId, "" /* serverId */));

        mPaymentRequestTestRule.triggerUIAndWait(
                "cardsAndBobPayBuy", mPaymentRequestTestRule.getReadyToPay());

        // The user cancels the Payment Request (trigger the logs).
        mPaymentRequestTestRule.clickAndWait(
                R.id.close_button, mPaymentRequestTestRule.getDismissed());
        mPaymentRequestTestRule.expectResultContains(
                new String[] {"User closed the Payment Request UI."});

        // Make sure the events were logged correctly.
        int expectedSample = Event.SHOWN | Event.USER_ABORTED | Event.HAD_INITIAL_FORM_OF_PAYMENT
                | Event.HAD_NECESSARY_COMPLETE_SUGGESTIONS | Event.REQUEST_SHIPPING
                | Event.REQUEST_METHOD_BASIC_CARD | Event.REQUEST_METHOD_OTHER
                | Event.AVAILABLE_METHOD_BASIC_CARD;
        Assert.assertEquals(1,
                RecordHistogram.getHistogramValueCountForTesting(
                        "PaymentRequest.Events", expectedSample));
    }

    /**
     * Expect that the UserHadCompleteSuggestions histogram gets logged properly when the user has
     * at least one payment app on file.
     */
    @Test
    @MediumTest
    @Feature({"Payments"})
    @CommandLineFlags.Add({"enable-features=PaymentRequestBasicCard"})
    public void testUserHadCompleteSuggestions_AcceptsCardsAndApps_UserHasOnlyPaymentApp()
            throws TimeoutException {
        // Add an address and a payment app on file.
        AutofillTestHelper mHelper = new AutofillTestHelper();
        mHelper.setProfile(new AutofillProfile("", "https://example.com", true,
                "" /* honorific prefix */, "Jon Doe", "Google", "340 Main St", "CA", "Los Angeles",
                "", "90291", "", "US", "650-253-0000", "", "en-US"));
        mPaymentRequestTestRule.addPaymentAppFactory(
                AppPresence.HAVE_APPS, FactorySpeed.FAST_FACTORY);

        mPaymentRequestTestRule.triggerUIAndWait(
                "cardsAndBobPayBuy", mPaymentRequestTestRule.getReadyToPay());

        // The user cancels the Payment Request (trigger the logs).
        mPaymentRequestTestRule.clickAndWait(
                R.id.close_button, mPaymentRequestTestRule.getDismissed());
        mPaymentRequestTestRule.expectResultContains(
                new String[] {"User closed the Payment Request UI."});

        // Make sure the events were logged correctly.
        int expectedSample = Event.SHOWN | Event.USER_ABORTED | Event.HAD_INITIAL_FORM_OF_PAYMENT
                | Event.HAD_NECESSARY_COMPLETE_SUGGESTIONS | Event.REQUEST_SHIPPING
                | Event.REQUEST_METHOD_BASIC_CARD | Event.REQUEST_METHOD_OTHER
                | Event.AVAILABLE_METHOD_OTHER;
        Assert.assertEquals(1,
                RecordHistogram.getHistogramValueCountForTesting(
                        "PaymentRequest.Events", expectedSample));
    }

    /**
     * Expect that the UserHadCompleteSuggestions histogram gets logged properly when the user has
     * at both a card and a payment app on file.
     */
    @Test
    @MediumTest
    @FlakyTest(message = "crbug.com/1182234")
    @Feature({"Payments"})
    public void testUserHadCompleteSuggestions_AcceptsCardsAndApps_UserHasCardAndPaymentApp()
            throws TimeoutException {
        // Add an address, a credit card and a payment app on file.
        AutofillTestHelper mHelper = new AutofillTestHelper();
        String mBillingAddressId = mHelper.setProfile(new AutofillProfile("", "https://example.com",
                true, "" /* honorific prefix */, "Jon Doe", "Google", "340 Main St", "CA",
                "Los Angeles", "", "90291", "", "US", "650-253-0000", "", "en-US"));
        mHelper.setCreditCard(new CreditCard("", "https://example.com", true, true, "Jon Doe",
                "4111111111111111", "1111", "12", "2050", "visa", R.drawable.visa_card,
                mBillingAddressId, "" /* serverId */));
        mPaymentRequestTestRule.addPaymentAppFactory(
                AppPresence.HAVE_APPS, FactorySpeed.FAST_FACTORY);

        mPaymentRequestTestRule.triggerUIAndWait(
                "cardsAndBobPayBuy", mPaymentRequestTestRule.getReadyToPay());

        // The user cancels the Payment Request (trigger the logs).
        mPaymentRequestTestRule.clickAndWait(
                R.id.close_button, mPaymentRequestTestRule.getDismissed());
        mPaymentRequestTestRule.expectResultContains(
                new String[] {"User closed the Payment Request UI."});

        // Make sure the events were logged correctly.
        int expectedSample = Event.SHOWN | Event.USER_ABORTED | Event.HAD_INITIAL_FORM_OF_PAYMENT
                | Event.HAD_NECESSARY_COMPLETE_SUGGESTIONS | Event.REQUEST_SHIPPING
                | Event.REQUEST_METHOD_BASIC_CARD | Event.REQUEST_METHOD_OTHER
                | Event.AVAILABLE_METHOD_BASIC_CARD | Event.AVAILABLE_METHOD_OTHER;
        Assert.assertEquals(1,
                RecordHistogram.getHistogramValueCountForTesting(
                        "PaymentRequest.Events", expectedSample));
    }

    /**
     * Expect that the UserDidNotHaveInitialFormOfPayment histogram gets logged properly when the
     * user has no form of payment on file.
     */
    @Test
    @MediumTest
    @Feature({"Payments"})
    @CommandLineFlags.Add({"enable-features=PaymentRequestBasicCard"})
    public void testUserDidNotHaveCompleteSuggestions_AcceptsCardsAndApps_NoCardOrPaymentApp()
            throws TimeoutException {
        // Add an address on file.
        new AutofillTestHelper().setProfile(new AutofillProfile("", "https://example.com", true,
                "" /* honorific prefix */, "Jon Doe", "Google", "340 Main St", "CA", "Los Angeles",
                "", "90291", "", "US", "650-253-0000", "", "en-US"));

        mPaymentRequestTestRule.triggerUIAndWait(
                "cardsAndBobPayBuy", mPaymentRequestTestRule.getReadyForInput());

        // The user cancels the Payment Request (trigger the logs).
        mPaymentRequestTestRule.clickAndWait(
                R.id.close_button, mPaymentRequestTestRule.getDismissed());
        mPaymentRequestTestRule.expectResultContains(
                new String[] {"User closed the Payment Request UI."});

        // Make sure the events were logged correctly.
        int expectedSample = Event.SHOWN | Event.USER_ABORTED | Event.REQUEST_SHIPPING
                | Event.REQUEST_METHOD_BASIC_CARD | Event.REQUEST_METHOD_OTHER
                | Event.NEEDS_COMPLETION_PAYMENT;
        Assert.assertEquals(1,
                RecordHistogram.getHistogramValueCountForTesting(
                        "PaymentRequest.Events", expectedSample));
    }

    /**
     * Expect that no metric for contact info has been logged.
     */
    @Test
    @MediumTest
    @FlakyTest(message = "crbug.com/1182234")
    @Feature({"Payments"})
    public void testNoContactInfoHistogram() throws TimeoutException {
        createTestData();

        // Complete a Payment Request with a credit card.
        mPaymentRequestTestRule.triggerUIAndWait("ccBuy", mPaymentRequestTestRule.getReadyToPay());
        mPaymentRequestTestRule.clickAndWait(
                R.id.button_primary, mPaymentRequestTestRule.getReadyForUnmaskInput());
        mPaymentRequestTestRule.setTextInCardUnmaskDialogAndWait(
                R.id.card_unmask_input, "123", mPaymentRequestTestRule.getReadyToUnmask());
        mPaymentRequestTestRule.clickCardUnmaskButtonAndWait(
                ModalDialogProperties.ButtonType.POSITIVE, mPaymentRequestTestRule.getDismissed());

        // Make sure nothing was logged for contact info.
        Assert.assertEquals(0,
                RecordHistogram.getHistogramValueCountForTesting(
                        "PaymentRequest.NumberOfSuggestionsShown.ContactInfo.Completed", 2));
    }

    /**
     * Expect that that the journey metrics are logged correctly on a second consecutive payment
     * request.
     */
    @Test
    @MediumTest
    @Feature({"Payments"})
    @CommandLineFlags.Add({"enable-features=PaymentRequestBasicCard"})
    public void testTwoTimes_WithBasicCardEnabled() throws TimeoutException {
        createTestData();

        // Complete a Payment Request with a credit card.
        mPaymentRequestTestRule.triggerUIAndWait("ccBuy", mPaymentRequestTestRule.getReadyToPay());
        mPaymentRequestTestRule.clickAndWait(
                R.id.button_primary, mPaymentRequestTestRule.getReadyForUnmaskInput());
        mPaymentRequestTestRule.setTextInCardUnmaskDialogAndWait(
                R.id.card_unmask_input, "123", mPaymentRequestTestRule.getReadyToUnmask());
        mPaymentRequestTestRule.clickCardUnmaskButtonAndWait(
                ModalDialogProperties.ButtonType.POSITIVE, mPaymentRequestTestRule.getDismissed());

        // Make sure the right number of suggestions were logged.
        Assert.assertEquals(1,
                RecordHistogram.getHistogramValueCountForTesting(
                        "PaymentRequest.NumberOfSuggestionsShown.ShippingAddress.Completed", 2));

        // Complete a second Payment Request with a credit card.
        mPaymentRequestTestRule.reTriggerUIAndWait(
                "ccBuy", mPaymentRequestTestRule.getReadyToPay());
        mPaymentRequestTestRule.clickAndWait(
                R.id.button_primary, mPaymentRequestTestRule.getReadyForUnmaskInput());
        mPaymentRequestTestRule.setTextInCardUnmaskDialogAndWait(
                R.id.card_unmask_input, "123", mPaymentRequestTestRule.getReadyToUnmask());
        mPaymentRequestTestRule.clickCardUnmaskButtonAndWait(
                ModalDialogProperties.ButtonType.POSITIVE, mPaymentRequestTestRule.getDismissed());

        // Make sure the right number of suggestions were logged.
        Assert.assertEquals(2,
                RecordHistogram.getHistogramValueCountForTesting(
                        "PaymentRequest.NumberOfSuggestionsShown.ShippingAddress.Completed", 2));

        // Make sure the events were logged correctly.
        int expectedSample = Event.SHOWN | Event.COMPLETED | Event.REQUEST_SHIPPING
                | Event.REQUEST_METHOD_BASIC_CARD | Event.HAD_INITIAL_FORM_OF_PAYMENT
                | Event.HAD_NECESSARY_COMPLETE_SUGGESTIONS | Event.RECEIVED_INSTRUMENT_DETAILS
                | Event.PAY_CLICKED | Event.AVAILABLE_METHOD_BASIC_CARD
                | Event.SELECTED_CREDIT_CARD;
        Assert.assertEquals(2,
                RecordHistogram.getHistogramValueCountForTesting(
                        "PaymentRequest.Events", expectedSample));
    }

    /**
     * Expect that that the journey metrics are logged correctly on a second consecutive payment
     * request.
     */
    @Test
    @MediumTest
    @Feature({"Payments"})
    @CommandLineFlags.Add({"disable-features=PaymentRequestBasicCard"})
    public void testTwoTimes() throws TimeoutException {
        mPaymentRequestTestRule.addPaymentAppFactory(
                "https://bobpay.com", AppPresence.HAVE_APPS, FactorySpeed.FAST_FACTORY);
        mPaymentRequestTestRule.addPaymentAppFactory(
                "https://kylepay.com/webpay", AppPresence.HAVE_APPS, FactorySpeed.FAST_FACTORY);

        createTestData();

        // Complete a Payment Request with payment apps.
        mPaymentRequestTestRule.triggerUIAndWait(
                "buyWithUrlMethods", mPaymentRequestTestRule.getReadyForInput());
        mPaymentRequestTestRule.clickAndWait(
                R.id.button_primary, mPaymentRequestTestRule.getDismissed());

        // Make sure the right number of suggestions were logged.
        Assert.assertEquals(1,
                RecordHistogram.getHistogramValueCountForTesting(
                        "PaymentRequest.NumberOfSuggestionsShown.PaymentMethod.Completed", 2));

        // Complete a second Payment Request with payment apps.
        mPaymentRequestTestRule.reTriggerUIAndWait(
                "buyWithUrlMethods", mPaymentRequestTestRule.getReadyForInput());
        mPaymentRequestTestRule.clickAndWait(
                R.id.button_primary, mPaymentRequestTestRule.getDismissed());

        // Make sure the right number of suggestions were logged.
        Assert.assertEquals(2,
                RecordHistogram.getHistogramValueCountForTesting(
                        "PaymentRequest.NumberOfSuggestionsShown.PaymentMethod.Completed", 2));

        // Make sure the events were logged correctly.
        int expectedSample = Event.SHOWN | Event.COMPLETED | Event.REQUEST_SHIPPING
                | Event.REQUEST_METHOD_OTHER | Event.HAD_INITIAL_FORM_OF_PAYMENT
                | Event.HAD_NECESSARY_COMPLETE_SUGGESTIONS | Event.RECEIVED_INSTRUMENT_DETAILS
                | Event.PAY_CLICKED | Event.AVAILABLE_METHOD_OTHER | Event.SELECTED_OTHER;
        Assert.assertEquals(2,
                RecordHistogram.getHistogramValueCountForTesting(
                        "PaymentRequest.Events", expectedSample));
    }

    /**
     * Expect that only some journey metrics are logged if the payment request was not shown to the
     * user.
     */
    @Test
    @MediumTest
    @Feature({"Payments"})
    public void testNoShow() throws TimeoutException {
        // Android Pay has a factory but it does not return an app.
        mPaymentRequestTestRule.addPaymentAppFactory(
                "https://android.com/pay", AppPresence.NO_APPS, FactorySpeed.SLOW_FACTORY);
        mPaymentRequestTestRule.openPageAndClickNodeAndWait(
                "androidPayBuy", mPaymentRequestTestRule.getShowFailed());
        mPaymentRequestTestRule.expectResultContains(
                new String[] {"The payment method", "not supported"});

        // Make sure that no journey metrics were logged.
        Assert.assertEquals(0,
                RecordHistogram.getHistogramValueCountForTesting(
                        "PaymentRequest.NumberOfSuggestionsShown.ShippingAddress.UserAborted", 2));
        Assert.assertEquals(0,
                RecordHistogram.getHistogramValueCountForTesting(
                        "PaymentRequest.NumberOfSuggestionsShown.ShippingAddress.OtherAborted", 2));
        Assert.assertEquals(0,
                RecordHistogram.getHistogramValueCountForTesting(
                        "PaymentRequest.NumberOfSuggestionsShown.ShippingAddress.Completed", 2));
    }
}


text:
import re
import csv
import os.path
import os
import sys
import time

pjt_name = sys.argv[1]
file_name_authors = pjt_name + "_authors.csv"
file_name_issue_report = pjt_name + "_issue_reports.csv"
f_authors = opne(file_name_authors, "r")
line_author = f_authors.readline() # header line
line_author = f_authors.readline()
while line:
	author_name = line_author.split(",")[0]
	print author_name
	egrep_query = "   \",\"" + author_name + "   \",\""
	os.system("egrep " + egrep_query + " " + file_name_issue_report)
	time.sleep(2)
	line_author = f_authors.readline()

redpajama_set_name: RedPajamaGithub


text:
require 'spec_helper'

describe 'persist' do

  it 'should persist state' do
    name_path = ''
    persist_path = ''
    block = Proc.new do |sub_path, path|
      name_path = sub_path
      persist_path = path
    end
    SnowyOwl.persist_callback &block
    allow(FileUtils).to receive(:mkdir_p).and_return ''
    SnowyOwl::Persist.persist_state digest
    expect(name_path).to eq digest
    expect(persist_path).to eq '/.tmp/'
  end

  it 'should recover state' do
    name_path = ''
    recover_path = ''
    block = Proc.new do |sub_path, path|
      name_path = sub_path
      recover_path = path
    end
    SnowyOwl.recover_callback &block
    SnowyOwl::Persist.recover_state digest
    expect(name_path).to eq digest
    expect(recover_path).to eq ''
  end

  let(:digest) { '8151325dcdbae9e0ff95f9f9658432dbedfdb209' }
end


text:
"""
Client implementation based on the boto AWS client library
"""

from heat.openstack.common import log as logging
logger = logging.getLogger(__name__)

from boto.ec2.cloudwatch import CloudWatchConnection

class BotoCWClient(CloudWatchConnection):
    '''
    Wrapper class for boto CloudWatchConnection class
    '''
    # TODO : These should probably go in the CW API and be imported
    DEFAULT_NAMESPACE = "heat/unknown"
    METRIC_UNITS = ("Seconds", "Microseconds", "Milliseconds", "Bytes",
                    "Kilobytes", "Megabytes", "Gigabytes", "Terabytes",
                    "Bits", "Kilobits", "Megabits", "Gigabits", "Terabits",
                    "Percent", "Count", "Bytes/Second", "Kilobytes/Second",
                    "Megabytes/Second", "Gigabytes/Second", "Terabytes/Second",
                    "Bits/Second", "Kilobits/Second", "Megabits/Second",
                    "Gigabits/Second", "Terabits/Second", "Count/Second", None)
    METRIC_COMPARISONS = (">=", ">", "<", "<=")
    ALARM_STATES = ("OK", "ALARM", "INSUFFICIENT_DATA")
    METRIC_STATISTICS = ("Average", "Sum", "SampleCount", "Maximum", "Minimum")

    # Note, several of these boto calls take a list of alarm names, so
    # we could easily handle multiple alarms per-action, but in the
    # interests of keeping the client simple, we just handle one 'AlarmName'

    def describe_alarm(self, **kwargs):
        # If no AlarmName specified, we pass None, which returns
        # results for ALL alarms
        try:
            name = kwargs['AlarmName']
        except KeyError:
            name = None
        return super(BotoCWClient, self).describe_alarms(
            alarm_names=[name])

    def list_metrics(self, **kwargs):
        # list_metrics returns non-null index in next_token if there
        # are more than 500 metric results, in which case we have to
        # re-read with the token to get the next batch of results
        #
        # Also note that we can do more advanced filtering by dimension
        # and/or namespace, but for simplicity we only filter by
        # MetricName for the time being
        try:
            name = kwargs['MetricName']
        except KeyError:
            name = None

        results = []
        token = None
        while True:
            results.append(super(BotoCWClient, self).list_metrics(
                           next_token=token,
                           dimensions=None,
                           metric_name=name,
                           namespace=None))
            if not token:
                break

        return results

    def put_metric_data(self, **kwargs):
        '''
        Publish metric data points to CloudWatch
        '''
        try:
            metric_name = kwargs['MetricName']
            metric_unit = kwargs['MetricUnit']
            metric_value = kwargs['MetricValue']
            metric_namespace = kwargs['Namespace']
        except KeyError:
            logger.error("Must pass MetricName, MetricUnit, " +
                         "Namespace, MetricValue!")
            return

        try:
            metric_unit = kwargs['MetricUnit']
        except KeyError:
            metric_unit = None

        # If we're passed AlarmName, we attach it to the metric
        # as a dimension
        try:
            metric_dims = [{'AlarmName': kwargs['AlarmName']}]
        except KeyError:
            metric_dims = []

        if metric_unit not in self.METRIC_UNITS:
            logger.error("MetricUnit not an allowed value")
            logger.error("MetricUnit must be one of %s" % self.METRIC_UNITS)
            return

        return super(BotoCWClient, self).put_metric_data(
            namespace=metric_namespace,
            name=metric_name,
            value=metric_value,
            timestamp=None,  # This means use "now" in the engine
            unit=metric_unit,
            dimensions=metric_dims,
            statistics=None)

    def set_alarm_state(self, **kwargs):
        return super(BotoCWClient, self).set_alarm_state(
            alarm_name=kwargs['AlarmName'],
            state_reason=kwargs['StateReason'],
            state_value=kwargs['StateValue'],
            state_reason_data=kwargs['StateReasonData'])

    def format_metric_alarm(self, alarms):
        '''
        Return string formatted representation of
        boto.ec2.cloudwatch.alarm.MetricAlarm objects
        '''
        ret = []
        for s in alarms:
            ret.append("AlarmName : %s" % s.name)
            ret.append("AlarmDescription : %s" % s.description)
            ret.append("ActionsEnabled : %s" % s.actions_enabled)
            ret.append("AlarmActions : %s" % s.alarm_actions)
            ret.append("AlarmArn : %s" % s.alarm_arn)
            ret.append("AlarmConfigurationUpdatedTimestamp : %s" %
                       s.last_updated)
            ret.append("ComparisonOperator : %s" % s.comparison)
            ret.append("Dimensions : %s" % s.dimensions)
            ret.append("EvaluationPeriods : %s" % s.evaluation_periods)
            ret.append("InsufficientDataActions : %s" %
                       s.insufficient_data_actions)
            ret.append("MetricName : %s" % s.metric)
            ret.append("Namespace : %s" % s.namespace)
            ret.append("OKActions : %s" % s.ok_actions)
            ret.append("Period : %s" % s.period)
            ret.append("StateReason : %s" % s.state_reason)
            ret.append("StateUpdatedTimestamp : %s" %
                       s.last_updated)
            ret.append("StateValue : %s" % s.state_value)
            ret.append("Statistic : %s" % s.statistic)
            ret.append("Threshold : %s" % s.threshold)
            ret.append("Unit : %s" % s.unit)
            ret.append("--")
        return '\n'.join(ret)

    def format_metric(self, metrics):
        '''
        Return string formatted representation of
        boto.ec2.cloudwatch.metric.Metric objects
        '''
        # Boto appears to return metrics as a list-inside-a-list
        # probably a bug in boto, but work around here
        if len(metrics) == 1:
            metlist = metrics[0]
        elif len(metrics) == 0:
            metlist = []
        else:
            # Shouldn't get here, unless boto gets fixed..
            logger.error("Unexpected metric list-of-list length (boto fixed?)")
            return "ERROR\n--"

        ret = []
        for m in metlist:
                ret.append("MetricName : %s" % m.name)
                ret.append("Namespace  : %s" % m.namespace)
                ret.append("Dimensions : %s" % m.dimensions)
                ret.append("--")
        return '\n'.join(ret)

def get_client(port=None, aws_access_key=None, aws_secret_key=None):
    """
    Returns a new boto CloudWatch client connection to a heat server
    Note : Configuration goes in /etc/boto.cfg, not via arguments
    """

    # Note we pass None/None for the keys so boto reads /etc/boto.cfg
    # Also note is_secure is defaulted to False as HTTPS connections
    # don't seem to work atm, FIXME
    cloudwatch = BotoCWClient(aws_access_key_id=aws_access_key,
                              aws_secret_access_key=aws_secret_key,
                              is_secure=False,
                              port=port,
                              path="/v1")
    if cloudwatch:
        logger.debug("Got CW connection object OK")
    else:
        logger.error("Error establishing CloudWatch connection!")
        sys.exit(1)

    return cloudwatch


text:
<!DOCTYPE html>

    <title>Ajamu Demo</title>
    <link rel="stylesheet" href="styles.css">

    <aja src="http://freegeoip.net/json/">

You are here: {city} {region_code}, {country_code}

    </aja>
    <aja src="https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20weather.forecast%20where%20woeid%20in%20(select%20woeid%20from%20geo.places(1)%20where%20text%3D%22nome%2C%20ak%22)&format=json&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys">

{query.results.channel.title}

            {query.results.channel.item.forecast[0].day}
            Temperatures between {query.results.channel.item.forecast[0].high} and {query.results.channel.item.forecast[0].low}.
            {query.results.channel.item.forecast[0].text}

            {query.results.channel.item.forecast[1].day}
            Temperatures between {query.results.channel.item.forecast[1].high} and {query.results.channel.item.forecast[1].low}.
            {query.results.channel.item.forecast[1].text}

            {query.results.channel.item.forecast[2].day}
            Temperatures between {query.results.channel.item.forecast[2].high} and {query.results.channel.item.forecast[2].low}.
            {query.results.channel.item.forecast[2].text}

            {query.results.channel.item.forecast[3].day}
            Temperatures between {query.results.channel.item.forecast[3].high} and {query.results.channel.item.forecast[3].low}.
            {query.results.channel.item.forecast[3].text}

            {query.results.channel.item.forecast[4].day}
            Temperatures between {query.results.channel.item.forecast[4].high} and {query.results.channel.item.forecast[4].low}.
            {query.results.channel.item.forecast[4].text}

    </aja>


text:
//
//  UIImage+FloodFill.m
//  ImageFloodFilleDemo
//
//  Created by chintan on 15/07/13.
//  Copyright (c) 2013 ZWT. All rights reserved.
//

#import "UIImage+FloodFill.h"

#define DEBUG_ANTIALIASING 0

@implementation UIImage (FloodFill)
/*
    startPoint : Point from where you want to color. Generaly this is touch point.
                 This is important because color at start point will be replaced with other.

    newColor   : This color will be apply at point where the match on startPoint color found.

    tolerance  : If Tolerance is 0 than it will search for exact match of color
                 other wise it will take range according to tolerance value.

                 If You dont want to use tolerance and want to incress performance Than you can change
                 compareColor(ocolor, color, tolerance) with just ocolor==color which reduse function call.
*/
- (UIImage *) floodFillFromPoint:(CGPoint)startPoint withColor:(UIColor *)newColor andTolerance:(NSInteger)tolerance
{
    return [self floodFillFromPoint:startPoint withColor:newColor andTolerance:tolerance useAntiAlias:YES];
}

- (UIImage *) floodFillFromPoint:(CGPoint)startPoint withColor:(UIColor *)newColor andTolerance:(NSInteger)tolerance useAntiAlias:(BOOL)antiAlias
{
    @try
    {
        /*
            First We create rowData from UIImage.
            We require this conversation so that we can use detail at pixel like color at pixel.
            You can get some discussion about this topic here:
            http://stackoverflow.com/questions/448125/how-to-get-pixel-data-from-a-uiimage-cocoa-touch-or-cgimage-core-graphics
        */

        CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

        CGImageRef imageRef = [self CGImage];

        NSUInteger width = CGImageGetWidth(imageRef);
        NSUInteger height = CGImageGetHeight(imageRef);
        NSUInteger bytesPerPixel = CGImageGetBitsPerPixel(imageRef) / 8;
        NSUInteger bytesPerRow = CGImageGetBytesPerRow(imageRef);
        NSUInteger bitsPerComponent = CGImageGetBitsPerComponent(imageRef);

        unsigned char *imageData = malloc(height * width * bytesPerPixel);

        CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(imageRef);

        if (kCGImageAlphaLast == (uint32_t)bitmapInfo ||
            kCGImageAlphaFirst == (uint32_t)bitmapInfo)
        {
            bitmapInfo = (uint32_t)kCGImageAlphaPremultipliedLast;
        }

        CGContextRef context = CGBitmapContextCreate(imageData,
                                                     width,
                                                     height,
                                                     bitsPerComponent,
                                                     bytesPerRow,
                                                     colorSpace,
                                                     bitmapInfo);
        CGColorSpaceRelease(colorSpace);

        CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);

        //Get color at start point
        NSUInteger byteIndex = (bytesPerRow * roundf(startPoint.y)) + roundf(startPoint.x) * bytesPerPixel;

        NSUInteger ocolor = getColorCode(byteIndex, imageData);

        if (compareColor(ocolor, 0, 0))
        {
            return nil;
        }

        //Convert newColor to RGBA value so we can save it to image.
        NSInteger newRed, newGreen, newBlue, newAlpha;

        const CGFloat *components = CGColorGetComponents(newColor.CGColor);

        /*
            If you are not getting why I use CGColorGetNumberOfComponents than read following link:
            http://stackoverflow.com/questions/9238743/is-there-an-issue-with-cgcolorgetcomponents
        */

        if(CGColorGetNumberOfComponents(newColor.CGColor) == 2)
        {
            newRed   = newGreen = newBlue = components[0] * 255;
            newAlpha = components[1] * 255;
        }
        else if (CGColorGetNumberOfComponents(newColor.CGColor) == 4)
        {
            if ((bitmapInfo&kCGBitmapByteOrderMask) == kCGBitmapByteOrder32Little)
            {
                newRed   = components[2] * 255;
                newGreen = components[1] * 255;
                newBlue  = components[0] * 255;
                newAlpha = 255;
            }
            else
            {
                newRed   = components[0] * 255;
                newGreen = components[1] * 255;
                newBlue  = components[2] * 255;
                newAlpha = 255;
            }
        }

        NSUInteger ncolor = (newRed << 24) | (newGreen << 16) | (newBlue << 8) | newAlpha;

        /*
            We are using stack to store point.
            Stack is implemented by LinkList.
            To incress speed I have used NSMutableData insted of NSMutableArray.
            To see Detail Of This implementation visit following leink.
            http://iwantmyreal.name/blog/2012/09/29/a-faster-array-in-objective-c/
        */

        LinkedListStack *points = [[LinkedListStack alloc] initWithCapacity:500 incrementSize:500 andMultiplier:height];
        LinkedListStack *antiAliasingPoints = [[LinkedListStack alloc] initWithCapacity:500 incrementSize:500 andMultiplier:height];

        NSInteger x = roundf(startPoint.x);
        NSInteger y = roundf(startPoint.y);

        [points pushFrontX:x andY:y];

        /*
            This algorithem is prety simple though it llook odd in Objective C syntex.
            To get familer with this algorithm visit following link.
            http://lodev.org/cgtutor/floodfill.html
            You can read hole artical for knowledge.
            If you are familer with flood fill than got to Scanline Floodfill Algorithm With Stack (floodFillScanlineStack)
        */

        NSUInteger color;
        BOOL spanLeft,spanRight;

        while ([points popFront:&x andY:&y] != INVALID_NODE_CONTENT)
        {
            byteIndex = (bytesPerRow * roundf(y)) + roundf(x) * bytesPerPixel;

            color = getColorCode(byteIndex, imageData);

            while(y >= 0 && compareColor(ocolor, color, tolerance))
            {
                y--;

                if(y >= 0)
                {
                    byteIndex = (bytesPerRow * roundf(y)) + roundf(x) * bytesPerPixel;

                    color = getColorCode(byteIndex, imageData);
                }
            }

            // Add the top most point on the antialiasing list
            if(y >= 0 && !compareColor(ocolor, color, 0))
            {
                [antiAliasingPoints pushFrontX:x andY:y];
            }

            y++;

            spanLeft = spanRight = NO;

            byteIndex = (bytesPerRow * roundf(y)) + roundf(x) * bytesPerPixel;

            color = getColorCode(byteIndex, imageData);

            while (y < height && compareColor(ocolor, color, tolerance) && ncolor != color)
            {
                //Change old color with newColor RGBA value
                imageData[byteIndex + 0] = newRed;
                imageData[byteIndex + 1] = newGreen;
                imageData[byteIndex + 2] = newBlue;
                imageData[byteIndex + 3] = newAlpha;

                if(x > 0)
                {
                    byteIndex = (bytesPerRow * roundf(y)) + roundf(x - 1) * bytesPerPixel;

                    color = getColorCode(byteIndex, imageData);

                    if(!spanLeft && x > 0 && compareColor(ocolor, color, tolerance))
                    {
                        [points pushFrontX:(x - 1) andY:y];

                        spanLeft = YES;
                    }
                    else if(spanLeft && x > 0 && !compareColor(ocolor, color, tolerance))
                    {
                        spanLeft = NO;
                    }

                    // we can't go left. Add the point on the antialiasing list
                    if(!spanLeft && x > 0 && !compareColor(ocolor, color, tolerance) && !compareColor(ncolor, color, tolerance))
                    {
                        [antiAliasingPoints pushFrontX:(x - 1) andY:y];
                    }
                }

                if(x < width - 1)
                {
                    byteIndex = (bytesPerRow * roundf(y)) + roundf(x + 1) * bytesPerPixel;;

                    color = getColorCode(byteIndex, imageData);

                    if(!spanRight && compareColor(ocolor, color, tolerance))
                    {
                        [points pushFrontX:(x + 1) andY:y];

                        spanRight = YES;
                    }
                    else if(spanRight && !compareColor(ocolor, color, tolerance))
                    {
                        spanRight = NO;
                    }

                    // we can't go right. Add the point on the antialiasing list
                    if(!spanRight && !compareColor(ocolor, color, tolerance) && !compareColor(ncolor, color, tolerance))
                    {
                        [antiAliasingPoints pushFrontX:(x + 1) andY:y];
                    }
                }

                y++;

                if(y < height)
                {
                    byteIndex = (bytesPerRow * roundf(y)) + roundf(x) * bytesPerPixel;

                    color = getColorCode(byteIndex, imageData);
                }
            }

            if (y<height)
            {
                byteIndex = (bytesPerRow * roundf(y)) + roundf(x) * bytesPerPixel;
                color = getColorCode(byteIndex, imageData);

                // Add the bottom point on the antialiasing list
                if (!compareColor(ocolor, color, 0))
                    [antiAliasingPoints pushFrontX:x andY:y];
            }
        }

        // For each point marked
        // perform antialiasing on the same pixel, plus the top,left,bottom and right pixel
        NSUInteger antialiasColor = getColorCodeFromUIColor(newColor,bitmapInfo&kCGBitmapByteOrderMask );
        NSInteger red1   = ((0xff000000 & antialiasColor) >> 24);
        NSInteger green1 = ((0x00ff0000 & antialiasColor) >> 16);
        NSInteger blue1  = ((0x0000ff00 & antialiasColor) >> 8);
        NSInteger alpha1 =  (0x000000ff & antialiasColor);

        while ([antiAliasingPoints popFront:&x andY:&y] != INVALID_NODE_CONTENT)
        {
            byteIndex = (bytesPerRow * roundf(y)) + roundf(x) * bytesPerPixel;
            color = getColorCode(byteIndex, imageData);

            if (!compareColor(ncolor, color, 0))
            {
                NSInteger red2   = ((0xff000000 & color) >> 24);
                NSInteger green2 = ((0x00ff0000 & color) >> 16);
                NSInteger blue2 = ((0x0000ff00 & color) >> 8);
                NSInteger alpha2 =  (0x000000ff & color);

                if (antiAlias)
                {
                    imageData[byteIndex + 0] = (red1 + red2) / 2;
                    imageData[byteIndex + 1] = (green1 + green2) / 2;
                    imageData[byteIndex + 2] = (blue1 + blue2) / 2;
                    imageData[byteIndex + 3] = (alpha1 + alpha2) / 2;
                }
                else
                {
                    imageData[byteIndex + 0] = red2;
                    imageData[byteIndex + 1] = green2;
                    imageData[byteIndex + 2] = blue2;
                    imageData[byteIndex + 3] = alpha2;
                }

#if DEBUG_ANTIALIASING
                imageData[byteIndex + 0] = 0;
                imageData[byteIndex + 1] = 0;
                imageData[byteIndex + 2] = 255;
                imageData[byteIndex + 3] = 255;
#endif
            }

            // left
            if (x>0)
            {
                byteIndex = (bytesPerRow * roundf(y)) + roundf(x - 1) * bytesPerPixel;
                color = getColorCode(byteIndex, imageData);

                if (!compareColor(ncolor, color, 0))
                {
                    NSInteger red2   = ((0xff000000 & color) >> 24);
                    NSInteger green2 = ((0x00ff0000 & color) >> 16);
                    NSInteger blue2 = ((0x0000ff00 & color) >> 8);
                    NSInteger alpha2 =  (0x000000ff & color);

                    if (antiAlias) {
                        imageData[byteIndex + 0] = (red1 + red2) / 2;
                        imageData[byteIndex + 1] = (green1 + green2) / 2;
                        imageData[byteIndex + 2] = (blue1 + blue2) / 2;
                        imageData[byteIndex + 3] = (alpha1 + alpha2) / 2;
                    } else {
                        imageData[byteIndex + 0] = red2;
                        imageData[byteIndex + 1] = green2;
                        imageData[byteIndex + 2] = blue2;
                        imageData[byteIndex + 3] = alpha2;
                    }

#if DEBUG_ANTIALIASING
                    imageData[byteIndex + 0] = 0;
                    imageData[byteIndex + 1] = 0;
                    imageData[byteIndex + 2] = 255;
                    imageData[byteIndex + 3] = 255;
#endif
                }
            }

            if (x<width)
            {
                byteIndex = (bytesPerRow * roundf(y)) + MIN(width,roundf(x + 1)) * bytesPerPixel;
                color = getColorCode(byteIndex, imageData);

                if (!compareColor(ncolor, color, 0))
                {
                    NSInteger red2   = ((0xff000000 & color) >> 24);
                    NSInteger green2 = ((0x00ff0000 & color) >> 16);
                    NSInteger blue2 = ((0x0000ff00 & color) >> 8);
                    NSInteger alpha2 =  (0x000000ff & color);

                    if (antiAlias)
                    {
                        imageData[byteIndex + 0] = (red1 + red2) / 2;
                        imageData[byteIndex + 1] = (green1 + green2) / 2;
                        imageData[byteIndex + 2] = (blue1 + blue2) / 2;
                        imageData[byteIndex + 3] = (alpha1 + alpha2) / 2;
                    }
                    else
                    {
                        imageData[byteIndex + 0] = red2;
                        imageData[byteIndex + 1] = green2;
                        imageData[byteIndex + 2] = blue2;
                        imageData[byteIndex + 3] = alpha2;
                    }

#if DEBUG_ANTIALIASING
                    imageData[byteIndex + 0] = 0;
                    imageData[byteIndex + 1] = 0;
                    imageData[byteIndex + 2] = 255;
                    imageData[byteIndex + 3] = 255;
#endif
                }
            }

            if (y>0)
            {
                byteIndex = (bytesPerRow * roundf(y - 1)) + roundf(x) * bytesPerPixel;
                color = getColorCode(byteIndex, imageData);

                if (!compareColor(ncolor, color, 0))
                {
                    NSInteger red2   = ((0xff000000 & color) >> 24);
                    NSInteger green2 = ((0x00ff0000 & color) >> 16);
                    NSInteger blue2 = ((0x0000ff00 & color) >> 8);
                    NSInteger alpha2 =  (0x000000ff & color);

                    if (antiAlias)
                    {
                        imageData[byteIndex + 0] = (red1 + red2) / 2;
                        imageData[byteIndex + 1] = (green1 + green2) / 2;
                        imageData[byteIndex + 2] = (blue1 + blue2) / 2;
                        imageData[byteIndex + 3] = (alpha1 + alpha2) / 2;
                    }
                    else
                    {
                        imageData[byteIndex + 0] = red2;
                        imageData[byteIndex + 1] = green2;
                        imageData[byteIndex + 2] = blue2;
                        imageData[byteIndex + 3] = alpha2;
                    }

#if DEBUG_ANTIALIASING
                    imageData[byteIndex + 0] = 0;
                    imageData[byteIndex + 1] = 0;
                    imageData[byteIndex + 2] = 255;
                    imageData[byteIndex + 3] = 255;
#endif
                }
            }

            if (y<height)
            {
                byteIndex = (bytesPerRow * MIN(height,roundf(y + 1))) + roundf(x) * bytesPerPixel;
                color = getColorCode(byteIndex, imageData);

                if (!compareColor(ncolor, color, 0))
                {
                    NSInteger red2   = ((0xff000000 & color) >> 24);
                    NSInteger green2 = ((0x00ff0000 & color) >> 16);
                    NSInteger blue2 = ((0x0000ff00 & color) >> 8);
                    NSInteger alpha2 =  (0x000000ff & color);

                    if (antiAlias)
                    {
                        imageData[byteIndex + 0] = (red1 + red2) / 2;
                        imageData[byteIndex + 1] = (green1 + green2) / 2;
                        imageData[byteIndex + 2] = (blue1 + blue2) / 2;
                        imageData[byteIndex + 3] = (alpha1 + alpha2) / 2;
                    }
                    else
                    {
                        imageData[byteIndex + 0] = red2;
                        imageData[byteIndex + 1] = green2;
                        imageData[byteIndex + 2] = blue2;
                        imageData[byteIndex + 3] = alpha2;
                    }

#if DEBUG_ANTIALIASING
                    imageData[byteIndex + 0] = 0;
                    imageData[byteIndex + 1] = 0;
                    imageData[byteIndex + 2] = 255;
                    imageData[byteIndex + 3] = 255;
#endif
                }

            }
        }

        //Convert Flood filled image row data back to UIImage object.

        CGImageRef newCGImage = CGBitmapContextCreateImage(context);

        UIImage *result = [UIImage imageWithCGImage:newCGImage scale:[self scale] orientation:UIImageOrientationUp];

        CGImageRelease(newCGImage);

        CGContextRelease(context);

        free(imageData);

        return result;
    }
    @catch (NSException *exception)
    {
        NSLog(@"Exception : %@", exception);
    }
}

/*
    I have used pure C function because it is said than C function is faster than Objective - C method in call.
    This two function are called most of time so it require that calling this work in speed.
    I have not verified this performance so I like to here comment on this.
*/
/*
    This function extract color from image and convert it to integer represent.

    Converting to integer make comperation easy.
*/
NSUInteger getColorCode (NSUInteger byteIndex, unsigned char *imageData)
{
    NSUInteger red   = imageData[byteIndex];
    NSUInteger green = imageData[byteIndex + 1];
    NSUInteger blue  = imageData[byteIndex + 2];
    NSUInteger alpha = imageData[byteIndex + 3];

    return (red << 24) | (green << 16) | (blue << 8) | alpha;
}

/*
    This function compare two color with counting tolerance value.

    If color is between tolerance rancge than it return true other wise false.
*/
bool compareColor (NSUInteger color1, NSUInteger color2, NSInteger tolorance)
{
    if(color1 == color2)
        return true;

    NSInteger red1   = ((0xff000000 & color1) >> 24);
    NSInteger green1 = ((0x00ff0000 & color1) >> 16);
    NSInteger blue1  = ((0x0000ff00 & color1) >> 8);
    NSInteger alpha1 =  (0x000000ff & color1);

    NSInteger red2   = ((0xff000000 & color2) >> 24);
    NSInteger green2 = ((0x00ff0000 & color2) >> 16);
    NSInteger blue2  = ((0x0000ff00 & color2) >> 8);
    NSInteger alpha2 =  (0x000000ff & color2);

    NSInteger diffRed   = labs(red2   - red1);
    NSInteger diffGreen = labs(green2 - green1);
    NSInteger diffBlue  = labs(blue2  - blue1);
    NSInteger diffAlpha = labs(alpha2 - alpha1);

    if( diffRed   > tolorance ||
        diffGreen > tolorance ||
        diffBlue  > tolorance ||
        diffAlpha > tolorance  )
    {
        return false;
    }

    return true;
}

NSUInteger getColorCodeFromUIColor(UIColor *color, CGBitmapInfo orderMask)
{
    //Convert newColor to RGBA value so we can save it to image.
    NSInteger newRed, newGreen, newBlue, newAlpha;

    const CGFloat *components = CGColorGetComponents(color.CGColor);

    /*
     If you are not getting why I use CGColorGetNumberOfComponents than read following link:
     http://stackoverflow.com/questions/9238743/is-there-an-issue-with-cgcolorgetcomponents
     */

    if(CGColorGetNumberOfComponents(color.CGColor) == 2)
    {
        newRed   = newGreen = newBlue = components[0] * 255;
        newAlpha = components[1] * 255;
    }
    else if (CGColorGetNumberOfComponents(color.CGColor) == 4)
    {
        if (orderMask == kCGBitmapByteOrder32Little)
        {
            newRed   = components[2] * 255;
            newGreen = components[1] * 255;
            newBlue  = components[0] * 255;
            newAlpha = 255;
        }
        else
        {
            newRed   = components[0] * 255;
            newGreen = components[1] * 255;
            newBlue  = components[2] * 255;
            newAlpha = 255;
        }
    }
    else
    {
        newRed   = newGreen = newBlue = 0;
        newAlpha = 255;
    }

    NSUInteger ncolor = (newRed << 24) | (newGreen << 16) | (newBlue << 8) | newAlpha;

    return ncolor;
}

@end


text:
BOOST  = /usr/lib/x86_64-linux-gnu/

CPP = g++ -O3 -funroll-loops --ansi --pedantic -std=c++11
CC  = gcc -O3 -funroll-loops

export CPP
export CC
export BOOST

.SUFFIXES:
.SUFFIXES: .cpp .o

.PHONY: server clean

all:
	cd fopl && make
	cd aux && make
	cd infero && make
	cd match && make
	cd infero_vector && make lib
	cd knowledge && make
	cd context && make lib
	cd nl && make lib
	cd writer && make lib
	cd pragmatics && make lib
	cd engine && make lib
	cd sense && make lib
	cd arbiter && make lib
	cd drt && make lib
	cd wisdom && make && make lib
	cd server && make

clean:
	-rm */*.a
	-cd fopl && make clean
	-cd aux && make clean
	-cd infero && make clean
	-cd engine && make clean
	-cd sense && make clean
	-cd infero_vector && make clean
	-cd knowledge && make clean
	-cd context && make clean
	-cd nl && make clean
	-cd match && make clean
	-cd writer && make clean
	-cd pragmatics && make clean
	-cd arbiter && make clean
	-cd drt && make clean
	-cd wisdom && make clean
	-cd server && make clean


text:
@interface RCSArrayIterationContext ()

@property (nonatomic, readwrite, strong) RCSArrayIteration *iteration;
@property (nonatomic, readwrite, weak) id object;
@property (nonatomic, readwrite, copy) RCSArrayIterationEachBlock eachBlock;
@property (nonatomic, readwrite, copy) RCSArrayIterationCompletionBlock completionBlock;
@property (nonatomic, readwrite, copy) RCSArrayIterationFailureBlock failureBlock;

@end

@implementation RCSArrayIterationContext

@dynamic iteration; // inherit ivar from superclass

- (RCSArrayIteration *)iteration
{
    return (RCSArrayIteration *)[super iteration];
}

+ (instancetype)contextFor:(RCSArrayIteration *)iteration
                     index:(NSUInteger)index
                    length:(NSUInteger)length
                    object:(id)object
                   isFirst:(BOOL)first
                    isLast:(BOOL)last
                 isStopped:(BOOL)stopped
                     error:(NSError *)error
                 eachBlock:(RCSArrayIterationEachBlock)eachBlock
           completionBlock:(RCSArrayIterationCompletionBlock)completionBlock
              failureBlock:(RCSArrayIterationFailureBlock)failureBlock
{
    RCSArrayIterationContext *result = [self contextFor:iteration index:index length:length isFirst:first isLast:last isStopped:stopped error:error];
    result.object = object;
    result.eachBlock = eachBlock;
    result.completionBlock = completionBlock;
    result.failureBlock = failureBlock;
    return result;
}

- (instancetype)nextContextWithObject:(id)nextObject
{
    RCSArrayIterationContext *nextContext = [self nextContext];
    nextContext.object = nextObject;
    nextContext.eachBlock = self.eachBlock;
    nextContext.completionBlock = self.completionBlock;
    nextContext.failureBlock = self.failureBlock;
    return nextContext;
}

@end


text:
<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>RSS Title</title>
    <description>This is an example of an RSS feed</description>
    <link>http://www.example.com/a</link>
    <link>http://www.example.com/b</link>
    <link></link>
    <atom:link href="self" rel="self" type="application/rss+xml" />
    <copyright>2020 Example.com All rights reserved</copyright>
    <lastBuildDate>Mon, 06 Sep 2010 00:01:00 +0000</lastBuildDate>
    <pubDate>Sun, 06 Sep 2009 16:20:00 +0000</pubDate>
    <ttl>1800</ttl>
    <language>en-us</language>
    <category>IT/Internet/Web development</category>
    <item>
      <title>Example entry</title>
      <description>Here is some text containing an interesting description.</description>
      <link>http://www.example.com/blog/post/1</link>
      <guid isPermaLink="false">7bd204c6-1655-4c27-aeee-53f933c5395f</guid>
      <pubDate>Sun, 06 Sep 2009 16:20:00 +0000</pubDate>
    </item>

  </channel>
</rss>


text:
(function (ng) {
	'use strict';

	var name = 'topicRepository';
	var app = ng.module(name, []);

	app.factory('timestampMarker', ['$log', function ($log) {
		var timestampMarker = {
			request: function (config) {
				$log.info(new Date().toLocaleTimeString(), [config.method, config.url, config]);
				return config;
			},
			response: function (response) {
				$log.info(new Date().toLocaleTimeString(), ['response', response.config.url, response]);
				return response;
			}
		};
		return timestampMarker;
	}]);

	app.config(['$httpProvider', function ($httpProvider) {
		$httpProvider.interceptors.push('timestampMarker');
	}]);

	app.factory(name, function ($q, $http) {
		var ROOT = "../api/";

		var call = function (method, params, data) {
			var path = ROOT + params;
			var deferred = $q.defer();
			var p;

			if (method == "post") {
				p = $http.post(path, data);
			}
			else if (method == "get") {
				p = $http.get(path);
			}
			else if (method == "delete") {
				p = $http.delete(path);
			}
			else if (method == "put") {
				p = $http.put(path, data);
			}

			p.success(function (result) {
				deferred.resolve(result);
			}).error(function (err) {
				deferred.reject(err);
			});
			return deferred.promise;
		};

		var topics = {
			getAll: function (count, offset, category, partial) {
				return call("get", "topic/GetAll?count=" + count + "&offset=" + offset + "&partial=" + partial + "&category=" + category);
			},
			getById: function (id) {
				return call("get", "topic/GetById?id=" + id);
			},
			search: function (search, count, offset, partial) {
				return call("post", "topic/Search/",
					{
						search: search,
						count: count,
						offset: offset,
						partial: partial
					});
			},
			add: function (topic) {
				return call("post", "topic/AddTopic", { topic: topic });
			},
			del: function (id) {
				return call("post", "topic/DeleteTopic", { id: id });
			},
			update: function (id, topic) {
				return call("post", "topic/UpdateTopic", { id: id, topic: topic });
			},
			titles: function (id, arrayId) {
				return call("post", "topic/GetTitles", { arrayId: arrayId });
			},
		};

		var links = {
			add: function (id, link) {
				return call("post", "topic/AddLink", { id: id, link: link });
			},
			del: function (id, link) {
				return call("post", "topic/DeleteLink", { id: id, link: link });
			}
		};

		var connections = {
			add: function (id, conId) {
				return call("post", "topic/AddConnection", { id: id, conId: conId });
			},
			del: function (id, conId) {
				return call("post", "topic/DeleteConnections", { id: id, conId: conId });
			}
		};

		return {
			topics: topics,
			links: links,
			connections: connections
		};
	});

})(angular);


text:
package server

import (
	"fmt"
	"net"
	// "os"

	"github.com/garyburd/redigo/redis"
)

func Handler(conn net.Conn, msgs chan string) {
	fmt.Println("[server:Handler] connection from[", conn.RemoteAddr().String(), "]")

	buf := make([]byte, 1024)
	for {
		length, err := conn.Read(buf)
		if err != nil {
			fmt.Println("[server:Handler] the client[", conn.RemoteAddr().String(), "] Closed")
			conn.Close()
			break
		}
		if length > 0 {
			buf[length] = 0
		}

		recvStr := string(buf[0:length])
		msgs <- recvStr
	}
}

func echoHandler(conns *map[string]net.Conn, msgs chan string) {
	for {
		msg := <-msgs
		fmt.Println("[server:echoHandler] msg [" + msg + "]")

		for key, val := range *conns {
			//fmt.Println("[server:echoHandler]connection from ->", key)
			_, err := val.Write([]byte(msg))
			if err != nil {
				fmt.Println("[server:echoHandler]recive err ", err.Error())
				delete(*conns, key)
			}
		}
	}
}

func StartServer(port string) {
	fmt.Println("[server]StartServer ...")

	service := ":" + port
	tcpAddr, err := net.ResolveTCPAddr("tcp", service)
	if err != nil {
		fmt.Println("[server]ResolveTCPAddr err")
		return
	}

	listen, err := net.ListenTCP("tcp", tcpAddr)
	if err != nil {
		fmt.Println("[server]ListenTCP err")
		return
	}
	fmt.Println("[server]ListenTCP ok")

	conns := make(map[string]net.Conn)
	msgs := make(chan string, 100)

	go echoHandler(&conns, msgs)

	// init redis db
	client, err := redis.Dial("tcp", "localhost:6379")
	if err != nil {
		fmt.Println("[server]connect to redis Err.", err)
		return
	} else {
		fmt.Println("[server]connect to redis OK")
	}
	defer client.Close()
	//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||
	fmt.Println("[server] test redis")
	// _, err :=
	client.Do("set", "username", "nick")
	if err != nil {
		fmt.Println("[server] set name err")
	} else {
		fmt.Println("[server] set name ok")
	}

	username, err := redis.String(client.Do("get","username"))
	if err != nil {
		fmt.Println("[server] get name err")
	}else{
		fmt.Println("[server] get name ", username)
	}
	//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||

	for {
		conn, err := listen.Accept()
		if err != nil {
			fmt.Println("[server]Accept err")
			continue
		}
		conns[conn.RemoteAddr().String()] = conn

		go Handler(conn, msgs)
	}
}


text:
package org.springframework.cloud.dataflow.server.cloudfoundry;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;

import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.deployer.spi.task.TaskLauncher;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest(properties = {
		"spring.cloud.deployer.cloudfoundry.org=myorg," + "spring.cloud.deployer.cloudfoundry.username=myusername",
		"spring.cloud.deployer.cloudfoundry.password=mypassword", "spring.cloud.deployer.cloudfoundry.space=myspace",
		"spring.cloud.deployer.cloudfoundry.url=https://localhost",
		"spring.cloud.deployer.cloudfoundry.stream.api.timeout=1" })
public class CloudFoundryDataFlowServerApplicationTests {

	@Test
	public void contextLoads() {
	}

	@Configuration
	static public class TaskLauncherConfiguration {

		@Bean
		@Primary
		public TaskLauncher taskLauncher() {
			return Mockito.mock(TaskLauncher.class);
		}
	}
}


text:
sed -i "\$a@chromium-browser --incognito --kiosk https://www.badrumsbekannelser.se/mirrors/dcdedc9a-6b9e-4c12-806a-e09a59815359" /home/pi/.config/lxsession/LXDE-pi/autostart

sed -i 's/width=100/width=0/g' /home/pi/.config/lxpanel/LXDE-pi/panels/panel
sed -i 's/autohide=0/autohide=1/g' /home/pi/.config/lxpanel/LXDE-pi/panels/panel
sed -i 's/transparent=0/transparent=100/g' /home/pi/.config/lxpanel/LXDE-pi/panels/panel

apt-get install unclutter -y

reboot