text:
package mesosphere.marathon.state

import org.mockito.Mockito._
import org.mockito.Matchers._
import scala.concurrent.{ Future, Await }
import scala.concurrent.duration._
import org.joda.time.DateTime
import mesosphere.marathon.MarathonSpec
import scala.language.postfixOps
import PathId._

class AppRepositoryTest extends MarathonSpec {
  test("App") {
    val path = "testApp".toRootPath
    val store = mock[MarathonStore[AppDefinition]]
    val timestamp = new Timestamp(DateTime.now())
    val appDef = AppDefinition(id = path, version = timestamp)
    val future = Future.successful(Some(appDef))

    when(store.fetch(s"testApp:$timestamp")).thenReturn(future)

    val repo = new AppRepository(store)
    val res = repo.app(path, timestamp)

    assert(Some(appDef) == Await.result(res, 5.seconds), "Should return the correct AppDefinition")
    verify(store).fetch(s"testApp:$timestamp")
  }

  test("Store") {
    val path = "testApp".toRootPath
    val store = mock[MarathonStore[AppDefinition]]
    val appDef = AppDefinition(id = path)
    val future = Future.successful(Some(appDef))
    val versionedKey = s"testApp:${appDef.version}"

    when(store.store(versionedKey, appDef)).thenReturn(future)
    when(store.store("testApp", appDef)).thenReturn(future)

    val repo = new AppRepository(store)
    val res = repo.store(appDef)

    assert(appDef == Await.result(res, 5.seconds), "Should return the correct AppDefinition")
    verify(store).store(versionedKey, appDef)
    verify(store).store(s"testApp", appDef)
  }

  test("AppIds") {
    val store = mock[MarathonStore[AppDefinition]]
    val future = Future.successful(Seq("app1", "app2", "app1:version", "app2:version").iterator)

    when(store.names()).thenReturn(future)

    val repo = new AppRepository(store)
    val res = repo.allIds()

    assert(Seq("app1", "app2") == Await.result(res, 5.seconds), "Should return only unversioned names")
    verify(store).names()
  }

  test("Apps") {
    val store = mock[MarathonStore[AppDefinition]]
    val appDef1 = AppDefinition("app1".toPath)
    val appDef2 = AppDefinition("app2".toPath)
    val appDef1Old = appDef1.copy(version = Timestamp(appDef1.version.dateTime.minusDays(1)))
    val appDef2Old = appDef2.copy(version = Timestamp(appDef2.version.dateTime.minusDays(1)))
    val allApps = Seq(appDef1, appDef2, appDef1Old, appDef2Old)

    val future = Future.successful((Seq("app1", "app2") ++ allApps.map(x => s"${x.id}:${x.version}")).toIterator)

    when(store.names()).thenReturn(future)
    when(store.fetch(appDef1.id.toString)).thenReturn(Future.successful(Some(appDef1)))
    when(store.fetch(appDef2.id.toString)).thenReturn(Future.successful(Some(appDef2)))

    val repo = new AppRepository(store)
    val res = repo.apps()

    assert(Seq(appDef1, appDef2) == Await.result(res, 5.seconds), "Should return only current versions")
    verify(store).names()
    verify(store).fetch(appDef1.id.toString)
    verify(store).fetch(appDef2.id.toString)
  }

  test("ListVersions") {
    val store = mock[MarathonStore[AppDefinition]]
    val appDef1 = AppDefinition("app1".toRootPath)
    val version1 = appDef1.copy(version = Timestamp(appDef1.version.dateTime.minusDays(1)))
    val version2 = appDef1.copy(version = Timestamp(appDef1.version.dateTime.minusDays(2)))
    val version3 = appDef1.copy(version = Timestamp(appDef1.version.dateTime.minusDays(3)))
    val appDef2 = AppDefinition("app2".toRootPath)
    val allApps = Seq(appDef1, version1, version2, version3, appDef2)

    val future = Future.successful((Seq("app1", "app2") ++ allApps.map(x => s"${x.id.safePath}:${x.version}")).toIterator)

    when(store.names()).thenReturn(future)

    val repo = new AppRepository(store)
    val res = repo.listVersions(appDef1.id)

    val expected = Seq(appDef1.version, version1.version, version2.version, version3.version)
    assert(expected == Await.result(res, 5.seconds), "Should return all versions of given app")
    verify(store).names()
  }

  test("Expunge") {
    val store = mock[MarathonStore[AppDefinition]]
    val appDef1 = AppDefinition("app1".toRootPath)
    val version1 = appDef1.copy(version = Timestamp(appDef1.version.dateTime.minusDays(1)))
    val version2 = appDef1.copy(version = Timestamp(appDef1.version.dateTime.minusDays(2)))
    val version3 = appDef1.copy(version = Timestamp(appDef1.version.dateTime.minusDays(3)))
    val appDef2 = AppDefinition("app2".toRootPath)
    val allApps = Seq(appDef1, version1, version2, version3, appDef2)

    val future = Future.successful((Seq("app1", "app2") ++ allApps.map(x => s"${x.id.safePath}:${x.version}")).toIterator)

    when(store.names()).thenReturn(future)
    when(store.expunge(any())).thenReturn(Future.successful(true))

    val repo = new AppRepository(store)
    val res = Await.result(repo.expunge(appDef1.id), 5.seconds).toSeq

    assert(res.size == 5, "Should expunge all versions")
    assert(res.forall(identity), "Should succeed")

    verify(store).names()
    verify(store).expunge("app1")
    for {
      app <- allApps
      if app.id.toString == "app1"
    } verify(store).expunge(s"${app.id}:${app.version}")
  }
}


text:
package de.fu_berlin.inf.ag_se.browser.listener;

import de.fu_berlin.inf.ag_se.browser.html.IElement;

public interface IDNDListener {
	public void dragStart(long offsetX, long offsetY, IElement element,
                          String mimeType, String data);

	public void drop(long offsetX, long offsetY, IElement element,
                     String mimeType, String data);
}

redpajama_set_name: RedPajamaGithub


text:
;(function() {
  "use strict";

  var BaseController = require("BaseController"),
      _ = require("lodash");

  var multiSelectors = {
    play: [".player-play-pause.play", ".button-nfplayerPlay"],
    pause: [".player-play-pause.pause", ".button-nfplayerPause"],
    playNext: [".player-next-episode", ".button-nfplayerNextEpisode"],
    mute: [".player-control-button.volume", ".button-volumeLow, .button-volumeMedium, .button-volumeMax, .button-volumeMuted"],

    playState: [".player-play-pause.pause",".button-nfplayerPause"],
    song: [".player-status-main-title", ".title"]
  };

  var controller = new BaseController({
    siteName: "Netflix"
  });

  controller.checkPlayer = function() {
    var that = this;

    if(this.doc().querySelector(multiSelectors.play[0]) || this.doc().querySelector(multiSelectors.pause[0])) {
      _.each(multiSelectors, function(value, key) {
        that.selectors[key] = value[0];
      });
    } else {
      _.each(multiSelectors, function(value, key) {
        that.selectors[key] = value[1];
      });
    }
  };
})();


text:
<!DOCTYPE html>

        <meta charset="UTF-8">
        <title>Eli Roman</title>
        <link rel="stylesheet" href="css/old-style.css">

        <link rel="shortcut icon" href="img/ProfilePic.jpg" type="image/png">

Eli Roman

Cell: 203-604-3674

Email: eli.j.roman@gmail.com

I am a web developer and computer science student currently studying at norwalk community college. As of yet I have no experience beyond acedemic education and personal experimentation, but I hope to change that soon.

Education

Norwalk Community college

Major: Computer Science

				Minor: Web Development

Skills

Computer skills

Microsoft Word & Powerpoint

Adobe Premiere

Adobe Dreamweaver

Adobe Photoshop

Wordpress

Programing Languages

Java

HTML

CSS

Javascript

			<form action="MAILTO:eli.j.roman@gmail.com" method="post" enctype="text/plain">

Contact Me:

Type a comment and send it to my email.

				<textarea id="message" name="message" placeholder="Message"></textarea>

				<input type="submit" value="Send">
				<input type="reset" value="Reset">
			</form>


text:
// Copyright 2016 Proyectos y Sistemas de Mantenimiento SL (eProsima).
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * @file StringTopic.cpp
 *
 */

#include "fastcdr/FastBuffer.h"
#include "fastcdr/Cdr.h"

#include "StringType.h"

using namespace eprosima::fastrtps::rtps;

StringType::StringType()
{
    setName("StringType");
    m_typeSize = (uint32_t)String::getMaxCdrSerializedSize() + 4 /*encapsulation*/;
    m_isGetKeyDefined = false;

}

StringType::~StringType()
{
    // TODO Auto-generated destructor stub
}

bool StringType::serialize(
        void* data,
        SerializedPayload_t* payload)
{
    bool ret_value = false;
    String* hw = (String*) data;

    try
    {
        // Object that manages the raw buffer.
        eprosima::fastcdr::FastBuffer fastbuffer((char*)payload->data, payload->max_size);
        // Object that serializes the data.
        eprosima::fastcdr::Cdr ser(fastbuffer, eprosima::fastcdr::Cdr::DEFAULT_ENDIAN,
                eprosima::fastcdr::Cdr::DDS_CDR);
        payload->encapsulation = ser.endianness() == eprosima::fastcdr::Cdr::BIG_ENDIANNESS ? CDR_BE : CDR_LE;
        // Serialize encapsulation
        ser.serialize_encapsulation();
        //serialize the object:
        hw->serialize(ser);
        payload->length = (uint32_t)ser.getSerializedDataLength();
        ret_value = true;
    }
    catch (eprosima::fastcdr::exception::Exception&)
    {
    }
    return ret_value;
}

bool StringType::deserialize(
        SerializedPayload_t* payload,
        void* data)
{
    bool ret_value = false;
    String* hw = (String*) data;

    try
    {
        // Object that manages the raw buffer.
        eprosima::fastcdr::FastBuffer fastbuffer((char*)payload->data, payload->length);
        // Object that serializes the data.
        eprosima::fastcdr::Cdr deser(fastbuffer, eprosima::fastcdr::Cdr::DEFAULT_ENDIAN,
                eprosima::fastcdr::Cdr::DDS_CDR); // Object that deserializes the data.
        // Deserialize encapsulation.
        deser.read_encapsulation();
        payload->encapsulation = deser.endianness() == eprosima::fastcdr::Cdr::BIG_ENDIANNESS ? CDR_BE : CDR_LE;
        //serialize the object:
        hw->deserialize(deser);
        ret_value =  true;
    }
    catch (eprosima::fastcdr::exception::Exception&)
    {
    }
    return ret_value;
}

std::function<uint32_t()> StringType::getSerializedSizeProvider(
        void* data)
{
    return [data]() -> uint32_t
           {
               return (uint32_t)type::getCdrSerializedSize(*static_cast<String*>(data)) + 4 /*encapsulation*/;
           };
}

void* StringType::createData()
{
    return (void*)new String();
}

void StringType::deleteData(
        void* data)
{
    delete((String*)data);
}

bool StringType::getKey(
        void* /*data*/,
        InstanceHandle_t* /*ihandle*/,
        bool /*force_md5*/)
{
    return false;
}

bool StringType::is_bounded() const
{
    return true;
}

bool StringType::is_plain() const
{
    return false;
}


text:
export { default } from './useThemeProps';
export { default as getThemeProps } from './getThemeProps';


text:
package br.com.caelum.vraptor.interceptor;

import java.lang.reflect.Type;

/**
 * Component that Extract the name of a generic type.
 *
 * @author Lucas Cavalcanti
 * @since 3.0.2
 */
public interface TypeNameExtractor {

	String nameFor(Type generic);

}


text:
package handler

import (
	"fmt"
	"io"
	"net/http"
	"net/http/httptest"
	"net/url"
	"os"
	"reflect"
	"runtime"
	"runtime/pprof"
	"strconv"
	"sync"
	"testing"
	"time"

	"context"

	apicontainer "github.com/aws/amazon-ecs-agent/agent/api/container"
	mock_api "github.com/aws/amazon-ecs-agent/agent/api/mocks"
	apitask "github.com/aws/amazon-ecs-agent/agent/api/task"
	"github.com/aws/amazon-ecs-agent/agent/config"
	rolecredentials "github.com/aws/amazon-ecs-agent/agent/credentials"
	mock_credentials "github.com/aws/amazon-ecs-agent/agent/credentials/mocks"
	"github.com/aws/amazon-ecs-agent/agent/data"
	mock_dockerapi "github.com/aws/amazon-ecs-agent/agent/dockerclient/dockerapi/mocks"
	"github.com/aws/amazon-ecs-agent/agent/doctor"
	"github.com/aws/amazon-ecs-agent/agent/engine/dockerstate"
	mock_engine "github.com/aws/amazon-ecs-agent/agent/engine/mocks"
	"github.com/aws/amazon-ecs-agent/agent/eventhandler"
	"github.com/aws/amazon-ecs-agent/agent/eventstream"

	"github.com/aws/amazon-ecs-agent/agent/utils/retry"
	mock_retry "github.com/aws/amazon-ecs-agent/agent/utils/retry/mock"
	"github.com/aws/amazon-ecs-agent/agent/version"
	"github.com/aws/amazon-ecs-agent/agent/wsclient"
	mock_wsclient "github.com/aws/amazon-ecs-agent/agent/wsclient/mock"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/gorilla/websocket"
	"github.com/pkg/errors"
	"github.com/stretchr/testify/assert"

	"github.com/golang/mock/gomock"
)

const (
	samplePayloadMessage = `
{
  "type": "PayloadMessage",
  "message": {
    "messageId": "123",
    "tasks": [
      {
        "taskDefinitionAccountId": "123",
        "containers": [
          {
            "environment": {},
            "name": "name",
            "cpu": 1,
            "essential": true,
            "memory": 1,
            "portMappings": [],
            "overrides": "{}",
            "image": "i",
            "mountPoints": [],
            "volumesFrom": []
          }
        ],
        "elasticNetworkInterfaces":[{
                "attachmentArn": "eni_attach_arn",
                "ec2Id": "eni_id",
                "ipv4Addresses":[{
                    "primary": true,
                    "privateAddress": "ipv4"
                }],
                "ipv6Addresses": [{
                    "address": "ipv6"
                }],
                "subnetGatewayIpv4Address": "ipv4/20",
                "macAddress": "mac"
        }],
        "roleCredentials": {
          "credentialsId": "credsId",
          "accessKeyId": "accessKeyId",
          "expiration": "2016-03-25T06:17:19.318+0000",
          "roleArn": "r1",
          "secretAccessKey": "secretAccessKey",
          "sessionToken": "token"
        },
        "version": "3",
        "volumes": [],
        "family": "f",
        "arn": "arn",
        "desiredStatus": "RUNNING"
      }
    ],
    "generatedAt": 1,
    "clusterArn": "1",
    "containerInstanceArn": "1",
    "seqNum": 1
  }
}
`
	sampleRefreshCredentialsMessage = `
{
  "type": "IAMRoleCredentialsMessage",
  "message": {
    "messageId": "123",
    "clusterArn": "default",
    "taskArn": "t1",
    "roleType": "TaskApplication",
    "roleCredentials": {
      "credentialsId": "credsId",
      "accessKeyId": "newakid",
      "expiration": "later",
      "roleArn": "r1",
      "secretAccessKey": "newskid",
      "sessionToken": "newstkn"
    }
  }
}
`
	acsURL = "http://endpoint.tld"
)

var testConfig = &config.Config{
	Cluster:            "someCluster",
	AcceptInsecureCert: true,
}

var testCreds = credentials.NewStaticCredentials("test-id", "test-secret", "test-token")

type mockSessionResources struct {
	client wsclient.ClientServer
}

func (m *mockSessionResources) createACSClient(url string, cfg *config.Config) wsclient.ClientServer {
	return m.client
}

func (m *mockSessionResources) connectedToACS() {
}

func (m *mockSessionResources) getSendCredentialsURLParameter() string {
	return "true"
}

// TestACSWSURL tests if the URL is constructed correctly when connecting to ACS
func TestACSWSURL(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()
	taskEngine := mock_engine.NewMockTaskEngine(ctrl)

	taskEngine.EXPECT().Version().Return("Docker version result", nil)

	wsurl := acsWsURL(acsURL, "myCluster", "myContainerInstance", taskEngine, &mockSessionResources{})

	parsed, err := url.Parse(wsurl)
	assert.NoError(t, err, "should be able to parse URL")
	assert.Equal(t, "/ws", parsed.Path, "wrong path")
	assert.Equal(t, "myCluster", parsed.Query().Get("clusterArn"), "wrong cluster")
	assert.Equal(t, "myContainerInstance", parsed.Query().Get("containerInstanceArn"), "wrong container instance")
	assert.Equal(t, version.Version, parsed.Query().Get("agentVersion"), "wrong agent version")
	assert.Equal(t, version.GitHashString(), parsed.Query().Get("agentHash"), "wrong agent hash")
	assert.Equal(t, "DockerVersion: Docker version result", parsed.Query().Get("dockerVersion"), "wrong docker version")
	assert.Equalf(t, "true", parsed.Query().Get(sendCredentialsURLParameterName), "Wrong value set for: %s", sendCredentialsURLParameterName)
	assert.Equal(t, "1", parsed.Query().Get("seqNum"), "wrong seqNum")
	protocolVersion, _ := strconv.Atoi(parsed.Query().Get("protocolVersion"))
	assert.True(t, protocolVersion > 1, "ACS protocol version should be greater than 1")
}

// TestHandlerReconnectsOnConnectErrors tests if handler reconnects retries
// to establish the session with ACS when ClientServer.Connect() returns errors
func TestHandlerReconnectsOnConnectErrors(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()
	taskEngine := mock_engine.NewMockTaskEngine(ctrl)
	taskEngine.EXPECT().Version().Return("Docker: 1.5.0", nil).AnyTimes()

	ecsClient := mock_api.NewMockECSClient(ctrl)
	ecsClient.EXPECT().DiscoverPollEndpoint(gomock.Any()).Return(acsURL, nil).AnyTimes()

	ctx, cancel := context.WithCancel(context.Background())
	taskHandler := eventhandler.NewTaskHandler(ctx, data.NewNoopClient(), nil, nil)

	mockWsClient := mock_wsclient.NewMockClientServer(ctrl)
	mockWsClient.EXPECT().SetAnyRequestHandler(gomock.Any()).AnyTimes()
	mockWsClient.EXPECT().AddRequestHandler(gomock.Any()).AnyTimes()
	mockWsClient.EXPECT().Serve().AnyTimes()
	mockWsClient.EXPECT().Close().Return(nil).AnyTimes()
	gomock.InOrder(
		// Connect fails 10 times
		mockWsClient.EXPECT().Connect().Return(io.EOF).Times(10),
		// Cancel trying to connect to ACS on the 11th attempt
		// Failure to retry on Connect() errors should cause the
		// test  to time out as the context is never cancelled
		mockWsClient.EXPECT().Connect().Do(func() {
			cancel()
		}).Return(nil).MinTimes(1),
	)
	acsSession := session{
		containerInstanceARN: "myArn",
		credentialsProvider:  testCreds,
		agentConfig:          testConfig,
		taskEngine:           taskEngine,
		ecsClient:            ecsClient,
		dataClient:           data.NewNoopClient(),
		taskHandler:          taskHandler,
		backoff:              retry.NewExponentialBackoff(connectionBackoffMin, connectionBackoffMax, connectionBackoffJitter, connectionBackoffMultiplier),
		ctx:                  ctx,
		cancel:               cancel,
		resources:            &mockSessionResources{mockWsClient},
		_heartbeatTimeout:    20 * time.Millisecond,
		_heartbeatJitter:     10 * time.Millisecond,
	}
	go func() {
		acsSession.Start()
	}()

	// Wait for context to be cancelled
	select {
	case <-ctx.Done():
	}
}

// TestIsInactiveInstanceErrorReturnsTrueForInactiveInstance tests if the 'InactiveInstance'
// exception is identified correctly by the handler
func TestIsInactiveInstanceErrorReturnsTrueForInactiveInstance(t *testing.T) {
	assert.True(t, isInactiveInstanceError(fmt.Errorf("InactiveInstanceException: ")),
		"inactive instance exception message parsed incorrectly")
}

// TestIsInactiveInstanceErrorReturnsFalseForActiveInstance tests if non 'InactiveInstance'
// exceptions are identified correctly by the handler
func TestIsInactiveInstanceErrorReturnsFalseForActiveInstance(t *testing.T) {
	assert.False(t, isInactiveInstanceError(io.EOF),
		"inactive instance exception message parsed incorrectly")
}

// TestComputeReconnectDelayForInactiveInstance tests if the reconnect delay is computed
// correctly for an inactive instance
func TestComputeReconnectDelayForInactiveInstance(t *testing.T) {
	acsSession := session{_inactiveInstanceReconnectDelay: inactiveInstanceReconnectDelay}
	assert.Equal(t, inactiveInstanceReconnectDelay, acsSession.computeReconnectDelay(true),
		"Reconnect delay doesn't match expected value for inactive instance")
}

// TestComputeReconnectDelayForActiveInstance tests if the reconnect delay is computed
// correctly for an active instance
func TestComputeReconnectDelayForActiveInstance(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()

	mockBackoff := mock_retry.NewMockBackoff(ctrl)
	mockBackoff.EXPECT().Duration().Return(connectionBackoffMax)

	acsSession := session{backoff: mockBackoff}
	assert.Equal(t, connectionBackoffMax, acsSession.computeReconnectDelay(false),
		"Reconnect delay doesn't match expected value for active instance")
}

// TestWaitForDurationReturnsTrueWhenContextNotCancelled tests if the
// waitForDurationOrCancelledSession method behaves correctly when the session context
// is not cancelled
func TestWaitForDurationReturnsTrueWhenContextNotCancelled(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	acsSession := session{
		ctx:    ctx,
		cancel: cancel,
	}

	assert.True(t, acsSession.waitForDuration(time.Millisecond),
		"WaitForDuration should return true when uninterrupted")
}

// TestWaitForDurationReturnsFalseWhenContextCancelled tests if the
// waitForDurationOrCancelledSession method behaves correctly when the session contexnt
// is cancelled
func TestWaitForDurationReturnsFalseWhenContextCancelled(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()

	ctx, cancel := context.WithCancel(context.Background())
	acsSession := session{
		ctx:    ctx,
		cancel: cancel,
	}
	cancel()

	assert.False(t, acsSession.waitForDuration(time.Millisecond),
		"WaitForDuration should return false when interrupted")
}

func TestShouldReconnectWithoutBackoffReturnsTrueForEOF(t *testing.T) {
	assert.True(t, shouldReconnectWithoutBackoff(io.EOF),
		"Reconnect without backoff should return true when connection is closed")
}

func TestShouldReconnectWithoutBackoffReturnsFalseForNonEOF(t *testing.T) {
	assert.False(t, shouldReconnectWithoutBackoff(fmt.Errorf("not EOF")),
		"Reconnect without backoff should return false for non io.EOF error")
}

// TestHandlerReconnectsWithoutBackoffOnEOFError tests if the session handler reconnects
// to ACS without any delay when the connection is closed with the io.EOF error
func TestHandlerReconnectsWithoutBackoffOnEOFError(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()

	taskEngine := mock_engine.NewMockTaskEngine(ctrl)
	taskEngine.EXPECT().Version().Return("Docker: 1.5.0", nil).AnyTimes()

	ecsClient := mock_api.NewMockECSClient(ctrl)
	ecsClient.EXPECT().DiscoverPollEndpoint(gomock.Any()).Return(acsURL, nil).AnyTimes()

	ctx, cancel := context.WithCancel(context.Background())
	taskHandler := eventhandler.NewTaskHandler(ctx, data.NewNoopClient(), nil, nil)

	deregisterInstanceEventStream := eventstream.NewEventStream("DeregisterContainerInstance", ctx)
	deregisterInstanceEventStream.StartListening()

	mockBackoff := mock_retry.NewMockBackoff(ctrl)
	mockWsClient := mock_wsclient.NewMockClientServer(ctrl)
	mockWsClient.EXPECT().SetAnyRequestHandler(gomock.Any()).AnyTimes()
	mockWsClient.EXPECT().AddRequestHandler(gomock.Any()).AnyTimes()
	mockWsClient.EXPECT().Close().Return(nil).AnyTimes()
	gomock.InOrder(
		mockWsClient.EXPECT().Connect().Return(io.EOF),
		// The backoff.Reset() method is expected to be invoked when the connection
		// is closed with io.EOF
		mockBackoff.EXPECT().Reset(),
		mockWsClient.EXPECT().Connect().Do(func() {
			// cancel the context on the 2nd connect attempt, which should stop
			// the test
			cancel()
		}).Return(io.EOF),
		mockBackoff.EXPECT().Reset().AnyTimes(),
	)
	acsSession := session{
		containerInstanceARN:            "myArn",
		credentialsProvider:             testCreds,
		agentConfig:                     testConfig,
		taskEngine:                      taskEngine,
		ecsClient:                       ecsClient,
		deregisterInstanceEventStream:   deregisterInstanceEventStream,
		dataClient:                      data.NewNoopClient(),
		taskHandler:                     taskHandler,
		backoff:                         mockBackoff,
		ctx:                             ctx,
		cancel:                          cancel,
		resources:                       &mockSessionResources{mockWsClient},
		latestSeqNumTaskManifest:        aws.Int64(10),
		_heartbeatTimeout:               20 * time.Millisecond,
		_heartbeatJitter:                10 * time.Millisecond,
		_inactiveInstanceReconnectDelay: inactiveInstanceReconnectDelay,
	}
	go func() {
		acsSession.Start()
	}()

	// Wait for context to be cancelled
	select {
	case <-ctx.Done():
	}
}

// TestHandlerReconnectsWithoutBackoffOnEOFError tests if the session handler reconnects
// to ACS after a backoff duration when the connection is closed with non io.EOF error
func TestHandlerReconnectsWithBackoffOnNonEOFError(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()

	taskEngine := mock_engine.NewMockTaskEngine(ctrl)
	taskEngine.EXPECT().Version().Return("Docker: 1.5.0", nil).AnyTimes()

	ecsClient := mock_api.NewMockECSClient(ctrl)
	ecsClient.EXPECT().DiscoverPollEndpoint(gomock.Any()).Return(acsURL, nil).AnyTimes()

	ctx, cancel := context.WithCancel(context.Background())
	taskHandler := eventhandler.NewTaskHandler(ctx, data.NewNoopClient(), nil, nil)

	deregisterInstanceEventStream := eventstream.NewEventStream("DeregisterContainerInstance", ctx)
	deregisterInstanceEventStream.StartListening()

	mockBackoff := mock_retry.NewMockBackoff(ctrl)
	mockWsClient := mock_wsclient.NewMockClientServer(ctrl)
	mockWsClient.EXPECT().SetAnyRequestHandler(gomock.Any()).AnyTimes()
	mockWsClient.EXPECT().AddRequestHandler(gomock.Any()).AnyTimes()
	mockWsClient.EXPECT().Close().Return(nil).AnyTimes()
	gomock.InOrder(
		mockWsClient.EXPECT().Connect().Return(fmt.Errorf("not EOF")),
		// The backoff.Duration() method is expected to be invoked when
		// the connection is closed with a non-EOF error code to compute
		// the backoff. Also, no calls to backoff.Reset() are expected
		// in this code path.
		mockBackoff.EXPECT().Duration().Return(time.Millisecond),
		mockWsClient.EXPECT().Connect().Do(func() {
			cancel()
		}).Return(io.EOF),
		mockBackoff.EXPECT().Reset().AnyTimes(),
	)
	acsSession := session{
		containerInstanceARN:          "myArn",
		credentialsProvider:           testCreds,
		agentConfig:                   testConfig,
		taskEngine:                    taskEngine,
		ecsClient:                     ecsClient,
		deregisterInstanceEventStream: deregisterInstanceEventStream,
		dataClient:                    data.NewNoopClient(),
		taskHandler:                   taskHandler,
		backoff:                       mockBackoff,
		ctx:                           ctx,
		cancel:                        cancel,
		resources:                     &mockSessionResources{mockWsClient},
		_heartbeatTimeout:             20 * time.Millisecond,
		_heartbeatJitter:              10 * time.Millisecond,
	}
	go func() {
		acsSession.Start()
	}()

	// Wait for context to be cancelled
	select {
	case <-ctx.Done():
	}
}

// TestHandlerGeneratesDeregisteredInstanceEvent tests if the session handler generates
// an event into the deregister instance event stream when the acs connection is closed
// with inactive instance error
func TestHandlerGeneratesDeregisteredInstanceEvent(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()
	taskEngine := mock_engine.NewMockTaskEngine(ctrl)
	taskEngine.EXPECT().Version().Return("Docker: 1.5.0", nil).AnyTimes()

	ecsClient := mock_api.NewMockECSClient(ctrl)
	ecsClient.EXPECT().DiscoverPollEndpoint(gomock.Any()).Return(acsURL, nil).AnyTimes()

	ctx, cancel := context.WithCancel(context.Background())
	taskHandler := eventhandler.NewTaskHandler(ctx, data.NewNoopClient(), nil, nil)

	deregisterInstanceEventStream := eventstream.NewEventStream("DeregisterContainerInstance", ctx)

	// receiverFunc cancels the context when invoked. Any event on the deregister
	// instance even stream would trigger this.
	receiverFunc := func(...interface{}) error {
		cancel()
		return nil
	}
	err := deregisterInstanceEventStream.Subscribe("DeregisterContainerInstance", receiverFunc)
	assert.NoError(t, err, "Error adding deregister instance event stream subscriber")
	deregisterInstanceEventStream.StartListening()
	mockWsClient := mock_wsclient.NewMockClientServer(ctrl)
	mockWsClient.EXPECT().SetAnyRequestHandler(gomock.Any()).AnyTimes()
	mockWsClient.EXPECT().AddRequestHandler(gomock.Any()).AnyTimes()
	mockWsClient.EXPECT().Close().Return(nil).AnyTimes()
	mockWsClient.EXPECT().Connect().Return(fmt.Errorf("InactiveInstanceException:"))
	inactiveInstanceReconnectDelay := 200 * time.Millisecond
	acsSession := session{
		containerInstanceARN:            "myArn",
		credentialsProvider:             testCreds,
		agentConfig:                     testConfig,
		taskEngine:                      taskEngine,
		ecsClient:                       ecsClient,
		deregisterInstanceEventStream:   deregisterInstanceEventStream,
		dataClient:                      data.NewNoopClient(),
		taskHandler:                     taskHandler,
		backoff:                         retry.NewExponentialBackoff(connectionBackoffMin, connectionBackoffMax, connectionBackoffJitter, connectionBackoffMultiplier),
		ctx:                             ctx,
		cancel:                          cancel,
		resources:                       &mockSessionResources{mockWsClient},
		_heartbeatTimeout:               20 * time.Millisecond,
		_heartbeatJitter:                10 * time.Millisecond,
		_inactiveInstanceReconnectDelay: inactiveInstanceReconnectDelay,
	}
	go func() {
		acsSession.Start()
	}()

	// Wait for context to be cancelled
	select {
	case <-ctx.Done():
	}
}

// TestHandlerReconnectDelayForInactiveInstanceError tests if the session handler applies
// the proper reconnect delay with ACS when ClientServer.Connect() returns the
// InstanceInactive error
func TestHandlerReconnectDelayForInactiveInstanceError(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()
	taskEngine := mock_engine.NewMockTaskEngine(ctrl)
	taskEngine.EXPECT().Version().Return("Docker: 1.5.0", nil).AnyTimes()

	ecsClient := mock_api.NewMockECSClient(ctrl)
	ecsClient.EXPECT().DiscoverPollEndpoint(gomock.Any()).Return(acsURL, nil).AnyTimes()

	ctx, cancel := context.WithCancel(context.Background())
	taskHandler := eventhandler.NewTaskHandler(ctx, data.NewNoopClient(), nil, nil)

	deregisterInstanceEventStream := eventstream.NewEventStream("DeregisterContainerInstance", ctx)
	deregisterInstanceEventStream.StartListening()

	mockWsClient := mock_wsclient.NewMockClientServer(ctrl)
	mockWsClient.EXPECT().SetAnyRequestHandler(gomock.Any()).AnyTimes()
	mockWsClient.EXPECT().AddRequestHandler(gomock.Any()).AnyTimes()
	mockWsClient.EXPECT().Close().Return(nil).AnyTimes()
	var firstConnectionAttemptTime time.Time
	inactiveInstanceReconnectDelay := 200 * time.Millisecond
	gomock.InOrder(
		mockWsClient.EXPECT().Connect().Do(func() {
			firstConnectionAttemptTime = time.Now()
		}).Return(fmt.Errorf("InactiveInstanceException:")),
		mockWsClient.EXPECT().Connect().Do(func() {
			reconnectDelay := time.Now().Sub(firstConnectionAttemptTime)
			reconnectDelayTime := time.Now()
			t.Logf("Delay between successive connections: %v", reconnectDelay)
			timeSubFuncSlopAllowed := 2 * time.Millisecond
			if reconnectDelay < inactiveInstanceReconnectDelay {
				// On windows platform, we found issue with time.Now().Sub(...) reporting 199.9989 even
				// after the code has already waited for time.NewTimer(200)ms.
				assert.WithinDuration(t, reconnectDelayTime, firstConnectionAttemptTime.Add(inactiveInstanceReconnectDelay), timeSubFuncSlopAllowed)
			}
			cancel()
		}).Return(io.EOF),
	)
	acsSession := session{
		containerInstanceARN:            "myArn",
		credentialsProvider:             testCreds,
		agentConfig:                     testConfig,
		taskEngine:                      taskEngine,
		ecsClient:                       ecsClient,
		deregisterInstanceEventStream:   deregisterInstanceEventStream,
		dataClient:                      data.NewNoopClient(),
		taskHandler:                     taskHandler,
		backoff:                         retry.NewExponentialBackoff(connectionBackoffMin, connectionBackoffMax, connectionBackoffJitter, connectionBackoffMultiplier),
		ctx:                             ctx,
		cancel:                          cancel,
		resources:                       &mockSessionResources{mockWsClient},
		_heartbeatTimeout:               20 * time.Millisecond,
		_heartbeatJitter:                10 * time.Millisecond,
		_inactiveInstanceReconnectDelay: inactiveInstanceReconnectDelay,
	}
	go func() {
		acsSession.Start()
	}()

	// Wait for context to be cancelled
	select {
	case <-ctx.Done():
	}
}

// TestHandlerReconnectsOnServeErrors tests if the handler retries to
// to establish the session with ACS when ClientServer.Connect() returns errors
func TestHandlerReconnectsOnServeErrors(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()
	taskEngine := mock_engine.NewMockTaskEngine(ctrl)
	taskEngine.EXPECT().Version().Return("Docker: 1.5.0", nil).AnyTimes()

	ecsClient := mock_api.NewMockECSClient(ctrl)
	ecsClient.EXPECT().DiscoverPollEndpoint(gomock.Any()).Return(acsURL, nil).AnyTimes()

	ctx, cancel := context.WithCancel(context.Background())
	taskHandler := eventhandler.NewTaskHandler(ctx, data.NewNoopClient(), nil, nil)

	mockWsClient := mock_wsclient.NewMockClientServer(ctrl)
	mockWsClient.EXPECT().SetAnyRequestHandler(gomock.Any()).AnyTimes()
	mockWsClient.EXPECT().AddRequestHandler(gomock.Any()).AnyTimes()
	mockWsClient.EXPECT().Connect().Return(nil).AnyTimes()
	mockWsClient.EXPECT().Close().Return(nil).AnyTimes()
	gomock.InOrder(
		// Serve fails 10 times
		mockWsClient.EXPECT().Serve().Return(io.EOF).Times(10),
		// Cancel trying to Serve ACS requests on the 11th attempt
		// Failure to retry on Serve() errors should cause the
		// test to time out as the context is never cancelled
		mockWsClient.EXPECT().Serve().Do(func() {
			cancel()
		}),
	)

	acsSession := session{
		containerInstanceARN: "myArn",
		credentialsProvider:  testCreds,
		agentConfig:          testConfig,
		taskEngine:           taskEngine,
		ecsClient:            ecsClient,
		dataClient:           data.NewNoopClient(),
		taskHandler:          taskHandler,
		backoff:              retry.NewExponentialBackoff(connectionBackoffMin, connectionBackoffMax, connectionBackoffJitter, connectionBackoffMultiplier),
		ctx:                  ctx,
		cancel:               cancel,
		resources:            &mockSessionResources{mockWsClient},
		_heartbeatTimeout:    20 * time.Millisecond,
		_heartbeatJitter:     10 * time.Millisecond,
	}
	go func() {
		acsSession.Start()
	}()

	// Wait for context to be cancelled
	select {
	case <-ctx.Done():
	}
}

// TestHandlerStopsWhenContextIsCancelled tests if the session's Start() method returns
// when session context is cancelled
func TestHandlerStopsWhenContextIsCancelled(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()
	taskEngine := mock_engine.NewMockTaskEngine(ctrl)
	taskEngine.EXPECT().Version().Return("Docker: 1.5.0", nil).AnyTimes()

	ecsClient := mock_api.NewMockECSClient(ctrl)
	ecsClient.EXPECT().DiscoverPollEndpoint(gomock.Any()).Return(acsURL, nil).AnyTimes()

	ctx, cancel := context.WithCancel(context.Background())
	taskHandler := eventhandler.NewTaskHandler(ctx, data.NewNoopClient(), nil, nil)

	mockWsClient := mock_wsclient.NewMockClientServer(ctrl)
	mockWsClient.EXPECT().SetAnyRequestHandler(gomock.Any()).AnyTimes()
	mockWsClient.EXPECT().AddRequestHandler(gomock.Any()).AnyTimes()
	mockWsClient.EXPECT().Connect().Return(nil).AnyTimes()
	mockWsClient.EXPECT().Close().Return(nil).AnyTimes()
	gomock.InOrder(
		mockWsClient.EXPECT().Serve().Return(io.EOF),
		mockWsClient.EXPECT().Serve().Do(func() {
			cancel()
		}).Return(errors.New("InactiveInstanceException")),
	)
	acsSession := session{
		containerInstanceARN: "myArn",
		credentialsProvider:  testCreds,
		agentConfig:          testConfig,
		taskEngine:           taskEngine,
		ecsClient:            ecsClient,
		dataClient:           data.NewNoopClient(),
		taskHandler:          taskHandler,
		backoff:              retry.NewExponentialBackoff(connectionBackoffMin, connectionBackoffMax, connectionBackoffJitter, connectionBackoffMultiplier),
		ctx:                  ctx,
		cancel:               cancel,
		resources:            &mockSessionResources{mockWsClient},
		_heartbeatTimeout:    20 * time.Millisecond,
		_heartbeatJitter:     10 * time.Millisecond,
	}

	// The session error channel would have an event when the Start() method returns
	// Cancelling the context should trigger this
	sessionError := make(chan error)
	go func() {
		sessionError <- acsSession.Start()
	}()
	<-sessionError
}

// TestHandlerReconnectsOnDiscoverPollEndpointError tests if handler retries
// to establish the session with ACS on DiscoverPollEndpoint errors
func TestHandlerReconnectsOnDiscoverPollEndpointError(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()
	taskEngine := mock_engine.NewMockTaskEngine(ctrl)
	taskEngine.EXPECT().Version().Return("Docker: 1.5.0", nil).AnyTimes()

	ecsClient := mock_api.NewMockECSClient(ctrl)
	ctx, cancel := context.WithCancel(context.Background())
	taskHandler := eventhandler.NewTaskHandler(ctx, data.NewNoopClient(), nil, nil)

	mockWsClient := mock_wsclient.NewMockClientServer(ctrl)
	mockWsClient.EXPECT().SetAnyRequestHandler(gomock.Any()).AnyTimes()
	mockWsClient.EXPECT().AddRequestHandler(gomock.Any()).AnyTimes()
	mockWsClient.EXPECT().Serve().AnyTimes()
	mockWsClient.EXPECT().Close().Return(nil).AnyTimes()
	mockWsClient.EXPECT().Connect().Do(func() {
		// Serve() cancels the context
		cancel()
	}).Return(nil).MinTimes(1)

	gomock.InOrder(
		// DiscoverPollEndpoint returns an error on its first invocation
		ecsClient.EXPECT().DiscoverPollEndpoint(gomock.Any()).Return("", fmt.Errorf("oops")).Times(1),
		// Second invocation returns a success
		ecsClient.EXPECT().DiscoverPollEndpoint(gomock.Any()).Return(acsURL, nil).Times(1),
	)
	acsSession := session{
		containerInstanceARN: "myArn",
		credentialsProvider:  testCreds,
		agentConfig:          testConfig,
		taskEngine:           taskEngine,
		ecsClient:            ecsClient,
		dataClient:           data.NewNoopClient(),
		taskHandler:          taskHandler,
		backoff:              retry.NewExponentialBackoff(connectionBackoffMin, connectionBackoffMax, connectionBackoffJitter, connectionBackoffMultiplier),
		ctx:                  ctx,
		cancel:               cancel,
		resources:            &mockSessionResources{mockWsClient},
		_heartbeatTimeout:    20 * time.Millisecond,
		_heartbeatJitter:     10 * time.Millisecond,
	}
	go func() {
		acsSession.Start()
	}()
	start := time.Now()

	// Wait for context to be cancelled
	select {
	case <-ctx.Done():
	}

	// Measure the duration between retries
	timeSinceStart := time.Since(start)
	if timeSinceStart < connectionBackoffMin {
		t.Errorf("Duration since start is less than minimum threshold for backoff: %s", timeSinceStart.String())
	}

	// The upper limit here should really be connectionBackoffMin + (connectionBackoffMin * jitter)
	// But, it can be off by a few milliseconds to account for execution of other instructions
	// In any case, it should never be higher than 4*connectionBackoffMin
	if timeSinceStart > 4*connectionBackoffMin {
		t.Errorf("Duration since start is greater than maximum anticipated wait time: %v", timeSinceStart.String())
	}
}

// TestConnectionIsClosedOnIdle tests if the connection to ACS is closed
// when the channel is idle
func TestConnectionIsClosedOnIdle(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()
	taskEngine := mock_engine.NewMockTaskEngine(ctrl)
	taskEngine.EXPECT().Version().Return("Docker: 1.5.0", nil).AnyTimes()

	ecsClient := mock_api.NewMockECSClient(ctrl)
	ctx, cancel := context.WithCancel(context.Background())
	taskHandler := eventhandler.NewTaskHandler(ctx, data.NewNoopClient(), nil, nil)
	defer cancel()

	wait := sync.WaitGroup{}
	wait.Add(1)
	mockWsClient := mock_wsclient.NewMockClientServer(ctrl)
	mockWsClient.EXPECT().SetAnyRequestHandler(gomock.Any()).Do(func(v interface{}) {}).AnyTimes()
	mockWsClient.EXPECT().AddRequestHandler(gomock.Any()).Do(func(v interface{}) {}).AnyTimes()
	mockWsClient.EXPECT().Connect().Return(nil)
	mockWsClient.EXPECT().Serve().Do(func() {
		wait.Done()
		// Pretend as if the maximum heartbeatTimeout duration has
		// been breached while Serving requests
		time.Sleep(30 * time.Millisecond)
	}).Return(io.EOF)

	connectionClosed := make(chan bool)
	mockWsClient.EXPECT().Close().Do(func() {
		wait.Wait()
		// Record connection closed
		connectionClosed <- true
	}).Return(nil)
	acsSession := session{
		containerInstanceARN: "myArn",
		credentialsProvider:  testCreds,
		agentConfig:          testConfig,
		taskEngine:           taskEngine,
		ecsClient:            ecsClient,
		dataClient:           data.NewNoopClient(),
		taskHandler:          taskHandler,
		ctx:                  context.Background(),
		backoff:              retry.NewExponentialBackoff(connectionBackoffMin, connectionBackoffMax, connectionBackoffJitter, connectionBackoffMultiplier),
		resources:            &mockSessionResources{},
		_heartbeatTimeout:    20 * time.Millisecond,
		_heartbeatJitter:     10 * time.Millisecond,
	}
	go acsSession.startACSSession(mockWsClient)

	// Wait for connection to be closed. If the connection is not closed
	// due to inactivity, the test will time out
	<-connectionClosed
}

func TestHandlerDoesntLeakGoroutines(t *testing.T) {
	// Skip this test on "windows" platform as we have observed this to
	// fail often after upgrading the windows builds to golang v1.17.
	if runtime.GOOS == "windows" {
		t.Skip()
	}
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()
	taskEngine := mock_engine.NewMockTaskEngine(ctrl)
	dockerClient := mock_dockerapi.NewMockDockerClient(ctrl)
	ecsClient := mock_api.NewMockECSClient(ctrl)
	ctx, cancel := context.WithCancel(context.Background())
	taskHandler := eventhandler.NewTaskHandler(ctx, data.NewNoopClient(), nil, nil)

	closeWS := make(chan bool)
	server, serverIn, requests, errs, err := startMockAcsServer(t, closeWS)
	if err != nil {
		t.Fatal(err)
	}
	go func() {
		for {
			select {
			case <-requests:
			case <-errs:
			case <-ctx.Done():
				return
			}
		}
	}()

	timesConnected := 0
	ecsClient.EXPECT().DiscoverPollEndpoint("myArn").Return(server.URL, nil).AnyTimes().Do(func(_ interface{}) {
		timesConnected++
	})
	taskEngine.EXPECT().Version().Return("Docker: 1.5.0", nil).AnyTimes()
	taskEngine.EXPECT().AddTask(gomock.Any()).AnyTimes()
	dockerClient.EXPECT().SystemPing(gomock.Any(), gomock.Any()).AnyTimes()

	emptyHealthchecksList := []doctor.Healthcheck{}
	emptyDoctor, _ := doctor.NewDoctor(emptyHealthchecksList, "test-cluster", "this:is:an:instance:arn")

	ended := make(chan bool, 1)
	go func() {

		acsSession := session{
			containerInstanceARN:     "myArn",
			credentialsProvider:      testCreds,
			agentConfig:              testConfig,
			taskEngine:               taskEngine,
			dockerClient:             dockerClient,
			ecsClient:                ecsClient,
			dataClient:               data.NewNoopClient(),
			taskHandler:              taskHandler,
			ctx:                      ctx,
			_heartbeatTimeout:        1 * time.Second,
			backoff:                  retry.NewExponentialBackoff(connectionBackoffMin, connectionBackoffMax, connectionBackoffJitter, connectionBackoffMultiplier),
			resources:                newSessionResources(testCreds),
			credentialsManager:       rolecredentials.NewManager(),
			latestSeqNumTaskManifest: aws.Int64(12),
			doctor:                   emptyDoctor,
		}
		acsSession.Start()
		ended <- true
	}()
	// Warm it up
	serverIn <- `{"type":"HeartbeatMessage","message":{"healthy":true,"messageId":"123"}}`
	serverIn <- samplePayloadMessage

	beforeGoroutines := runtime.NumGoroutine()
	for i := 0; i < 40; i++ {
		serverIn <- `{"type":"HeartbeatMessage","message":{"healthy":true,"messageId":"123"}}`
		serverIn <- samplePayloadMessage
		closeWS <- true
	}

	cancel()
	<-ended

	// The number of goroutines finishing in the MockACSServer will affect
	// the result unless we wait here.
	time.Sleep(2 * time.Second)
	afterGoroutines := runtime.NumGoroutine()

	t.Logf("Goroutines after 1 and after %v acs messages: %v and %v", timesConnected, beforeGoroutines, afterGoroutines)

	if timesConnected < 20 {
		t.Fatal("Expected times connected to be a large number, was ", timesConnected)
	}
	if afterGoroutines > beforeGoroutines+2 {
		t.Error("Goroutine leak, oh no!")
		pprof.Lookup("goroutine").WriteTo(os.Stdout, 1)
	}

}

// TestStartSessionHandlesRefreshCredentialsMessages tests the agent restart
// scenario where the payload to refresh credentials is processed immediately on
// connection establishment with ACS
func TestStartSessionHandlesRefreshCredentialsMessages(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()
	taskEngine := mock_engine.NewMockTaskEngine(ctrl)
	ecsClient := mock_api.NewMockECSClient(ctrl)
	ctx, cancel := context.WithCancel(context.Background())
	taskHandler := eventhandler.NewTaskHandler(ctx, data.NewNoopClient(), nil, nil)
	closeWS := make(chan bool)
	server, serverIn, requestsChan, errChan, err := startMockAcsServer(t, closeWS)
	if err != nil {
		t.Fatal(err)
	}
	defer close(serverIn)

	go func() {
		for {
			select {
			case <-requestsChan:
				// Cancel the context when we get the ack request
				cancel()
			}
		}
	}()

	// DiscoverPollEndpoint returns the URL for the server that we started
	ecsClient.EXPECT().DiscoverPollEndpoint("myArn").Return(server.URL, nil).Times(1)
	taskEngine.EXPECT().Version().Return("Docker: 1.5.0", nil).AnyTimes()

	credentialsManager := mock_credentials.NewMockManager(ctrl)
	dockerClient := mock_dockerapi.NewMockDockerClient(ctrl)

	emptyHealthchecksList := []doctor.Healthcheck{}
	emptyDoctor, _ := doctor.NewDoctor(emptyHealthchecksList, "test-cluster", "this:is:a:container:arn")

	latestSeqNumberTaskManifest := int64(10)
	ended := make(chan bool, 1)
	go func() {
		acsSession := NewSession(ctx,
			testConfig,
			nil,
			"myArn",
			testCreds,
			dockerClient,
			ecsClient,
			dockerstate.NewTaskEngineState(),
			data.NewNoopClient(),
			taskEngine,
			credentialsManager,
			taskHandler,
			&latestSeqNumberTaskManifest,
			emptyDoctor,
		)
		acsSession.Start()
		// StartSession should never return unless the context is canceled
		ended <- true
	}()

	updatedCredentials := rolecredentials.TaskIAMRoleCredentials{}
	taskFromEngine := &apitask.Task{}
	credentialsIdInRefreshMessage := "credsId"
	// Ensure that credentials manager interface methods are invoked in the
	// correct order, with expected arguments
	gomock.InOrder(
		// Return a task from the engine for GetTaskByArn
		taskEngine.EXPECT().GetTaskByArn("t1").Return(taskFromEngine, true),
		// The last invocation of SetCredentials is to update
		// credentials when a refresh message is received by the handler
		credentialsManager.EXPECT().SetTaskCredentials(gomock.Any()).Do(func(creds *rolecredentials.TaskIAMRoleCredentials) {
			updatedCredentials = *creds
			// Validate parsed credentials after the update
			expectedCreds := rolecredentials.TaskIAMRoleCredentials{
				ARN: "t1",
				IAMRoleCredentials: rolecredentials.IAMRoleCredentials{
					RoleArn:         "r1",
					AccessKeyID:     "newakid",
					SecretAccessKey: "newskid",
					SessionToken:    "newstkn",
					Expiration:      "later",
					CredentialsID:   credentialsIdInRefreshMessage,
					RoleType:        "TaskApplication",
				},
			}
			if !reflect.DeepEqual(updatedCredentials, expectedCreds) {
				t.Errorf("Mismatch between expected and credentials expected: %v, added: %v", expectedCreds, updatedCredentials)
			}
		}).Return(nil),
	)
	serverIn <- sampleRefreshCredentialsMessage

	select {
	case err := <-errChan:
		t.Fatal("Error should not have been returned from server", err)
	case <-ctx.Done():
		// Context is canceled when requestsChan receives an ack
	}

	// Validate that the correct credentialsId is set for the task
	credentialsIdFromTask := taskFromEngine.GetCredentialsID()
	if credentialsIdFromTask != credentialsIdInRefreshMessage {
		t.Errorf("Mismatch between expected and added credentials id for task, expected: %s, added: %s", credentialsIdInRefreshMessage, credentialsIdFromTask)
	}

	server.Close()
	// Cancel context should close the session
	<-ended
}

// TestACSSessionResourcesCorrectlySetsSendCredentials tests if acsSessionResources
// struct correctly sets 'sendCredentials'
func TestACSSessionResourcesCorrectlySetsSendCredentials(t *testing.T) {
	acsResources := newSessionResources(nil)
	// Validate that 'sendCredentials' is set to true on create
	sendCredentials := acsResources.getSendCredentialsURLParameter()
	if sendCredentials != "true" {
		t.Errorf("Mismatch in sendCredentials URL parameter value, expected: 'true', got: %s", sendCredentials)
	}
	// Simulate a successful connection to ACS
	acsResources.connectedToACS()
	// On successful connection to ACS, 'sendCredentials' should be set to false
	sendCredentials = acsResources.getSendCredentialsURLParameter()
	if sendCredentials != "false" {
		t.Errorf("Mismatch in sendCredentials URL parameter value, expected: 'false', got: %s", sendCredentials)
	}
}

// TestHandlerReconnectsCorrectlySetsSendCredentialsURLParameter tests if
// the 'sendCredentials' URL parameter is set correctly for successive
// invocations of startACSSession
func TestHandlerReconnectsCorrectlySetsSendCredentialsURLParameter(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()
	taskEngine := mock_engine.NewMockTaskEngine(ctrl)
	ecsClient := mock_api.NewMockECSClient(ctrl)
	ctx, cancel := context.WithCancel(context.Background())
	taskHandler := eventhandler.NewTaskHandler(ctx, data.NewNoopClient(), nil, nil)

	mockWsClient := mock_wsclient.NewMockClientServer(ctrl)
	mockWsClient.EXPECT().SetAnyRequestHandler(gomock.Any()).AnyTimes()
	mockWsClient.EXPECT().AddRequestHandler(gomock.Any()).AnyTimes()
	mockWsClient.EXPECT().Close().Return(nil).AnyTimes()
	mockWsClient.EXPECT().Serve().Return(io.EOF).AnyTimes()

	dockerClient := mock_dockerapi.NewMockDockerClient(ctrl)
	resources := newSessionResources(testCreds)
	gomock.InOrder(
		// When the websocket client connects to ACS for the first
		// time, 'sendCredentials' should be set to true
		mockWsClient.EXPECT().Connect().Do(func() {
			validateSendCredentialsInSession(t, resources, "true")
		}).Return(nil),
		// For all subsequent connections to ACS, 'sendCredentials'
		// should be set to false
		mockWsClient.EXPECT().Connect().Do(func() {
			validateSendCredentialsInSession(t, resources, "false")
		}).Return(nil).AnyTimes(),
	)

	acsSession := session{
		containerInstanceARN: "myArn",
		credentialsProvider:  testCreds,
		agentConfig:          testConfig,
		taskEngine:           taskEngine,
		dockerClient:         dockerClient,
		ecsClient:            ecsClient,
		dataClient:           data.NewNoopClient(),
		taskHandler:          taskHandler,
		ctx:                  ctx,
		resources:            resources,
		backoff:              retry.NewExponentialBackoff(connectionBackoffMin, connectionBackoffMax, connectionBackoffJitter, connectionBackoffMultiplier),
		_heartbeatTimeout:    20 * time.Millisecond,
		_heartbeatJitter:     10 * time.Millisecond,
	}
	go func() {
		for i := 0; i < 10; i++ {
			acsSession.startACSSession(mockWsClient)
		}
		cancel()
	}()

	// Wait for context to be cancelled
	select {
	case <-ctx.Done():
	}
}

// TODO: replace with gomock
func startMockAcsServer(t *testing.T, closeWS <-chan bool) (*httptest.Server, chan<- string, <-chan string, <-chan error, error) {
	serverChan := make(chan string, 1)
	requestsChan := make(chan string, 1)
	errChan := make(chan error, 1)

	upgrader := websocket.Upgrader{ReadBufferSize: 1024, WriteBufferSize: 1024}
	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		ws, err := upgrader.Upgrade(w, r, nil)

		if err != nil {
			errChan <- err
		}

		go func() {
			_, msg, err := ws.ReadMessage()
			if err != nil {
				errChan <- err
			} else {
				requestsChan <- string(msg)
			}
		}()
		for {
			select {
			case str := <-serverChan:
				err := ws.WriteMessage(websocket.TextMessage, []byte(str))
				if err != nil {
					errChan <- err
				}

			case <-closeWS:
				ws.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
				ws.Close()
				errChan <- io.EOF
				// Quit listening to serverChan if we've been closed
				return
			}

		}
	})

	server := httptest.NewTLSServer(handler)
	return server, serverChan, requestsChan, errChan, nil
}

// validateAddedTask validates fields in addedTask for expected values
// It returns an error if there's a mismatch
func validateAddedTask(expectedTask apitask.Task, addedTask apitask.Task) error {
	// The ecsacs.Task -> apitask.Task conversion initializes all fields in apitask.Task
	// with empty objects. So, we create a new object to compare with only those
	// fields that we are intrested in for comparison
	taskToCompareFromAdded := apitask.Task{
		Arn:                 addedTask.Arn,
		Family:              addedTask.Family,
		Version:             addedTask.Version,
		DesiredStatusUnsafe: addedTask.GetDesiredStatus(),
		StartSequenceNumber: addedTask.StartSequenceNumber,
	}

	if !reflect.DeepEqual(expectedTask, taskToCompareFromAdded) {
		return fmt.Errorf("Mismatch between added and expected task: expected: %v, added: %v", expectedTask, taskToCompareFromAdded)
	}

	return nil
}

// validateAddedContainer validates fields in addedContainer for expected values
// It returns an error if there's a mismatch
func validateAddedContainer(expectedContainer *apicontainer.Container, addedContainer *apicontainer.Container) error {
	// The ecsacs.Task -> apitask.Task conversion initializes all fields in apicontainer.Container
	// with empty objects. So, we create a new object to compare with only those
	// fields that we are intrested in for comparison
	containerToCompareFromAdded := &apicontainer.Container{
		Name:      addedContainer.Name,
		CPU:       addedContainer.CPU,
		Essential: addedContainer.Essential,
		Memory:    addedContainer.Memory,
		Image:     addedContainer.Image,
	}
	if !reflect.DeepEqual(expectedContainer, containerToCompareFromAdded) {
		return fmt.Errorf("Mismatch between added and expected container: expected: %v, added: %v", expectedContainer, containerToCompareFromAdded)
	}
	return nil
}

func validateSendCredentialsInSession(t *testing.T, state sessionState, expected string) {
	sendCredentials := state.getSendCredentialsURLParameter()
	if sendCredentials != expected {
		t.Errorf("Incorrect value set for sendCredentials, expected: %s, got: %s", expected, sendCredentials)
	}
}


text:
extern "C"
{
	AIUnicodeStringSuite*	sAIUnicodeString = nullptr;
	SPBlocksSuite*			sSPBlocks = nullptr;
	AIFileFormatSuite*		sAIFileFormat = nullptr;
	AIDocumentSuite*		sAIDocument = nullptr;
	AITextFrameSuite*		sAITextFrame = nullptr;
	AIArtSuite*				sAIArt = nullptr;
	AIPathSuite*			sAIPath = nullptr;
	AIMatchingArtSuite*		sAIMatchingArt = nullptr;
	AIMdMemorySuite*		sAIMdMemory = nullptr;
	EXTERN_TEXT_SUITES

	// Added for Ai2Canvas functionality
	AIPathStyleSuite *sAIPathStyle = nullptr;
	AIHardSoftSuite *sAIHardSoft = nullptr;
	AIRealMathSuite *sAIRealMath = nullptr;
	AIGradientSuite *sAIGradient = nullptr;
	AIMaskSuite *sAIMask = nullptr;
	AIPluginGroupSuite *sAIPluginGroup = nullptr;
	AICustomColorSuite *sAICustomColor = nullptr;
	AIColorConversionSuite *sAIColorConversion = nullptr;
	AIBlendStyleSuite *sAIBlendStyle = nullptr;
	AILayerSuite *sAILayer = nullptr;
	AIATEPaintSuite *sATEPaint = nullptr;
	AIFontSuite *sAIFont = nullptr;
	AIATETextUtilSuite *sATETextUtil = nullptr;
	AIDataFilterSuite *sAIDataFilter = nullptr;
	AISymbolSuite *sAISymbol = nullptr;
	AIPatternSuite *sAIPattern = nullptr;
	AIPlacedSuite *sAIPlaced = nullptr;
	AIRasterSuite *sAIRaster = nullptr;
	AIImageOptSuite *sAIImageOpt = nullptr;
	AIArtStyleSuite *sAIArtStyle = nullptr;
	AIArtStyleParserSuite *sAIArtStyleParser = nullptr;
	AILiveEffectSuite *sAILiveEffect = nullptr;
	AIDictionarySuite *sAIDictionary = nullptr;
	AIDictionaryIteratorSuite *sAIDictionaryIterator = nullptr;
	AIEntrySuite *sAIEntry = nullptr;
	AIRealBezierSuite *sAIRealBezier = nullptr;
};

ImportSuite gImportSuites[] =
{
	kAIUnicodeStringSuite, kAIUnicodeStringSuiteVersion, &sAIUnicodeString,
	kSPBlocksSuite, kSPBlocksSuiteVersion, &sSPBlocks,
	kAIFileFormatSuite, kAIFileFormatVersion, &sAIFileFormat,
	kAIDocumentSuite, kAIDocumentVersion, &sAIDocument,
	kAITextFrameSuite, kAITextFrameVersion, &sAITextFrame,
	kAIArtSuite, kAIArtSuiteVersion, &sAIArt,
	kAIPathSuite, kAIPathVersion, &sAIPath,
	kAIMatchingArtSuite, kAIMatchingArtVersion, &sAIMatchingArt,
	kAIMdMemorySuite, kAIMdMemorySuiteVersion, &sAIMdMemory,

	// Added for Ai2Canvas functionality
	kAIPathStyleSuite, kAIPathStyleVersion, &sAIPathStyle,
	kAIHardSoftSuite, kAIHardSoftVersion, &sAIHardSoft,
	kAIRealMathSuite, kAIRealMathVersion, &sAIRealMath,
	kAIGradientSuite, kAIGradientVersion, &sAIGradient,
	kAIMaskSuite, kAIMaskVersion, &sAIMask,
	kAIPluginGroupSuite, kAIPluginGroupVersion, &sAIPluginGroup,
	kAICustomColorSuite, kAICustomColorVersion, &sAICustomColor,
	kAIColorConversionSuite, kAIColorConversionVersion, &sAIColorConversion,
	kAIBlendStyleSuite, kAIBlendStyleVersion, &sAIBlendStyle,
	kAILayerSuite, kAILayerVersion, &sAILayer,
	kAIATEPaintSuite, kAIATEPaintSuiteVersion, &sATEPaint,
	kAIFontSuite, kAIFontSuiteVersion, &sAIFont,
	kAIATETextUtilSuite, kAIATETextUtilSuiteVersion, &sATETextUtil,
	kAIDataFilterSuite, kAIDataFilterSuiteVersion, &sAIDataFilter,
	kAISymbolSuite, kAISymbolSuiteVersion, &sAISymbol,
	kAIPatternSuite, kAIPatternSuiteVersion, &sAIPattern,
	kAIPlacedSuite, kAIPlacedSuiteVersion, &sAIPlaced,
	kAIRasterSuite, kAIRasterSuiteVersion, &sAIRaster,
	kAIArtStyleSuite, kAIArtStyleSuiteVersion, &sAIArtStyle,
    kAIArtStyleParserSuite, kAIArtStyleParserSuiteVersion, &sAIArtStyleParser,
	kAILiveEffectSuite, kAILiveEffectSuiteVersion, &sAILiveEffect,
	kAIDictionarySuite, kAIDictionarySuiteVersion, &sAIDictionary,
	kAIDictionaryIteratorSuite, kAIDictionaryIteratorSuiteVersion, &sAIDictionaryIterator,
	kAIEntrySuite, kAIEntrySuiteVersion, &sAIEntry,
	kAIImageOptSuite, kAIImageOptSuiteVersion, &sAIImageOpt,
	kAIRealBezierSuite, kAIRealBezierSuiteVersion, &sAIRealBezier,

	IMPORT_TEXT_SUITES
	nullptr, 0, nullptr
};

// End Ai2CanvasSuites.cpp


text:
vsts extension to run and report coverage using nunit3 and OpenCover on TFS 2015

![buildresultssummary](https://cloud.githubusercontent.com/assets/16986510/16158215/9121d88c-34bc-11e6-8514-981edcf0581c.png)

![buildresultsdetails](https://cloud.githubusercontent.com/assets/16986510/16158177/6ac3b3c2-34bc-11e6-9728-5d59f63f9b90.png)

[How to use...](docs/usage.md)

[How to build from sources...](docs/build.md)


text:
module ShouldFail where

-- GHC < 5.01 used to get the line number wrong.
f (f f) = f

g = g


text:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical" >

    <ListView
        android:id="@+id/ab_drop_menu_lv"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:cacheColorHint="@android:color/transparent"
        android:divider="#333333"
        android:dividerHeight="0.8dp"
        android:listSelector="@android:color/transparent" />

</LinearLayout>


text:
@interface TableViewController () <TableViewCellDelegate>

@end

@implementation TableViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    [self cd_startObserveProtocols:@[@protocol(TableViewCellDelegate),
                                     @protocol(AnotherTableViewCellDelegate)]];
    [self printProtocols];

}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

- (void)viewWillDisappear:(BOOL)animated {
    [self cd_stopObserve];
}

#pragma mark - Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return 100;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"reuseIdentifier" forIndexPath:indexPath];

    return cell;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
//    UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
//    NSArray *responderChain = [cell cd_responderChain];
//    NSMutableString *string =  [NSMutableString new];
//    for (UIResponder *responder in responderChain) {
//        NSString *nextStr = [responderChain lastObject] == responder ? @""  : @"->";
//        NSString *str = [NSString stringWithFormat:@"%@%@", [responder class], nextStr];
//        [string appendString:str];
//    }
//    NSLog(@"%@", string);
}

- (void)didPressButton:(UIButton *)button onCell:(TableViewCell *)cell {
    self.navigationController.navigationBar.barTintColor = [[UIColor randomColor] colorWithAlphaComponent:0.5];
}

- (void)didSwitch:(UISwitch *)sender {
    self.view.backgroundColor = sender.isOn ? [UIColor redColor] : [UIColor whiteColor];
}

- (void)didChangedSliderValue:(CGFloat)value {
    self.navigationController.navigationBar.alpha = value;
}

- (void)printProtocols {
    NSArray *array = [[CDProtocol protocolFromObjCProtocol:@protocol(UITableViewDelegate)] selectors];
    NSLog(@"%@", array);
}

@end


text:
Color relief or hypsometric tints depict elevation as bands of color, to enhance elevation zones so map readers can better see differences in relief. The colors selected for the tints are assumed to relate to the ground cover typically found at various elevations in the area being mapped. A typical color scheme progresses from dark greens for lower elevations up through yellows/browns, and on to grays and white at the highest elevations - [Bjørn Sandvik](http://blog.thematicmapping.org/2012/06/creating-color-relief-and-slope-shading.html).

In order to create color our DEM, we need to create colored breaks for a selected number of elevation bins. First, let's check what the min and max values are using the `gdalinfo` command with the `-stats` flag:

```
gdalinfo sf-dem.tif -stats
```

We should get something like this:

```
Josephs-MacBook-Pro-2:XX_digital_elevation_models Jozo$ gdalinfo sf-dem.tif -stats
Driver: GTiff/GeoTIFF
Files: sf-dem.tif
Size is 676, 675
Coordinate System is:
GEOGCS["NAD83",
    DATUM["North_American_Datum_1983",
        SPHEROID["GRS 1980",6378137,298.2572221010002,
            AUTHORITY["EPSG","7019"]],
        TOWGS84[0,0,0,0,0,0,0],
        AUTHORITY["EPSG","6269"]],
    PRIMEM["Greenwich",0],
    UNIT["degree",0.0174532925199433],
    AUTHORITY["EPSG","4269"]]
Origin = (-122.437530223697820,37.812525827311823)
Pixel Size = (0.000092539239086,-0.000092652993030)
Metadata:
  AREA_OR_POINT=Area
Image Structure Metadata:
  INTERLEAVE=BAND
Corner Coordinates:
Upper Left  (-122.4375302,  37.8125258) (122d26'15.11"W, 37d48'45.09"N)
Lower Left  (-122.4375302,  37.7499851) (122d26'15.11"W, 37d44'59.95"N)
Upper Right (-122.3749737,  37.8125258) (122d22'29.91"W, 37d48'45.09"N)
Lower Right (-122.3749737,  37.7499851) (122d22'29.91"W, 37d44'59.95"N)
Center      (-122.4062520,  37.7812554) (122d24'22.51"W, 37d46'52.52"N)
Band 1 Block=676x3 Type=Float32, ColorInterp=Gray
  Minimum=-2.314, Maximum=126.607, Mean=19.995, StdDev=24.762
  NoData Value=-9999
  Metadata:
    STATISTICS_MAXIMUM=126.60684204102
    STATISTICS_MEAN=19.995340656419
    STATISTICS_MINIMUM=-2.3140776157379
    STATISTICS_STDDEV=24.762441881228
```

We can see that: `Min=-2.4` and `Max=126.7`. Using this information we can make some elevation breaks and some corresponding colors for each break. The example below shows how gdal will use apply a color to the pixels with the corresponding elevation.

```
elev1 r g b
elev2 r g b
elev3 r g b
elev4 r g b
...
```

Make a `color-relief.txt` using the `echo` command, like so. In this case, `echo` takes everything between the quotations and stuffs it into a file called `color-relief.txt` usng the `>` operator:

```
echo '0 0 0 0
26 110 220 110
51 240 250 160
76 230 220 170
101 220 220 220
127 250 250 250' > color-relief.txt
```

Now we can generate our colored relief:

```
gdaldem color-relief -of PNG sf-dem.tif color-relief.txt sf-dem-coloredRelief.tif
```


text:
using content::BrowserThread;

// A bridge from ManagedMode (which lives on the UI thread) to
// ManagedModeURLFilter (which might live on a different thread).
class ManagedMode::URLFilterContext {
 public:
  explicit URLFilterContext(
      scoped_refptr<base::SequencedTaskRunner> task_runner)
      : task_runner_(task_runner) {}
  ~URLFilterContext() {}

  const ManagedModeURLFilter* url_filter() const {
    DCHECK(task_runner_->RunsTasksOnCurrentThread());
    return &url_filter_;
  }

  void SetDefaultFilteringBehavior(
      ManagedModeURLFilter::FilteringBehavior behavior) {
    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    // Because ManagedMode is a singleton, we can pass the pointer to
    // |url_filter_| unretained.
    task_runner_->PostTask(
        FROM_HERE,
        base::Bind(&ManagedModeURLFilter::SetDefaultFilteringBehavior,
                   base::Unretained(&url_filter_),
                   behavior));
  }

  void LoadWhitelists(ScopedVector<ManagedModeSiteList> site_lists) {
    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    task_runner_->PostTask(FROM_HERE,
                           base::Bind(&ManagedModeURLFilter::LoadWhitelists,
                                      base::Unretained(&url_filter_),
                                      base::Passed(&site_lists),
                                      base::Bind(&base::DoNothing)));
  }

  void ShutdownOnUIThread() {
    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    bool result = task_runner_->DeleteSoon(FROM_HERE, this);
    DCHECK(result);
  }

 private:
  ManagedModeURLFilter url_filter_;
  scoped_refptr<base::SequencedTaskRunner> task_runner_;

  DISALLOW_COPY_AND_ASSIGN(URLFilterContext);
};

// static
ManagedMode* ManagedMode::GetInstance() {
  return Singleton<ManagedMode, LeakySingletonTraits<ManagedMode> >::get();
}

// static
void ManagedMode::RegisterPrefs(PrefService* prefs) {
  prefs->RegisterBooleanPref(prefs::kInManagedMode, false);
}

// static
void ManagedMode::RegisterUserPrefs(PrefService* prefs) {
  prefs->RegisterIntegerPref(prefs::kDefaultManagedModeFilteringBehavior,
                             2,
                             PrefService::UNSYNCABLE_PREF);
}

// static
void ManagedMode::Init(Profile* profile) {
  GetInstance()->InitImpl(profile);
}

void ManagedMode::InitImpl(Profile* profile) {
  DCHECK(g_browser_process);
  DCHECK(g_browser_process->local_state());

  Profile* original_profile = profile->GetOriginalProfile();
  // Set the value directly in the PrefService instead of using
  // CommandLinePrefStore so we can change it at runtime.
  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kNoManaged)) {
    SetInManagedMode(NULL);
  } else if (IsInManagedModeImpl() ||
      CommandLine::ForCurrentProcess()->HasSwitch(switches::kManaged)) {
    SetInManagedMode(original_profile);
  }
}

// static
bool ManagedMode::IsInManagedMode() {
  return GetInstance()->IsInManagedModeImpl();
}

bool ManagedMode::IsInManagedModeImpl() const {
  // |g_browser_process| can be NULL during startup.
  if (!g_browser_process)
    return false;
  // Local State can be NULL during unit tests.
  if (!g_browser_process->local_state())
    return false;
  return g_browser_process->local_state()->GetBoolean(prefs::kInManagedMode);
}

// static
void ManagedMode::EnterManagedMode(Profile* profile,
                                   const EnterCallback& callback) {
  GetInstance()->EnterManagedModeImpl(profile, callback);
}

void ManagedMode::EnterManagedModeImpl(Profile* profile,
                                       const EnterCallback& callback) {
  Profile* original_profile = profile->GetOriginalProfile();
  if (IsInManagedModeImpl()) {
    callback.Run(original_profile == managed_profile_);
    return;
  }
  if (!callbacks_.empty()) {
    // We are already in the process of entering managed mode, waiting for
    // browsers to close. Don't allow entering managed mode again for a
    // different profile, and queue the callback for the same profile.
    if (original_profile != managed_profile_)
      callback.Run(false);
    else
      callbacks_.push_back(callback);
    return;
  }

  if (!PlatformConfirmEnter()) {
    callback.Run(false);
    return;
  }
  // Close all other profiles.
  // At this point, we shouldn't be waiting for other browsers to close (yet).
  DCHECK_EQ(0u, browsers_to_close_.size());
  for (BrowserList::const_iterator i = BrowserList::begin();
       i != BrowserList::end(); ++i) {
    if ((*i)->profile()->GetOriginalProfile() != original_profile)
      browsers_to_close_.insert(*i);
  }

  if (browsers_to_close_.empty()) {
    SetInManagedMode(original_profile);
    callback.Run(true);
    return;
  }
  // Remember the profile we're trying to manage while we wait for other
  // browsers to close.
  managed_profile_ = original_profile;
  callbacks_.push_back(callback);
  registrar_.Add(this, chrome::NOTIFICATION_CLOSE_ALL_BROWSERS_REQUEST,
                 content::NotificationService::AllSources());
  registrar_.Add(this, chrome::NOTIFICATION_BROWSER_CLOSE_CANCELLED,
                 content::NotificationService::AllSources());
  for (std::set<Browser*>::const_iterator i = browsers_to_close_.begin();
       i != browsers_to_close_.end(); ++i) {
    (*i)->window()->Close();
  }
}

// static
void ManagedMode::LeaveManagedMode() {
  GetInstance()->LeaveManagedModeImpl();
}

void ManagedMode::LeaveManagedModeImpl() {
  bool confirmed = PlatformConfirmLeave();
  if (confirmed)
    SetInManagedMode(NULL);
}

// static
const ManagedModeURLFilter* ManagedMode::GetURLFilterForIOThread() {
  return GetInstance()->GetURLFilterForIOThreadImpl();
}

// static
const ManagedModeURLFilter* ManagedMode::GetURLFilterForUIThread() {
  return GetInstance()->GetURLFilterForUIThreadImpl();
}

const ManagedModeURLFilter* ManagedMode::GetURLFilterForIOThreadImpl() {
  return io_url_filter_context_->url_filter();
}

const ManagedModeURLFilter* ManagedMode::GetURLFilterForUIThreadImpl() {
  return ui_url_filter_context_->url_filter();
}

std::string ManagedMode::GetDebugPolicyProviderName() const {
  // Save the string space in official builds.
#ifdef NDEBUG
  NOTREACHED();
  return std::string();
#else
  return "Managed Mode";
#endif
}

bool ManagedMode::UserMayLoad(const extensions::Extension* extension,
                              string16* error) const {
  string16 tmp_error;
  if (ExtensionManagementPolicyImpl(&tmp_error))
    return true;

  // If the extension is already loaded, we allow it, otherwise we'd unload
  // all existing extensions.
  ExtensionService* extension_service =
      extensions::ExtensionSystem::Get(managed_profile_)->extension_service();

  // |extension_service| can be NULL in a unit test.
  if (extension_service &&
      extension_service->GetInstalledExtension(extension->id()))
    return true;

  if (error)
    *error = tmp_error;
  return false;
}

bool ManagedMode::UserMayModifySettings(const extensions::Extension* extension,
                                        string16* error) const {
  return ExtensionManagementPolicyImpl(error);
}

bool ManagedMode::ExtensionManagementPolicyImpl(string16* error) const {
  if (!IsInManagedModeImpl())
    return true;

  if (error)
    *error = l10n_util::GetStringUTF16(IDS_EXTENSIONS_LOCKED_MANAGED_MODE);
  return false;
}

void ManagedMode::OnBrowserAdded(Browser* browser) {
  // Return early if we don't have any queued callbacks.
  if (callbacks_.empty())
    return;

  DCHECK(managed_profile_);
  if (browser->profile()->GetOriginalProfile() != managed_profile_)
    FinalizeEnter(false);
}

void ManagedMode::OnBrowserRemoved(Browser* browser) {
  // Return early if we don't have any queued callbacks.
  if (callbacks_.empty())
    return;

  DCHECK(managed_profile_);
  if (browser->profile()->GetOriginalProfile() == managed_profile_) {
    // Ignore closing browser windows that are in managed mode.
    return;
  }
  size_t count = browsers_to_close_.erase(browser);
  DCHECK_EQ(1u, count);
  if (browsers_to_close_.empty())
    FinalizeEnter(true);
}

ManagedMode::ManagedMode()
    : managed_profile_(NULL),
      io_url_filter_context_(
          new URLFilterContext(
              BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO))),
      ui_url_filter_context_(
          new URLFilterContext(
              BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI))) {
  BrowserList::AddObserver(this);
}

ManagedMode::~ManagedMode() {
  // This class usually is a leaky singleton, so this destructor shouldn't be
  // called. We still do some cleanup, in case we're owned by a unit test.
  BrowserList::RemoveObserver(this);
  DCHECK_EQ(0u, callbacks_.size());
  DCHECK_EQ(0u, browsers_to_close_.size());
  io_url_filter_context_.release()->ShutdownOnUIThread();
  ui_url_filter_context_.release()->ShutdownOnUIThread();
}

void ManagedMode::Observe(int type,
                          const content::NotificationSource& source,
                          const content::NotificationDetails& details) {
  // Return early if we don't have any queued callbacks.
  if (callbacks_.empty())
    return;

  switch (type) {
    case chrome::NOTIFICATION_CLOSE_ALL_BROWSERS_REQUEST: {
      FinalizeEnter(false);
      return;
    }
    case chrome::NOTIFICATION_BROWSER_CLOSE_CANCELLED: {
      Browser* browser = content::Source<Browser>(source).ptr();
      if (browsers_to_close_.find(browser) != browsers_to_close_.end())
        FinalizeEnter(false);
      return;
    }
    default:
      NOTREACHED();
  }
}

void ManagedMode::FinalizeEnter(bool result) {
  if (result)
    SetInManagedMode(managed_profile_);
  for (std::vector<EnterCallback>::iterator it = callbacks_.begin();
       it != callbacks_.end(); ++it) {
    it->Run(result);
  }
  callbacks_.clear();
  browsers_to_close_.clear();
  registrar_.RemoveAll();
}

bool ManagedMode::PlatformConfirmEnter() {
  // TODO(bauerb): Show platform-specific confirmation dialog.
  return true;
}

bool ManagedMode::PlatformConfirmLeave() {
  // TODO(bauerb): Show platform-specific confirmation dialog.
  return true;
}

void ManagedMode::SetInManagedMode(Profile* newly_managed_profile) {
  // Register the ManagementPolicy::Provider before changing the pref when
  // setting it, and unregister it after changing the pref when clearing it,
  // so pref observers see the correct ManagedMode state.
  bool in_managed_mode = !!newly_managed_profile;
  if (in_managed_mode) {
    DCHECK(!managed_profile_ || managed_profile_ == newly_managed_profile);
    extensions::ExtensionSystem::Get(
        newly_managed_profile)->management_policy()->RegisterProvider(this);
    pref_change_registrar_.reset(new PrefChangeRegistrar());
    pref_change_registrar_->Init(newly_managed_profile->GetPrefs());
    pref_change_registrar_->Add(
        prefs::kDefaultManagedModeFilteringBehavior,
        base::Bind(
            &ManagedMode::OnDefaultFilteringBehaviorChanged,
            base::Unretained(this)));
  } else {
    extensions::ExtensionSystem::Get(
        managed_profile_)->management_policy()->UnregisterProvider(this);
    pref_change_registrar_.reset();
  }

  managed_profile_ = newly_managed_profile;
  ManagedModeURLFilter::FilteringBehavior behavior =
      ManagedModeURLFilter::ALLOW;
  if (in_managed_mode) {
    int behavior_value = managed_profile_->GetPrefs()->GetInteger(
        prefs::kDefaultManagedModeFilteringBehavior);
    behavior = ManagedModeURLFilter::BehaviorFromInt(behavior_value);
  }
  io_url_filter_context_->SetDefaultFilteringBehavior(behavior);
  ui_url_filter_context_->SetDefaultFilteringBehavior(behavior);
  g_browser_process->local_state()->SetBoolean(prefs::kInManagedMode,
                                               in_managed_mode);
  if (in_managed_mode)
    UpdateWhitelist();

  // This causes the avatar and the profile menu to get updated.
  content::NotificationService::current()->Notify(
      chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED,
      content::NotificationService::AllBrowserContextsAndSources(),
      content::NotificationService::NoDetails());
}

ScopedVector<ManagedModeSiteList> ManagedMode::GetActiveSiteLists() {
  DCHECK(managed_profile_);
  ScopedVector<ManagedModeSiteList> site_lists;
  // TODO(bauerb): Get site lists from all extensions.
  return site_lists.Pass();
}

void ManagedMode::OnDefaultFilteringBehaviorChanged() {
  DCHECK(IsInManagedModeImpl());

  int behavior_value = managed_profile_->GetPrefs()->GetInteger(
      prefs::kDefaultManagedModeFilteringBehavior);
  ManagedModeURLFilter::FilteringBehavior behavior =
      ManagedModeURLFilter::BehaviorFromInt(behavior_value);
  io_url_filter_context_->SetDefaultFilteringBehavior(behavior);
  ui_url_filter_context_->SetDefaultFilteringBehavior(behavior);
}

void ManagedMode::UpdateWhitelist() {
  io_url_filter_context_->LoadWhitelists(GetActiveSiteLists());
  ui_url_filter_context_->LoadWhitelists(GetActiveSiteLists());
}