text:
@implementation AGSError

+ (NSError *)noConnectionNameFound
{
    return [self errorWithCode:AGSErrorCodeNoConnectionNameFound
                   description:AGSValidatorLocalized(@"Authentication failed")
                 failureReason:AGSValidatorLocalized(@"Can't find connection name to use for authentication")];
}

+ (NSError *)notConnectedToInternetError
{
    return [self errorWithCode:AGSErrorCodeNotConnectedToInternet
                   description:AGSValidatorLocalized(@"The server could not be contacted")
                 failureReason:AGSValidatorLocalized(@"Make sure your network settings are correct and your network connection is active, or try again later.")];
}

#pragma mark - Login errors

+ (NSError *)defaultLoginErrorFor:(NSError *)error
{
    return [self errorWithCode:AGSAuthenticationFailed
                   description:AGSValidatorLocalized(@"There was an error logging in")
                 failureReason:nil];
}

+ (NSError *)invalidLoginCredentials:(AGSUsernameType)usernameType
{
    NSString *failureReason;
    if (usernameType == AGSUsernameTypeEmail) {
        failureReason = AGSValidatorLocalized(@"The email and password you entered are invalid. Please try again.");
    }
    else if (usernameType == AGSUsernameTypeUsername) {
        failureReason = AGSValidatorLocalized(@"The username and password you entered are invalid. Please try again.");
    }
    else {
       failureReason = AGSValidatorLocalized(@"The phone number and password you entered are invalid. Please try again.");
    }

    return [self errorWithCode:AGSErrorCodeInvalidCredentials
                   description:AGSValidatorLocalized(@"Invalid login credentials")
                 failureReason:failureReason];
}

+ (NSError *)invalidLoginUsername:(AGSUsernameType)usernameType
{
    NSString *failureReason;
    if (usernameType == AGSUsernameTypeEmail) {
        failureReason = AGSValidatorLocalized(@"The email you entered is invalid. Please try again.");
    }
    else if (usernameType == AGSUsernameTypeUsername) {
        failureReason = AGSValidatorLocalized(@"The username you entered is invalid. Please try again.");
    }
    else {
        failureReason = AGSValidatorLocalized(@"The phone number you entered is invalid. Please try again.");
    }

    return [self errorWithCode:AGSErrorCodeInvalidUsername
                   description:AGSValidatorLocalized(@"Invalid login credentials")
                 failureReason:failureReason];
}

+ (NSError *)invalidLoginPassword
{
    return [self errorWithCode:AGSErrorCodeInvalidPassword
                   description:AGSValidatorLocalized(@"Invalid login credentials")
                 failureReason:AGSValidatorLocalized(@"The password you entered is invalid. Please try again.")];
}

#pragma mark - SignUp errors

+ (NSError *)invalidSignUpCredentials:(AGSUsernameType)usernameType
{
    NSString *failureReason;
    if (usernameType == AGSUsernameTypeEmail) {
        failureReason = AGSValidatorLocalized(@"The email and password you entered are invalid. Please try again.");
    }
    else if (usernameType == AGSUsernameTypeUsername) {
        failureReason = AGSValidatorLocalized(@"The username and password you entered are invalid. Please try again.");
    }
    else {
       failureReason = AGSValidatorLocalized(@"The phone number and password you entered are invalid. Please try again.");
    }

    return [self errorWithCode:AGSErrorCodeInvalidCredentials
                   description:AGSValidatorLocalized(@"Invalid credentials")
                 failureReason:failureReason];
}

+ (NSError *)invalidSignUpUsername:(AGSUsernameType)usernameType
{
    NSString *failureReason;
    if (usernameType == AGSUsernameTypeEmail) {
        failureReason = AGSValidatorLocalized(@"The email you entered is invalid. Please try again.");
    }
    else if (usernameType == AGSUsernameTypeUsername) {
        failureReason = AGSValidatorLocalized(@"The username you entered is invalid. Please try again.");
    }
    else {
       failureReason = AGSValidatorLocalized(@"The phone number you entered is invalid. Please try again.");
    }

    return [self errorWithCode:AGSErrorCodeInvalidUsername
                   description:AGSValidatorLocalized(@"Invalid credentials")
                 failureReason:failureReason];
}

+ (NSError *)invalidSignUpPassword
{
    return [self errorWithCode:AGSErrorCodeInvalidPassword
                   description:AGSValidatorLocalized(@"Invalid credentials")
                 failureReason:AGSValidatorLocalized(@"The password you entered is invalid. Please try again.")];
}

#pragma mark - Change password errors

+ (NSError *)invalidChangePasswordCredentials:(AGSUsernameType)usernameType
{
    NSString *failureReason;
    if (usernameType == AGSUsernameTypeEmail) {
        failureReason = AGSValidatorLocalized(@"The email and password you entered are invalid. Please try again.");
    }
    else if (usernameType == AGSUsernameTypeUsername) {
        failureReason = AGSValidatorLocalized(@"The username and password you entered are invalid. Please try again.");
    }
    else {
       failureReason = AGSValidatorLocalized(@"The phone number and password you entered are invalid. Please try again.");
    }

    return [self errorWithCode:AGSErrorCodeInvalidCredentials
                   description:AGSValidatorLocalized(@"Invalid credentials")
                 failureReason:failureReason];
}

+ (NSError *)invalidChangePasswordUsername:(AGSUsernameType)usernameType
{
    NSString *failureReason;
    if (usernameType == AGSUsernameTypeEmail) {
        failureReason = AGSValidatorLocalized(@"The email you entered is invalid. Please try again.");
    }
    else if (usernameType == AGSUsernameTypeUsername) {
        failureReason = AGSValidatorLocalized(@"The username you entered is invalid. Please try again.");
    }
    else {
        failureReason = AGSValidatorLocalized(@"The phone number you entered is invalid. Please try again.");
    }

    return [self errorWithCode:AGSErrorCodeInvalidUsername
                   description:AGSValidatorLocalized(@"Invalid credentials")
                 failureReason:failureReason];
}

+ (NSError *)invalidChangePasswordPassword
{
    return [self errorWithCode:AGSErrorCodeInvalidPassword
                   description:AGSValidatorLocalized(@"Invalid credentials")
                 failureReason:AGSValidatorLocalized(@"The password you entered is invalid. Please try again.")];
}

+ (NSError *)invalidChangePasswordRepeatPassword
{
    return [self errorWithCode:AGSErrorCodeInvalidRepeatPassword
                   description:AGSValidatorLocalized(@"Invalid credentials")
                 failureReason:AGSValidatorLocalized(@"The passwords you entered must match. Please try again.")];
}

+ (NSError *)invalidChangePasswordRepeatPasswordAndPassword
{
    return [self errorWithCode:AGSErrorCodeInvalidPasswordAndRepeatPassword
                   description:AGSValidatorLocalized(@"Invalid credentials")
                 failureReason:AGSValidatorLocalized(@"The passwords you entered must match. Please try again.")];
}

#pragma mark - Social Errors

+ (NSError *)unkownProviderForStrategy:(NSString *)strategyName
{
    return [self errorWithCode:AGSErrorCodeUknownProviderForStrategy
                   description:AGSValidatorLocalized(@"Couldn't found authentication method for unknown strategy")
                 failureReason:[NSString stringWithFormat:AGSValidatorLocalized(@"The strategy %@ has no registered authentication provider"), strategyName]];
}

+ (NSError *)facebookCancelled
{
    return [self errorWithCode:AGSErrorCodeFacebookCancelled
                   description:AGSValidatorLocalized(@"There was an error contacting Facebook")
                 failureReason:AGSValidatorLocalized(@"You need to authorize the application")];
}

+ (NSError *)twitterAppNotAuthorized
{
    return [self errorWithCode:AGSErrorCodeTwitterAppNotAuthorized
                   description:AGSValidatorLocalized(@"There was an error contacting Twitter")
                 failureReason:AGSValidatorLocalized(@"Permissions were not granted. Please authorize the app in Settings > Twitter")];
}

+ (NSError *)twitterAppOauthNotAuthorized
{
    return [self errorWithCode:AGSErrorCodeTwitterAppNotAuthorized
                   description:AGSValidatorLocalized(@"There was an error contacting Twitter")
                 failureReason:AGSValidatorLocalized(@"Permissions were not granted. Try again")];
}

+ (NSError *)twitterCancelled
{
    return [self errorWithCode:AGSErrorCodeTwitterCancelled
                   description:AGSValidatorLocalized(@"There was an error contacting Twitter")
                 failureReason:AGSValidatorLocalized(@"User cancelled the login operation. Try again")];
}

+ (NSError *)twitterNotConfigured
{
    return [self errorWithCode:AGSErrorCodeTwitterNotConfigured
                   description:AGSValidatorLocalized(@"There was an error contacting Twitter")
                 failureReason:AGSValidatorLocalized(@"The domain has not been setup for Twitter.")];
}

+ (NSError *)twitterInvalidAccount
{
    return [self errorWithCode:AGSErrorCodeTwitterInvalidAccount
                   description:AGSValidatorLocalized(@"There was an error contacting Twitter")
                 failureReason:AGSValidatorLocalized(@"The twitter account seems to be invalid. Please check it in Settings > Twitter and re-enter them.")];
}

+ (NSError *)googleplusFailed
{
    return [self errorWithCode:AGSErrorCodeGooglePlusFailed
                   description:AGSValidatorLocalized(@"There was an error contacting Google+")
                 failureReason:AGSValidatorLocalized(@"Permissions were not granted. Try again")];
}

#pragma mark - Utility methods

+ (NSError *)errorWithCode:(NSInteger)code description:(NSString *)description failureReason:(NSString *)failureReason
{
    NSError *error = [NSError errorWithDomain:ERROR_DOMAIN
                                         code:code
                                     userInfo:@{
                                                NSLocalizedDescriptionKey: description,
                                                NSLocalizedFailureReasonErrorKey: failureReason,
                                                }];
    return error;
}

@end


text:
/****** HACKS ******/
#embed_npwlo                { display: none; }

/****** INTERFACE ******/
div._MA           { width: 100%; height: 100%; position: relative; min-width: 0px; min-height: 0px; }
div._TO           { position: absolute; z-index: 100; width: 100% }
div._BM           { position: absolute; z-index: 100; width: 100%; bottom: 0 }
div._PS           { position: absolute; z-index: 1; overflow-y: hidden; overflow-x: hidden }
div._PG           { position: absolute; width:100%; height:100%; overflow-y: hidden; overflow-x: hidden }
div._CO           { position: absolute; top: 0px; left: 0px; right: 0px; bottom: 0px; }
div._NJ           { }
._BO              { position: absolute; overflow: hidden; }
div._OB           { position: absolute; overflow: hidden; top: 0px; left: 0px; }
div._IB           { position: absolute; overflow: scroll; top: 0px; left: 0px; }
div._VB           { position: absolute; top: 0px; right: 0px }
div._HB           { position: absolute; left: 0px; bottom: 0px }

div._WB           { /* wrapable */ }
div._US           { -moz-user-select: none; -webkit-user-select: none; -ms-user-select: none; user-select: none; }
input._IT         { border: 0px; background: none; margin: -5px; padding: 5px; width: 100%; }
div._IC           { position: absolute; overflow: hidden; width: 100%; }
input::-ms-clear  { display: none; }

redpajama_set_name: RedPajamaGithub


text: Angular element directive for an old-fashion timer


text:
.draggable-container {
	min-height: 300px;
}

#newcreated,
#tokenattribute,
#csvattribute,
#centralattribute {
    margin-left: 0.75%;
    margin-right: 0.75%;
    margin-bottom: 20px;
}

#tokenattribute {
    margin-left: 1.5%;
}

#centralattribute {
    margin-right: 1.5%;
}

#centralattribute .centralatt {
    padding-bottom: 15px;
}

#newcreated  .attribute-item input {
	display: block;
	margin: 2px auto;
	width: 80%;
}

#centralattribute div.centralatt div.token-attribute {
	margin-top: -5px;
	min-height: 20px;
}

#newcreated,
#tokenattribute {
    height: 100%;
}

.heading{
    height: auto;
    padding-top: 7px;
    font-weight: bold;
}

div.mappable-attribute-wrapper {
	width : 80%;
	margin: 6px auto;
	padding:6px;
}

div.attribute-item, .already-mapped-attribute {
	width : 80%;
	margin: 6px auto;
	padding:4px;
	text-align:center;
}

#centralattribute .explanation {
	width:90%;
	margin: 0 auto;
	text-align: left;
}

#centralattribute .explanation-row {
	display: table-row;
}

#centralattribute .explanation input,
#centralattribute .explanation label {
	display: table-cell;
	padding-top: 4px;
	padding-bottom: 4px;
}

#centralattribute .explanation label {
	padding-left: 8px;
}

.attribute-item.draggable {
	cursor: move;
}

div.mappable-attribute-wrapper.target-hover {
	padding-bottom: 27px;
}

div.mappable-attribute-wrapper.paired.target-hover {
	padding-bottom: 4px;
}

div.mappable-attribute-wrapper.paired.ui-state-disabled {
    opacity: 1;
	filter:alpha(opacity=100);
}

.draggable-container .attribute-column .ui-draggable-dragging {
    z-index: 100;
}

/* Existing attribute column in CSV CPDB import */
.centralatt {
    min-height: 100px;
}


text:
// ----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// ----------------------------------------------------------------------------

using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows.Media;

namespace Microsoft.Azure.Zumo.WindowsPhone8.CSharp.Test
{
    /// <summary>
    /// UI model for a test method.
    /// </summary>
    public class TestDescription : INotifyPropertyChanged
    {
        private string _name;

        public string Name
        {
            get { return _name; }
            set
            {
                _name = value;
                OnPropertyChanged();
            }
        }

        private Color _color;

        public Color Color
        {
            get { return _color; }
            set
            {
                _color = value;
                OnPropertyChanged();
                OnPropertyChanged("Brush");
            }
        }

        public SolidColorBrush Brush
        {
            get { return new SolidColorBrush(Color); }
        }

        public ObservableCollection<string> Details { get; private set; }

        public TestDescription()
        {
            Details = new ObservableCollection<string>();
            Color = Color.FromArgb(0xFF, 0xFF, 0xFF, 0xFF);
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected void OnPropertyChanged([CallerMemberName] string memberName = "")
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(memberName));
            }
        }
    }
}


text:
using System;

namespace Blockchain.Investments.Core.Domain
{
    public class Transaction
    {
        public JournalType Journal {get; set;}
        public Guid AccountAggregateId {get; set;}
        public string Tag {get;set;}
        public double Value {get; set;}
        public double Quantity {get;set;}
        public string LotId {get;set;}
    }
    public enum JournalType
    {
           Debit = 1,
           Credit = 2
    }
}


text:
START_ATF_NAMESPACE
    namespace std
    {
        template<>
        const struct  deque<RECV_DATA,allocator<RECV_DATA> > : _Deque_val<RECV_DATA,allocator<RECV_DATA> >
        {
            RECV_DATA **_Map;
            unsigned __int64 _Mapsize;
            unsigned __int64 _Myoff;
            unsigned __int64 _Mysize;
        };
        static_assert(ATF::checkSize<std::deque<RECV_DATA,std::allocator<RECV_DATA> >, 56>(), "std::deque<RECV_DATA,std::allocator<RECV_DATA> >");
    }; // end namespace std
END_ATF_NAMESPACE


text:
**Markdown Preview Enhanced** supports rendering `flow charts`, `sequence diagrams`, `mermaid`, `PlantUML`, `WaveDrom`, `GraphViz`, `Vega & Vega-lite`, `Ditaa` diagrams.
You can also render `TikZ`, `Python Matplotlib`, `Plotly` and all sorts of other graphs and diagrams by using [Code Chunk](code-chunk.md).

> Please note that some diagrams don't work well with file exports such as PDF, pandoc, etc.

## Flow Charts

This feature is powered by [flowchart.js](https://flowchart.js.org/).

- code block with `flow` notation will be rendered by [flowchart.js](https://flowchart.js.org/).

![screenshot from 2017-11-25 21-43-02](https://user-images.githubusercontent.com/1908863/33236942-aa809c1c-d229-11e7-9c4b-9a680fd852ed.png)

## Sequence Diagrams

This feature is powered by [js-sequence-diagrams](https://bramp.github.io/js-sequence-diagrams/).

- code block with `sequence` notation will be rendered by [js-sequence-diagrams](https://bramp.github.io/js-sequence-diagrams/).
- Two themes are supported: `simple`(default theme) and `hand`.

![screenshot from 2017-11-25 21-47-41](https://user-images.githubusercontent.com/1908863/33236972-4f190f98-d22a-11e7-842f-d9c4a74d2118.png)

## Mermaid

Markdown Preview Enhanced uses [mermaid](https://github.com/knsv/mermaid) to render flow charts and sequence diagram.

- code block with `mermaid` notation will be rendered by [mermaid](https://github.com/knsv/mermaid).
- check [mermaid doc](https://mermaid-js.github.io/mermaid) for more information about how to create flowchart and sequence diagram
  ![screen shot 2017-06-05 at 8 04 58 pm](https://cloud.githubusercontent.com/assets/1908863/26809423/42afb410-4a2a-11e7-8a18-57e7c67caa9f.png)

Three mermaid themes are provided, and you can choose theme from [package settings](usages.md?id=package-settings):

- `mermaid.css`
- `mermaid.dark.css`
- `mermaid.forest.css`
  ![screen shot 2017-06-05 at 8 47 00 pm](https://cloud.githubusercontent.com/assets/1908863/26810274/555562d0-4a30-11e7-91ca-98742d6afbd5.png)

You can also edit the mermaid init config by running `Markdown Preview Enhanced: Open Mermaid Config` command.

## PlantUML

Markdown Preview Enhanced uses [PlantUML](https://plantuml.com/) to create multiple kinds of graph. (**Java** is required to be installed)

- You can install [Graphviz](https://www.graphviz.org/) (not required) to generate all diagram types.
- Code block with `puml` or `plantuml` notation will be rendered by [PlantUML](https://plantuml.com/).

![screen shot 2017-06-05 at 8 05 55 pm](https://cloud.githubusercontent.com/assets/1908863/26809436/65414084-4a2a-11e7-91ee-7b03b0496513.png)

If `@start...` is not found, then `@startuml ... @enduml` will automatically be inserted.

## WaveDrom

Markdown Preview Enhanced uses [WaveDrom](https://wavedrom.com/) to create digital timing diagram.

- Code block with `wavedrom` notation will be rendered by [WaveDrom](https://github.com/drom/wavedrom).

![screen shot 2017-06-05 at 8 07 30 pm](https://cloud.githubusercontent.com/assets/1908863/26809462/9dc3eb96-4a2a-11e7-90e7-ad6bcb8dbdb1.png)

## GraphViz

Markdown Preview Enhanced uses [Viz.js](https://github.com/mdaines/viz.js) to render [dot language](https://tinyurl.com/kjoouup) diagram.

- Code block with `viz` or `dot` notation will be rendered by [Viz.js](https://github.com/mdaines/viz.js).
- You can choose different engines by specifying `{engine="..."}`. Engine `circo`, `dot`, `neato`, `osage`, or `twopi` are supported. Default engine is `dot`.

![screen shot 2018-03-18 at 3 18 17 pm](https://user-images.githubusercontent.com/1908863/37570596-a565306e-2abf-11e8-8904-d73306f675ec.png)

## Vega and Vega-lite

Markdown Preview Enhanced supports [vega](https://vega.github.io/vega/) and [vega-lite](https://vega.github.io/vega-lite/) **static** diagrams.

- Code block with `vega` notation will be rendered by [vega](https://vega.github.io/vega/).
- Code block with `vega-lite` notation will be rendered by [vega-lite](https://vega.github.io/vega-lite/).
- Both `JSON` and `YAML` inputs are supported.

![screen shot 2017-07-28 at 7 59 58 am](https://user-images.githubusercontent.com/1908863/28718265-d023e1c2-736a-11e7-8678-a29704f3a23c.png)

You can also [@import](file-imports.md) a `JSON` or `YAML` file as `vega` diagram, for example:

```markdown
@import "your_vega_source.json" {as="vega"}
@import "your_vega_lite_source.json" {as="vega-lite"}
```

## Ditaa

Markdown Preview Enhanced supports [ditaa](https://github.com/stathissideris/ditaa) that can convert diagrams drawn using ascii art ('drawings' that contain characters that resemble lines like | / - ), into proper bitmap graphics.

(**Java** is required to be installed)

`ditaa` is integrated with [code chunk](code-chunk.md), for example:

  ```ditaa {cmd=true args=["-E"]}
  +--------+   +-------+    +-------+
  |        | --+ ditaa +--> |       |
  |  Text  |   +-------+    |diagram|
  |Document|   |!magic!|    |       |
  |     {d}|   |       |    |       |
  +---+----+   +-------+    +-------+
      :                         ^
      |       Lots of work      |
      +-------------------------+
  ```

> shift-enter to run code chunk.
> set `{hide=true}` to hide code block.
> set `{run_on_save=true}` to render ditaa when you save the markdown file.

![screen shot 2017-07-28 at 8 11 15 am](https://user-images.githubusercontent.com/1908863/28718626-633fa18e-736c-11e7-8a4a-915858dafff6.png)

---

If you don't want to render graphs but only display code block, then you can add `{code_block=true}` like below:

    ```mermaid {code_block=true}
    // your mermaid code here
    ```

---

You can set attributes for the container of the diagram.
For example:

    ```puml {align="center"}
    a->b
    ```

will put the puml diagram at the center of preview.

---

When you export your markdown file to [GFM Markdown](markdown.md), the diagrams will be saved as png images to your `imageFolderPath` defined in package settings.
You can control the exported image filename by declaring `{filename="your_file_name.png"}`.

For example:

    ```mermaid {filename="my_mermaid.png"}
    ...
    ```

[➔ TOC](toc.md)


text:
package org.bitbucket.cowwoc.diffmatchpatch;

import java.util.LinkedList;

import org.bitbucket.cowwoc.diffmatchpatch.DiffMatchPatch.Diff;
import org.bitbucket.cowwoc.diffmatchpatch.DiffMatchPatch.LinesToCharsResult;

public class DiffMatchPatchWrapper {
    private static final DiffMatchPatch DIFF_MATCH_PATCH = new DiffMatchPatch();

    public static LinkedList<Diff> diffLinesOnly(String text1, String text2) {
        LinesToCharsResult linesAsChars = DIFF_MATCH_PATCH.diffLinesToChars(text1, text2);
        LinkedList<Diff> diffs = DIFF_MATCH_PATCH.diffMain(linesAsChars.chars1, linesAsChars.chars2, false);
        DIFF_MATCH_PATCH.diffCharsToLines(diffs, linesAsChars.lineArray);
        return diffs;
    }

    public static LinkedList<Diff> diffWithinLine(String text1, String text2) {
        LinkedList<Diff> diffs = DIFF_MATCH_PATCH.diffMain(text1, text2);
        DIFF_MATCH_PATCH.diffCleanupSemantic(diffs);
        return diffs;
    }
}


text:
{% import "WebPortfolio/macros/forms.html" as f with context %}
{% extends "WebPortfolio/Package/User/Account/_layout.html" %}

{% block login_content %}

{{ login_title | default('Signup')}}

                    <form method="POST" id="pilot-login-signup-form" action="{{url_for('UserAccount:signup')}}">
                        {{- f.csrf_field() -}}
                        <input type="hidden" name="next" value="{{ login_url_next }}">

                            Name:
                            <input type="text" required class="form-control"  name="name" placeholder="Enter Name">

                            Email:
                            <input type="email" required class="form-control"  name="email" placeholder="Enter email">

                            Password:
                            <input type="password" required class="form-control" name="password" placeholder="Password">

                            Confirm Password:
                            <input type="password" class="form-control" name="password2" placeholder="Confirm Password">

                            {{recaptcha}}

                        <button type="submit" id="pilot-login-signup-button" class="btn btn-primary btn-block btn-lg">Signup</button>
                    </form>

                    Login

{% endblock %}


text:
package com.client.core.base.model.helper.impl;

import com.bullhornsdk.data.model.entity.core.standard.ClientContact;
import com.bullhornsdk.data.model.entity.core.standard.ClientCorporation;
import com.bullhornsdk.data.model.entity.core.standard.CorporateUser;
import com.bullhornsdk.data.model.entity.core.standard.Opportunity;
import com.client.core.base.model.helper.AbstractTriggerHelper;
import com.client.core.base.model.relatedentity.BullhornRelatedEntity;
import com.client.core.base.model.relatedentity.OpportunityRelatedEntity;

import java.util.Map;
import java.util.Set;

public abstract class OpportunityTriggerHelper extends AbstractTriggerHelper<Opportunity> {

	private CorporateUser opportunityOwner;
	private ClientCorporation clientCorporation;
	private ClientContact clientContact;

	public OpportunityTriggerHelper(Integer updatingUserID, Map<? extends BullhornRelatedEntity, Set<String>> relatedEntityFields) {
		super(updatingUserID, Opportunity.class, OpportunityRelatedEntity.OPPORTUNITY, relatedEntityFields);
	}

	public CorporateUser getOpportunityOwner() {
		if (opportunityOwner == null) {
			this.opportunityOwner = findCorporateUser(getNewEntity().getOwner().getId(), OpportunityRelatedEntity.OPPORTUNITY_OWNER);
		}

		return opportunityOwner;
	}

	public ClientCorporation getClientCorporation() {
		if (clientCorporation == null) {
			this.clientCorporation = findClientCorporation(getNewEntity().getClientCorporation().getId(), OpportunityRelatedEntity.CLIENT_CORPORATION);
		}

		return clientCorporation;
	}

	public ClientContact getClientContact() {
		if (clientContact == null) {
			this.clientContact = findClientContact(getNewEntity().getClientContact().getId(), OpportunityRelatedEntity.CLIENT_CONTACT);
		}

		return clientContact;
	}

}


text:
package org.apache.pinot.core.query.aggregation.function;

import com.google.common.base.Preconditions;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.calcite.sql.parser.SqlParseException;
import org.apache.commons.lang3.StringUtils;
import org.apache.datasketches.Util;
import org.apache.datasketches.memory.Memory;
import org.apache.datasketches.theta.AnotB;
import org.apache.datasketches.theta.Intersection;
import org.apache.datasketches.theta.SetOperationBuilder;
import org.apache.datasketches.theta.Sketch;
import org.apache.datasketches.theta.Union;
import org.apache.datasketches.theta.UpdateSketch;
import org.apache.datasketches.theta.UpdateSketchBuilder;
import org.apache.pinot.common.function.AggregationFunctionType;
import org.apache.pinot.common.utils.DataSchema.ColumnDataType;
import org.apache.pinot.core.common.BlockValSet;
import org.apache.pinot.core.operator.filter.predicate.PredicateEvaluator;
import org.apache.pinot.core.operator.filter.predicate.PredicateEvaluatorProvider;
import org.apache.pinot.core.query.aggregation.AggregationResultHolder;
import org.apache.pinot.core.query.aggregation.ObjectAggregationResultHolder;
import org.apache.pinot.core.query.aggregation.groupby.GroupByResultHolder;
import org.apache.pinot.core.query.aggregation.groupby.ObjectGroupByResultHolder;
import org.apache.pinot.core.query.request.context.ExpressionContext;
import org.apache.pinot.core.query.request.context.FilterContext;
import org.apache.pinot.core.query.request.context.FunctionContext;
import org.apache.pinot.core.query.request.context.predicate.Predicate;
import org.apache.pinot.core.query.request.context.utils.QueryContextConverterUtils;
import org.apache.pinot.spi.data.FieldSpec.DataType;
import org.apache.pinot.sql.parsers.CalciteSqlParser;

/**
 * The {@code DistinctCountThetaSketchAggregationFunction} can be used in 2 modes:
 *

 *

 *     Simple union without post-aggregation (1 or 2 arguments): main expression to aggregate on, optional theta-sketch
 *     parameters
 *
E.g. DISTINCT_COUNT_THETA_SKETCH(col)
 *

 *

 *     Union with post-aggregation (at least 4 arguments): main expression to aggregate on, theta-sketch parameters,
 *     filter(s), post-aggregation expression
 *
E.g. DISTINCT_COUNT_THETA_SKETCH(col, '', 'dimName=''gender'' AND dimValue=''male''',
 *     'dimName=''course'' AND dimValue=''math''', 'SET_INTERSECT($1,$2)')
 *

 *

 * Currently there is only 1 parameter for the function:
 *

 *

 *     nominalEntries: The nominal entries used to create the sketch. (Default 4096)
 *

 *

 *
E.g. DISTINCT_COUNT_THETA_SKETCH(col, 'nominalEntries=8192')
 */
@SuppressWarnings({"rawtypes", "unchecked"})
public class DistinctCountThetaSketchAggregationFunction extends BaseSingleInputAggregationFunction<List<Sketch>, Comparable> {
  private static final String SET_UNION = "SET_UNION";
  private static final String SET_INTERSECT = "SET_INTERSECT";
  private static final String SET_DIFF = "SET_DIFF";
  private static final String DEFAULT_SKETCH_IDENTIFIER = "$0";
  private static final Sketch EMPTY_SKETCH = new UpdateSketchBuilder().build().compact();

  private final List<ExpressionContext> _inputExpressions;
  private final boolean _includeDefaultSketch;
  private final List<FilterEvaluator> _filterEvaluators;
  private final ExpressionContext _postAggregationExpression;
  private final UpdateSketchBuilder _updateSketchBuilder = new UpdateSketchBuilder();
  private final SetOperationBuilder _setOperationBuilder = new SetOperationBuilder();

  public DistinctCountThetaSketchAggregationFunction(List<ExpressionContext> arguments) {
    super(arguments.get(0));

    // Initialize the UpdateSketchBuilder and SetOperationBuilder with the parameters
    int numArguments = arguments.size();
    if (numArguments > 1) {
      ExpressionContext paramsExpression = arguments.get(1);
      Preconditions.checkArgument(paramsExpression.getType() == ExpressionContext.Type.LITERAL,
          "Second argument of DISTINCT_COUNT_THETA_SKETCH aggregation function must be literal (parameters)");
      Parameters parameters = new Parameters(paramsExpression.getLiteral());
      int nominalEntries = parameters.getNominalEntries();
      _updateSketchBuilder.setNominalEntries(nominalEntries);
      _setOperationBuilder.setNominalEntries(nominalEntries);
    }

    if (numArguments < 4) {
      // Simple union without post-aggregation

      _inputExpressions = Collections.singletonList(_expression);
      _includeDefaultSketch = true;
      _filterEvaluators = Collections.emptyList();
      _postAggregationExpression = ExpressionContext.forIdentifier(DEFAULT_SKETCH_IDENTIFIER);
    } else {
      // Union with post-aggregation

      // Input expressions should include the main expression and the lhs of the predicates in the filters
      _inputExpressions = new ArrayList<>();
      _inputExpressions.add(_expression);
      Map<ExpressionContext, Integer> expressionIndexMap = new HashMap<>();
      expressionIndexMap.put(_expression, 0);

      // Process the filter expressions
      _filterEvaluators = new ArrayList<>(numArguments - 3);
      for (int i = 2; i < numArguments - 1; i++) {
        ExpressionContext filterExpression = arguments.get(i);
        Preconditions.checkArgument(filterExpression.getType() == ExpressionContext.Type.LITERAL,
            "Third to second last argument of DISTINCT_COUNT_THETA_SKETCH aggregation function must be literal (filter expression)");
        FilterContext filter;
        try {
          filter =
              QueryContextConverterUtils.getFilter(CalciteSqlParser.compileToExpression(filterExpression.getLiteral()));
        } catch (SqlParseException e) {
          throw new IllegalArgumentException("Invalid filter expression: " + filterExpression.getLiteral());
        }
        // NOTE: Collect expressions before constructing the FilterInfo so that expressionIndexMap always include the
        //       expressions in the filter.
        collectExpressions(filter, _inputExpressions, expressionIndexMap);
        _filterEvaluators.add(getFilterEvaluator(filter, expressionIndexMap));
      }

      // Process the post-aggregation expression
      ExpressionContext postAggregationExpression = arguments.get(numArguments - 1);
      Preconditions.checkArgument(postAggregationExpression.getType() == ExpressionContext.Type.LITERAL,
          "Last argument of DISTINCT_COUNT_THETA_SKETCH aggregation function must be literal (post-aggregation expression)");
      try {
        _postAggregationExpression = QueryContextConverterUtils
            .getExpression(CalciteSqlParser.compileToExpression(postAggregationExpression.getLiteral()));
      } catch (SqlParseException e) {
        throw new IllegalArgumentException(
            "Invalid post-aggregation expression: " + postAggregationExpression.getLiteral());
      }

      // Validate the post-aggregation expression
      _includeDefaultSketch = validatePostAggregationExpression(_postAggregationExpression, _filterEvaluators.size());
    }
  }

  @Override
  public AggregationFunctionType getType() {
    return AggregationFunctionType.DISTINCTCOUNTTHETASKETCH;
  }

  @Override
  public List<ExpressionContext> getInputExpressions() {
    return _inputExpressions;
  }

  @Override
  public AggregationResultHolder createAggregationResultHolder() {
    return new ObjectAggregationResultHolder();
  }

  @Override
  public GroupByResultHolder createGroupByResultHolder(int initialCapacity, int maxCapacity) {
    return new ObjectGroupByResultHolder(initialCapacity, maxCapacity);
  }

  @Override
  public void aggregate(int length, AggregationResultHolder aggregationResultHolder,
      Map<ExpressionContext, BlockValSet> blockValSetMap) {
    int numExpressions = _inputExpressions.size();
    boolean[] singleValues = new boolean[numExpressions];
    DataType[] valueTypes = new DataType[numExpressions];
    Object[] valueArrays = new Object[numExpressions];
    extractValues(blockValSetMap, singleValues, valueTypes, valueArrays);
    int numFilters = _filterEvaluators.size();

    // Main expression is always index 0
    if (valueTypes[0] != DataType.BYTES) {
      List<UpdateSketch> updateSketches = getUpdateSketches(aggregationResultHolder);
      if (singleValues[0]) {
        switch (valueTypes[0]) {
          case INT:
            int[] intValues = (int[]) valueArrays[0];
            if (_includeDefaultSketch) {
              UpdateSketch defaultSketch = updateSketches.get(0);
              for (int i = 0; i < length; i++) {
                defaultSketch.update(intValues[i]);
              }
            }
            for (int i = 0; i < numFilters; i++) {
              FilterEvaluator filterEvaluator = _filterEvaluators.get(i);
              UpdateSketch updateSketch = updateSketches.get(i + 1);
              for (int j = 0; j < length; j++) {
                if (filterEvaluator.evaluate(singleValues, valueTypes, valueArrays, j)) {
                  updateSketch.update(intValues[j]);
                }
              }
            }
            break;
          case LONG:
            long[] longValues = (long[]) valueArrays[0];
            if (_includeDefaultSketch) {
              UpdateSketch defaultSketch = updateSketches.get(0);
              for (int i = 0; i < length; i++) {
                defaultSketch.update(longValues[i]);
              }
            }
            for (int i = 0; i < numFilters; i++) {
              FilterEvaluator filterEvaluator = _filterEvaluators.get(i);
              UpdateSketch updateSketch = updateSketches.get(i + 1);
              for (int j = 0; j < length; j++) {
                if (filterEvaluator.evaluate(singleValues, valueTypes, valueArrays, j)) {
                  updateSketch.update(longValues[j]);
                }
              }
            }
            break;
          case FLOAT:
            float[] floatValues = (float[]) valueArrays[0];
            if (_includeDefaultSketch) {
              UpdateSketch defaultSketch = updateSketches.get(0);
              for (int i = 0; i < length; i++) {
                defaultSketch.update(floatValues[i]);
              }
            }
            for (int i = 0; i < numFilters; i++) {
              FilterEvaluator filterEvaluator = _filterEvaluators.get(i);
              UpdateSketch updateSketch = updateSketches.get(i + 1);
              for (int j = 0; j < length; j++) {
                if (filterEvaluator.evaluate(singleValues, valueTypes, valueArrays, j)) {
                  updateSketch.update(floatValues[j]);
                }
              }
            }
            break;
          case DOUBLE:
            double[] doubleValues = (double[]) valueArrays[0];
            if (_includeDefaultSketch) {
              UpdateSketch defaultSketch = updateSketches.get(0);
              for (int i = 0; i < length; i++) {
                defaultSketch.update(doubleValues[i]);
              }
            }
            for (int i = 0; i < numFilters; i++) {
              FilterEvaluator filterEvaluator = _filterEvaluators.get(i);
              UpdateSketch updateSketch = updateSketches.get(i + 1);
              for (int j = 0; j < length; j++) {
                if (filterEvaluator.evaluate(singleValues, valueTypes, valueArrays, j)) {
                  updateSketch.update(doubleValues[j]);
                }
              }
            }
            break;
          case STRING:
            String[] stringValues = (String[]) valueArrays[0];
            if (_includeDefaultSketch) {
              UpdateSketch defaultSketch = updateSketches.get(0);
              for (int i = 0; i < length; i++) {
                defaultSketch.update(stringValues[i]);
              }
            }
            for (int i = 0; i < numFilters; i++) {
              FilterEvaluator filterEvaluator = _filterEvaluators.get(i);
              UpdateSketch updateSketch = updateSketches.get(i + 1);
              for (int j = 0; j < length; j++) {
                if (filterEvaluator.evaluate(singleValues, valueTypes, valueArrays, j)) {
                  updateSketch.update(stringValues[j]);
                }
              }
            }
            break;
          default:
            throw new IllegalStateException(
                "Illegal single-value data type for DISTINCT_COUNT_THETA_SKETCH aggregation function: "
                    + valueTypes[0]);
        }
      } else {
        switch (valueTypes[0]) {
          case INT:
            int[][] intValues = (int[][]) valueArrays[0];
            if (_includeDefaultSketch) {
              UpdateSketch defaultSketch = updateSketches.get(0);
              for (int i = 0; i < length; i++) {
                for (int value : intValues[i]) {
                  defaultSketch.update(value);
                }
              }
            }
            for (int i = 0; i < numFilters; i++) {
              FilterEvaluator filterEvaluator = _filterEvaluators.get(i);
              UpdateSketch updateSketch = updateSketches.get(i + 1);
              for (int j = 0; j < length; j++) {
                if (filterEvaluator.evaluate(singleValues, valueTypes, valueArrays, j)) {
                  for (int value : intValues[j]) {
                    updateSketch.update(value);
                  }
                }
              }
            }
            break;
          case LONG:
            long[][] longValues = (long[][]) valueArrays[0];
            if (_includeDefaultSketch) {
              UpdateSketch defaultSketch = updateSketches.get(0);
              for (int i = 0; i < length; i++) {
                for (long value : longValues[i]) {
                  defaultSketch.update(value);
                }
              }
            }
            for (int i = 0; i < numFilters; i++) {
              FilterEvaluator filterEvaluator = _filterEvaluators.get(i);
              UpdateSketch updateSketch = updateSketches.get(i + 1);
              for (int j = 0; j < length; j++) {
                if (filterEvaluator.evaluate(singleValues, valueTypes, valueArrays, j)) {
                  for (long value : longValues[j]) {
                    updateSketch.update(value);
                  }
                }
              }
            }
            break;
          case FLOAT:
            float[][] floatValues = (float[][]) valueArrays[0];
            if (_includeDefaultSketch) {
              UpdateSketch defaultSketch = updateSketches.get(0);
              for (int i = 0; i < length; i++) {
                for (float value : floatValues[i]) {
                  defaultSketch.update(value);
                }
              }
            }
            for (int i = 0; i < numFilters; i++) {
              FilterEvaluator filterEvaluator = _filterEvaluators.get(i);
              UpdateSketch updateSketch = updateSketches.get(i + 1);
              for (int j = 0; j < length; j++) {
                if (filterEvaluator.evaluate(singleValues, valueTypes, valueArrays, j)) {
                  for (float value : floatValues[j]) {
                    updateSketch.update(value);
                  }
                }
              }
            }
            break;
          case DOUBLE:
            double[][] doubleValues = (double[][]) valueArrays[0];
            if (_includeDefaultSketch) {
              UpdateSketch defaultSketch = updateSketches.get(0);
              for (int i = 0; i < length; i++) {
                for (double value : doubleValues[i]) {
                  defaultSketch.update(value);
                }
              }
            }
            for (int i = 0; i < numFilters; i++) {
              FilterEvaluator filterEvaluator = _filterEvaluators.get(i);
              UpdateSketch updateSketch = updateSketches.get(i + 1);
              for (int j = 0; j < length; j++) {
                if (filterEvaluator.evaluate(singleValues, valueTypes, valueArrays, j)) {
                  for (double value : doubleValues[j]) {
                    updateSketch.update(value);
                  }
                }
              }
            }
            break;
          case STRING:
            String[][] stringValues = (String[][]) valueArrays[0];
            if (_includeDefaultSketch) {
              UpdateSketch defaultSketch = updateSketches.get(0);
              for (int i = 0; i < length; i++) {
                for (String value : stringValues[i]) {
                  defaultSketch.update(value);
                }
              }
            }
            for (int i = 0; i < numFilters; i++) {
              FilterEvaluator filterEvaluator = _filterEvaluators.get(i);
              UpdateSketch updateSketch = updateSketches.get(i + 1);
              for (int j = 0; j < length; j++) {
                if (filterEvaluator.evaluate(singleValues, valueTypes, valueArrays, j)) {
                  for (String value : stringValues[j]) {
                    updateSketch.update(value);
                  }
                }
              }
            }
            break;
          default:
            throw new IllegalStateException(
                "Illegal multi-value data type for DISTINCT_COUNT_THETA_SKETCH aggregation function: " + valueTypes[0]);
        }
      }
    } else {
      // Serialized sketch
      List<Union> unions = getUnions(aggregationResultHolder);
      Sketch[] sketches = deserializeSketches((byte[][]) valueArrays[0], length);
      if (_includeDefaultSketch) {
        Union defaultUnion = unions.get(0);
        for (Sketch sketch : sketches) {
          defaultUnion.update(sketch);
        }
      }
      for (int i = 0; i < numFilters; i++) {
        FilterEvaluator filterEvaluator = _filterEvaluators.get(i);
        Union union = unions.get(i + 1);
        for (int j = 0; j < length; j++) {
          if (filterEvaluator.evaluate(singleValues, valueTypes, valueArrays, j)) {
            union.update(sketches[j]);
          }
        }
      }
    }
  }

  @Override
  public void aggregateGroupBySV(int length, int[] groupKeyArray, GroupByResultHolder groupByResultHolder,
      Map<ExpressionContext, BlockValSet> blockValSetMap) {
    int numExpressions = _inputExpressions.size();
    boolean[] singleValues = new boolean[numExpressions];
    DataType[] valueTypes = new DataType[numExpressions];
    Object[] valueArrays = new Object[numExpressions];
    extractValues(blockValSetMap, singleValues, valueTypes, valueArrays);
    int numFilters = _filterEvaluators.size();

    // Main expression is always index 0
    if (valueTypes[0] != DataType.BYTES) {
      if (singleValues[0]) {
        switch (valueTypes[0]) {
          case INT:
            int[] intValues = (int[]) valueArrays[0];
            for (int i = 0; i < length; i++) {
              List<UpdateSketch> updateSketches = getUpdateSketches(groupByResultHolder, groupKeyArray[i]);
              int value = intValues[i];
              if (_includeDefaultSketch) {
                updateSketches.get(0).update(value);
              }
              for (int j = 0; j < numFilters; j++) {
                if (_filterEvaluators.get(j).evaluate(singleValues, valueTypes, valueArrays, i)) {
                  updateSketches.get(j + 1).update(value);
                }
              }
            }
            break;
          case LONG:
            long[] longValues = (long[]) valueArrays[0];
            for (int i = 0; i < length; i++) {
              List<UpdateSketch> updateSketches = getUpdateSketches(groupByResultHolder, groupKeyArray[i]);
              long value = longValues[i];
              if (_includeDefaultSketch) {
                updateSketches.get(0).update(value);
              }
              for (int j = 0; j < numFilters; j++) {
                if (_filterEvaluators.get(j).evaluate(singleValues, valueTypes, valueArrays, i)) {
                  updateSketches.get(j + 1).update(value);
                }
              }
            }
            break;
          case FLOAT:
            float[] floatValues = (float[]) valueArrays[0];
            for (int i = 0; i < length; i++) {
              List<UpdateSketch> updateSketches = getUpdateSketches(groupByResultHolder, groupKeyArray[i]);
              float value = floatValues[i];
              if (_includeDefaultSketch) {
                updateSketches.get(0).update(value);
              }
              for (int j = 0; j < numFilters; j++) {
                if (_filterEvaluators.get(j).evaluate(singleValues, valueTypes, valueArrays, i)) {
                  updateSketches.get(j + 1).update(value);
                }
              }
            }
            break;
          case DOUBLE:
            double[] doubleValues = (double[]) valueArrays[0];
            for (int i = 0; i < length; i++) {
              List<UpdateSketch> updateSketches = getUpdateSketches(groupByResultHolder, groupKeyArray[i]);
              double value = doubleValues[i];
              if (_includeDefaultSketch) {
                updateSketches.get(0).update(value);
              }
              for (int j = 0; j < numFilters; j++) {
                if (_filterEvaluators.get(j).evaluate(singleValues, valueTypes, valueArrays, i)) {
                  updateSketches.get(j + 1).update(value);
                }
              }
            }
            break;
          case STRING:
            String[] stringValues = (String[]) valueArrays[0];
            for (int i = 0; i < length; i++) {
              List<UpdateSketch> updateSketches = getUpdateSketches(groupByResultHolder, groupKeyArray[i]);
              String value = stringValues[i];
              if (_includeDefaultSketch) {
                updateSketches.get(0).update(value);
              }
              for (int j = 0; j < numFilters; j++) {
                if (_filterEvaluators.get(j).evaluate(singleValues, valueTypes, valueArrays, i)) {
                  updateSketches.get(j + 1).update(value);
                }
              }
            }
            break;
          default:
            throw new IllegalStateException(
                "Illegal single-value data type for DISTINCT_COUNT_THETA_SKETCH aggregation function: "
                    + valueTypes[0]);
        }
      } else {
        switch (valueTypes[0]) {
          case INT:
            int[][] intValues = (int[][]) valueArrays[0];
            for (int i = 0; i < length; i++) {
              List<UpdateSketch> updateSketches = getUpdateSketches(groupByResultHolder, groupKeyArray[i]);
              int[] values = intValues[i];
              if (_includeDefaultSketch) {
                UpdateSketch defaultSketch = updateSketches.get(0);
                for (int value : values) {
                  defaultSketch.update(value);
                }
              }
              for (int j = 0; j < numFilters; j++) {
                if (_filterEvaluators.get(j).evaluate(singleValues, valueTypes, valueArrays, i)) {
                  UpdateSketch updateSketch = updateSketches.get(j + 1);
                  for (int value : values) {
                    updateSketch.update(value);
                  }
                }
              }
            }
            break;
          case LONG:
            long[][] longValues = (long[][]) valueArrays[0];
            for (int i = 0; i < length; i++) {
              List<UpdateSketch> updateSketches = getUpdateSketches(groupByResultHolder, groupKeyArray[i]);
              long[] values = longValues[i];
              if (_includeDefaultSketch) {
                UpdateSketch defaultSketch = updateSketches.get(0);
                for (long value : values) {
                  defaultSketch.update(value);
                }
              }
              for (int j = 0; j < numFilters; j++) {
                if (_filterEvaluators.get(j).evaluate(singleValues, valueTypes, valueArrays, i)) {
                  UpdateSketch updateSketch = updateSketches.get(j + 1);
                  for (long value : values) {
                    updateSketch.update(value);
                  }
                }
              }
            }
            break;
          case FLOAT:
            float[][] floatValues = (float[][]) valueArrays[0];
            for (int i = 0; i < length; i++) {
              List<UpdateSketch> updateSketches = getUpdateSketches(groupByResultHolder, groupKeyArray[i]);
              float[] values = floatValues[i];
              if (_includeDefaultSketch) {
                UpdateSketch defaultSketch = updateSketches.get(0);
                for (float value : values) {
                  defaultSketch.update(value);
                }
              }
              for (int j = 0; j < numFilters; j++) {
                if (_filterEvaluators.get(j).evaluate(singleValues, valueTypes, valueArrays, i)) {
                  UpdateSketch updateSketch = updateSketches.get(j + 1);
                  for (float value : values) {
                    updateSketch.update(value);
                  }
                }
              }
            }
            break;
          case DOUBLE:
            double[][] doubleValues = (double[][]) valueArrays[0];
            for (int i = 0; i < length; i++) {
              List<UpdateSketch> updateSketches = getUpdateSketches(groupByResultHolder, groupKeyArray[i]);
              double[] values = doubleValues[i];
              if (_includeDefaultSketch) {
                UpdateSketch defaultSketch = updateSketches.get(0);
                for (double value : values) {
                  defaultSketch.update(value);
                }
              }
              for (int j = 0; j < numFilters; j++) {
                if (_filterEvaluators.get(j).evaluate(singleValues, valueTypes, valueArrays, i)) {
                  UpdateSketch updateSketch = updateSketches.get(j + 1);
                  for (double value : values) {
                    updateSketch.update(value);
                  }
                }
              }
            }
            break;
          case STRING:
            String[][] stringValues = (String[][]) valueArrays[0];
            for (int i = 0; i < length; i++) {
              List<UpdateSketch> updateSketches = getUpdateSketches(groupByResultHolder, groupKeyArray[i]);
              String[] values = stringValues[i];
              if (_includeDefaultSketch) {
                UpdateSketch defaultSketch = updateSketches.get(0);
                for (String value : values) {
                  defaultSketch.update(value);
                }
              }
              for (int j = 0; j < numFilters; j++) {
                if (_filterEvaluators.get(j).evaluate(singleValues, valueTypes, valueArrays, i)) {
                  UpdateSketch updateSketch = updateSketches.get(j + 1);
                  for (String value : values) {
                    updateSketch.update(value);
                  }
                }
              }
            }
            break;
          default:
            throw new IllegalStateException(
                "Illegal multi-value data type for DISTINCT_COUNT_THETA_SKETCH aggregation function: " + valueTypes[0]);
        }
      }
    } else {
      // Serialized sketch
      Sketch[] sketches = deserializeSketches((byte[][]) valueArrays[0], length);
      for (int i = 0; i < length; i++) {
        List<Union> unions = getUnions(groupByResultHolder, groupKeyArray[i]);
        Sketch sketch = sketches[i];
        if (_includeDefaultSketch) {
          unions.get(0).update(sketch);
        }
        for (int j = 0; j < numFilters; j++) {
          if (_filterEvaluators.get(j).evaluate(singleValues, valueTypes, valueArrays, i)) {
            unions.get(j + 1).update(sketch);
          }
        }
      }
    }
  }

  @Override
  public void aggregateGroupByMV(int length, int[][] groupKeysArray, GroupByResultHolder groupByResultHolder,
      Map<ExpressionContext, BlockValSet> blockValSetMap) {
    int numExpressions = _inputExpressions.size();
    boolean[] singleValues = new boolean[numExpressions];
    DataType[] valueTypes = new DataType[numExpressions];
    Object[] valueArrays = new Object[numExpressions];
    extractValues(blockValSetMap, singleValues, valueTypes, valueArrays);
    int numFilters = _filterEvaluators.size();

    // Main expression is always index 0
    if (valueTypes[0] != DataType.BYTES) {
      if (singleValues[0]) {
        switch (valueTypes[0]) {
          case INT:
            int[] intValues = (int[]) valueArrays[0];
            if (_includeDefaultSketch) {
              for (int i = 0; i < length; i++) {
                for (int groupKey : groupKeysArray[i]) {
                  getUpdateSketches(groupByResultHolder, groupKey).get(0).update(intValues[i]);
                }
              }
            }
            for (int i = 0; i < numFilters; i++) {
              FilterEvaluator filterEvaluator = _filterEvaluators.get(i);
              for (int j = 0; j < length; j++) {
                if (filterEvaluator.evaluate(singleValues, valueTypes, valueArrays, j)) {
                  for (int groupKey : groupKeysArray[i]) {
                    getUpdateSketches(groupByResultHolder, groupKey).get(i + 1).update(intValues[j]);
                  }
                }
              }
            }
            break;
          case LONG:
            long[] longValues = (long[]) valueArrays[0];
            if (_includeDefaultSketch) {
              for (int i = 0; i < length; i++) {
                for (int groupKey : groupKeysArray[i]) {
                  getUpdateSketches(groupByResultHolder, groupKey).get(0).update(longValues[i]);
                }
              }
            }
            for (int i = 0; i < numFilters; i++) {
              FilterEvaluator filterEvaluator = _filterEvaluators.get(i);
              for (int j = 0; j < length; j++) {
                if (filterEvaluator.evaluate(singleValues, valueTypes, valueArrays, j)) {
                  for (int groupKey : groupKeysArray[i]) {
                    getUpdateSketches(groupByResultHolder, groupKey).get(i + 1).update(longValues[j]);
                  }
                }
              }
            }
            break;
          case FLOAT:
            float[] floatValues = (float[]) valueArrays[0];
            if (_includeDefaultSketch) {
              for (int i = 0; i < length; i++) {
                for (int groupKey : groupKeysArray[i]) {
                  getUpdateSketches(groupByResultHolder, groupKey).get(0).update(floatValues[i]);
                }
              }
            }
            for (int i = 0; i < numFilters; i++) {
              FilterEvaluator filterEvaluator = _filterEvaluators.get(i);
              for (int j = 0; j < length; j++) {
                if (filterEvaluator.evaluate(singleValues, valueTypes, valueArrays, j)) {
                  for (int groupKey : groupKeysArray[i]) {
                    getUpdateSketches(groupByResultHolder, groupKey).get(i + 1).update(floatValues[j]);
                  }
                }
              }
            }
            break;
          case DOUBLE:
            double[] doubleValues = (double[]) valueArrays[0];
            if (_includeDefaultSketch) {
              for (int i = 0; i < length; i++) {
                for (int groupKey : groupKeysArray[i]) {
                  getUpdateSketches(groupByResultHolder, groupKey).get(0).update(doubleValues[i]);
                }
              }
            }
            for (int i = 0; i < numFilters; i++) {
              FilterEvaluator filterEvaluator = _filterEvaluators.get(i);
              for (int j = 0; j < length; j++) {
                if (filterEvaluator.evaluate(singleValues, valueTypes, valueArrays, j)) {
                  for (int groupKey : groupKeysArray[i]) {
                    getUpdateSketches(groupByResultHolder, groupKey).get(i + 1).update(doubleValues[j]);
                  }
                }
              }
            }
            break;
          case STRING:
            String[] stringValues = (String[]) valueArrays[0];
            if (_includeDefaultSketch) {
              for (int i = 0; i < length; i++) {
                for (int groupKey : groupKeysArray[i]) {
                  getUpdateSketches(groupByResultHolder, groupKey).get(0).update(stringValues[i]);
                }
              }
            }
            for (int i = 0; i < numFilters; i++) {
              FilterEvaluator filterEvaluator = _filterEvaluators.get(i);
              for (int j = 0; j < length; j++) {
                if (filterEvaluator.evaluate(singleValues, valueTypes, valueArrays, j)) {
                  for (int groupKey : groupKeysArray[i]) {
                    getUpdateSketches(groupByResultHolder, groupKey).get(i + 1).update(stringValues[j]);
                  }
                }
              }
            }
            break;
          default:
            throw new IllegalStateException(
                "Illegal single-value data type for DISTINCT_COUNT_THETA_SKETCH aggregation function: "
                    + valueTypes[0]);
        }
      } else {
        switch (valueTypes[0]) {
          case INT:
            int[][] intValues = (int[][]) valueArrays[0];
            if (_includeDefaultSketch) {
              for (int i = 0; i < length; i++) {
                for (int groupKey : groupKeysArray[i]) {
                  UpdateSketch defaultSketch = getUpdateSketches(groupByResultHolder, groupKey).get(0);
                  for (int value : intValues[i]) {
                    defaultSketch.update(value);
                  }
                }
              }
            }
            for (int i = 0; i < numFilters; i++) {
              FilterEvaluator filterEvaluator = _filterEvaluators.get(i);
              for (int j = 0; j < length; j++) {
                if (filterEvaluator.evaluate(singleValues, valueTypes, valueArrays, j)) {
                  for (int groupKey : groupKeysArray[i]) {
                    UpdateSketch updateSketch = getUpdateSketches(groupByResultHolder, groupKey).get(i + 1);
                    for (int value : intValues[i]) {
                      updateSketch.update(value);
                    }
                  }
                }
              }
            }
            break;
          case LONG:
            long[][] longValues = (long[][]) valueArrays[0];
            if (_includeDefaultSketch) {
              for (int i = 0; i < length; i++) {
                for (int groupKey : groupKeysArray[i]) {
                  UpdateSketch defaultSketch = getUpdateSketches(groupByResultHolder, groupKey).get(0);
                  for (long value : longValues[i]) {
                    defaultSketch.update(value);
                  }
                }
              }
            }
            for (int i = 0; i < numFilters; i++) {
              FilterEvaluator filterEvaluator = _filterEvaluators.get(i);
              for (int j = 0; j < length; j++) {
                if (filterEvaluator.evaluate(singleValues, valueTypes, valueArrays, j)) {
                  for (int groupKey : groupKeysArray[i]) {
                    UpdateSketch updateSketch = getUpdateSketches(groupByResultHolder, groupKey).get(i + 1);
                    for (long value : longValues[i]) {
                      updateSketch.update(value);
                    }
                  }
                }
              }
            }
            break;
          case FLOAT:
            float[][] floatValues = (float[][]) valueArrays[0];
            if (_includeDefaultSketch) {
              for (int i = 0; i < length; i++) {
                for (int groupKey : groupKeysArray[i]) {
                  UpdateSketch defaultSketch = getUpdateSketches(groupByResultHolder, groupKey).get(0);
                  for (float value : floatValues[i]) {
                    defaultSketch.update(value);
                  }
                }
              }
            }
            for (int i = 0; i < numFilters; i++) {
              FilterEvaluator filterEvaluator = _filterEvaluators.get(i);
              for (int j = 0; j < length; j++) {
                if (filterEvaluator.evaluate(singleValues, valueTypes, valueArrays, j)) {
                  for (int groupKey : groupKeysArray[i]) {
                    UpdateSketch updateSketch = getUpdateSketches(groupByResultHolder, groupKey).get(i + 1);
                    for (float value : floatValues[i]) {
                      updateSketch.update(value);
                    }
                  }
                }
              }
            }
            break;
          case DOUBLE:
            double[][] doubleValues = (double[][]) valueArrays[0];
            if (_includeDefaultSketch) {
              for (int i = 0; i < length; i++) {
                for (int groupKey : groupKeysArray[i]) {
                  UpdateSketch defaultSketch = getUpdateSketches(groupByResultHolder, groupKey).get(0);
                  for (double value : doubleValues[i]) {
                    defaultSketch.update(value);
                  }
                }
              }
            }
            for (int i = 0; i < numFilters; i++) {
              FilterEvaluator filterEvaluator = _filterEvaluators.get(i);
              for (int j = 0; j < length; j++) {
                if (filterEvaluator.evaluate(singleValues, valueTypes, valueArrays, j)) {
                  for (int groupKey : groupKeysArray[i]) {
                    UpdateSketch updateSketch = getUpdateSketches(groupByResultHolder, groupKey).get(i + 1);
                    for (double value : doubleValues[i]) {
                      updateSketch.update(value);
                    }
                  }
                }
              }
            }
            break;
          case STRING:
            String[][] stringValues = (String[][]) valueArrays[0];
            if (_includeDefaultSketch) {
              for (int i = 0; i < length; i++) {
                for (int groupKey : groupKeysArray[i]) {
                  UpdateSketch defaultSketch = getUpdateSketches(groupByResultHolder, groupKey).get(0);
                  for (String value : stringValues[i]) {
                    defaultSketch.update(value);
                  }
                }
              }
            }
            for (int i = 0; i < numFilters; i++) {
              FilterEvaluator filterEvaluator = _filterEvaluators.get(i);
              for (int j = 0; j < length; j++) {
                if (filterEvaluator.evaluate(singleValues, valueTypes, valueArrays, j)) {
                  for (int groupKey : groupKeysArray[i]) {
                    UpdateSketch updateSketch = getUpdateSketches(groupByResultHolder, groupKey).get(i + 1);
                    for (String value : stringValues[i]) {
                      updateSketch.update(value);
                    }
                  }
                }
              }
            }
            break;
          default:
            throw new IllegalStateException(
                "Illegal multi-value data type for DISTINCT_COUNT_THETA_SKETCH aggregation function: " + valueTypes[0]);
        }
      }
    } else {
      // Serialized sketch
      Sketch[] sketches = deserializeSketches((byte[][]) valueArrays[0], length);
      if (_includeDefaultSketch) {
        for (int i = 0; i < length; i++) {
          for (int groupKey : groupKeysArray[i]) {
            getUnions(groupByResultHolder, groupKey).get(0).update(sketches[i]);
          }
        }
      }
      for (int i = 0; i < numFilters; i++) {
        FilterEvaluator filterEvaluator = _filterEvaluators.get(i);
        for (int j = 0; j < length; j++) {
          if (filterEvaluator.evaluate(singleValues, valueTypes, valueArrays, j)) {
            for (int groupKey : groupKeysArray[i]) {
              getUnions(groupByResultHolder, groupKey).get(i + 1).update(sketches[i]);
            }
          }
        }
      }
    }
  }

  @Override
  public List<Sketch> extractAggregationResult(AggregationResultHolder aggregationResultHolder) {
    List result = aggregationResultHolder.getResult();
    if (result == null) {
      int numSketches = _filterEvaluators.size() + 1;
      List<Sketch> sketches = new ArrayList<>(numSketches);
      for (int i = 0; i < numSketches; i++) {
        sketches.add(EMPTY_SKETCH);
      }
      return sketches;
    }

    if (result.get(0) instanceof Sketch) {
      return result;
    } else {
      return convertToSketches(result);
    }
  }

  @Override
  public List<Sketch> extractGroupByResult(GroupByResultHolder groupByResultHolder, int groupKey) {
    List result = groupByResultHolder.getResult(groupKey);
    if (result.get(0) instanceof Sketch) {
      return result;
    } else {
      return convertToSketches(result);
    }
  }

  @Override
  public List<Sketch> merge(List<Sketch> sketches1, List<Sketch> sketches2) {
    int numSketches = sketches1.size();
    List<Sketch> mergedSketches = new ArrayList<>(numSketches);
    for (int i = 0; i < numSketches; i++) {
      Sketch sketch1 = sketches1.get(i);
      Sketch sketch2 = sketches2.get(i);
      if (sketch1.isEmpty()) {
        mergedSketches.add(sketch2);
        continue;
      }
      if (sketch2.isEmpty()) {
        mergedSketches.add(sketch1);
        continue;
      }
      Union union = _setOperationBuilder.buildUnion();
      union.update(sketch1);
      union.update(sketch2);
      // NOTE: Compact the sketch in unsorted, on-heap fashion for performance concern.
      //       See https://datasketches.apache.org/docs/Theta/ThetaSize.html for more details.
      mergedSketches.add(union.getResult(false, null));
    }
    return mergedSketches;
  }

  @Override
  public boolean isIntermediateResultComparable() {
    return false;
  }

  @Override
  public ColumnDataType getIntermediateResultColumnType() {
    return ColumnDataType.OBJECT;
  }

  @Override
  public ColumnDataType getFinalResultColumnType() {
    return ColumnDataType.LONG;
  }

  @Override
  public Comparable extractFinalResult(List<Sketch> sketches) {
    return Math.round(evaluatePostAggregationExpression(_postAggregationExpression, sketches).getEstimate());
  }

  /**
   * Helper method to collect expressions in the filter.
   */
  private static void collectExpressions(FilterContext filter, List<ExpressionContext> expressions,
      Map<ExpressionContext, Integer> expressionIndexMap) {
    List<FilterContext> children = filter.getChildren();
    if (children != null) {
      for (FilterContext child : children) {
        collectExpressions(child, expressions, expressionIndexMap);
      }
    } else {
      ExpressionContext expression = filter.getPredicate().getLhs();
      if (expressionIndexMap.putIfAbsent(expression, expressions.size()) == null) {
        expressions.add(expression);
      }
    }
  }

  /**
   * Creates a FilterEvaluator for the given filter.
   */
  private static FilterEvaluator getFilterEvaluator(FilterContext filter,
      Map<ExpressionContext, Integer> expressionIndexMap) {
    List<FilterContext> children = filter.getChildren();
    if (children != null) {
      // AND/OR
      List<FilterEvaluator> childEvaluators = new ArrayList<>(children.size());
      for (FilterContext child : children) {
        childEvaluators.add(getFilterEvaluator(child, expressionIndexMap));
      }
      if (filter.getType() == FilterContext.Type.AND) {
        return new AndFilterEvaluator(childEvaluators);
      } else {
        return new OrFilterEvaluator(childEvaluators);
      }
    } else {
      // Predicate
      Predicate predicate = filter.getPredicate();
      int expressionIndex = expressionIndexMap.get(predicate.getLhs());
      return new PredicateFilterEvaluator(predicate, expressionIndex);
    }
  }

  /**
   * Validates the post-aggregation expression:
   *   - The sketch id ($0, $1, etc.) does not exceed the number of filters
   *   - Only contains valid set operations (SET_UNION/SET_INTERSECT/SET_DIFF)
   *   - SET_UNION/SET_INTERSECT contains at least 2 arguments
   *   - SET_DIFF contains exactly 2 arguments
   * Returns whether the post-aggregation expression contains the default sketch ($0).
   */
  private static boolean validatePostAggregationExpression(ExpressionContext expression, int numFilters) {
    Preconditions.checkArgument(expression.getType() != ExpressionContext.Type.LITERAL,
        "Post-aggregation expression should not contain literal expression: %s", expression.getLiteral());

    if (expression.getType() == ExpressionContext.Type.IDENTIFIER) {
      int sketchId = extractSketchId(expression.getIdentifier());
      Preconditions
          .checkArgument(sketchId <= numFilters, "Sketch id: %s exceeds number of filters: %s", sketchId, numFilters);
      return sketchId == 0;
    }

    FunctionContext function = expression.getFunction();
    String functionName = function.getFunctionName();
    List<ExpressionContext> arguments = function.getArguments();
    int numArguments = arguments.size();
    boolean includeDefaultSketch = false;
    switch (functionName.toUpperCase()) {
      case SET_UNION:
      case SET_INTERSECT:
        Preconditions
            .checkArgument(numArguments >= 2, "SET_UNION and SET_INTERSECT should have at least 2 arguments, got: %s",
                numArguments);
        for (ExpressionContext argument : arguments) {
          includeDefaultSketch |= validatePostAggregationExpression(argument, numFilters);
        }
        break;
      case SET_DIFF:
        Preconditions.checkArgument(numArguments == 2, "SET_DIFF should have 2 arguments, got: %s", numArguments);
        for (ExpressionContext argument : arguments) {
          includeDefaultSketch |= validatePostAggregationExpression(argument, numFilters);
        }
        break;
      default:
        throw new IllegalArgumentException("Invalid set operation: " + functionName);
    }
    return includeDefaultSketch;
  }

  /**
   * Extracts the sketch id from the identifier (e.g. $0 -> 0, $1 -> 1).
   */
  private static int extractSketchId(String identifier) {
    Preconditions
        .checkArgument(identifier.charAt(0) == '$', "Invalid identifier: %s, expecting $0, $1, etc.", identifier);
    int sketchId = Integer.parseInt(identifier.substring(1));
    Preconditions.checkArgument(sketchId >= 0, "Invalid identifier: %s, expecting $0, $1, etc.", identifier);
    return sketchId;
  }

  /**
   * Extracts values from the BlockValSet map.
   */
  private void extractValues(Map<ExpressionContext, BlockValSet> blockValSetMap, boolean[] singleValues,
      DataType[] valueTypes, Object[] valueArrays) {
    int numExpressions = _inputExpressions.size();
    for (int i = 0; i < numExpressions; i++) {
      BlockValSet blockValSet = blockValSetMap.get(_inputExpressions.get(i));
      boolean singleValue = blockValSet.isSingleValue();
      DataType valueType = blockValSet.getValueType();
      singleValues[i] = singleValue;
      valueTypes[i] = valueType;
      if (singleValue) {
        switch (valueType) {
          case INT:
            valueArrays[i] = blockValSet.getIntValuesSV();
            break;
          case LONG:
            valueArrays[i] = blockValSet.getLongValuesSV();
            break;
          case FLOAT:
            valueArrays[i] = blockValSet.getFloatValuesSV();
            break;
          case DOUBLE:
            valueArrays[i] = blockValSet.getDoubleValuesSV();
            break;
          case STRING:
            valueArrays[i] = blockValSet.getStringValuesSV();
            break;
          case BYTES:
            valueArrays[i] = blockValSet.getBytesValuesSV();
            break;
          default:
            throw new IllegalStateException();
        }
      } else {
        switch (valueType) {
          case INT:
            valueArrays[i] = blockValSet.getIntValuesMV();
            break;
          case LONG:
            valueArrays[i] = blockValSet.getLongValuesMV();
            break;
          case FLOAT:
            valueArrays[i] = blockValSet.getFloatValuesMV();
            break;
          case DOUBLE:
            valueArrays[i] = blockValSet.getDoubleValuesMV();
            break;
          case STRING:
            valueArrays[i] = blockValSet.getStringValuesMV();
            break;
          default:
            throw new IllegalStateException();
        }
      }
    }
  }

  /**
   * Returns the UpdateSketch list from the result holder or creates a new one if it does not exist.
   */
  private List<UpdateSketch> getUpdateSketches(AggregationResultHolder aggregationResultHolder) {
    List<UpdateSketch> updateSketches = aggregationResultHolder.getResult();
    if (updateSketches == null) {
      updateSketches = buildUpdateSketches();
      aggregationResultHolder.setValue(updateSketches);
    }
    return updateSketches;
  }

  /**
   * Returns the Union list from the result holder or creates a new one if it does not exist.
   */
  private List<Union> getUnions(AggregationResultHolder aggregationResultHolder) {
    List<Union> unions = aggregationResultHolder.getResult();
    if (unions == null) {
      unions = buildUnions();
      aggregationResultHolder.setValue(unions);
    }
    return unions;
  }

  /**
   * Returns the UpdateSketch list for the given group key or creates a new one if it does not exist.
   */
  private List<UpdateSketch> getUpdateSketches(GroupByResultHolder groupByResultHolder, int groupKey) {
    List<UpdateSketch> updateSketches = groupByResultHolder.getResult(groupKey);
    if (updateSketches == null) {
      updateSketches = buildUpdateSketches();
      groupByResultHolder.setValueForKey(groupKey, updateSketches);
    }
    return updateSketches;
  }

  /**
   * Returns the Union list for the given group key or creates a new one if it does not exist.
   */
  private List<Union> getUnions(GroupByResultHolder groupByResultHolder, int groupKey) {
    List<Union> unions = groupByResultHolder.getResult(groupKey);
    if (unions == null) {
      unions = buildUnions();
      groupByResultHolder.setValueForKey(groupKey, unions);
    }
    return unions;
  }

  /**
   * Builds the UpdateSketch list.
   */
  private List<UpdateSketch> buildUpdateSketches() {
    int numSketches = _filterEvaluators.size() + 1;
    List<UpdateSketch> updateSketches = new ArrayList<>(numSketches);
    for (int i = 0; i < numSketches; i++) {
      updateSketches.add(_updateSketchBuilder.build());
    }
    return updateSketches;
  }

  /**
   * Builds the Union list.
   */
  private List<Union> buildUnions() {
    int numUnions = _filterEvaluators.size() + 1;
    List<Union> unions = new ArrayList<>(numUnions);
    for (int i = 0; i < numUnions; i++) {
      unions.add(_setOperationBuilder.buildUnion());
    }
    return unions;
  }

  /**
   * Deserializes the sketches from the bytes.
   */
  private Sketch[] deserializeSketches(byte[][] serializedSketches, int length) {
    Sketch[] sketches = new Sketch[length];
    for (int i = 0; i < length; i++) {
      sketches[i] = Sketch.wrap(Memory.wrap(serializedSketches[i]));
    }
    return sketches;
  }

  /**
   * Converts the given Unions to Sketches.
   */
  private List<Sketch> convertToSketches(List<Union> unions) {
    int numUnions = unions.size();
    List<Sketch> sketches = new ArrayList<>(numUnions);
    for (Union union : unions) {
      // NOTE: Compact the sketch in unsorted, on-heap fashion for performance concern.
      //       See https://datasketches.apache.org/docs/Theta/ThetaSize.html for more details.
      sketches.add(union.getResult(false, null));
    }
    return sketches;
  }

  /**
   * Evaluates the post-aggregation expression.
   */
  protected Sketch evaluatePostAggregationExpression(List<Sketch> sketches) {
    return evaluatePostAggregationExpression(_postAggregationExpression, sketches);
  }

  /**
   * Evaluates the post-aggregation expression.
   */
  private Sketch evaluatePostAggregationExpression(ExpressionContext expression, List<Sketch> sketches) {
    if (expression.getType() == ExpressionContext.Type.IDENTIFIER) {
      return sketches.get(extractSketchId(expression.getIdentifier()));
    }

    // NOTE: Compact the sketch in unsorted, on-heap fashion for performance concern.
    //       See https://datasketches.apache.org/docs/Theta/ThetaSize.html for more details.
    FunctionContext function = expression.getFunction();
    String functionName = function.getFunctionName();
    List<ExpressionContext> arguments = function.getArguments();
    switch (functionName.toUpperCase()) {
      case SET_UNION:
        Union union = _setOperationBuilder.buildUnion();
        for (ExpressionContext argument : arguments) {
          union.update(evaluatePostAggregationExpression(argument, sketches));
        }
        return union.getResult(false, null);
      case SET_INTERSECT:
        Intersection intersection = _setOperationBuilder.buildIntersection();
        for (ExpressionContext argument : arguments) {
          intersection.update(evaluatePostAggregationExpression(argument, sketches));
        }
        return intersection.getResult(false, null);
      case SET_DIFF:
        AnotB diff = _setOperationBuilder.buildANotB();
        diff.update(evaluatePostAggregationExpression(arguments.get(0), sketches),
            evaluatePostAggregationExpression(arguments.get(1), sketches));
        return diff.getResult(false, null);
      default:
        throw new IllegalStateException();
    }
  }

  /**
   * Helper class to wrap the theta-sketch parameters.
   */
  private static class Parameters {
    private static final char PARAMETER_DELIMITER = ';';
    private static final char PARAMETER_KEY_VALUE_SEPARATOR = '=';
    private static final String NOMINAL_ENTRIES_KEY = "nominalEntries";

    private int _nominalEntries = Util.DEFAULT_NOMINAL_ENTRIES;

    Parameters(String parametersString) {
      StringUtils.deleteWhitespace(parametersString);
      String[] keyValuePairs = StringUtils.split(parametersString, PARAMETER_DELIMITER);
      for (String keyValuePair : keyValuePairs) {
        String[] keyAndValue = StringUtils.split(keyValuePair, PARAMETER_KEY_VALUE_SEPARATOR);
        Preconditions.checkArgument(keyAndValue.length == 2, "Invalid parameter: %s", keyValuePair);
        String key = keyAndValue[0];
        String value = keyAndValue[1];
        if (key.equalsIgnoreCase(NOMINAL_ENTRIES_KEY)) {
          _nominalEntries = Integer.parseInt(value);
        } else {
          throw new IllegalArgumentException("Invalid parameter key: " + key);
        }
      }
    }

    int getNominalEntries() {
      return _nominalEntries;
    }
  }

  /**
   * Helper interface to evaluate the filter on the values.
   */
  private interface FilterEvaluator {

    /**
     * Evaluates the given values with the filter, returns {@code true} if the values pass the filter, {@code false}
     * otherwise.
     */
    boolean evaluate(boolean[] singleValues, DataType[] valueTypes, Object[] valueArrays, int index);
  }

  private static class AndFilterEvaluator implements FilterEvaluator {
    final List<FilterEvaluator> _children;

    private AndFilterEvaluator(List<FilterEvaluator> children) {
      _children = children;
    }

    @Override
    public boolean evaluate(boolean[] singleValues, DataType[] valueTypes, Object[] valueArrays, int index) {
      for (FilterEvaluator child : _children) {
        if (!child.evaluate(singleValues, valueTypes, valueArrays, index)) {
          return false;
        }
      }
      return true;
    }
  }

  private static class OrFilterEvaluator implements FilterEvaluator {
    final List<FilterEvaluator> _children;

    private OrFilterEvaluator(List<FilterEvaluator> children) {
      _children = children;
    }

    @Override
    public boolean evaluate(boolean[] singleValues, DataType[] valueTypes, Object[] valueArrays, int index) {
      for (FilterEvaluator child : _children) {
        if (child.evaluate(singleValues, valueTypes, valueArrays, index)) {
          return true;
        }
      }
      return false;
    }
  }

  private static class PredicateFilterEvaluator implements FilterEvaluator {
    final Predicate _predicate;
    final int _expressionIndex;
    PredicateEvaluator _predicateEvaluator;

    private PredicateFilterEvaluator(Predicate predicate, int expressionIndex) {
      _predicate = predicate;
      _expressionIndex = expressionIndex;
    }

    @Override
    public boolean evaluate(boolean[] singleValues, DataType[] valueTypes, Object[] valueArrays, int index) {
      boolean singleValue = singleValues[_expressionIndex];
      DataType valueType = valueTypes[_expressionIndex];
      Object valueArray = valueArrays[_expressionIndex];
      if (_predicateEvaluator == null) {
        _predicateEvaluator = PredicateEvaluatorProvider.getPredicateEvaluator(_predicate, null, valueType);
      }
      if (singleValue) {
        switch (valueType) {
          case INT:
            return _predicateEvaluator.applySV(((int[]) valueArray)[index]);
          case LONG:
            return _predicateEvaluator.applySV(((long[]) valueArray)[index]);
          case FLOAT:
            return _predicateEvaluator.applySV(((float[]) valueArray)[index]);
          case DOUBLE:
            return _predicateEvaluator.applySV(((double[]) valueArray)[index]);
          case STRING:
            return _predicateEvaluator.applySV(((String[]) valueArray)[index]);
          case BYTES:
            return _predicateEvaluator.applySV(((byte[][]) valueArray)[index]);
          default:
            throw new IllegalStateException();
        }
      } else {
        switch (valueType) {
          case INT:
            int[] intValues = ((int[][]) valueArray)[index];
            return _predicateEvaluator.applyMV(intValues, intValues.length);
          case LONG:
            long[] longValues = ((long[][]) valueArray)[index];
            return _predicateEvaluator.applyMV(longValues, longValues.length);
          case FLOAT:
            float[] floatValues = ((float[][]) valueArray)[index];
            return _predicateEvaluator.applyMV(floatValues, floatValues.length);
          case DOUBLE:
            double[] doubleValues = ((double[][]) valueArray)[index];
            return _predicateEvaluator.applyMV(doubleValues, doubleValues.length);
          case STRING:
            String[] stringValues = ((String[][]) valueArray)[index];
            return _predicateEvaluator.applyMV(stringValues, stringValues.length);
          default:
            throw new IllegalStateException();
        }
      }
    }
  }
}