text:
import os
import time
import copy
import zlib
import gzip
import ssl
import struct
import socket
import urlparse
import operator
import random
import tempfile
import webbrowser
import threading
import subprocess
import datetime
from collections import defaultdict
from StringIO import StringIO

from burst import console
from burst.conf import conf
from burst.cookie import Cookie
from burst.color import *
from burst.exception import *
from burst.utils import make_table, clear_line, \
                         re_space, smart_split, smart_rsplit, \
                         truncate, stats, parse_qs

class Request():
  """The Request class is the base of Burst. To create an instance, you have
  two options: either use a socket or a string representing the whole request
  into the constructor or use the 'create' function.

  The two methods __repr__ and __str__ have been defined to provide
  user-friendly interaction within the interpreter.
  """

  def __init__(self, fd, hostname=None, port=None, use_ssl=False):
    """Create a request. fd should be either a socket descriptor
       or a string. In both case, it should contain a full request.
       To generate a request from a URL, see c()"""
    if isinstance(fd, basestring):
      fd = StringIO(fd)
    try:
      banner = read_banner(fd)
      # ASSUMPTION: The request line contains three elements seperated by
      #             a space.
      self.method, url, self.http_version = banner
    except ValueError:
      raise NotConnected(' '.join(banner))
    if self.method.upper() == "CONNECT":
      # ASSUMPTION: CONNECT method needs a hostname and port
      self.hostname, self.port = url.rsplit(":", 1)
      self.port = int(self.port)
      self.url = ""
      self.use_ssl = False
    elif hostname:
      self.hostname = hostname
      self.port = port if port else 80
      self.use_ssl = use_ssl
      self.url = url
    else:
      p_url = urlparse.urlparse(url)
      self.url = urlparse.urlunparse(("", "") + p_url[2:])
      self.hostname = p_url.hostname
      if not self.hostname:
        raise BurstException("No hostname: " + str(url))
      if p_url.scheme == 'https':
        self.use_ssl = True
        self.port = int(p_url.port) if p_url.port else 443
      else:
        self.port = int(p_url.port) if p_url.port else 80
        self.use_ssl = use_ssl
    self.set_headers(read_headers(fd))
    self.raw_content = read_content(fd, self.headers, method=self.method)
    if self.raw_content:
      self.content = _clear_content(self.headers, self.raw_content)
    else:
      self.content = ""
    self.response = None

  @property
  def path(self):
    return urlparse.urlparse(self.url).path

  @property
  def query(self):
    return urlparse.urlparse(self.url).query

  @property
  def cookies(self):
    cookies = []
    for h in self.get_header("Cookie"):
      cookies.extend(Cookie.parse(h))
    return cookies

  def has_header(self, name, value=None):
    """Test if the request contains a specific header (case insensitive).
    If value is supplied, it is matched (case insensitive) against the first
    header with the matching name.
    """
    return _has_header(self.headers, name, value)

  def get_header(self, name):
    """Return the headers of the request matching name (case insensitive).
    This method always returns a list.
    """
    return _get_header(self.headers, name)

  def set_headers(self, headers):
    self.headers = []
    # ASSUMPTION: Headers are seperated by a newline character
    for l in headers.splitlines():
      if l:
        # ASSUMPTION: Each header is composed of two fields seperated by
        #             a colon.
        t, v = [q.strip() for q in l.split(":", 1)]
        self.headers.append((t, v))

  def update_content_length(self):
    """Update the Content-Length header according to the content of the
    request"""
    l = str(len(self.raw_content)) if self.raw_content else "0"
    for i, c in enumerate(self.headers):
      h, v = c
      if h.title() == "Content-Length":
        self.headers[i] = (h, l)
        # ASSUMPTION: There is only one Content-Length header per request
        break
    else:
      self.headers.append(("Content-Length", l))

  def remove_header(self, name):
    """Remove all the headers matching the specified name"""
    for i, c in enumerate(self.headers):
      h, v = c
      if h.title() == name:
        del self.headers[i]

  def bind(self, r):
    """Bind the Request to another one. This method will copy the supplied
    request's cookies and response set-cookies to the Request."""
    r_new = self.copy()
    for c in r.get_header('Cookie'):
      r_new.headers.append(('Cookie', c))
    if r.response:
      cookies = []
      for c in r.response.get_header('Set-Cookie'):
        cookies.append(Cookie.parse(c, set_cookie=True))
      r_new.headers.append(('Cookie', "; ".join([str(x) for x in cookies])))
    return r_new

  def __repr__(self):
    return self.repr(width=None)

  def repr(self, width=None, rl=False):
    if width:
      hostname = smart_rsplit(self.hostname, int(0.3 * width), ".")
      path = smart_split(self.path, int(0.6 * width), "/")
    else:
      hostname = self.hostname
      path = self.path
    fields = [info(self.method, rl=rl), hostname, path]
    if self.use_ssl: fields.append(warning("SSL", rl=rl))
    return ("<" + " ".join(fields) + ">").encode("utf-8")

  def copy(self):
    """Copy a request. The response is not duplicated."""
    r_new = copy.copy(self)
    r_new.headers = copy.deepcopy(self.headers)
    r_new.response = None
    return r_new

  def __str__(self, headers_only=False):
    s = StringIO()
    if self.method == "CONNECT":
      s.write("{s.method} {s.hostname}:{s.port} {s.http_version}\r\n".format(s=self))
    else:
      s.write("{s.method} {s.url} {s.http_version}\r\n".format(s=self))
    for h, v in self.headers:
      s.write("{}: {}\r\n".format(h, v))
    s.write("\r\n")
    if not headers_only and self.content:
      s.write(self.content)
    return s.getvalue()

  def __eq__(self, r):
    """Compare two requests based on the host, port, use of ssl, url, headers
    and content (if present)"""
    if self.hostname != r.hostname or \
       self.port != r.port or \
       self.use_ssl != r.use_ssl or \
       self.url != r.url or \
       self.headers != r.headers:
      return False
    if (self.content or r.content) and self.content != r.content:
      return False
    return True

  def similar(self, r):
    """Compare two requests based on the host, port, use of ssl and path"""
    if self.hostname != r.hostname or \
       self.port != r.port or \
       self.use_ssl != r.use_ssl or \
       self.path != r.path:
      return False
    return True

  def __call__(self, conn=None, chunk_func=None):
    """Make the request to the server. If conn is supplied, it will be used
    as connection socket. If chunk_func is supplied, it will be call for
    every chunk received, if appplicable.
    """
    if conn:
      sock = conn
    else:
      sock = connect(self.hostname, self.port, self.use_ssl)
    if conf.history:
      history_lock.acquire()
      history.append(self)
      history_lock.release()
    _send_request(sock, self)
    t_start = datetime.datetime.now()
    self.response = Response(sock.makefile('rb', 0), self, chunk_func=chunk_func)
    self.response.sent_date = t_start
    self.response.received_date = datetime.datetime.now()

  def edit(self):
    """Edit the request. The original request is modified.
    """
    if conf.update_content_length:
      self.remove_header("Content-Length")
    fd, fname = tempfile.mkstemp(suffix=".http")
    with os.fdopen(fd, 'w') as f:
      f.write(str(self))
    ret = subprocess.call(conf.editor.format(fname), shell=True)
    if not ret:
      f = open(fname, 'r')
      self.__init__(f, self.hostname, self.port, self.use_ssl)
      if self.method in ('POST', 'PUT') and conf.update_content_length:
        self.update_content_length()
      os.remove(fname)

  def play(self, call_func=None, pre_func=None, post_func=None):
    """Start your editor with a dump of the Request and its Response.
    Every time the request file is saved, the request is made to the server and
    the response updated. When the editor terminates, the last valid request
    made is returned. The original request is not modified.

    If call_func is provided, it will be called every time the request is saved.
    The corresponding Request object is passed as an argument to this callback.

    If pre_func is provided, it will be called before the request is sent.
    A Request is passed as argument, it should return a Request.

    If post_func is provided, it will be called once the response has been read.
    A Response is passed as argument, it should return a Response.

    The behaviour of your editor can be modified via the conf.editor_play
    parameters.
    """
    r_tmp = self.copy()
    if conf.update_content_length:
      r_tmp.remove_header("Content-Length")
    fdreq, freqname = tempfile.mkstemp(suffix=".http")
    fdrep, frepname = tempfile.mkstemp(suffix=".http")
    with os.fdopen(fdreq, 'w') as f:
      f.write(str(r_tmp))
    if self.response:
      with os.fdopen(fdrep, 'w') as f:
        f.write(str(self.response))
    last_access = os.stat(freqname).st_mtime
    ret = subprocess.Popen(conf.editor_play.format(freqname,frepname), shell=True)
    r_new = None
    while ret.poll() != 0:
      if os.stat(freqname).st_mtime != last_access:
        freq = open(freqname, 'r')
        try:
          r_new = Request(freq, self.hostname, self.port, self.use_ssl)
          if r_new.method in ('POST', 'PUT') and conf.update_content_length:
            r_new.update_content_length()
          freq.close()
          if pre_func:
            r_new = pre_func(r_new)
          if call_func:
            call_func(r_new)
          else:
            r_new()
          if post_func:
            res_text = post_func(r_new.response)
          else:
            res_text = r_new.response
          if res_text:
            frep = open(frepname, 'w')
            frep.write(str(res_text))
        except Exception, e:
          frep = open(frepname, 'w')
          frep.write("Error:\n")
          frep.write(str(e))
        frep.close()
        last_access = os.stat(freqname).st_mtime
      # hack to avoid 100% CPU usage. Should be replaced by pyinotify.
      time.sleep(0.1)
    os.remove(freqname)
    os.remove(frepname)
    return r_new

  def extract(self, arg, from_response=None):
    """Extract a particular field of the request.
    The field is looked up in:
      * attributes
      * headers
      * URL query
      * request body
      * cookies
      * response
    """
    if from_response:
      if self.response:
        return self.response.extract(arg)
      return None
    if hasattr(self, arg):
      return getattr(self, arg)
    h = self.get_header(arg)
    if h:
      return h[0]
    if self.query:
      query = parse_qs(self.query)
      if arg in query:
        return query[arg][0]
    if self.content:
      post = parse_qs(self.content)
      if arg in post:
        return post[arg][0]
    try:
      for c in self.cookies:
        if c.name == arg:
          return c.value
    except CookieException:
      pass
    if from_response is None and self.response:
      return self.response.extract(arg)

  def filter(self, predicate):
    """Filter the Request according to a predicate. This method is used by
    RequestSet.filter"""
    return bool(predicate(self))

  def follow(self):
    """Generate a new request based on the Location header."""
    if not self.response or not self.response.status in ('301', '302'):
      return
    else:
      for h, v in self.response.headers:
        if h == "Location":
          url_p = urlparse.urlparse(v)
          if url_p.scheme in ('http', 'https'):
            return c(v)
          elif not url_p.scheme and url_p.path:
            nr = self.copy()
            n_path = urlparse.urljoin(self.url, v)
            nr.url = urlparse.urlunparse(urlparse.urlparse(self.url)[:2] +
                                         urlparse.urlparse(n_path)[2:])
            return nr
          else:
            raise BurstException("Unknown redirection, please add some code " \
                                  "in burst/http.py:Request.follow")

def create(url):
  """Create a request on the fly, based on a URL"""
  p_url = urlparse.urlparse(url)
  host = p_url.hostname
  if not p_url.path:
    url += "/"
  return Request("""GET {} HTTP/1.1
Host: {}
User-Agent: Mozilla/5.0 (Windows; U; MSIE 9.0; Windows NT 0.9; en-US)
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en;q=0.5
Accept-Encoding: gzip, deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7

""".format(url, host))

c = create

class Response():
  """A response object, always associated with a request.
  """
  def __init__(self, fd, request, chunk_func=None):
    try:
      banner = read_banner(fd)
      # ASSUMPTION: A response status line contains three elements
      #             seperated by a space
      self.http_version, self.status, self.reason = banner
    except ValueError:
      raise BadStatusLine(banner)
    self.set_headers(read_headers(fd))
    self.request = request
    if request.method == "HEAD":
      self.raw_content = self.content = ""
    else:
      self.raw_content = read_content(fd, self.headers, self.status,
                                      chunk_func=chunk_func)
      if self.raw_content:
        self.content = _clear_content(self.headers, self.raw_content)
      else:
        self.content = ""

  def __repr__(self):
    return self.repr()

  @property
  def time(self):
    return self.received_date - self.sent_date

  def repr(self, rl=False):
    flags = []
    if self.content: flags.append(str(len(self.content)))
    if self.has_header("Content-Type"):
      flags.append(",".join([x.split(";")[0] for x in
                                             self.get_header("Content-Type")]))
    if self.has_header("Location"):
      flags.append(",".join(self.get_header("Location")))
    if self.has_header("Transfer-Encoding", "chunked"): flags.append("chunked")
    if self.has_header("Content-Encoding", "gzip"): flags.append("gzip")
    if self.has_header("Content-Encoding", "deflate"): flags.append("deflate")
    for c in self.get_header("Set-Cookie"):
      flags.append("C:" + c)
    return "<" + color_status(self.status, rl) + " " + " ".join(flags) + ">"

  def has_header(self, name, value=None):
    """Test if the response contains a specific header (case insensitive).
    If value is supplied, it is matched (case insensitive) against the first
    header with the matching name.
    """
    return _has_header(self.headers, name, value)

  def get_header(self, name):
    """Return the headers of the response matching name (case insensitive).
    This method always returns a list.
    """
    return _get_header(self.headers, name)

  def edit(self):
    """Edit the response through your editor. The original response is modified.
    """
    fd, fname = tempfile.mkstemp(suffix=".http")
    if self.content != self.raw_content:
      print warning("The response is currently encoded. It will be decoded " \
                    "before edition."),
      raw_input()
      self.normalise()
    if conf.update_content_length:
      self.remove_header("Content-Length")
    with os.fdopen(fd, 'w') as f:
      f.write(self.raw())
    ret = subprocess.call(conf.editor.format(fname), shell=True)
    if not ret:
      f = open(fname, 'r')
      self.__init__(f, self.request)
      if self.content:
        self.update_content_length()
      os.remove(fname)

  def copy(self):
    """Copy a Response. Both response will have the same request."""
    res_new = copy.copy(self)
    res_new.headers = copy.deepcopy(self.headers)
    return res_new

  def normalise(self):
    """Normalise the response content by dropping any extra encoding"""
    self.raw_content = res_new.content
    self.remove_header("Transfer-Encoding")
    self.remove_header("Content-Encoding")
    self.update_content_length()

  def remove_header(self, name):
    """Remove all the headers matching the specified name"""
    for i, c in enumerate(self.headers):
      h, v = c
      if h.title() == name:
        del self.headers[i]

  def update_content_length(self):
    """Update the Content-Length header according to the content of the
    response"""
    l = str(len(self.raw_content)) if self.raw_content else "0"
    for i, c in enumerate(self.headers):
      h, v = c
      if h.title() == "Content-Length":
        self.headers[i] = (h, l)
        break
    else:
      self.headers.append(("Content-Length", l))

  @property
  def cookies(self):
    cookies = []
    for h in self.get_header("Set-Cookie"):
      cookies.append(Cookie.parse(h, set_cookie=True))
    return cookies

  @property
  def is_javascript(self):
    if any(["javascript" in h for h in self.get_header("Content-Type")]):
      return True
    return False

  @property
  def is_html(self):
    if any(["html" in h for h in self.get_header("Content-Type")]):
      return True
    return False

  @property
  def closed(self):
    if self.has_header("Connection", "close") or self.http_version == "HTTP/1.0":
      return True
    return False

  @property
  def length(self):
    return len(self.content)

  @property
  def content_type(self):
    try:
      return self.get_header("Content-Type")[0]
    except IndexError:
      return None

  def __str__(self, headers_only=False):
    s = StringIO()
    s.write("{s.http_version} {s.status} {s.reason}\r\n".format(s=self))
    for h, v in self.headers:
      s.write("{}: {}\r\n".format(h, v))
    s.write("\r\n")
    if not headers_only and self.content:
      s.write(self.content)
    return s.getvalue()

  def raw(self):
    s = StringIO()
    s.write("{s.http_version} {s.status} {s.reason}\r\n".format(s=self))
    for h, v in self.headers:
      s.write("{}: {}\r\n".format(h, v))
    s.write("\r\n")
    if hasattr(self, "raw_content") and self.raw_content:
      s.write(self.raw_content)
    return s.getvalue()

  def set_headers(self, headers):
    self.headers = []
    for l in headers.splitlines():
      if l:
        t, v = [q.strip() for q in l.split(":", 1)]
        self.headers.append((t, v))

  def preview(self):
    """Preview the reponse in your browser.
    """
    fd, fname = tempfile.mkstemp()
    with os.fdopen(fd, 'w') as f:
      f.write(self.content)
    webbrowser.open_new_tab(fname)

  def extract(self, arg):
    """Extract a particular field of the response.
    The field is looked up in:
      * attributes
      * headers
      * cookies
    """
    if hasattr(self, arg):
      return getattr(self, arg)
    h = self.get_header(arg)
    if h:
      return h[0]
    for c in self.cookies:
      if c.name == arg:
        return c.value

  def filter(self, predicate):
    return bool(predicate(self))

def compare(r1, r2):
  fd1, f1name = tempfile.mkstemp(suffix=".http")
  fd2, f2name = tempfile.mkstemp(suffix=".http")
  with os.fdopen(fd1, 'w') as f:
    f.write(str(r1))
  with os.fdopen(fd2, 'w') as f:
    f.write(str(r2))
  subprocess.call(conf.diff_editor.format(f1name, f2name), shell=True)
  os.remove(f1name)
  os.remove(f2name)

cmp = compare

class RequestSet():
  """Set of request. This object behaves like a list.
  """

  def __init__(self, reqs=None):
    self.reqs = reqs if reqs else []
    self.hostname = None

  def __getitem__(self, i):
    if isinstance(i, slice):
      return RequestSet(self.reqs[i])
    return self.reqs[i]

  def __len__(self):
    return len(self.reqs)

  def __add__(self, other):
    return RequestSet(self.reqs + other.reqs)

  def __bool__(self):
    return bool(self.reqs)

  def append(self, r):
    self.reqs.append(r)

  def extend(self, rs):
    self.reqs.extend(rs)

  def pop(self):
    return self.reqs.pop()

  def filter(self, predicate):
    return RequestSet([r for r in self.reqs if r.filter(predicate)])

  def extract(self, arg, from_response=None):
    return [r.extract(arg, from_response) for r in self.reqs]

  def copy(self):
    return RequestSet([r.copy() for r in self.reqs])

  def cmp(self, i1, i2):
    compare(self[i1], self[i2])

  def cmp_response(self, i1, i2):
    compare(self[i1].response, self[i2].response)

  def __repr__(self):
    status = defaultdict(int)
    for r in self.reqs:
      if r.response:
        status[r.response.status] += 1
      else:
        status["unknown"] += 1
    status_flat = [color_status(x) + ":" + str(nb) for x, nb in sorted(status.items())]
    hostnames = set([r.hostname for r in self.reqs])
    return "{" + " ".join(status_flat) + " | " + ", ".join(hostnames) + "}"

  def __str__(self):
    return unicode(self).encode('utf-8')

  def __unicode__(self, width=None):

    def n_length(r, i):
      if r.response and r.response.content:
        p = str(len(r.response.content))
        if hasattr(r, "payload"):
          p += "(" + str(len(r.response.content)-len(encode(r.payload))) + ")"
        return p
      else:
        return "-"

    cols = [
            ("Method", lambda r, i: info(r.method), None),
            ("Path", lambda r, i: r.path, (9, smart_rsplit, "/")),
            ("Status", lambda r, i: color_status(r.response.status) if r.response else "-", None),
            ("Length", n_length, None)]

    if any([hasattr(x, "payload") for x in self.reqs]):
      cols.insert(2, ("Point", lambda r, i: getattr(r, "injection_point", "-"), (2, truncate)))
      cols.insert(3, ("Payload", lambda r, i: getattr(r, "payload", "-").decode("utf8"), (3, truncate)))
      cols.append(("Time", lambda r, i: "{:.4f}".format(r.response.time.total_seconds()) if
                                        (r.response and hasattr(r.response, "time")) else "-", None))
    else:
      cols.insert(2, ("Query", lambda r, i: r.query, (3, smart_rsplit, "&")))
    if len(set([r.hostname for r in self.reqs])) > 1:
      cols.insert(1, ("Host", lambda r, i: r.hostname, (2, smart_rsplit, ".")))
    if len(self.reqs) > 5:
      cols.insert(0, ("Id", lambda r, i: str(i), None))
    return make_table(self.reqs, cols, console.term_width)

  def _summary_attr(self, rs, attr, p_str, indent):
    values = [ attr(r) for r in rs if r.response ]
    if not values:
      return False
    avg, bottom, top = stats(values)
    if indent:
      print " ",
    print p_str.format(bottom, avg, top)
    outsiders = [ r for r in rs if r.response and (attr(r) < bottom or  attr(r) > top)]
    if outsiders:
      if indent:
        bl = "    | "
      else:
        bl = " | "
      print "\n".join([bl + getattr(r, "payload", "-") + " " + error(str(attr(r))) for r in outsiders])
      return True
    return False

  def summary(self):
    sips = set([ x.injection_point for x in self.reqs if hasattr(x, "injection_point")])
    for ip in sips:
      if not ip and len(sips) == 1:
        ors = self
        split = False
      else:
        print "Injection point:", ip
        ors = self.filter(lambda x: hasattr(x, "injection_point") and x.injection_point == ip)
        split = True
      rs = ors
      if rs:
        if self._summary_attr(rs, lambda x: x.response.length, "Length: [{:.1f} {:.1f} {:.1f}]", split):
          print
      rs = ors.filter(lambda x: hasattr(x.response, "time"))
      if rs:
        if self._summary_attr(rs, lambda x: x.response.time.total_seconds(), "Time: [{:.3f} {:.3f} {:.3f}]", split):
          print

  def by_length(self):
    return RequestSet(sorted(self.reqs, key=operator.attrgetter("response.length")))

  def by_status(self):
    return RequestSet(sorted(self.reqs, key=operator.attrgetter("response.status")))

  def by_path(self):
    return RequestSet(sorted(self.reqs, key=operator.attrgetter("path")))

  def without_payloads(self):
    return RequestSet([x for x in self.reqs if not hasattr(x, "payload")])

  def _init_connection(self):
    return connect(self.hostname, self.port, self.use_ssl)

  def clear(self):
    for r in self.reqs:
      r.response = None

  def __call__(self, force=False, randomised=False, verbose=1,
               post_func=None, post_args=[]):
    if not self.reqs:
      raise Exception("No request to proceed")
    hostnames = set([r.hostname for r in self.reqs])
    ports = set([r.port for r in self.reqs])
    use_ssls = set([r.use_ssl for r in self.reqs])
    if len(hostnames) > 1 or len(ports) > 1 or len(use_ssls) > 1:
      raise Exception("Only one host per request set to run it")
    self.hostname = hostnames.pop()
    self.port = ports.pop()
    self.use_ssl = use_ssls.pop()
    if force and verbose:
      print "Clearing previous responses..."
      self.clear()
    conn = self._init_connection()
    if verbose:
      print "Running {} requests...".format(len(self.reqs)),
      clear_line()
    indices = range(len(self.reqs))
    if randomised: random.shuffle(indices)
    done = 0
    todo = len(self.reqs)
    for i in indices:
      r = self.reqs[i]
      if verbose:
        print "Running {} requests...{:.2f}%".format(todo, done * 100. / todo),
        clear_line()
      next = False
      if r.response and not force:
        todo -= 1
        next = True
      while not next:
        try:
          if verbose == 2: print repr(r)
          r(conn=conn)
          if post_func: post_func(r, *post_args)
          if verbose == 2: print repr(r.response)
          if r.response.closed:
            conn = self._init_connection()
          done += 1
          next = True
        except (socket.error, BadStatusLine):
          conn = self._init_connection()
          next = False
        if conf.delay:
          time.sleep(conf.delay)
    if verbose:
      print "Running {} requests...done.".format(len(self.reqs))
    conn.close()

class History(RequestSet):
  """History is a singleton class which contains all the
  requests made through Burst.
  """

  def _enabled(self):
    if not conf.history:
      raise Exception("History not enabled. Set conf.history = True")

  def __repr__(self):
    self._enabled()
    return RequestSet.__repr__(self)

  def __str__(self):
    self._enabled()
    return RequestSet.__str__(self)

  def clear(self):
    self.reqs = []

history_lock = threading.RLock()
history = History()

# Following, internal function used by Request and Response
# mostly inspired by httplib

def read_banner(fp):
  banner = re_space.split(fp.readline().strip(), maxsplit=2)
  return banner

def read_headers(fp):
  headers = ""
  while True:
    l = fp.readline()
    headers += l
    if l == "\r\n" or l == "\n":
      break
  return headers

def _has_header(headers, name, value=None):
  for h, v in headers:
    if h.lower() == name.lower():
      if value is None:
        return True
      elif v.lower() == value.lower():
        return True
      else:
        return False
  return False

def _get_header(headers, name):
  return [v for h, v in headers if h.lower() == name.lower()]

def read_content(fp, headers, status=None, method=None, chunk_func=None):
  if status == "304":
    return None
  elif _has_header(headers, "Transfer-Encoding", "chunked"):
    return _chunked_read_content(fp, chunk_func=chunk_func).getvalue()
  elif _has_header(headers, "Content-Length"):
    # ASSUMPTION: The first Content-Length header will be use to
    #             read the response
    length_str = _get_header(headers, "Content-Length")[0]
    # ASSUMPTION: The value of Content-Length can be converted to an integer
    length = int(length_str)
    if length < 0:
      raise BurstException("Invalid Content-Length")
    return _read_content(fp, length).getvalue()
  elif (status and status != "204") or method == "POST" or method == "PUT":
    # ASSUMPTION: In case we have no indication on what to read, if the method
    #             is POST or the status 200, we read until EOF
    return fp.read()
  return None

def _chunked_read_content(fp, chunk_func=None):
  buffer = StringIO()
  while True:
    diff = ""
    l = fp.readline()
    diff += l
    s = int(l, 16)
    if s == 0:
      diff += fp.readline()
      buffer.write(diff)
      if chunk_func:
        chunk_func(diff)
      return buffer
    diff += _read_content(fp, s).getvalue()
    diff += fp.readline()
    buffer.write(diff)
    if chunk_func:
      chunk_func(diff)

def _read_content(fp, length):
  buffer = StringIO()
  while True:
    l = len(buffer.getvalue())
    if l < length:
      buffer.write(fp.read(length - l))
    else:
      break
  return buffer

def _clear_content(headers, raw_content):
  if _has_header(headers, "Transfer-Encoding", "chunked"):
    content_io = StringIO(raw_content)
    buffer = StringIO()
    while True:
      s = int(content_io.readline(), 16)
      if s == 0:
        content = buffer.getvalue()
        break
      buffer.write(_read_content(content_io, s).getvalue())
      content_io.readline()
  else:
    content = raw_content
  if _has_header(headers, "Content-Encoding", "gzip"):
    cs = StringIO(content)
    gzipper = gzip.GzipFile(fileobj=cs)
    return gzipper.read()
  if _has_header(headers, "Content-Encoding", "deflate"):
    try:
      unzipped = StringIO(zlib.decompress(content))
    except zlib.error:
      unzipped = StringIO(zlib.decompress(content, -zlib.MAX_WBITS))
    return unzipped.read()
  return content

def _wrap_socket(sock):
  if conf.ssl_verify or conf.ssl_reverse:
    return ssl.wrap_socket(sock, ssl_version=conf._ssl_version,
                           cert_reqs=ssl.CERT_REQUIRED,
                           ca_certs=conf.ssl_verify)
  else:
    return ssl.wrap_socket(sock, ssl_version=conf._ssl_version)

def _socks5_connect(hostname, port, use_ssl):
  p_url = urlparse.urlparse(conf.proxy)
  p_hostname = p_url.hostname
  p_port = p_url.port
  sock = socket.create_connection((p_hostname, p_port))
  sock.sendall("\x05\x01\x00")
  auth = sock.recv(2)
  if auth != "\x05\x00":
    raise ProxyError("Authentication required for the proxy")
  p_r = "\x05\x01\x00"
  try:
    p_r += "\x01" + socket.inet_aton(hostname)
  except socket.error:
    p_r += "\x03" + chr(len(hostname)) + hostname
  p_r += struct.pack(">H", port)
  sock.sendall(p_r)
  p_res = sock.recv(4)
  if not p_res.startswith("\x05\x00"):
    raise ProxyError("Socks proxy returned: " + repr(p_res))
  if p_res[3] == "\x01":
    sock.recv(4)
  elif p_res[3] == "\x03":
    p_l = ord(sock.recv(1))
    sock.recv(p_l)
  sock.recv(2)
  if use_ssl:
    try:
      sock = _wrap_socket(sock)
    except socket.error, e:
      print e
      raise UnableToConnect("Unable to use SSL with the proxy")
  return sock

def _socks4_connect(hostname, port, use_ssl):
  p_url = urlparse.urlparse(conf.proxy)
  p_hostname = p_url.hostname
  p_port = p_url.port
  try:
    ipaddr = socket.inet_aton(hostname)
    resolv = False
  except socket.error:
    ipaddr = "\x00\x00\x00\x01"
    resolv = True
  p_r = "\x04\x01" + struct.pack(">H", port) + ipaddr + "\x00"
  if resolv:
    p_r += hostname + "\x00"
  sock = socket.create_connection((p_hostname, p_port))
  sock.sendall(p_r)
  p_res = sock.recv(8)
  if not p_res.startswith("\x00\x5A"):
    raise ProxyError("Socks proxy returned: " + repr(p_res))
  if use_ssl:
    try:
      sock = _wrap_socket(sock)
    except socket.error:
      raise UnableToConnect("Unable to use SSL with the proxy")
  return sock

def _http_connect(hostname, port, use_ssl):
  p_url = urlparse.urlparse(conf.proxy)
  p_hostname = p_url.hostname
  p_port = p_url.port
  p_use_ssl = True if p_url.scheme[-1] == 's' else False
  try:
    sock = socket.create_connection((p_hostname, p_port))
  except socket.error:
    raise ProxyError("Unable to connect to the proxy")
  if p_use_ssl:
    try:
      # No check is made to verify proxy certificate
      sock = ssl.wrap_socket(sock, ssl_version=conf._ssl_version)
    except socket.error:
      raise ProxyError("Unable to use SSL with the proxy")
  if use_ssl:
    f = sock.makefile("rwb", 0)
    f.write("CONNECT {}:{} HTTP/1.1\r\n\r\n".format(hostname, port))
    try:
      v, s, m = read_banner(f)
    except ValueError:
      raise BadStatusLine()
    if s != "200":
      raise ProxyError("Bad status " + s + " " + m)
    _ = read_headers(f)
    sock = _wrap_socket(sock)
  return sock

def _direct_connect(hostname, port, use_ssl):
  try:
    sock = socket.create_connection((hostname, port))
  except socket.error:
    raise UnableToConnect()
  if use_ssl:
    try:
      sock = _wrap_socket(sock)
    except socket.error, e:
      raise UnableToConnect("Unable to use SSL with the server")
  return sock

def connect(hostname, port, use_ssl):
  if conf.proxy:
    p_url = urlparse.urlparse(conf.proxy)
    if p_url.scheme.startswith("http"):
      return _http_connect(hostname, port, use_ssl)
    elif p_url.scheme.startswith("socks4"):
      return _socks4_connect(hostname, port, use_ssl)
    elif p_url.scheme.startswith("socks5"):
      return _socks5_connect(hostname, port, use_ssl)
    else:
      raise NotImplementedError("Available proxy protocols: http(s), socks4a, socks5")
  else:
    return _direct_connect(hostname, port, use_ssl)

def _send_request(sock, request):
  if conf.proxy and not request.use_ssl:
    p_url = urlparse.urlparse(conf.proxy)
    if p_url.scheme == "http":
      p_url = urlparse.urlparse(request.url)
      url = urlparse.urlunparse(("http", request.hostname + ":" + str(request.port)) + p_url[2:])
      buf = [" ".join([request.method, url, request.http_version]), ]
    else:
      buf = [" ".join([request.method, request.url, request.http_version]), ]
  else:
    buf = [" ".join([request.method, request.url, request.http_version]), ]
  buf += ["{}: {}".format(h, v) for h, v in request.headers] + ["", ""]
  data = "\r\n".join(buf)
  if request.raw_content:
    data += request.raw_content
  # if request.footers:
  #   data += ["{}: {}".format (h, v) for h, v in request.footers] + ["",""]
  sock.sendall(data)


text:
[![StyleCI](https://styleci.io/repos/41588945/shield)](https://styleci.io/repos/41588945)

# Core
Atlas Core

redpajama_set_name: RedPajamaGithub


text:
 Compares WorkflowDefinition with other WorkflowDefinition

**Namespace:** [OfficeDevPnP.Core.Framework.Provisioning.Model](OfficeDevPnP.Core.Framework.Provisioning.Model.md)
**Assembly:** OfficeDevPnP.Core.dll
## Syntax
```C#
public override bool Equals(Object obj)
```
### Parameters
#### obj
  Type: System.Object
  WorkflowDefinition object

### Return Value
Type: bool
true if the specified object is equal to the current object; otherwise, false.

## See also
- [WorkflowDefinition](OfficeDevPnP.Core.Framework.Provisioning.Model.WorkflowDefinition.md)
- [OfficeDevPnP.Core.Framework.Provisioning.Model](OfficeDevPnP.Core.Framework.Provisioning.Model.md)


text:
"""BIG-IP® Advanced Firewall Manager™ (AFM®) module.

REST URI
    ``http://localhost/mgmt/tm/security/nat``

GUI Path
    ``Security --> Network Address Translation``

REST Kind
    ``tm:security:nat:*``
"""
from f5.bigip.mixins import CheckExistenceMixin
from f5.bigip.mixins import CommandExecutionMixin
from f5.bigip.resource import Collection
from f5.bigip.resource import OrganizingCollection
from f5.bigip.resource import Resource

class Nat(OrganizingCollection):
    """BIG-IP® AFM® Nat organizing collection."""

    def __init__(self, security):
        super(Nat, self).__init__(security)
        self._meta_data['minimum_version'] = '12.1.0'
        self._meta_data['allowed_lazy_attributes'] = [
            Policy_s,
            Source_Translations,
            Destination_Translations]

class Rules_s(Collection):
    """BIG-IP® AFM® Nat Rules sub-collection."""

    def __init__(self, policy):
        super(Rules_s, self).__init__(policy)
        self._meta_data['required_json_kind'] = \
            'tm:security:nat:policy:rules:rulescollectionstate'
        self._meta_data['allowed_lazy_attributes'] = [Rule]
        self._meta_data['attribute_registry'] = \
            {'tm:security:nat:policy:rules:rulesstate':
                Rule}

class Rule(Resource, CheckExistenceMixin):
    """BIG-IP® AFM® Rule resource.

    NOTE:: The 'place-before' and 'place-after' attribute are
        mandatory but cannot be present with one another. Those attributes
        will not be visible when the class is created, they exist for the
        sole purpose of rule ordering in the BIGIP. The ordering of the
        rules corresponds to the index in the 'items' of the Rules_s
        sub-collection.
    """

    def __init__(self, rules_s):
        super(Rule, self).__init__(rules_s)
        self._meta_data['required_json_kind'] = \
            'tm:security:nat:policy:rules:rulesstate'

        self._meta_data['exclusive_attributes'].append(
            ('place-after', 'place-before'))
        self._meta_data['minimum_additional_parameters'] = {'place-before',
                                                            'place-after'}

    def update(self, **kwargs):
        """We need to implement the custom exclusive parameter check."""
        self._check_exclusive_parameters(**kwargs)
        return super(Rule, self)._update(**kwargs)

    def modify(self, **kwargs):
        """We need to implement the custom exclusive parameter check."""
        self._check_exclusive_parameters(**kwargs)
        return super(Rule, self)._modify(**kwargs)

    def load(self, **kwargs):
        return super(Rule, self)._load(**kwargs)

    def delete(self, **kwargs):
        return super(Rule, self)._delete(**kwargs)

    def exists(self, **kwargs):
        return super(Rule, self)._load(**kwargs)

class Source_Translations(Collection, CommandExecutionMixin):
    """BIG-IP® AFM® Nat Source Translation collection"""

    def __init__(self, nat):
        super(Source_Translations, self).__init__(nat)
        self._meta_data['allowed_lazy_attributes'] = [Source_Translation]
        self._meta_data['attribute_registry'] = \
            {'tm:security:nat:source-translation:source-translationstate':
                Source_Translation}
        self._meta_data['allowed_commands'].append('reset-stats')

class Source_Translation(Resource, CommandExecutionMixin):
    def __init__(self, source_translations):
        super(Source_Translation, self).__init__(source_translations)
        self._meta_data['required_json_kind'] = \
            'tm:security:nat:source-translation:source-translationstate'
        self._meta_data['required_creation_parameters'].update(
            ('partition',))
        self._meta_data['required_load_parameters'].update(
            ('partition',))
        self._meta_data['allowed_commands'].append('reset-stats')

class Destination_Translations(Collection, CommandExecutionMixin):
    """BIG-IP® AFM® Nat Destination Translation collection"""

    def __init__(self, nat):
        super(Destination_Translations, self).__init__(nat)
        self._meta_data['allowed_lazy_attributes'] = [Destination_Translation]
        self._meta_data['attribute_registry'] = \
            {'tm:security:nat:destination-translation:destination-translationstate':
                Destination_Translation}
        self._meta_data['allowed_commands'].append('reset-stats')

class Destination_Translation(Resource, CommandExecutionMixin):
    def __init__(self, destination_translations):
        super(Destination_Translation, self).__init__(destination_translations)
        self._meta_data['required_json_kind'] = \
            'tm:security:nat:destination-translation:destination-translationstate'
        self._meta_data['required_creation_parameters'].update(
            ('partition',))
        self._meta_data['required_load_parameters'].update(
            ('partition',))
        self._meta_data['allowed_commands'].append('reset-stats')

class Policy_s(Collection):
    """BIG-IP® AFM® Nat Policy collection"""

    def __init__(self, nat):
        super(Policy_s, self).__init__(nat)
        self._meta_data['allowed_lazy_attributes'] = [Policy]
        self._meta_data['attribute_registry'] = \
            {'tm:security:nat:policy:policystate':
                Policy}

class Policy(Resource):
    """BIG-IP® AFM® Nat Policy resource"""

    def __init__(self, policy_s):
        super(Policy, self).__init__(policy_s)
        self._meta_data['required_json_kind'] = \
            'tm:security:nat:policy:policystate'
        self._meta_data['required_creation_parameters'].update(('partition',))
        self._meta_data['required_load_parameters'].update(('partition',))
        self._meta_data['allowed_lazy_attributes'] = [Rules_s]
        self._meta_data['attribute_registry'] = \
            {'tm:security:nat:rules:rulescollectionstate':
                Rules_s}


text:
#include <memory>

#include "api/video/i420_buffer.h"
#include "common_video/include/video_frame.h"
#include "modules/video_coding/utility/quality_scaler.h"
#include "rtc_base/event.h"
#include "rtc_base/fakeclock.h"
#include "rtc_base/random.h"
#include "test/gmock.h"
#include "test/gtest.h"
#include "video/overuse_frame_detector.h"

namespace webrtc {

using ::testing::InvokeWithoutArgs;
using ::testing::_;

namespace {
  const int kWidth = 640;
  const int kHeight = 480;
  // Corresponds to load of 15%
  const int kFrameIntervalUs = 33 * rtc::kNumMicrosecsPerMillisec;
  const int kProcessTimeUs = 5 * rtc::kNumMicrosecsPerMillisec;
}  // namespace

class MockCpuOveruseObserver : public AdaptationObserverInterface {
 public:
  MockCpuOveruseObserver() {}
  virtual ~MockCpuOveruseObserver() {}

  MOCK_METHOD1(AdaptUp, void(AdaptReason));
  MOCK_METHOD1(AdaptDown, void(AdaptReason));
};

class CpuOveruseObserverImpl : public AdaptationObserverInterface {
 public:
  CpuOveruseObserverImpl() :
    overuse_(0),
    normaluse_(0) {}
  virtual ~CpuOveruseObserverImpl() {}

  void AdaptDown(AdaptReason) { ++overuse_; }
  void AdaptUp(AdaptReason) { ++normaluse_; }

  int overuse_;
  int normaluse_;
};

class OveruseFrameDetectorUnderTest : public OveruseFrameDetector {
 public:
  OveruseFrameDetectorUnderTest(const CpuOveruseOptions& options,
                                AdaptationObserverInterface* overuse_observer,
                                CpuOveruseMetricsObserver* metrics_observer)
      : OveruseFrameDetector(options,
                             overuse_observer,
                             metrics_observer) {}
  ~OveruseFrameDetectorUnderTest() {}

  using OveruseFrameDetector::CheckForOveruse;
};

class OveruseFrameDetectorTest : public ::testing::Test,
                                 public CpuOveruseMetricsObserver {
 protected:
  void SetUp() override {
    observer_.reset(new MockCpuOveruseObserver());
    options_.min_process_count = 0;
    ReinitializeOveruseDetector();
  }

  void ReinitializeOveruseDetector() {
    overuse_detector_.reset(new OveruseFrameDetectorUnderTest(
        options_, observer_.get(), this));
  }

  void OnEncodedFrameTimeMeasured(int encode_time_ms,
                                  const CpuOveruseMetrics& metrics) override {
    metrics_ = metrics;
  }

  int InitialUsage() {
    return ((options_.low_encode_usage_threshold_percent +
             options_.high_encode_usage_threshold_percent) / 2.0f) + 0.5;
  }

  virtual void InsertAndSendFramesWithInterval(int num_frames,
                                               int interval_us,
                                               int width,
                                               int height,
                                               int delay_us) {
    VideoFrame frame(I420Buffer::Create(width, height),
                     webrtc::kVideoRotation_0, 0);
    uint32_t timestamp = 0;
    while (num_frames-- > 0) {
      frame.set_timestamp(timestamp);
      int64_t capture_time_us = rtc::TimeMicros();
      overuse_detector_->FrameCaptured(frame, capture_time_us);
      clock_.AdvanceTimeMicros(delay_us);
      overuse_detector_->FrameSent(timestamp, rtc::TimeMicros(),
                                   capture_time_us, delay_us);
      clock_.AdvanceTimeMicros(interval_us - delay_us);
      timestamp += interval_us * 90 / 1000;
    }
  }

  virtual void InsertAndSendFramesWithRandomInterval(int num_frames,
                                                     int min_interval_us,
                                                     int max_interval_us,
                                                     int width,
                                                     int height,
                                                     int delay_us) {
    webrtc::Random random(17);

    VideoFrame frame(I420Buffer::Create(width, height),
                     webrtc::kVideoRotation_0, 0);
    uint32_t timestamp = 0;
    while (num_frames-- > 0) {
      frame.set_timestamp(timestamp);
      int interval_us = random.Rand(min_interval_us, max_interval_us);
      int64_t capture_time_us = rtc::TimeMicros();
      overuse_detector_->FrameCaptured(frame, capture_time_us);
      clock_.AdvanceTimeMicros(delay_us);
      overuse_detector_->FrameSent(timestamp, rtc::TimeMicros(),
                                   capture_time_us,
                                   rtc::Optional<int>(delay_us));

      overuse_detector_->CheckForOveruse();
      // Avoid turning clock backwards.
      if (interval_us > delay_us)
        clock_.AdvanceTimeMicros(interval_us - delay_us);

      timestamp += interval_us * 90 / 1000;
    }
  }

  virtual void ForceUpdate(int width, int height) {
    // Insert one frame, wait a second and then put in another to force update
    // the usage. From the tests where these are used, adding another sample
    // doesn't affect the expected outcome (this is mainly to check initial
    // values and whether the overuse detector has been reset or not).
    InsertAndSendFramesWithInterval(2, rtc::kNumMicrosecsPerSec,
                                    width, height, kFrameIntervalUs);
  }
  void TriggerOveruse(int num_times) {
    const int kDelayUs = 32 * rtc::kNumMicrosecsPerMillisec;
    for (int i = 0; i < num_times; ++i) {
      InsertAndSendFramesWithInterval(
          1000, kFrameIntervalUs, kWidth, kHeight, kDelayUs);
      overuse_detector_->CheckForOveruse();
    }
  }

  void TriggerUnderuse() {
    const int kDelayUs1 = 5000;
    const int kDelayUs2 = 6000;
    InsertAndSendFramesWithInterval(
        1300, kFrameIntervalUs, kWidth, kHeight, kDelayUs1);
    InsertAndSendFramesWithInterval(
        1, kFrameIntervalUs, kWidth, kHeight, kDelayUs2);
    overuse_detector_->CheckForOveruse();
  }

  int UsagePercent() { return metrics_.encode_usage_percent; }

  int64_t OveruseProcessingTimeLimitForFramerate(int fps) const {
    int64_t frame_interval = rtc::kNumMicrosecsPerSec / fps;
    int64_t max_processing_time_us =
        (frame_interval * options_.high_encode_usage_threshold_percent) / 100;
    return max_processing_time_us;
  }

  int64_t UnderuseProcessingTimeLimitForFramerate(int fps) const {
    int64_t frame_interval = rtc::kNumMicrosecsPerSec / fps;
    int64_t max_processing_time_us =
        (frame_interval * options_.low_encode_usage_threshold_percent) / 100;
    return max_processing_time_us;
  }

  CpuOveruseOptions options_;
  rtc::ScopedFakeClock clock_;
  std::unique_ptr<MockCpuOveruseObserver> observer_;
  std::unique_ptr<OveruseFrameDetectorUnderTest> overuse_detector_;
  CpuOveruseMetrics metrics_;

  static const auto reason_ = AdaptationObserverInterface::AdaptReason::kCpu;
};

// UsagePercent() > high_encode_usage_threshold_percent => overuse.
// UsagePercent() < low_encode_usage_threshold_percent => underuse.
TEST_F(OveruseFrameDetectorTest, TriggerOveruse) {
  // usage > high => overuse
  EXPECT_CALL(*(observer_.get()), AdaptDown(reason_)).Times(1);
  TriggerOveruse(options_.high_threshold_consecutive_count);
}

TEST_F(OveruseFrameDetectorTest, OveruseAndRecover) {
  // usage > high => overuse
  EXPECT_CALL(*(observer_.get()), AdaptDown(reason_)).Times(1);
  TriggerOveruse(options_.high_threshold_consecutive_count);
  // usage < low => underuse
  EXPECT_CALL(*(observer_.get()), AdaptUp(reason_)).Times(testing::AtLeast(1));
  TriggerUnderuse();
}

TEST_F(OveruseFrameDetectorTest, OveruseAndRecoverWithNoObserver) {
  overuse_detector_.reset(new OveruseFrameDetectorUnderTest(
      options_, nullptr, this));
  EXPECT_CALL(*(observer_.get()), AdaptDown(reason_)).Times(0);
  TriggerOveruse(options_.high_threshold_consecutive_count);
  EXPECT_CALL(*(observer_.get()), AdaptUp(reason_)).Times(0);
  TriggerUnderuse();
}

TEST_F(OveruseFrameDetectorTest, DoubleOveruseAndRecover) {
  EXPECT_CALL(*(observer_.get()), AdaptDown(reason_)).Times(2);
  TriggerOveruse(options_.high_threshold_consecutive_count);
  TriggerOveruse(options_.high_threshold_consecutive_count);
  EXPECT_CALL(*(observer_.get()), AdaptUp(reason_)).Times(testing::AtLeast(1));
  TriggerUnderuse();
}

TEST_F(OveruseFrameDetectorTest, TriggerUnderuseWithMinProcessCount) {
  const int kProcessIntervalUs = 5 * rtc::kNumMicrosecsPerSec;
  options_.min_process_count = 1;
  CpuOveruseObserverImpl overuse_observer;
  overuse_detector_.reset(new OveruseFrameDetectorUnderTest(
      options_, &overuse_observer, this));
  InsertAndSendFramesWithInterval(
      1200, kFrameIntervalUs, kWidth, kHeight, kProcessTimeUs);
  overuse_detector_->CheckForOveruse();
  EXPECT_EQ(0, overuse_observer.normaluse_);
  clock_.AdvanceTimeMicros(kProcessIntervalUs);
  overuse_detector_->CheckForOveruse();
  EXPECT_EQ(1, overuse_observer.normaluse_);
}

TEST_F(OveruseFrameDetectorTest, ConstantOveruseGivesNoNormalUsage) {
  EXPECT_CALL(*(observer_.get()), AdaptUp(reason_)).Times(0);
  EXPECT_CALL(*(observer_.get()), AdaptDown(reason_)).Times(64);
  for (size_t i = 0; i < 64; ++i) {
    TriggerOveruse(options_.high_threshold_consecutive_count);
  }
}

TEST_F(OveruseFrameDetectorTest, ConsecutiveCountTriggersOveruse) {
  EXPECT_CALL(*(observer_.get()), AdaptDown(reason_)).Times(1);
  options_.high_threshold_consecutive_count = 2;
  ReinitializeOveruseDetector();
  TriggerOveruse(2);
}

TEST_F(OveruseFrameDetectorTest, IncorrectConsecutiveCountTriggersNoOveruse) {
  EXPECT_CALL(*(observer_.get()), AdaptDown(reason_)).Times(0);
  options_.high_threshold_consecutive_count = 2;
  ReinitializeOveruseDetector();
  TriggerOveruse(1);
}

TEST_F(OveruseFrameDetectorTest, ProcessingUsage) {
  InsertAndSendFramesWithInterval(
      1000, kFrameIntervalUs, kWidth, kHeight, kProcessTimeUs);
  EXPECT_EQ(kProcessTimeUs * 100 / kFrameIntervalUs, UsagePercent());
}

TEST_F(OveruseFrameDetectorTest, ResetAfterResolutionChange) {
  ForceUpdate(kWidth, kHeight);
  EXPECT_EQ(InitialUsage(), UsagePercent());
  InsertAndSendFramesWithInterval(
      1000, kFrameIntervalUs, kWidth, kHeight, kProcessTimeUs);
  EXPECT_NE(InitialUsage(), UsagePercent());
  // Verify reset (with new width/height).
  ForceUpdate(kWidth, kHeight + 1);
  EXPECT_EQ(InitialUsage(), UsagePercent());
}

TEST_F(OveruseFrameDetectorTest, ResetAfterFrameTimeout) {
  ForceUpdate(kWidth, kHeight);
  EXPECT_EQ(InitialUsage(), UsagePercent());
  InsertAndSendFramesWithInterval(
      1000, kFrameIntervalUs, kWidth, kHeight, kProcessTimeUs);
  EXPECT_NE(InitialUsage(), UsagePercent());
  InsertAndSendFramesWithInterval(
      2, options_.frame_timeout_interval_ms *
      rtc::kNumMicrosecsPerMillisec, kWidth, kHeight, kProcessTimeUs);
  EXPECT_NE(InitialUsage(), UsagePercent());
  // Verify reset.
  InsertAndSendFramesWithInterval(
      2, (options_.frame_timeout_interval_ms + 1) *
      rtc::kNumMicrosecsPerMillisec, kWidth, kHeight, kProcessTimeUs);
  ForceUpdate(kWidth, kHeight);
  EXPECT_EQ(InitialUsage(), UsagePercent());
}

TEST_F(OveruseFrameDetectorTest, MinFrameSamplesBeforeUpdating) {
  options_.min_frame_samples = 40;
  ReinitializeOveruseDetector();
  InsertAndSendFramesWithInterval(
      40, kFrameIntervalUs, kWidth, kHeight, kProcessTimeUs);
  EXPECT_EQ(InitialUsage(), UsagePercent());
  // Pass time far enough to digest all previous samples.
  clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec);
  InsertAndSendFramesWithInterval(1, kFrameIntervalUs, kWidth, kHeight,
                                  kProcessTimeUs);
  // The last sample has not been processed here.
  EXPECT_EQ(InitialUsage(), UsagePercent());

  // Pass time far enough to digest all previous samples, 41 in total.
  clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec);
  InsertAndSendFramesWithInterval(
      1, kFrameIntervalUs, kWidth, kHeight, kProcessTimeUs);
  EXPECT_NE(InitialUsage(), UsagePercent());
}

TEST_F(OveruseFrameDetectorTest, InitialProcessingUsage) {
  ForceUpdate(kWidth, kHeight);
  EXPECT_EQ(InitialUsage(), UsagePercent());
}

TEST_F(OveruseFrameDetectorTest, MeasuresMultipleConcurrentSamples) {
  EXPECT_CALL(*(observer_.get()), AdaptDown(reason_))
      .Times(testing::AtLeast(1));
  static const int kIntervalUs = 33 * rtc::kNumMicrosecsPerMillisec;
  static const size_t kNumFramesEncodingDelay = 3;
  VideoFrame frame(I420Buffer::Create(kWidth, kHeight),
                   webrtc::kVideoRotation_0, 0);
  for (size_t i = 0; i < 1000; ++i) {
    // Unique timestamps.
    frame.set_timestamp(static_cast<uint32_t>(i));
    int64_t capture_time_us = rtc::TimeMicros();
    overuse_detector_->FrameCaptured(frame, capture_time_us);
    clock_.AdvanceTimeMicros(kIntervalUs);
    if (i > kNumFramesEncodingDelay) {
      overuse_detector_->FrameSent(
          static_cast<uint32_t>(i - kNumFramesEncodingDelay), rtc::TimeMicros(),
          capture_time_us, kIntervalUs);
    }
    overuse_detector_->CheckForOveruse();
  }
}

TEST_F(OveruseFrameDetectorTest, UpdatesExistingSamples) {
  // >85% encoding time should trigger overuse.
  EXPECT_CALL(*(observer_.get()), AdaptDown(reason_))
      .Times(testing::AtLeast(1));
  static const int kIntervalUs = 33 * rtc::kNumMicrosecsPerMillisec;
  static const int kDelayUs = 30 * rtc::kNumMicrosecsPerMillisec;
  VideoFrame frame(I420Buffer::Create(kWidth, kHeight),
                   webrtc::kVideoRotation_0, 0);
  uint32_t timestamp = 0;
  for (size_t i = 0; i < 1000; ++i) {
    frame.set_timestamp(timestamp);
    int64_t capture_time_us = rtc::TimeMicros();
    overuse_detector_->FrameCaptured(frame, capture_time_us);
    // Encode and send first parts almost instantly.
    clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerMillisec);
    overuse_detector_->FrameSent(timestamp, rtc::TimeMicros(), capture_time_us,
                                 rtc::kNumMicrosecsPerMillisec);
    // Encode heavier part, resulting in >85% usage total.
    clock_.AdvanceTimeMicros(kDelayUs - rtc::kNumMicrosecsPerMillisec);
    overuse_detector_->FrameSent(timestamp, rtc::TimeMicros(), capture_time_us,
                                 kDelayUs);
    clock_.AdvanceTimeMicros(kIntervalUs - kDelayUs);
    timestamp += kIntervalUs * 90 / 1000;
    overuse_detector_->CheckForOveruse();
  }
}

TEST_F(OveruseFrameDetectorTest, RunOnTqNormalUsage) {
  rtc::TaskQueue queue("OveruseFrameDetectorTestQueue");

  rtc::Event event(false, false);
  queue.PostTask([this, &event] {
    overuse_detector_->StartCheckForOveruse();
    event.Set();
  });
  event.Wait(rtc::Event::kForever);

  // Expect NormalUsage(). When called, stop the |overuse_detector_| and then
  // set |event| to end the test.
  EXPECT_CALL(*(observer_.get()), AdaptUp(reason_))
      .WillOnce(InvokeWithoutArgs([this, &event] {
        overuse_detector_->StopCheckForOveruse();
        event.Set();
      }));

  queue.PostTask([this] {
    const int kDelayUs1 = 5 * rtc::kNumMicrosecsPerMillisec;
    const int kDelayUs2 = 6 * rtc::kNumMicrosecsPerMillisec;
    InsertAndSendFramesWithInterval(1300, kFrameIntervalUs, kWidth, kHeight,
                                    kDelayUs1);
    InsertAndSendFramesWithInterval(1, kFrameIntervalUs, kWidth, kHeight,
                                    kDelayUs2);
  });

  EXPECT_TRUE(event.Wait(10000));
}

TEST_F(OveruseFrameDetectorTest, MaxIntervalScalesWithFramerate) {
  const int kCapturerMaxFrameRate = 30;
  const int kEncodeMaxFrameRate = 20;  // Maximum fps the encoder can sustain.

  // Trigger overuse.
  int64_t frame_interval_us = rtc::kNumMicrosecsPerSec / kCapturerMaxFrameRate;
  // Processing time just below over use limit given kEncodeMaxFrameRate.
  int64_t processing_time_us =
      (98 * OveruseProcessingTimeLimitForFramerate(kEncodeMaxFrameRate)) / 100;
  EXPECT_CALL(*(observer_.get()), AdaptDown(reason_)).Times(1);
  for (int i = 0; i < options_.high_threshold_consecutive_count; ++i) {
    InsertAndSendFramesWithInterval(1200, frame_interval_us, kWidth, kHeight,
                                    processing_time_us);
    overuse_detector_->CheckForOveruse();
  }

  // Simulate frame rate reduction and normal usage.
  frame_interval_us = rtc::kNumMicrosecsPerSec / kEncodeMaxFrameRate;
  overuse_detector_->OnTargetFramerateUpdated(kEncodeMaxFrameRate);
  EXPECT_CALL(*(observer_.get()), AdaptDown(reason_)).Times(0);
  for (int i = 0; i < options_.high_threshold_consecutive_count; ++i) {
    InsertAndSendFramesWithInterval(1200, frame_interval_us, kWidth, kHeight,
                                    processing_time_us);
    overuse_detector_->CheckForOveruse();
  }

  // Reduce processing time to trigger underuse.
  processing_time_us =
      (98 * UnderuseProcessingTimeLimitForFramerate(kEncodeMaxFrameRate)) / 100;
  EXPECT_CALL(*(observer_.get()), AdaptUp(reason_)).Times(1);
  InsertAndSendFramesWithInterval(1200, frame_interval_us, kWidth, kHeight,
                                  processing_time_us);
  overuse_detector_->CheckForOveruse();
}

TEST_F(OveruseFrameDetectorTest, RespectsMinFramerate) {
  const int kMinFrameRate = 7;  // Minimum fps allowed by current detector impl.
  overuse_detector_->OnTargetFramerateUpdated(kMinFrameRate);

  // Normal usage just at the limit.
  int64_t frame_interval_us = rtc::kNumMicrosecsPerSec / kMinFrameRate;
  // Processing time just below over use limit given kEncodeMaxFrameRate.
  int64_t processing_time_us =
      (98 * OveruseProcessingTimeLimitForFramerate(kMinFrameRate)) / 100;
  EXPECT_CALL(*(observer_.get()), AdaptDown(reason_)).Times(0);
  for (int i = 0; i < options_.high_threshold_consecutive_count; ++i) {
    InsertAndSendFramesWithInterval(1200, frame_interval_us, kWidth, kHeight,
                                    processing_time_us);
    overuse_detector_->CheckForOveruse();
  }

  // Over the limit to overuse.
  processing_time_us =
      (102 * OveruseProcessingTimeLimitForFramerate(kMinFrameRate)) / 100;
  EXPECT_CALL(*(observer_.get()), AdaptDown(reason_)).Times(1);
  for (int i = 0; i < options_.high_threshold_consecutive_count; ++i) {
    InsertAndSendFramesWithInterval(1200, frame_interval_us, kWidth, kHeight,
                                    processing_time_us);
    overuse_detector_->CheckForOveruse();
  }

  // Reduce input frame rate. Should still trigger overuse.
  overuse_detector_->OnTargetFramerateUpdated(kMinFrameRate - 1);
  EXPECT_CALL(*(observer_.get()), AdaptDown(reason_)).Times(1);
  for (int i = 0; i < options_.high_threshold_consecutive_count; ++i) {
    InsertAndSendFramesWithInterval(1200, frame_interval_us, kWidth, kHeight,
                                    processing_time_us);
    overuse_detector_->CheckForOveruse();
  }
}

TEST_F(OveruseFrameDetectorTest, LimitsMaxFrameInterval) {
  const int kMaxFrameRate = 20;
  overuse_detector_->OnTargetFramerateUpdated(kMaxFrameRate);
  int64_t frame_interval_us = rtc::kNumMicrosecsPerSec / kMaxFrameRate;
  // Maximum frame interval allowed is 35% above ideal.
  int64_t max_frame_interval_us = (135 * frame_interval_us) / 100;
  // Maximum processing time, without triggering overuse, allowed with the above
  // frame interval.
  int64_t max_processing_time_us =
      (max_frame_interval_us * options_.high_encode_usage_threshold_percent) /
      100;

  // Processing time just below overuse limit given kMaxFrameRate.
  int64_t processing_time_us = (98 * max_processing_time_us) / 100;
  EXPECT_CALL(*(observer_.get()), AdaptDown(reason_)).Times(0);
  for (int i = 0; i < options_.high_threshold_consecutive_count; ++i) {
    InsertAndSendFramesWithInterval(1200, max_frame_interval_us, kWidth,
                                    kHeight, processing_time_us);
    overuse_detector_->CheckForOveruse();
  }

  // Go above limit, trigger overuse.
  processing_time_us = (102 * max_processing_time_us) / 100;
  EXPECT_CALL(*(observer_.get()), AdaptDown(reason_)).Times(1);
  for (int i = 0; i < options_.high_threshold_consecutive_count; ++i) {
    InsertAndSendFramesWithInterval(1200, max_frame_interval_us, kWidth,
                                    kHeight, processing_time_us);
    overuse_detector_->CheckForOveruse();
  }

  // Increase frame interval, should still trigger overuse.
  max_frame_interval_us *= 2;
  EXPECT_CALL(*(observer_.get()), AdaptDown(reason_)).Times(1);
  for (int i = 0; i < options_.high_threshold_consecutive_count; ++i) {
    InsertAndSendFramesWithInterval(1200, max_frame_interval_us, kWidth,
                                    kHeight, processing_time_us);
    overuse_detector_->CheckForOveruse();
  }
}

// Models screencast, with irregular arrival of frames which are heavy
// to encode.
TEST_F(OveruseFrameDetectorTest, NoOveruseForLargeRandomFrameInterval) {
  // TODO(bugs.webrtc.org/8504): When new estimator is relanded,
  // behavior is improved in this scenario, with only AdaptUp events,
  // and estimated load closer to the true average.

  // EXPECT_CALL(*(observer_.get()), AdaptDown(_)).Times(0);
  // EXPECT_CALL(*(observer_.get()), AdaptUp(reason_))
  //     .Times(testing::AtLeast(1));

  const int kNumFrames = 500;
  const int kEncodeTimeUs = 100 * rtc::kNumMicrosecsPerMillisec;

  const int kMinIntervalUs = 30 * rtc::kNumMicrosecsPerMillisec;
  const int kMaxIntervalUs = 1000 * rtc::kNumMicrosecsPerMillisec;

  const int kTargetFramerate = 5;

  overuse_detector_->OnTargetFramerateUpdated(kTargetFramerate);

  InsertAndSendFramesWithRandomInterval(kNumFrames,
                                        kMinIntervalUs, kMaxIntervalUs,
                                        kWidth, kHeight, kEncodeTimeUs);
  // Average usage 19%. Check that estimate is in the right ball park.
  // EXPECT_NEAR(UsagePercent(), 20, 10);
  EXPECT_NEAR(UsagePercent(), 20, 35);
}

// Models screencast, with irregular arrival of frames, often
// exceeding the timeout interval.
TEST_F(OveruseFrameDetectorTest, NoOveruseForRandomFrameIntervalWithReset) {
  // TODO(bugs.webrtc.org/8504): When new estimator is relanded,
  // behavior is improved in this scenario, and we get AdaptUp events.
  EXPECT_CALL(*(observer_.get()), AdaptDown(_)).Times(0);
  // EXPECT_CALL(*(observer_.get()), AdaptUp(reason_))
  //     .Times(testing::AtLeast(1));

  const int kNumFrames = 500;
  const int kEncodeTimeUs = 100 * rtc::kNumMicrosecsPerMillisec;

  const int kMinIntervalUs = 30 * rtc::kNumMicrosecsPerMillisec;
  const int kMaxIntervalUs = 3000 * rtc::kNumMicrosecsPerMillisec;

  const int kTargetFramerate = 5;

  overuse_detector_->OnTargetFramerateUpdated(kTargetFramerate);

  InsertAndSendFramesWithRandomInterval(kNumFrames,
                                        kMinIntervalUs, kMaxIntervalUs,
                                        kWidth, kHeight, kEncodeTimeUs);

  // Average usage 6.6%, but since the frame_timeout_interval_ms is
  // only 1500 ms, we often reset the estimate to the initial value.
  // Check that estimate is in the right ball park.
  EXPECT_GE(UsagePercent(), 1);
  EXPECT_LE(UsagePercent(), InitialUsage() + 5);
}

// Tests using new cpu load estimator
class OveruseFrameDetectorTest2 : public OveruseFrameDetectorTest {
 protected:
  void SetUp() override {
    options_.filter_time_ms = 5 * rtc::kNumMillisecsPerSec;
    OveruseFrameDetectorTest::SetUp();
  }

  void InsertAndSendFramesWithInterval(int num_frames,
                                       int interval_us,
                                       int width,
                                       int height,
                                       int delay_us) override {
    VideoFrame frame(I420Buffer::Create(width, height),
                     webrtc::kVideoRotation_0, 0);
    while (num_frames-- > 0) {
      int64_t capture_time_us = rtc::TimeMicros();
      overuse_detector_->FrameCaptured(frame, capture_time_us /* ignored */);
      overuse_detector_->FrameSent(0 /* ignored timestamp */,
                                   0 /* ignored send_time_us */,
                                   capture_time_us, delay_us);
      clock_.AdvanceTimeMicros(interval_us);
    }
  }

  void InsertAndSendFramesWithRandomInterval(int num_frames,
                                             int min_interval_us,
                                             int max_interval_us,
                                             int width,
                                             int height,
                                             int delay_us) override {
    webrtc::Random random(17);

    VideoFrame frame(I420Buffer::Create(width, height),
                     webrtc::kVideoRotation_0, 0);
    for (int i = 0; i < num_frames; i++) {
      int interval_us = random.Rand(min_interval_us, max_interval_us);
      int64_t capture_time_us = rtc::TimeMicros();
      overuse_detector_->FrameCaptured(frame, capture_time_us);
      overuse_detector_->FrameSent(0 /* ignored timestamp */,
                                   0 /* ignored send_time_us */,
                                   capture_time_us, delay_us);

      overuse_detector_->CheckForOveruse();
      clock_.AdvanceTimeMicros(interval_us);
    }
  }

  void ForceUpdate(int width, int height) override {
    // This is mainly to check initial values and whether the overuse
    // detector has been reset or not.
    InsertAndSendFramesWithInterval(1, rtc::kNumMicrosecsPerSec, width, height,
                                    kFrameIntervalUs);
  }
};

// UsagePercent() > high_encode_usage_threshold_percent => overuse.
// UsagePercent() < low_encode_usage_threshold_percent => underuse.
TEST_F(OveruseFrameDetectorTest2, TriggerOveruse) {
  // usage > high => overuse
  EXPECT_CALL(*(observer_.get()), AdaptDown(reason_)).Times(1);
  TriggerOveruse(options_.high_threshold_consecutive_count);
}

TEST_F(OveruseFrameDetectorTest2, OveruseAndRecover) {
  // usage > high => overuse
  EXPECT_CALL(*(observer_.get()), AdaptDown(reason_)).Times(1);
  TriggerOveruse(options_.high_threshold_consecutive_count);
  // usage < low => underuse
  EXPECT_CALL(*(observer_.get()), AdaptUp(reason_)).Times(testing::AtLeast(1));
  TriggerUnderuse();
}

TEST_F(OveruseFrameDetectorTest2, OveruseAndRecoverWithNoObserver) {
  overuse_detector_.reset(new OveruseFrameDetectorUnderTest(
      options_, nullptr, this));
  EXPECT_CALL(*(observer_.get()), AdaptDown(reason_)).Times(0);
  TriggerOveruse(options_.high_threshold_consecutive_count);
  EXPECT_CALL(*(observer_.get()), AdaptUp(reason_)).Times(0);
  TriggerUnderuse();
}

TEST_F(OveruseFrameDetectorTest2, DoubleOveruseAndRecover) {
  EXPECT_CALL(*(observer_.get()), AdaptDown(reason_)).Times(2);
  TriggerOveruse(options_.high_threshold_consecutive_count);
  TriggerOveruse(options_.high_threshold_consecutive_count);
  EXPECT_CALL(*(observer_.get()), AdaptUp(reason_)).Times(testing::AtLeast(1));
  TriggerUnderuse();
}

TEST_F(OveruseFrameDetectorTest2, TriggerUnderuseWithMinProcessCount) {
  const int kProcessIntervalUs = 5 * rtc::kNumMicrosecsPerSec;
  options_.min_process_count = 1;
  CpuOveruseObserverImpl overuse_observer;
  overuse_detector_.reset(new OveruseFrameDetectorUnderTest(
      options_, &overuse_observer, this));
  InsertAndSendFramesWithInterval(
      1200, kFrameIntervalUs, kWidth, kHeight, kProcessTimeUs);
  overuse_detector_->CheckForOveruse();
  EXPECT_EQ(0, overuse_observer.normaluse_);
  clock_.AdvanceTimeMicros(kProcessIntervalUs);
  overuse_detector_->CheckForOveruse();
  EXPECT_EQ(1, overuse_observer.normaluse_);
}

TEST_F(OveruseFrameDetectorTest2, ConstantOveruseGivesNoNormalUsage) {
  EXPECT_CALL(*(observer_.get()), AdaptUp(reason_)).Times(0);
  EXPECT_CALL(*(observer_.get()), AdaptDown(reason_)).Times(64);
  for (size_t i = 0; i < 64; ++i) {
    TriggerOveruse(options_.high_threshold_consecutive_count);
  }
}

TEST_F(OveruseFrameDetectorTest2, ConsecutiveCountTriggersOveruse) {
  EXPECT_CALL(*(observer_.get()), AdaptDown(reason_)).Times(1);
  options_.high_threshold_consecutive_count = 2;
  ReinitializeOveruseDetector();
  TriggerOveruse(2);
}

TEST_F(OveruseFrameDetectorTest2, IncorrectConsecutiveCountTriggersNoOveruse) {
  EXPECT_CALL(*(observer_.get()), AdaptDown(reason_)).Times(0);
  options_.high_threshold_consecutive_count = 2;
  ReinitializeOveruseDetector();
  TriggerOveruse(1);
}

TEST_F(OveruseFrameDetectorTest2, ProcessingUsage) {
  InsertAndSendFramesWithInterval(
      1000, kFrameIntervalUs, kWidth, kHeight, kProcessTimeUs);
  EXPECT_EQ(kProcessTimeUs * 100 / kFrameIntervalUs, UsagePercent());
}

TEST_F(OveruseFrameDetectorTest2, ResetAfterResolutionChange) {
  ForceUpdate(kWidth, kHeight);
  EXPECT_EQ(InitialUsage(), UsagePercent());
  InsertAndSendFramesWithInterval(
      1000, kFrameIntervalUs, kWidth, kHeight, kProcessTimeUs);
  EXPECT_NE(InitialUsage(), UsagePercent());
  // Verify reset (with new width/height).
  ForceUpdate(kWidth, kHeight + 1);
  EXPECT_EQ(InitialUsage(), UsagePercent());
}

TEST_F(OveruseFrameDetectorTest2, ResetAfterFrameTimeout) {
  ForceUpdate(kWidth, kHeight);
  EXPECT_EQ(InitialUsage(), UsagePercent());
  InsertAndSendFramesWithInterval(
      1000, kFrameIntervalUs, kWidth, kHeight, kProcessTimeUs);
  EXPECT_NE(InitialUsage(), UsagePercent());
  InsertAndSendFramesWithInterval(
      2, options_.frame_timeout_interval_ms *
      rtc::kNumMicrosecsPerMillisec, kWidth, kHeight, kProcessTimeUs);
  EXPECT_NE(InitialUsage(), UsagePercent());
  // Verify reset.
  InsertAndSendFramesWithInterval(
      2, (options_.frame_timeout_interval_ms + 1) *
      rtc::kNumMicrosecsPerMillisec, kWidth, kHeight, kProcessTimeUs);
  ForceUpdate(kWidth, kHeight);
  EXPECT_EQ(InitialUsage(), UsagePercent());
}

TEST_F(OveruseFrameDetectorTest2, ConvergesSlowly) {
  InsertAndSendFramesWithInterval(1, kFrameIntervalUs, kWidth, kHeight,
                                  kProcessTimeUs);
  // No update for the first sample.
  EXPECT_EQ(InitialUsage(), UsagePercent());

  // Total time approximately 40 * 33ms = 1.3s, significantly less
  // than the 5s time constant.
  InsertAndSendFramesWithInterval(
      40, kFrameIntervalUs, kWidth, kHeight, kProcessTimeUs);

  // Should have started to approach correct load of 15%, but not very far.
  EXPECT_LT(UsagePercent(), InitialUsage());
  EXPECT_GT(UsagePercent(), (InitialUsage() * 3 + 15) / 4);

  // Run for roughly 10s more, should now be closer.
  InsertAndSendFramesWithInterval(
      300, kFrameIntervalUs, kWidth, kHeight, kProcessTimeUs);
  EXPECT_NEAR(UsagePercent(), 20, 5);
}

TEST_F(OveruseFrameDetectorTest2, InitialProcessingUsage) {
  ForceUpdate(kWidth, kHeight);
  EXPECT_EQ(InitialUsage(), UsagePercent());
}

TEST_F(OveruseFrameDetectorTest2, MeasuresMultipleConcurrentSamples) {
  EXPECT_CALL(*(observer_.get()), AdaptDown(reason_))
      .Times(testing::AtLeast(1));
  static const int kIntervalUs = 33 * rtc::kNumMicrosecsPerMillisec;
  static const size_t kNumFramesEncodingDelay = 3;
  VideoFrame frame(I420Buffer::Create(kWidth, kHeight),
                   webrtc::kVideoRotation_0, 0);
  for (size_t i = 0; i < 1000; ++i) {
    // Unique timestamps.
    frame.set_timestamp(static_cast<uint32_t>(i));
    int64_t capture_time_us = rtc::TimeMicros();
    overuse_detector_->FrameCaptured(frame, capture_time_us);
    clock_.AdvanceTimeMicros(kIntervalUs);
    if (i > kNumFramesEncodingDelay) {
      overuse_detector_->FrameSent(
          static_cast<uint32_t>(i - kNumFramesEncodingDelay), rtc::TimeMicros(),
          capture_time_us, kIntervalUs);
    }
    overuse_detector_->CheckForOveruse();
  }
}

TEST_F(OveruseFrameDetectorTest2, UpdatesExistingSamples) {
  // >85% encoding time should trigger overuse.
  EXPECT_CALL(*(observer_.get()), AdaptDown(reason_))
      .Times(testing::AtLeast(1));
  static const int kIntervalUs = 33 * rtc::kNumMicrosecsPerMillisec;
  static const int kDelayUs = 30 * rtc::kNumMicrosecsPerMillisec;
  VideoFrame frame(I420Buffer::Create(kWidth, kHeight),
                   webrtc::kVideoRotation_0, 0);
  uint32_t timestamp = 0;
  for (size_t i = 0; i < 1000; ++i) {
    frame.set_timestamp(timestamp);
    int64_t capture_time_us = rtc::TimeMicros();
    overuse_detector_->FrameCaptured(frame, capture_time_us);
    // Encode and send first parts almost instantly.
    clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerMillisec);
    overuse_detector_->FrameSent(timestamp, rtc::TimeMicros(), capture_time_us,
                                 rtc::kNumMicrosecsPerMillisec);
    // Encode heavier part, resulting in >85% usage total.
    clock_.AdvanceTimeMicros(kDelayUs - rtc::kNumMicrosecsPerMillisec);
    overuse_detector_->FrameSent(timestamp, rtc::TimeMicros(), capture_time_us,
                                 kDelayUs);
    clock_.AdvanceTimeMicros(kIntervalUs - kDelayUs);
    timestamp += kIntervalUs * 90 / 1000;
    overuse_detector_->CheckForOveruse();
  }
}

TEST_F(OveruseFrameDetectorTest2, RunOnTqNormalUsage) {
  rtc::TaskQueue queue("OveruseFrameDetectorTestQueue");

  rtc::Event event(false, false);
  queue.PostTask([this, &event] {
    overuse_detector_->StartCheckForOveruse();
    event.Set();
  });
  event.Wait(rtc::Event::kForever);

  // Expect NormalUsage(). When called, stop the |overuse_detector_| and then
  // set |event| to end the test.
  EXPECT_CALL(*(observer_.get()), AdaptUp(reason_))
      .WillOnce(InvokeWithoutArgs([this, &event] {
        overuse_detector_->StopCheckForOveruse();
        event.Set();
      }));

  queue.PostTask([this] {
    const int kDelayUs1 = 5 * rtc::kNumMicrosecsPerMillisec;
    const int kDelayUs2 = 6 * rtc::kNumMicrosecsPerMillisec;
    InsertAndSendFramesWithInterval(1300, kFrameIntervalUs, kWidth, kHeight,
                                    kDelayUs1);
    InsertAndSendFramesWithInterval(1, kFrameIntervalUs, kWidth, kHeight,
                                    kDelayUs2);
  });

  EXPECT_TRUE(event.Wait(10000));
}

// Models screencast, with irregular arrival of frames which are heavy
// to encode.
TEST_F(OveruseFrameDetectorTest2, NoOveruseForLargeRandomFrameInterval) {
  EXPECT_CALL(*(observer_.get()), AdaptDown(_)).Times(0);
  EXPECT_CALL(*(observer_.get()), AdaptUp(reason_))
      .Times(testing::AtLeast(1));

  const int kNumFrames = 500;
  const int kEncodeTimeUs = 100 * rtc::kNumMicrosecsPerMillisec;

  const int kMinIntervalUs = 30 * rtc::kNumMicrosecsPerMillisec;
  const int kMaxIntervalUs = 1000 * rtc::kNumMicrosecsPerMillisec;

  InsertAndSendFramesWithRandomInterval(kNumFrames,
                                        kMinIntervalUs, kMaxIntervalUs,
                                        kWidth, kHeight, kEncodeTimeUs);
  // Average usage 19%. Check that estimate is in the right ball park.
  EXPECT_NEAR(UsagePercent(), 20, 10);
}

// Models screencast, with irregular arrival of frames, often
// exceeding the timeout interval.
TEST_F(OveruseFrameDetectorTest2, NoOveruseForRandomFrameIntervalWithReset) {
  EXPECT_CALL(*(observer_.get()), AdaptDown(_)).Times(0);
  EXPECT_CALL(*(observer_.get()), AdaptUp(reason_))
      .Times(testing::AtLeast(1));

  const int kNumFrames = 500;
  const int kEncodeTimeUs = 100 * rtc::kNumMicrosecsPerMillisec;

  const int kMinIntervalUs = 30 * rtc::kNumMicrosecsPerMillisec;
  const int kMaxIntervalUs = 3000 * rtc::kNumMicrosecsPerMillisec;

  InsertAndSendFramesWithRandomInterval(kNumFrames,
                                        kMinIntervalUs, kMaxIntervalUs,
                                        kWidth, kHeight, kEncodeTimeUs);

  // Average usage 6.6%, but since the frame_timeout_interval_ms is
  // only 1500 ms, we often reset the estimate to the initial value.
  // Check that estimate is in the right ball park.
  EXPECT_GE(UsagePercent(), 1);
  EXPECT_LE(UsagePercent(), InitialUsage() + 5);
}

}  // namespace webrtc


text:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.hanrui.android.accountms.Outaccountinfo">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="我的支出"
        android:textSize="20sp"
        android:gravity="center"/>
    <ListView
        android:id="@+id/lvoutaccountinfo"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
    <TextView
        android:id="@+id/empty_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:text="还没有任何记录哦"/>
</LinearLayout>


text:
<!DOCTYPE html>

    <title id='Description'>In this demo the jqxInput is bound to JSON data.</title>
    <link rel="stylesheet" href="<?php echo base_url(); ?>assets/jqwidgets/jqwidgets/styles/jqx.base.css" type="text/css" />

    <link rel="stylesheet" href="<?php echo base_url(); ?>assets/jqwidgets/jqwidgets/styles/jqx.bootstrap.css" media="screen">

Thông báo thành công!

Thông báo lỗi!

                    <button id="btn"><?php echo lang('load') ?></button>


text:
<?php

namespace Kcs\WatchdogBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;

class ErrorController extends Controller
{
    public function showAction($id)
    {
        $error = $this->get('kcs.watchdog.storage')->find($id);
        if ($error === null) {
            throw $this->createNotFoundException();
        }

        return $this->render('KcsWatchdogBundle:Error:show.html.twig', array('error' => $error));
    }
}


text:
package us.kbase.test.auth2;

import java.util.HashMap;
import java.util.Map;

// http://stackoverflow.com/a/8879328/643675
public class MapBuilder<K,V> {

	private Map<K,V> map;

	public static <K,V> MapBuilder<K,V> newHashMap(){
		return new MapBuilder<K,V>(new HashMap<K,V>());
	}

	public MapBuilder(Map<K,V> map) {
		this.map = map;
	}

	public MapBuilder<K,V> with(K key, V value){
		map.put(key, value);
		return this;
	}

	public Map<K,V> build(){
		return map;
	}

}


text:
namespace Kafka.Client.Exceptions
{
    using System;

    public class MessageSizeTooLargeException : Exception
    {
    }
}


text:
jobs.workdistributed.com
========================

Code I wrote as an exercise (hosted at jobs.workdistributed.com)


text:
__author__ = "mfreer"
__date__ = "2012-08-24 08:41"
__version__ = "1.3"
__all__ = ['ScatteringAngles']

import egads.core.egads_core as egads_core
import egads.core.metadata as egads_metadata
import numpy

class ScatteringAngles(egads_core.EgadsAlgorithm):

    """
    FILE        scattering_angles.py

    VERSION     1.3

    CATEGORY    Radiation

    PURPOSE     Calculates the scattering angle for each pixel on an image given the camera
                viewing angle and solar vector.

    DESCRIPTION Calculates the scattering angle for each pixel on an image given the camera
                viewing angle and solar vector.

    INPUT       n_x        coeff            _        number of pixels in x dimension
                n_y        coeff            _        number of pixels in y dimension
                theta_c    array[n_x,n_y]   deg      camera viewing zenith angle
                phi_c      array[n_x,n_y]   deg      camera viewing azimuth angle (0 deg = flight dir)
                theta_sun  coeff            deg      solar zenith angle
                phi_sun    coeff            deg      solar azimuth angle

    OUTPUT      theta_scat    array[n_x, n_y]    deg    scattering angles of each pixel

    SOURCE      Andre Ehrlich, Leipzig Institute for Meteorology (a.ehrlich@uni-leipzig.de)

    REFERENCES
    """

    def __init__(self, return_Egads=True):
        egads_core.EgadsAlgorithm.__init__(self, return_Egads)
        self.output_metadata = egads_metadata.VariableMetadata({'units':'deg',
                                                               'long_name':'scattering angle',
                                                               'standard_name':'',
                                                               'Category':['Radiation']})

        self.metadata = egads_metadata.AlgorithmMetadata({'Inputs':['n_x', 'n_y', 'theta_c', 'phi_c', 'theta_sun', 'phi_sun'],
                                                          'InputUnits':['', '', 'deg', 'deg', 'deg', 'deg'],
                                                          'InputTypes':['coeff', 'coeff', 'array', 'array', 'coeff', 'coeff'],
                                                          'InputDescription':['Number of pixels in x dimension',
                                                                              'Number of pixels in y dimension',
                                                                              'Camera viewing zenith angle',
                                                                              'Camera viewing azimuth angle (0 deg = flight dir)',
                                                                              'Solar zenith angle',
                                                                              'Solar azimuth angle'],
                                                          'Outputs':['theta_scat'],
                                                          'OutputUnits':['deg'],
                                                          'OutputTypes':['array[n_x, n_y]'],
                                                          'OutputDescription':['Scattering angles of each pixel'],
                                                          'Purpose':'Calculates the scattering angle for each pixel on an image given the camera viewing angle and solar vector',
                                                          'Description':'No description',
                                                          'Category':'Radiation',
                                                          'Source':'Andre Ehrlich, Leipzig Institute for Meteorology (a.ehrlich@uni-leipzig.de)',
                                                          'References':'',
                                                          'Processor':self.name,
                                                          'ProcessorDate':__date__,
                                                          'ProcessorVersion':__version__,
                                                          'DateProcessed':self.now()},
                                                          self.output_metadata)

    def run(self, n_x, n_y, theta_c, phi_c, theta_sun, phi_sun):
        return egads_core.EgadsAlgorithm.run(self, n_x, n_y, theta_c, phi_c, theta_sun, phi_sun)

    def _algorithm(self, n_x, n_y, theta_c, phi_c, theta_sun, phi_sun):
        sin = numpy.sin
        cos = numpy.cos
        rad2deg = 180 / numpy.pi
        deg2rad = numpy.pi / 180.0
        theta_sun_r = theta_sun * deg2rad
        phi_sun_r = phi_sun * deg2rad
        theta_c_r = theta_c * deg2rad
        phi_c_r = phi_c * deg2rad
        theta_scat_r = numpy.arccos(-sin(theta_sun_r) * cos(phi_sun_r) * sin(theta_c_r) * cos(phi_c_r)
                                  - sin(theta_sun_r) * sin(phi_sun_r) * sin(theta_c_r) * cos(phi_c_r)
                                  + cos(theta_sun_r) * cos(theta_c_r))
        theta_scat = theta_scat_r * rad2deg
        return theta_scat


text:
module Pohoda
  module Parsers
    module Int
      class IntDocType
        include ParserCore::BaseParser

        def int_doc_header
          submodel_at(Int::IntDocHeaderType, 'int:intDocHeader')
        end

        def int_doc_detail
          array_of_at(Int::IntDocItemType, ['int:intDocDetail', 'int:intDocItem'])
        end

        def int_doc_summary
          submodel_at(Int::IntDocSummaryType, 'int:intDocSummary')
        end

        def print
          array_of_at(Prn::PrinterSettingsType, ['int:print', 'prn:printerSettings'])
        end

        def to_h
          hash = {}
          hash[:attributes] = attributes

          hash[:int_doc_header] = int_doc_header.to_h if has? 'int:intDocHeader'
          hash[:int_doc_detail] = int_doc_detail.map(&:to_h) if has? 'int:intDocDetail'
          hash[:int_doc_summary] = int_doc_summary.to_h if has? 'int:intDocSummary'
          hash[:print] = print.map(&:to_h) if has? 'int:print'

          hash
        end
      end
    end
  end
end


text:
<?php

declare(strict_types=1);

/*
 * This file is part of the SkeletonDancer package.
 *
 * (c) Sebastiaan Stok <s.stok@rollerscapes.net>
 *
 * This source file is subject to the MIT license that is bundled
 * with this source code in the file LICENSE.
 */

namespace SkeletonDancer\Test;

use Symfony\Component\Console\Question\Question;
use Symfony\Component\Console\Style\SymfonyStyle;

class SymfonyStyleTestHelper extends SymfonyStyle
{
    public function askQuestion(Question $question)
    {
        $question->setMaxAttempts(1);

        return parent::askQuestion($question);
    }
}


text:
@class BaseResponse, NSMutableArray;

@interface GetTalkRoomMemberResp : WXPBGeneratedMessage
{
}

+ (void)initialize;

// Remaining properties
@property(retain, nonatomic) BaseResponse *baseResponse; // @dynamic baseResponse;
@property(retain, nonatomic) NSMutableArray *memberList; // @dynamic memberList;
@property(nonatomic) int memberNum; // @dynamic memberNum;
@property(nonatomic) int micSeq; // @dynamic micSeq;

@end


text:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>org.aludratest.eclipse</groupId>
	<artifactId>org.aludratest.eclipse.vde</artifactId>
	<version>0.6.7.qualifier</version>
	<name>AludraTest Eclipse Visual Data Editor</name>
	<description>Visual Data Editor Plug-In for Eclipse IDE.</description>

	<packaging>eclipse-plugin</packaging>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<tycho-version>0.22.0</tycho-version>
	</properties>

	<repositories>
		<repository>
			<id>p2-eclipse-kepler</id>
			<url>http://download.eclipse.org/releases/kepler</url>
			<layout>p2</layout>
		</repository>
		<repository>
			<id>p2-eclipse-nattable</id>
			<url>http://download.eclipse.org/nattable/releases/1.3.0/repository</url>
			<layout>p2</layout>
		</repository>
	</repositories>

	<build>
		<plugins>
			<plugin>
				<groupId>org.eclipse.tycho</groupId>
				<artifactId>tycho-maven-plugin</artifactId>
				<version>${tycho-version}</version>
				<extensions>true</extensions>
			</plugin>

			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.1</version>
				<configuration>
					<source>1.6</source>
					<target>1.6</target>
				</configuration>
			</plugin>

			<!-- copy JAR dependencies to lib -->
			<plugin>
				<artifactId>maven-dependency-plugin</artifactId>
				<version>2.10</version>
				<executions>
					<execution>
						<id>copy-dependencies</id>
						<phase>validate</phase>
						<goals>
							<goal>copy</goal>
						</goals>
						<configuration>
							<artifactItems>
								<artifactItem>
									<groupId>org.aludratest</groupId>
									<artifactId>aludratest</artifactId>
									<version>3.0.2</version>
									<destFileName>aludratest-3.0.2.jar</destFileName>
								</artifactItem>
								<artifactItem>
									<groupId>org.databene</groupId>
									<artifactId>databene-commons</artifactId>
									<version>1.0.5</version>
								</artifactItem>
								<artifactItem>
									<groupId>org.databene</groupId>
									<artifactId>databene-formats</artifactId>
									<version>1.0.11</version>
								</artifactItem>
								<artifactItem>
									<groupId>org.mozilla</groupId>
									<artifactId>rhino</artifactId>
									<version>1.7R5</version>
								</artifactItem>
							</artifactItems>
							<outputDirectory>lib</outputDirectory>
						</configuration>
					</execution>
				</executions>
			</plugin>

			<plugin>
				<groupId>org.eclipse.tycho</groupId>
				<artifactId>tycho-source-plugin</artifactId>
				<version>${tycho-version}</version>
				<executions>
					<execution>
						<id>plugin-source</id>
						<goals>
							<goal>plugin-source</goal>
						</goals>
					</execution>
				</executions>
			</plugin>
		</plugins>
	</build>

</project>


text:
#include "gm/gm.h"
#include "include/core/SkCanvas.h"
#include "include/core/SkColor.h"
#include "include/core/SkMatrix.h"
#include "include/core/SkPaint.h"
#include "include/core/SkPathBuilder.h"
#include "include/core/SkPathEffect.h"
#include "include/core/SkRect.h"
#include "include/core/SkRefCnt.h"
#include "include/core/SkScalar.h"
#include "include/core/SkSize.h"
#include "include/core/SkString.h"
#include "include/core/SkTypes.h"
#include "include/effects/SkDashPathEffect.h"
#include "tools/timer/TimeUtils.h"

int dash1[] = { 1, 1 };
int dash2[] = { 1, 3 };
int dash3[] = { 1, 1, 3, 3 };
int dash4[] = { 1, 3, 2, 4 };

struct DashExample {
    int* pattern;
    int length;
} dashExamples[] = {
    { dash1, SK_ARRAY_COUNT(dash1) },
    { dash2, SK_ARRAY_COUNT(dash2) },
    { dash3, SK_ARRAY_COUNT(dash3) },
    { dash4, SK_ARRAY_COUNT(dash4) }
};

class DashCircleGM : public skiagm::GM {
public:
    DashCircleGM() : fRotation(0) { }

protected:
    SkString onShortName() override { return SkString("dashcircle"); }

    SkISize onISize() override { return SkISize::Make(900, 1200); }

    void onDraw(SkCanvas* canvas) override {
        SkPaint refPaint;
        refPaint.setAntiAlias(true);
        refPaint.setColor(0xFFbf3f7f);
        refPaint.setStroke(true);
        refPaint.setStrokeWidth(1);
        const SkScalar radius = 125;
        SkRect oval = SkRect::MakeLTRB(-radius - 20, -radius - 20, radius + 20, radius + 20);
        SkPath circle = SkPath::Circle(0, 0, radius);
        SkScalar circumference = radius * SK_ScalarPI * 2;
        int wedges[] = { 6, 12, 36 };
        canvas->translate(radius+20, radius+20);
        for (int wedge : wedges) {
            SkScalar arcLength = 360.f / wedge;
            canvas->save();
            for (const DashExample& dashExample : dashExamples) {
                SkPathBuilder refPath;
                int dashUnits = 0;
                for (int index = 0; index < dashExample.length; ++index) {
                    dashUnits += dashExample.pattern[index];
                }
                SkScalar unitLength = arcLength / dashUnits;
                SkScalar angle = 0;
                for (int index = 0; index < wedge; ++index) {
                    for (int i2 = 0; i2 < dashExample.length; i2 += 2) {
                        SkScalar span = dashExample.pattern[i2] * unitLength;
                        refPath.moveTo(0, 0);
                        refPath.arcTo(oval, angle, span, false);
                        refPath.close();
                        angle += span + (dashExample.pattern[i2 + 1]) * unitLength;
                    }
                }
                canvas->save();
                canvas->rotate(fRotation);
                canvas->drawPath(refPath.detach(), refPaint);
                canvas->restore();
                SkPaint p;
                p.setAntiAlias(true);
                p.setStroke(true);
                p.setStrokeWidth(10);
                SkScalar intervals[4];
                int intervalCount = dashExample.length;
                SkScalar dashLength = circumference / wedge / dashUnits;
                for (int index = 0; index < dashExample.length; ++index) {
                    intervals[index] = dashExample.pattern[index] * dashLength;
                }
                p.setPathEffect(SkDashPathEffect::Make(intervals, intervalCount, 0));
                canvas->save();
                canvas->rotate(fRotation);
                canvas->drawPath(circle, p);
                canvas->restore();
                canvas->translate(0, radius * 2 + 50);
            }
            canvas->restore();
            canvas->translate(radius * 2 + 50, 0);
        }
    }

    bool onAnimate(double nanos) override {
        constexpr SkScalar kDesiredDurationSecs = 100.0f;

        fRotation = TimeUtils::Scaled(1e-9 * nanos, 360.0f/kDesiredDurationSecs, 360.0f);
        return true;
    }

private:
    SkScalar fRotation;

    using INHERITED = GM;
};

DEF_GM(return new DashCircleGM; )

class DashCircle2GM : public skiagm::GM {
public:
    DashCircle2GM() {}

protected:
    SkString onShortName() override { return SkString("dashcircle2"); }

    SkISize onISize() override { return SkISize::Make(635, 900); }

    void onDraw(SkCanvas* canvas) override {
        // These intervals are defined relative to tau.
        static constexpr SkScalar kIntervals[][2]{
                {0.333f, 0.333f},
                {0.015f, 0.015f},
                {0.01f , 0.09f },
                {0.097f, 0.003f},
                {0.02f , 0.04f },
                {0.1f  , 0.2f  },
                {0.25f , 0.25f },
                {0.6f  , 0.7f  }, // adds to > 1
                {1.2f  , 0.8f  }, // on is > 1
                {0.1f  , 1.1f  }, // off is > 1*/
        };

        static constexpr int kN = SK_ARRAY_COUNT(kIntervals);
        static constexpr SkScalar kRadius = 20.f;
        static constexpr SkScalar kStrokeWidth = 15.f;
        static constexpr SkScalar kPad = 5.f;
        static constexpr SkRect kCircle = {-kRadius, -kRadius, kRadius, kRadius};

        static constexpr SkScalar kThinRadius = kRadius * 1.5;
        static constexpr SkRect kThinCircle = {-kThinRadius, -kThinRadius,
                                                kThinRadius,  kThinRadius};
        static constexpr SkScalar kThinStrokeWidth = 0.4f;

        sk_sp<SkPathEffect> deffects[SK_ARRAY_COUNT(kIntervals)];
        sk_sp<SkPathEffect> thinDEffects[SK_ARRAY_COUNT(kIntervals)];
        for (int i = 0; i < kN; ++i) {
            static constexpr SkScalar kTau = 2 * SK_ScalarPI;
            static constexpr SkScalar kCircumference = kRadius * kTau;
            SkScalar scaledIntervals[2] = {kCircumference * kIntervals[i][0],
                                           kCircumference * kIntervals[i][1]};
            deffects[i] = SkDashPathEffect::Make(
                    scaledIntervals, 2, kCircumference * fPhaseDegrees * kTau / 360.f);
            static constexpr SkScalar kThinCircumference = kThinRadius * kTau;
            scaledIntervals[0] = kThinCircumference * kIntervals[i][0];
            scaledIntervals[1] = kThinCircumference * kIntervals[i][1];
            thinDEffects[i] = SkDashPathEffect::Make(
                    scaledIntervals, 2, kThinCircumference * fPhaseDegrees * kTau / 360.f);
        }

        SkMatrix rotate;
        rotate.setRotate(25.f);
        const SkMatrix kMatrices[]{
                SkMatrix::I(),
            SkMatrix::Scale(1.2f, 1.2f),
                SkMatrix::MakeAll(1, 0, 0, 0, -1, 0, 0, 0, 1),  // y flipper
                SkMatrix::MakeAll(-1, 0, 0, 0, 1, 0, 0, 0, 1),  // x flipper
            SkMatrix::Scale(0.7f, 0.7f),
                rotate,
                SkMatrix::Concat(
                        SkMatrix::Concat(SkMatrix::MakeAll(-1, 0, 0, 0, 1, 0, 0, 0, 1), rotate),
                        rotate)
        };

        SkPaint paint;
        paint.setAntiAlias(true);
        paint.setStrokeWidth(kStrokeWidth);
        paint.setStroke(true);

        // Compute the union of bounds of all of our test cases.
        SkRect bounds = SkRect::MakeEmpty();
        const SkRect kBounds = kThinCircle.makeOutset(kThinStrokeWidth / 2.f,
                                                      kThinStrokeWidth / 2.f);
        for (const auto& m : kMatrices) {
            SkRect devBounds;
            m.mapRect(&devBounds, kBounds);
            bounds.join(devBounds);
        }

        canvas->save();
        canvas->translate(-bounds.fLeft + kPad, -bounds.fTop + kPad);
        for (size_t i = 0; i < SK_ARRAY_COUNT(deffects); ++i) {
            canvas->save();
            for (const auto& m : kMatrices) {
                canvas->save();
                canvas->concat(m);

                paint.setPathEffect(deffects[i]);
                paint.setStrokeWidth(kStrokeWidth);
                canvas->drawOval(kCircle, paint);

                paint.setPathEffect(thinDEffects[i]);
                paint.setStrokeWidth(kThinStrokeWidth);
                canvas->drawOval(kThinCircle, paint);

                canvas->restore();
                canvas->translate(bounds.width() + kPad, 0);
            }
            canvas->restore();
            canvas->translate(0, bounds.height() + kPad);
        }
        canvas->restore();
    }

protected:
    bool onAnimate(double nanos) override {
        fPhaseDegrees = 1e-9 * nanos;
        return true;
    }

    // Init with a non-zero phase for when run as a non-animating GM.
    SkScalar fPhaseDegrees = 12.f;
};

DEF_GM(return new DashCircle2GM;)

DEF_SIMPLE_GM(maddash, canvas, 1600, 1600) {
    canvas->drawRect({0, 0, 1600, 1600}, SkPaint());
    SkPaint p;
    p.setColor(SK_ColorRED);
    p.setAntiAlias(true);
    p.setStroke(true);
    p.setStrokeWidth(380);

    SkScalar intvls[] = { 2.5, 10 /* 1200 */ };
    p.setPathEffect(SkDashPathEffect::Make(intvls, 2, 0));

    canvas->drawCircle(400, 400, 200, p);

    SkPathBuilder path;
    path.moveTo(800, 400);
    path.quadTo(1000, 400, 1000, 600);
    path.quadTo(1000, 800, 800, 800);
    path.quadTo(600, 800, 600, 600);
    path.quadTo(600, 400, 800, 400);
    path.close();
    canvas->translate(350, 150);
    p.setStrokeWidth(320);
    canvas->drawPath(path.detach(), p);

    path.moveTo(800, 400);
    path.cubicTo(900, 400, 1000, 500, 1000, 600);
    path.cubicTo(1000, 700, 900, 800, 800, 800);
    path.cubicTo(700, 800, 600, 700, 600, 600);
    path.cubicTo(600, 500, 700, 400, 800, 400);
    path.close();
    canvas->translate(-550, 500);
    p.setStrokeWidth(300);
    canvas->drawPath(path.detach(), p);
}


text:
namespace System.Collections.Generic
{
    /// <summary>
    /// Provides common operations with <see cref="HashSet{T}"/> instances as extension methods.
    /// </summary>
    public static class HashSetExtensions
    {
        /// <summary>
        /// Converts a target enumerable into a new instance of a <see cref="HashSet{T}"/>.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="set"></param>
        /// <returns></returns>
        public static HashSet<T> ToHashSet<T>(this IEnumerable<T> set)
        {
            return new HashSet<T>(set);
        }
    }
}