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

package com.google.api.ads.adwords.awreporting.model.entities;

import com.google.api.ads.adwords.awreporting.model.csv.annotation.CsvField;
import com.google.api.ads.adwords.awreporting.model.csv.annotation.MoneyField;
import com.google.api.ads.adwords.awreporting.model.entities.dateranges.DateRangeHandler;
import com.google.api.ads.adwords.awreporting.model.entities.dateranges.Last14DaysDateRangeHandler;
import com.google.api.ads.adwords.awreporting.model.entities.dateranges.Last30DaysDateRangeHandler;
import com.google.api.ads.adwords.awreporting.model.entities.dateranges.Last7DaysDateRangeHandler;
import com.google.api.ads.adwords.awreporting.model.entities.dateranges.LastMonthDateRangeHandler;
import com.google.api.ads.adwords.awreporting.model.entities.dateranges.LastWeekDateRangeHandler;
import com.google.api.ads.adwords.awreporting.model.entities.dateranges.ThisMonthDateRangeHandler;
import com.google.api.ads.adwords.awreporting.model.entities.dateranges.TodayDateRangeHandler;
import com.google.api.ads.adwords.awreporting.model.entities.dateranges.YesterdayDateRangeHandler;
import com.google.api.ads.adwords.awreporting.model.util.BigDecimalUtil;
import com.google.api.ads.adwords.awreporting.model.util.DateUtil;
import com.google.api.ads.adwords.lib.jaxb.v201506.ReportDefinitionDateRangeType;
import com.google.api.client.util.Maps;

import com.googlecode.objectify.annotation.Index;

import org.joda.time.DateTime;

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

import javax.persistence.Column;
import javax.persistence.MappedSuperclass;

/**
 * The base abstract class with base report fields
 *
 *  Fields from http://code.google.com/apis/adwords/docs/appendix/reports.html Fields from
 * http://code.google.com/apis/adwords/docs/reportguide.html
 *
 * @author jtoledo@google.com (Julian Toledo)
 * @author gustavomoreira@google.com (Gustavo Moreira)
 */
@MappedSuperclass
public abstract class ReportBase extends Report {

  public static final String DAYOFWEEK = "dayOfWeek";
  public static final String WEEK = "week";
  public static final String MONTH = "month";
  public static final String QUARTER = "quarter";
  public static final String YEAR = "year";

  // General
  @Column(name = "ACCOUNT_DESCRIPTIVE_NAME", length = 255)
  @CsvField(value = "Account", reportField = "AccountDescriptiveName")
  protected String accountDescriptiveName;

  @Column(name = "ACCOUNTTIMEZONEID")
  @CsvField(value = "Time zone", reportField = "AccountTimeZoneId")
  protected String accountTimeZoneId;

  @Column(name = "CUSTOMER_DESCRIPTIVE_NAME")
  @CsvField(value = "Client name", reportField = "CustomerDescriptiveName")
  protected String customerDescriptiveName;

  @Column(name = "PRIMARYCOMPANYNAME")
  @CsvField(value = "Company name", reportField = "PrimaryCompanyName")
  protected String primaryCompanyName;

  @Column(name = "CURRENCY_CODE", length = 6)
  @CsvField(value = "Currency", reportField = "AccountCurrencyCode")
  protected String currencyCode;

  // Date Segments
  @Index
  @Column(name = "DAY")
  @CsvField(value = "Day", reportField = "Date")
  protected Date day;

  @Column(name = "DAYOFWEEK")
  @CsvField(value = "Day of week", reportField = "DayOfWeek")
  protected String dayOfWeek;

  @Column(name = "WEEK")
  @CsvField(value = "Week", reportField = "Week")
  protected String week;

  @Index
  @Column(name = "MONTH")
  @CsvField(value = "Month", reportField = "Month")
  protected Date month;

  @Column(name = "MONTH_OF_YEAR")
  @CsvField(value = "Month of Year", reportField = "MonthOfYear")
  protected String monthOfYear;

  @Column(name = "QUARTER")
  @CsvField(value = "Quarter", reportField = "Quarter")
  private String quarter;

  @Column(name = "YEAR")
  @CsvField(value = "Year", reportField = "Year")
  protected Long year;

  // Main Metrics
  @Column(name = "COST")
  @CsvField(value = "Cost", reportField = "Cost")
  @MoneyField
  protected BigDecimal cost;

  @Column(name = "CLICKS")
  @CsvField(value = "Clicks", reportField = "Clicks")
  protected Long clicks;

  @Column(name = "IMPRESSIONS")
  @CsvField(value = "Impressions", reportField = "Impressions")
  protected Long impressions;

  @Column(name = "CTR")
  @CsvField(value = "CTR", reportField = "Ctr")
  protected BigDecimal ctr;

  @Column(name = "AVERAGE_CPM")
  @CsvField(value = "Avg. CPM", reportField = "AverageCpm")
  @MoneyField
  protected BigDecimal avgCpm;

  @Column(name = "AVERAGE_CPC")
  @CsvField(value = "Avg. CPC", reportField = "AverageCpc")
  @MoneyField
  protected BigDecimal avgCpc;

  @Column(name = "AVERAGE_POSITION")
  @CsvField(value = "Avg. position", reportField = "AveragePosition")
  protected BigDecimal avgPosition;

  // Main Segments
  @Column(name = "DEVICE", length = 64)
  @CsvField(value = "Device", reportField = "Device")
  protected String device;

  @Column(name = "CLICK_TYPE", length = 64)
  @CsvField(value = "Click type", reportField = "ClickType")
  protected String clickType;

  @Column(name = "NETWORK", length = 32)
  @CsvField(value = "Network", reportField = "AdNetworkType1")
  protected String adNetwork;

  @Column(name = "NETWORK_PARTNERS", length = 32)
  @CsvField(value = "Network (with search partners)", reportField = "AdNetworkType2")
  protected String adNetworkPartners;

  // Conversion Columns
  // Many Per Click
  @Column(name = "CONVERSIONSMANYPERCLICK")
  @CsvField(value = "Conversions", reportField = "ConversionsManyPerClick")
  protected Long conversionsManyPerClick = 0L;

  @Column(name = "CONVERSIONRATEMANYPERCLICK")
  @CsvField(value = "Conv. rate", reportField = "ConversionRateManyPerClick")
  protected BigDecimal conversionRateManyPerClick;

  @Column(name = "COSTPERCONVERSIONMANYPERCLICK")
  @CsvField(value = "Cost / conv.", reportField = "CostPerConversionManyPerClick")
  @MoneyField
  protected BigDecimal costPerConversionManyPerClick;

  @Column(name = "VALUEPERCONVERSIONMANYPERCLICK")
  @CsvField(value = "Value / conv.", reportField = "ValuePerConversionManyPerClick")
  protected BigDecimal valuePerConversionManyPerClick;

  // One Per Click
  @Column(name = "CONVERTEDCLICKS")
  @CsvField(value = "Converted clicks", reportField = "ConvertedClicks")
  protected Long convertedClicks = 0L;

  @Column(name = "CLICKCONVERSIONRATE")
  @CsvField(value = "Click conversion rate", reportField = "ClickConversionRate")
  protected BigDecimal clickConversionRate;

  @Column(name = "COSTPERCONVERTEDCLICK")
  @CsvField(value = "Cost / converted click", reportField = "CostPerConvertedClick")
  @MoneyField
  protected BigDecimal costPerConvertedClick;

  @Column(name = "VALUEPERCONVERTEDCLICK")
  @CsvField(value = "Value / converted click", reportField = "ValuePerConvertedClick")
  protected BigDecimal valuePerConvertedClick;

  // General
  @Column(name = "CONVERSIONCATEGORYNAME")
  @CsvField(value = "Conversion category", reportField = "ConversionCategoryName")
  protected String conversionCategoryName;

  @Column(name = "CONVERSIONTYPENAME")
  @CsvField(value = "Conversion name", reportField = "ConversionTypeName")
  protected String conversionTypeName;

  @Column(name = "CONVERSIONVALUE")
  @CsvField(value = "Total conv. value", reportField = "ConversionValue")
  protected BigDecimal conversionValue;

  @Column(name = "VIEWTHROUGHCONVERSIONS")
  @CsvField(value = "View-through conv.", reportField = "ViewThroughConversions")
  protected Long viewThroughConversions = 0L;

  private static final Map<String, DateRangeHandler> dateRangeHandlers = Maps.newHashMap();

  static {
    dateRangeHandlers.put(ReportDefinitionDateRangeType.LAST_14_DAYS.name(),
        new Last14DaysDateRangeHandler());
    dateRangeHandlers.put(ReportDefinitionDateRangeType.LAST_30_DAYS.name(),
        new Last30DaysDateRangeHandler());
    dateRangeHandlers.put(ReportDefinitionDateRangeType.LAST_7_DAYS.name(),
        new Last7DaysDateRangeHandler());
    dateRangeHandlers.put(ReportDefinitionDateRangeType.LAST_MONTH.name(),
        new LastMonthDateRangeHandler());
    dateRangeHandlers.put(ReportDefinitionDateRangeType.LAST_WEEK.name(),
        new LastWeekDateRangeHandler());
    dateRangeHandlers.put(ReportDefinitionDateRangeType.THIS_MONTH.name(),
        new ThisMonthDateRangeHandler());
    dateRangeHandlers.put(ReportDefinitionDateRangeType.TODAY.name(), new TodayDateRangeHandler());
    dateRangeHandlers.put(ReportDefinitionDateRangeType.YESTERDAY.name(),
        new YesterdayDateRangeHandler());
  }

  /**
   * Hibernate needs an empty constructor
   */
  public ReportBase() {
    timestamp = new DateTime().toDate();
  }

  public ReportBase(Long topAccountId, Long accountId) {
    this.topAccountId = topAccountId;
    this.accountId = accountId;
    timestamp = new DateTime().toDate();
  }

  @Override
  public abstract void setId();

  @Override
  public String setIdDates() {
    // Time Segments
    if (this.getDay() != null) {
      return "-" + this.getDay();
    }
    if (this.getMonth() != null) {
      return "-" + DateUtil.formatYearMonth(this.getMonthDateTime());
    }
    if (this.getDayOfWeek() != null) {
      return "-" + this.getDayOfWeek();
    }
    if (this.getWeek() != null) {
      return "-" + this.getWeek();
    }
    if (this.getQuarter() != null) {
      return "-" + this.getQuarter();
    }
    if (this.getMonthOfYear() != null) {
      return "-" + this.getMonthOfYear();
    }
    if (this.getYear() != null) {
      return "-" + this.getYear();
    }

    if (this.getDateRangeType() != null) {
      DateRangeHandler handler = dateRangeHandlers.get(this.getDateRangeType());
      if (handler != null) {
        this.setMonth(handler.retrieveMonth(DateTime.now()));
        this.setDateStart(DateUtil.formatYearMonthDay(handler.retrieveDateStart(DateTime.now())));
        this.setDateEnd(DateUtil.formatYearMonthDay(handler.retrieveDateEnd(DateTime.now())));
      }
    }
    if (this.getDateStart() != null && this.getDateEnd() != null) {
      return "-" + this.getDateStart() + "-" + this.getDateEnd();
    }
    return "";
  }

  public String getDay() {
    if (day != null) {
      return DateUtil.formatYearMonthDay(day);
    } else {
      return null;
    }
  }

  public void setDay(DateTime day) {
    this.day = new DateTime(day).toDate();
  }

  public void setDay(String day) {
    try {
      DateTime parseDateTime = DateUtil.parseDateTime(day);
      if (parseDateTime != null) {
        this.day = parseDateTime.toDate();
      }
    } catch (IllegalArgumentException e) {
      this.day = null;
    }
  }

  public String getMonth() {
    if (month != null) {
      return DateUtil.formatYearMonthDay(month);
    } else {
      return null;
    }
  }

  public DateTime getMonthDateTime() {
    return new DateTime(month);
  }

  public void setMonth(DateTime month) {
    this.month = new DateTime(month).toDate();
  }

  public void setMonth(String month) {
    try {
      DateTime parseDateTime = DateUtil.parseDateTime(month);
      if (parseDateTime != null) {
        this.month = parseDateTime.toDate();
      }
    } catch (IllegalArgumentException e) {
      this.month = null;
    }
  }

  public String getMonthOfYear() {
    return monthOfYear;
  }

  public void setMonthOfYear(String monthOfYear) {
    this.monthOfYear = monthOfYear;
  }

  public String getDayOfWeek() {
    return dayOfWeek;
  }

  public void setDayOfWeek(String dayOfWeek) {
    this.dayOfWeek = dayOfWeek;
  }

  public String getWeek() {
    return week;
  }

  public void setWeek(String week) {
    this.week = week;
  }

  public String getQuarter() {
    return quarter;
  }

  public void setQuarter(String quarter) {
    this.quarter = quarter;
  }

  public Long getYear() {
    return year;
  }

  public void setYear(Long year) {
    this.year = year;
  }

  public void setCtr(BigDecimal ctr) {
    this.ctr = ctr;
  }

  public void setAvgCpm(BigDecimal avgCpm) {
    this.avgCpm = avgCpm;
  }

  public void setAvgCpc(BigDecimal avgCpc) {
    this.avgCpc = avgCpc;
  }

  public void setAvgPosition(BigDecimal avgPosition) {
    this.avgPosition = avgPosition;
  }

  public String getAccountDescriptiveName() {
    return accountDescriptiveName;
  }

  public void setAccountDescriptiveName(String accountDescriptiveName) {
    this.accountDescriptiveName = accountDescriptiveName;
  }

  public String getAccountTimeZoneId() {
    return accountTimeZoneId;
  }

  public void setAccountTimeZoneId(String accountTimeZoneId) {
    this.accountTimeZoneId = accountTimeZoneId;
  }

  public String getPrimaryCompanyName() {
    return primaryCompanyName;
  }

  public void setPrimaryCompanyName(String primaryCompanyName) {
    this.primaryCompanyName = primaryCompanyName;
  }

  public String getCustomerDescriptiveName() {
    return customerDescriptiveName;
  }

  public void setCustomerDescriptiveName(String customerDescriptiveName) {
    this.customerDescriptiveName = customerDescriptiveName;
  }

  public BigDecimal getCost() {
    return cost;
  }

  public void setCost(BigDecimal cost) {
    this.cost = cost;
  }

  public Long getClicks() {
    return clicks;
  }

  public void setClicks(Long clicks) {
    this.clicks = clicks;
  }

  public Long getImpressions() {
    return impressions;
  }

  public void setImpressions(Long impressions) {
    this.impressions = impressions;
  }

  public String getCtr() {
    return BigDecimalUtil.formatAsReadable(ctr);
  }

  public BigDecimal getCtrBigDecimal() {
    return ctr;
  }

  public void setCtr(String ctr) {
    // removing percentage symbol from the string
    if (ctr != null) {
      String replace = ctr.replace("%", "");
      this.ctr = BigDecimalUtil.parseFromNumberString(replace);
    }
  }

  public BigDecimal getAvgCpm() {
    return avgCpm;
  }

  public BigDecimal getAvgCpc() {
    return avgCpc;
  }

  public String getAvgPosition() {
    return BigDecimalUtil.formatAsReadable(avgPosition);
  }

  public BigDecimal getAvgPositionBigDecimal() {
    return avgPosition;
  }

  public void setAvgPosition(String avgPosition) {
    this.avgPosition = BigDecimalUtil.parseFromNumberString(avgPosition);
  }

  public String getCurrencyCode() {
    return currencyCode;
  }

  public void setCurrencyCode(String currencyCode) {
    this.currencyCode = currencyCode;
  }

  public String getDevice() {
    return device;
  }

  public void setDevice(String device) {
    this.device = device;
  }

  public String getClickType() {
    return clickType;
  }

  public void setClickType(String clickType) {
    this.clickType = clickType;
  }

  public String getAdNetwork() {
    return adNetwork;
  }

  public void setAdNetwork(String adNetwork) {
    this.adNetwork = adNetwork;
  }

  public String getAdNetworkPartners() {
    return adNetworkPartners;
  }

  public void setAdNetworkPartners(String adNetworkPartners) {
    this.adNetworkPartners = adNetworkPartners;
  }

  // Conversion Columns
  public Long getConvertedClicks() {
    return convertedClicks;
  }

  public void setConvertedClicks(Long convertedClicks) {
    this.convertedClicks = convertedClicks;
  }

  public Long getConversionsManyPerClick() {
    return conversionsManyPerClick;
  }

  public void setConversionsManyPerClick(Long conversionsManyPerClick) {
    this.conversionsManyPerClick = conversionsManyPerClick;
  }

  public String getConversionRateManyPerClick() {
    return BigDecimalUtil.formatAsReadable(conversionRateManyPerClick);
  }

  public BigDecimal getConversionRateManyPerClickBigDecimal() {
    return conversionRateManyPerClick;
  }

  public void setConversionRateManyPerClick(String conversionRateManyPerClick) {
    this.conversionRateManyPerClick =
        BigDecimalUtil.parseFromNumberString(conversionRateManyPerClick);
  }

  public BigDecimal getCostPerConversionManyPerClick() {
    return costPerConversionManyPerClick;
  }

  public void setCostPerConversionManyPerClick(BigDecimal costPerConversionManyPerClick) {
    this.costPerConversionManyPerClick = costPerConversionManyPerClick;
  }

  public String getValuePerConversionManyPerClick() {
    return BigDecimalUtil.formatAsReadable(valuePerConversionManyPerClick);
  }

  public BigDecimal getValuePerConversionManyPerClickBigDecimal() {
    return valuePerConversionManyPerClick;
  }

  public void setValuePerConversionManyPerClick(String valuePerConversionManyPerClick) {
    this.valuePerConversionManyPerClick =
        BigDecimalUtil.parseFromNumberString(valuePerConversionManyPerClick);
  }

  public String getClickConversionRate() {
    return BigDecimalUtil.formatAsReadable(clickConversionRate);
  }

  public BigDecimal getClickConversionRateBigDecimal() {
    return clickConversionRate;
  }

  public void setClickConversionRate(String clickConversionRate) {
    this.clickConversionRate = BigDecimalUtil.parseFromNumberString(clickConversionRate);
  }

  public BigDecimal getCostPerConvertedClick() {
    return costPerConvertedClick;
  }

  public void setCostPerConvertedClick(BigDecimal costPerConvertedClick) {
    this.costPerConvertedClick = costPerConvertedClick;
  }

  public String getValuePerConvertedClick() {
    return BigDecimalUtil.formatAsReadable(valuePerConvertedClick);
  }

  public BigDecimal getValuePerConvertedClickBigDecimal() {
    return valuePerConvertedClick;
  }

  public void setValuePerConvertedClick(String valuePerConvertedClick) {
    this.valuePerConvertedClick = BigDecimalUtil.parseFromNumberString(valuePerConvertedClick);
  }

  public String getConversionCategoryName() {
    return conversionCategoryName;
  }

  public void setConversionCategoryName(String conversionCategoryName) {
    this.conversionCategoryName = conversionCategoryName;
  }

  public String getConversionTypeName() {
    return conversionTypeName;
  }

  public void setConversionTypeName(String conversionTypeName) {
    this.conversionTypeName = conversionTypeName;
  }

  public String getConversionValue() {
    return BigDecimalUtil.formatAsReadable(conversionValue);
  }

  public BigDecimal getConversionValueBigDecimal() {
    return conversionValue;
  }

  public void setConversionValue(String conversionValue) {
    this.conversionValue = BigDecimalUtil.parseFromNumberString(conversionValue);
  }

  public Long getViewThroughConversions() {
    return viewThroughConversions;
  }

  public void setViewThroughConversions(Long viewThroughConversions) {
    this.viewThroughConversions = viewThroughConversions;
  }

  @Override
  public int hashCode() {
    final int prime = 31;
    int result = super.hashCode();
    result = prime * result
        + ((accountDescriptiveName == null) ? 0 : accountDescriptiveName.hashCode());
    result = prime * result + ((accountTimeZoneId == null) ? 0 : accountTimeZoneId.hashCode());
    result = prime * result + ((adNetwork == null) ? 0 : adNetwork.hashCode());
    result = prime * result + ((adNetworkPartners == null) ? 0 : adNetworkPartners.hashCode());
    result = prime * result + ((avgCpc == null) ? 0 : avgCpc.hashCode());
    result = prime * result + ((avgCpm == null) ? 0 : avgCpm.hashCode());
    result = prime * result + ((avgPosition == null) ? 0 : avgPosition.hashCode());
    result = prime * result + ((clickType == null) ? 0 : clickType.hashCode());
    result = prime * result + ((clicks == null) ? 0 : clicks.hashCode());
    result = prime * result
        + ((conversionCategoryName == null) ? 0 : conversionCategoryName.hashCode());
    result = prime * result + ((clickConversionRate == null) ? 0 : clickConversionRate.hashCode());
    result = prime * result
        + ((conversionRateManyPerClick == null) ? 0 : conversionRateManyPerClick.hashCode());
    result = prime * result + ((conversionTypeName == null) ? 0 : conversionTypeName.hashCode());
    result = prime * result + ((conversionValue == null) ? 0 : conversionValue.hashCode());
    result = prime * result + ((convertedClicks == null) ? 0 : convertedClicks.hashCode());
    result = prime * result
        + ((conversionsManyPerClick == null) ? 0 : conversionsManyPerClick.hashCode());
    result = prime * result + ((cost == null) ? 0 : cost.hashCode());
    result = prime * result + ((costPerConvertedClick == null) ? 0 : costPerConvertedClick.hashCode());
    result = prime * result
        + ((costPerConversionManyPerClick == null) ? 0 : costPerConversionManyPerClick.hashCode());
    result = prime * result + ((ctr == null) ? 0 : ctr.hashCode());
    result = prime * result + ((currencyCode == null) ? 0 : currencyCode.hashCode());
    result = prime * result
        + ((customerDescriptiveName == null) ? 0 : customerDescriptiveName.hashCode());
    result = prime * result + ((day == null) ? 0 : day.hashCode());
    result = prime * result + ((dayOfWeek == null) ? 0 : dayOfWeek.hashCode());
    result = prime * result + ((device == null) ? 0 : device.hashCode());
    result = prime * result + ((impressions == null) ? 0 : impressions.hashCode());
    result = prime * result + ((month == null) ? 0 : month.hashCode());
    result = prime * result + ((monthOfYear == null) ? 0 : monthOfYear.hashCode());
    result = prime * result + ((primaryCompanyName == null) ? 0 : primaryCompanyName.hashCode());
    result = prime * result + ((quarter == null) ? 0 : quarter.hashCode());
    result = prime * result + ((valuePerConvertedClick == null) ? 0 : valuePerConvertedClick.hashCode());
    result = prime
        * result
        + ((valuePerConversionManyPerClick == null) ? 0 : valuePerConversionManyPerClick.hashCode());
    result = prime * result
        + ((viewThroughConversions == null) ? 0 : viewThroughConversions.hashCode());
    result = prime * result + ((week == null) ? 0 : week.hashCode());
    result = prime * result + ((year == null) ? 0 : year.hashCode());
    return result;
  }

  @Override
  public boolean equals(Object obj) {
    if (this == obj)
      return true;
    if (!super.equals(obj))
      return false;
    if (getClass() != obj.getClass())
      return false;
    ReportBase other = (ReportBase) obj;
    if (accountDescriptiveName == null) {
      if (other.accountDescriptiveName != null)
        return false;
    } else if (!accountDescriptiveName.equals(other.accountDescriptiveName))
      return false;
    if (accountTimeZoneId == null) {
      if (other.accountTimeZoneId != null)
        return false;
    } else if (!accountTimeZoneId.equals(other.accountTimeZoneId))
      return false;
    if (adNetwork == null) {
      if (other.adNetwork != null)
        return false;
    } else if (!adNetwork.equals(other.adNetwork))
      return false;
    if (adNetworkPartners == null) {
      if (other.adNetworkPartners != null)
        return false;
    } else if (!adNetworkPartners.equals(other.adNetworkPartners))
      return false;
    if (avgCpc == null) {
      if (other.avgCpc != null)
        return false;
    } else if (!avgCpc.equals(other.avgCpc))
      return false;
    if (avgCpm == null) {
      if (other.avgCpm != null)
        return false;
    } else if (!avgCpm.equals(other.avgCpm))
      return false;
    if (avgPosition == null) {
      if (other.avgPosition != null)
        return false;
    } else if (!avgPosition.equals(other.avgPosition))
      return false;
    if (clickType == null) {
      if (other.clickType != null)
        return false;
    } else if (!clickType.equals(other.clickType))
      return false;
    if (clicks == null) {
      if (other.clicks != null)
        return false;
    } else if (!clicks.equals(other.clicks))
      return false;
    if (conversionCategoryName == null) {
      if (other.conversionCategoryName != null)
        return false;
    } else if (!conversionCategoryName.equals(other.conversionCategoryName))
      return false;
    if (clickConversionRate == null) {
      if (other.clickConversionRate != null)
        return false;
    } else if (!clickConversionRate.equals(other.clickConversionRate))
      return false;
    if (conversionRateManyPerClick == null) {
      if (other.conversionRateManyPerClick != null)
        return false;
    } else if (!conversionRateManyPerClick.equals(other.conversionRateManyPerClick))
      return false;
    if (conversionTypeName == null) {
      if (other.conversionTypeName != null)
        return false;
    } else if (!conversionTypeName.equals(other.conversionTypeName))
      return false;
    if (conversionValue == null) {
      if (other.conversionValue != null)
        return false;
    } else if (!conversionValue.equals(other.conversionValue))
      return false;
    if (convertedClicks == null) {
      if (other.convertedClicks != null)
        return false;
    } else if (!convertedClicks.equals(other.convertedClicks))
      return false;
    if (conversionsManyPerClick == null) {
      if (other.conversionsManyPerClick != null)
        return false;
    } else if (!conversionsManyPerClick.equals(other.conversionsManyPerClick))
      return false;
    if (cost == null) {
      if (other.cost != null)
        return false;
    } else if (!cost.equals(other.cost))
      return false;
    if (costPerConvertedClick == null) {
      if (other.costPerConvertedClick != null)
        return false;
    } else if (!costPerConvertedClick.equals(other.costPerConvertedClick))
      return false;
    if (costPerConversionManyPerClick == null) {
      if (other.costPerConversionManyPerClick != null)
        return false;
    } else if (!costPerConversionManyPerClick.equals(other.costPerConversionManyPerClick))
      return false;
    if (ctr == null) {
      if (other.ctr != null)
        return false;
    } else if (!ctr.equals(other.ctr))
      return false;
    if (currencyCode == null) {
      if (other.currencyCode != null)
        return false;
    } else if (!currencyCode.equals(other.currencyCode))
      return false;
    if (customerDescriptiveName == null) {
      if (other.customerDescriptiveName != null)
        return false;
    } else if (!customerDescriptiveName.equals(other.customerDescriptiveName))
      return false;
    if (day == null) {
      if (other.day != null)
        return false;
    } else if (!day.equals(other.day))
      return false;
    if (dayOfWeek == null) {
      if (other.dayOfWeek != null)
        return false;
    } else if (!dayOfWeek.equals(other.dayOfWeek))
      return false;
    if (device == null) {
      if (other.device != null)
        return false;
    } else if (!device.equals(other.device))
      return false;
    if (impressions == null) {
      if (other.impressions != null)
        return false;
    } else if (!impressions.equals(other.impressions))
      return false;
    if (month == null) {
      if (other.month != null)
        return false;
    } else if (!month.equals(other.month))
      return false;
    if (monthOfYear == null) {
      if (other.monthOfYear != null)
        return false;
    } else if (!monthOfYear.equals(other.monthOfYear))
      return false;
    if (primaryCompanyName == null) {
      if (other.primaryCompanyName != null)
        return false;
    } else if (!primaryCompanyName.equals(other.primaryCompanyName))
      return false;
    if (quarter == null) {
      if (other.quarter != null)
        return false;
    } else if (!quarter.equals(other.quarter))
      return false;
    if (valuePerConvertedClick == null) {
      if (other.valuePerConvertedClick != null)
        return false;
    } else if (!valuePerConvertedClick.equals(other.valuePerConvertedClick))
      return false;
    if (valuePerConversionManyPerClick == null) {
      if (other.valuePerConversionManyPerClick != null)
        return false;
    } else if (!valuePerConversionManyPerClick.equals(other.valuePerConversionManyPerClick))
      return false;
    if (viewThroughConversions == null) {
      if (other.viewThroughConversions != null)
        return false;
    } else if (!viewThroughConversions.equals(other.viewThroughConversions))
      return false;
    if (week == null) {
      if (other.week != null)
        return false;
    } else if (!week.equals(other.week))
      return false;
    if (year == null) {
      if (other.year != null)
        return false;
    } else if (!year.equals(other.year))
      return false;
    return true;
  }
}


text:
"use strict";

var Class = require('ouro-base');

module.exports = Class.extend({

  init: function(code, message, additional) {

    //maintain reference to instance
    var self = this;

    this.code = code;
    this.message = message;

    if( typeof additional === 'object') {

      //copy all properties of this object and its prototype chain
      for( var property in additional ) {
        this[property] = additional[property];
      }

      //make sure we get non-enumerable object properties
      Object.getOwnPropertyNames(additional).map(function(property) {
        self[property] = additional[property];
      });
    }

    if( !this.stack ) {
      this.stack = new Error(message).stack;
    }

  }

});

redpajama_set_name: RedPajamaGithub


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

    window.LunchUX = window.LunchUX || {};

    function Person(options) {
        options = options || {};
        this.id = options.id || nextId();
        this.name = options.name || "";
        this.ageClass = options.ageClass || AgeClass.child;
        this.isStudent = options.isStudent;
        this.isFosterChild = options.isFosterChild;
        this.isHomeless = options.isHomeless;
        this.incomes = options.incomes || {};
    }

    Person.prototype.valid = function() {
        return this.name !== "";
    };

    Person.prototype.toString = function() {
        return this.name;
    };

    var AgeClass = {
        child: 1,
        adult: 2
    };

    var nextId = (function() {
        var id = 0;
        return function() {
            return ++id;
        };
    }());

    function Model(store) {
        this.store = store;
        this.events = new LunchUX.Event();

        this.data = store.load() || this.defaultValues();

        this.formDisplay = [];
    }

    Model.prototype.clear = function() {
        this.data = this.defaultValues();
        this.store.reset();
    };

    Model.prototype.defaultValues = function() {
        return {
            people: [],
            caseNumber: null, // null means has not said yes or no to having other help, empty string "" means no, non-empty string means yes
            last4SSN: null, // null means has not said yes or no to having an SSN, empty string "" means no, non-empty string means yes
            phone: "",
            email: "",
            street: "",
            city: "",
            state: "",
            zip: "",
            readNonDiscriminationStatement: false,
            readUseOfInformationStatement: false,
            signature: "",
            completed: {},
            isHispanic: undefined,
            isHispanicDeclined: undefined,
            races: [],
            date: null,
            id: this.getUniqueId()
        };
    };

    Model.prototype.getUniqueId = function() {
        return Math.random().toString(36).slice(2) + "-" + (new Date()).getTime().toString(36);
    };

    Model.prototype.setInitialHousehold = function() {
        this.data.people = [];
        this.data.people.push(new Person({ageClass: AgeClass.child}));
        this.data.people.push(new Person({ageClass: AgeClass.adult}));
        this.save();
    };

    Model.prototype.addPerson = function(options) {
        if (options instanceof Person) {
            this.data.people.push(options);
        } else {
            var person = new Person(options);
            this.data.people.push(person);
        }
        this.save();
        this.events.notify("addedPerson", person);
    };

    Model.prototype.deletePerson = function(person) {
        var index;
        this.data.people.forEach(function(p, i) {
            if (p === person) {
                index = i;
            }
        });
        this.data.people.splice(index, 1);
        this.save();
        this.events.notify("deletedPerson", person);
    };

    Model.prototype.all = function() {
        return this.data;
    };

    Model.prototype.reset = function() {
        this.formDisplay = [];
    };

    Model.prototype.toggleDetailsForm = function(view) {
        var state;
        var found = false;

        this.formDisplay.forEach(function(s) {
            if (s.view === view) {
                found = true;
                state = s;
            }
        }.bind(this));

        if (!found) {
            state = {view: view, show: true}; // show on initial click
            this.formDisplay.push(state);
        } else {
            state.show = !state.show;
        }

        if (state.show) {
            this.formDisplay.forEach(function(s) {
                if (s.view !== view && s.show) {
                    s.show = false;
                    this.events.notify("toggleDetailsForm", s.view, false);
                }
            }.bind(this));
        }

        this.events.notify("toggleDetailsForm", view, state.show);
    };

    Model.prototype.showDetailsForm = function(view) {
        if (!(view in this.detailsFormHidden)) {
            return false; // initially hidden
        }
        return !this.detailsFormHidden[view];
    };

    Model.prototype.kids = function() {
        return this.all().people.filter(function(person) { return person.ageClass === AgeClass.child; });
    };

    Model.prototype.adults = function() {
        return this.all().people.filter(function(person) { return person.ageClass === AgeClass.adult; });
    };

    Model.prototype.sortedHousehold = function() {
        var household = this.all().people;
        household.sort(function(a, b) {
            if (a.ageClass === b.ageClass) {
                var x = a.id;
                var y = b.id;
                return x < y ? -1 : x > y ? 1 : 0;
            }
            return a.ageClass - b.ageClass;
        });
        return household;
    };

    Model.prototype.on = function(type, handler) {
        this.events.bind(type, handler);
    };

    Model.prototype.save = function() {
        this.store.save(this.data);
        this.events.notify("saved");
    };

    Model.prototype.savePerson = function(person) {
        for (var i = 0, people = this.data.people; i < people.length; i++) {
            if (person.id === people[i].id) {
                people[i] = person;
                break;
            }
        }
        this.save();
        this.events.notify("updatedPerson", {person: person});
    };

    Model.prototype.get = function(prop) {
        return this.data[prop];
    };

    Model.prototype.set = function(prop, value) {
        this.data[prop] = value;
        this.save();
        this.events.notify("updated:" + prop);
    };

    Model.prototype.hasExistingSession = function() {
        return this.get("people").length > 0;
    };

    window.LunchUX.Model = Model;
    window.LunchUX.Person = Person;
    window.LunchUX.AgeClass = AgeClass;
}());


text:
package org.intellij.lang.xpath.xslt.impl;

import com.intellij.ide.highlighter.XmlFileType;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.JarFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.xml.XmlTag;
import com.intellij.util.indexing.*;
import com.intellij.util.io.DataExternalizer;
import com.intellij.util.io.EnumDataDescriptor;
import com.intellij.util.io.EnumeratorStringDescriptor;
import com.intellij.util.io.KeyDescriptor;
import com.intellij.util.text.CharArrayUtil;
import com.intellij.util.xml.NanoXmlBuilder;
import com.intellij.util.xml.NanoXmlUtil;
import org.intellij.lang.xpath.xslt.XsltSupport;
import org.intellij.lang.xpath.xslt.psi.*;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

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

public final class XsltSymbolIndex extends FileBasedIndexExtension<String, XsltSymbolIndex.Kind> {
  @NonNls
  public static final ID<String, Kind> NAME = ID.create("XsltSymbolIndex");

  @Override
  @NotNull
  public ID<String, Kind> getName() {
    return NAME;
  }

  @Override
  @NotNull
  public DataIndexer<String, Kind, FileContent> getIndexer() {
    return new DataIndexer<>() {
      @Override
      @NotNull
      public Map<String, Kind> map(@NotNull FileContent inputData) {
        CharSequence inputDataContentAsText = inputData.getContentAsText();
        if (CharArrayUtil.indexOf(inputDataContentAsText, XsltSupport.XSLT_NS, 0) == -1) {
          return Collections.emptyMap();
        }
        final Map<String, Kind> map = new HashMap<>();
        NanoXmlUtil.parse(CharArrayUtil.readerFromCharSequence(inputData.getContentAsText()), new NanoXmlBuilder() {
          NanoXmlBuilder attributeHandler;
          int depth;

          @Override
          public void addAttribute(String key, String nsPrefix, String nsURI, String value, String type) throws Exception {
            if (attributeHandler != null) {
              attributeHandler.addAttribute(key, nsPrefix, nsURI, value, type);
            }
          }

          @Override
          public void startElement(String name, String nsPrefix, String nsURI, String systemID, int lineNr) {
            attributeHandler = null;
            if (depth == 1 && XsltSupport.XSLT_NS.equals(nsURI)) {
              if ("template".equals(name)) {
                attributeHandler = new MyAttributeHandler(map, Kind.TEMPLATE);
              }
              else if ("variable".equals(name)) {
                attributeHandler = new MyAttributeHandler(map, Kind.VARIABLE);
              }
              else if ("param".equals(name)) {
                attributeHandler = new MyAttributeHandler(map, Kind.PARAM);
              }
            }
            depth++;
          }

          @Override
          public void endElement(String name, String nsPrefix, String nsURI) {
            attributeHandler = null;
            depth--;
          }
        });
        return map;
      }
    };
  }

  @NotNull
  @Override
  public DataExternalizer<Kind> getValueExternalizer() {
    return new EnumDataDescriptor<>(Kind.class);
  }

  @NotNull
  @Override
  public KeyDescriptor<String> getKeyDescriptor() {
    return EnumeratorStringDescriptor.INSTANCE;
  }

  @NotNull
  @Override
  public FileBasedIndex.InputFilter getInputFilter() {
    return new DefaultFileTypeSpecificInputFilter(XmlFileType.INSTANCE) {
      @Override
      public boolean acceptInput(@NotNull VirtualFile file) {
        return !(file.getFileSystem() instanceof JarFileSystem);
      }
    };
  }

  @Override
  public boolean dependsOnFileContent() {
    return true;
  }

  @Override
  public int getVersion() {
    return 0;
  }

  enum Kind {
    PARAM(XsltParameter.class), VARIABLE(XsltVariable.class), TEMPLATE(XsltTemplate.class), ANYTHING(null);

    final Class<? extends XsltElement> myClazz;

    Kind(Class<? extends XsltElement> clazz) {
      myClazz = clazz;
    }

    @Nullable
    public XsltElement wrap(XmlTag tag) {
      final Class<? extends XsltElement> clazz;
      if (myClazz != null) {
        if (!StringUtil.toLowerCase(name()).equals(tag.getLocalName())) {
          return null;
        }
        clazz = myClazz;
      }
      else {
        try {
          clazz = valueOf(StringUtil.toUpperCase(tag.getLocalName())).myClazz;
        }
        catch (IllegalArgumentException e) {
          return null;
        }
      }
      return XsltElementFactory.getInstance().wrapElement(tag, clazz);
    }
  }

  private static class MyAttributeHandler implements NanoXmlBuilder {
    private final Map<String, Kind> myMap;
    private final Kind myKind;

    MyAttributeHandler(Map<String, Kind> map, Kind k) {
      myMap = map;
      myKind = k;
    }

    @Override
    public void addAttribute(String key, String nsPrefix, String nsURI, String value, String type) {
      if (key.equals("name") && (nsURI == null || nsURI.length() == 0) && value != null) {
        if (myMap.put(value, myKind) != null) {
          myMap.put(value, Kind.ANYTHING);
        }
      }
    }
  }
}


text:
class ServerConnection < Multiconnect::Connection::Base

  def report_error(e)
    Honeybadger.notify(e)
  end

  def request(action, *args)
    client_args = args.deep_dup
    result = self.client.send action, *client_args

    if result.is_a? JsonApiClient::Scope
      result = result.all
    end

    result

  rescue JsonApiClient::Errors::NotFound => e
    result = JsonApiClient::ResultSet.new

    result.meta = {status: status}

    result.errors = ActiveModel::Errors.new(result)
    result.errors.add("NofFound", e.message)

    result
  end
end

class CacheFallbackConnection < Multiconnect::Connection::Base

  def report_error(e)
  end

  def request(action, *args)
    key = sorted_args(args)
    Rails.cache.fetch key
  end
end

class CacheFirstToCircuitBreakerServerConnection < CircuitBreakerServerConnection

  def report_error(e)
    Honeybadger.notify(e)
    InfluxDB.notify(e)
  end

  def request(action, *args)
    key = key_from_args( *args )
    Rails.cache.fetch key do
      super
    end
  end

  private

  def key_from_args( *args )
    # downcase everything and sort the keys alpabetically so that {q: "dui", loc: "seattle"} is the same as {loc:"seattle", q: "dui"}
  end
end

class CircuitBreakerServerConnection < Multiconnect::Connection::Base

  def report_error(e)
    Honeybadger.notify(e)
    InfluxDB.notify(e)
  end

  def request(action, *args)
    if ready_for_request?
      client_args = args.deep_dup
      result = self.client.send action, *client_args

      if result.is_a? JsonApiClient::Scope
        result = result.all
      end

      result
    else
      raise "fall through!"
    end

  rescue JsonApiClient::Errors::NotFound => e
    result = JsonApiClient::ResultSet.new

    result.meta = {status: status}

    result.errors = ActiveModel::Errors.new(result)
    result.errors.add( "FileNotFound", e.message )

    result
  rescue => e
    @responding = false
    # default circuit broken for 30 seconds. This should probably be 1 - 2 - 5 - 15 - 30 - 1 min - 2 min*
    @timeout = 30.seconds.from.

    # propagate the error up to be handled by Connection::Base
    raise e
  end

  private

  def ready_for_request?
    @responding || Time.now > @timeout
  end
end


text:
context('Full round trip', () => {
  before(() => {
    // TODO: uncomment once Applitools work properly
    // (cy as any).eyesOpen({
    //   appName: 'books_app',
    //   testName: 'round-trip',
    //   browser: { width: 800, height: 600 },
    // });
    window.localStorage.removeItem('books_app');
    cy.visit('/');
  });

  beforeEach(() => {
    (cy as any).restoreLocalStorage();
  });

  afterEach(() => {
    (cy as any).saveLocalStorage();
  });

  after(() => {
    // TODO: uncomment once Applitools work properly
    // (cy as any).eyesClose();
  });

  it('shows a message when the credentials are wrong', () => {
    cy.findByRole('textbox', { name: /username/i })
      .clear()
      .type('wronguser');
    cy.findByLabelText(/password/i).type('supersafepassword');
    cy.findByRole('button', { name: /login/i }).click();
    // TODO: uncomment once Applitools work properly
    // (cy as any).eyesCheckWindow(
    //   'show a message when the credentials are wrong'
    // );
    cy.contains('Invalid username or password').should('be.visible');
  });

  it('is possible to login', () => {
    cy.findByRole('textbox', { name: /username/i })
      .clear()
      .type('test{enter}');
  });

  it('is possible to search for books', () => {
    cy.contains('My Collection');
    cy.findByRole('button', { name: /menu/i }).click();
    cy.findByText(/browse books/i).click();

    // TODO: uncomment once Applitools work properly
    // (cy as any).eyesCheckWindow('is possible to search for books');
    cy.findByRole('textbox', { name: /search for a book/i }).type(
      'The Alchemist'
    );
    cy.get('bc-book-preview').its('length').should('be.gte', 1);
  });

  it('is possible to add books', () => {
    cy.get('bc-book-preview').eq(2).click();

    cy.findByRole('button', { name: /add book to collection/i }).click();
    // TODO: uncomment once Applitools work properly
    // (cy as any).eyesCheckWindow('is possible to add books');
    cy.findByRole('button', { name: /add book to collection/i }).should(
      'not.exist'
    );
  });

  it('is possible to remove books', () => {
    cy.go('back');

    cy.get('bc-book-preview').eq(4).click();

    cy.findByRole('button', { name: /add book to collection/i }).click();
    cy.findByRole('button', { name: /remove book from collection/i }).click();

    // TODO: uncomment once Applitools work properly
    // (cy as any).eyesCheckWindow('is possible to remove books');
    cy.findByRole('button', { name: /remove book from collection/i }).should(
      'not.exist'
    );
  });

  it('is possible to show the collection', () => {
    cy.findByRole('button', { name: /menu/i }).click();
    cy.findByText(/my collection/i).click();

    // TODO: uncomment once Applitools work properly
    // (cy as any).eyesCheckWindow('is possible to show the collection');
    cy.get('bc-book-preview').its('length').should('be', 1);
  });

  it('is possible to sign out', () => {
    cy.findByRole('button', { name: /menu/i }).click();
    cy.findByText(/sign out/i).click();
    cy.findByRole('button', { name: /ok/i }).click();

    // TODO: uncomment once Applitools work properly
    // (cy as any).eyesCheckWindow('is possible to sign out');
    cy.findByRole('textbox', { name: /username/i }).should('exist');
    cy.findByLabelText(/password/i).should('exist');
  });
});


text:
* [A. Kefa and First Steps][]

[A. Kefa and First Steps]: http://codeforces.com/contest/580/problem/A


text:
import { NgModule } from '@angular/core';
import { ConfigurationService } from './configuration.service';
import { InstrumentationService } from './instrumentation.service';
import { StorageService } from './storage.service';

@NgModule(
    {
        providers: [
            ConfigurationService,
            InstrumentationService,
            StorageService
        ]
    })
export class CoreModule {
}