text:
package gov.sandia.seme.framework;

import java.io.Serializable;

/**
 * Provides methods for handling meta-data attributes attached to an object. The
 * underlying implementation left to the user, this interface defines methods
 * for setting and retrieving key:value pairs of information for a given object.
 *
 * @htmlonly
 * @author David Hart, dbhart
 * @endhtmlonly
 */
public interface Describable extends Serializable {

    /**
     * Get a named option.
     *
     * @param name the key name
     * @return the value
     */
    Object getOpt(String name);

    /**
     * Set a named option.
     *
     * @param name the key name
     * @param val the new value
     */
    void setOpt(String name, Object val);

    /**
     * Get a named option as a double.
     *
     * @param name the key name
     * @return the value
     */
    double getDoubleOpt(String name);

    /**
     * Set a named option from a double.
     *
     * @param name the key name
     * @param val the new value
     */
    void setDoubleOpt(String name, double val);

    /**
     * Get a named option as a string.
     *
     * @param name the key name
     * @return the value
     */
    String getStringOpt(String name);

    /**
     * Set the named option as a string.
     *
     * @param name the key name
     * @param val the new value
     */
    void setStringOpt(String name, String val);

    /**
     * Get a named option as an integer.
     *
     * @param name the key name
     * @return the value
     */
    int getIntegerOpt(String name);

    /**
     * Set the named option as an integer.
     *
     * @param name the key name
     * @param val the new value
     */
    void setIntegerOpt(String name, int val);

    /**
     * Get a named option as a double array.
     *
     * @param name the key name
     * @return the value array
     */
    double[] getDoubleArrayOpt(String name);

    /**
     * Set the named option to an array of doubles.
     *
     * @param name the key name
     * @param values the new list of values
     */
    void setDoubleArrayOpt(String name, double[] values);

    /**
     * Get a named option as a string array.
     *
     * @param name the key name
     * @return the value array
     */
    String[] getStringArrayOpt(String name);

    /**
     * Set the named option to an array of Strings.
     *
     * @param name the key name
     * @param values the new list of values
     */
    void setStringArrayOpt(String name, String[] values);

    /**
     * Get a named option as an integer array.
     *
     * @param name the key name
     * @return the value array
     */
    int[] getIntegerArrayOpt(String name);

    /**
     * Set the named option to an array of integers.
     *
     * @param name the key name
     * @param values the new list of values
     */
    void setIntegerArrayOpt(String name, int[] values);

    /**
     * Set the underlying meta-data obeject.
     *
     * @param metaData the new meta-data object
     */
    void setMetaData(Object metaData);

    /**
     * Get the underlying meta-data storage object.
     *
     * @return the underlying meta-data storage object
     */
    Object getMetaData();

    /**
     * Get a list of all key names.
     *
     * @return the list of all key names
     */
    String[] getOptKeys();

}


text:
package org.projectfloodlight.openflow.protocol.ver11;

import org.projectfloodlight.openflow.protocol.*;
import org.projectfloodlight.openflow.protocol.action.*;
import org.projectfloodlight.openflow.protocol.actionid.*;
import org.projectfloodlight.openflow.protocol.bsntlv.*;
import org.projectfloodlight.openflow.protocol.errormsg.*;
import org.projectfloodlight.openflow.protocol.meterband.*;
import org.projectfloodlight.openflow.protocol.instruction.*;
import org.projectfloodlight.openflow.protocol.instructionid.*;
import org.projectfloodlight.openflow.protocol.match.*;
import org.projectfloodlight.openflow.protocol.stat.*;
import org.projectfloodlight.openflow.protocol.oxm.*;
import org.projectfloodlight.openflow.protocol.oxs.*;
import org.projectfloodlight.openflow.protocol.queueprop.*;
import org.projectfloodlight.openflow.types.*;
import org.projectfloodlight.openflow.util.*;
import org.projectfloodlight.openflow.exceptions.*;
import org.projectfloodlight.openflow.protocol.OFGroupType;
import io.netty.buffer.ByteBuf;
import com.google.common.hash.PrimitiveSink;

public class OFGroupTypeSerializerVer11 {

    public final static byte ALL_VAL = (byte) 0x0;
    public final static byte SELECT_VAL = (byte) 0x1;
    public final static byte INDIRECT_VAL = (byte) 0x2;
    public final static byte FF_VAL = (byte) 0x3;

    public static OFGroupType readFrom(ByteBuf bb) throws OFParseError {
        try {
            return ofWireValue(bb.readByte());
        } catch (IllegalArgumentException e) {
            throw new OFParseError(e);
        }
    }

    public static void writeTo(ByteBuf bb, OFGroupType e) {
        bb.writeByte(toWireValue(e));
    }

    public static void putTo(OFGroupType e, PrimitiveSink sink) {
        sink.putByte(toWireValue(e));
    }

    public static OFGroupType ofWireValue(byte val) {
        switch(val) {
            case ALL_VAL:
                return OFGroupType.ALL;
            case SELECT_VAL:
                return OFGroupType.SELECT;
            case INDIRECT_VAL:
                return OFGroupType.INDIRECT;
            case FF_VAL:
                return OFGroupType.FF;
            default:
                throw new IllegalArgumentException("Illegal wire value for type OFGroupType in version 1.1: " + val);
        }
    }

    public static byte toWireValue(OFGroupType e) {
        switch(e) {
            case ALL:
                return ALL_VAL;
            case SELECT:
                return SELECT_VAL;
            case INDIRECT:
                return INDIRECT_VAL;
            case FF:
                return FF_VAL;
            default:
                throw new IllegalArgumentException("Illegal enum value for type OFGroupType in version 1.1: " + e);
        }
    }

}

redpajama_set_name: RedPajamaGithub


text:
Dublin Traceroute now has a blog! Check it out at
https://blog.dublin-traceroute.net .

### What is it?

**Dublin Traceroute is a NAT-aware multipath tracerouting tool**

Modern networks leverage [Equal-cost Multi-Path routing](https://en.wikipedia.org/wiki/Equal-cost_multi-path_routing)
for load balancing, reliability, and network capacity reasons.
Traditional traceroute may provide hard-to-interpret or even misleading results
when used in presence of ECMP routing. Tools like
[paris-traceroute](https://paris-traceroute.net) were created to address this
issue. Dublin Traceroute:
* adds a new NAT detection technique on top of that
* introduces visualization and analysis tools (via its [Python
  bindings](https://github.com/insomniacslk/python-dublin-traceroute))
* provides a modular and reusable library for easier integration.

Dublin Traceroute is released under the [2-clause BSD license](http://opensource.org/licenses/BSD-2-Clause)).

### How does it work?

Dublin Traceroute uses the techniques invented by the authors of
[Paris-traceroute](http://paris-traceroute.net) to enumerate the paths of ECMP
flow-based load balancing, and introduces a new technique for NAT detection.

The multipath enumeration is explained at
[http://paris-traceroute.net/about](http://paris-traceroute.net/about), which I
recommend to read.
In short, IP packets travelling from host A to host B may take different paths
depending on the presence of ECMP routing. Given that now there are multiple
equal-cost paths between A and B, traditional traceroute cannot force packets
through a unique path, and cannot distinguish which path each packet belongs to.

A visual example will make it easier to understand:

![multipath network](tr01.png)
[[diagram source]](tr01.dot)

In the above graph you can see that there are two "first hops", namely B and C.
The same thing for the "second hops" (D and E), and a packet either traverses B
-> D -> F, or traverses C -> E -> F.
Traditional traceroute has no knowledge that a packet may traverse multiple
paths

![regular traceroute on an ECMP network](tr02.png)
[[diagram source]](tr02.dot)

The black arrows in the above graph indicate the possible network paths, the red
arrows show a possible path that traditional traceroute may show you instead of the
correct ones.

It gets worse when two equal-cost paths have different lengths:

![regular traceroute on variable-length ECMP network](tr03.png)
[[diagram source]](tr03.dot)

The team who created Paris-traceroute invented a technique that leverages the ECMP
flow hashing to probe all the possible paths. Dublin Traceroute does what
Paris-traceroute can do, plus a bit more.

### So, what's new?

Three things:

**It can detect NATs.**
Dublin Traceroute can detect whether a traceroute is traversing NATs. For
example, if your home router hides your network behind a NAT, Dublin Traceroute
will detect that, and will also detect other NATs that are being traversed (e.g.
your ISP's CGNAT).

To detect NATs, Dublin Traceroute forges a custom IP ID in the outgoing packets,
and keeps track of them in the response packets.
If the response packet references an outgoing packet with different
source/destination IP addresses and ports, this may indicate the presence of a
NAT. In that case, the packet referenced in the response will be different from
the one that was sent, and cannot be correlated anymore. However, the IP ID is
expected to be unchanged (thanks to the presence of the `don't-fragment` bit), and
it will contain a value to correlate it to one of the outgoing packets.

Note that this technique is different from Steven Bellovin's
[A technique for Counting NATted Hosts](https://www.cs.columbia.edu/~smb/papers/fnat.pdf).

At the best of my knowledge, there is no prior technique like this. If I am wrong,
please let me know so that I can give credit where due.

**It is modular and reusable.**
Dublin Traceroute is implemented as a library and a command-line tool, making it
easy to reuse in your projects.
The results are encoded in JSON format, so you can easily integrate them in your
own application.

The core library and CLI are written in C++1, using the beautiful network packet library
[libtins](https://libtins.github.io).

If you prefer to use Python, or if you need graphical visualization and data
analysis, you can use [the Python bindings](https://github.com/insomniacslk/python-dublin-traceroute).

There is also a Go implementation in this repository, which I use for
experimentation. The Go implementation has feature parity with the C++ one, and
adds IPv6 UDP support. However the C++ implementation is the main one, and
every new feature will be eventually backported to it.

**It supports certain types of broken NATs.**
Dublin Traceroute is able to work with some broken NATs that some hosting providers use
( ~~e.g. I found that Scaleway does that~~ update: they fixed it, see https://github.com/insomniacslk/dublin-traceroute/issues/28).
When you run through this kind of NAT, you will see that neither traditional traceroute
nor paris-traceroute show responses beyond that point, even if those response packets
arrived back.

See the [examples](examples.md) to see Dublin Traceroute at work.

### Why?

Paris-traceroute is a nice tool, and the research behind it is really cool. The
implementation is a good proof-of-concept, but I needed more.

It all started as an excuse to learn more about C++11. Then I found libtins, so I
decided to write a C++11 implementation of paris-traceroute. I wanted it to
be flexible, expressive and simple to understand.

## Examples

Below the graphical output of a traceroute to Google's public DNS, 8.8.8.8. You can see the various
paths, the NAT detecton and the ICMP codes of the received packets.

![dublin-traceroute example](traceroute_8.8.8.8.png)

See the [examples](examples.md) page for more examples on the command-line tool and the C++ and Python libraries.

## Objectives

Dublin Traceroute aims to be:

* fast
* easy to use
* multi-language (currently C++ and Python, plus a parallel Go
  implementation)
* multi-platform: any system with a reasonable C++11 or Go compiler will work
* accurate: the reported paths should be as close as possible to the reality
* visual: it can generate diagrams from the traceroute data
* robust: no memory leaks, no crashes
* usable in larger systems
* business-friendly from the licensing point of view (it is released under the
  [2-clause BSD license](http://opensource.org/licenses/BSD-2-Clause))

## Feature matrix

There are three code bases, one in C++, one in Go, and one in Python. Why so
many? Originally, `dublin-traceroute` was written in C++11. Then I added Python
bindings to simplify the generation of the dot file for graphical output, and to
allow Pandas support for statistical analysis.
Later on I realized that the C++ implementation was limiting the speed of
development of `dublin-traceroute`, so I gave it a try with Go. A basic
implementation took one afternoon, and a few more days to make it 100%
compatible with the C++ one, and to implement IPv6 probes. This suggested that
the Go implementation could become the primary one in the future. However Go
binaries are far larger than C++ ones, which is an issue on memory-constrained
devices, so the switchover is not going to happen soon.

The matrix below compares the features of each implementation. Remember that the
Python bindings add features on top of the C++ library.

|     | C++ cli/lib | Python bindings | Go cli |
| --- | --- | --- | --- |
| IPv4/UDP probe | yes | yes (using C++ lib) | yes |
| IPv6/UDP probe | no | no (depends on C++ lib) | yes |
| IPv4/TCP probe | no | no (depends on C++ lib) | no |
| IPv6/TCP probe | no | no (depends on C++ lib) | no |
| IPv4/ICMP probe | no | no (depends on C++ lib) | no |
| IPv6/ICMP probe | no | no (depends on C++ lib) | no |
| JSON output | yes | yes (depends on C++ lib) | yes |
| DOT output | yes | yes (depends on C++ lib) | yes |
| PNG output | no (done in Python bindings) | yes | no (done in Python bindings) |
| Statistical analysis | no (done in Python bindings) | yes (using Pandas) | no (done in Python bindings, might switch to go-gota) |
| Multi-platform | no (Linux-only, macOS breaks at every major release) | yes (where Python runs, and Linux-only if using traceroute functionalities) | yes (Linux, macOS tested, might work on others) |
| Can be used as a library | yes | yes | no |
| Linking | dynamic | dynamic | static |
| Size | ~650kb libdublintraceroute + 700kb libtins (+ optional libpcap) | ~450kb Python lib + 650kb C++ lib | ~4MB static binary |
| Depends on libpcap | yes if libtins is compiled with libcap support | yes if libtins is compiled with libpcap support | no |

## Installation instructions

### From packages

Dublin Traceroute is packaged in several Linux distributions.

**Debian, Ubuntu, or any other Debian-based system**
```
apt install dublin-traceroute
```

https://tracker.debian.org/pkg/dublin-traceroute
https://packages.ubuntu.com/search?keywords=dublin-traceroute

**ArchLinux**
```
pacman install dublin-traceroute
```

https://aur.archlinux.org/packages/dublin-traceroute/

**Fedora, RedHat, CentOS**

Use the `teknoraver/networking` COPR at https://copr.fedorainfracloud.org/coprs/teknoraver/networking/

Then `yum update` and `yum install dublin-traceroute` (replace with `dnf` where
relevant).

### From source

Independently of the OS, to build dublin-traceroute you need:
  * cmake
  * gcc >= 4.9 or clang >= 3.8

#### On Linux

* Install [libtins](https://github.com/mfontanini/libtins) 3.4+ from source
* Install [jsoncpp](https://github.com/open-source-parsers/jsoncpp) from source
* Install libpcap-dev
* Check out dublin-traceroute on github

```shell
git clone https://github.com/insomniacslk/dublin-traceroute.git
```

* Build it

```bash
cd dublin-traceroute
mkdir build
cd build
cmake ..
make
```

#### On macOS

You need the latest XCode installed to build this project. Then run:
```bash
brew install https://raw.githubusercontent.com/insomniacslk/dublin-traceroute/master/homebrew/dublin-traceroute.rb
```

This will be as simple as `brew install dublin-traceroute` after https://github.com/Homebrew/homebrew/pull/50000 will be merged.

Please [file an issue](https://github.com/insomniacslk/dublin-traceroute/issues/new/choose) with the necessary details if this doesn't work for you.

### On Windows

Windows is not supported at this stage. If you are willing to port
`dublin-traceroute` on Windows, please do!

#### Installing

* Install it in the system paths (by default under
/usr/local/{bin,lib,include}). This will also install the provided __libtins__
shared library and headers.

```bash
make install # as root
```

Note that if `setcap` is found when installing, it is used to set the
`CAP_NET_RAW` capability on the `dublin-traceroute` binary.
This allows any regular user to run `dublin-traceroute` without root privileges
but to be still able to use raw sockets, necessary to forge the traceroute packets.
If ```setcap``` is not found, the set-uid bit is set. If you don't want any of these,
you have to run it as root.

### Other hints

It will use your default compiler. Alternatively, if you prefer, you can force a
different compiler. For GCC:

```bash
CXX=g++ make
```

or for clang:

```bash
CXX=clang++ make
```

## Running

`dublin-traceroute` requires raw sockets. This means that you should need the `CAP_NET_RAW` capability set (see `setcap(8)`). Alternatively you can run it as root, but this is not recommended, and `dublin-traceroute` will print a warning.

The usage is very simple, and explained in the help message:

```bash
$ ./dublin-traceroute --help
Dublin Traceroute v0.3.3
Written by Andrea Barberio - https://insomniac.slackware.it

Usage:
  dublin-traceroute <target> [--sport=SRC_PORT]
                             [--dport=dest_base_port]
                             [--npaths=num_paths]
                             [--min-ttl=min_ttl]
                             [--max-ttl=max_ttl]
                             [--delay=delay_in_ms]
                             [--broken-nat]
                             [--help]
                             [--version]

Options:
  -h --help                     this help
  -v --version                  print the version of Dublin Traceroute
  -s SRC_PORT --sport=SRC_PORT  the source port to send packets from
  -d DST_PORT --dport=DST_PORT  the base destination port to send packets to
  -n NPATHS --npaths=NPATHS     the number of paths to probe
  -t MIN_TTL --min-ttl=MIN_TTL  the minimum TTL to probe
  -T MAX_TTL --max-ttl=MAX_TTL  the maximum TTL to probe. Must be greater or equal than the minimum TTL
  -D DELAY --delay=DELAY        the inter-packet delay
  -b --broken-nat               the network has a broken NAT configuration (e.g. no payload fixup). Try this if you see fewer hops than expected

See documentation at https://dublin-traceroute.net
Please report bugs at https://github.com/insomniacslk/dublin-traceroute
Additional features in the Python module at https://github.com/insomniacslk/python-dublin-traceroute
```

## Running via Docker

You can see dublin-traceroute at work using the docker image [`insomniacslk/dublin-traceroute`](https://cloud.docker.com/u/insomniacslk/repository/docker/insomniacslk/dublin-traceroute).

Just run:

```
docker run --rm -v "$PWD/output:/output" insomniacslk/dublin-traceroute
```

This will run `dublin-traceroute 8.8.8.8` and produce output files in the `output` directory.

## What is missing?

At the moment, a lot of things, including:

* ~~let the user choose the source port~~
* ~~improve the the command-line tool by adding more arguments~~ done in [commit 8a3ae75](https://github.com/insomniacslk/dublin-traceroute/commit/8a3ae7513645afdad5eabd8d6f368383dff98c8b)
* introduce more tracerouting strategies: at the moment it sends all the packets at once
* send more than one packet per hop (traceroute sends 3 packets per hop)
* ~~support MPLS~~ done in https://github.com/insomniacslk/dublin-traceroute/issues/6
* IPv6 probes in the C++ library (already implemented in the Go codebase)
* support for TCP, ICMP, and DNS probes
* add Path MTU Discovery to detect latencies introduced by fragmentation
* improve the documentation
* ~~improve the build system (there is just a static Makefile now)~~ done in [commit ffa9d3c](https://github.com/insomniacslk/dublin-traceroute/commit/ffa9d3c306fb772e2c95963a94cdc386b0126206), using CMake

See [TODO.md](TODO.md) for more details.

## FAQ

#### Why the name Dublin Traceroute?

[Paris-traceroute](http://paris-traceroute.net) was named after the french capital
since the research and the development happened there. In my case, it happened in
the city where I live and work, **Dublin**, hence the name.

#### You say this is your first C++ project. Is this an excuse to say that the code sucks?

Yes.

#### How do I ask a question or contribute?

Go to the [Dublin Traceroute mailing list](https://groups.google.com/forum/#!forum/dublin-traceroute) or to IRC, #dublin-traceroute @ FreeNode, and just ask :)

Otherwise you can [open an issue](https://github.com/insomniacslk/dublin-traceroute/issues) or [make a pull request](https://github.com/insomniacslk/dublin-traceroute/pulls) on the GitHub page of dublin-traceroute, or contact me directly (see below).

#### What is the license of Dublin Traceroute?

The [2-clause BSD](http://opensource.org/licenses/BSD-2-Clause)

#### Who are you?

My name is Andrea Barberio, you can find more about me at
https://insomniac.slackware.it


text:
namespace blink {

using testing::ElementsAre;

static Vector<wtf_size_t> ChunkIndices(const PendingLayer& layer) {
  Vector<wtf_size_t> indices;
  for (auto it = layer.Chunks().begin(); it != layer.Chunks().end(); ++it)
    indices.push_back(it.IndexInPaintArtifact());
  return indices;
}

TEST(PendingLayerTest, MightOverlap) {
  TestPaintArtifact artifact;
  artifact.Chunk().Bounds(gfx::Rect(0, 0, 100, 100));
  artifact.Chunk().Bounds(gfx::Rect(0, 0, 100, 100));
  auto t2 = CreateTransform(t0(), TransformationMatrix().Translate(99, 0),
                            FloatPoint3D(100, 100, 0));
  artifact.Chunk(*t2, c0(), e0()).Bounds(gfx::Rect(0, 0, 100, 100));
  auto t3 = CreateTransform(t0(), TransformationMatrix().Translate(100, 0),
                            FloatPoint3D(100, 100, 0));
  artifact.Chunk(*t3, c0(), e0()).Bounds(gfx::Rect(0, 0, 100, 100));
  auto t4 =
      CreateAnimatingTransform(t0(), TransformationMatrix().Translate(100, 0),
                               FloatPoint3D(100, 100, 0));
  artifact.Chunk(*t4, c0(), e0()).Bounds(gfx::Rect(0, 0, 100, 100));
  PaintChunkSubset chunks(artifact.Build());

  PendingLayer pending_layer(chunks, chunks.begin());
  EXPECT_TRUE(
      pending_layer.MightOverlap(PendingLayer(chunks, chunks.begin() + 1)));
  EXPECT_TRUE(
      pending_layer.MightOverlap(PendingLayer(chunks, chunks.begin() + 2)));
  EXPECT_FALSE(
      pending_layer.MightOverlap(PendingLayer(chunks, chunks.begin() + 3)));
  EXPECT_TRUE(
      pending_layer.MightOverlap(PendingLayer(chunks, chunks.begin() + 4)));
}

TEST(PendingLayerTest, MightOverlapCommonClipAncestor) {
  auto common_clip = CreateClip(c0(), t0(), FloatRoundedRect(0, 0, 100, 100));
  auto c1 = CreateClip(*common_clip, t0(), FloatRoundedRect(0, 100, 100, 100));
  auto c2 = CreateClip(*common_clip, t0(), FloatRoundedRect(50, 100, 100, 100));
  auto c3 =
      CreateClip(*common_clip, t0(), FloatRoundedRect(100, 100, 100, 100));

  TestPaintArtifact artifact;
  artifact.Chunk(t0(), *c1, e0())
      .Bounds(gfx::Rect(0, 100, 200, 100))
      .Chunk(t0(), *c2, e0())
      .Bounds(gfx::Rect(0, 100, 200, 100))
      .Chunk(t0(), *c3, e0())
      .Bounds(gfx::Rect(0, 100, 200, 100));
  PaintChunkSubset chunks(artifact.Build());

  PendingLayer pending_layer1(chunks, chunks.begin());
  PendingLayer pending_layer2(chunks, chunks.begin() + 1);
  PendingLayer pending_layer3(chunks, chunks.begin() + 2);
  EXPECT_FALSE(pending_layer1.MightOverlap(pending_layer3));
  EXPECT_TRUE(pending_layer1.MightOverlap(pending_layer2));
  EXPECT_TRUE(pending_layer2.MightOverlap(pending_layer3));
}

TEST(PendingLayerTest, Merge) {
  TestPaintArtifact artifact;
  artifact.Chunk()
      .Bounds(gfx::Rect(0, 0, 30, 40))
      .RectKnownToBeOpaque(gfx::Rect(0, 0, 30, 40));
  artifact.Chunk()
      .Bounds(gfx::Rect(10, 20, 30, 40))
      .RectKnownToBeOpaque(gfx::Rect(10, 20, 30, 40));
  artifact.Chunk()
      .Bounds(gfx::Rect(-5, -25, 20, 20))
      .RectKnownToBeOpaque(gfx::Rect(-5, -25, 20, 20));
  PaintChunkSubset chunks(artifact.Build());

  PendingLayer pending_layer(chunks, chunks.begin());

  EXPECT_EQ(gfx::RectF(0, 0, 30, 40), pending_layer.BoundsForTesting());
  EXPECT_THAT(ChunkIndices(pending_layer), ElementsAre(0));
  EXPECT_EQ(pending_layer.BoundsForTesting(),
            pending_layer.RectKnownToBeOpaque());

  ASSERT_TRUE(pending_layer.Merge(PendingLayer(chunks, chunks.begin() + 1)));

  // Bounds not equal to one PaintChunk.
  EXPECT_EQ(gfx::RectF(0, 0, 40, 60), pending_layer.BoundsForTesting());
  EXPECT_THAT(ChunkIndices(pending_layer), ElementsAre(0, 1));
  EXPECT_EQ(gfx::RectF(0, 0, 30, 40), pending_layer.RectKnownToBeOpaque());

  ASSERT_TRUE(pending_layer.Merge(PendingLayer(chunks, chunks.begin() + 2)));

  EXPECT_EQ(gfx::RectF(-5, -25, 45, 85), pending_layer.BoundsForTesting());
  EXPECT_THAT(ChunkIndices(pending_layer), ElementsAre(0, 1, 2));
  EXPECT_EQ(gfx::RectF(0, 0, 30, 40), pending_layer.RectKnownToBeOpaque());
}

TEST(PendingLayerTest, MergeWithGuestTransform) {
  TestPaintArtifact artifact;
  artifact.Chunk().Bounds(gfx::Rect(0, 0, 30, 40));
  auto transform = Create2DTranslation(t0(), 20, 25);
  artifact.Chunk(*transform, c0(), e0()).Bounds(gfx::Rect(0, 0, 50, 60));
  PaintChunkSubset chunks(artifact.Build());

  PendingLayer pending_layer(chunks, chunks.begin());
  ASSERT_TRUE(pending_layer.Merge(PendingLayer(chunks, chunks.begin() + 1)));
  EXPECT_EQ(gfx::RectF(0, 0, 70, 85), pending_layer.BoundsForTesting());
  EXPECT_EQ(PropertyTreeState::Root(), pending_layer.GetPropertyTreeState());
}

TEST(PendingLayerTest, MergeWithHomeTransform) {
  TestPaintArtifact artifact;
  auto transform = Create2DTranslation(t0(), 20, 25);
  artifact.Chunk(*transform, c0(), e0()).Bounds(gfx::Rect(0, 0, 30, 40));
  artifact.Chunk().Bounds(gfx::Rect(0, 0, 50, 60));
  PaintChunkSubset chunks(artifact.Build());

  PendingLayer pending_layer(chunks, chunks.begin());
  ASSERT_TRUE(pending_layer.Merge(PendingLayer(chunks, chunks.begin() + 1)));
  EXPECT_EQ(gfx::RectF(0, 0, 50, 65), pending_layer.BoundsForTesting());
  EXPECT_EQ(PropertyTreeState::Root(), pending_layer.GetPropertyTreeState());
}

TEST(PendingLayerTest, MergeWithBothTransforms) {
  TestPaintArtifact artifact;
  auto t1 = Create2DTranslation(t0(), 20, 25);
  artifact.Chunk(*t1, c0(), e0()).Bounds(gfx::Rect(0, 0, 30, 40));
  auto t2 = Create2DTranslation(t0(), -20, -25);
  artifact.Chunk(*t2, c0(), e0()).Bounds(gfx::Rect(0, 0, 50, 60));
  PaintChunkSubset chunks(artifact.Build());

  PendingLayer pending_layer(chunks, chunks.begin());
  ASSERT_TRUE(pending_layer.Merge(PendingLayer(chunks, chunks.begin() + 1)));
  EXPECT_EQ(gfx::RectF(-20, -25, 70, 90), pending_layer.BoundsForTesting());
  EXPECT_EQ(PropertyTreeState::Root(), pending_layer.GetPropertyTreeState());
}

TEST(PendingLayerTest, MergeSparseTinyLayers) {
  TestPaintArtifact artifact;
  artifact.Chunk()
      .Bounds(gfx::Rect(0, 0, 3, 4))
      .RectKnownToBeOpaque(gfx::Rect(0, 0, 3, 4));
  artifact.Chunk()
      .Bounds(gfx::Rect(20, 20, 3, 4))
      .RectKnownToBeOpaque(gfx::Rect(20, 20, 3, 4));
  PaintChunkSubset chunks(artifact.Build());

  PendingLayer pending_layer(chunks, chunks.begin());
  ASSERT_TRUE(pending_layer.Merge(PendingLayer(chunks, chunks.begin() + 1)));
  EXPECT_EQ(gfx::RectF(0, 0, 23, 24), pending_layer.BoundsForTesting());
  EXPECT_THAT(ChunkIndices(pending_layer), ElementsAre(0, 1));
}

TEST(PendingLayerTest, DontMergeSparse) {
  TestPaintArtifact artifact;
  artifact.Chunk()
      .Bounds(gfx::Rect(0, 0, 30, 40))
      .RectKnownToBeOpaque(gfx::Rect(0, 0, 30, 40));
  artifact.Chunk()
      .Bounds(gfx::Rect(200, 200, 30, 40))
      .RectKnownToBeOpaque(gfx::Rect(200, 200, 30, 40));
  PaintChunkSubset chunks(artifact.Build());

  PendingLayer pending_layer(chunks, chunks.begin());
  ASSERT_FALSE(pending_layer.Merge(PendingLayer(chunks, chunks.begin() + 1)));
  EXPECT_EQ(gfx::RectF(0, 0, 30, 40), pending_layer.BoundsForTesting());
  EXPECT_EQ(chunks.begin()->properties, pending_layer.GetPropertyTreeState());
  EXPECT_THAT(ChunkIndices(pending_layer), ElementsAre(0));
}

TEST(PendingLayerTest, PendingLayerDontMergeSparseWithTransforms) {
  TestPaintArtifact artifact;
  auto t1 = Create2DTranslation(t0(), 20, 25);
  artifact.Chunk(*t1, c0(), e0()).Bounds(gfx::Rect(0, 0, 30, 40));
  auto t2 = Create2DTranslation(t0(), 1000, 1000);
  artifact.Chunk(*t2, c0(), e0()).Bounds(gfx::Rect(0, 0, 50, 60));
  PaintChunkSubset chunks(artifact.Build());

  PendingLayer pending_layer(chunks, chunks.begin());
  ASSERT_FALSE(pending_layer.Merge(PendingLayer(chunks, chunks.begin() + 1)));
  EXPECT_EQ(gfx::RectF(0, 0, 30, 40), pending_layer.BoundsForTesting());
  EXPECT_EQ(chunks.begin()->properties, pending_layer.GetPropertyTreeState());
  EXPECT_THAT(ChunkIndices(pending_layer), ElementsAre(0));
}

TEST(PendingLayerTest, DontMergeSparseInCompositedEffect) {
  TestPaintArtifact artifact;
  auto t1 = Create2DTranslation(t0(), 20, 25);
  auto e1 =
      CreateOpacityEffect(e0(), 1.0f, CompositingReason::kWillChangeOpacity);
  artifact.Chunk(*t1, c0(), *e1).Bounds(gfx::Rect(0, 0, 30, 40));
  auto t2 = Create2DTranslation(t0(), 1000, 1000);
  artifact.Chunk(*t2, c0(), *e1).Bounds(gfx::Rect(0, 0, 50, 60));
  PaintChunkSubset chunks(artifact.Build());

  PendingLayer pending_layer(chunks, chunks.begin());
  ASSERT_FALSE(pending_layer.Merge(PendingLayer(chunks, chunks.begin() + 1)));
  EXPECT_EQ(gfx::RectF(0, 0, 30, 40), pending_layer.BoundsForTesting());
  EXPECT_EQ(chunks.begin()->properties, pending_layer.GetPropertyTreeState());
  EXPECT_THAT(ChunkIndices(pending_layer), ElementsAre(0));
}

TEST(PendingLayerTest, MergeSparseInNonCompositedEffect) {
  TestPaintArtifact artifact;
  auto t1 = Create2DTranslation(t0(), 20, 25);
  auto t2 = Create2DTranslation(t0(), 1000, 1000);
  auto e1 = CreateOpacityEffect(e0(), 1.0f, CompositingReason::kNone);
  artifact.Chunk(*t1, c0(), *e1).Bounds(gfx::Rect(0, 0, 30, 40));
  artifact.Chunk(*t2, c0(), *e1).Bounds(gfx::Rect(0, 0, 50, 60));
  PaintChunkSubset chunks(artifact.Build());

  PendingLayer pending_layer(chunks, chunks.begin());
  EXPECT_FALSE(pending_layer.Merge(PendingLayer(chunks, chunks.begin() + 1)));
}

TEST(PendingLayerTest, KnownOpaque) {
  TestPaintArtifact artifact;
  artifact.Chunk().Bounds(gfx::Rect(0, 0, 30, 40));
  artifact.Chunk()
      .Bounds(gfx::Rect(0, 0, 25, 35))
      .RectKnownToBeOpaque(gfx::Rect(0, 0, 25, 35));
  artifact.Chunk()
      .Bounds(gfx::Rect(0, 0, 50, 60))
      .RectKnownToBeOpaque(gfx::Rect(0, 0, 50, 60));
  PaintChunkSubset chunks(artifact.Build());

  PendingLayer pending_layer(chunks, chunks.begin());
  EXPECT_TRUE(pending_layer.RectKnownToBeOpaque().IsEmpty());

  ASSERT_TRUE(pending_layer.Merge(PendingLayer(chunks, chunks.begin() + 1)));
  // Chunk 2 doesn't cover the entire layer, so not opaque.
  EXPECT_EQ(gfx::RectF(0, 0, 25, 35), pending_layer.RectKnownToBeOpaque());
  EXPECT_NE(pending_layer.BoundsForTesting(),
            pending_layer.RectKnownToBeOpaque());

  ASSERT_TRUE(pending_layer.Merge(PendingLayer(chunks, chunks.begin() + 2)));
  // Chunk 3 covers the entire layer, so now it's opaque.
  EXPECT_EQ(gfx::RectF(0, 0, 50, 60), pending_layer.BoundsForTesting());
  EXPECT_EQ(pending_layer.BoundsForTesting(),
            pending_layer.RectKnownToBeOpaque());
}

TEST(PendingLayerTest, CanNotMergeAcrossPaintArtifacts) {
  TestPaintArtifact test_artifact_a;
  test_artifact_a.Chunk().RectDrawing(gfx::Rect(0, 0, 100, 100), Color::kWhite);
  PaintChunkSubset chunks_a(test_artifact_a.Build());
  PendingLayer layer_a(chunks_a, chunks_a.begin());

  TestPaintArtifact test_artifact_b;
  test_artifact_b.Chunk().RectDrawing(gfx::Rect(0, 0, 100, 100), Color::kGray);
  PaintChunkSubset chunks_b(test_artifact_b.Build());
  PendingLayer layer_b(chunks_b, chunks_b.begin());

  EXPECT_FALSE(layer_a.Merge(layer_b));
}

class PendingLayerTextOpaquenessTest
    : public testing::Test,
      public testing::WithParamInterface<bool> {
 protected:
  bool PrefersLCDText() const { return GetParam(); }
};

INSTANTIATE_TEST_SUITE_P(All,
                         PendingLayerTextOpaquenessTest,
                         ::testing::Values(false, true));

TEST_P(PendingLayerTextOpaquenessTest, OpaqueTextAndOpaqueText) {
  TestPaintArtifact artifact;
  artifact.Chunk(t0(), c0(), e0())
      .RectDrawing(gfx::Rect(100, 100, 250, 250), Color::kBlack)
      .HasText()
      .TextKnownToBeOnOpaqueBackground()
      .Chunk(t0(), c0(), e0())
      .RectDrawing(gfx::Rect(200, 200, 300, 300), Color::kBlack)
      .HasText()
      .TextKnownToBeOnOpaqueBackground();
  PaintChunkSubset chunks(artifact.Build());
  PendingLayer layer_a(chunks, chunks.begin());
  PendingLayer layer_b(chunks, chunks.begin() + 1);
  ASSERT_TRUE(layer_a.Merge(layer_b, PrefersLCDText()));
  EXPECT_EQ(gfx::RectF(100, 100, 400, 400), layer_a.BoundsForTesting());
  EXPECT_TRUE(layer_a.TextKnownToBeOnOpaqueBackground());
}

TEST_P(PendingLayerTextOpaquenessTest, NonOpaqueTextAndOpaqueText) {
  TestPaintArtifact artifact;
  artifact.Chunk(t0(), c0(), e0())
      .RectDrawing(gfx::Rect(100, 100, 250, 250), Color::kBlack)
      .HasText()
      .Chunk(t0(), c0(), e0())
      .RectDrawing(gfx::Rect(200, 200, 300, 300), Color::kBlack)
      .HasText()
      .TextKnownToBeOnOpaqueBackground();
  PaintChunkSubset chunks(artifact.Build());
  PendingLayer layer_a(chunks, chunks.begin());
  PendingLayer layer_b(chunks, chunks.begin() + 1);
  bool merged = layer_a.Merge(layer_b, PrefersLCDText());
  if (PrefersLCDText()) {
    // Not merged because merging would lose TextKnownToBeOnOpaqueBackground().
    ASSERT_FALSE(merged);
  } else {
    ASSERT_TRUE(merged);
    EXPECT_EQ(gfx::RectF(100, 100, 400, 400), layer_a.BoundsForTesting());
    EXPECT_FALSE(layer_a.TextKnownToBeOnOpaqueBackground());
  }
}

TEST_P(PendingLayerTextOpaquenessTest, OpaqueTextAndNonOpaqueText) {
  TestPaintArtifact artifact;
  artifact.Chunk(t0(), c0(), e0())
      .RectDrawing(gfx::Rect(100, 100, 250, 250), Color::kBlack)
      .HasText()
      .TextKnownToBeOnOpaqueBackground()
      .Chunk(t0(), c0(), e0())
      .RectDrawing(gfx::Rect(200, 200, 300, 300), Color::kBlack)
      .HasText();
  PaintChunkSubset chunks(artifact.Build());
  PendingLayer layer_a(chunks, chunks.begin());
  PendingLayer layer_b(chunks, chunks.begin() + 1);
  bool merged = layer_a.Merge(layer_b, PrefersLCDText());
  if (PrefersLCDText()) {
    // Not merged because merging would lose TextKnownToBeOnOpaqueBackground().
    ASSERT_FALSE(merged);
  } else {
    ASSERT_TRUE(merged);
    EXPECT_EQ(gfx::RectF(100, 100, 400, 400), layer_a.BoundsForTesting());
    EXPECT_FALSE(layer_a.TextKnownToBeOnOpaqueBackground());
  }
}

TEST_P(PendingLayerTextOpaquenessTest, NonOpaqueTextAndOpaqueTextCovered) {
  TestPaintArtifact artifact;
  artifact.Chunk(t0(), c0(), e0())
      .RectDrawing(gfx::Rect(200, 200, 100, 100), Color::kBlack)
      .HasText()
      .Chunk(t0(), c0(), e0())
      .RectDrawing(gfx::Rect(100, 100, 300, 300), Color::kBlack)
      .RectKnownToBeOpaque(gfx::Rect(200, 200, 100, 100))
      .HasText()
      .TextKnownToBeOnOpaqueBackground();
  PaintChunkSubset chunks(artifact.Build());
  PendingLayer layer_a(chunks, chunks.begin());
  PendingLayer layer_b(chunks, chunks.begin() + 1);
  ASSERT_TRUE(layer_a.Merge(layer_b, PrefersLCDText()));
  EXPECT_EQ(gfx::RectF(100, 100, 300, 300), layer_a.BoundsForTesting());
  EXPECT_EQ(gfx::RectF(200, 200, 100, 100), layer_a.RectKnownToBeOpaque());
  EXPECT_TRUE(layer_a.TextKnownToBeOnOpaqueBackground());
}

TEST_P(PendingLayerTextOpaquenessTest, OpaqueTextAndNonOpaqueTextCovered) {
  TestPaintArtifact artifact;
  artifact.Chunk(t0(), c0(), e0())
      .RectDrawing(gfx::Rect(100, 100, 250, 250), Color::kBlack)
      .RectKnownToBeOpaque(gfx::Rect(100, 100, 210, 210))
      .HasText()
      .TextKnownToBeOnOpaqueBackground()
      .Chunk(t0(), c0(), e0())
      .RectDrawing(gfx::Rect(200, 200, 100, 100), Color::kBlack)
      .HasText();
  PaintChunkSubset chunks(artifact.Build());
  PendingLayer layer_a(chunks, chunks.begin());
  PendingLayer layer_b(chunks, chunks.begin() + 1);
  ASSERT_TRUE(layer_a.Merge(layer_b, PrefersLCDText()));
  EXPECT_EQ(gfx::RectF(100, 100, 250, 250), layer_a.BoundsForTesting());
  EXPECT_EQ(gfx::RectF(100, 100, 210, 210), layer_a.RectKnownToBeOpaque());
  EXPECT_TRUE(layer_a.TextKnownToBeOnOpaqueBackground());
}

TEST_P(PendingLayerTextOpaquenessTest, NoTextAndOpaqueText) {
  TestPaintArtifact artifact;
  artifact.Chunk(t0(), c0(), e0())
      .RectDrawing(gfx::Rect(100, 100, 250, 250), Color::kBlack)
      .RectKnownToBeOpaque(gfx::Rect(100, 100, 210, 210))
      .Chunk(t0(), c0(), e0())
      .RectDrawing(gfx::Rect(200, 200, 300, 300), Color::kBlack)
      .HasText()
      .TextKnownToBeOnOpaqueBackground();
  PaintChunkSubset chunks(artifact.Build());
  PendingLayer layer_a(chunks, chunks.begin());
  PendingLayer layer_b(chunks, chunks.begin() + 1);
  ASSERT_TRUE(layer_a.Merge(layer_b, PrefersLCDText()));
  EXPECT_EQ(gfx::RectF(100, 100, 400, 400), layer_a.BoundsForTesting());
  EXPECT_EQ(gfx::RectF(100, 100, 210, 210), layer_a.RectKnownToBeOpaque());
  EXPECT_TRUE(layer_a.TextKnownToBeOnOpaqueBackground());
}

TEST_P(PendingLayerTextOpaquenessTest, OpaqueTextAndNoText) {
  TestPaintArtifact artifact;
  artifact.Chunk(t0(), c0(), e0())
      .RectDrawing(gfx::Rect(100, 100, 250, 250), Color::kBlack)
      .RectKnownToBeOpaque(gfx::Rect(100, 100, 210, 210))
      .HasText()
      .TextKnownToBeOnOpaqueBackground()
      .Chunk(t0(), c0(), e0())
      .RectDrawing(gfx::Rect(200, 200, 300, 300), Color::kBlack);
  PaintChunkSubset chunks(artifact.Build());
  PendingLayer layer_a(chunks, chunks.begin());
  PendingLayer layer_b(chunks, chunks.begin() + 1);
  ASSERT_TRUE(layer_a.Merge(layer_b, PrefersLCDText()));
  EXPECT_EQ(gfx::RectF(100, 100, 400, 400), layer_a.BoundsForTesting());
  EXPECT_EQ(gfx::RectF(100, 100, 210, 210), layer_a.RectKnownToBeOpaque());
  EXPECT_TRUE(layer_a.TextKnownToBeOnOpaqueBackground());
}

TEST_P(PendingLayerTextOpaquenessTest, NonOpaqueNoTextAndNonOpaqueText) {
  TestPaintArtifact artifact;
  artifact.Chunk(t0(), c0(), e0())
      .RectDrawing(gfx::Rect(100, 100, 250, 250), Color::kBlack)
      .Chunk(t0(), c0(), e0())
      .RectDrawing(gfx::Rect(200, 200, 300, 300), Color::kBlack)
      .HasText();
  PaintChunkSubset chunks(artifact.Build());
  PendingLayer layer_a(chunks, chunks.begin());
  PendingLayer layer_b(chunks, chunks.begin() + 1);
  ASSERT_TRUE(layer_a.Merge(layer_b, PrefersLCDText()));
  EXPECT_EQ(gfx::RectF(100, 100, 400, 400), layer_a.BoundsForTesting());
  EXPECT_FALSE(layer_a.TextKnownToBeOnOpaqueBackground());
}

TEST_P(PendingLayerTextOpaquenessTest, NonOpaqueTextAndNonOpaqueNoText) {
  TestPaintArtifact artifact;
  artifact.Chunk(t0(), c0(), e0())
      .RectDrawing(gfx::Rect(100, 100, 250, 250), Color::kBlack)
      .HasText()
      .Chunk(t0(), c0(), e0())
      .RectDrawing(gfx::Rect(200, 200, 300, 300), Color::kBlack);
  PaintChunkSubset chunks(artifact.Build());
  PendingLayer layer_a(chunks, chunks.begin());
  PendingLayer layer_b(chunks, chunks.begin() + 1);
  ASSERT_TRUE(layer_a.Merge(layer_b, PrefersLCDText()));
  EXPECT_EQ(gfx::RectF(100, 100, 400, 400), layer_a.BoundsForTesting());
  EXPECT_FALSE(layer_a.TextKnownToBeOnOpaqueBackground());
}

TEST_P(PendingLayerTextOpaquenessTest, OpaqueNoTextAndNonOpaqueText) {
  TestPaintArtifact artifact;
  artifact.Chunk(t0(), c0(), e0())
      .RectDrawing(gfx::Rect(100, 100, 250, 250), Color::kBlack)
      .RectKnownToBeOpaque(gfx::Rect(100, 100, 210, 210))
      .Chunk(t0(), c0(), e0())
      .RectDrawing(gfx::Rect(200, 200, 100, 100), Color::kBlack)
      .HasText();
  PaintChunkSubset chunks(artifact.Build());
  PendingLayer layer_a(chunks, chunks.begin());
  PendingLayer layer_b(chunks, chunks.begin() + 1);
  ASSERT_TRUE(layer_a.Merge(layer_b, PrefersLCDText()));
  EXPECT_EQ(gfx::RectF(100, 100, 250, 250), layer_a.BoundsForTesting());
  EXPECT_EQ(gfx::RectF(100, 100, 210, 210), layer_a.RectKnownToBeOpaque());
  EXPECT_TRUE(layer_a.TextKnownToBeOnOpaqueBackground());
}

TEST_P(PendingLayerTextOpaquenessTest, NonOpaqueTextAndOpaqueNoText) {
  TestPaintArtifact artifact;
  artifact.Chunk(t0(), c0(), e0())
      .RectDrawing(gfx::Rect(200, 200, 100, 100), Color::kBlack)
      .HasText()
      .Chunk(t0(), c0(), e0())
      .RectDrawing(gfx::Rect(100, 100, 250, 250), Color::kBlack)
      .RectKnownToBeOpaque(gfx::Rect(100, 100, 210, 210));
  PaintChunkSubset chunks(artifact.Build());
  PendingLayer layer_a(chunks, chunks.begin());
  PendingLayer layer_b(chunks, chunks.begin() + 1);
  ASSERT_TRUE(layer_a.Merge(layer_b, PrefersLCDText()));
  EXPECT_EQ(gfx::RectF(100, 100, 250, 250), layer_a.BoundsForTesting());
  EXPECT_EQ(gfx::RectF(100, 100, 210, 210), layer_a.RectKnownToBeOpaque());
  EXPECT_TRUE(layer_a.TextKnownToBeOnOpaqueBackground());
}

TEST_P(PendingLayerTextOpaquenessTest, UnitedClippedToOpaque) {
  // Though the second chunk has text not on opaque background, and it's not
  // fully covered by the opaque rect of the first chunk, the non-opaque area
  // is not visible in the final layer, so we still allow the merge.
  auto clip1 = CreateClip(c0(), t0(), FloatRoundedRect(175, 175, 100, 100));
  TestPaintArtifact artifact;
  artifact.Chunk(t0(), *clip1, e0())
      .RectDrawing(gfx::Rect(100, 100, 250, 250), Color::kBlack)
      .RectKnownToBeOpaque(gfx::Rect(100, 100, 210, 210))
      .HasText()
      .TextKnownToBeOnOpaqueBackground()
      .Chunk(t0(), *clip1, e0())
      .RectDrawing(gfx::Rect(200, 200, 300, 300), Color::kBlack)
      .HasText();
  PaintChunkSubset chunks(artifact.Build());
  PendingLayer layer_a(chunks, chunks.begin());
  PendingLayer layer_b(chunks, chunks.begin() + 1);
  ASSERT_TRUE(layer_a.Merge(layer_b, PrefersLCDText()));
  EXPECT_EQ(gfx::RectF(175, 175, 100, 100), layer_a.BoundsForTesting());
  EXPECT_EQ(gfx::RectF(100, 100, 210, 210), layer_a.RectKnownToBeOpaque());
  EXPECT_TRUE(layer_a.TextKnownToBeOnOpaqueBackground());
}

}  // namespace blink


text:
(() => {
  "use strict";
  const gulp = require("gulp");
  const argv = require("yargs").argv;
  const folder = argv.compress ? "dist" : "www";
  const gulpLoadPlugins = require("gulp-load-plugins");
  const plugins = gulpLoadPlugins();

  plugins.runSequence = require("run-sequence");
  plugins.bowerFiles = require("main-bower-files");
  plugins.rimraf = require("rimraf");
  plugins.open = require("open");
  plugins.karma = require("karma").Server;
  plugins.es = require("event-stream");

  const options = {
    argv,
    folder,
    pattern : ["gulp/**/*.js"],
    bowerPath : "bower_components",
    env : argv.compress ? "production" : "testing",
    devPaths : {
      base : "src/",
      baseSpecs : "specs/",
      allFiles : "src/**/*",
      styles : "src/**/*.scss",
      scripts : "src/**/*.js",
      images : "src/images/**/*",
      specs : "specs/**/*.js",
      templates : [ "src/**/*.html", "!src/index.html"],
      index : "src/index.html"
    },
    distPaths : {
      scripts : argv.compress ? folder + "/scripts" : folder,
      styles : folder + "/styles",
      fonts : folder + "/fonts",
      images : folder + "/images",
      templates : folder + "/templates"
    },
    karmaConfig : __dirname + "/karma.conf.js",
    jshintConfig : ".jshintrc"
  };

  require("load-gulp-tasks")(gulp, options, plugins);
})();


text:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class BoardHighlight : MonoBehaviour
{
	public static BoardHighlight Instance{ set; get;}
	public GameObject HighlightPrefab;
	private List<GameObject> highlights;
	private void Start(){
		Instance = this;
		highlights = new List<GameObject> ();
	}

	private GameObject getHighLightObject (){
		GameObject go = highlights.Find (g => !g.activeSelf);
		if (go == null) {
			go = Instantiate (HighlightPrefab);
			highlights.Add (go);
		}
		return go;
	}

	public void highlightAollowedMoves(bool [,] moves){
		for (int i = 0; i < 8; i++) {
			for (int j = 0; j < 8; j++) {
				if (moves [i, j]) {
					GameObject go = getHighLightObject ();
					go.SetActive (true);
					Vector3 v3 = BoardManager.translateToWorldCoord (new Vector2 ((float)i, (float)j));
					v3.y = 0.1f;
					go.transform.position = v3;
				}
			}
		}
	}

	public void HideHighlights(){
		foreach (GameObject go in  highlights) {
			go.SetActive (false);
		}
	}
}


text:
<?php

declare(strict_types=1);

namespace Sylius\Component\Core\Test\Services;

use Sylius\Component\Channel\Factory\ChannelFactoryInterface;
use Sylius\Component\Core\Model\ChannelInterface;
use Sylius\Component\Currency\Model\CurrencyInterface;
use Sylius\Component\Locale\Model\LocaleInterface;
use Sylius\Component\Resource\Factory\FactoryInterface;
use Sylius\Component\Resource\Repository\RepositoryInterface;

/**
 * @author Mateusz Zalewski <mateusz.zalewski@lakion.com>
 */
final class DefaultChannelFactory implements DefaultChannelFactoryInterface
{
    public const DEFAULT_CHANNEL_NAME = 'Default';
    public const DEFAULT_CHANNEL_CODE = 'DEFAULT';
    public const DEFAULT_CHANNEL_CURRENCY = 'USD';

    /**
     * @var ChannelFactoryInterface
     */
    private $channelFactory;

    /**
     * @var FactoryInterface
     */
    private $currencyFactory;

    /**
     * @var FactoryInterface
     */
    private $localeFactory;

    /**
     * @var RepositoryInterface
     */
    private $channelRepository;

    /**
     * @var RepositoryInterface
     */
    private $currencyRepository;

    /**
     * @var RepositoryInterface
     */
    private $localeRepository;

    /**
     * @var string
     */
    private $defaultLocaleCode;

    /**
     * @param ChannelFactoryInterface $channelFactory
     * @param FactoryInterface $currencyFactory
     * @param FactoryInterface $localeFactory
     * @param RepositoryInterface $channelRepository
     * @param RepositoryInterface $currencyRepository
     * @param RepositoryInterface $localeRepository
     * @param string $defaultLocaleCode
     */
    public function __construct(
        ChannelFactoryInterface $channelFactory,
        FactoryInterface $currencyFactory,
        FactoryInterface $localeFactory,
        RepositoryInterface $channelRepository,
        RepositoryInterface $currencyRepository,
        RepositoryInterface $localeRepository,
        string $defaultLocaleCode
    ) {
        $this->channelFactory = $channelFactory;
        $this->currencyFactory = $currencyFactory;
        $this->localeFactory = $localeFactory;
        $this->channelRepository = $channelRepository;
        $this->currencyRepository = $currencyRepository;
        $this->localeRepository = $localeRepository;
        $this->defaultLocaleCode = $defaultLocaleCode;
    }

    /**
     * {@inheritdoc}
     */
    public function create(?string $code = null, ?string $name = null, ?string $currencyCode = null): array
    {
        $currency = $this->provideCurrency($currencyCode);
        $locale = $this->provideLocale();

        /** @var ChannelInterface $channel */
        $channel = $this->channelFactory->createNamed($name ?: self::DEFAULT_CHANNEL_NAME);
        $channel->setCode($code ?: self::DEFAULT_CHANNEL_CODE);
        $channel->setTaxCalculationStrategy('order_items_based');

        $channel->addCurrency($currency);
        $channel->setBaseCurrency($currency);

        $channel->addLocale($locale);
        $channel->setDefaultLocale($locale);

        $this->channelRepository->add($channel);

        return [
            'channel' => $channel,
            'currency' => $currency,
            'locale' => $locale,
        ];
    }

    /**
     * @param string|null $currencyCode
     *
     * @return CurrencyInterface
     */
    private function provideCurrency(?string $currencyCode): CurrencyInterface
    {
        $currencyCode = (null !== $currencyCode) ? $currencyCode : self::DEFAULT_CHANNEL_CURRENCY;

        /** @var CurrencyInterface $currency */
        $currency = $this->currencyRepository->findOneBy(['code' => $currencyCode]);

        if (null === $currency) {
            $currency = $this->currencyFactory->createNew();
            $currency->setCode($currencyCode);

            $this->currencyRepository->add($currency);
        }

        return $currency;
    }

    /**
     * @return LocaleInterface
     */
    private function provideLocale(): LocaleInterface
    {
        /** @var LocaleInterface $locale */
        $locale = $this->localeRepository->findOneBy(['code' => $this->defaultLocaleCode]);

        if (null === $locale) {
            $locale = $this->localeFactory->createNew();
            $locale->setCode($this->defaultLocaleCode);

            $this->localeRepository->add($locale);
        }

        return $locale;
    }
}


text:
package com.hp.hpl.jena.rdf.listeners;

import com.hp.hpl.jena.rdf.model.*;

import java.util.*;

/**
    Class that merely notes that a change has occurred. The only method its user
    should be interested in is hasChanged().

 	@author kers
*/
public class ChangedListener implements ModelChangedListener
    {
    /**
        True iff a change has occurred since the last check
    */
    private boolean changed = false;
    /**
        Record that a change has occurred by setting changed true.
    */
    protected void setChanged() { changed = true; }
    /**
        Answer true iff a change has occurred since the last hasChanged and set changed
        false.
        @return true iff a change has occurred since the last call to hasChanged
    */
    public boolean hasChanged() { try { return changed; } finally { changed = false; } }
    public void addedStatement( Statement s ) { setChanged(); }
    public void addedStatements( Statement [] statements ) { setChanged(); }
    public void addedStatements( List<Statement> statements ) { setChanged(); }
    public void addedStatements( StmtIterator statements ) { setChanged(); }
    public void addedStatements( Model m ) { setChanged(); }
    public void removedStatement( Statement s ) { setChanged(); }
    public void removedStatements( Statement [] statements ) { setChanged(); }
    public void removedStatements( List<Statement> statements ) { setChanged(); }
    public void removedStatements( StmtIterator statements ) { setChanged(); }
    public void removedStatements( Model m ) { setChanged(); }
    public void notifyEvent( Model m, Object event ) {}
    }

/*
    (c) Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Hewlett-Packard Development Company, LP
    All rights reserved.

    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions
    are met:

    1. Redistributions of source code must retain the above copyright
       notice, this list of conditions and the following disclaimer.

    2. Redistributions in binary form must reproduce the above copyright
       notice, this list of conditions and the following disclaimer in the
       documentation and/or other materials provided with the distribution.

    3. The name of the author may not be used to endorse or promote products
       derived from this software without specific prior written permission.

    THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
    OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
    IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
    NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
    THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/


text:
---

copyright:
 years: 2015, 2016

---

# Enabling actionable notifications for iOS
{: #enable-actionable-notifications-ios}

Unlike traditional push notifications, actionable notifications prompt users to make a selection upon receipt of the notification alert without opening the app. Use the following instructions to enable actionable push notifications in your application.

1. Create a user response action.

	Objective-C

	```
	// For Objective-C
	UIMutableUserNotificationAction *acceptAction = [[UIMutableUserNotificationAction alloc] init];
	    acceptAction.identifier = @"ACCEPT_ACTION";
	    acceptAction.title = @"Accept";
	     /* Optional properties
	     acceptAction.destructive = NO;
	  acceptAction.authenticationRequired = NO; */
	  ```

	Swift

	```
	let acceptAction = UIMutableUserNotificationAction()
	acceptAction.identifier = "ACCEPT_ACTION"
	acceptAction.title = "Accept"
	acceptAction.destructive = false
	acceptAction.authenticationRequired = false
	acceptAction.activationMode = UIUserNotificationActivationMode.Foreground*/
	```
	```
	let declineAction = UIMutableUserNotificationAction()
	declineAction.identifier = "DECLINE_ACTION"
	declineAction.title = "Decline"
	declineAction.destructive = true
	declineAction.authenticationRequired = false
	declineAction.activationMode = UIUserNotificationActivationMode.Background
	```

2. Create the notification category and set an action. **UIUserNotificationActionContextDefault** or **UIUserNotificationActionContextMinimal** are valid contexts.

	Objective-C

	```
	// For Objective-C
	UIMutableUserNotificationCategory *callCat = [[UIMutableUserNotificationCategory alloc] init];
	    callCat.identifier = @"POLL_CATEGORY";
	    [callCat setActions:@[acceptAction, declineAction] forContext:UIUserNotificationActionContextDefault];
	```

	Swift

	```
	// For Swift
	let pushCategory = UIMutableUserNotificationCategory()
	pushCategory.identifier = "TODO_CATEGORY"
	pushCategory.setActions([acceptAction, declineAction], forContext: UIUserNotificationActionContext.Default)
	```

1. Create the notification setting and assign the categories from the previous step.

	Objective-C

	```
	// For Objective-C
	NSSet *categories = [NSSet setWithObjects:callCat, nil];
	```

	Swift

	```
	// For Swift
	let categories = NSSet(array:[pushCategory]);
	```

1. Create the local or remote notification and assign it the identity of the category.

	Objective-C

	```
	//For Objective-C

	[[UIApplication sharedApplication] registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge) categories:categories]];

	[[UIApplication sharedApplication] registerForRemoteNotifications];
	```

	Swift

	```
	//For Swift
	let notificationTypes: UIUserNotificationType = UIUserNotificationType.Badge | UIUserNotificationType.Alert | UIUserNotificationType.Sound
	let notificationSettings: UIUserNotificationSettings = UIUserNotificationSettings(forTypes: notificationTypes, categories: categories)

	application.registerUserNotificationSettings(notificationSettings)
	application.registerForRemoteNotifications()
	```


text:
using System.Diagnostics;
using System.Globalization;
using System.Net.Sockets;
using System.Text;

#if SYSTEM_NET_PRIMITIVES_DLL
namespace System.Net
#else
namespace System.Net.Internals
#endif
{
    // This class is used when subclassing EndPoint, and provides indication
    // on how to format the memory buffers that the platform uses for network addresses.
#if SYSTEM_NET_PRIMITIVES_DLL
    public
#else
    internal
#endif
    class SocketAddress
    {
        internal static readonly int IPv6AddressSize = SocketAddressPal.IPv6AddressSize;
        internal static readonly int IPv4AddressSize = SocketAddressPal.IPv4AddressSize;

        internal int InternalSize;
        internal byte[] Buffer;

        private const int MinSize = 2;
        private const int MaxSize = 32; // IrDA requires 32 bytes
        private bool _changed = true;
        private int _hash;

        public AddressFamily Family
        {
            get
            {
                return SocketAddressPal.GetAddressFamily(Buffer);
            }
        }

        public int Size
        {
            get
            {
                return InternalSize;
            }
        }

        // Access to unmanaged serialized data. This doesn't
        // allow access to the first 2 bytes of unmanaged memory
        // that are supposed to contain the address family which
        // is readonly.
        public byte this[int offset]
        {
            get
            {
                if (offset < 0 || offset >= Size)
                {
                    throw new IndexOutOfRangeException();
                }
                return Buffer[offset];
            }
            set
            {
                if (offset < 0 || offset >= Size)
                {
                    throw new IndexOutOfRangeException();
                }
                if (Buffer[offset] != value)
                {
                    _changed = true;
                }
                Buffer[offset] = value;
            }
        }

        public SocketAddress(AddressFamily family) : this(family, MaxSize)
        {
        }

        public SocketAddress(AddressFamily family, int size)
        {
            if (size < MinSize)
            {
                throw new ArgumentOutOfRangeException(nameof(size));
            }

            InternalSize = size;
            Buffer = new byte[(size / IntPtr.Size + 2) * IntPtr.Size];

            SocketAddressPal.SetAddressFamily(Buffer, family);
        }

        internal SocketAddress(IPAddress ipAddress)
            : this(ipAddress.AddressFamily,
                ((ipAddress.AddressFamily == AddressFamily.InterNetwork) ? IPv4AddressSize : IPv6AddressSize))
        {
            // No Port.
            SocketAddressPal.SetPort(Buffer, 0);

            if (ipAddress.AddressFamily == AddressFamily.InterNetworkV6)
            {
                Span<byte> addressBytes;
                unsafe
                {
                    // TODO https://github.com/dotnet/roslyn/issues/17287: Clean up once we can stackalloc into a span
                    byte* mem = stackalloc byte[IPAddressParserStatics.IPv6AddressBytes];
                    addressBytes = new Span<byte>(mem, IPAddressParserStatics.IPv6AddressBytes);
                }
                ipAddress.TryWriteBytes(addressBytes, out int bytesWritten);
                Debug.Assert(bytesWritten == IPAddressParserStatics.IPv6AddressBytes);

                SocketAddressPal.SetIPv6Address(Buffer, addressBytes, (uint)ipAddress.ScopeId);
            }
            else
            {
#pragma warning disable CS0618 // using Obsolete Address API because it's the more efficient option in this case
                uint address = unchecked((uint)ipAddress.Address);
#pragma warning restore CS0618

                Debug.Assert(ipAddress.AddressFamily == AddressFamily.InterNetwork);
                SocketAddressPal.SetIPv4Address(Buffer, address);
            }
        }

        internal SocketAddress(IPAddress ipaddress, int port)
            : this(ipaddress)
        {
            SocketAddressPal.SetPort(Buffer, unchecked((ushort)port));
        }

        internal IPAddress GetIPAddress()
        {
            if (Family == AddressFamily.InterNetworkV6)
            {
                Debug.Assert(Size >= IPv6AddressSize);

                Span<byte> address;
                unsafe
                {
                    // TODO https://github.com/dotnet/roslyn/issues/17287: Clean up once we can stackalloc into a span
                    byte* mem = stackalloc byte[IPAddressParserStatics.IPv6AddressBytes];
                    address = new Span<byte>(mem, IPAddressParserStatics.IPv6AddressBytes);
                }
                uint scope;
                SocketAddressPal.GetIPv6Address(Buffer, address, out scope);

                return new IPAddress(address, (long)scope);
            }
            else if (Family == AddressFamily.InterNetwork)
            {
                Debug.Assert(Size >= IPv4AddressSize);
                long address = (long)SocketAddressPal.GetIPv4Address(Buffer) & 0x0FFFFFFFF;
                return new IPAddress(address);
            }
            else
            {
#if SYSTEM_NET_PRIMITIVES_DLL
                throw new SocketException(SocketError.AddressFamilyNotSupported);
#else
                throw new SocketException((int)SocketError.AddressFamilyNotSupported);
#endif
            }
        }

        internal IPEndPoint GetIPEndPoint()
        {
            IPAddress address = GetIPAddress();
            int port = (int)SocketAddressPal.GetPort(Buffer);
            return new IPEndPoint(address, port);
        }

        // For ReceiveFrom we need to pin address size, using reserved Buffer space.
        internal void CopyAddressSizeIntoBuffer()
        {
            Buffer[Buffer.Length - IntPtr.Size] = unchecked((byte)(InternalSize));
            Buffer[Buffer.Length - IntPtr.Size + 1] = unchecked((byte)(InternalSize >> 8));
            Buffer[Buffer.Length - IntPtr.Size + 2] = unchecked((byte)(InternalSize >> 16));
            Buffer[Buffer.Length - IntPtr.Size + 3] = unchecked((byte)(InternalSize >> 24));
        }

        // Can be called after the above method did work.
        internal int GetAddressSizeOffset()
        {
            return Buffer.Length - IntPtr.Size;
        }

        public override bool Equals(object comparand)
        {
            SocketAddress castedComparand = comparand as SocketAddress;
            if (castedComparand == null || this.Size != castedComparand.Size)
            {
                return false;
            }
            for (int i = 0; i < this.Size; i++)
            {
                if (this[i] != castedComparand[i])
                {
                    return false;
                }
            }
            return true;
        }

        public override int GetHashCode()
        {
            if (_changed)
            {
                _changed = false;
                _hash = 0;

                int i;
                int size = Size & ~3;

                for (i = 0; i < size; i += 4)
                {
                    _hash ^= (int)Buffer[i]
                            | ((int)Buffer[i + 1] << 8)
                            | ((int)Buffer[i + 2] << 16)
                            | ((int)Buffer[i + 3] << 24);
                }
                if ((Size & 3) != 0)
                {
                    int remnant = 0;
                    int shift = 0;

                    for (; i < Size; ++i)
                    {
                        remnant |= ((int)Buffer[i]) << shift;
                        shift += 8;
                    }
                    _hash ^= remnant;
                }
            }
            return _hash;
        }

        public override string ToString()
        {
            StringBuilder bytes = new StringBuilder();
            for (int i = SocketAddressPal.DataOffset; i < this.Size; i++)
            {
                if (i > SocketAddressPal.DataOffset)
                {
                    bytes.Append(",");
                }
                bytes.Append(this[i].ToString(NumberFormatInfo.InvariantInfo));
            }
            return Family.ToString() + ":" + Size.ToString(NumberFormatInfo.InvariantInfo) + ":{" + bytes.ToString() + "}";
        }
    }
}


text:
# -*- coding: utf-8 -*-
# pylint: disable-msg = C0103, W0221
#
# Copyright 2004-2006 André Malo or his licensors, as applicable
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
Command line interface
======================

The svnmailer provides two different command line interfaces. On the one hand
there's the compatibility command line to the mailer.py script, which has some
limitations and problems because of its unflexibility. On the other hand
you'll find the new-style command line, which contains no subcommands and
fixed parameters at all.

The CLI simply transforms old-style command lines to the new format internally
and processes these further using the optparse module::

    svn-mailer commit <rep> <rev> [<config>]
 -> svn-mailer --commit --repository <rep> --revision <rev>
              [--config <config>]

    svn-mailer propchange <rep> <rev> <author> <prop> [<conf>]
 -> svn-mailer --propchange --repository <rep> --revision <rev>
               --author <author> --propname <prop>
              [--config <conf>]

    # (useful with svn 1.2 and later)
    svn-mailer propchange2 <rep> <rev> <author> <prop> <action> [<conf>]
 -> svn-mailer --propchange --repository <rep> --revision <rev>
               --author <author> --propname <prop> --action <action>
              [--config <conf>]

    svn-mailer lock <rep> <author> [<conf>]
 -> svn-mailer --lock --repository <rep> --author <author>
              [--config <conf>]

    svn-mailer unlock <rep> <author> [<conf>]
 -> svn-mailer --unlock --repository <rep> --author <author>
              [--config <conf>]
"""
__author__    = "André Malo"
__docformat__ = "epytext en"
__all__       = ['getOptions', 'CommandlineError']

# global imports
import optparse

# Exceptions
class Error(Exception):
    """ Base exception for this module """
    pass

class CommandlineError(Error):
    """ Error in commandline """
    pass

def getOptions(argv = None):
    """ Parse commandline options

        @param argv: Command line list. If argv is None,
            sys.argv[1:] is evaluated instead
        @type argv: C{list}

        @return: option object
        @rtype: C{optparse.OptionParser}

        @exception CommandlineError: Error in command line options
    """
    from svnmailer import util
    from svnmailer.settings import modes

    usage = """%prog <options>"""
    parser = SvnmailerOptionParser(usage = usage, version = True)
    options, args = parser.parse_args(argv)

    # Check parameter consistency
    if args:
        raise CommandlineError("Too much arguments")

    if not options.repository:
        raise CommandlineError("Missing repository path")

    if not options.revision:
        if options.mode in (modes.commit, modes.propchange):
            raise CommandlineError("Missing revision number")

    if not options.author:
        if options.mode in (modes.propchange, modes.lock, modes.unlock):
            raise CommandlineError("Missing author parameter")

    if not options.propname:
        if options.mode == modes.propchange:
            raise CommandlineError("Missing property name parameter")

    # de-localize the paths
    try:
        options.repository = util.filename.fromLocale(
            options.repository, options.path_encoding
        )
    except UnicodeError, exc:
        raise CommandlineError("--repository recode problem: %s" % str(exc))

    if options.config:
        try:
            options.config = util.filename.fromLocale(
                options.config, options.path_encoding
            )
        except UnicodeError, exc:
            raise CommandlineError("--config recode problem: %s" % str(exc))

    return options

class SvnmailerOptionParser(optparse.OptionParser):
    """ Fully initialized option parser

        @ivar _svn: The svn version
        @type _svn: C{tuple}
    """

    def __init__(self, *args, **kwargs):
        """ Initialization """
        from svnmailer import subversion

        self._svn = subversion.version
        optparse.OptionParser.__init__(self, *args, **kwargs)
        self._initSvnmailer()

    def parse_args(self, args = None, *other_args, **kwargs):
        """ Accepts also the old command line """
        args = self._transformSvnmailerOldStyle(args)
        if not args:
            raise CommandlineError(
                "Type '%s --help' for usage" % self.get_prog_name()
            )

        options, fixed = optparse.OptionParser.parse_args(
            self, args, *other_args, **kwargs
        )

        # fixup action attribute (expected later)
        if not self._svn.min_1_2:
            options.action = None

        return (options, fixed)

    def error(self, msg):
        """ We raise an exception instead of exiting

            @param msg: The error message
            @type msg: C{str}

            @exception CommandlineError: command line error
        """
        raise CommandlineError(str(msg))

    def get_version(self):
        """ Returns the version string """
        from svnmailer import version

        return "svnmailer-%s\nwith svn %d.%d.%d%s" % (
            version, self._svn.major, self._svn.minor, self._svn.patch,
            self._svn.tag
        )

    def get_prog_name(self):
        """ Returns the program name """
        try:
            # >= python 2.4
            return optparse.OptionParser.get_prog_name(self)
        except AttributeError:
            try:
                # >= python 2.3.4
                return optparse.OptionParser._get_prog_name(self)
            except AttributeError:
                # <= python 2.3.3
                if self.prog:
                    return self.prog
                else:
                    import os, sys
                    return os.path.basename(sys.argv[0])

    def format_help(self, formatter = None):
        """ Adds a description of the old style options """
        import textwrap

        width = (self._getTerminalWidth() or 80) - 1
        optionhelp = None
        while optionhelp is None:
            try:
                formatter = optparse.IndentedHelpFormatter(width = width)
                optionhelp = optparse.OptionParser.format_help(self, formatter)
            except ValueError:
                # terminal too small *sigh*
                if width < 79:
                    width = 79
                else:
                    width += 10

        oldstyle = textwrap.fill(
            "Alternatively you can use the old style compatibility "
            "command lines (options described above don't apply then):",
            width = width,
        )

        prog = self.get_prog_name()
        indent = " " * (len(prog) + 1)
        clines = [
            "",
            "%(prog)s commit <repos> <revision> [<config>]",
            "%(prog)s propchange <repos> <revision> <author> <propname> "
                     "[<config>]",
        ]
        if self._svn.min_1_2:
            clines.extend([
                "",
                "svn 1.2 and later:",
                "%(prog)s propchange2 <repos> <revision> <author> <propname> "
                         "<action> [<config>]",
                "%(prog)s lock <repos> <author> [<config>]",
                "%(prog)s unlock <repos> <author> [<config>]",
            ])
        clines = ["%s\n" % textwrap.fill(
            line % {'prog': prog}, width = width, subsequent_indent = indent
        ) for line in clines]

        return "%s\n%s\n%s" % (optionhelp, oldstyle, ''.join(clines))

    def _getTerminalWidth(self):
        """ Returns terminal width if determined, None otherwise

            @return: The width
            @rtype: C{int}
        """
        try:
            import errno, fcntl, struct, sys, termios

            def getwidth(fd):
                """ Returns the width for descriptor fd """
                # struct winsize { /* on linux in asm/termios.h */
                #     unsigned short ws_row;
                #     unsigned short ws_col;
                #     unsigned short ws_xpixel;
                #     unsigned short ws_ypixel;
                # }
                return struct.unpack("4H", fcntl.ioctl(
                    fd, termios.TIOCGWINSZ, struct.pack("4H", 0, 0, 0, 0)
                ))[1]

            try:
                return getwidth(sys.stdout.fileno())
            except IOError, exc:
                if exc[0] == errno.EINVAL:
                    return getwidth(sys.stdin.fileno())
                raise # otherwise

        except (SystemExit, KeyboardInterrupt):
            raise

        except:
            # don't even ignore
            pass

        return None

    def _initSvnmailer(self):
        """ Builds the options from option groups """
        self._addSvnmailerCommonOptions()
        self._addSvnmailerBehaviourOptions()
        self._addSvnmailerSupplementalOptions()

    def _addSvnmailerCommonOptions(self):
        """ Adds the common options group """
        common_options = optparse.OptionGroup(
            self, 'COMMON PARAMETERS'
        )
        common_options.add_option('--debug',
            action = 'store_true',
            default = False,
            help = "Run in debug mode (means basically that all messages "
                "are sent to STDOUT)",
        )
        common_options.add_option('-d', '--repository',
            help = 'The repository directory',
        )
        common_options.add_option('-f', '--config',
            help = 'The configuration file',
        )
        common_options.add_option('-e', '--path-encoding',
            help = 'Specifies the character encoding to be used for '
                'filenames. By default the encoding is tried to be '
                'determined automatically depending on the locale.'
        )
        self.add_option_group(common_options)

    def _addSvnmailerBehaviourOptions(self):
        """ Adds the behaviour options group """
        from svnmailer.settings import modes

        behaviour_options = optparse.OptionGroup(
            self, 'BEHAVIOUR OPTIONS',
            description = "The behaviour options are mutually exclusive, "
                "i.e. the last one wins."
        )
        behaviour_options.add_option('-c', '--commit',
            dest = 'mode',
            action = 'store_const',
            const = modes.commit,
            default = modes.commit,
            help = 'This is a regular commit of versioned data '
                   '(post-commit hook). This is default.',
        )
        behaviour_options.add_option('-p', '--propchange',
            dest = 'mode',
            action = 'store_const',
            const = modes.propchange,
            help = 'This is a modification of unversioned properties '
                '(post-revprop-change hook)',
        )

        if self._svn.min_1_2:
            behaviour_options.add_option('-l', '--lock',
                dest = 'mode',
                action = 'store_const',
                const = modes.lock,
                help = '(svn 1.2 and later) This is a locking call '
                    '(post-lock hook)',
            )
            behaviour_options.add_option('-u', '--unlock',
                dest = 'mode',
                action = 'store_const',
                const = modes.unlock,
                help = '(svn 1.2 and later) This is a unlocking call '
                    '(post-unlock hook)',
            )

        self.add_option_group(behaviour_options)

    def _addSvnmailerSupplementalOptions(self):
        """ Adds the supplemental options """
        supp_options = optparse.OptionGroup(
            self, 'SUPPLEMENTAL PARAMETERS'
        )

        supp_options.add_option('-r', '--revision',
            action = 'store',
            type = 'int',
            help = 'The modified/committed revision number',
        )
        supp_options.add_option('-a', '--author',
            help = 'The author of the modification',
        )
        supp_options.add_option('-n', '--propname',
            help = 'The name of the modified property',
        )

        if self._svn.min_1_2:
            supp_options.add_option('-o', '--action',
                help = '(svn 1.2 and later) The property change action',
            )

        self.add_option_group(supp_options)

    def _transformSvnmailerOldStyle(self, argv):
        """ Parses the command line according to old style rules

            @param argv: Command line list. If argv is None,
                sys.argv[1:] is evaluated instead
            @type argv: C{list}

            @return: The commandline, possibly transformed to new style
            @rtype: C{list}
        """
        if argv is None:
            import sys
            argv = sys.argv[1:]

        if argv:
            length = len(argv)

            # svn-mailer commit <rep> <rev> [<conf>]
            if argv[0] == "commit" and 3 <= length <= 4:
                config = argv[3:]
                argv = ["--commit",
                        "--repository", argv[1], "--revision", argv[2],
                ]
                if config:
                    argv.extend(["--config", config[0]])

            # svn-mailer propchange <rep> <rev> <author> <prop> [<conf>]
            elif argv[0] == "propchange" and 5 <= length <= 6:
                config = argv[5:]
                argv = ["--propchange",
                        "--repository", argv[1], "--revision", argv[2],
                        "--author", argv[3], "--propname", argv[4],
                ]
                if config:
                    argv.extend(["--config", config[0]])

            else:
                if self._svn.min_1_2:
                    # svn-mailer propchange2 <rep> <rev> <author> <prop> <act>
                    #            [<conf>]
                    if argv[0] == "propchange2" and 6 <= length <= 7:
                        config = argv[6:]
                        argv = ["--propchange",
                                "--repository", argv[1], "--revision", argv[2],
                                "--author", argv[3], "--propname", argv[4],
                                "--action", argv[5],
                        ]
                        if config:
                            argv.extend(["--config", config[0]])

                    # svn-mailer lock <rep> <author> [<conf>]
                    # svn-mailer unlock <rep> <author> [<conf>]
                    elif argv[0] in ("lock", "unlock") and 3 <= length <= 4:
                        config = argv[3:]
                        argv = ["--%s" % argv[0],
                                "--repository", argv[1], "--author", argv[2]
                        ]
                        if config:
                            argv.extend(["--config", config[0]])

        return argv


text:
/**
 * The Selection Model module
 *
 * The ngRepeat companion. This module exists to give developers a lightweight
 * option for easily managing selections in lists and tables. It also aims to
 * play nicely with native angular features so you can leverage existing tools
 * for filtering, sorting, animations, etc.
 *
 * @package selectionModel
 */

angular.module('selectionModel', []);

/**
 * Selection Model Ignore
 *
 * For clickable elements that don't directly interact with `selectionModel`.
 *
 * Useful for when you want to manually change the selection, or for things like
 * "delete" buttons that belong under `ngRepeat` but shouldn't select an item
 * when clicked.
 *
 * @package selectionModel
 * @copyright 2014 Justin Russell, released under the MIT license
 */

angular.module('selectionModel').directive('selectionModelIgnore', [
  function() {
    'use strict';
    return {
      restrict: 'A',
      link: function(scope, element, attrs) {
        element.on('click', function(event) {
          event.selectionModelIgnore = true;

          /**
           * If jQuery is on the page `event` will actually be a jQuery Event
           * and other handlers will only get to see a subset of the event
           * properties that supported by all browsers. Our custom attribute
           * will be dropped. We need to instead decorate the original event
           * object.
           *
           * @see https://github.com/jtrussell/angular-selection-model/issues/27
           */
          if(event.originalEvent) {
            event.originalEvent.selectionModelIgnore = true;
          }
        });
      }
    };
  }
]);

/**
 * Selection Model - a selection aware companion for ngRepeat
 *
 * @package selectionModel
 * @copyright 2014 Justin Russell, released under the MIT license
 */

angular.module('selectionModel').directive('selectionModel', [
  'selectionStack', 'uuidGen', 'selectionModelOptions',
  function(selectionStack, uuidGen, selectionModelOptions) {
    'use strict';
    return {
      restrict: 'A',
      link: function(scope, element, attrs) {

        /**
         * Defaults from the options provider
         *
         * Use `selectionModelOptionsProvider` when configuring your module to
         * set application wide defaults
         */
        var defaultOptions = selectionModelOptions.get()
          , defaultSelectedAttribute = defaultOptions.selectedAttribute
          , defaultSelectedClass = defaultOptions.selectedClass
          , defaultType = defaultOptions.type
          , defaultMode = defaultOptions.mode
          , defaultCleanupStrategy = defaultOptions.cleanupStrategy;

        /**
         * The selection model type
         *
         * Controls how selections are presented on the underlying element. Use
         * 'basic' (the default) to simplye assign a "selected" class to
         * selected items. If set to 'checkbox' it'll also sync the checked
         * state of the first checkbox child in each underlying `tr` or `li`
         * element.
         *
         * Note that the 'checkbox' type assumes the first input child element
         * will be the checkbox.
         */
        var smType = attrs.selectionModelType || defaultType;

        /**
         * The selection mode
         *
         * Supports 'single', 'multi[ple]', and 'multi[ple]-additive'. Single
         * mode will only allow one item to be marked as selected at a time.
         * Vanilla multi mode allows for multiple selectioned items but requires
         * modifier keys to select more than one item at a time. Additive-multi
         * mode allows for multiple items to be selected and will not deselect
         * other items when a vanilla click is made. Additive multi also allows
         * for de-selection without a modifier key (think of `'multi-additive'`
         * as turning every click into a ctrl-click.
         */
        var smMode = attrs.selectionModelMode || defaultMode
          , isMultiMode = /^multi(ple)?(-additive)?$/.test(smMode)
          , isModeAdditive = /^multi(ple)?-additive/.test(smMode);

        /**
         * The item attribute to track selected status
         *
         * Use `selection-model-selected-attribute` to override the default
         * attribute.
         */
        var selectedAttribute = attrs.selectionModelSelectedAttribute || defaultSelectedAttribute;

        /**
         * The selected class name
         *
         * Will be applied to dom items (e.g. `tr` or `li`) representing
         * selected items. Use `selection-model-selected-class` to override the
         * default class name.
         */
        var selectedClass = attrs.selectionModelSelectedClass || defaultSelectedClass;

        /**
         * The cleanup strategy
         *
         * How to handle items that are removed from the current view. By
         * default no action is taken, you may set this to `deselect` to force
         * items to be deselected when they are filtered away, paged away, or
         * otherwise no longer visible on the client.
         */
        var cleanupStrategy = attrs.selectionModelCleanupStrategy || defaultCleanupStrategy;

        /**
         * The change callback
         *
         * To be executed whenever the item's selected state changes.
         */
        var smOnChange = attrs.selectionModelOnChange;

        /**
         * The list of items
         *
         * selectionModel must be attached to the same element as an ngRepeat
         */
        var repeatLine = attrs.ngRepeat;
        if(!repeatLine) {
          throw 'selectionModel must be used along side ngRepeat';
        }

        /**
         * The list of selected items
         *
         * If used should resolve to an (initially empty) array.  Use this in
         * your view as **read only** if you'd like to do something with just
         * the selected items. Note that order is not guarenteed and any items
         * added to this array programmatically are ignored.
         */
        var selectedItemsList = scope.$eval(attrs.selectionModelSelectedItems);

        /**
         * The last-click stack id
         *
         * There may be multiple selection models on the page and each will need
         * independent click stacks.
         */
        var clickStackId = (function() {
          if(!isMultiMode) {
            return null;
          }
          var idAttr = 'data-selection-model-stack-id';
          // Id may be cached on this element
          var stackId = element.attr(idAttr);
          if(stackId) {
            return stackId;
          }

          // Otherwise it may be on the partent
          stackId = element.parent().attr(idAttr);
          if(stackId) {
            element.attr(idAttr, stackId);
            return stackId;
          }

          // welp guess we're the first, create a new one and cache it on this
          // element (for us) and the parent element (for others)
          stackId = uuidGen.create();
          element.attr(idAttr, stackId);
          element.parent().attr(idAttr, stackId);
          return stackId;
        }());

        var repeatParts = repeatLine.split(' in ')
          , smItem = scope.$eval(repeatParts[0]);

        var updateDom = function() {
          if(smItem[selectedAttribute]) {
            element.addClass(selectedClass);
          } else {
            element.removeClass(selectedClass);
          }

          if('checkbox' === smType) {
            var cb = element.find('input');
            cb.prop('checked', smItem[selectedAttribute]);
          }
        };

        var getAllVisibleItems = function() {
          return scope.$eval(repeatParts[1]);
        };

        // Strips away filters - this lets us e.g. deselect items that are
        // filtered out
        var getAllItems = function() {
          return scope.$eval(repeatParts[1].split(/[|=]/)[0]);
        };

        // Get us back to a "clean" state. Usually we'll want to skip
        // deselection for items that are about to be selected again to avoid
        // firing the `selection-mode-on-change` handler extra times.
        //
        // `except` param may be `undefined` (deselect all the things), a single
        // item (don't deselect *that* item), or an array of two items (don't
        // deselect anything between those items inclusively).
        var deselectAllItemsExcept = function(except) {
          var useSelectedArray = angular.isArray(selectedItemsList)
            , isRange = angular.isArray(except) && 2 === except.length
            , allItems = getAllItems()
            , numItemsFound = 0
            , doDeselect = false
            , ixItem;
          if(useSelectedArray) {
            selectedItemsList.length = 0;
          }
          angular.forEach(allItems, function(item) {
            if(isRange) {
              ixItem = except.indexOf(item);
              if(ixItem > -1) {
                numItemsFound++;
                doDeselect = false;
                except.splice(ixItem, 1);
              } else {
                doDeselect = 1 !== numItemsFound;
              }
            } else {
              doDeselect = item !== except;
            }
            if(doDeselect) {
              item[selectedAttribute] = false;
            } else {
              if(useSelectedArray && item[selectedAttribute]) {
                selectedItemsList.push(item);
              }
            }
          });
        };

        var selectItemsBetween = function(lastItem) {
          var allItems = getAllVisibleItems()
            , foundLastItem = false
            , foundThisItem = false;

          lastItem = lastItem || smItem;

          angular.forEach(getAllVisibleItems(), function(item) {
            foundThisItem = foundThisItem || item === smItem;
            foundLastItem = foundLastItem || item === lastItem;
            var inRange = (foundLastItem + foundThisItem) === 1;
            if(inRange || item === smItem || item === lastItem) {
              item[selectedAttribute] = true;
            }
          });
        };

        /**
         * Item click handler
         *
         * Use the `ctrl` key to select/deselect while preserving the rest of
         * your selection. Note your your selection mode must be set to
         * `'multiple'` to allow for more than one selected item at a time. In
         * single select mode you still must use the `ctrl` or `shitft` keys to
         * deselect an item.
         *
         * The `shift` key allows you to select ranges of items at a time. Use
         * `ctrl` + `shift` to select a range while preserving your existing
         * selection. In single select mode `shift` behaves like `ctrl`.
         *
         * When an item is clicked with no modifier keys pressed it will be the
         * only selected item.
         *
         * On Mac the `meta` key is treated as `ctrl`.
         *
         * Note that when using the `'checkbox'` selection model type clicking
         * on a checkbox will have no effect on any row other than the one the
         * checkbox is in.
         */
        var handleClick = function(event) {

          /**
           * Set by the `selectionModelIgnore` directive
           *
           * Use `selectionModelIgnore` to cause `selectionModel` to selectively
           * ignore clicks on elements. This is useful if you want to manually
           * change a selection when certain things are clicked.
           */
          if(event.selectionModelIgnore || (event.originalEvent && event.originalEvent.selectionModelIgnore)) {
            return;
          }

          // Never handle a single click twice.
          if(event.selectionModelClickHandled || (event.originalEvent && event.originalEvent.selectionModelClickHandled)) {
            return;
          }
          event.selectionModelClickHandled = true;
          if(event.originalEvent) {
            event.originalEvent.selectionModelClickHandled = true;
          }

          var isCtrlKeyDown = event.ctrlKey || event.metaKey || isModeAdditive
            , isShiftKeyDown = event.shiftKey
            , target = event.target || event.srcElement
            , isCheckboxClick = 'checkbox' === smType &&
                'INPUT' === target.tagName &&
                'checkbox' === target.type;

          /**
           * Guard against label + checkbox clicks
           *
           * Clicking a label will cause a click event to also be fired on the
           * associated input element. If that input is nearby (i.e. under the
           * selection model element) we'll suppress the click on the label to
           * avoid duplicate click events.
           */
          if('LABEL' === target.tagName) {
            var labelFor = angular.element(target).attr('for');
            if(labelFor) {
              var childInputs = element[0].getElementsByTagName('INPUT'), ix;
              for(ix = childInputs.length; ix--;) {
                if(childInputs[ix].id === labelFor) {
                  return;
                }
              }
            } else if(target.getElementsByTagName('INPUT').length) {
              // Label has a nested input element, we'll handle the click on
              // that element
              return;
            }
          }

          // Select multiple allows for ranges - use shift key
          if(isShiftKeyDown && isMultiMode && !isCheckboxClick) {
            // Use ctrl+shift for additive ranges
            if(!isCtrlKeyDown) {
              scope.$apply(function() {
                deselectAllItemsExcept([smItem, selectionStack.peek(clickStackId)]);
              });
            }
            selectItemsBetween(selectionStack.peek(clickStackId));
            scope.$apply();
            return;
          }

          // Use ctrl/shift without multi select to true toggle a row
          if(isCtrlKeyDown || isShiftKeyDown || isCheckboxClick) {
            var isSelected = !smItem[selectedAttribute];
            if(!isMultiMode) {
              deselectAllItemsExcept(smItem);
            }
            smItem[selectedAttribute] = isSelected;
            if(smItem[selectedAttribute]) {
              selectionStack.push(clickStackId, smItem);
            }
            scope.$apply();
            return;
          }

          // Otherwise the clicked on row becomes the only selected item
          deselectAllItemsExcept(smItem);
          scope.$apply();

          smItem[selectedAttribute] = true;
          selectionStack.push(clickStackId, smItem);
          scope.$apply();
        };

        /**
         * Routine to keep the list of selected items up to date
         *
         * Adds/removes this item from `selectionModelSelectedItems`.
         */
        var updateSelectedItemsList = function() {
          if(angular.isArray(selectedItemsList)) {
            var ixSmItem = selectedItemsList.indexOf(smItem);
            if(smItem[selectedAttribute]) {
              if(-1 === ixSmItem) {
                selectedItemsList.push(smItem);
              }
            } else {
              if(-1 < ixSmItem) {
                selectedItemsList.splice(ixSmItem, 1);
              }
            }
          }
        };

        element.on('click', handleClick);
        if('checkbox' === smType) {
          var elCb = element.find('input');
          if(elCb[0] && 'checkbox' === elCb[0].type) {
            element.find('input').on('click', handleClick);
          }
        }

        // We might be coming in with a selection
        updateDom();
        updateSelectedItemsList();

        // If we were given a cleanup strategy then setup a `'$destroy'`
        // listener on the scope.
        if('deselect' === cleanupStrategy) {
          scope.$on('$destroy', function() {
            var oldSelectedStatus = smItem[selectedAttribute];
            smItem[selectedAttribute] = false;
            updateSelectedItemsList();
            if(smOnChange && oldSelectedStatus) {
              scope.$eval(smOnChange);
            }
          });
        }

        scope.$watch(repeatParts[0] + '.' + selectedAttribute, function(newVal, oldVal) {
          // Be mindful of programmatic changes to selected state
          if(newVal !== oldVal) {
            if(!isMultiMode && newVal && !oldVal) {
              deselectAllItemsExcept(smItem);
              smItem[selectedAttribute] = true;
            }
            updateDom();
            updateSelectedItemsList();

            if(smOnChange) {
              scope.$eval(smOnChange);
            }
          }
        });
      }
    };
  }
]);

/**
 * Default options for the selection model directive
 *
 *
 *
 * @package selectionModel
 */

angular.module('selectionModel').provider('selectionModelOptions', [function() {
  'use strict';

  var options = {
    selectedAttribute: 'selected',
    selectedClass: 'selected',
    type: 'basic',
    mode: 'single',
    cleanupStrategy: 'none'
  };

  this.set = function(userOpts) {
    angular.extend(options, userOpts);
  };

  this.$get = function() {
    var exports = {
      get: function() {
        return angular.copy(options);
      }
    };
    return exports;
  };

}]);

angular.module('selectionModel').service('selectionStack', function() {
  'use strict';
  var exports = {}
    , maxSize = 1000
    , stacks = {};

  exports.push = function(id, item) {
    if(!stacks.hasOwnProperty(id)) {
      stacks[id] = [];
    }
    var stack = stacks[id];
    stack.push(item);
    while(stack.length > maxSize) {
      stack.shift();
    }
    return stack.length;
  };

  exports.pop = function(id) {
    if(!stacks.hasOwnProperty(id)) {
      stacks[id] = [];
    }
    var stack = stacks[id];
    return stack.pop();
  };

  exports.peek = function(id) {
    if(!stacks.hasOwnProperty(id)) {
      stacks[id] = [];
    }
    var stack = stacks[id];
    return stack.length ? stack[stack.length - 1] : undefined;
  };

  return exports;
});

/*jshint bitwise:false */

angular.module('selectionModel').service('uuidGen', function() {
  'use strict';
  var exports = {};
  var uid = ['0', '0', '0'];

  exports.create = function() {
    var index = uid.length;
    var digit;
    while (index) {
      index--;
      digit = uid[index].charCodeAt(0);
      if (digit === 57 /*'9'*/ ) {
        uid[index] = 'A';
        return uid.join('');
      }
      if (digit === 90 /*'Z'*/ ) {
        uid[index] = '0';
      } else {
        uid[index] = String.fromCharCode(digit + 1);
        return uid.join('');
      }
    }
    uid.unshift('0');
    return uid.join('');
  };

  return exports;
});