text:
The .NET 2.1.26 and .NET SDK 2.1.522 releases are available for download. The latest 2.1 release is always listed at [.NET 2.1 Releases](../README.md).

## Downloads

|           | SDK Installer1                        | SDK Binaries1                 | Runtime Installer                                        | Runtime Binaries                                 | ASP.NET Core Runtime           |
| --------- | :------------------------------------------:     | :----------------------:                 | :---------------------------:                            | :-------------------------:                      | :-----------------:            |
| Windows   | [x86][dotnet-sdk-win-x86.exe] \| [x64][dotnet-sdk-win-x64.exe] | [x86][dotnet-sdk-win-x86.zip] \| [x64][dotnet-sdk-win-x64.zip] | [x86][dotnet-runtime-win-x86.exe] \| [x64][dotnet-runtime-win-x64.exe] | [x86][dotnet-runtime-win-x86.zip] \| [x64][dotnet-runtime-win-x64.zip] \| [ARM][dotnet-runtime-win-arm.zip] | [x86][aspnetcore-runtime-win-x86.exe] \| [x64][aspnetcore-runtime-win-x64.exe] \|
 [Hosting Bundle][dotnet-hosting-win.exe]2 |
| macOS     | [x64][dotnet-sdk-osx-x64.pkg]  | [x64][dotnet-sdk-osx-x64.tar.gz]     | [x64][dotnet-runtime-osx-x64.pkg] | [x64][dotnet-runtime-osx-x64.tar.gz] | [x64][aspnetcore-runtime-osx-x64.tar.gz]1
| Linux     | [See installation steps][linux-install]   | [x64][dotnet-sdk-linux-x64.tar.gz] \| [ARM][dotnet-sdk-linux-arm.tar.gz] \| [ARM64][dotnet-sdk-linux-arm64.tar.gz] \| [x64 Alpine][dotnet-sdk-linux-musl-x64.tar.gz] | - | [x64][dotnet-runtime-linux-x64.tar.gz] \| [ARM][dotnet-runtime-linux-arm.tar.gz] \| [ARM64][dotnet-runtime-linux-arm64.tar.gz] \| [x64 Alpine][dotnet-runtime-linux-musl-x64.tar.gz] | [x64][aspnetcore-runtime-linux-x64.tar.gz]1  \| [ARM][aspnetcore-runtime-linux-arm.tar.gz]1 \| [x64 Alpine][aspnetcore-runtime-linux-musl-x64.tar.gz]1 |
| Checksums | [SDK][checksums-sdk]                             | -                                        | [Runtime][checksums-runtime]                             | - | - |

1. Includes the .NET Core and ASP.NET Core Runtimes.

2. For hosting stand-alone apps on Windows Servers. Includes the ASP.NET Core Module for IIS and can be installed separately on servers without installing .NET Core runtime.

The .NET SDK includes a matching updated .NET Runtime. Downloading the Runtime or ASP.NET Core packages is not needed when installing the SDK.

You can check your .NET SDK version by running the following command. The example version shown is for this release.

```console
$ dotnet --version
2.1.522
```

Visit [.NET Documentation](https://docs.microsoft.com/dotnet/core/) to learn about .NET, for building many different types of applications.

## Docker Images

The [.NET Core Docker images](https://hub.docker.com/_/microsoft-dotnet) have been updated for this release. The [.NET Docker samples](https://github.com/dotnet/dotnet-docker/blob/main/samples/README.md) show various ways to use .NET and Docker together.

The following repos have been updated:

* [dotnet/sdk](https://hub.docker.com/_/microsoft-dotnet-sdk/): .NET Core SDK
* [dotnet/aspnet](https://hub.docker.com/_/microsoft-dotnet-aspnet/): ASP.NET Core Runtime
* [dotnet/runtime](https://hub.docker.com/_/microsoft-dotnet-runtime/): .NET Core Runtime
* [dotnet/runtime-deps](https://hub.docker.com/_/microsoft-dotnet-runtime-deps/): .NET Core Runtime Dependencies

## Visual Studio Compatibility

This update for .NET Core 2.1 includes multiple SDK builds. If you are a Visual Studio 2019, Visual Studio 2017 or Visual Studio for Mac user, there are MSBuild version requirements that are satisfied by specific, matching .NET Core SDK versions. See the following table to select the correct download.

| OS | Development Environment | .NET Core SDK |
| :-- | :-- | :--: |
| Windows | Visual Studio 2017 | [2.1.522](#downloads) |
| macOS | Visual Studio for Mac | [Visual Studio for Mac .NET Core Support](https://docs.microsoft.com/visualstudio/mac/net-core-support) |

Note: This is not a security release hence this update won't be immediately available through Visual Studio. However, this is expected to show up in Visual Studio's January servicing release.

This update of .NET Core 2.1 is the last update for .NET Core 2.1.6xx SDK since [Visual Studio 16.0 is out of support](https://docs.microsoft.com/en-us/visualstudio/releases/2019/servicing) as of January 2021. We will continue to update versions 2.1.5xx and 2.1.8xx until [.NET Core 2.1 reaches end of life](https://github.com/dotnet/core/blob/main/releases.md).

## Notable Changes

.NET Core 2.1.26 release carries both security and non-security fixes.

# Microsoft Security Advisory CVE-2021-26701 | .NET Core Remote Code Execution Vulnerability

## Executive summary

Microsoft is releasing this security advisory to provide information about a vulnerability in .NET 5.0, .NET Core 3.1, and .NET Core 2.1. This advisory also provides guidance on what developers can do to update their applications to remove this vulnerability.

A remote code execution vulnerability exists in .NET 5 and .NET Core due to how text encoding is performed.

* [Blog Roundup][dotnet-blog]
* [Known issues](../2.1-known-issues.md)

### Additional fixes in this release

* [Setup](https://github.com/dotnet/core-setup/pulls?q=milestone%3A2.1.26+is%3Aclosed+label%3Aservicing-approved)

## Feedback

Your feedback is important and appreciated. We've created an issue at [dotnet/core #6035](https://github.com/dotnet/core/issues/6035) for your questions and comments.

## Packages updated in this release:

Package name | Version
:----------- | :------------------
microsoft.aspnetcore.all | 2.1.26.nupkg
microsoft.aspnetcore.app | 2.1.26.nupkg
microsoft.dotnet.web.client.itemtemplates | 2.1.26.nupkg
microsoft.dotnet.web.itemtemplates | 2.1.26.nupkg
microsoft.dotnet.web.projecttemplates.2.1 | 2.1.26.nupkg
microsoft.dotnet.web.spa.projecttemplates.2.1 | 2.1.26.nupkg
microsoft.netcore.platforms | 2.1.13.nupkg
system.text.encodings.web | 4.5.1.nupkg
microsoft.netcore.app | 2.1.26.nupkg
microsoft.netcore.dotnetapphost | 2.1.26.nupkg
microsoft.netcore.dotnethost | 2.1.26.nupkg
microsoft.netcore.dotnethostpolicy | 2.1.26.nupkg
microsoft.netcore.dotnethostresolver | 2.1.26.nupkg
runtime.linux-arm.microsoft.netcore.app | 2.1.26.nupkg
runtime.linux-arm.microsoft.netcore.dotnetapphost | 2.1.26.nupkg
runtime.linux-arm.microsoft.netcore.dotnethost | 2.1.26.nupkg
runtime.linux-arm.microsoft.netcore.dotnethostpolicy | 2.1.26.nupkg
runtime.linux-arm.microsoft.netcore.dotnethostresolver | 2.1.26.nupkg
runtime.linux-arm64.microsoft.netcore.app | 2.1.26.nupkg
runtime.linux-arm64.microsoft.netcore.dotnetapphost | 2.1.26.nupkg
runtime.linux-arm64.microsoft.netcore.dotnethost | 2.1.26.nupkg
runtime.linux-arm64.microsoft.netcore.dotnethostpolicy | 2.1.26.nupkg
runtime.linux-arm64.microsoft.netcore.dotnethostresolver | 2.1.26.nupkg
runtime.linux-musl-x64.microsoft.netcore.app | 2.1.26.nupkg
runtime.linux-musl-x64.microsoft.netcore.dotnetapphost | 2.1.26.nupkg
runtime.linux-musl-x64.microsoft.netcore.dotnethost | 2.1.26.nupkg
runtime.linux-musl-x64.microsoft.netcore.dotnethostpolicy | 2.1.26.nupkg
runtime.linux-musl-x64.microsoft.netcore.dotnethostresolver | 2.1.26.nupkg
runtime.linux-x64.microsoft.netcore.app | 2.1.26.nupkg
runtime.linux-x64.microsoft.netcore.dotnetapphost | 2.1.26.nupkg
runtime.linux-x64.microsoft.netcore.dotnethost | 2.1.26.nupkg
runtime.linux-x64.microsoft.netcore.dotnethostpolicy | 2.1.26.nupkg
runtime.linux-x64.microsoft.netcore.dotnethostresolver | 2.1.26.nupkg
runtime.osx-x64.microsoft.netcore.app | 2.1.26.nupkg
runtime.osx-x64.microsoft.netcore.dotnetapphost | 2.1.26.nupkg
runtime.osx-x64.microsoft.netcore.dotnethost | 2.1.26.nupkg
runtime.osx-x64.microsoft.netcore.dotnethostpolicy | 2.1.26.nupkg
runtime.osx-x64.microsoft.netcore.dotnethostresolver | 2.1.26.nupkg
runtime.rhel.6-x64.microsoft.netcore.app | 2.1.26.nupkg
runtime.rhel.6-x64.microsoft.netcore.dotnetapphost | 2.1.26.nupkg
runtime.rhel.6-x64.microsoft.netcore.dotnethost | 2.1.26.nupkg
runtime.rhel.6-x64.microsoft.netcore.dotnethostpolicy | 2.1.26.nupkg
runtime.rhel.6-x64.microsoft.netcore.dotnethostresolver | 2.1.26.nupkg
runtime.win-arm.microsoft.netcore.app | 2.1.26.nupkg
runtime.win-arm.microsoft.netcore.dotnetapphost | 2.1.26.nupkg
runtime.win-arm.microsoft.netcore.dotnethost | 2.1.26.nupkg
runtime.win-arm.microsoft.netcore.dotnethostpolicy | 2.1.26.nupkg
runtime.win-arm.microsoft.netcore.dotnethostresolver | 2.1.26.nupkg
runtime.win-arm64.microsoft.netcore.app | 2.1.26.nupkg
runtime.win-arm64.microsoft.netcore.dotnetapphost | 2.1.26.nupkg
runtime.win-arm64.microsoft.netcore.dotnethost | 2.1.26.nupkg
runtime.win-arm64.microsoft.netcore.dotnethostpolicy | 2.1.26.nupkg
runtime.win-arm64.microsoft.netcore.dotnethostresolver | 2.1.26.nupkg
runtime.win-x64.microsoft.netcore.app | 2.1.26.nupkg
runtime.win-x64.microsoft.netcore.dotnetapphost | 2.1.26.nupkg
runtime.win-x64.microsoft.netcore.dotnethost | 2.1.26.nupkg
runtime.win-x64.microsoft.netcore.dotnethostpolicy | 2.1.26.nupkg
runtime.win-x64.microsoft.netcore.dotnethostresolver | 2.1.26.nupkg
runtime.win-x86.microsoft.netcore.app | 2.1.26.nupkg
runtime.win-x86.microsoft.netcore.dotnetapphost | 2.1.26.nupkg
runtime.win-x86.microsoft.netcore.dotnethost | 2.1.26.nupkg
runtime.win-x86.microsoft.netcore.dotnethostpolicy | 2.1.26.nupkg
runtime.win-x86.microsoft.netcore.dotnethostresolver | 2.1.26.nupkg
vs.redist.common.netcore.hostfxr.x64.2.1 | 2.1.26-servicing-29812-01.nupkg
vs.redist.common.netcore.hostfxr.x86.2.1 | 2.1.26-servicing-29812-01.nupkg
vs.redist.common.netcore.sharedframework.x64.2.1 | 2.1.26-servicing-29812-01.nupkg
vs.redist.common.netcore.sharedframework.x86.2.1 | 2.1.26-servicing-29812-01.nupkg
vs.redist.common.netcore.sharedhost.x64.2.1 | 2.1.26-servicing-29812-01.nupkg
vs.redist.common.netcore.sharedhost.x86.2.1 | 2.1.26-servicing-29812-01.nupkg

[blob-runtime]: https://dotnetcli.blob.core.windows.net/dotnet/Runtime/
[blob-sdk]: https://dotnetcli.blob.core.windows.net/dotnet/Sdk/
[release-notes]: https://github.com/dotnet/core/blob/main/release-notes/2.1/2.1.26/2.1.26.md

[checksums-runtime]: https://dotnetcli.blob.core.windows.net/dotnet/checksums/2.1.26-sha.txt
[checksums-sdk]: https://dotnetcli.blob.core.windows.net/dotnet/checksums/2.1.26-sha.txt

[linux-install]: https://docs.microsoft.com/dotnet/core/install/linux
[linux-setup]: https://docs.microsoft.com/dotnet/core/install/
[dotnet-blog]:  https://devblogs.microsoft.com/dotnet/net-march-2021/

[//]: # ( Runtime 2.1.26)
[dotnet-runtime-linux-arm.tar.gz]: https://download.visualstudio.microsoft.com/download/pr/52126202-3b11-4c57-abcf-e6785b457d3b/ad4fdb33a45f1609ca648816809cdda4/dotnet-runtime-2.1.26-linux-arm.tar.gz
[dotnet-runtime-linux-arm64.tar.gz]: https://download.visualstudio.microsoft.com/download/pr/2bf29c8c-38ac-49fd-a025-bb98a6026b8a/2aecbd120ed7f3742fb20ef8fb7a5299/dotnet-runtime-2.1.26-linux-arm64.tar.gz
[dotnet-runtime-linux-musl-x64.tar.gz]: https://download.visualstudio.microsoft.com/download/pr/53121af1-4d0b-4bdb-8437-7e4d05fefec2/ec54855ab05b4d0a7763359accd1a11f/dotnet-runtime-2.1.26-linux-musl-x64.tar.gz
[dotnet-runtime-linux-x64.tar.gz]: https://download.visualstudio.microsoft.com/download/pr/5c00bafe-4ead-4e9a-82b6-884a9727e751/fdb7f6701e556d89b6884037cc9983cb/dotnet-runtime-2.1.26-linux-x64.tar.gz
[dotnet-runtime-osx-x64.pkg]: https://download.visualstudio.microsoft.com/download/pr/3ae95a85-8462-48bf-93b3-36c06503c963/3aa1ec7156426f37f24caac2e1cfd7f7/dotnet-runtime-2.1.26-osx-x64.pkg
[dotnet-runtime-osx-x64.tar.gz]: https://download.visualstudio.microsoft.com/download/pr/3d45ab34-41d7-4b03-9c63-c2cac3e34bfa/ade28caed6519aab9b45ec2a230d3655/dotnet-runtime-2.1.26-osx-x64.tar.gz
[dotnet-runtime-win-arm.zip]: https://download.visualstudio.microsoft.com/download/pr/3f75f681-9792-45c5-ae91-49caf1522ba8/bf1665017e2bafdb36269eddc27cd16e/dotnet-runtime-2.1.26-win-arm.zip
[dotnet-runtime-win-x64.exe]: https://download.visualstudio.microsoft.com/download/pr/0a7f035b-4367-49ab-9967-fc71c9b9ca85/c124b47ace07cc8d93713f0fbcedc398/dotnet-runtime-2.1.26-win-x64.exe
[dotnet-runtime-win-x64.zip]: https://download.visualstudio.microsoft.com/download/pr/d924d020-06cc-4500-b90a-d230056c2ebe/434fc8e5ea999711d025b27cd8733170/dotnet-runtime-2.1.26-win-x64.zip
[dotnet-runtime-win-x86.exe]: https://download.visualstudio.microsoft.com/download/pr/32d74f73-fcb1-42d8-912f-73e0f8489683/7adb8e13c890d95e82b2b6819c1e1565/dotnet-runtime-2.1.26-win-x86.exe
[dotnet-runtime-win-x86.zip]: https://download.visualstudio.microsoft.com/download/pr/e257e320-c8c4-40ed-8493-cc028c90cb41/597c6f16979f08c81b67e11358a0c7b2/dotnet-runtime-2.1.26-win-x86.zip

[//]: # ( ASP 2.1.26)
[aspnetcore-runtime-linux-arm.tar.gz]: https://download.visualstudio.microsoft.com/download/pr/5d5de5cd-5a86-41fb-ba6d-9672f25ffbe4/cd3ec8bb9f8e600249705d078c46418e/aspnetcore-runtime-2.1.26-linux-arm.tar.gz
[aspnetcore-runtime-linux-musl-x64.tar.gz]: https://download.visualstudio.microsoft.com/download/pr/44261a39-5045-418e-9a34-08a0d53e96e6/ab16ae2a67b1e517c4b3bbf2d076c36b/aspnetcore-runtime-2.1.26-linux-musl-x64.tar.gz
[aspnetcore-runtime-linux-x64.tar.gz]: https://download.visualstudio.microsoft.com/download/pr/29ba76e1-db96-4cbb-8964-0a6c859712c4/d6e56c1dacf78b6846464a77dda4115d/aspnetcore-runtime-2.1.26-linux-x64.tar.gz
[aspnetcore-runtime-osx-x64.tar.gz]: https://download.visualstudio.microsoft.com/download/pr/649a6bbc-b0c7-4a57-9683-04e5c806943f/0439b79da4f5a2c113a3102e60b05e20/aspnetcore-runtime-2.1.26-osx-x64.tar.gz
[aspnetcore-runtime-win-x64.exe]: https://download.visualstudio.microsoft.com/download/pr/50de78a9-36af-4500-a75d-8c3d13b15bb1/3bc0ecee1fd2724f75f041feeda5cb6d/aspnetcore-runtime-2.1.26-win-x64.exe
[aspnetcore-runtime-win-x64.zip]: https://download.visualstudio.microsoft.com/download/pr/94869d15-8424-4bf0-9824-7a0ba2162b2f/3ca5871f89c077c608f6374e58a92955/aspnetcore-runtime-2.1.26-win-x64.zip
[aspnetcore-runtime-win-x86.exe]: https://download.visualstudio.microsoft.com/download/pr/9f733b99-0cd3-4569-acde-40bcfcd86b70/57a09a183b7338af99181ed79e3025a6/aspnetcore-runtime-2.1.26-win-x86.exe
[aspnetcore-runtime-win-x86.zip]: https://download.visualstudio.microsoft.com/download/pr/e1953f09-8b30-4a40-b7ac-204149671d6d/2350c0ab769cbaff195c90dd920931bf/aspnetcore-runtime-2.1.26-win-x86.zip
[dotnet-hosting-win.exe]: https://download.visualstudio.microsoft.com/download/pr/24b6ff4e-0c2c-4955-abdc-b339df494a62/2d2edeafccfde9b8a33ced28cad5b7a7/dotnet-hosting-2.1.26-win.exe

[//]: # ( SDK 2.1.522 )
[dotnet-sdk-linux-arm.tar.gz]: https://download.visualstudio.microsoft.com/download/pr/c5df216a-8049-4766-b58f-f152ea37fe0a/c1d9fc6d0c1f5cb6b9e289d5fb1b3aa8/dotnet-sdk-2.1.522-linux-arm.tar.gz
[dotnet-sdk-linux-arm64.tar.gz]: https://download.visualstudio.microsoft.com/download/pr/1599ebfd-8a9f-4939-8597-d040e1c0f278/4c0c3f17e42a3a9a2de0130e45654cc4/dotnet-sdk-2.1.522-linux-arm64.tar.gz
[dotnet-sdk-linux-musl-x64.tar.gz]: https://download.visualstudio.microsoft.com/download/pr/a1c8c424-6d09-4deb-8eda-89d1a536934b/569900f0de06228873c62aca04383e29/dotnet-sdk-2.1.522-linux-musl-x64.tar.gz
[dotnet-sdk-linux-x64.tar.gz]: https://download.visualstudio.microsoft.com/download/pr/ea7e9a50-a8df-4c62-96fe-0c7edf4d7d81/d616e0c64dad68f58cde43736d299678/dotnet-sdk-2.1.522-linux-x64.tar.gz
[dotnet-sdk-osx-x64.pkg]: https://download.visualstudio.microsoft.com/download/pr/bfaecd11-bc61-4c69-8f73-3aad45a5e377/7d21d24fd4ebc6c3015e5622a1d5ec8d/dotnet-sdk-2.1.522-osx-x64.pkg
[dotnet-sdk-osx-x64.tar.gz]: https://download.visualstudio.microsoft.com/download/pr/82695746-f2c9-46dd-a1ad-c006ce4d5a5f/fae2794dba35300089b1f0de6af539b4/dotnet-sdk-2.1.522-osx-x64.tar.gz
[dotnet-sdk-win-x64.exe]: https://download.visualstudio.microsoft.com/download/pr/5be98caf-d5d4-4d30-b8f5-66c1884e675c/68ba4c84aeb489254044ec0e0ad1f852/dotnet-sdk-2.1.522-win-x64.exe
[dotnet-sdk-win-x64.zip]: https://download.visualstudio.microsoft.com/download/pr/c9e64b62-bfdf-441d-b46e-45479d108bcf/77dfd390cc524054edef8639efd5c943/dotnet-sdk-2.1.522-win-x64.zip
[dotnet-sdk-win-x86.exe]: https://download.visualstudio.microsoft.com/download/pr/4dd88832-b055-47ef-bc31-581d0c801e59/589f0bb7d0216ea7ef7e566caa84c7d5/dotnet-sdk-2.1.522-win-x86.exe
[dotnet-sdk-win-x86.zip]: https://download.visualstudio.microsoft.com/download/pr/fcd7ebff-b816-4725-9a00-5bc8c406f23f/6063f32be0b7d295db08f72bcc864639/dotnet-sdk-2.1.522-win-x86.zip


text:
package models

import (
	"fmt"

	"github.com/alexhokl/helper/datetime"
	"github.com/fatih/color"
)

// PrintID prints ID of a pull request
func (pr PullRequestDetail) PrintID() {
	fmt.Printf("%d\n", pr.ID)
}

// PrintShortDescription prints a short description of the specified pull request
func (pr PullRequestDetail) PrintShortDescription(isIncludeCreatedOn bool) {
	pr.PrintOneLiner()

	if isIncludeCreatedOn {
		color.New(color.FgGreen).Printf("\tCreated:%s\n", datetime.GetLocalDateTimeString(&pr.UpdatedOn))
	}

	color.New(color.FgMagenta).Printf("\t%s",
		pr.Source.Branch.Name)
	fmt.Printf(" -> ")
	color.New(color.FgYellow).Printf("%s\n",
		pr.Destination.Branch.Name)

	approveStr := ""
	for _, reviewer := range pr.Participants {
		if reviewer.Approved {
			approveStr = fmt.Sprintf("%s\n\tApproved by %s", approveStr, reviewer.User.DisplayName)
		}
	}
	if approveStr != "" {
		color.New(color.FgBlue).Println(approveStr)
	}
	fmt.Println("---")
}

// PrintOneLiner prints a short description of the specified pull request
func (pr PullRequestDetail) PrintOneLiner() {
	fmt.Printf("%d", pr.ID)
	color.New(color.FgGreen).Printf(" Updated:%s", datetime.GetLocalDateTimeString(&pr.UpdatedOn))
	color.New(color.FgCyan).Printf(" %s", pr.Author.DisplayName)
	fmt.Printf(" %s\n", pr.Title)
}

// PrintDescription prints description of the specified pull request
func (pr PullRequestDetail) PrintDescription() {
	fmt.Printf("Description:\n%s\n", pr.Description)
}

// ToString returns the description of a comment
func (c Comment) ToString() string {
	return fmt.Sprintf(
		"Comment by %s (%s): %s",
		c.User.DisplayName,
		datetime.GetLocalDateTimeString(&c.UpdatedOn),
		c.Content.Raw)
}

// ToString returns the description of an update
func (c Update) ToString() string {
	return fmt.Sprintf(
		"Commit made by %s (%s): %s",
		c.Author.DisplayName,
		datetime.GetLocalDateTimeString(&c.Date),
		c.Source.Commit.Hash)
}

redpajama_set_name: RedPajamaGithub


text:
""" Definition for RHEAS Datasets decorators.

.. module:: datasets.decorators
   :synopsis: Definition of the Datasets decorators

.. moduleauthor:: Kostas Andreadis <kandread@jpl.nasa.gov>

"""

from functools import wraps
import tempfile
import shutil
import urllib
from datetime import datetime
from ftplib import FTP
import re
from pydap.client import open_url
import netCDF4 as netcdf4
import numpy as np
from osgeo import gdal
import datasets

def resetDatetime(dt):
    """Set time to 00:00 to align with daily data."""
    return datetime(dt.year, dt.month, dt.day, 0, 0)

def path(fetch):
    """Decorator for getting files from local path."""
    @wraps(fetch)
    def wrapper(*args, **kwargs):
        url, bbox, dt = fetch(*args, **kwargs)
        outpath = tempfile.mkdtemp()
        filename = url.format(dt.year, dt.month, dt.day)
        try:
            shutil.copy(filename, outpath)
            lfilename = filename.split("/")[-1]
        except:
            lfilename = None
        return outpath, lfilename, bbox, dt
    return wrapper

def http(fetch):
    """Decorator for downloading files from HTTP sites."""
    @wraps(fetch)
    def wrapper(*args, **kwargs):
        url, bbox, dt = fetch(*args, **kwargs)
        outpath = tempfile.mkdtemp()
        filename = url.format(dt.year, dt.month, dt.day)
        try:
            lfilename = filename.split("/")[-1]
            urllib.urlcleanup()
            urllib.urlretrieve(filename, "{0}/{1}".format(outpath, lfilename))
        except:
            lfilename = None
        return outpath, lfilename, bbox, dt
    return wrapper

def ftp(fetch):
    """Decorator for downloading files from FTP sites."""
    @wraps(fetch)
    def wrapper(*args, **kwargs):
        url, bbox, dt = fetch(*args, **kwargs)
        ftpurl = url.split("/")[2]
        outpath = tempfile.mkdtemp()
        try:
            conn = FTP(ftpurl)
            conn.login()
            conn.cwd("/".join(url.split("/")[3:-1]).format(dt.year, dt.month, dt.day))
            name = url.split("/")[-1].format(dt.year, dt.month, dt.day)
            filenames = [f for f in conn.nlst() if re.match(r".*{0}.*".format(name), f) is not None]
            if len(filenames) > 0:
                filename = filenames[0]
                with open("{0}/{1}".format(outpath, filename), 'wb') as f:
                    conn.retrbinary("RETR {0}".format(filename), f.write)
                filenames.append("{0}/{1}".format(outpath, filename))
            else:
                filename = None
        except:
            filename = None
        return outpath, filename, bbox, dt
    return wrapper

def opendap(fetch):
    """Decorator for fetching data from Opendap servers."""
    @wraps(fetch)
    def wrapper(*args, **kwargs):
        url, varname, bbox, dt = fetch(*args, **kwargs)
        ds = open_url(url)
        for var in ds.keys():
            if var.lower().startswith("lon") or var.lower() == "x":
                lonvar = var
            if var.lower().startswith("lat") or var.lower() == "y":
                latvar = var
            if var.lower().startswith("time") or var.lower() == "t":
                timevar = var
        lat = ds[latvar][:].data
        lon = ds[lonvar][:].data
        lon[lon > 180] -= 360
        res = abs(lat[0]-lat[1])  # assume rectangular grid
        i1, i2, j1, j2 = datasets.spatialSubset(np.sort(lat)[::-1], np.sort(lon), res, bbox)
        t = ds[timevar]
        tt = netcdf4.num2date(t[:].data, units=t.units)
        ti = [tj for tj in range(len(tt)) if resetDatetime(tt[tj]) >= dt[0] and resetDatetime(tt[tj]) <= dt[1]]
        if len(ti) > 0:
            lati = np.argsort(lat)[::-1][i1:i2]
            loni = np.argsort(lon)[j1:j2]
            if len(ds[varname].data[0].shape) > 3:
                data = ds[varname].data[0][ti[0]:ti[-1]+1, 0, lati[0]:lati[-1]+1, loni[0]:loni[-1]+1]
            else:
                data = ds[varname].data[0][ti[0]:ti[-1]+1, 0, lati[0]:lati[-1]+1, loni[0]:loni[-1]+1]
            dt = tt[ti]
        else:
            data = None
            dt = None
        lat = np.sort(lat)[::-1][i1:i2]
        lon = np.sort(lon)[j1:j2]
        return data, lat, lon, dt
    return wrapper

def netcdf(fetch):
    """Decorator for fetching NetCDF files (local or from Opendap servers)."""
    @wraps(fetch)
    def wrapper(*args, **kwargs):
        url, varname, bbox, dt = fetch(*args, **kwargs)
        ds = netcdf4.Dataset(url)
        for var in ds.variables:
            if var.lower().startswith("lon") or var.lower() == "x":
                lonvar = var
            if var.lower().startswith("lat") or var.lower() == "y":
                latvar = var
            if var.lower().startswith("time") or var.lower() == "t":
                timevar = var
        lat = ds.variables[latvar][:]
        lon = ds.variables[lonvar][:]
        lon[lon > 180] -= 360
        res = abs(lat[0]-lat[1])  # assume rectangular grid
        i1, i2, j1, j2 = datasets.spatialSubset(np.sort(lat)[::-1], np.sort(lon), res, bbox)
        t = ds.variables[timevar]
        tt = netcdf4.num2date(t[:], units=t.units)
        ti = [tj for tj in range(len(tt)) if resetDatetime(tt[tj]) >= dt[0] and resetDatetime(tt[tj]) <= dt[1]]
        if len(ti) > 0:
            lati = np.argsort(lat)[::-1][i1:i2]
            loni = np.argsort(lon)[j1:j2]
            if len(ds.variables[varname].shape) > 3:
                data = ds.variables[varname][ti, 0, lati, loni]
            else:
                data = ds.variables[varname][ti, lati, loni]
            dt = tt[ti]
        else:
            data = None
            dt = None
        lat = np.sort(lat)[::-1][i1:i2]
        lon = np.sort(lon)[j1:j2]
        return data, lat, lon, dt
    return wrapper

def geotiff(fetch):
    """Decorator for reading data from raster files."""
    @wraps(fetch)
    def wrapper(*args, **kwargs):
        outpath, filename, bbox, dt = fetch(*args, **kwargs)
        if filename is not None:
            lfilename = datasets.uncompress(filename, outpath)
            f = gdal.Open("{0}/{1}".format(outpath, lfilename))
            xul, xres, _, yul, _, yres = f.GetGeoTransform()
            data = f.ReadAsArray()
            nr, nc = data.shape
            lat = np.arange(yul + yres/2.0, yul + yres * nr, yres)
            lon = np.arange(xul + xres/2.0, xul + xres * nc, xres)
            i1, i2, j1, j2 = datasets.spatialSubset(lat, lon, xres, bbox)
            data = data[i1:i2, j1:j2]
            lat = lat[i1:i2]
            lon = lon[j1:j2]
            shutil.rmtree(outpath)
        else:
            data = lat = lon = None
        return data, lat, lon, dt
    return wrapper


text:
package client;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import drawable.Drawable;
import drawable.Turtle;

public class DrawableSet {
	private Map<Integer, Drawable> myObjs;
	private List<Integer> myActive;

	private DrawingBoard myBoard;

	private static Drawable getNewDrawable(DrawingBoard board) {
		return new Turtle(board);
	}

	public DrawableSet(DrawingBoard board) {
		myBoard = board;
		myObjs = new HashMap<>();
		myActive = new ArrayList<>();
	}

	public DrawableSet(DrawingBoard board, Map<Integer, Drawable> objs) {
		myBoard = board;
		myObjs = objs;
		myActive = (List<Integer>) objs.keySet();
	}

	public void makeFirst() {
		myActive.add(1);
		myObjs.put(1, getNewDrawable(myBoard));
		myObjs.get(1).draw();
	}

	public List<Drawable> setActive(List<Integer> actives) {
		myActive = actives;

		List<Drawable> toReturn = new ArrayList<>();
		for(int i : myActive) {
			if (!myObjs.containsKey(i)) {
				myObjs.put(i, getNewDrawable(myBoard));
				myObjs.get(i).draw();
			}
			else {
				toReturn.add(myObjs.get(i));
			}
		}
		return toReturn;
	}

	public Drawable get(int i) {
		if (myObjs.containsKey(i)) {
			return myObjs.get(i);
		}
		else {
			return null;
		}
	}

	public List<Integer> getActiveInt() {
		return myActive;
	}

	public List<Drawable> getActiveObjs() {
		List<Drawable> toReturn = new ArrayList<>();
		for (int i : myActive) {
			toReturn.add(myObjs.get(i));
		}
		return toReturn;
	}

	public Drawable getLastActive() {
		int last = myActive.get(myActive.size() - 1);
		return myObjs.get(last);
	}

	public List<Drawable> getAll() {
		return new ArrayList<>(myObjs.values());
	}

	public int getIndex(Drawable obj) {
		for (int i: myObjs.keySet()) {
			if (myObjs.get(i).equals(obj)) {
				return i;
			}
		}
		return -1;
	}
}


text:
package de.mrapp.android.dialog.decorator;

import android.content.DialogInterface;
import android.content.res.ColorStateList;
import android.graphics.Typeface;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.Button;

import java.util.Collections;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

import androidx.annotation.ColorInt;
import androidx.annotation.LayoutRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
import de.mrapp.android.dialog.R;
import de.mrapp.android.dialog.ScrollableArea.Area;
import de.mrapp.android.dialog.listener.OnClickListenerWrapper;
import de.mrapp.android.dialog.model.ValidateableDialog;
import de.mrapp.android.dialog.view.DialogRootView.AreaViewType;
import de.mrapp.android.dialog.view.DialogRootView.DividerLocation;
import de.mrapp.android.dialog.view.DialogRootView.DividerViewType;
import de.mrapp.android.dialog.view.DialogRootView.ViewType;
import de.mrapp.android.dialog.view.Divider;
import de.mrapp.util.Condition;

/**
 * A decorator, which allows to modify the view hierarchy of a dialog, which is designed according
 * to Android 5's Material design guidelines even on pre-Lollipop devices and may contain up to
 * three buttons.
 *
 * @author Michael Rapp
 * @since 3.2.0
 */
public class ButtonBarDialogDecorator extends AbstractDialogDecorator<ValidateableDialog>
        implements de.mrapp.android.dialog.model.ButtonBarDialogDecorator {

    /**
     * The name of the extra, which is used to store, whether the dialog's buttons should be
     * stacked, or not, within a bundle.
     */
    private static final String STACK_BUTTONS_EXTRA =
            ButtonBarDialogDecorator.class.getSimpleName() + "::stackButtons";

    /**
     * The name of the extra, which is used to store the text color of the dialog's buttons within a
     * bundle.
     */
    private static final String BUTTON_TEXT_COLOR_EXTRA =
            ButtonBarDialogDecorator.class.getSimpleName() + "::buttonTextColor";

    /**
     * The name of the extra, which is used to store, whether the divider, which is shown above the
     * dialog's buttons, should be shown, or not, within a bundle.
     */
    private static final String SHOW_BUTTON_BAR_DIVIDER_EXTRA =
            ButtonBarDialogDecorator.class.getSimpleName() + "::showButtonBarDivider";

    /**
     * The name of the extra, which is used to store the text of the positive button within a
     * bundle.
     */
    private static final String POSITIVE_BUTTON_TEXT_EXTRA =
            ButtonBarDialogDecorator.class.getSimpleName() + "::positiveButtonText";

    /**
     * The name of the extra, which is used to store the text of the neutral button within a
     * bundle.
     */
    private static final String NEUTRAL_BUTTON_TEXT_EXTRA =
            ButtonBarDialogDecorator.class.getSimpleName() + "::neutralButtonText";

    /**
     * The name of the extra, which is used to store the text of the negative button within a
     * bundle.
     */
    private static final String NEGATIVE_BUTTON_TEXT_EXTRA =
            ButtonBarDialogDecorator.class.getSimpleName() + "::negativeButtonText";

    /**
     * The parent view of the layout, which is used to show the dialog's buttons.
     */
    private ViewGroup buttonBarContainer;

    /**
     * The positive button of the dialog.
     */
    private Button positiveButton;

    /**
     * The negative button of the dialog.
     */
    private Button negativeButton;

    /**
     * The neutral button of the dialog.
     */
    private Button neutralButton;

    /**
     * The divider, which is shown above the dialog's buttons.
     */
    private Divider buttonBarDivider;

    /**
     * The text color of the dialog's buttons.
     */
    private ColorStateList buttonTextColor;

    /**
     * The typeface of the dialog's buttons.
     */
    private Typeface buttonTypeface;

    /**
     * True, if the buttons of the dialog are aligned vertically, false otherwise.
     */
    private boolean stackButtons;

    /**
     * The text of the negative button of the dialog.
     */
    private CharSequence negativeButtonText;

    /**
     * The text of the neutral button of the dialog.
     */
    private CharSequence neutralButtonText;

    /**
     * The text of the positive button of the dialog.
     */
    private CharSequence positiveButtonText;

    /**
     * The listener, which is notified, when the negative button of the dialog, is clicked.
     */
    private DialogInterface.OnClickListener negativeButtonListener;

    /**
     * The listener, which is notified, when the neutral button of the dialog, is clicked.
     */
    private DialogInterface.OnClickListener neutralButtonListener;

    /**
     * The listener, which is notified, when the positive button of the dialog, is clicked.
     */
    private DialogInterface.OnClickListener positiveButtonListener;

    /**
     * True, if the divider, which is located above the dialog's buttons, is shown, false
     * otherwise.
     */
    private boolean showButtonBarDivider;

    /**
     * The resource id of the custom button bar of the dialog.
     */
    private int customButtonBarViewId = -1;

    /**
     * The custom button bar of the dialog.
     */
    private View customButtonBarView;

    /**
     * Inflates the layout, which is used to show the dialog's buttons.
     *
     * @return The view, which has been inflated, as an instance of the class {@link View} or null,
     * if no view has been inflated
     */
    private View inflateButtonBar() {
        if (getRootView() != null) {
            if (buttonBarContainer == null) {
                LayoutInflater layoutInflater = LayoutInflater.from(getContext());
                buttonBarContainer = (ViewGroup) layoutInflater
                        .inflate(R.layout.button_bar_container, getRootView(), false);
                buttonBarDivider = buttonBarContainer.findViewById(R.id.button_bar_divider);
            }

            if (buttonBarContainer.getChildCount() > 1) {
                buttonBarContainer.removeViewAt(1);
            }

            if (customButtonBarView != null) {
                buttonBarContainer.addView(customButtonBarView);
            } else if (customButtonBarViewId != -1) {
                LayoutInflater layoutInflater = LayoutInflater.from(getContext());
                View view =
                        layoutInflater.inflate(customButtonBarViewId, buttonBarContainer, false);
                buttonBarContainer.addView(view);
            } else {
                LayoutInflater layoutInflater = LayoutInflater.from(getContext());
                View view = layoutInflater.inflate(
                        stackButtons ? R.layout.stacked_button_bar : R.layout.horizontal_button_bar,
                        buttonBarContainer, false);
                buttonBarContainer.addView(view);
            }

            View positiveButtonView = buttonBarContainer.findViewById(android.R.id.button1);
            View negativeButtonView = buttonBarContainer.findViewById(android.R.id.button2);
            View neutralButtonView = buttonBarContainer.findViewById(android.R.id.button3);
            positiveButton =
                    positiveButtonView instanceof Button ? (Button) positiveButtonView : null;
            negativeButton =
                    negativeButtonView instanceof Button ? (Button) negativeButtonView : null;
            neutralButton = neutralButtonView instanceof Button ? (Button) neutralButtonView : null;
            return buttonBarContainer;
        }

        return null;
    }

    /**
     * Adapts the button bar.
     */
    private void adaptButtonBar() {
        if (buttonBarContainer != null) {
            inflateButtonBar();
            adaptPositiveButton();
            adaptNegativeButton();
            adaptNeutralButton();
            adaptButtonTextColor();
            adaptButtonTypeface();
            adaptButtonBarContainerVisibility();
            adaptButtonBarDividerVisibility();
        }
    }

    /**
     * Adapts the text color of the dialog's buttons.
     */
    private void adaptButtonTextColor() {
        if (buttonTextColor != null) {
            if (positiveButton != null) {
                positiveButton.setTextColor(buttonTextColor);
            }

            if (neutralButton != null) {
                neutralButton.setTextColor(buttonTextColor);
            }

            if (negativeButton != null) {
                negativeButton.setTextColor(buttonTextColor);
            }
        }
    }

    /**
     * Adapts the typeface of the dialog's buttons.
     */
    private void adaptButtonTypeface() {
        if (buttonTypeface != null) {
            if (positiveButton != null) {
                positiveButton.setTypeface(buttonTypeface);
            }

            if (neutralButton != null) {
                neutralButton.setTypeface(buttonTypeface);
            }

            if (negativeButton != null) {
                negativeButton.setTypeface(buttonTypeface);
            }
        }
    }

    /**
     * Adapts the dialog's positive button.
     */
    private void adaptPositiveButton() {
        if (positiveButton != null) {
            positiveButton.setText(positiveButtonText != null ?
                    positiveButtonText.toString().toUpperCase(Locale.getDefault()) : null);
            OnClickListenerWrapper onClickListener =
                    new OnClickListenerWrapper(positiveButtonListener, true, getDialog(),
                            DialogInterface.BUTTON_POSITIVE);
            positiveButton.setOnClickListener(onClickListener);
            positiveButton.setVisibility(
                    !TextUtils.isEmpty(positiveButtonText) ? View.VISIBLE : View.GONE);
            adaptButtonBarContainerVisibility();
        }
    }

    /**
     * Adapts the dialog's neutral button.
     */
    private void adaptNeutralButton() {
        if (neutralButton != null) {
            neutralButton.setText(neutralButtonText != null ?
                    neutralButtonText.toString().toUpperCase(Locale.getDefault()) : null);
            OnClickListenerWrapper onClickListener =
                    new OnClickListenerWrapper(neutralButtonListener, false, getDialog(),
                            DialogInterface.BUTTON_NEUTRAL);
            neutralButton.setOnClickListener(onClickListener);
            neutralButton.setVisibility(
                    !TextUtils.isEmpty(neutralButtonText) ? View.VISIBLE : View.GONE);
            adaptButtonBarContainerVisibility();
        }
    }

    /**
     * Adapts the dialog's negative button.
     */
    private void adaptNegativeButton() {
        if (negativeButton != null) {
            negativeButton.setText(negativeButtonText != null ?
                    negativeButtonText.toString().toUpperCase(Locale.getDefault()) : null);
            OnClickListenerWrapper onClickListener =
                    new OnClickListenerWrapper(negativeButtonListener, false, getDialog(),
                            DialogInterface.BUTTON_NEGATIVE);
            negativeButton.setOnClickListener(onClickListener);
            negativeButton.setVisibility(
                    !TextUtils.isEmpty(negativeButtonText) ? View.VISIBLE : View.GONE);
            adaptButtonBarContainerVisibility();
        }
    }

    /**
     * Adapts the visibility of the parent view, which contains the dialog's buttons.
     */
    private void adaptButtonBarContainerVisibility() {
        if (buttonBarContainer != null) {
            if (TextUtils.isEmpty(positiveButtonText) && TextUtils.isEmpty(neutralButtonText) &&
                    TextUtils.isEmpty(negativeButtonText)) {
                buttonBarContainer.setVisibility(View.GONE);
            } else {
                buttonBarContainer.setVisibility(View.VISIBLE);
            }
        }
    }

    /**
     * Adapts the visibility of the divider, which is shown above the dialog's buttons.
     */
    private void adaptButtonBarDividerVisibility() {
        if (buttonBarDivider != null) {
            buttonBarDivider.setVisibility(showButtonBarDivider ? View.VISIBLE : View.GONE);
            buttonBarDivider.setVisibleByDefault(showButtonBarDivider);
        }
    }

    /**
     * Creates a new decorator, which allows to modify the view hierarchy of a dialog, which is
     * designed according to Android 5's Material design guidelines even on pre-Lollipop devices and
     * may contain up to three buttons.
     *
     * @param dialog
     *         The dialog, whose view hierarchy should be modified by the decorator, as an instance
     *         of the type {@link ValidateableDialog}. The dialog may not be null
     */
    public ButtonBarDialogDecorator(@NonNull final ValidateableDialog dialog) {
        super(dialog);
    }

    @Override
    public final Button getButton(final int whichButton) {
        switch (whichButton) {
            case DialogInterface.BUTTON_POSITIVE:
                return (positiveButton != null && positiveButton.getVisibility() == View.VISIBLE) ?
                        positiveButton : null;
            case DialogInterface.BUTTON_NEGATIVE:
                return (negativeButton != null && negativeButton.getVisibility() == View.VISIBLE) ?
                        negativeButton : null;
            case DialogInterface.BUTTON_NEUTRAL:
                return (neutralButton != null && neutralButton.getVisibility() == View.VISIBLE) ?
                        neutralButton : null;
            default:
                return null;
        }
    }

    @Override
    public final void setPositiveButton(@Nullable final CharSequence text,
                                        @Nullable final DialogInterface.OnClickListener listener) {
        positiveButtonText = text;
        positiveButtonListener = listener;
        adaptPositiveButton();
    }

    @Override
    public final void setPositiveButton(@StringRes final int resourceId,
                                        @Nullable final DialogInterface.OnClickListener listener) {
        setPositiveButton(getContext().getText(resourceId), listener);
    }

    @Override
    public final void setNegativeButton(@Nullable final CharSequence text,
                                        @Nullable final DialogInterface.OnClickListener listener) {
        negativeButtonText = text;
        negativeButtonListener = listener;
        adaptNegativeButton();
    }

    @Override
    public final void setNegativeButton(@StringRes final int resourceId,
                                        @Nullable final DialogInterface.OnClickListener listener) {
        setNegativeButton(getContext().getText(resourceId), listener);
    }

    @Override
    public final void setNeutralButton(@Nullable final CharSequence text,
                                       @Nullable final DialogInterface.OnClickListener listener) {
        neutralButtonText = text;
        neutralButtonListener = listener;
        adaptNeutralButton();
    }

    @Override
    public final void setNeutralButton(@StringRes final int resourceId,
                                       @Nullable final DialogInterface.OnClickListener listener) {
        setNeutralButton(getContext().getText(resourceId), listener);
    }

    @Override
    public final boolean areButtonsStacked() {
        return stackButtons;
    }

    @Override
    public final void stackButtons(final boolean stackButtons) {
        this.stackButtons = stackButtons;
        adaptButtonBar();
    }

    @Nullable
    @Override
    public final ColorStateList getButtonTextColor() {
        return buttonTextColor;
    }

    @Override
    public final void setButtonTextColor(@ColorInt final int color) {
        setButtonTextColor(ColorStateList.valueOf(color));
    }

    @Override
    public final void setButtonTextColor(@NonNull final ColorStateList colorStateList) {
        Condition.INSTANCE.ensureNotNull(colorStateList, "The color state list may not be null");
        buttonTextColor = colorStateList;
        adaptButtonTextColor();
    }

    @Nullable
    @Override
    public final Typeface getButtonTypeface() {
        return buttonTypeface;
    }

    @Override
    public final void setButtonTypeface(@NonNull final Typeface typeface) {
        Condition.INSTANCE.ensureNotNull(typeface, "The typeface may not be null");
        buttonTypeface = typeface;
        adaptButtonTypeface();
    }

    @Override
    public final boolean isButtonBarDividerShown() {
        return showButtonBarDivider;
    }

    @Override
    public final void showButtonBarDivider(final boolean show) {
        this.showButtonBarDivider = show;
        adaptButtonBarDividerVisibility();
    }

    @Override
    public final boolean isCustomButtonBarUsed() {
        return customButtonBarView != null || customButtonBarViewId != -1;
    }

    @Override
    public final void setCustomButtonBar(@LayoutRes final int resourceId) {
        customButtonBarView = null;
        customButtonBarViewId = resourceId;
        adaptButtonBar();
    }

    @Override
    public final void setCustomButtonBar(@Nullable final View view) {
        customButtonBarView = view;
        customButtonBarViewId = -1;
        adaptButtonBar();
    }

    @Override
    public final void onSaveInstanceState(@NonNull final Bundle outState) {
        outState.putBoolean(STACK_BUTTONS_EXTRA, areButtonsStacked());
        outState.putParcelable(BUTTON_TEXT_COLOR_EXTRA, getButtonTextColor());
        outState.putBoolean(SHOW_BUTTON_BAR_DIVIDER_EXTRA, isButtonBarDividerShown());
        outState.putCharSequence(POSITIVE_BUTTON_TEXT_EXTRA, positiveButtonText);
        outState.putCharSequence(NEUTRAL_BUTTON_TEXT_EXTRA, neutralButtonText);
        outState.putCharSequence(NEGATIVE_BUTTON_TEXT_EXTRA, negativeButtonText);
    }

    @Override
    public final void onRestoreInstanceState(@NonNull final Bundle savedInstanceState) {
        stackButtons(savedInstanceState.getBoolean(STACK_BUTTONS_EXTRA));
        showButtonBarDivider(savedInstanceState.getBoolean(SHOW_BUTTON_BAR_DIVIDER_EXTRA));
        setPositiveButton(savedInstanceState.getCharSequence(POSITIVE_BUTTON_TEXT_EXTRA),
                positiveButtonListener);
        setNeutralButton(savedInstanceState.getCharSequence(NEUTRAL_BUTTON_TEXT_EXTRA),
                neutralButtonListener);
        setNegativeButton(savedInstanceState.getCharSequence(NEGATIVE_BUTTON_TEXT_EXTRA),
                negativeButtonListener);
        ColorStateList buttonTextColor = savedInstanceState.getParcelable(BUTTON_TEXT_COLOR_EXTRA);

        if (buttonTextColor != null) {
            setButtonTextColor(buttonTextColor);
        }
    }

    @NonNull
    @Override
    protected final Map<ViewType, View> onAttach(@NonNull final Window window,
                                                 @NonNull final View view,
                                                 @NonNull final Map<ViewType, View> areas,
                                                 final Void param) {
        View inflatedView = inflateButtonBar();

        if (inflatedView != null) {
            adaptButtonTextColor();
            adaptButtonTypeface();
            adaptPositiveButton();
            adaptNeutralButton();
            adaptNegativeButton();
            adaptButtonBarDividerVisibility();
            Map<ViewType, View> result = new HashMap<>();
            result.put(new AreaViewType(Area.BUTTON_BAR), buttonBarContainer);
            result.put(new DividerViewType(DividerLocation.BOTTOM), buttonBarDivider);
            return result;
        }

        return Collections.emptyMap();
    }

    @Override
    protected final void onDetach() {
        if (buttonBarContainer != null) {
            buttonBarContainer.removeAllViews();
            buttonBarContainer = null;
        }

        positiveButton = null;
        negativeButton = null;
        neutralButton = null;
        buttonBarDivider = null;
    }

}


text:
package kieker.tools.common;

import kieker.common.exception.ConfigurationException;

import teetime.framework.Configuration;
import teetime.framework.Execution;

/**
 * Abstract class to create runnable teetime services.
 *
 * @param <T>
 *            a Teetime configuration
 *
 * @author Reiner Jung
 *
 * @since 1.15
 */
public abstract class AbstractEmbeddableService<T extends Configuration> implements Runnable {

	private Execution<T> execution;

	/**
	 * Default constructor.
	 */
	public AbstractEmbeddableService() {
		// nothing to be done here
	}

	@Override
	public final void run() {
		try {
			this.execution = new Execution<>(this.createTeetimeConfiguration());
			this.execution.executeBlocking();
			this.shutdownService();
		} catch (final ConfigurationException e) {
			this.logError(e);
		}
	}

	/**
	 * Terminate a running service.
	 */
	public final void terminate() {
		if (this.execution != null) {
			this.execution.abortEventually();
		}
	}

	/**
	 * Log exceptions to the UI.
	 *
	 * @param e
	 *            configuration exception
	 */
	protected abstract void logError(ConfigurationException e);

	/**
	 * Trigger cleanup features of the service.
	 */
	protected abstract void shutdownService();

	/**
	 * Create and initialize teetime configuration for a service.
	 *
	 * @return return the newly created service
	 *
	 * @throws ConfigurationException
	 *             in case the creation fails
	 */
	protected abstract T createTeetimeConfiguration()
			throws ConfigurationException;

}


text:
package org.webdsl.querylist;

import java.util.Iterator;
import java.util.List;

public interface QueryList<T extends Comparable<Object>> {

	public abstract void addFilter(Filter filter);

	public abstract List<T> list();

	public abstract void add(T o);

	public abstract boolean contains(T o);

	public abstract T get(int index);

	public abstract Iterator<T> iterator();

	public abstract boolean remove(T o);

	public abstract int size();

	public abstract Object[] toArray();

}


text:
package org.osgi.impl.service.upnp.cp.event;

import org.osgi.impl.service.upnp.cp.util.UPnPListener;

public class Subscription {
	private String				subscriptionId;
	private String				publisherpath;
	private long				expiryTime;
	private String				time;
	boolean						active			= false;
	private UPnPListener		listener;
	private String				host;
	private int					eventKey		= 0;
	boolean						initialEvent	= true;
	private boolean				infinite		= false;
	boolean						waiting			= false;

	// Constructor which is used for intializing all the variables.
	public Subscription(String subscriptionId, String publisherpath, long t,
			String time, UPnPListener listener, String host) {
		this.subscriptionId = subscriptionId;
		this.publisherpath = publisherpath;
		this.expiryTime = t;
		this.time = time;
		this.listener = listener;
		this.host = host;
	}

	// Returns the publisher path
	String getPublisherPath() {
		return publisherpath;
	}

	// Returns the service id.
	synchronized String getSubscriptionId() {
		return subscriptionId;
	}

	// Returns timer associated with this subscription
	synchronized long getExpirytime() {
		return expiryTime;
	}

	// Returns the timeout value assigned for this subscription
	public String getTimeout() {
		return time;
	}

	// This method is used to activate this subscription object
	void setActive(boolean res) {
		active = res;
	}

	// Returns true if this subsctiption object is a valid one else returns
	// false.
	boolean getActive() {
		return active;
	}

	// Returns the host variable
	String getHost() {
		return host;
	}

	// Returns the UPnP Listener object
	UPnPListener getListener() {
		return listener;
	}

	// Sets the timeout variable to a new value
	void setTimeout(String timeout) {
		time = timeout;
	}

	// Sets the timer with new timer obejct
	void setExpirytime(long expirytime) {
		expiryTime = expirytime;
	}

	// Removes the listener from this subsctiption object
	void removeListener() {
		listener = null;
	}

	// Returns the event key
	int getEventkey() {
		return eventKey;
	}

	// Returns the event key
	void setEventkey(int key) {
		eventKey = key;
	}

	// Returns the event key
	boolean getInitialEvent() {
		return initialEvent;
	}

	// Returns the event key
	void setInitialEvent(boolean res) {
		initialEvent = res;
	}

	void setInfinite(boolean value) {
		infinite = value;
	}

	synchronized boolean getInfinite() {
		return infinite;
	}

	synchronized boolean waiting() {
		return waiting;
	}

	synchronized void setWaiting(boolean waiting) {
		this.waiting = waiting;
	}
}


text:
(function () {
          var r = new Flow({
            target: '/dashboard/upload',
            chunkSize: 1024*1024,
            testChunks: false
          });
          // Flow.js isn't supported, fall back on a different method
          if (!r.support) {
            $('.flow-error').show();
            return ;
          }
          // Show a place for dropping/selecting files
          $('.flow-drop').show();
          r.assignDrop($('.flow-drop')[0]);
          r.assignBrowse($('.flow-browse')[0]);
          r.assignBrowse($('.flow-browse-folder')[0], true);
          r.assignBrowse($('.flow-browse-image')[0], false, false, {accept: 'image/*'});
          // Handle file add event
          r.on('fileAdded', function(file){
            // Show progress bar
            $('.flow-progress, .flow-list').show();
            // Add the file to the list
            $('.flow-list').append(
              '
' +
              'Uploading  ' +
              ' ' +
              ' ' +
              '' +
              'Download' +
              ' ' +
              '' +
              ' ' +
              '' +
              '' +
              ' ' +
              '' +
              '' +
              ' ' +
              ''
            );
            var $self = $('.flow-file-'+file.uniqueIdentifier);
            $self.find('.flow-file-name').text(file.name);
            $self.find('.flow-file-size').text(readablizeBytes(file.size));
            $self.find('.flow-file-download').attr('href', '/download/' + file.uniqueIdentifier).hide();
            $self.find('.flow-file-pause').on('click', function () {
              file.pause();
              $self.find('.flow-file-pause').hide();
              $self.find('.flow-file-resume').show();
            });
            $self.find('.flow-file-resume').on('click', function () {
              file.resume();
              $self.find('.flow-file-pause').show();
              $self.find('.flow-file-resume').hide();
            });
            $self.find('.flow-file-cancel').on('click', function () {
              file.cancel();
              $self.remove();
            });
          });
          r.on('filesSubmitted', function(file) {
            r.upload();
          });
          r.on('complete', function(){
            // Hide pause/resume when the upload has completed
            $('.flow-progress .progress-resume-link, .flow-progress .progress-pause-link').hide();
          });
          r.on('fileSuccess', function(file,message){
            var $self = $('.flow-file-'+file.uniqueIdentifier);
            // Reflect that the file upload has completed
            $self.find('.flow-file-progress').text('(completed)');
            $self.find('.flow-file-pause, .flow-file-resume').remove();
            $self.find('.flow-file-download').attr('href', '/download/' + file.uniqueIdentifier).show();
          });
          r.on('fileError', function(file, message){
            // Reflect that the file upload has resulted in error
            $('.flow-file-'+file.uniqueIdentifier+' .flow-file-progress').html('(file could not be uploaded: '+message+')');
          });
          r.on('fileProgress', function(file){
            // Handle progress for both the file and the overall upload
            $('.flow-file-'+file.uniqueIdentifier+' .flow-file-progress')
              .html(Math.floor(file.progress()*100) + '% '
                + readablizeBytes(file.averageSpeed) + '/s '
                + secondsToStr(file.timeRemaining()) + ' remaining') ;
            $('.progress-bar').css({width:Math.floor(r.progress()*100) + '%'});
          });
          r.on('uploadStart', function(){
            // Show pause, hide resume
            $('.flow-progress .progress-resume-link').hide();
            $('.flow-progress .progress-pause-link').show();
          });
          r.on('catchAll', function() {
            console.log.apply(console, arguments);
          });
          window.r = {
            pause: function () {
              r.pause();
              // Show resume, hide pause
              $('.flow-file-resume').show();
              $('.flow-file-pause').hide();
              $('.flow-progress .progress-resume-link').show();
              $('.flow-progress .progress-pause-link').hide();
            },
            cancel: function() {
              r.cancel();
              $('.flow-file').remove();
            },
            upload: function() {
              $('.flow-file-pause').show();
              $('.flow-file-resume').hide();
              r.resume();
            },
            flow: r
          };
        })();
        function readablizeBytes(bytes) {
          var s = ['bytes', 'kB', 'MB', 'GB', 'TB', 'PB'];
          var e = Math.floor(Math.log(bytes) / Math.log(1024));
          return (bytes / Math.pow(1024, e)).toFixed(2) + " " + s[e];
        }
        function secondsToStr (temp) {
          function numberEnding (number) {
            return (number > 1) ? 's' : '';
          }
          var years = Math.floor(temp / 31536000);
          if (years) {
            return years + ' year' + numberEnding(years);
          }
          var days = Math.floor((temp %= 31536000) / 86400);
          if (days) {
            return days + ' day' + numberEnding(days);
          }
          var hours = Math.floor((temp %= 86400) / 3600);
          if (hours) {
            return hours + ' hour' + numberEnding(hours);
          }
          var minutes = Math.floor((temp %= 3600) / 60);
          if (minutes) {
            return minutes + ' minute' + numberEnding(minutes);
          }
          var seconds = temp % 60;
          return seconds + ' second' + numberEnding(seconds);
        }


text:
`User Configuration` is a way of specifying the options passed to the component at run-time.  The configuration object will be stored as a (possibly nested) dictionary within the component's config, at `config["User Configuration"]`.  These data are used instead of command line arguments to allow the user to send complex/nested data structures as configuration to the component, allow multiple component (instance) within a process to be configured with different values for the same parameter, and to save developer time by automatically parsing these data into usable structures.  For example, given the following config:
```
{
  "logSensorData": true,
  "logPeriod": 0.1,
  "logFields": {
    "time": "float",
    "data": "int"
  }
  "sensorOffsets": [
    0.1,
    0.2,
    0.3
  ]
}
```
  The user could access the configuration structure using the following `c++` code anywhere within the component:
```
bool logData = config["User Configuration"]["logSensorData"].asBool();
float period = config["User Configuration"]["logPeriod"].asFloat();
std::string firstField = config["User Configuration"]["logFields"]["time"].asString();
std::string secondField = config["User Configuration"]["logFields"]["data"].asString();
float firstOffset = config["User Configuration"]["sensorOffsets"][0].asFloat();
float secondOffset = config["User Configuration"]["sensorOffsets"][1].asFloat();
```
  The documentation for the generated objects can be found at [jsoncpp](http://open-source-parsers.github.io/jsoncpp-docs/doxygen/), which is the library used to parse the `JSON`.


text:
<!doctype html>

    <title>Code coverage report for src/features/</title>
    <meta charset="utf-8" />
    <link rel="stylesheet" href="../../prettify.css" />
    <link rel="stylesheet" href="../../base.css" />
    <meta name="viewport" content="width=device-width, initial-scale=1">

      all files src/features/

        0%
        Statements
        0/119

        0%
        Branches
        0/30

        0%
        Functions
        0/13

        0%
        Lines
        0/116

   File

   Statements

   Branches

   Functions

   Lines

	completion-provider.ts

	0%
	0/34
	0%
	0/18
	0%
	0/2
	0%
	0/33

	document-symbol-provider.ts

	0%
	0/14
	100%
	0/0
	0%
	0/1
	0%
	0/14

	hover-provider.ts

	0%
	0/7
	0%
	0/2
	0%
	0/1
	0%
	0/7

	linter-provider.ts

	0%
	0/64
	0%
	0/10
	0%
	0/9
	0%
	0/62

  Code coverage
  generated by istanbul at Mon Aug 28 2017 10:15:52 GMT+0100 (BST)


text:
/*
 * DurableClient QuickStart Example.
 *
 * This is to use newly added listener callback "afterRegionLive"
 * It merely prints the events captured from the Geode Native Client.
 *
 */

// Include the Geode library.
#include <geode/GeodeCppCache.hpp>
#include <geode/CacheListener.hpp>

// Use the "geode" namespace.
using namespace apache::geode::client;

// The SimpleCacheListener class.
class DurableCacheListener : public CacheListener {
 public:
  // The regionLiveCallback. This get called once all the queued events are
  // recieved by client on reconnect.
  virtual void afterRegionLive(const RegionEvent& event);
  virtual void afterCreate(const EntryEvent& event);
  virtual void afterUpdate(const EntryEvent& event);
};


text:
package org.marketcetera.event.impl;

import java.math.BigDecimal;
import java.util.Date;

import javax.annotation.concurrent.ThreadSafe;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;

import org.marketcetera.event.*;
import org.marketcetera.event.beans.HasEventBean;
import org.marketcetera.event.beans.ImbalanceBean;
import org.marketcetera.event.util.EventServices;
import org.marketcetera.trade.Instrument;
import org.marketcetera.util.misc.ClassVersion;

/* $License$ */

/**
 * Provides an implementation for {@link ImbalanceEvent}.
 *
 * @author Colin DuPlantis
 * @version $Id$
 * @since $Release$
 */
@ThreadSafe
@XmlAccessorType(XmlAccessType.NONE)
@ClassVersion("$Id$")
abstract class AbstractImbalanceEvent
        implements ImbalanceEvent, HasEventBean
{
    /* (non-Javadoc)
     * @see org.marketcetera.event.Event#getMessageId()
     */
    @Override
    public long getMessageId()
    {
        return imbalance.getMessageId();
    }
    /* (non-Javadoc)
     * @see org.marketcetera.event.Event#getTimestamp()
     */
    @Override
    public Date getTimestamp()
    {
        return imbalance.getTimestamp();
    }
    /* (non-Javadoc)
     * @see org.marketcetera.event.Event#getSource()
     */
    @Override
    public Object getSource()
    {
        return imbalance.getSource();
    }
    /* (non-Javadoc)
     * @see org.marketcetera.event.Event#setSource(java.lang.Object)
     */
    @Override
    public void setSource(Object inSource)
    {
        imbalance.setSource(inSource);
    }
    /* (non-Javadoc)
     * @see org.marketcetera.event.Event#getProvider()
     */
    @Override
    public String getProvider()
    {
        return imbalance.getProvider();
    }
    /* (non-Javadoc)
     * @see org.marketcetera.event.Event#setProvider(java.lang.String)
     */
    @Override
    public void setProvider(String inProvider)
    {
        imbalance.setProvider(inProvider);
    }
    /* (non-Javadoc)
     * @see org.marketcetera.event.TimestampCarrier#getTimeMillis()
     */
    @Override
    public long getTimeMillis()
    {
        return imbalance.getTimeMillis();
    }
    /* (non-Javadoc)
     * @see org.marketcetera.event.HasEventType#getEventType()
     */
    @Override
    public EventType getEventType()
    {
        return imbalance.getEventType();
    }
    /* (non-Javadoc)
     * @see org.marketcetera.event.HasEventType#setEventType(org.marketcetera.event.EventType)
     */
    @Override
    public void setEventType(EventType inEventType)
    {
        imbalance.setEventType(inEventType);
    }
    /* (non-Javadoc)
     * @see org.marketcetera.event.HasInstrument#getInstrument()
     */
    @Override
    public Instrument getInstrument()
    {
        return imbalance.getInstrument();
    }
    /* (non-Javadoc)
     * @see org.marketcetera.event.HasInstrument#getInstrumentAsString()
     */
    @Override
    public String getInstrumentAsString()
    {
        return imbalance.getInstrumentAsString();
    }
    /* (non-Javadoc)
     * @see org.marketcetera.event.beans.HasEventBean#getEventBean()
     */
    @Override
    public ImbalanceBean getEventBean()
    {
        return imbalance;
    }
    /* (non-Javadoc)
     * @see org.marketcetera.event.ImbalanceEvent#getAuctionType()
     */
    @Override
    public AuctionType getAuctionType()
    {
        return imbalance.getAuctionType();
    }
    /* (non-Javadoc)
     * @see org.marketcetera.event.ImbalanceEvent#getExchange()
     */
    @Override
    public String getExchange()
    {
        return imbalance.getExchange();
    }
    /* (non-Javadoc)
     * @see org.marketcetera.event.ImbalanceEvent#getFarPrice()
     */
    @Override
    public BigDecimal getFarPrice()
    {
        return imbalance.getFarPrice();
    }
    /* (non-Javadoc)
     * @see org.marketcetera.event.ImbalanceEvent#getImbalanceVolume()
     */
    @Override
    public BigDecimal getImbalanceVolume()
    {
        return imbalance.getImbalanceVolume();
    }
    /* (non-Javadoc)
     * @see org.marketcetera.event.ImbalanceEvent#getInstrumentStatus()
     */
    @Override
    public InstrumentStatus getInstrumentStatus()
    {
        return imbalance.getInstrumentStatus();
    }
    /* (non-Javadoc)
     * @see org.marketcetera.event.ImbalanceEvent#getImbalanceus()
     */
    @Override
    public MarketStatus getMarketStatus()
    {
        return imbalance.getMarketStatus();
    }
    /* (non-Javadoc)
     * @see org.marketcetera.event.ImbalanceEvent#getNearPrice()
     */
    @Override
    public BigDecimal getNearPrice()
    {
        return imbalance.getNearPrice();
    }
    /* (non-Javadoc)
     * @see org.marketcetera.event.ImbalanceEvent#getPairedVolume()
     */
    @Override
    public BigDecimal getPairedVolume()
    {
        return imbalance.getPairedVolume();
    }
    /* (non-Javadoc)
     * @see org.marketcetera.event.ImbalanceEvent#getReferencePrice()
     */
    @Override
    public BigDecimal getReferencePrice()
    {
        return imbalance.getReferencePrice();
    }
    /* (non-Javadoc)
     * @see org.marketcetera.event.ImbalanceEvent#getImbalanceType()
     */
    @Override
    public ImbalanceType getImbalanceType()
    {
        return imbalance.getImbalanceType();
    }
    /* (non-Javadoc)
     * @see org.marketcetera.event.ImbalanceEvent#isShortSaleRestricted()
     */
    @Override
    public boolean isShortSaleRestricted()
    {
        return imbalance.getShortSaleRestricted();
    }
    /* (non-Javadoc)
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString()
    {
        StringBuilder builder = new StringBuilder();
        builder.append("Imbalance for ").append(imbalance.getInstrument().getFullSymbol()).append(" [").append(imbalance.getEventType()).append("] ")
            .append(" auction: ").append(imbalance.getAuctionType()).append(" on exchange ").append(imbalance.getExchange()).append(" instrument status: ").append(imbalance.getInstrumentStatus())
            .append(" market status: ").append(imbalance.getMarketStatus()).append(" at ").append(imbalance.getTimestamp());
        return builder.toString();
    }
    /* (non-Javadoc)
     * @see java.lang.Object#hashCode()
     */
    @Override
    public final int hashCode()
    {
        return EventServices.eventHashCode(this);
    }
    /* (non-Javadoc)
     * @see java.lang.Object#equals(java.lang.Object)
     */
    @Override
    public final boolean equals(Object obj)
    {
        return EventServices.eventEquals(this,
                                         obj);
    }
    /**
     * Create a new AbstractImbalanceEventImpl instance.
     *
     * @param inImbalanceBean a ImbalanceBean value
     * @throws IllegalArgumentException if MessageId < 0
     * @throws IllegalArgumentException if Timestamp is null
     * @throws IllegalArgumentException if Instrument is null
     */
    protected AbstractImbalanceEvent(ImbalanceBean inImbalance)
    {
        imbalance = ImbalanceBean.copy(inImbalance);
        imbalance.setDefaults();
        imbalance.validate();
    }
    /**
     * Create a new AbstractImbalanceEventImpl instance.
     *
     *
This constructor is intended to be used by JAXB only.
     */
    protected AbstractImbalanceEvent()
    {
        imbalance = new ImbalanceBean();
    }
    /**
     * imbalance value
     */
    @XmlElement
    private final ImbalanceBean imbalance;
    private static final long serialVersionUID = 981566862437586058L;
}


text:
package org.reveno.atp.metrics.meter;

import org.reveno.atp.core.api.Destroyable;

public interface Histogram extends Sinkable, Destroyable {

    Histogram update(long value);

    boolean isReady();

}


text:
__git_command_successful () {
    if (( ${#pipestatus:#0} > 0 )); then
	_message 'not a git repository'
	return 1
    fi
    return 0
}

__git_tag_names() {
    local expl
    declare -a tag_names
    tag_names=(${${(f)"$(_call_program branchrefs git for-each-ref --format='"%(refname)"' refs/tags 2>/dev/null)"}#refs/tags/})
    __git_command_successful || return
    _wanted tag-names expl tag-name compadd $* - $tag_names
}

__git_branch_names() {
    local expl
    declare -a branch_names
    branch_names=(${${(f)"$(_call_program branchrefs git for-each-ref --format='"%(refname)"' refs/heads 2>/dev/null)"}#refs/heads/})
    __git_command_successful || return
    _wanted branch-names expl branch-name compadd $* - $branch_names
}

__git_feature_branch_names() {
    local expl
    declare -a branch_names
    branch_names=(${${(f)"$(_call_program branchrefs git for-each-ref --format='"%(refname)"' refs/heads/feature 2>/dev/null)"}#refs/heads/feature/})
    __git_command_successful || return
    _wanted branch-names expl branch-name compadd $* - $branch_names
}

__git_refactor_branch_names() {
    local expl
    declare -a branch_names
    branch_names=(${${(f)"$(_call_program branchrefs git for-each-ref --format='"%(refname)"' refs/heads/refactor 2>/dev/null)"}#refs/heads/refactor/})
    __git_command_successful || return
    _wanted branch-names expl branch-name compadd $* - $branch_names
}

__git_bug_branch_names() {
    local expl
    declare -a branch_names
    branch_names=(${${(f)"$(_call_program branchrefs git for-each-ref --format='"%(refname)"' refs/heads/bug 2>/dev/null)"}#refs/heads/bug/})
    __git_command_successful || return
    _wanted branch-names expl branch-name compadd $* - $branch_names
}

__git_submodule_names() {
    local expl
    declare -a submodule_names
    submodule_names=(${(f)"$(_call_program branchrefs git submodule status | awk '{print $2}')"})
    __git_command_successful || return
    _wanted submodule-names expl submodule-name compadd $* - $submodule_names
}

__git_author_names() {
    local expl
    declare -a author_names
    author_names=(${(f)"$(_call_program branchrefs git log --format='%aN' | sort -u)"})
    __git_command_successful || return
    _wanted author-names expl author-name compadd $* - $author_names
}

_git-changelog() {
    _arguments \
	'(-l --list)'{-l,--list}'[list commits]' \
}

_git-effort() {
    _arguments \
	'--above[ignore file with less than x commits]' \
}

_git-contrib() {
    _arguments \
	':author:__git_author_names'
}

_git-count() {
    _arguments \
	'--all[detailed commit count]'
}

_git-delete-branch() {
    _arguments \
	':branch-name:__git_branch_names'
}

_git-delete-submodule() {
    _arguments \
	':submodule-name:__git_submodule_names'
}

_git-delete-tag() {
    _arguments \
	':tag-name:__git_tag_names'
}

_git-extras() {
    local curcontext=$curcontext state line ret=1
    declare -A opt_args

    _arguments -C \
	': :->command' \
	'*:: :->option-or-argument' && ret=0

    case $state in
	(command)
	    declare -a commands
	    commands=(
		'update:update git-extras'
	    )
	    _describe -t commands command commands && ret=0
	    ;;
    esac

    _arguments \
	'(-v --version)'{-v,--version}'[show current version]' \
}

_git-graft() {
    _arguments \
	':src-branch-name:__git_branch_names' \
	':dest-branch-name:__git_branch_names'
}

_git-squash() {
    _arguments \
	':branch-name:__git_branch_names'
}

_git-feature() {
    local curcontext=$curcontext state line ret=1
    declare -A opt_args

    _arguments -C \
	': :->command' \
	'*:: :->option-or-argument' && ret=0

    case $state in
	(command)
	    declare -a commands
	    commands=(
		'finish:merge feature into the current branch'
	    )
	    _describe -t commands command commands && ret=0
	    ;;
	(option-or-argument)
	    curcontext=${curcontext%:*}-$line[1]:
	    case $line[1] in
		(finish)
		    _arguments -C \
			':branch-name:__git_feature_branch_names'
		    ;;
	    esac
    esac
}

_git-refactor() {
    local curcontext=$curcontext state line ret=1
    declare -A opt_args

    _arguments -C \
	': :->command' \
	'*:: :->option-or-argument' && ret=0

    case $state in
	(command)
	    declare -a commands
	    commands=(
		'finish:merge refactor into the current branch'
	    )
	    _describe -t commands command commands && ret=0
	    ;;
	(option-or-argument)
	    curcontext=${curcontext%:*}-$line[1]:
	    case $line[1] in
		(finish)
		    _arguments -C \
			':branch-name:__git_refactor_branch_names'
		    ;;
	    esac
    esac
}

_git-bug() {
    local curcontext=$curcontext state line ret=1
    declare -A opt_args

    _arguments -C \
	': :->command' \
	'*:: :->option-or-argument' && ret=0

    case $state in
	(command)
	    declare -a commands
	    commands=(
		'finish:merge bug into the current branch'
	    )
	    _describe -t commands command commands && ret=0
	    ;;
	(option-or-argument)
	    curcontext=${curcontext%:*}-$line[1]:
	    case $line[1] in
		(finish)
		    _arguments -C \
			':branch-name:__git_bug_branch_names'
		    ;;
	    esac
    esac
}

zstyle ':completion:*:*:git:*' user-commands \
    changelog:'populate changelog file with commits since the previous tag' \
    contrib:'display author contributions' \
    count:'count commits' \
    delete-branch:'delete local and remote branch' \
    delete-submodule:'delete submodule' \
    delete-tag:'delete local and remote tag' \
    extras:'git-extras' \
    graft:'merge commits from source branch to destination branch' \
    squash:'merge commits from source branch into the current one as a single commit' \
    feature:'create a feature branch' \
    refactor:'create a refactor branch' \
    bug:'create a bug branch' \
    summary:'repository summary' \
    effort:'display effort statistics' \
    repl:'read-eval-print-loop' \
    commits-since:'list commits since a given date' \
    release:'release commit with the given tag' \
    alias:'define, search and show aliases' \
    ignore:'add patterns to .gitignore' \
    info:'show info about the repository' \
    create-branch:'create local and remote branch' \
    fresh-branch:'create empty local branch' \
    undo:'remove the latest commit' \
    setup:'setup a git repository' \
    touch:'one step creation of new files' \
    obliterate:'Completely remove a file from the repository, including past commits and tags' \
    local-commits:'list unpushed commits on the local branch' \


text:
require "spec_helper"

RSpec.describe KigoConnector::Property do

  context "V1 API" do
    describe "#list_properties" do

      it "returns a list of properties" do
        VCR.use_cassette("list_properties_v1") do
          properties = KigoConnector::Property.list
          expect(properties.size).to be > 0
        end
      end
    end

    describe "#info" do

      context "for an existing/accesible property" do

        it "returns info for a property" do
          VCR.use_cassette("property_info_v1") do
            property = KigoConnector::Property.new(id: 62637)
            expect(property.info["PROP_NAME"]).to eq "B34.2.3 | Sky Terrace Güell III"
          end
        end
      end

      context "for a non existing/accesible property" do

        it "raises ApiCallError" do
          VCR.use_cassette("property_info_v1") do
            property = KigoConnector::Property.new(id: 999999999999)
            expect { property.info["PROP_NAME"].to raise_exception KigoConnector::ApiCallError }
          end
        end

      end
    end

    describe "#real_time_pricing_calculation" do

      it "returns price info" do
        VCR.use_cassette("real_time_pricing_v1", match_requests_on: [:method, :uri]) do
          property = KigoConnector::Property.new(id: 62637)
          price_info = property.real_time_pricing_calculaton(check_in: "2015-07-28", check_out: "2015-07-31", guests: 4)
          expect(price_info["TOTAL_AMOUNT"]).to eq "515.64"
        end
      end

    end

    describe "#periods" do

      it "returns period rates' info" do
        VCR.use_cassette("property_pricing_setup_v1") do
          property = KigoConnector::Property.new(id: 62637)
          expect(property.periods.size).to eq 36
        end
      end

    end
  end

  context "V2 API" do

    describe "#list_properties" do

      it "returns a list of properties" do
        VCR.use_cassette("list_properties_v2") do
          properties = KigoConnector::Property.list(api_version: "2")
          expect(properties.size).to be > 0
        end
      end

    end

    describe "#info" do

      context "for an existing/accesible property" do

        it "returns info for a property" do
          VCR.use_cassette("property_info_v2") do
            property = KigoConnector::Property.new(id: 155091, api_version: "2")
            expect(property.info["PROP_NAME"]).to eq "The Lofts at Park Crest  (2 BR)"
          end
        end

      end

      context "for a non existing/accesible property" do

        it "raises ApiCallError" do
          VCR.use_cassette("property_info_v2") do
            property = KigoConnector::Property.new(id: 62637, api_version: "2")
            expect { property.info["PROP_NAME"].to raise_exception KigoConnector::ApiCallError }
          end
        end
      end
    end

    describe "#real_time_pricing_calculation" do

      it "returns price info" do
        VCR.use_cassette("real_time_pricing_v2", match_requests_on: [:method, :uri]) do
          property = KigoConnector::Property.new(id: 155091, api_version: "2")
          price_info = property.real_time_pricing_calculaton(check_in: "2015-08-28", check_out: "2015-08-31", guests: 4)
          expect(price_info["TOTAL_AMOUNT"]).to eq "1766.74"
        end
      end

    end

    describe "#periods" do

      it "returns period rates' info" do
        VCR.use_cassette("property_pricing_setup_v2") do
          property = KigoConnector::Property.new(id: 155091, api_version: "2")
          expect(property.periods.size).to eq 5
        end
      end

    end
  end

end