text:
package org.auraframework.integration.test.util;

import java.io.File;
import java.io.FileOutputStream;
import java.io.PrintWriter;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
import java.util.Set;
import java.util.concurrent.Semaphore;
import java.util.logging.Logger;

import org.apache.commons.codec.binary.Base64;
import org.apache.http.NameValuePair;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.message.BasicNameValuePair;
import org.auraframework.def.ApplicationDef;
import org.auraframework.def.BaseComponentDef;
import org.auraframework.def.ComponentDef;
import org.auraframework.def.DefDescriptor;
import org.auraframework.system.AuraContext.Mode;
import org.auraframework.test.util.AuraUITestingUtil;
import org.auraframework.test.util.SauceUtil;
import org.auraframework.test.util.WebDriverProvider;
import org.auraframework.test.util.WebDriverUtil;
import org.auraframework.test.util.WebDriverUtil.BrowserType;
import org.auraframework.throwable.AuraExceptionUtil;
import org.auraframework.util.ServiceLocator;
import org.auraframework.util.test.annotation.FreshBrowserInstance;
import org.auraframework.util.test.annotation.WebDriverTest;
import org.eclipse.jetty.util.log.Log;
import org.json.JSONArray;
import org.junit.After;
import org.junit.Before;
import org.openqa.selenium.By;
import org.openqa.selenium.Dimension;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.Keys;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.TimeoutException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.interactions.Action;
import org.openqa.selenium.interactions.Actions;
import org.openqa.selenium.interactions.HasTouchScreen;
import org.openqa.selenium.interactions.touch.FlickAction;
import org.openqa.selenium.interactions.touch.TouchActions;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.remote.RemoteWebDriver;
import org.openqa.selenium.support.events.EventFiringWebDriver;
import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.uiautomation.ios.client.uiamodels.impl.RemoteIOSDriver;
import org.uiautomation.ios.client.uiamodels.impl.augmenter.IOSDriverAugmenter;

import com.google.common.collect.Lists;
import com.google.common.collect.Sets;

import junit.framework.AssertionFailedError;

/**
 * Base class for Aura WebDriver tests.
 */
@WebDriverTest
public abstract class WebDriverTestCase extends IntegrationTestCase {
    // Rerun test marked with the flapper annotation a certain number of times before failing the build
    private static int FLAPPER_NUM_RETRIES = 1;

    private static final Logger logger = Logger.getLogger("WebDriverTestCase");

    /** Checks whether {@code oneClass} is mentioned as a class on {@code elem}. */
    public boolean hasCssClass(WebElement elem, String oneClass) {
        String allClasses = elem.getAttribute("class");
        return allClasses.contains(" " + oneClass + " ") || allClasses.equals(oneClass)
                || allClasses.startsWith(oneClass + " ") || allClasses.endsWith(" " + oneClass);
    }

    private WebDriver currentDriver = null;
    private BrowserType currentBrowserType = null;
    private AuraUITestingUtil auraUITestingUtil;
    private Boolean needsFreshBrowser = null;

    @Retention(RetentionPolicy.RUNTIME)
    @Target({ ElementType.TYPE, ElementType.METHOD })
    public @interface TargetBrowsers {
        BrowserType[] value();
    }

    @Retention(RetentionPolicy.RUNTIME)
    @Target({ ElementType.TYPE, ElementType.METHOD })
    public @interface ExcludeBrowsers {
        BrowserType[] value();
    }

    @Retention(RetentionPolicy.RUNTIME)
    @Target({ ElementType.TYPE, ElementType.METHOD })
    @Inherited
    public @interface CheckAccessibility {
        boolean value() default true;

        // Default browser to run accessibility test is Google Chrome
        BrowserType browserType() default BrowserType.GOOGLECHROME;
    }

    @Retention(RetentionPolicy.RUNTIME)
    @Target({ ElementType.TYPE, ElementType.METHOD })
    @Inherited
    public @interface Flapper {
    }

    /**
     * @Before is called when running from your IDE, running from test/runner.app will invoke "runBare"
     * and does not call Before methods
     */
    @Before
    public void beforeWebDriverTestCase() {
        currentBrowserType = BrowserType.GOOGLECHROME;
        needsFreshBrowser = true;
    }

    @Override
    public void setUp() throws Exception {
        super.setUp();
        if (currentBrowserType == null) {
            beforeWebDriverTestCase();
        }
    }

    @After
    public void afterWebDriverTestCase() {
        if (currentDriver != null && needsFreshBrowser) {
            try {
                currentDriver.quit();
            } catch (Exception e) {
                // if the driver is dead or already quit, we just want to ignore the exception
            }
            currentDriver = null;
        }
    }

    public String getBrowserTypeString() {
        if (this.currentBrowserType != null) {
            return "?browser=" + this.currentBrowserType.name();
        }
        return "";
    }

    protected void superRunTest() throws Throwable {
        super.runTest();
    }

    public void runTestWithBrowser(BrowserType browserType) throws Throwable {
        Throwable failure = null;
        if (currentBrowserType != browserType) {
            currentDriver = null;
            currentBrowserType = browserType;
        }

        for (int i = 0; i <= FLAPPER_NUM_RETRIES; i++) {
            try {
                // re-initialize driver pointer here because test analysis might need it after perBrowserTearDown
                getDriver();
                setUp();
                superRunTest();
                return;
            } catch (Throwable th) {
                failure = th;
                if (!isFlapper()) {
                    break;
                }

                logger.info(getClass().getName() + "." + getName() + " failed at iteration " + (i + 1) + " of "
                        + (FLAPPER_NUM_RETRIES + 1) + " with error: " + AuraExceptionUtil.getStackTrace(th));

                quitDriver();
            } finally {
                tearDown();
            }
        }

        if (failure != null) {
            throw failure;
        }
    }

    /**
     * Checks if the current test is marked with the flapper annotation.
     */
    private boolean isFlapper() {
        Class<?> testClass = getClass();
        if (testClass.isAnnotationPresent(Flapper.class)) {
            return true;
        }
        if (getTestLabels().contains("flapper")) {
            return true;
        }
        try {
            return testClass.getMethod(getName()).isAnnotationPresent(Flapper.class);
        } catch (Throwable t) {
            return false;
        }
    }

    /**
     * Checks if the current test is marked with the flapper annotation.
     */
    private boolean needsFreshBrowser() {
        if (needsFreshBrowser != null) {
            return needsFreshBrowser;
        }

        Class<?> testClass = getClass();

        if (testClass.getAnnotation(FreshBrowserInstance.class) != null) {
            return needsFreshBrowser = true;
        }
        try {
            if (testClass.getMethod(getName()).getAnnotation(FreshBrowserInstance.class) != null) {
                return needsFreshBrowser = true;
            }
        } catch (NoSuchMethodException e) {
            // ignore
        }
        if (getTestLabels().contains("freshBrowserInstance")) {
            return needsFreshBrowser = true;
        }
        return needsFreshBrowser = false;
    }

    @SuppressWarnings("serial")
    private static class AggregateFailure extends AssertionFailedError {
        private final Collection<Throwable> failures;

        private AggregateFailure(Collection<Throwable> failures) {
            super(String.format("There were errors across %s browsers:", failures == null ? 0 : failures.size()));
            this.failures = failures;
        }

        @Override
        public void printStackTrace(PrintWriter printer) {
            printer.append(getMessage()).append('\n');
            for (Throwable e : failures) {
                e.printStackTrace(printer);
            }
        }
    }

    @Override
    public void runTest() throws Throwable {
        // sometimes the first set of parallel WebDriver tests that run have problems,
        // this may be due to the extra steps that happen when everything is initialized
        // here we force the first test to execute single threaded and also initialize
        // aura before invoking that first test
        HttpGet get = null;
        try {
            LOCK_FIRST_TEST_SEMAPHORE.acquire();
            if (numWebDriverTestsExecuted == 0) {
                get = obtainGetMethod("/uitest/testApp.app", true, null);
                getResponseBody(perform(get)); // need to drain response for HttpClient
            }
            runTestImpl();
        } finally {
            if (get != null) {
                get.releaseConnection();
            }
            numWebDriverTestsExecuted++;
            // release enough permits to run in parallel after first
            LOCK_FIRST_TEST_SEMAPHORE.release(TestExecutor.NUM_THREADS);
        }
    }

    private static int numWebDriverTestsExecuted;
    private static final Semaphore LOCK_FIRST_TEST_SEMAPHORE = new Semaphore(1);

    private void runTestImpl() throws Throwable {
        List<Throwable> failures = Lists.newArrayList();
        for (BrowserType browser : WebDriverUtil.getBrowserListForTestRun(this.getTargetBrowsers(),
                this.getExcludedBrowsers())) {
            try {
                runTestWithBrowser(browser);
            } catch (Throwable t) {
                Throwable th = addAuraInfoToTestFailure(t);
                logger.warning(AuraExceptionUtil.getStackTrace(th));
                failures.add(th);
            } finally {
                quitDriver();
            }
        }
        // Aggregate results across browser runs, if more than one failure was encountered
        if (!failures.isEmpty()) {
            if (failures.size() == 1) {
                throw failures.get(0);
            }
            throw new AggregateFailure(failures);
        }
    }

    @SuppressWarnings("unchecked")
    public final Map<String, Map<String, Map<String, List<Object>>>> getAuraStats() {
        return (Map<String, Map<String, Map<String, List<Object>>>>) getAuraUITestingUtil()
                .getRawEval("return $A.PERFCORE.stats.get();");
    }

    public JSONArray getLastCollectedMetrics() {
        return null;
    }

    /**
     * Wrapper for non-asserted failures
     */
    public static class UnexpectedError extends Error {
        private static final long serialVersionUID = 1L;

        UnexpectedError(String description, Throwable cause) {
            super(description, cause);
        }
    }

    private static String WRAPPER_APP = "<aura:application access=\"GLOBAL\" render=\"%s\"><%s/></aura:application>";

    /**
     * Load a string as a component in an app.
     *
     * @param namePrefix the name of the component
     * @param componentText The actual text of the component.
     * @param isClient Should we use client or server rendering.
     */
    protected void loadComponent(String namePrefix, String componentText, boolean isClient)
            throws Exception {
        String appText;
        String render;

        if (isClient) {
            render = "client";
        } else {
            render = "server";
        }

        DefDescriptor<ComponentDef> cmpDesc = addSourceAutoCleanup(ComponentDef.class, componentText, namePrefix);
        appText = String.format(WRAPPER_APP, render, cmpDesc.getDescriptorName());
        loadApplication(namePrefix + "App", appText, isClient);
    }

    /**
     * A convenience routine to load a application string.
     *
     * @param namePrefix the application name.
     * @param appText the actual text of the application
     */
    protected void loadApplication(String namePrefix, String appText, boolean isClient) throws Exception {
        DefDescriptor<ApplicationDef> appDesc = addSourceAutoCleanup(ApplicationDef.class, appText, namePrefix);
        String openPath = String.format("/%s/%s.app", appDesc.getNamespace(), appDesc.getName());
        if (isClient) {
            open(openPath);
        } else {
            // when using server side rendering, we need to not wait for aura
            openNoAura(openPath);
        }
    }

    /**
     * Gather up useful info to add to a test failure. try to get
     *

     *
any client js errors

     *
last known js test function

     *
running/waiting

     *
a screenshot

     *

     *
     * @param originalErr the test failure
     * @throws Throwable a new AssertionFailedError or UnexpectedError with the original and additional info
     */
    private Throwable addAuraInfoToTestFailure(Throwable originalErr) {
        StringBuffer description = new StringBuffer();
        if (originalErr != null) {
            String msg = originalErr.getMessage();
            if (msg != null) {
                description.append(msg);
            }
        }

        description.append(String.format("\nBrowser: %s", currentBrowserType));
        if (getAuraUITestingUtil() != null) {
            description.append("\nUser-Agent: " + getAuraUITestingUtil().getUserAgent());
        }
        if (currentDriver == null) {
            description.append("\nTest failed before WebDriver was initialized");
        } else {
            description
                    .append("\nWebDriver: " + currentDriver);
            description.append("\nJS state: ");
            try {
                String dump = (String) getAuraUITestingUtil()
                        .getRawEval("return (window.$A && $A.test && $A.test.getDump())||'';");
                if (dump.isEmpty()) {
                    description.append("no errors detected");
                } else {
                    description.append(dump);
                }
            } catch (Throwable t) {
                description.append(t.getMessage());
            }

            String screenshotsDirectory = System.getProperty("screenshots.directory");
            if (screenshotsDirectory != null) {
                String screenshot = null;
                TakesScreenshot ts = (TakesScreenshot) currentDriver;
                try {
                    screenshot = ts.getScreenshotAs(OutputType.BASE64);
                } catch (WebDriverException e) {
                    description.append(String.format("%nScreenshot: {capture error: %s}", e.getMessage()));
                }

                if (screenshot != null) {
                    String fileName = getClass().getName() + "." + getName() + "_" + currentBrowserType + ".png";
                    try {
                        File path = new File(screenshotsDirectory + "/" + fileName);
                        path.getParentFile().mkdirs();
                        byte[] bytes = Base64.decodeBase64(screenshot.getBytes());
                        FileOutputStream fos = new FileOutputStream(path);
                        fos.write(bytes);
                        fos.close();
                        String baseUrl = System.getProperty("screenshots.baseurl");
                        description.append(String.format("%nScreenshot: data:image/png;base64,%s", screenshot));
                        description.append(String.format("%nScreenshot: %s/%s", baseUrl, fileName));
                    } catch (Throwable t) {
                        description.append(String.format("%nScreenshot: {save error: %s}", t.getMessage()));
                    }
                }
            }

            try {
                description.append("\nApplication cache status: ");
                description
                        .append(getAuraUITestingUtil()
                                .getRawEval(
                                        "var cache=window.applicationCache;return (cache===undefined || cache===null)?'undefined':cache.status;")
                                .toString());
            } catch (Exception ex) {
                description.append("error calculating status: " + ex);
            }
            description.append("\n");
            if (SauceUtil.areTestsRunningOnSauce()) {
                String linkToJob = SauceUtil.getLinkToPublicJobInSauce(currentDriver);
                description.append("\nSauceLabs-recording: ");
                description.append((linkToJob != null) ? linkToJob : "{not available}");
            }
        }

        // replace original exception with new exception with additional info
        Throwable newFailure;
        if (originalErr instanceof AssertionFailedError) {
            newFailure = new AssertionFailedError(description.toString());
        } else {
            description.insert(0, originalErr.getClass() + ": ");
            newFailure = new UnexpectedError(description.toString(), originalErr.getCause());
        }
        newFailure.setStackTrace(originalErr.getStackTrace());
        return newFailure;
    }

    protected BrowserType getBrowserType() {
        return currentBrowserType;
    }

    /**
     * Find all the browsers the current test case should be executed in. Test cases can be annotated with multiple
     * target browsers. If the testcase does not have an annotation, the class level annotation is used.
     *
     * @return
     * @throws NoSuchMethodException
     */
    public Set<BrowserType> getTargetBrowsers() {
        TargetBrowsers targetBrowsers = null;
        try {
            Method method = getClass().getMethod(getName());
            targetBrowsers = method.getAnnotation(TargetBrowsers.class);
            if (targetBrowsers == null) {
                // Inherit defaults from the test class
                targetBrowsers = getClass().getAnnotation(TargetBrowsers.class);
            }
        } catch (NoSuchMethodException e) {
            // Do nothing
        }
        if (targetBrowsers == null) {
            // If no target browsers are specified, default to ALL
            return EnumSet.allOf(BrowserType.class);
        }
        return Sets.newEnumSet(Arrays.asList(targetBrowsers.value()), BrowserType.class);
    }

    /**
     * Browser types to be excluded for this testcase or test class.
     *
     * @return
     * @throws NoSuchMethodException
     */
    public Set<BrowserType> getExcludedBrowsers() {
        ExcludeBrowsers excludeBrowsers = null;
        try {
            Method method = getClass().getMethod(getName());
            excludeBrowsers = method.getAnnotation(ExcludeBrowsers.class);
            if (excludeBrowsers == null) {
                // Inherit defaults from the test class
                excludeBrowsers = getClass().getAnnotation(ExcludeBrowsers.class);
            }
        } catch (NoSuchMethodException e) {
            // Do nothing
        }
        if (excludeBrowsers == null) {
            return EnumSet.noneOf(BrowserType.class);
        }
        return Sets.newEnumSet(Arrays.asList(excludeBrowsers.value()), BrowserType.class);
    }

    public boolean isAccessibilityTestDisabled() {
        CheckAccessibility checkAccessibility = null;
        try {
            Method method = getClass().getMethod(getName());
            checkAccessibility = method.getAnnotation(CheckAccessibility.class);
            if (checkAccessibility == null) {
                // Inherit defaults from the test class
                checkAccessibility = getClass().getAnnotation(CheckAccessibility.class);
            }
        } catch (NoSuchMethodException e) {
            // Do nothing
        }
        return checkAccessibility != null ? !checkAccessibility.value() : false;
    }

    public WebDriver getDriver() {
        if (currentDriver == null) {
            WebDriverProvider provider = ServiceLocator.get().get(WebDriverProvider.class);
            DesiredCapabilities capabilities;
            if (SauceUtil.areTestsRunningOnSauce()) {
                capabilities = SauceUtil.getCapabilities(currentBrowserType, this);
            } else {
                capabilities = currentBrowserType.getCapability();
            }

            capabilities.setCapability(WebDriverProvider.REUSE_BROWSER_PROPERTY, !needsFreshBrowser());

            /*
             * Dimension windowSize = getWindowSize(); if (currentBrowserType == BrowserType.GOOGLECHROME) {
             * WebDriverUtil.addChromeOptions(capabilities, windowSize); }
             */

            logger.info(String.format("Requesting: %s", capabilities));
            if(currentBrowserType == BrowserType.GOOGLECHROME) {
                boolean runHeadless = Boolean.parseBoolean(System.getProperty(WebDriverProvider.BROWSER_RUN_HEADLESS_PROPERTY));
                WebDriverUtil.addChromeOptions(capabilities, null, runHeadless);
            }

            currentDriver = provider.get(capabilities);

            if (currentDriver == null) {
                fail("Failed to get webdriver for " + currentBrowserType);
            }

            /*
             * if (windowSize != null) { currentDriver.manage().window().setSize(windowSize); }
             */

            String driverInfo = "Received: " + currentDriver;
            if (SauceUtil.areTestsRunningOnSauce()) {
                driverInfo += "\n      running in SauceLabs at " + SauceUtil.getLinkToPublicJobInSauce(currentDriver);
            }
            logger.info(driverInfo);

            auraUITestingUtil = new AuraUITestingUtil(currentDriver);
            auraUITestingUtil.setTimeoutInSecs(Integer.parseInt(System.getProperty("webdriver.timeout", "30")));
        }
        return currentDriver;
    }

    public AuraUITestingUtil getAuraUITestingUtil() {
        if(auraUITestingUtil == null){
            auraUITestingUtil = new AuraUITestingUtil(getDriver());
            auraUITestingUtil.setTimeoutInSecs(Integer.parseInt(System.getProperty("webdriver.timeout", "30")));
        }
        return auraUITestingUtil;
    }

    /**
     * @return non-null to specify a desired window size to be set when a new driver is created
     */
    protected Dimension getWindowSize() {
        return null;
    }

    public final void quitDriver() {
        if (currentDriver != null) {
            try {
                currentDriver.quit();
            } catch (Exception e) {
                Log.getLogger(getClass()).warn(currentDriver.toString(), e);
            }
            currentDriver = null;
            auraUITestingUtil = null;
        }
    }

    protected URI getAbsoluteURI(String url) throws Exception {
        return getTestServletConfig().getBaseUrl().toURI().resolve(url);
    }

    /**
     * Append a query param to avoid possible browser caching of pages
     */
    public String addBrowserNonce(String url) {
        if (!url.startsWith("about:blank")) {
            Map<String, String> params = new HashMap<>();
            params.put("browser.nonce", String.valueOf(System.currentTimeMillis()));
            url = addUrlParams(url, params);
        }
        return url;
    }

    /**
     * Add additional parameters to the URL. These paremeters will be added after the query string, and before a hash
     * (if present).
     */
    public String addUrlParams(String url, Map<String, String> params) {
        // save any fragment
        int hashLoc = url.indexOf('#');
        String hash = "";
        if (hashLoc >= 0) {
            hash = url.substring(hashLoc);
            url = url.substring(0, hashLoc);
        }

        // strip query string
        int qLoc = url.indexOf('?');
        String qs = "";
        if (qLoc >= 0) {
            qs = url.substring(qLoc + 1);
            url = url.substring(0, qLoc);
        }

        // add any additional params
        List<NameValuePair> newParams = Lists.newArrayList();
        URLEncodedUtils.parse(newParams, new Scanner(qs), "UTF-8");
        for (String key : params.keySet()) {
            newParams.add(new BasicNameValuePair(key, params.get(key)));
        }

        return url + "?" + URLEncodedUtils.format(newParams, "UTF-8") + hash;
    }

    /**
     * Open a URI without any additional handling. This will, however, add a nonce to the URL to prevent caching of the
     * page.
     */
    protected void openRaw(URI uri) {
        String url = addBrowserNonce(uri.toString());
        getDriver().get(url);
    }

    /**
     * Open a URI without any additional handling. This will, however, add a nonce to the URL to prevent caching of the
     * page.
     */
    protected void openRaw(String url) throws Exception {
        openRaw(getAbsoluteURI(url));
    }

    /**
     * Open a url without any additional handling, not even a browser.nonce
     */
    protected void openTotallyRaw(String url) throws Exception {
        getDriver().get(getAbsoluteURI(url).toString());
    }

    /**
     * Open a URL without the usual waitForAuraInit().
     */
    protected void openNoAura(String url) throws Exception {
        open(url, getAuraModeForCurrentBrowser(), false);
    }

    /**
     * Open a Aura URL with the default mode provided by {@link WebDriverTestCase#getAuraModeForCurrentBrowser()} and
     * wait for intialization as defined by {@link AuraUITestingUtil#waitForAuraInit()}.
     *
     * @throws MalformedURLException
     * @throws URISyntaxException
     */
    protected void open(String url) throws Exception {
        open(url, getAuraModeForCurrentBrowser(), true);
    }

    /**
     * Return the Mode for web-driver test.
     */
    public Mode getAuraModeForCurrentBrowser() {
        return Mode.SELENIUM;
    }

    public void open(DefDescriptor<? extends BaseComponentDef> dd) throws Exception {
        open(getUrl(dd));
    }

    /**
     * Open a Aura URL in given aura.mode and wait for initialization.
     *
     * @throws MalformedURLException
     * @throws URISyntaxException
     */
    protected void open(String url, Mode mode) throws Exception {
        open(url, mode, true);
    }

    protected void open(String url, Mode mode, boolean waitForInit) throws Exception {
        Map<String, String> params = new HashMap<>();
        params.put("aura.mode", mode.name());
        params.put("aura.test", getQualifiedName());
        url = addUrlParams(url, params);
        getAuraUITestingUtil().getRawEval("document._waitingForReload = true;");
        try {
            openAndWait(url, waitForInit);
        } catch (TimeoutException e) {
            // Hack to avoid timeout issue for IE8. Appears that tests fail for the first time when we run the
            // test in new vm session on Sauce.
            if (currentBrowserType == BrowserType.IE8) {
                openAndWait(url, waitForInit);
            } else {
                throw e;
            }
        }
    }

    private void openAndWait(String url, boolean waitForInit) throws Exception {
        getAuraUITestingUtil().getRawEval("document._waitingForReload = true;");
        openRaw(url);
        getAuraUITestingUtil().waitUntil((ExpectedCondition<Boolean>) d -> {
            Object ret = getAuraUITestingUtil().getRawEval("return !document._waitingForReload");
            if (ret != null && ((Boolean) ret).booleanValue()) {
                return true;
            }
            return false;
        }, getAuraUITestingUtil().getTimeout(), "fail on loading url:" + url);

        if (waitForInit) {
            getAuraUITestingUtil().waitForAuraInit(getAuraErrorsExpectedDuringInit());
        }
    }

    protected Set<String> getAuraErrorsExpectedDuringInit() {
        return Collections.emptySet();
    }

    /**
     * Wait the specified number of seconds for the provided javascript to evaluate to true.
     *
     * @throws AssertionFailedError if the provided javascript does not return a boolean.
     */
    public void waitForCondition(final String javascript, int timeoutInSecs) {
        getAuraUITestingUtil().waitUntil((ExpectedCondition<Boolean>) d -> getAuraUITestingUtil().getBooleanEval(javascript), timeoutInSecs, "fail on waiting for condition:" + javascript);
    }

    /**
     * Wait for the provided javascript to evaluate to true. Make sure script has return statement.
     */
    public void waitForCondition(final String javascript) {
        waitForCondition(javascript, getAuraUITestingUtil().getTimeout());
    }

    /**
     * Wait for a specified amount of time.
     */
    public void waitFor(long timeoutInSeconds) {
        WebDriverWait wait = new WebDriverWait(getDriver(), timeoutInSeconds);
        try {
            wait.until((ExpectedCondition<Boolean>) d -> false);
        } catch (TimeoutException expected) {
            return;
        }
    }

    /**
     * Find first matching element in the DOM.
     */
    protected WebElement findDomElement(By locator) {
        return getAuraUITestingUtil().findDomElement(locator);
    }

    /**
     * Find list of matching element in the DOM.
     */
    protected List<WebElement> findDomElements(By locator) {
        return getAuraUITestingUtil().findDomElements(locator);
    }

    /**
     * Return true if there is at least one element matching the locator.
     */
    public boolean isElementPresent(By locator) {
        return getDriver().findElements(locator).size() > 0;
    }

    /**
     * Gets the visible text for the first element matching the locator.
     */
    protected String getText(By locator) {
        return findDomElement(locator).getText();
    }

    public Action shiftTab() {
        Actions builder = new Actions(getDriver());
        builder.keyDown(Keys.SHIFT)
                .sendKeys(Keys.TAB)
                .keyUp(Keys.SHIFT);
        return builder.build();
    }

    /**
     * Flick starting at on_element, and moving by the xoffset and yoffset with normal speed
     *
     * @param locator
     * @param xOffset
     * @param yOffset
     */
    public void flick(By locator, int xOffset, int yOffset) {
        getAuraUITestingUtil().waitForElement("Cannot locate element to flick: " + locator, locator);
        WebElement element = getAuraUITestingUtil().findDomElement(locator);
        flick(element, xOffset, yOffset, FlickAction.SPEED_NORMAL);
    }

    public void flick(WebElement element, int xOffset, int yOffset) {
        // FlickAction.SPEED_FAST is too slow for the tests so changing it to 200
        flick(element, xOffset, yOffset, 200);
    }

    public void flick(WebElement element, int xOffset, int yOffset, int speed) {
        WebDriver driver = getDriver();
        // check for wrapped driver
        if (driver instanceof EventFiringWebDriver) {
            driver = ((EventFiringWebDriver) driver).getWrappedDriver();
        }
        driver = augmentDriver();
        // for iPhone
        int yOffsetByDevice = yOffset;

        if (this.getBrowserType() == BrowserType.IPAD) {
            yOffsetByDevice = yOffset * 2;
        }
        if (driver instanceof HasTouchScreen) {
            Action flick = (new TouchActions(driver)).flick(element, xOffset, yOffsetByDevice, speed).build();
            flick.perform();
        } else {
            Action flick = (new Actions(driver)).dragAndDropBy(element, xOffset, yOffsetByDevice).build();
            flick.perform();
        }
    }

    public void flick(int xOffset, int yOffset) {
        WebDriver driver = getDriver();
        driver = augmentDriver();
        // for iPhone
        int yOffsetByDevice = yOffset;

        if (this.getBrowserType() == BrowserType.IPAD) {
            yOffsetByDevice = yOffset * 2;
        }

        Action flick = (new TouchActions(driver)).flick(xOffset, yOffsetByDevice).build();
        flick.perform();
    }

    private RemoteIOSDriver augmentDriver() {
        RemoteIOSDriver driver = IOSDriverAugmenter.getIOSDriver((RemoteWebDriver) getDriver());
        return driver;
    }

    protected void assertClassesSame(String message, String expected, String actual) {
        getAuraUITestingUtil().assertClassesSame(message, expected, actual);
    }

    @Override
    public void runBare() throws Throwable {
        establishSpringContext();
        injectBeans();
        logger.info(String.format("Running: %s.%s", getClass().getName(), getName()));
        runTest();
    }

    /**
     * Returns the shadowRoot property of a given element. This is a necessary prerequisite to query for items inside
     * an elements Shadow DOM.
     *
     * @param element the WebElement to retrieve the shadowRoot property of.
     * @return        the shadowRoot DOM subtree of a given WebElement.
     */
    public WebElement getShadowRoot(WebElement element) {
        return (WebElement) ((JavascriptExecutor)getDriver()).executeScript("return arguments[0].shadowRoot", element);
    }

    /**
     * Returns an element inside of a Shadow DOM. The list of passed in selectors will be iterated over and at each
     * element found, the shadowRoot property will be expanded before doing the next query.
     *
     * @param selectors an array of By selectors where each selector besides the final one is a shadow boundary.
     * @return          an element inside a Shadow DOM or null if none is found.
     */
    public WebElement findElementInShadowDom(By[] selectors) {
        WebElement curr = null;
        for (int i = 0; i < selectors.length; i++) {
            if (curr == null) {
                curr = findDomElement(selectors[i]);
            } else {
                curr = curr.findElement(selectors[i]);
            }
            if (i != selectors.length-1) {
                curr = getShadowRoot(curr);
            }
        }
        return curr;
    }
}

redpajama_set_name: RedPajamaGithub


text:
Oscars 2017: Academy Awards host Jimmy Kimmel leads Hollywood's attack on Donald Trump's politics
Oscars 2017: Academy Awards host Jimmy Kimmel leads Hollywood's attack on Donald Trump's politics
The 89th Academy Awards kickstarted with a bang with the host Jimmy Kimmel taking a fresh jibe at US President Donald Trump during the Oscars 2017 ceremony.
Fukres
The 89th Academy Awards kickstarted with a bang with the host Jimmy Kimmel taking a fresh jibe at US President Donald Trump. After finishing his flawless rendition of the song Can't Stop The Feeling from Trolls, Justin Timberlake called upon Kimmel.
The 49-year-old comedian and talk show host didn't miss the glorious opportunity to attack his newest President, a Hollywood trend nowadays. "I want to say thank you to President Trump," Kimmel said. He added, "I mean, remember last year when it seemed the Oscars were racist?"
Popular comedian and talk show host Jimmy Kimmel is hosting the 89th Annual Academy Awards. (Courtesy: Reuters)
Kimmel was referencing to last year's controversy which triggered one April Reign to create the hashtag #OscarsSoWhite, which has literally been trending ever since the nominations got announced. However, this year, the Academy's picks have been more racially diverse with films like Fences, Hidden Figures, Moonlight and the inexistent "Hidden Fences" coming to light. All three movies are up for the Best Picture with Moonlight standing out as the most prospective winner of the coveted award.
US President Donald Trump is a common target at awards ceremonies nowadays. Earlier, stars have taken sharp blows at the President at Grammys, BRITs, BAFTAs and the Golden Globes.
Kimmel went on to say, "Black people saved NASA and white people saved jazz. That's progress," while referencing to both Hidden Figures and La La Land.
"The country is divided right now. I've been getting a lot of advice, it's time to bring people together. There's only one Braveheart in this room, and he's not going to unite us either," he said as he pointed out to Mel Gibson sitting in the audience. "You look great, Mel – I think the Scientology is really working."
"The #Oscars are about the movies and you can't have movies without movie candy, it's un-American." – Jimmy #Kimmel #Oscars pic.twitter.com/YH5lMuyF1I
— Jimmy Kimmel Live (@JimmyKimmelLive) February 27, 2017

redpajama_set_name: RedPajamaCommonCrawl


text:
Over 180 years ago Charles TANQUERAY was on a mission to create the world's finest gin. He set up his distillery in Bloomsbury, London in 1830 and, after years of experimentation and searching for the finest ingredients, TANQUERAY London Dry was born. Since then, TANQUERAY has continued to be driven by Charles' spirit of exploration and innovation and we now have a portfolio including TANQUERAY NºTEN, TANQUERAY Rangpur, TANQUERAY Malacca, TANQUERAY Flor de Sevilla and limited editions inspired by Charles' recipes.
It is this rich heritage, ingenuity and superior quality and taste that has led to TANQUERAY winning numerous prestigious awards, including being named the bartenders favourite gin in Drinks International Brands Report 2018.
TANQUERAY LONDON DRY
It has 4 Perfectly Balanced Botanicals.
Tanqueray – a perfect balance of four botanicals, ingredients that remain unchanged since they were first used by Charles Tanqueray in 1830.
Perfection is simple. Juniper, Angelica, Liquorice and Coriander is all it takes. It's no wonder why Tanqueray is Voted the Bartender's choice for the perfect T&T.
TANQUERAY No. TEN
– Fresh Citrus Heart Gin, Small Batch distilled
The fresh citrus heart gin, Tanqueray No. TEN is a small batch gin – the first ever to be distilled with whole, fresh citrus fruits instead of the rinds alone, which gives the gin its citrus heart and brings out more flavour in your cocktails.
It's no wonder why Tanqueray No. TEN is the first white spirit to be inducted into the San Francisco World Spirits Hall of Fame.
Additional information about the TANQUERAY brand can be found at http://www.TANQUERAY.com.
Introducing John Dewar and Sons Fine Whisky Emporium


For thousands of years, men and women of all countries and races have shared the tragedy of pre-mature hair loss.
The reason for hair loss is a subject that no two doctors, seem to agree on and everyone seems to have their own opinion on the subject. The major causes of hairfall are hormonal, nutritional deficiencies and complication to other diseases and medications. Hormone related hair fall may also result from an increased sensitivity of hair follicles to male hormones or due to greater number of male hormone receptors attached to hair follicles. This is the component that is inherited through the genes — termed as Pitta constitution.


Joan Rivers' death probed by NYS Department of Health What prompted such a swift investigation by the NYS Department of Health? In 'ordinary' wrongful death cases, the DOH investigation takes many months. Not here.
NY Attorney Helps Injured Victims Understand How Cases Work You've got a legal problem. Where do you get information about your legal problem? Wouldn't it be cool to have a book telling you from the inside how it works?
Most American Teens Lack Being Physically Fit Recent studies have shown that a good number of teenagers are overweight and not physically fit. Why is that? Is it bad eating habits? Is it lack of motivation?
How Healthy is the Food in your Fridge? Food warning labels, the American diet and Doctors arguments, whats the story on junk food? NY Medical Malpractice Attorney shares the Time Magazine report.
Do You Know How Much Sugar is in Your Kids' Cereals? Shocking new information revealed about level of sugar in children's cereals. NY Lawyer shares CBS News report of latest nutrition results among Americans.
$100 Million Dollar Settlement to Meningitis Victims New York Medical Malpractice Attorney shares news. Meningitis victims successfully settle their lawsuit. One hundred million dollar settlement fund created.
Pfizer Recalls Antidepressant Effexor NY Lawyer shares recall notice of Pfizer drug Effexor XR antidepressant and it's generic counterpart due to reports of finding wrong drugs in packaged bottles.
Something Fishy Going on in NYC's Chinatown Markets New York City's Chinese seafood markets apparently carrying fish and seafood related items that are causing skin infections. Great Neck Lawyer shares report.


text:
Showing results by narrator "John Barrowman" in All Categories
Torchwood: The Collected Radio Dramas
Seven BBC Radio 4 Full-Cast Dramas
By: James Goss, Joseph Lidster, Rupert Laight
Narrated by: John Barrowman, Gareth David-Lloyd, full cast, and others
John Barrowman, Eve Myles and Gareth David-Lloyd star in seven full-cast BBC Radio 4 dramas based on the hit BBC TV series. In "Lost Souls" by Joseph Lidster, voices from the past are calling out from the Large Hadron Collider at CERN, and scientists are disappearing. Can Torchwood help? 'Asylum' by Anita Sullivan sees PC Andy Davidson turn to Torchwood after he arrests a very unusual shoplifter. 'Golden Age' by James Goss finds the team in Delhi, on the trail of a dangerous energy field.
Outside the government, beyond the police.
By Nigel on 09-06-17
Narrated by: John Barrowman, Gareth David-Lloyd, full cast, Eve Myles
By: Peter Anghelides
Narrated by: John Barrowman
A storm is brewing: the water levels of the Bristol Channel are inexplicably rising, and Cardiff Bay is under threat from the worst flooding in years. In the midst of the climate chaos, Torchwood is called to investigate a series of gruesome murders.
Classic Torchwood
By Mr M Eliff on 05-08-16
4 out of 5 stars 51 ratings
Torchwood: Golden Age
By: James Goss
Narrated by: John Barrowman, Eve Myles, Gareth David-Lloyd
On the trail of a dangerous energy field, Torchwood are led to Delhi. There they witness the simultaneous disappearance of hundreds of people, and Jack discovers that the field centres on an old colonial mansion - Torchwood India. Jack is shocked to find that Torchwood India is still going strong - he shut it down himself over 80 years ago. He's even more surprised to find that its members, including his old flame the Duchess, haven't aged a day.
By Emily on 16-11-17
By: Anita Sullivan
When PC Andy Davidson arrests a young girl for shoplifting, he thinks it's going to be a routine case. That is, until he sees that she is carrying a gun. The girl is soaking wet, covered in mud, and the weapon is like nothing he's ever seen before. He knows that this is a case for Torchwood...
Torchwood at its best.
By Alan on 16-08-16
Lost Souls (Dramatised)
By: Joseph Lidster
Narrated by: John Barrowman, Eve Myles, Gareth David-Lloyd, and others
Martha Jones, ex-time traveller, has been called to CERN, the world¿s largest particle physics laboratory in Geneva. They¿re about to activate the Large Hadron Collider, designed to recreate conditions after the Big Bang and thus give an insight into what the Universe is made of. But so much could go wrong: it could open a gateway to a parallel dimension, or even create a black hole.
Torchwood The lost souls
By stargirl on 07-07-17
Narrated by: John Barrowman, Eve Myles, Gareth David-Lloyd, Freema Agyeman
Bone Quill
By: John Barrowman
Narrated by: John Barrowman, Carol E. Barrowman
Twelve-year-old twins Matt and Emily Calder are Animare: they can bring art to life and enter paintings at will. They must do everything in their power to prevent a breach in Hollow Earth: a supernatural place that holds all the demons, devils and creatures ever imagined. The Hollow Earth Society are getting closer to finding the key that will release the beasts: an ancient bone quill whose powers can be only be used by a powerful Animare.
Story gets better and better
By EC W on 23-02-18
Torchwood: The Dead Line
By: Phil Ford
When a Cardiff hospital is inundated with patients that have fallen into coma-like trances, Torchwood move in to investigate. They find that the trances were triggered by phone calls, all of which were made from a number that hadn't been active for over 30 years. Determined to find out who's been calling the unfortunate victims, Jack rings the mysterious number - two, zero, five, nine - nothing. It's a dead line. Until it calls Jack back, he answers - and falls into a deep trance...
Good story
By Mr Paul Eyre on 03-01-15
By: John Barrowman, Carole E. Barrowman
Twins Matt and Emily Calder have imaginations so powerful that they can make art come to life. Their powers are sought by villains intent on accessing the terrors of Hollow Earth - a place where all the devils, demons, and monsters ever imagined lie trapped for all eternity. If Hollow Earth is breached, the world will be plunged into chaos. If Hollow Earth is breached... the twins are as good as dead.
By Rose on 13-04-13


Pro Float Inc | Do I Want Different Types of Float Tanks?
Do I Want Different Types of Float Tanks?
10 May Do I Want Different Types of Float Tanks?
Deciding on the details of your brand-new float centre is no easy feat. There are many intricacies that don't start to fall into place until you're facing the issue head-on. Determining how many tanks you need and what type of tanks are best suited to your potential client base are both big questions people often forget to ask themselves before choosing a space. However, the answers to these questions are incredibly important to figure out how much space you'll actually need and the type of renovations you'll have to make to accommodate your float tanks.
Also, have you considered the possibility of maintaining different types of tanks in the same space? Offering a variety of solutions (like pods, tanks, cabins and rooms) may be the best fit for your potential clients. However, this could also pose some technical and financial problems, from both a business and facilities standpoint.
Here are some pros and cons of housing different float solutions in the same centre.
Has there really ever been a time you didn't enjoy being given a choice in regards to a service? With massages, it's often Swedish, hot stone, full-body, back-only, among others. Or maybe you've signed up for a yoga class and the choices are endless: Bikram, Ashtanga, Hatha, Yin, etc.
Generally, when you provide a service, it's imperative you develop different styles or options to suit different lifestyles, personalities, and physical differences.
It's no different with a sensory deprivation tank. First-time floaters and tank veterans alike may all decide they'd like to try something new. In this case, offering different solutions may work to your benefit. You'll acquire new clients (by solving common newbie issues like fear of tight spaces) and retain existing clientele who are hoping to upgrade or change up their usual tank.
Pods, tanks, cabins, and rooms all require different parts to start with and different spares for back-up. Sometimes, suppliers will give you discounts if you buy their solution in bulk (a few at a time), which usually leaves you spending less money but for less variety.
If you have a few different tank styles, chances are a first-timer who expressed they didn't enjoy their session can still be converted. Offer to book them in for a different solution and it's likely they'll come back and love it, especially since the more you float, the easier it becomes to settle into your float. Having more than one tank-style allows unsure customers the ability to test out a different solution. It also gives them more reason to try it again and thoroughly enjoy the float as a slightly more experienced floater. The more options, the more repeat clients you can expect to show up, try, and fall in love with floating.
CON: The Science Behind Owning Different Solutions Can Get Tricky.
Don't forget, each tank has its own appropriate fill level, salt level and necessary pH values that can take ages to perfect. In reality, it may be easier in the long-run to operate all the same tank solutions. Your treatments and testing will be similar across the board, leaving less room for errors.
Bottom line: you know yourself, your limits, your budget, and your customers. Choose the solutions you deem the best for your potential client base and what you really think you can manage.
No matter your floating question, Pro Float Inc. has you covered. Contact us today for more info on opening a float centre.


text:
Q: Data of Message app in IOS I am developing a messaging app for IOS. So, for this I want to access and modify messages from the default message app in IOS.
So, how can I access the data of message app like we access photos and contacts?
Thank You

A: You Cannot access messages from the default messages App. This is not privileged for developers by Apple.
For more information check this link :
http://developer.apple.com/library/ios/#documentation/UserExperience/Conceptual/SystemMessaging_TopicsForIOS/Articles/SendinganSMSMessage.html#//apple_ref/doc/uid/TP40010416-SW1

redpajama_set_name: RedPajamaStackExchange


Growing up, I thought I knew everything. I attacked the world in a way that only a child can and made choices that were less than ideal. I shrugged off advice and lived by the thought that it was my way or the highway. Yes, I was your typical teen who ignored most words of wisdom.
However, I was smart enough to take one piece of advice from my mom to heart. You see, when I was just 13 years old, she sat me down and explained to me the importance of skin care and protecting my skin. Now I'm not sure I really "got" it way back then but something about what she told me just stuck. Her words echoed through my head each morning as I hopped out of bed and prepared for the day. And with her wisdom, I developed a skin care routine that has helped me keep youthful looking skin into my mid-30's.
Looking at my mom now, I know I was wise indeed to heed her advice regarding skin care. At almost 70 (sorry mom!) she is stunning. Radiant. And pretty much the poster child for how every woman wants to look as she ages.
And for the first time ever, I'm going to share her wisdom with you in the hopes that where ever you are in your skin care routine, her tips can help you age gracefully and keep your skin glowing! So are you ready? I hope so because I'm ready to tell you all about my daily skin care routine for younger looking skin! Let's get started!
I learned early on that if I want younger looking skin, water is my friend! Drinking eight glasses of water a day has just become part of my routine and I can tell a big difference when I don't do it. Keeping hydrated keeps my skin looking bright and young, not to mention skin that is moist is less likely to look wrinkled! In fact, I've gotten so into the habit of having water with me that no matter where I go, my water bottle comes along. I truly think that this has helped me keep great looking skin over the years.
This may be the one rule that I broke a time or two in college but it's so important. Being a good Southern girl, my mama taught me to "put on my face" every morning. But even more importantly she taught me to take it off at night. Just that one simple step of keeping my skin clean while I sleep has played an important role in my skin care routine throughout the years. And while I may neglect some of my daily responsibilities in favor of sleep, cleaning my face thoroughly is not one of them!
Speaking of sleep….As a mother this has been one of the areas that I struggle with the most. Getting plenty of sleep may not sound like part or your skin care routing but it totally is! Sleep is the time when your cells regenerate and heal themselves so ensuring you get eight hours a night is a great way to make your skin look and feel fresher! And while eight full hours may be a stretch for most moms, I do ensure that getting sleep is a priority in my daily skin care routine!
While all the other tips I learned from my mama were important, the single best advice she ever gave me was to choose carefully when it came to my skin care products. Over the years, I've seen her try many a moisturizer to keep her skin looking young. She's never been afraid to see what is out there and discover what works best for her. Knowing that trial and error has been an essential part of her skin care routine, I am always on the look out for products that work better for me.
So recently when I discovered NO-AD Prevent & Repair and NO-AD Prevent & Brighten in the lotion aisle at Walmart, I was anxious to give it a try! Available in both 6.5 oz Spray and 12 oz Pump Lotion options, this affordable whole body moisturizer is a multi-functional beauty product that has SPF protection to help in achieving beautiful skin!
But that's just the start! This one easy to use product is perfect for your entire body and helps to beautify and moisturize your skin, all while helping to prevent aging! And with it's SPF component, it goes beyond simply moisturizing to ensure that you're protecting, repairing and all around loving the skin you're in!
No matter how busy my days get, NO-AD Anti-Aging Body Moisturizer's premium blend of vitamins, antioxidants and SPF 15 broad spectrum protection are easy to work into my routine! With a pump option that's perfect for when I need extra moisture or have a little more time, I'm ensured that from head to toe my skin will get the moisture it needs to prevent aging caused by cumulative daily sun damage!
And when time is tight and I'm running out the door, all it takes is a spray of NO-AD Anti-Aging Body Moisturizer and instantly my skin feels soft, smooth and protected in a way that I didn't know was possible!
So now that I am older, I'm so thankful that I've taken care of my skin over the years. But I'm even more thankful that I've discovered an easy skin care secret to improve my daily routine! I'm also more determined than ever to use NO-AD Anti-Aging Body Moisturizers daily to keep my skin looking great. Because you see, while it was super important for me to have an effective skin care routine when I was younger, now it's just down right essential.
But do you know what is even better? While NO-AD Anti-Aging Body Moisturizers fit perfectly into the tips my mama taught me, I'm the one being able to share this skin care secret with her! Because while she showed me that sometimes you find a product that works best in the last place you would have expected, I showed her that it doesn't take a million products (or a million bucks) to truly treat your skin! So instead of having tons of bottles that each target a different part of my body, I'm trusting ALL of my skin to the healing and protecting power of NO-AD!
So, are my mama's skin care tips working? Well, I'd like to think so! With her wisdom and NO-AD Anti Aging Body Moisturizers, I have to say that my mid-30's are looking pretty good! And I can only hope that by incorporating these tips into my daily life, I'll have radiant, glowing skin for years go come!
Are you ready to discover the secret to beautiful skin everyday? If so, click here to find a Walmart near you that carries NO-AD Anti-Aging Body Moisturizers. But wait! Once you're ensured that NO-AD is sold at a Walmart near you, grab a coupon to get yours for less! You can save $2.00 on any one (1) NO-AD Anti-Aging Body Moisturizer Pump Lotion or Spray Lotion! That's a 40% discount off the 12 ounce pump lotion and a 33% discount off the 6.5 ounce spray lotion! That makes this already incredibly affordable way to get gorgeous skin a total steal! So don't wait! Print your coupon and head to Walmart so you can start caring for your skin with NO-AD today!
Tell me, what does your skin care routine look like?
This seems like an interesting set of products.I am only 28 so I don't need to buy these, but I do know of some people that could benefit from using it.
Alicia recently posted..#Disney – Marvel's AVENGERS: Age of Ultron – New Spot NOW Available!!
Oh girl! I started using anti-aging when I was in my early 20's! Preventative care is where it's at!
I'm pretty good with implementing most of the tips you share and so far so good. My good genes have also been good to me!
Oh my lord, I cannot believe your mother is almost 70. She is so beautiful and youthful.
I love all your tips. My number one challenge is drinking plenty of water. But I know it will help. I have not seen NoAd moisturizers before, but will have to look for them next time I head out for lotion.
Although I seriously hate to admit it, my skin is starting to show signs of aging. I have these pesky little laugh lines that I would love to see GONE!
You and your mom are gorgeous! And these are really great tips. The water tips is so important and I am SO bad at it. I've been looking at those No-Ad products. Since making it over 40 eek! I'm definitely seeing more signs of aging.
I haven't seen this brand before! I love that it's under $5! Thanks! I need to grab a spray version!
You and your mom are beautiful 🙂 I've never seen this brand before but I agree with all your tips.. Water is my best friend for sure! I start my day with a glass and end my day with one and drink about 2 liters in between.. I also notice a huge difference in my skin when I don't get enough rest….
She's stunning (it must be genetic)! I try to follow these rules, but a little reminder is always appreciated. I know I could do a little more to ensure my skin's appearance a little longer.
She looks reallly good. I think this is the perfect time of year to show these products. I have little knowledge on proper skin treatments, and I found this very informative. Thank you for sharing this bit of information with us.
I am lucky to have fairly young looking skin for being over 50. Your tips will help me continue to have younger looking skin, especially with the NO AD products.
My skin is dry and dull. I could definitely use these to perk my skin up and look better.
I never used products on my skin to keep it moisturized until the last few years. I'm so bad! Now I can't imagine going without moisturizer, and the water does help a ton!
That was a great lesson to have take. 🙂 You both look great. My SIL has always taken excellent care of her skin and she looks younger than the rest of us who are her age. There's def. some merit to it.
2 years into my 30's and I've really noticed the aging process has begun, especially on my face. My biggest problem is of course sun damage because I don't put anything with an SPF on my face. My oily skin just sheds lotions and my face ends up a mess.
What a great line! I used to use No-Ad, but now that they have some anti-aging, I think I am going to revisit them again this summer!
Drinking enough water is also something that's neglected! Both of you look great!
We always used No-Ad growing up! Nice to see they have expanded their product line.
I have been one that learned early to drink lots of water every day too. I also try to use other beauty products to keep my skin looking younger.


text:
Q: How can I write a cloud functions onUpdate Firestore to get values from a collection on update of another collection I have a collection of orders mapped for a user. Which is in users/{userID}/orders/{orderID}) format. I need a function which onUpdate to this document sends a notification to an array of tokens saved in users/{userID}/tokens
exports.modifyUserCart = functions.firestore
    .document('users/{userID}/orders/{orderID}')
    .onUpdate((change, context) => {

    const document = change.after.exists ? change.after.data() : null;

    console.log(document.order_id)

    // document.order_id . "This prints correctly"

    // The tokens to be added to an array are in (users/{userID}/tokens). How
    // do I get the tokens from the collection of tokens

    var tokens = [] //array of tokens

    var message = {
        notification: {
            title: 'Get an upfront discount',
            body: "Clear your items in cart in the next hour to get an upfront
                discount of $100"
        },
        token: tokens
    };

    admin
      .messaging()
      .send(message)
      .then((response) => {
          // Response is a message ID string.
          console.log('Successfully sent message:', response);
      })
      .catch((error) => {
          console.log('Error sending message:', error);
      });
      // perform desired operations ...
});

A: I did a firestore database with the same architecture as yours:

users/{userID}/orders/{orderID} and users/{userID}/tokens/{tokenID}
The event I used to trigger the app is:
providers/cloud.firestore/eventTypes/document.update on the resource: users/{userID}/orders/{orderID}
this allowed me that the function executed when there was an update on any document in orders collections.
The sourcecode is in three files:
credentials.json: which is the login info for the service account that will interact with firestore in the second part. to get this file for your own projec you can follow here
package.json:
{
  "name": "sample-firestore",
  "version": "0.0.1",
  "dependencies": {
    "@google-cloud/firestore": "^2.6.1",
    "firebase-admin": "^8.8.0"
  }

}

index.js:
/**
 * Triggered by a change to a Firestore document.
 *
 * @param {!Object} event Event payload.
 * @param {!Object} context Metadata for the event.
 */
exports.helloFirestore = (event, context) => {
  const resource = context.resource;
  // log out the resource string that triggered the function
  console.log('Function triggered by change to: ' +  resource);
  // now log the full event object
  console.log(JSON.stringify(event));
  console.log("Doc Modified");
  const document = event.value.name;
  console.log(document);
  //ended know which document was modified

  //starting GET second collection

  const Firestore = require('@google-cloud/firestore');

  const db = new Firestore({
    projectId: '[YOUR_PROJECT_ID]',
    keyFilename: 'credential.json'
  });

  console.log(JSON.stringify(db));

  var str = document.split("/");
  console.log(str);
  console.log(str[6]);

  db.collection('users').doc(str[6]).collection('tokens').get()
  .then((snapshot) => {
    snapshot.forEach((doc) => {
      console.log(doc.id, '=>', doc.data());
    });
  })
  .catch((err) => {
    console.log('Error getting documents', err);
  });
};

this code in particular only logs the documents it gets to the console log, as an example of getting the documents if you want to perform other operations on the second part here are some code snippets of other operations.


View Bill's social profiles and photos on Facebook, MySpace, and +40 Networks.
"3835 matches for Bill Dealey. Find Bill Dealey's phone, address, etc. on Whitepages, the most trusted online directory."
Bill Dealey lives in Washington D.C. Metro and is a Developer and works for FreightDesk Technologies in the Computer Software industry.
Search results for Bill Dealey. 1. Bill Dealey Year of Birth: Heather Dealey · Bill Dealey ... Vienna, VA Herndon, VA Falls Church, VA ... Read more. 2.
Bill Dealey · Questions; Projects for which Bill Dealey is an ... Bill Dealey is not an answer contact for any project. Launchpad • Take the tour • Read the guide.
Marguerite Dealey, 96, a longtime Wautoma resident, ... Marguerite and Bill Dealey resided in Wautoma for many years and operated Dealey Oil Company.
View Bill Dealey's US census record to find family members, occupation details & more. Access is free so discover Bill Dealey's story today.
Full text of "IUP magazine"
Full text of "Brown alumni monthly"
· CNN LIVE EVENT/SPECIAL Punxsatawney Phil Proclaims Six More Weeks of Winter Remain Aired February 2, that's Bill Dealey that you see there.
Bill Dealey. Overview · Code; Bugs; Blueprints · Translations · Answers. Bugs related to Bill Dealey. Bill Dealey; Bugs. Search bugs related to Bill Dealey.
The guy holding him is Bill Dealey, the current pres of the Punxsutawney Groundhog Club, and the funeral director who buried my dad.
Bill Dealey. Overview · Code · Bugs ... Answered Solved Expired Invalid. No questions commented on by Bill Dealey found with the requested statuses.
People search: find Photos, Location, Education, Job!
Response to "Life expectancy of Catalytic converters"


text:
Q: What is the equivalent of Matlab's cwtft() in Python? (continuous morlet wavelet transform) I'm trying to implement a Morlet wavelet transform as matlab does, but I couldn't find any equivalent function in python. I want to implement it like this:
s0  = 6/fs;  % smallest scale
ds = 0.001; % spacing between scales
NbSc = 3000; % number of scales
SCA = {s0,ds,NbSc, 'lin'}; % specify scales
cwtstruct = cwtft({data, 1/fs},'scales',SCA);

and get the same outputs as Matlab's cwtstruct does.
I've already seen PyWavelets but it doesn't let you specify the scales in that way nor gives the same outputs.

A: Realize this is old, but in case you were wondering this should work or at least get you started.
I'm not sure what outputs in particular you're looking for, but Wxx is the scalogram (a 2D array in time-frequency space similar to a spectrogram).
If you're wanting the phase angle and modulus as shown in the Matlab help page, you might want to use the following wavelet : 'cmor30.0-60000.0'
Where the 30 is your desired bandwidth (think window width of a FFT) and 60000 is the central frequency of the wavelet.
import pywt
import numpy as np

fs=1e3
s0=6/fs
smax=3000
wave='morl'
scales=np.arange(s0,smax,1/fs)
Wxx,freq=pywt.cwt(data,scales,wave,sampling_period=1/fs)
freq=freq*fs


Let's start by redefining the term technical analysis. Technical analysis is the systematic evaluation of price, volume, breadth, and open interest, for the purpose of price forecasting. A systematic approach may simply use a bar chart and a ruler, or it may use all the calculation power available. Technical analysis may include any quantitative analysis as well as all forms of pattern recognition. Its objective is to decide, in advance, where prices will go over some time period, whether 1 hour, 1 day, or 5 years. Technical analysis must have clear and complete rules.
Technical analysis is no longer just the study of chart patterns or the identification of trends. It encompasses intramarket analysis, complex indicators, mean reversion, and the evaluation of test results. It can use a simple moving average or a neural network to forecast price moves. This book serves as a reference guide for all of these techniques, puts them in some order, and explains the functional similarities and differences for the purpose of trading. It includes some aspects of portfolio construction and multilevel risk control, which are integral parts of successful trading.


Just Now I Uploaded 15 digital imageries with all are in high definition version. From multitudinous photo in Christian bible stories photos, you can have Coloring 2018 with decor. Nonetheless, if you don't appropriate with concept, you can still take a look dream. Even so I promote you can use as an aspiration decoration, although as well as has exciting decor concept. Don't disremember for share this Christian bible stories cartoon bible story movies christian cartoons kids transformers coloring pages to comrade or your close friend. So they are would probably get also to establish they Coloring 2018. I am happy can share with plus to you all. Hopefully you would probably find which all this time are you look for.


text:
YG Family released new photos from final concert stop in Taiwan
On October 25th, the artists of YG Entertainment completed their "YG Family Galaxy 2014 Tour" at the Taoyuan County Stadium in Taiwan with over 23,000 fans in attendance.
The YG Family artists have been on tour since early this summer hitting major cities including Osaka, Beijing, Shanghai, Singapore, Seoul, and most recently, Taipei. The agency released photos from their last concert in Taiwan, which was hugely successful as over 23,000 fans were in attendance singing along to the likes of BIGBANG, PSY, WINNER, 2NE1, and Epik High.
While Epik High did not sing any of the new songs off their latest release Shoebox, which has been topping charts as of late since its release last week. The title track "Happen Ending" is topping charts at #1 with "Spoiler" and "Born Hater" not far behind! They have also been teasing for their upcoming solo concert "PARADE 2014".
Meanwhile, BIGBANG has revealed that they have been working hard on a new album and although there has been no definite date, VIPs anticipation are at an all time high since it has been two years since their last release as a group.
YG Entertainment in addition, released a teaser for "Who Is Next?" with a November 11th date.
The company has been extremely busy lately with the filming of MIX & MATCH's conclusion, which will determine the new members of boy group iKON, who is set to debut early 2015 and enter the Chinese market soon after. In addition, YG Entertainment's first girl group in 5 years will debut soon and is speculated to be sometime in November.
Check out the highlights below and visit the YG Family SNS pages for more photos!
Post by YG-Family.


text:
"3 to 5 Things" ; Apps & Palms
bySheba Kereere
Photo by Solen Feyissa
1. Opposition against Youth IG
Facebook is working on a version for instagram for preteens. Bloomberg reports that forty-four attorneys general are urging Facebook Inc. Chief Executive Officer Mark Zuckerberg to abandon plans to build a new version of photo-sharing network Instagram for young children, arguing the new app could harm kids' mental health and compromise their privacy. Facebook said in a statement it will prioritize safety, privacy and working with regulators and experts as it builds out the service. The company also committed not to show any advertisements on the youth platform.
2. Pay with your hand
Amazon has released a new way to pay; your hand. The Washington Post reports that Amazon announced a new palm-recognition system last week that lets people shop in two of its Amazon Go stores by scanning their palm at the entrance. The store automatically tracks what products they pick up and then charges the credit card associated with their hand. It's the latest in a long line of product announcements from the company to raise privacy or security concerns while selling its vision of an automated, frictionless future. Called "Amazon One", the palm-scanning system is only in two Go stores in Seattle at the moment.
3. Madagascar & COVID-19
Madagascar has started rolling out vaccinations of the COVID-19 vaccine despite the natural solution they were pushing a year ago. Africa News reports that The Indian Ocean island nation received its first shipment of 250,000 AstraZeneca jabs on Saturday. Madagascar on Monday rolled out its Covid-19 vaccination campaign. Health Minister Jean Louis Hanitrala Rakotovao was among the first to be inoculated in the capital, Antananarivo. Madagascar has registered 38,874 infections, including at least 716 deaths. President Andry Rajoelina has been criticized for his handling of the pandemic.Until recently, he had been promoting a herbal concoction as a cure for the virus prompting a warning from the WHO. "Our message is that people should be vaccinated. But it is voluntary," said Issa Sanogo, the United Nations Resident Coordinator in Madagascar.
Tags: AmazonfacebookInstagramMadagascar
3 to 5 Things
"3 to 5 Things" ; Schools & Aid
Jordan McNair The safety of college athletes was brought to light following the untimely death of Jordan McNair. WUSA9...
"3 to 5 Things" ; MoCo, Art & Malaria
1. MoCo Enters 3rd Phase Things are slowly opening back up in Montgomery County. The Bethesda Magazine reports that...
"3 to 5 Things"; Mental Health & Money
1. MoCo Students' Well-being Montgomery County released an announcement today concerning students. The County's website announced the launch of...
"3 to 5 Things" ; Colonial & COVID-19
1. Local Amazon Jobs Amazon is adding new jobs in Virginia. US News reports that the Tech Giant plans...
AYOO MAG
Announcing AYOO AFRICA 2020 TOP TEN D.C. Nominees
2020 TOP TEN D.C. Is Here!
Meet 2020 TOP TEN D.C. Judges
"Montgomery County's COVID-19 Response to Small Businesses and Entrepreneurs"


text:
Live report: on tour with Paloma Faith
Quirky UK actress-turned-songstress Paloma Faith descended on London's Hammersmith Apollo last month. The three-time BRIT Award nominee is currently in the midst of an extensive tour promoting her second album, Fall to Grace.
Erica Basnicki ⋅ Mar 11, 2013
It was 2009 when London-born Paloma Faith first broke into the UK music scene. Three hit singles and a platinum debut album is never a bad start to a pop star's career; and at the end of last year, Fall to Grace followed suit, also going platinum, peaking at number two in the UK Album Charts, and catapulting her to super-stardom in the process.
For her latest tour, everything audio was supplied by SSE Audio Group. FOH engineer Huw Richards is using an L-Acoustics KARA system for the first time, and it's proving particularly versatile, he reveals.
"We needed a flexible system that still packed a punch, as the venues on the tour are all so different," he says. "I'm impressed by KARA – it's a very compact and lightweight system, and although we're pushing it to its limits here, because of the way we are able to configure it, it actually covers the room better than an [L-Acoustics] V-DOSC or K1 system would."
Praise, indeed. Two hangs of 18 KARA along with three hung L-Acoustics SB18 subs per side were deployed, and power was via several racks of L-Acoustics LA8 amplifiers.
"The system has exceeded all my expectations," Richards insists. "I haven't had to ground-stack it once as the hung sub is powerful enough; and in terms of rigging, the boxes are usually down before the drum kit after the show, which is amazing, really."
System tech, SSE Audio's own Perttu Korteniemi, says two local crew is enough to hang any KARA system, because once propagated, it goes up (and comes down) very quickly. He also uses L-Acoustics' SoundVision software to make his room predictions.
"It's the only 3D prediction software out there, and it's excellent – though there's no wizard element to it, it's still a lot of maths," he smiles. "It's all IP-based now, so the role of a tech is pretty much a full-time job; if you have the dimensions of the room and seriously good drawings, you can do a lot of prep work; I already had a room file for the Apollo, which gave me an advantage." Console of choice at FOH was a DiGiCo SD10. A long-time fan of the manufacturer, Richards feels DiGiCo offers great value for money and excellent sound quality.
"Whatever the [DiGiCo] desk you're using, you still get pretty much what you'd get in the flagship SD7: great EQ, great preamps; it all stays the same quality, no matter the price," he says. "I'm running 54 channels here on my SD10, and I love that I have 12 faders in each bay rather than eight, because it's fantastic for drums, as I can pack the whole kit into one bay, which is ideal."
Richards is also impressed by the SD10's internal effects: he uses several reverbs for the drums and various delays for the vocals.
"There's a lot happening on stage so it's good to have all that processing available to send anywhere as and when you wish to. Miles [Hillyard, SSE Audio's senior project manager] also gave us some cool hardware to have a play around with, including the Waves PuigChild, which works beautifully on Paloma's vocal, as she has quite a peaky mid range," Richards explains. "We have it on a setting that seems to work well for her; it just catches the peaks and holds them back and it fattens the vocal up nicely. I then use a TC Electronic 6000 for Paloma's reverbs, which is also a brilliant bit of kit."
Audio travels via a digital path from the SD10 into two Lake processors (LM44 and LM260), which are located at FOH; then it goes into a Cisco switch, and then it's all fibre to stage left. From there, it breaks down to Cat5 to the stage Lakes (two additional LM44s), then it goes AES to the LA8 amplifiers.
"This means when the microphone hits the [DiGiCo] SD rack on stage, it doesn't go back to analogue until the speaker cables," Korteniemi explains. "This method keeps everything simple: there's no setting up of gains and no hiss; it's all nice and clean, so when you open up the PA, there is no interference whatsoever."
At monitor position, Saul Skoutarides worked from a Midas PRO 2, packed out at 53 channels. He provided individual in-ear monitor mixes to three dedicated backing vocalists and all band members; and Paloma's 'blinged out' gold Sennheiser SKM 5200 mk II was linked to Sennheiser's top-of-the-line 3732 receiver. The results, Skoutarides says, are phenomenal.
"The SKM 5200 sounds excellent, and because we're also using the dynamic [5235] head, it doesn't use too much band, therefore it's far more stable than a condenser for this application," he explains. "As it's the only radio mic we're using, I've brought in the 3732, which is also excellent. It has an AES output, so it sounds great if you want to keep it digital all the way, and it's in the NGB frequency range, which goes all the way from 606-790, so I can also use it as a scanner to scan my entire band every morning, because all my [11 x Sennheiser G3] in-ear systems fall into that band. It's just a great setup to work with."
Although Paloma Faith may only stand at 5ft 3", her stage presence transforms her into a fizzy, cheeky giant. A capacity crowd went home very satisfied that night, after witnessing a show that sounded as good as it looked, which, of course, is not surprising when you consider the quality of the team around her. www.digico.bizwww.l-acoustics.comwww.sennheiser.co.uk
Legends Live tour with Martin Audio MLA
Digico consoles provide 'Wall of Sound' for Paloma Faith UK tour
Game of Thrones live concert experience to tour Europe in 2018
Paloma Faith sings in the rain at the Brits with waterproof DPA d:facto
Satellite Tour mixed with SSL Live
Major live music report to be discussed at Music Week conference


Docebo, a global provider of cloud-based corporate learning management solutions, received an additional investment from Klass Capital.
Klass, which had made a $3m initial investment early this year, has partnered with management to acquire a controlling interest in the business buying the shares of Italian venture capital firm Principia SGR and made an additional growth equity investment to support the company's growth.
Following the close of the investment, whose amount was not disclosed, Docebo's management continues to own a significant stake of the company.
Established in Italy in 2005 by Claudio Erba, President and CEO, Docebo provides a SaaS-based enterprise learning management system (LMS) to mid-size to large organizations. The solutions, which currently has more than 28,000 installations, offers a scalable pricing model, a third party integration (via API), and service available 24/7 to further enhance the user experience. Clients include FreshBooks, Shopify, Zendesk and Optimizely, as well as for Fortune 500 companies Thomson Reuters, Bloomberg and Petronas.
The company has over offices in Sovico and Naples Italy, in Dubai, UAE, and Athens, GA, USA.


The Humanities Research Center hosts yearlong residential postdoctoral fellowships at Rice University for outstanding junior scholars. The program is designed to encourage interdisciplinary teaching and research, facilitate new research communities at Rice, and prepare junior scholars for future faculty positions. In 2016-17, Mellon postdocs will participate in the Rice Seminar, a yearlong research seminar designed to study a particular topic from an interdisciplinary perspective.
Find out more: Andrew W. Mellon Postdoctoral Fellows [Rice Seminar 2016-17] | Humanities Research Center.


text:
10.08.2013 Africa
Le Clos picks up week's second World Cup win
LISTEN AUG 10, 2013
Chad Le Clos of South Africa in action in the 200m butterfly on August 7, 2013. By Olaf Kraak (ANP/AFP/File)
BERLIN (AFP) - South Africa's Olympic and world champion Chad le Clos claimed his second World Cup win of the week on Saturday with victory in the men's 200m butterfly final in Berlin.
The 21-year-old, who shot to fame by beating Michael Phelps in the 200m fly final at last year's London Olympics, set the event's short-course world record in Eindhoven (1:49.04) on Wednesday.
Le Clos won both the 100 and 200m butterfly golds at Barcelona's world championships, which finished last Sunday before the World Cup series kicked off in Eindhoven, the Netherlands, on Wednesday then continuing in the German capital this weekend.
Le Clos had to dig deep in Berlin as he clocked 1min 49.90secs in the 200m final with Poland's Pawel Korzeniowski second at 0.53sec back and Japan's Daiya Seto adrift at 1.06 in third.
Over the shorter sprint distance, Le Clos, who added the world title to his Olympic crown in the 200m fly at the world championships last week, then finished third in the 50m final behind compatriot Roland Schoeman.
With Le Clos also swimming the 100m fly and 200m individual medley on Sunday, he admitted racing two World Cup meets in a week, straight after the world championships, was taking its toll.
"I'm happy with the time and nice to get another win (in the 100m fly final) under the belt," Le Clos told AFP.
"It's been a great couple of days, I've got a couple of events to come and then I get about 10 days off.
"Everyone is in the same boat, it's been a pretty tiring week.
"I was up at 5am on Friday to get the train from Eindhoven to Berlin, so it's been a really busy few days after the worlds."
Australia's world champion James Magnussen had to settle for second in the men's 100m freestyle final as he finished 0.3secs behind winner Vladimir Morozov of Russia, the 50m freestyle world silver medallist in Barcelona.
The 21-year-old Magnuseen, who defended his 100m title in Barcelona, will race again on Sunday in the 50m freestyle.
Spain's Mireia Belmonte, who won world silvers over 200m fly and 400m IM in Barcelona, broke the world short-course record in the women's 800m freestyle final.
Belmonte clocked 7mins 59.34secs, with New Zealand's Lauren Boyle came second and Denmark's Lotte Friis finished third.
More Africa
16.01.2021 | Africa
'Miracle' drug ivermectin unproven against Covid, scientists warn
Abdelbaset al-Megrahi: Lockerbie's lone culprit, despite battle to clear name
Scottish court upholds Lockerbie bomber's conviction
Unfinished history: 60 years after the murder of DRC hero Lumumba
Germany hits 2 million infections as WHO tackles new strains
Africa COVID-19 cases top 3 million, first wave peak surpassed
Africa CDC says nations must act fast to prepare for Covid vaccines
Climate change worsens child malnutrition: study


Here are some websites examples that use Income Activator's website builder and revenue streams.
This website demonstrates the lead process.
This is when you send 1 lead to 1 company at a time.
You begin by contacting a company you want to send leads to, and agree on what a lead is worth. You may wish to start off at a $10 referral rate, and increase it as you get more companies wanting your leads.
It's always best to send leads to companies providing services, like contractors, spas, chiropractors, dentists, lawyers, and so forth.
When your visitor clicks on the submit button, they are directed to your referral company's website, which you can embed into your website so that your visitor isn't kicked off your site.
The lead is then made, and your Income Activator program automatically creates your invoice. As you get more leads, they are automatically added to the invoice.
A lead is never based on your referral company closing the business. It's only based on you directing your visitors to your referral company's website.
This website, Car Carma is a light hearted look at how your astrological signs affects your driving.
It's eBooks were created through Income Activator's eBook templates.
This website demonstrates how to make money through Directory Referrals.
This is when you send 1 lead to MULTIPLE companies that all pay you.
Here is an example to sending 1 lead to 10 painters. If each painter agreed to pay you $10 to quote on a painting job, the website owner would make $100 per lead.
No one knows you're a dog when you're online. WhoLetTheDogIn.com has 10 Revenue streams.
Here you can see how you can get paid from your own Pay Per Click links, and make money just like Google does.
To do this you contact a company you want to send leads to, and agree on a pay per click rate. You can begin by suggesting $1 per click, and increase your rate as you get more companies wanting you to send then leads.
In this example you, when you click on the Pet Insurance Company Links, it will take you to the referral company's website, that you can embed into your own website. The advantage of this is that your visitor isn't kicked off your site, like they are with other pay per click links.
When your visitor clicks on the link, and is directed to your referral company's website, the click is tracked and your Income Activator website automatically creates your invoice.


text:
Fathers and Sons, Lovers and Killers: The Plot Thickens on "Damages"
While everyone is bound to being freaking out over the two-hour fifth season premiere of Lost, I'm hoping that fans of FX's Damages haven't forsaken the legal thriller this week as the series once again delivered a fantastic installment that filled in some of the blanks in the backstory between Patty Hewes and Daniel Purcell.
On this week's episode of Damages ("I Knew Your Pig"), the case against Daniel Purcell mounts as the police--embodied by dogged cop Detective Huntley (Tom Noonan)--clearly thinks he is their prime suspect while Daniel makes a discovery about Christine's murder and Patty learns that Daniel is lying to her about a number of things... and possibly everything. All this and Ellen digging around into Patty's past vis-a-vis a seventeen-year-old case that involved Patty AND Daniel Purcell. Hmmm...
Let's discuss.
Michael. I just *knew* that Michael was Daniel Purcell's son, after that totally awkward and charged encounter between them and Patty in front of the elevator in last week's episode. The oddness with which Daniel looked at Michael made it abundantly clear that he knew him from somewhere and the way that Patty pointedly introduced Michael as her son confirmed it (along with the heightened blond color of Michael's hair this season).
The clues were further spelled out in this week's episode as Michael asked Ellen for help on his college essay and Ellen learned that Patty and Purcell had worked on a case together seventeen years ago. Still, Michael appears to be totally weirded out by Purcell and even went so far as to refer to him as a "creep." Michael's a pretty smart kid so it's entirely possible that he figured out that Purcell was his dad a long time ago... could he have been the guy in the hooded sweatshirt who broke into his office before Christine's murder? Curious.
The Ring. Just when it seemed that Purcell was definitely guilty of murdering Christine (especially after the flashback that proves that they DID have an argument the night of the murder, seemingly after the gala), Purcell happens to notice that Christine's ruby ring--the one he bought her for her tenth anniversary and she always wore--was missing from her hand in the crime scene photos. So why would the stringy haired blonde guy--whom Purcell has fingered as Christine's killer--have taken the ruby ring and left the diamond one? I'd disbelieve Purcell's claim altogether if Patty didn't distinctly remember Christine wearing the ring the night of the murder.
And just when it seemed like Purcell's story was too good to be true, the stringy-haired blonde guy (or SHBG) turns up at a pawn shop with said ring. Why steal a very distinctive ruby ring from a murdered woman and then pawn it shortly thereafter? Could Daniel be telling the truth about Christine's murder? Was Ultima trying to send him a message? Was it a home invasion gone wrong? Or is something else going on altogether? It would be a pretty neat trick if Purcell did kill Christine and give himself a means of creating some doubt in the police's minds by having the ring go astray... and then wind up at a local pawn shop.
Daniel and Patty. Of course, Purcell did undermine Patty's whole defense of him by attempting to leave the country, at Claire's suggestion. Not sure if Claire was really being a supportive secret lover by telling Purcell to flee the country while he's under investigation for his wife's murder but Purcell did just that, unaware that Patty was having him watched... and had her men tip off the police about Purcell's intent to leave the country. Nicely played, Patty.
And we learned that Purcell not only has a violent temper but he actually did hit Christine three years earlier... and his wife filed a restraining order against him. Both were meant to be sealed in family court, so it's unclear how Det. Huntley got either of those files but one can imagine that Ultima is pulling some strings to sink Purcell, even if they didn't kill Christine themselves. Hmmm...
I loved that we were treated to a series of flashbacks this week to see the relationship between Patty and Purcell unfold ten years back. After Purcell was a star witness in Patty's first case seventeen years ago (and their partnership led to the conception of son Michael), seven years later they found themselves on opposite sides of a deposition in an IBC case that was being defended by none other than Ellen's protector Hollis Nye. Under questioning, Purcell buckled and his testimony won the case for Patty when she was able to produce a letter he wrote to his daughter's day care center alleging that 30 parts per million was a fatal percentage, even though his company had produced a report claiming that 100 parts per million was acceptable. Purcell was Patty's ace in the hole and they had colluded on the case. His payment? A photograph of Michael, the son he didn't know existed, which Patty had withheld until Purcell's testimony damned the defense.
Kendrick. This week's episode featured the first on-screen appearance of Walter Kendrick (The Wire's John Doman), the CEO of Ultimate National Resources; Kendrick was previously mentioned by Claire Maddox in Episode Two. After Kendrick gets a call from Wayne Suttry (who himself gets a visit from Claire Maddox while jogging in the park), he orders that security be heightened at all of the company's West Virginia coal plants.
Josh. Which is how reporter Josh Reston (Matthew Davis) finds himself getting beaten to a pulp after breaking in and stealing a water sample from a plant. Seemingly tipped off by Purcell to investigate the contamination levels in the ground water in the area--responsible for killing many local farmer's livestock (including the titular pig)--but Purcell is now not taking his calls. Sure, Purcell's under investigation for murder, but Josh is now putting himself in harm's way without being able to get a hold of the man who sent him down there in the first place. Hopefully, Patty, Ellen, and Tom can get to him before Ultima has him permanently silenced and find out what he's learned so far... and what will directly contradict the report that Purcell and Suttry's company has put together.
The Feds. Agents Harrison and Werner make a brief appearance in this week's episode as they tell Ellen that they are going to cool their investigation of Patty now that Tom has been pulled off of the infant mortality case and didn't end up buying a defendant's testimony. Ellen, of course, is none too pleased with this development and pursues things further, discovering the link between Patty and Purcell and believing (correctly) that Purcell is Michael's biological father. I'm definitely concerned with the fact that the agents aren't more perturbed with the way their case against Patty has gone and why they are playing things quite so cool. Theories?
Next week on Damages ("Hey! Mr. Pibb"), Patty concentrates on defending Daniel Purcell in the murder case against him, while Ellen and Tom travel to West Virginia research the case against Ultima National Resources.
Damages FX
Labels: Damages FX
I'm so happy that The Wire's John Doman is playing Kendrick. I love it! And I'm really interested to see how the reporter, Josh Reston, plays into all of this mess. Purcell is obviously lying about a lot of things but are his intentions good? It's very difficult to tell. I did like how he scolded Patty for using the picture of their son as a reward for his help. He is one of the few people we've ever seen stand up to Patty (and live)!
Jon88 said…
Speaking of "The Wire" -- that was Seth Gilliam playing Mark, the "I want you to meet my boyfriend" in the bar. Presumably in later episodes, he'll have lines.
Golden Ticket: An Advance Review of "Chuck Versus ...
Channel Surfing: ABC Tells Lauren Graham to "Let I...
Golden Compass: Theories, Revelations, and Reveals...
"Because I'll Destroy You": Conspiracies and Doubl...
Channel Surfing: Gordon Ramsay to Cook Live for FO...
Soda Water: An Early Look at Tonight's Episode of ...
No-Brainer: Astrid Still Needs Character Developme...
Talk Back: Season Two Premiere of BBC America's "L...
Channel Surfing: Nets Order Slew of Pilots, Kriste...
If You Can't Stand the Heat, Get Out of the Restau...
Channel Surfing: ABC Orders "V" Remake, "House" Ma...
Schemers and Dreamers: Lucky Charms, Cancer Scares...
Fear and Loathing Stalk the Crew of "Battlestar Ga...
BBC America Brings "Torchwood" to New York Comic-Con
Truth (and Lies) in Advertising: An Advance Review...
Channel Surfing: FOX to Get "AbFab," Jane Espenson...
Link Tank: TV Blog Coalition Roundup for Jan. 23 - 25
Eternal Romance: The Final Cylon and Ronald D. Moo...
Saving Not-So-Private Ryan: Former "Bionic Woman" ...
Channel Surfing: Harmon Ponders "Samantha Who." AB...
What Comes Around, Goes Around: The Season Five Pr...
Time Travel, Red Shirts, and Alliances: More with ...
Fathers and Sons, Lovers and Killers: The Plot Thi...
Channel Surfing: Clooney Returns to "ER," Gondry D...
Team Darlton Promise "No More Jack Flies a Kite" E...
Truth Be Told: An Advance Review of FOX's "Lie to Me"
Channel Surfing: Darlton Talk Donkey Wheel, Priest...
Bound to a Star: A Quick Early Look at Tonight's E...
Channel Surfing: First Look at Dominic Monaghan on...
Taunting Jughead: An Advance Look at Episode 503 o...
Talk Back: "Battlestar Galactica" Mid-Season Premi...
Talk Back: Season Premiere of HBO's "Big Love" ("B...
Channel Surfing: "Mad" Man Signs Deal, Moore Talks...
Link Tank: TV Blog Coalition Roundup for Jan. 16-18
ABC's Steve McPherson Talks "Pushing Daisies," "Di...
An Hour of Comedy Laughs (For a Change)
Belle of the Ball: An Advance Review of the First ...
Love is All Around Us: "Big Love" Creators and Sta...
Channel Surfing: NBC Renews "30 Rock" and "The Off...
Riding the Tide Out to Sea: An Advance Review of t...
"Everybody Has an Angle": Talk Back for "Damages" ...
Conchords' Mel Takes Flight: Televisionary Talks t...
Channel Surfing: "Gossip Girl" Spinoff Back to the...
Televisionary Exclusive: "Virtuality" Writer Micha...
My Lovely Sugar Lumps: An Advance Review of the Fi...
"Prison Break" to End and Other News from FOX's TC...
"Skins" Sneak Peek: Check Out Cook's Tattoo
Set Your TiVos: Season Three of "Gordon Ramsay's F...
Channel Surfing: Team Darlton Talks "Lost," Detail...
More Than Skin Deep: Televisionary Talks to Jamie ...
TV on DVD: "Skins: Volume One"
Channel Surfing: "Lost" Clues, Barrowman Pens "Tor...
Sex, Drugs, and ASBOs: An Advance Review of "Skins...
"Deal With It, Cate Blanchett!": "30 Rock," "John ...
Televisionary Named One of "30 Essential Twitter F...
Channel Surfing: Swoosie Kurtz Suits Up for "Heroe...
Link Tank: TV Blog Coalition Roundup for Jan. 9-11
(No) Sex and the City: Liz Heads to the Brooklyn B...
Channel Surfing: "Mad Men" to Return This Summer, ...
Talk Back: "Damages" Season Two Premiere
Out of the Frying Pan: BBC America Announces Seaso...
Channel Surfing: Donna Martin Graduates to "90210,...
Damage Report: Talking with the Creators and Star ...
Multiple Personality Reunion Tour: An Advance Revi...
Channel Surfing: ABC Schedule Still Missing "Daisi...
Mint Bailey's and White Toblerone: A Look at the "...
Channel Surfing: Fresh Hamm on "30 Rock," NBC Find...
What I'm Watching This Spring
Steampunk Robots and Feminist Villains: A Look at ...
Channel Surfing: "Doctor Who" Lands Smith and Circ...
Who Will Play the Doctor: The Eleventh Doctor is.....
First Look: "Skins" Season Three
Televisionary New Year Resolutions for 2009
A Pure Woman Faithfully Presented: An Advance Look...