text:
from __future__ import division
from builtins import map
from builtins import zip
from builtins import range
import ROOT
from collections import defaultdict
from operator import itemgetter
from PyAnalysisTools.base import InvalidInputError, _logger
from PyAnalysisTools.PlottingUtils import Formatting as fm
from PyAnalysisTools.PlottingUtils import HistTools as ht
from PyAnalysisTools.PlottingUtils.PlotConfig import get_draw_option_as_root_str, get_style_setters_and_values
from PyAnalysisTools.PlottingUtils.PlotConfig import get_default_plot_config
from PyAnalysisTools.base.ProcessConfig import find_process_config
import PyAnalysisTools.PlottingUtils.PlotableObject as PO

def retrieve_new_canvas(name, title='', size_x=800, size_y=600):
    """
    Retrieve a new TCanvas
    :param name: canvas name
    :param title: canvas title
    :param size_x: x size
    :param size_y: y size
    :return: empty canvas
    """
    canvas = ROOT.TCanvas(name, title, size_x, size_y)
    canvas.SetRightMargin(0.07)
    ROOT.SetOwnership(canvas, False)
    return canvas

def plot_obj(obj, plot_config, **kwargs):
    """
    Base wrapper to plot an object. Based on object type appropriate plotting functions are called
    :param obj: object to plot
    :param plot_config: plot configuration
    :param kwargs: additional arguments
    :return: canvas with plotted object
    """
    if isinstance(obj, ROOT.TH2):
        return plot_2d_hist(obj, plot_config, **kwargs)
    if isinstance(obj, ROOT.TH1):
        return plot_hist(obj, plot_config, **kwargs)
    if isinstance(obj, ROOT.TEfficiency) or isinstance(obj, ROOT.TGraph):
        return plot_graph(obj, plot_config, **kwargs)

def project_hist(tree, hist, var_name, cut_string='', weight=None, is_data=False):
    if cut_string is None:
        cut_string = ''
    if weight:
        if 'MC:' in weight:
            weight = weight.split('*')
            mc_weights = [w for w in weight if 'MC:' in w]
            for mc_w in mc_weights:
                weight.remove(mc_w)
            weight = '*'.join(weight)
            if not is_data:
                mc_weights = [mc_w.replace('MC:', '') for mc_w in mc_weights]
                for mc_w in mc_weights:
                    weight += '* {:s}'.format(mc_w)
        if 'DATA:' in weight:
            weight = weight.split('*')
            data_weights = [w for w in weight if 'DATA:' in w]
            for data_w in data_weights:
                weight.remove(data_w)
            weight = '*'.join(weight)
            if is_data:
                data_weights = [data_w.replace('DATA:', '') for data_w in data_weights]
                for data_w in data_weights:
                    weight += '* {:s}'.format(data_w)
        if cut_string == '':
            cut_string = weight
        else:
            cut_string = '%s * (%s)' % (weight, cut_string)
    n_selected_events = tree.Project(hist.GetName(), var_name, cut_string)
    _logger.debug("Selected %i events from tree %s for distribution %s and cut %s." % (n_selected_events,
                                                                                tree.GetName(),
                                                                                var_name,
                                                                                cut_string))
    if n_selected_events != hist.GetEntries():
        _logger.error("No of selected events does not match histogram entries. Probably FileHandle has been "
                      "initialised after histogram definition has been received")
        raise RuntimeError("Inconsistency in TTree::Project")
    if n_selected_events == -1:
        _logger.error("Unable to project {:s} from tree {:s} with cut {:s}".format(var_name, tree.GetName(),
                                                                                cut_string))
        raise RuntimeError("TTree::Project failed")
    return hist

def plot_objects(objects, plot_config, process_configs=None):
    """
    Base interface to plot multiple objects

    :param objects: objects to be plotted, e.g. TH1, TEfficiency
    :type objects: list or dict
    :param plot_config: plot configuration
    :type plot_config: PlotConfig
    :param process_configs: physics processes configuration containing e.g. colors and plot styles
    :type process_configs: ProcessConfig
    :return: canvas with plotted objects
    :rtype: TCanvas
    """
    if len(objects) == 0:
        _logger.warning("Requested plot objects with zero objects")
        return
    if isinstance(objects, dict):
        first_obj = list(objects.values())[0]
    elif isinstance(objects, list):
        first_obj = objects[0]
    if isinstance(first_obj, PO.PlotableObject):
        if isinstance(first_obj.plot_object, ROOT.TH1):
            return plot_histograms(objects, plot_config, process_configs)
        # if isinstance(first_obj, ROOT.TEfficiency) or isinstance(first_obj, ROOT.TGraph):
        #     return plot_graphs(objects, plot_config)
    if isinstance(first_obj, ROOT.TH1):
        return plot_histograms(objects, plot_config, process_configs)
    if isinstance(first_obj, ROOT.TEfficiency) or isinstance(first_obj, ROOT.TGraph):
        return plot_graphs(objects, plot_config)
    _logger.error("Unsupported type {:s} passed for plot_objects".format(type(list(objects.values())[0])))

def add_object_to_canvas(canvas, obj, plot_config, process_config=None, index=None):
    """
    Add an object to a canvas
    :param canvas: canvas to which the object should be added
    :type canvas: ROOT.TCanvas
    :param obj: plot object
    :type obj: ROOT.TH1, ROOT.TGraph, etc
    :param plot_config: plot configuration defining outline
    :type plot_config: PlotConfig
    :param process_config: specific process configuration (optional)
    :type process_config: ProcessConfig
    :param index: index of plot object in list of all plot objects to set specific styles like colors attached to
    plot_config (optional)
    :type index: int
    :return: nothing
    :rtype: None
    """
    if isinstance(obj, ROOT.TH1):
        add_histogram_to_canvas(canvas, obj, plot_config, process_config, index)
    if isinstance(obj, ROOT.TGraphAsymmErrors) or isinstance(obj, ROOT.TEfficiency) or isinstance(obj, ROOT.TGraph):
        add_graph_to_canvas(canvas, obj, plot_config)

def plot_hist(hist, plot_config, **kwargs):
    kwargs.setdefault("y_max", plot_config.yscale * hist.GetMaximum())
    # kwargs.setdefault("y_max", 1.1 * hist[0].GetMaximum()) - sm dev
    kwargs.setdefault("index", None)
    canvas = retrieve_new_canvas(plot_config.name, '', plot_config.canvas_size_x, plot_config.canvas_size_y)
    canvas.cd()
    ROOT.SetOwnership(hist, False)
    process_config = None
    draw_option = get_draw_option_as_root_str(plot_config, process_config)
    hist = format_obj(hist, plot_config)
    hist.Draw(draw_option)
    hist.SetMarkerSize(0.7)
    fm.apply_style(hist, plot_config, process_config, index=kwargs["index"])
    if plot_config.ymin is not None:
        fm.set_minimum_y(hist, plot_config.ymin)
    if plot_config.ymax is not None:
        fm.set_maximum_y(hist, plot_config.ymax)
    if plot_config.logy:
        hist.SetMaximum(hist.GetMaximum() * plot_config.yscale_log)
        if plot_config.ymin:
            hist.SetMinimum(max(0.1, plot_config.ymin))
        if hist.GetMinimum() == 0.:
            hist.SetMinimum(0.9)
        if plot_config.normalise:
            # hist.SetMinimum(0.000001)
            hist.SetMinimum(0.)
            fm.set_minimum_y(hist, plot_config.ymin)
        canvas.SetLogy()
    if plot_config.logx:
        canvas.SetLogx()
    ht.set_axis_labels(hist, plot_config)
    canvas.Update()
    return canvas

def plot_2d_hist(hist, plot_config, **kwargs):
    canvas = retrieve_new_canvas(plot_config.name, plot_config.title, plot_config.canvas_size_x,
                                 plot_config.canvas_size_y)
    canvas.cd()
    hist = format_obj(hist, plot_config)
    ROOT.SetOwnership(hist, False)
    draw_option = plot_config.draw_option
    if draw_option is None:
        _logger.warning("No draw option provided for TH2 for pc: {:s}. "
                        "Fall back to default: COLZ".format(plot_config.name))
        draw_option = 'COLZ'
    hist.Draw(draw_option)
    if plot_config.logx:
        canvas.SetLogx()
    if plot_config.logy:
        canvas.SetLogy()
    if plot_config.logz:
        canvas.SetLogz()
    if plot_config.style is not None:
        hist.SetMarkerStyle(plot_config.style)
    canvas.SetRightMargin(0.2)
    canvas.Modified()
    canvas.Update()
    return canvas

# todo: remove
# def fetch_process_config_old(process, process_config):
#     if process is None or process_config is None:
#         return None
#     if process not in process_config:
#         _logger.warning("Could not find process %s in process config" % process)
#         return None
#     return process_config[process]

def format_obj(obj, plot_config):
    if isinstance(obj, ROOT.TH1):
        return format_hist(obj, plot_config)
    if isinstance(obj, ROOT.TGraphAsymmErrors) or isinstance(obj, ROOT.TGraph) or isinstance(obj, ROOT.TMultiGraph):
        return format_hist(obj, plot_config)
    if isinstance(obj, ROOT.TEfficiency):
        return format_tefficiency(obj, plot_config)
    _logger.warn('Could not find implementation for ', obj)
    return obj

def get_title_from_plot_config(plot_config):
    xtitle = None
    if plot_config.xtitle is not None:
        xtitle = plot_config.xtitle
        if hasattr(plot_config, "unit"):
            xtitle += " [" + plot_config.unit + "]"
    y_title = "Entries"
    if plot_config.ytitle is not None:
        y_title = plot_config.ytitle
    return xtitle, y_title

def format_tefficiency(obj, plot_config):
    xtitle, ytitle = get_title_from_plot_config(plot_config)
    if xtitle is None:
        xtitle = ""
    obj.SetTitle(";{:s};{:s}".format(xtitle, ytitle))
    if plot_config.xmin is not None and plot_config.xmax is not None:
        ROOT.gPad.Update()
        obj.GetPaintedGraph().GetXaxis().SetRangeUser(plot_config.xmin, plot_config.xmax)
        obj.GetPaintedGraph().Set(0)
    return obj

def format_hist(hist, plot_config):
    if plot_config is None:
        return hist
    xtitle, ytitle = get_title_from_plot_config(plot_config)
    if xtitle:
        fm.set_title_x(hist, xtitle)
    if plot_config.xtitle_offset is not None:
        fm.set_title_x_offset(hist, plot_config.xtitle_offset)
    if plot_config.xtitle_size is not None:
        fm.set_title_x_size(hist, plot_config.xtitle_size)
    if hasattr(plot_config, "unit"):
        ytitle += " / %.1f %s" % (hist.GetXaxis().GetBinWidth(0), plot_config.unit)
    fm.set_title_y(hist, ytitle)
    if plot_config.ytitle_offset is not None:
        fm.set_title_y_offset(hist, plot_config.ytitle_offset)
    if plot_config.ytitle_size is not None:
        fm.set_title_y_size(hist, plot_config.ytitle_size)
    if isinstance(hist, ROOT.TH2):
        if plot_config.ztitle is not None:
            hist.GetZaxis().SetTitle(plot_config.ztitle)
        if plot_config.ztitle_offset is not None:
            fm.set_title_z_offset(hist, plot_config.ztitle_offset)
        if plot_config.ztitle_size is not None:
            fm.set_title_z_size(hist, plot_config.ztitle_size)
        if hasattr(plot_config, "rebinX") and hasattr(plot_config.rebinY):
            hist = ht.rebin2D(hist, plot_config.rebinX, plot_config.rebinY)
        if hasattr(plot_config, "zmin") and hasattr(plot_config, "zmax"):
            fm.set_range_z(hist, plot_config.zmin, plot_config.zmax)
    if plot_config.normalise:
        ht.normalise(hist, plot_config.normalise_range, plot_config.norm_scale)
        ymax = plot_config.yscale * hist.GetMaximum()
        if plot_config.ymax is not None:
            plot_config.ymax = max(plot_config.ymax, ymax)
        else:
            plot_config.ymax = ymax
    if plot_config.rebin and not isinstance(hist, ROOT.THStack) and not plot_config.ignore_rebin:
        hist = ht.rebin(hist, plot_config.rebin, plot_config.disable_bin_width_division)
        ymax = plot_config.yscale*hist.GetMaximum()
        if plot_config.ymax is not None:
            plot_config.ymax = min(plot_config.ymax, ymax)
        else:
            plot_config.ymax = ymax

    ROOT.SetOwnership(hist, False)
    return hist

def make_graph(name, x_vals, y_vals):
    """
    Create a TGraph based on x and y-values
    :param name: name of graph
    :type name: str
    :param x_vals: x-values
    :type x_vals: list
    :param y_vals: y-values
    :type y_vals: lists
    :return: graph
    :rtype: ROOT.TGraph
    """
    g = ROOT.TGraph(len(x_vals))
    g.SetName(name)
    for i, x in enumerate(x_vals):
        g.SetPoint(i, x, y_vals[i])
    ROOT.SetOwnership(g, False)
    return g

def plot_graphs(graphs, plot_config):
    """
    Plot function for graphs
    :param graphs: graphs to plot
    :type graphs: list or dict of TGraphs
    :param plot_config: plot configuration
    :type plot_config: PlotConfig
    :return: canvas with drawn graphs
    :rtype: ROOT.TCanvas
    """
    if isinstance(graphs, dict):
        graphs = list(graphs.values())
    canvas = plot_graph(graphs[0], plot_config)
    for index, graph in enumerate(graphs[1:]):
        add_graph_to_canvas(canvas, graph, plot_config, index+1)
    return canvas

def add_signal_to_canvas(signal, canvas, plot_config, process_configs):
    """
    Overlay a signal histogram to an existing canvas
    :param signal: tuple of signal name, histogram
    :type signal: list
    :param canvas: existing canvas to which signal should be added
    :type canvas: ROOT.TCanvas
    :param plot_config: plot configuration
    :type plot_config: PlotConfig
    :param process_configs: process configuration
    :type process_configs: ProcessConfig
    :return: nothing
    :rtype: None
    """
    add_histogram_to_canvas(canvas, signal[1], plot_config, process_configs[signal[0]])

def plot_histograms(hists, plot_config, process_configs=None, switchOff=False):
    """
    Plot histograms in canvas and apply styles according to plot and process configuration
    :param hists: histograms to plots
    :type hists: list or dict
    :param plot_config: plot configuration
    :type plot_config: PlotConfig
    :param process_configs: process configuration
    :type process_configs: ProcessConfig
    :param switchOff: switch off style application (optional)
    :type switchOff: bool
    :return: canvas with plotted histograms
    :rtype: ROOT.TCanvas
    """
    if plot_config is None:
        plot_config = get_default_plot_config(hists[0])
    canvas = retrieve_new_canvas(plot_config.name, '', plot_config.canvas_size_x, plot_config.canvas_size_y)
    canvas.cd()
    is_first = True
    max_y = None
    if isinstance(hists, dict):
        hist_defs = list(hists.items())
        # import re
        # hist_defs.sort(key=lambda s: int(re.findall('\d+', s[0])[0]))
    elif isinstance(hists, list):
        hist_defs = list(zip([None] * len(hists), hists))

    if isinstance(hist_defs[0][1], PO.PlotableObject):
        if not switchOff and not isinstance(hist_defs[0][1].plot_object, ROOT.TH2):
            max_y = 1.4 * max([item[1].plot_object.GetMaximum() for item in hist_defs])
        elif isinstance(hist_defs[0][1].plot_object, ROOT.TH2):
            max_y = plot_config.ymax
        # if plot_config.ordering is not None:
        #     sorted(hist_defs, key=lambda k: plot_config.ordering.index(k[0]))

        for process, hist in hist_defs:
            hist.plot_object = format_hist(hist.plot_object, plot_config)
            process_config = find_process_config(process, process_configs)
            if not (plot_config.is_set_to_value("ignore_style", True)) and \
                    plot_config.is_set_to_value("ignore_style", False):
                setattr(plot_config, 'draw', hist.draw_option)
                draw_option = get_draw_option_as_root_str(plot_config, process_config)
            else:
                draw_option = "hist"
            if not is_first and "same" not in draw_option:
                draw_option += "sames"
            hist.plot_object.Draw(draw_option)
            fm.apply_style_plotableObject(hist)

            if is_first:
                if isinstance(hist.plot_object, ROOT.TH2) and draw_option.lower() == "colz":
                    canvas.SetRightMargin(0.15)
                    fm.set_minimum_y(hist.plot_object, plot_config.ymin)
                    if plot_config.logz:
                        canvas.SetLogz()
                if switchOff:
                    fm.set_maximum_y(hist.plot_object, plot_config.ymax)
                else:
                    fm.set_maximum_y(hist.plot_object, max_y)
                    fm.set_minimum_y(hist.plot_object, plot_config.ymin)
                if plot_config.xmin and not plot_config.xmax:
                    fm.set_minimum(hist.plot_object, plot_config.xmin, "x")
                elif plot_config.xmin and plot_config.xmax:
                    fm.set_range(hist.plot_object, plot_config.xmin, plot_config.xmax, "x")
                if plot_config.logx:
                    canvas.SetLogx()
                # format_hist(hist.plot_object, plot_config)
                if not isinstance(hist.plot_object, ROOT.TH2):
                    if plot_config.ymax:
                        hist.plot_object.SetMaximum(plot_config.ymax)
                    else:
                        hist.plot_object.SetMaximum(hist.plot_object.GetMaximum() * 1.2)
            if plot_config.logy:
                hist.plot_object.SetMaximum(hist.plot_object.GetMaximum() * 100.)
                if plot_config.ymin > 0.:
                    hist.plot_object.SetMinimum(plot_config.ymin)
                # if hasattr(plot_config, "ymin"):
                #     hist.plot_object.SetMinimum(max(0.1, plot_config.ymin))
                else:
                    hist.plot_object.SetMinimum(0.9)
                if hist.plot_object.GetMinimum() == 0.:
                    hist.plot_object.SetMinimum(0.9)
                canvas.SetLogy()
                canvas.Update()
            is_first = False
            if plot_config.normalise:
                hist_defs[0][1].plot_object.SetMaximum(plot_config.ymax)
        canvas.Update()
        return canvas

    if not switchOff and plot_config.ymax is None:
        max_y = 1.4 * max([item[1].GetMaximum() for item in hist_defs])
    if plot_config.ordering is not None:
        hist_defs = sorted(hist_defs, key=lambda k: plot_config.ordering.index(k[0]))
    for process, hist in hist_defs:
        index = list(map(itemgetter(1), hist_defs)).index(hist)
        hist = format_hist(hist, plot_config)
        try:
            process_config = find_process_config(process, process_configs)
        except AttributeError:
            process_config = None
        if not (plot_config.is_set_to_value("ignore_style", True)) and \
                plot_config.is_set_to_value("ignore_style", False):
            draw_option = get_draw_option_as_root_str(plot_config, process_config)
        else:
            draw_option = "hist"
        if not is_first and "same" not in draw_option:
            draw_option += "sames"
        hist.Draw(draw_option)
        fm.apply_style(hist, plot_config, process_config, index=index)
        if is_first:
            if isinstance(hist, ROOT.TH2) and draw_option.lower() == "colz":
                canvas.SetRightMargin(0.15)
            format_hist(hist, plot_config)
            if plot_config.ymax:
                fm.set_maximum_y(hist, plot_config.ymax)
            else:
                fm.set_maximum_y(hist, max([h.GetMaximum() for _, h in hist_defs]) * 1.2)
            if plot_config.ymin:
                fm.set_minimum_y(hist, plot_config.ymin)
        if plot_config.logy:
            if not plot_config.normalise:
                hist.SetMaximum(hist.GetMaximum() * 100.)
            if plot_config.ymin > 0.:
                hist.SetMinimum(plot_config.ymin)
            else:
                hist.SetMinimum(0.9)
            if hist.GetMinimum() == 0.:
                hist.SetMinimum(0.9)
            canvas.SetLogy()
            canvas.Update()
        is_first = False
    if plot_config.normalise:
        hist_defs[0][1].SetMaximum(plot_config.ymax)
    canvas.Update()
    return canvas

def add_fit_to_canvas(canvas, fit_result, pdf=None, frame=None):
    canvas.cd()
    if frame:
        pdf.paramOn(frame, ROOT.RooFit.Layout(0.50, 0.9, 0.8))
        chi2 = frame.chiSquare("model", "data", 3)
        txt = ROOT.TText(2, 100, "#chi^{2} = " + "{:.2f}".format(chi2))
        ROOT.SetOwnership(txt, False)
        txt.SetTextSize(0.04)
        txt.SetTextColor(ROOT.kRed)
        frame.addObject(txt)
    else:
        for i in range(len(fit_result.floatParsFinal()) - 1):
            var = fit_result.floatParsFinal()[i]
            var_string = "{:s} = {:.2f} \\pm {:.2f}".format(var.GetName(), var.getValV(), var.getError())
            fm.add_text_to_canvas(canvas, var_string, pos={'x': 0.15, 'y': 0.9 - i * 0.05}, size=0.04, color=None)
    canvas.Update()

def apply_style(obj, style_setter, style_attr, color):
    """
    Apply defined styles to plottable object

    :param obj: plot object to be styled
    :type obj: TGraph, TH1, ...
    :param style_setter: attribute to be set, e.g. Fill, Marker, Line
    :type style_setter: str
    :param style_attr: attribute value
    :type style_attr: str
    :param color: color for attribute
    :type color: int
    :return: None
    :rtype: None
    """
    if style_attr is not None:
        if isinstance(style_attr, dict):
            for ss, attr in style_attr.items():
                getattr(obj, "Set" + ss + "Style")(attr)
        else:
            for ss in style_setter:
                getattr(obj, "Set" + ss + "Style")(style_attr)
    if color is not None:
        for ss in style_setter:
            getattr(obj, "Set" + ss + "Color")(color)

def add_histogram_to_canvas(canvas, hist, plot_config, process_config=None, index=None):
    canvas.cd()
    draw_option = get_draw_option_as_root_str(plot_config, process_config)
    hist = format_obj(hist, plot_config)
    apply_style(hist, *get_style_setters_and_values(plot_config, process_config, index))
    if "same" not in draw_option:
        draw_option += "sames"
    hist.Draw(draw_option)
    canvas.Update()

def plot_graph(graph, plot_config, **kwargs):
    """
    Plot a TGraph object

    :param graph: object to be plotted
    :type graph: TGraph
    :param plot_config: plot configuration defining style
    :type plot_config: PlotConfig
    :param kwargs: additional arguments like canvas name and title
    :type kwargs:
    :return: canvas containing plotted and formatted TGraph
    :rtype: TCanvas
    """
    kwargs.setdefault('index', 0)
    kwargs.setdefault('canvas_name', plot_config.name)
    kwargs.setdefault('canvas_title', '')
    canvas = retrieve_new_canvas(kwargs['canvas_name'], kwargs['canvas_title'], plot_config.canvas_size_x,
                                 plot_config.canvas_size_y)
    canvas.cd()
    draw_option = 'a' + get_draw_option_as_root_str(plot_config)
    if plot_config.ymax is not None:
        fm.set_range_y(graph, plot_config.ymin, plot_config.ymax)
    graph.Draw(draw_option)
    graph = format_obj(graph, plot_config)
    apply_style(graph, *get_style_setters_and_values(plot_config, index=kwargs['index']))
    ROOT.SetOwnership(graph, False)
    if plot_config.logy:
        canvas.SetLogy()

    canvas.Update()
    return canvas

def add_graph_to_canvas(canvas, graph, plot_config, index=None):
    """
    Add a TGraph or associated object to existing canvas
    :param canvas: canvas containing at least on graph
    :type canvas: ROOT.TCanvas
    :param graph: graph object to be added
    :type graph: TGraph (or in Inheritance scheme)
    :param plot_config: plot style configuration
    :type plot_config: PlotConfig
    :param index: index identifier for ith graph object in canvas for style choice (optional)
    :type index: int
    :return: nothing
    :rtype: None
    """
    canvas.cd()
    draw_option = get_draw_option_as_root_str(plot_config)
    if "same" not in draw_option:
        draw_option += "same"
    draw_option = draw_option.lstrip('a')
    apply_style(graph, *get_style_setters_and_values(plot_config, index=index))
    graph.Draw(draw_option)
    ROOT.SetOwnership(graph, False)
    canvas.Update()

def apply_ordering(hist_defs, ordering):
    for process, _ in hist_defs:
        if process not in ordering:
            ordering.append(process)
    return sorted(hist_defs, key=lambda k: ordering.index(k[0]))

def plot_stack(hists, plot_config, **kwargs):
    """
    Plot THStack
    :param hists: histogram list to be stacked
    :param plot_config:
    :param kwargs:
    :return:
    """
    kwargs.setdefault("process_configs", None)
    process_configs = kwargs["process_configs"]
    canvas = retrieve_new_canvas(plot_config.name, '', plot_config.canvas_size_x, plot_config.canvas_size_y)
    canvas.Clear()
    canvas.cd()
    if isinstance(hists, dict) or isinstance(hists, defaultdict):
        hist_defs = list(hists.items())
    elif isinstance(hists, list):
        hist_defs = list(zip([None] * len(hists), hists))
    else:
        _logger.error('Cannot deal with provided input {:s}'.format(hists.__str__()))
        raise InvalidInputError()
    stack = ROOT.THStack('hs', '')

    ROOT.SetOwnership(stack, False)
    data = None
    if plot_config.ordering is not None:
        hist_defs = apply_ordering(hist_defs, plot_config.ordering)
    for index, histograms in enumerate(hist_defs):
        process, hist = histograms
        try:
            if "data" in process.lower():
                if data is None:
                    data = [(process, hist)]
                else:
                    data.append((process, hist))
                continue
        except AttributeError:
            pass
        hist = format_hist(hist, plot_config)
        process_config = find_process_config(process, process_configs)
        draw_option = get_draw_option_as_root_str(plot_config, process_config)
        fm.apply_style(hist, plot_config, process_config, index)
        _logger.debug('Add hist {:s} to stack with draw option {:s}'.format(hist.GetName(), draw_option))
        stack.Add(hist, draw_option)
    stack.Draw()
    canvas.Update()
    format_hist(stack, plot_config)
    min_y, max_y = fm.get_min_max_y(canvas, plot_config)
    fm.set_range(stack, min_y, max_y)
    if data is not None:
        for data_campaing in data:
            add_data_to_stack(canvas, data_campaing[1], plot_config)
    if plot_config.logy:
        canvas.SetLogy()
    if plot_config.logx:
        try:
            xmin, xmax = plot_config.xmin, plot_config.xmax
        except AttributeError:
            xmin, xmax = max(0.0001, stack.GetXaxis().GetXmin()), stack.GetXaxis().GetXmax()
        fm.set_range_x(stack, xmin, xmax)
        canvas.SetLogx()

    return canvas

def add_data_to_stack(canvas, data, plot_config=None, blind=None):
    if blind:
        blind_data(data, blind)
    canvas.cd()
    ROOT.SetOwnership(data, False)
    data = format_hist(data, plot_config)
    data.Draw("Esames")

def blind_data(data, blind):
    """
    Apply blinding to a given distribution above blind cut value
    :param data: histogram
    :type data: TH1X
    :param blind: cut value above which distribution should be blinded
    :type blind: float
    :return: nothing
    :rtype: None
    """
    for b in range(data.GetNbinsX() + 1):
        if data.GetBinCenter(b) < blind:
            continue
        else:
            data.SetBinContent(b, 0.)
            data.SetBinError(b, 0.)

def add_signal_to_stack(canvas, signal, signal_strength=1., overlay=False, stack=None):
    if overlay:
        if not stack:
            raise InvalidInputError("Requested overlay of signal, but no stack provided.")
        clone = None
        for h in stack.GetHists():
            if clone is None:
                clone = h.Clone()
            else:
                clone.Add(h)
    canvas.cd()
    for process in signal:
        process.SetLineColor(ROOT.kRed)
        process.Scale(signal_strength)
        if overlay:
            process.Add(clone)
        process.Draw("histsames")

def add_ratio_to_canvas(canvas, ratio, y_min=None, y_max=None, y_title=None, name=None, title=''):
    _logger.error('add_ratio_to_canvas moved to RatioPlotter. Please update your code')
    return None  # RatioPlotter.add_ratio_to_canvas(canvas, ratio, y_min, y_max, y_title, name, title)


text:
<?xml version="1.0" encoding="UTF-8"?>
<!--
  ~ Copyright (c) 2011, The Broad Institute
  ~
  ~ Permission is hereby granted, free of charge, to any person
  ~ obtaining a copy of this software and associated documentation
  ~ files (the "Software"), to deal in the Software without
  ~ restriction, including without limitation the rights to use,
  ~ copy, modify, merge, publish, distribute, sublicense, and/or sell
  ~ copies of the Software, and to permit persons to whom the
  ~ Software is furnished to do so, subject to the following
  ~ conditions:
  ~
  ~ The above copyright notice and this permission notice shall be
  ~ included in all copies or substantial portions of the Software.
  ~ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  ~ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  ~ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  ~ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  ~ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  ~ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  ~ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  ~ OTHER DEALINGS IN THE SOFTWARE.
  -->

<package name="GATKEngine">
  <executable name="GATKEngine">
    <dependencies>
      <!-- Package everything in org.broadinstitute.sting -->
      <package name="org.broadinstitute.sting.**" />
      <!-- Tribble codecs -->
      <package name="org.broad.tribble.**" />
      <!-- Workaround - depend on the logger impl required by JEXL -->
      <package name="org.apache.commons.logging.impl" />
      <!-- R packages -->
      <dir name="org/broadinstitute/sting/utils/R" includes="**/*.tar.gz" />
      <!-- All R scripts in org.broadinstitute.sting -->
      <dir name="org/broadinstitute/sting" includes="**/*.R" />
      <!-- The GATK public key -->
      <file path="GATK_public.key" />
    </dependencies>
  </executable>
  <resources>
    <!-- Sample reads and reference files -->
    <file name="public/testdata/exampleBAM.bam" />
    <file name="public/testdata/exampleBAM.bam.bai" />
    <file name="public/testdata/exampleFASTA.fasta" />
    <file name="public/testdata/exampleFASTA.fasta.fai" />
    <file name="public/testdata/exampleFASTA.dict" />
  </resources>
</package>

redpajama_set_name: RedPajamaGithub


text:
package com.ystore.lib.chess;

import java.util.LinkedList;

public class Stack<T> {
    private LinkedList<T> stack = new LinkedList();

    public T pop() {
        if (this.stack.isEmpty())
            return null;
        return this.stack.removeLast();
    }

    public void push(T paramT) {
        this.stack.add(paramT);
    }
}


text:
package de.fhm.akfo.shop.authentication.rest.to;

public class RoleTo {

	/**
	 * Roles of User
	 */
	private String role;

	/**
	 * Default Constructor
	 */
	public RoleTo() {
	}

	public RoleTo(String role) {
		this.role = role;
	}

	public String getRole() {
		return role;
	}

	public void setRole(String role) {
		this.role = role;
	}

}


text:
    <?php foreach ($categories as $category) : ?>
        <a href="<?= \yii\helpers\Url::to(['goods/category', 'id' => $category->category_id]) ?>" class="list-group-item"><?= $category->cat_title ?>
    <? endforeach; ?>


text:
import json
import requests
import pprint                         # Allows Pretty Print of JSON
import os                             # Allows for the clearing of the Terminal Window
import csv                            # Allows outputting to CSV file
import time, datetime
import sys

"""
********************************************************************************************************************
The intention of this script is to:
Iterate through a list of users ( users.csv ), remove that member from the source team (based on the API token provided gFromTeamTOKEN)
returning their account to being a personal individual account.
Then immediately inviting the user to join new team (based on the API token provided gToTeamTOKEN).

NOTE:
  CSV file expects email, first name, last name
  One user per row

Users in target Team are invited as standard team members. These users will need to ACCEPT the invitation before joining the team.
Once they accept, they will enter the invite flow, and must select option to transfer their content to company.
If you need to promote anyone to an Administrative level, do so using the Admin web pages.

NOTES:
  When you remove a team member from a team:
  1. Account will be disconnected from the team and converted to an individual account
  2. Member will keep unshared files and folders, and shared folders that they own
  3. Member won't have access to team-owned folders that they were invited to after joining the team
  4. Member will still have access to Paper docs that they own and are private. They will lose access to paper documents that were
     shared with them, and also paper documents they owned and shared with others!

By default the script runs in MOCK or test mode. Edit the variable 'gMockRun' to make it run for real.
By default adding users to target team will send them an invite email, edit variable 'gSendWelcomeEmail' to stop this.
Script logs most console content to a file 'logfile.txt' in the location script is executed.

** WARNING **
If you enter incorrect Target Team Token, users accounts could be orphaned as they'll be removed from Source Team but not added to
the Target Team.

Requirements:
  Script tested on Python 3.6.5

  One Dropbox API Token is needed from each team, source team and target team. Inserted just below this comments section.
  Permissions needed on token:

  Source Team:
  - team_data.member    "View structure of your team's and members' folders"
  - members.delete        "Remove and recover your team members' accounts"

  Target Team:
  - team_data.member    "View structure of your team's and members' folders"
  - members.write        "View and manage your team membership"

Pre-requisites:
* Scripts requires library 'Requests' - You can install using "pip install requests"

********************************************************************************************************************
"""
gFromTeamTOKEN = ''     # Scoped API token for SOURCE team to remove user from
gToTeamTOKEN = ''       # Scoped API token for TARGET team to add user to

gMockRun = True                # If True the script emulates the actual call to the API so no account moves done
gSendWelcomeEmail = False      # If True the script will send a Welcome / invite to user added to target team.
gRetainTeamShares = False      # If True, when users removed from source team they will retain access to Dropbox Folders ( not paper folders ) already
                               # explicitly shared with them (not via group membership)

"""
********************************************************************************************************************
                                             DO NOT EDIT BELOW THIS POINT
********************************************************************************************************************
"""

# Track how long script takes to run
totalTimeStart = datetime.datetime.fromtimestamp(time.time())

# Global Variables
gUsers = []

#############################################
# Function to return a string representation of time taken
#############################################
def getTimeInHoursMinutesSeconds( sec ):
    sec = int(sec)
    hrs = sec / 3600
    sec -= 3600*hrs

    mins = sec / 60
    sec -= 60*mins

    return '%s hrs, %s mins, %s sec' % ( hrs, mins, sec);

#############################################
# Function to print Message to console in a tidy box
#############################################
def printmessageblock( str ):
  print ("\n*********************************************************")
  print ("* %s" % (str))
  print ("*********************************************************\n")
  return;

#############################################
# Step 0
# Clear the terminal window, not essential but makes it easier to read this way.
#############################################

os.system('cls' if os.name=='nt' else 'clear')

#############################################
# Step 1
# Check that there's a From and To Token provided.
#############################################
if (len( gFromTeamTOKEN ) <= 0  or len( gToTeamTOKEN ) <=0 ):
	printmessageblock ( "It would appear you're missing one of the necessary API Tokens. Ending script." )
	exit()

#############################################
# Step 1
# Check if user wants to proceed. This could be distructive in removing users from Team.
#############################################

printmessageblock('Are you sure you wish to proceed with running this script? ')
if (not gMockRun):
	print( "If you proceed, team members listed in CSV file and found in the corresponding source API team will be removed from that team.")
	print( "Script will attempt then to add them to target team")
else:
	print( "You are in MOCK RUN mode so no accounts will be removed or added.")

lsAnswer = input("\nType 'y' to proceed or 'n' to cancel this script: ")

if ( lsAnswer == 'y' or lsAnswer == 'Y'):
	print( "\nExecuting script" )
elif ( lsAnswer == 'n' or lsAnswer == 'N'):
	print( '\nExiting script\n')
	exit()
else:
	print("\n\nUser did not enter a 'n' or a 'y' input. Ending script.")
	exit();

#############################################
# Step 2
# Note the standard output to console
# Redirect standard output to File until end of script.
#############################################

print ( "Starting script, further outputs to log file." )
# Note the standard output
gstdout = sys.stdout
# Redirect standard output to log file
sys.stdout = open('logfile.txt', 'w')

#############################################
# Step 3
# Get the list of users to remove from source team
# and add to target team
#############################################
# Open a file to read from
with open( 'users.csv', 'r') as csvfileRead:
	# Open file to read from
	reader = csv.reader(csvfileRead)

	gUsers = list(reader)

#############################################
# Step 4
# Iterate through each user,
# uninvite from Source Team
#############################################

# Details for source team
aHeadersSource = {'Content-Type': 'application/json',
		'Authorization': 'Bearer %s' % gFromTeamTOKEN}
aURLSource = 'https://api.dropboxapi.com/2/team/members/remove'

# Details for target team
aHeadersTarget = {'Content-Type': 'application/json',
		'Authorization': 'Bearer %s' % gToTeamTOKEN}
aURLTarget = 'https://api.dropboxapi.com/2/team/members/add_v2'

for user in gUsers:

	aEmailAddress = user[0]
	aFirstName = user[1]
	aSurname = user[2]

	# Set Users Email into parameters
	aData = json.dumps({'user': {'.tag': 'email', 'email': aEmailAddress}, 'wipe_data': False, 'keep_account': True, 'retain_team_shares': gRetainTeamShares})

	print( "\n------------------------------------------------------------------------" )
	print( "Attempting to remove %s from source team." % aEmailAddress)

	""" Make the API call """
	if ( not gMockRun ):
		aResult = requests.post(aURLSource, headers=aHeadersSource, data=aData)

		#If we don't get a 200 HTML response code, we didn't get a result.
		if( aResult.status_code != 200 ):
			print ('-- Failed to remove %s from team. %s' % (aEmailAddress, aResult.text))
			continue;
		else:
			print ('++ Successfully removed %s from team. ' % (aEmailAddress))
	else:
		print ('++ MOCK RUN: Successfully removed %s from team.' % (aEmailAddress))

	##########################################
	# Now try invite them to the target team!
	##########################################

	# Set Users Email into parameters
	aData = json.dumps({"new_members": [{
            "member_email": aEmailAddress,
            "member_given_name": aFirstName,
            "member_surname": aSurname,
            "send_welcome_email": gSendWelcomeEmail
        }],
        "force_async": False
        })

	print( "\nAttempting to add %s to target team." % aEmailAddress)

	if ( not gMockRun ):
		""" Make the API call """
		aResult = requests.post(aURLTarget, headers=aHeadersTarget, data=aData)

		# If we don't get a 200 HTML response code, we didn't get a result.
		if( aResult.status_code != 200 ):
			print ('-- Failed to add %s to target team. %s' % (aEmailAddress, aResult.text))
			continue;
		else:
			print ('++ Successfully added %s to target team.' % (aEmailAddress))
	else:
		print ('++ MOCK RUN: Successfully added %s to target team.' % (aEmailAddress))

#############################################
# Final step
# 1. Output how long the script took to run.
#############################################

totalTimeStop = datetime.datetime.fromtimestamp(time.time())
totalTimeInSeconds = (totalTimeStop-totalTimeStart).total_seconds()
timeAsStr = getTimeInHoursMinutesSeconds( totalTimeInSeconds )
printmessageblock( " Script finished running, it took                                           %s." % ( timeAsStr ) )

# Put standard output back to console
sys.stdout = gstdout
print( "Script finished")


text:
<!DOCTYPE html>

    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
    <title>Cesium Sandcastle</title>
    <link rel="stylesheet" href="../../ThirdParty/codemirror-4.6/lib/codemirror.css">
    <link rel="stylesheet" href="CesiumSandcastle.css">

    <link rel="stylesheet" href="../../ThirdParty/codemirror-4.6/addon/hint/show-hint.css">

    <meta property="og:title" content="Cesium Sandcastle" />
    <meta property="og:description" content="The Cesium Sandcastle provides an interactive environment for testing Cesium code." />
    <meta property="og:type" content="website" />
    <meta property="og:url" content="http://cesiumjs.org/Cesium/Apps/Sandcastle/index.html" />
    <meta property="og:image" content="http://cesiumjs.org/images/Sandcastle.png" />
    <meta property="og:site_name" content="Cesium" />
    <meta property="fb:admins" content="1222088662,1322006496" />

Loading...

                New

                Run (F8)

                Suggest (Ctrl-Space)

                Info

Description:

                        <textarea data-dojo-type="dijit.form.Textarea" id="description"
                            data-dojo-props="trim:true" style="width: 335px;"></textarea>

Labels:

                        <textarea data-dojo-type="dijit.form.Textarea" id="label"
                            data-dojo-props="trim:true" style="width: 335px;"></textarea>

                Save As

You must save the file to this folder:
                        Apps/Sandcastle/gallery/*.html

Some browsers require you to manually rename
                        the saved file to a *.html file.

                            Save *.html file

                Open in New Window

                View as Thumbnail

            <input data-dojo-type="dijit.form.TextBox" type="text" id="search" name="search" data-dojo-props="trim:true, placeHolder:'Search Gallery', intermediateChanges:true"/>

                <textarea id="code" name="code">// Select a demo from the gallery to load.
                </textarea>

                <textarea id="htmlBody" name="htmlBody">
                    <!--
                    Select a demo from the gallery to load.
                    -->
                </textarea>


text:
package cn.jingzhuan.lib.chart2.base;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.RectF;
import android.os.Build;
import androidx.annotation.FloatRange;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;

import android.os.CountDownTimer;
import android.util.AttributeSet;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.widget.EdgeEffect;
import android.widget.OverScroller;

import cn.jingzhuan.lib.chart.R;
import cn.jingzhuan.lib.chart.Zoomer;
import cn.jingzhuan.lib.chart.event.OnLoadMoreKlineListener;
import cn.jingzhuan.lib.chart.utils.ForceAlign.XForce;
import cn.jingzhuan.lib.chart.Viewport;;
import cn.jingzhuan.lib.chart.component.Axis;
import cn.jingzhuan.lib.chart.component.AxisX;
import cn.jingzhuan.lib.chart.component.AxisY;
import cn.jingzhuan.lib.chart.component.Highlight;
import cn.jingzhuan.lib.chart.event.OnViewportChangeListener;
import cn.jingzhuan.lib.chart.utils.ForceAlign;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * Created by Donglua on 17/7/17.
 */

public abstract class Chart extends BitmapCachedChart {

    protected AxisY mAxisLeft = new AxisY(AxisY.LEFT_INSIDE);
    protected AxisY mAxisRight = new AxisY(AxisY.RIGHT_INSIDE);
    protected AxisX mAxisTop = new AxisX(AxisX.TOP);
    protected AxisX mAxisBottom = new AxisX(AxisX.BOTTOM);

    // State objects and values related to gesture tracking.
    private ScaleGestureDetector mScaleGestureDetector;
    private GestureDetector mGestureDetector;
    private OverScroller mScroller;
    private Zoomer mZoomer;
    private PointF mZoomFocalPoint = new PointF();
    private RectF mScrollerStartViewport = new RectF(); // Used only for zooms and flings.

    private boolean mScaleXEnable = true;
    private boolean mDraggingToMoveEnable = true;
    private boolean mIsMainChart = false;
    private boolean mIsHighlight = false;
    private boolean mIsLongPress = false;
    private boolean mDoubleTapToZoom = false;
    private boolean mScaleGestureEnable = true;

    private boolean mHighlightDisable = false;
    private boolean mHighlightVolatile = true;

    protected List<OnTouchPointChangeListener> mTouchPointChangeListeners;
    protected List<OnTouchHighlightChangeListener> mTouchHighlightChangeListeners;
    private List<OnViewportChangeListener> mOnViewportChangeListeners;
    protected OnViewportChangeListener mInternalViewportChangeListener;
    protected OnLoadMoreKlineListener mOnLoadMoreKlineListener;

    /**
     * The scaling factor for a single zoom 'step'.
     *
     * @see #zoomIn()
     * @see #zoomOut()
     */
    private static final float ZOOM_AMOUNT = 0.2f;

    private final Point mSurfaceSizeBuffer = new Point();

    // Edge effect / overscroll tracking objects.
    private EdgeEffect mEdgeEffectLeft;
    private EdgeEffect mEdgeEffectRight;

    private boolean mEdgeEffectLeftActive;
    private boolean mEdgeEffectRightActive;

    private boolean isTouching = false;
    private boolean isShowRange = false;

    protected Highlight[] mHighlights;
    int mFocusIndex = -1;

    protected boolean canLoadMore = true;

    private float scaleSensitivity = 1f;
    private boolean canZoomIn = true;
    private boolean canZoomOut = true;

    public Chart(Context context) {
        this(context, null, 0);
    }

    public Chart(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public Chart(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context, attrs, defStyleAttr);
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    public Chart(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init(context, attrs, defStyleAttr);
    }

    private void init(Context context, AttributeSet attrs, int defStyleAttr) {

        TypedArray a = context.getTheme().obtainStyledAttributes(
                attrs, R.styleable.Chart, defStyleAttr, defStyleAttr);

        mTouchPointChangeListeners = Collections.synchronizedList(new ArrayList<OnTouchPointChangeListener>());
        mTouchHighlightChangeListeners = Collections.synchronizedList(new ArrayList<OnTouchHighlightChangeListener>());
        mOnViewportChangeListeners = Collections.synchronizedList(new ArrayList<OnViewportChangeListener>());

        mAxisTop.setGridLineEnable(false);
        mAxisTop.setLabelEnable(false);

        try {
            List<Axis> axisList = new ArrayList<>(4);
            axisList.add(mAxisLeft);
            axisList.add(mAxisRight);
            axisList.add(mAxisTop);
            axisList.add(mAxisBottom);

            float labelTextSize = a.getDimension(R.styleable.Chart_labelTextSize, 28);
            float labelSeparation = a.getDimensionPixelSize(R.styleable.Chart_labelSeparation, 10);
            float gridThickness = a.getDimension(R.styleable.Chart_gridThickness, 2);
            float axisThickness = a.getDimension(R.styleable.Chart_axisThickness, 2);
            int gridColor = a.getColor(R.styleable.Chart_gridColor, Color.GRAY);
            int axisColor = a.getColor(R.styleable.Chart_axisColor, Color.GRAY);
            int labelTextColor = a.getColor(R.styleable.Chart_labelTextColor, Color.GRAY);

            for (Axis axis : axisList) {
                axis.setLabelTextSize(labelTextSize);
                axis.setLabelTextColor(labelTextColor);
                axis.setLabelSeparation(labelSeparation);
                axis.setGridColor(gridColor);
                axis.setGridThickness(gridThickness);
                axis.setAxisColor(axisColor);
                axis.setAxisThickness(axisThickness);
            }

        } finally {
            a.recycle();
        }

        initChart();

        setupInteractions(context);

        setupEdgeEffect(context);
    }

    public abstract void initChart();

    public abstract void highlightValue(Highlight highlight);

    public abstract void cleanHighlight();

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {

        getContentRect().set(
                getPaddingLeft() + (mAxisLeft.isInside() ? 0 : mAxisLeft.getLabelWidth()),
                getPaddingTop(),
                getWidth() - getPaddingRight() - (mAxisRight.isInside() ? 0 : mAxisRight.getLabelWidth()),
                getHeight() - getPaddingBottom() - mAxisBottom.getLabelHeight()
        );
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int minChartSize = getResources().getDimensionPixelSize(R.dimen.jz_chart_min_size);
        setMeasuredDimension(
                Math.max(getSuggestedMinimumWidth(),
                        resolveSize(minChartSize + getPaddingLeft()
                                        + (mAxisLeft.isInside() ? 0 : mAxisLeft.getLabelWidth())
                                        + getPaddingRight(),
                                widthMeasureSpec)),
                Math.max(getSuggestedMinimumHeight(),
                        resolveSize(minChartSize + getPaddingTop()
                                        + (mAxisBottom.isInside() ? 0 : mAxisBottom.getLabelHeight())
                                        + getPaddingBottom(),
                                heightMeasureSpec)));
    }

    protected abstract int getEntryIndexByCoordinate(float x, float y);

    //    -------- -------- --------

    private void setupInteractions(Context context) {

        mScaleGestureDetector = new ScaleGestureDetector(context, mScaleGestureListener);
        //设置 mMinSpan ,防止不能缩小
        try {
            Field field = mScaleGestureDetector.getClass().getDeclaredField("mMinSpan");
            field.setAccessible(true);
            field.set(mScaleGestureDetector, 1);
        } catch (Exception e) {
            e.printStackTrace();
        }
        mGestureDetector = new GestureDetector(context, mGestureListener);
        mGestureDetector.setIsLongpressEnabled(true);

        mScroller = new OverScroller(context);
        mZoomer = new Zoomer(context);
    }

    /**
     * Finds the lib point (i.e. within the lib's domain and range) represented by the
     * given pixel coordinates, if that pixel is within the lib region described by
     * {@link #mContentRect}. If the point is found, the "dest" argument is set to the point and
     * this function returns true. Otherwise, this function returns false and "dest" is unchanged.
     */
    private boolean hitTest(float x, float y, PointF dest) {
        if (!mContentRect.contains((int) x, (int) y)) {
            return false;
        }

        dest.set(mCurrentViewport.left
                        + mCurrentViewport.width()
                        * (x - mContentRect.left) / mContentRect.width(),
                mCurrentViewport.top
                        + mCurrentViewport.height()
                        * (y - mContentRect.bottom) / -mContentRect.height());
        return true;
    }

    /**
     * The scale listener, used for handling multi-finger scale gestures.
     */
    private final ScaleGestureDetector.OnScaleGestureListener mScaleGestureListener
            = new ScaleGestureDetector.SimpleOnScaleGestureListener() {
        /**
         * This is the active focal point in terms of the viewport. Could be a local
         * variable but kept here to minimize per-frame allocations.
         */
        private PointF viewportFocus = new PointF();
//        private float lastSpanX;

        @Override
        public boolean onScaleBegin(ScaleGestureDetector scaleGestureDetector) {
            if (!isScaleGestureEnable()) return super.onScaleBegin(scaleGestureDetector);

            isScaling = true;
//            lastSpanX = scaleGestureDetector.getCurrentSpanX();
            return true;
        }

        @Override
        public void onScaleEnd(ScaleGestureDetector detector) {
            super.onScaleEnd(detector);
            Log.d("Chart", "onScaleEnd");
        }

        @Override
        public boolean onScale(ScaleGestureDetector scaleGestureDetector) {
            Log.d("Chart", "onScale");

            if (!isScaleXEnable()) return false;
            if (!isScaleGestureEnable()) return super.onScale(scaleGestureDetector);

            float spanX = scaleGestureDetector.getCurrentSpan();
            float lastSpanX = scaleGestureDetector.getPreviousSpan();
            boolean zoomIn = spanX > lastSpanX; // 双指距离比上次大,为放大
            boolean zoomOut = lastSpanX > spanX; // 双指距离比上次小,为缩小

            boolean canZoom = Math.abs(Math.abs(lastSpanX) - Math.abs(spanX)) >= 5f;

            if (zoomIn) {
                setCanZoomOut(true);
                if (!isCanZoomIn())
                    return false;
            }

            if (zoomOut) {
                setCanZoomIn(true);
                if (!isCanZoomOut())
                    return false;
            }

            float scaleSpanX = lastSpanX;
            if (canZoom) {
                if (zoomIn) {
                    scaleSpanX = spanX * scaleSensitivity;
                } else if (zoomOut) {
                    lastSpanX = lastSpanX * scaleSensitivity;
                }
            }

            float newWidth;
            if (canZoom) {
                if (zoomIn) {
                    newWidth = lastSpanX / scaleSpanX * mCurrentViewport.width();
                } else {
                    newWidth = lastSpanX / spanX * mCurrentViewport.width();
                }
            } else {
                newWidth = lastSpanX / spanX * mCurrentViewport.width();
            }

            if (newWidth < mCurrentViewport.width() && mCurrentViewport.width() < 0.001) {
                return true;
            }

            float focusX = scaleGestureDetector.getFocusX();
            float focusY = scaleGestureDetector.getFocusY();

            if (canZoom) {
                if (zoomOut)
                    focusX *= scaleSensitivity;
                else if (zoomIn)
                    focusX /= scaleSensitivity;
            }

            hitTest(focusX, focusY, viewportFocus);

//            Log.d("Chart", "onScale"
//                    + ", viewportFocus.x:" + viewportFocus.x
//                    + ", newWidth:" + newWidth
//                    + ", focusX:" + focusX
//                    + ", focusY:" + focusY
//                    + ", (spanX - lastSpanX) :" + (spanX - lastSpanX)
//                    + ", spanX:" + spanX
//                    + ", lastSpanX:" + lastSpanX
//                    + ", mCurrentViewport.left:" + mCurrentViewport.left
//                    + ", mContentRect.left:" + mContentRect.left
//                    + ", mContentRect.width():" + mContentRect.width()
//            );

            mCurrentViewport.left = viewportFocus.x - newWidth * (focusX - mContentRect.left) / mContentRect.width();
            // mCurrentViewport.right = mCurrentViewport.left + newWidth;

//            Log.w("Chart", "onScale"
//                    + ", viewportFocus.x:" + viewportFocus.x
//                    + ", newWidth:" + newWidth
//                    + ", focusX:" + focusX
//                    + ", focusY:" + focusY
//                    + ", (spanX - lastSpanX) :" + (spanX - lastSpanX)
//                    + ", spanX:" + spanX
//                    + ", lastSpanX:" + lastSpanX
//                    + ", mCurrentViewport.left:" + mCurrentViewport.left
//                    + ", mContentRect.left:" + mContentRect.left
//                    + ", mContentRect.width():" + mContentRect.width()
//            );

            mCurrentViewport.constrainViewport();

            triggerViewportChange();
//            lastSpanX = spanX;

            return true;
        }
    };

    protected abstract void onTouchPoint(MotionEvent e);
    protected abstract void onTouchHighlight(MotionEvent e);

    /**
     * The gesture listener, used for handling simple gestures such as double touches, scrolls,
     * and flings.
     */
    private final GestureDetector.SimpleOnGestureListener mGestureListener
            = new GestureDetector.SimpleOnGestureListener() {

        @Override
        public boolean onDown(MotionEvent e) {

            releaseEdgeEffects();
            mScrollerStartViewport.set(mCurrentViewport);
            mScroller.forceFinished(true);

            postInvalidateOnAnimation();

            return true;
        }

        @Override
        public void onLongPress(MotionEvent e) {
            mIsLongPress = true;
            onTouchPoint(e);
            e.setAction(MotionEvent.ACTION_UP);
            mGestureDetector.onTouchEvent(e);
        }

        @Override
        public boolean onSingleTapUp(MotionEvent e) {
//            Log.d("Chart", "滑动 onSingleTapUp(" + e.getX() + ", " + e.getY() + "); isHighlight:" + isHighlight());
            return super.onSingleTapUp(e);
        }

        @Override
        public boolean onSingleTapConfirmed(MotionEvent e) {
//            Log.d("Chart", "滑动 onSingleTapConfirmed isClickable:" + isClickable()+ ", hasOnClickListeners:" + hasOnClickListeners() + "; isHighlight:" + isHighlight());
            if (isClickable() && hasOnClickListeners()) {
                cleanHighlight();
                performClick();
            } else {
                int index = getEntryIndexByCoordinate(e.getX(), e.getY());
//                Log.v("Chart", "滑动 onSingleTapConfirmed index:" + index + ", mHighlightVolatile:" + mHighlightVolatile + ", mHighlights != null:" + (mHighlights != null) + ", mHighlightDisable:" + mHighlightDisable);
                if (index >= 0) {
                    if (mHighlightVolatile && (mHighlights != null || mHighlightDisable)) {
                        if (isMainChart()) cleanHighlight();
                        else onTouchPoint(e);
                    } else {
                        onTouchPoint(e);
                    }
                } else {
                    cleanHighlight();
                    if (isClickable() && hasOnClickListeners()) {
                        performClick();
                    }
                }
            }

            return true;
        }

        @Override
        public boolean onDoubleTap(MotionEvent e) {
            if (mDoubleTapToZoom) {

                mZoomer.forceFinished(true);
                if (hitTest(e.getX(), e.getY(), mZoomFocalPoint)) {
                    mZoomer.startZoom(ZOOM_AMOUNT);
                }
                postInvalidateOnAnimation();
            }
            return true;
        }

        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
//            Log.d("Chart", "滑动 onScroll(" + e2.getX() + ", " + e2.getY() + "), isDraggingToMoveEnable:" + isDraggingToMoveEnable() + ", isMainChart:" + isMainChart() + ", inHighlight:" + isHighlight());
            // 主图高亮时 不滚动,只触发点击
            if ((!isDraggingToMoveEnable() && isHighlight()) // 分时主图,高亮时
                    || (!isDraggingToMoveEnable() && !isMainChart()) // K线副图
                    || (isDraggingToMoveEnable() && isMainChart() && isHighlight()) // K线主图,高亮时
            ) {
//                Log.d("Chart", "滑动 onTouchPoint(" + e2.getX() + ", " + e2.getY() + ") isTouching:" + isTouching + ", isLongPress:" + isLongPress());
                if (isLongPress()) {
                    if (isMainChart()) onTouchPoint(e2); else onTouchHighlight(e2); // if (isTouching) {  }
                }
                return super.onScroll(e1, e2, distanceX, distanceY);
            }

            if (mScaleGestureDetector.isInProgress()) {
                return false;
            }

            if (e1.getPointerCount() > 1 || e2.getPointerCount() > 1) {
                return true;
            }
            Log.w("Chart", "onScroll");

            // Scrolling uses math based on the viewport (as opposed to math using pixels).
            /**
             * Pixel offset is the offset in screen pixels, while viewport offset is the
             * offset within the current viewport. For additional information on surface sizes
             * and pixel offsets, see the docs for {@link computeScrollSurfaceSize()}. For
             * additional information about the viewport, see the comments for
             * {@link mCurrentViewport}.
             */

            float viewportOffsetX = distanceX * mCurrentViewport.width() / mContentRect.width();
            // float viewportOffsetY = -distanceY * mCurrentViewport.height() / mContentRect.height();
            computeScrollSurfaceSize(mSurfaceSizeBuffer);
            int scrolledX = (int) (mSurfaceSizeBuffer.x
                    * (mCurrentViewport.left + viewportOffsetX - Viewport.AXIS_X_MIN)
                    / (Viewport.AXIS_X_MAX - Viewport.AXIS_X_MIN));
            boolean canScrollX = mCurrentViewport.left > Viewport.AXIS_X_MIN
                    || mCurrentViewport.right < Viewport.AXIS_X_MAX;
            setViewportBottomLeft(
                    mCurrentViewport.left + viewportOffsetX
            );

            if (canScrollX && scrolledX < 0) {
                mEdgeEffectLeft.onPull(scrolledX / (float) mContentRect.width());
                mEdgeEffectLeftActive = true;
                if (canLoadMore && mOnLoadMoreKlineListener != null) {
                    mOnLoadMoreKlineListener.onLoadMoreKline(scrolledX);
                }
                canLoadMore = false;
            } else {
                canLoadMore = true;
            }
            if (canScrollX && scrolledX > mSurfaceSizeBuffer.x - mContentRect.width()) {
                mEdgeEffectRight.onPull((scrolledX - mSurfaceSizeBuffer.x + mContentRect.width())
                        / (float) mContentRect.width());
                mEdgeEffectRightActive = true;
            }

            return true;
        }

        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
            if (!isDraggingToMoveEnable()) return super.onFling(e1, e2, velocityX, velocityY);

            fling((int) -velocityX);

            if (!isDraggingToMoveEnable()) {
                onTouchPoint(e2);
            }

            return true;
        }
    };

    protected void triggerViewportChange() {
        postInvalidateOnAnimation();

        if (mInternalViewportChangeListener != null) {
            mInternalViewportChangeListener.onViewportChange(mCurrentViewport);
        }
        if (mOnViewportChangeListeners != null && !mOnViewportChangeListeners.isEmpty()) {
            synchronized (this) {
                for (OnViewportChangeListener mOnViewportChangeListener : mOnViewportChangeListeners) {
                    try {
                        mOnViewportChangeListener.onViewportChange(mCurrentViewport);
                    } catch (Exception e) {
                        Log.d("Chart", "onViewportChange", e);
                    }
                }
            }
        }
    }

    private void fling(int velocityX) {
        if (!canLoadMore) return;

        releaseEdgeEffects();
        // Flings use math in pixels (as opposed to math based on the viewport).
        computeScrollSurfaceSize(mSurfaceSizeBuffer);
        mScrollerStartViewport.set(mCurrentViewport);
        int startX = (int) (mSurfaceSizeBuffer.x * (mScrollerStartViewport.left - Viewport.AXIS_X_MIN) / (
                Viewport.AXIS_X_MAX - Viewport.AXIS_X_MIN));
        mScroller.forceFinished(true);
        mScroller.fling(
                startX,
                0,
                velocityX,
                0,
                0, mSurfaceSizeBuffer.x - mContentRect.width(),
                0, mSurfaceSizeBuffer.y - mContentRect.height(),
                mContentRect.width() / 2,
                0);
        postInvalidateOnAnimation();
    }

    /**
     * Computes the current scrollable surface size, in pixels. For example, if the entire lib
     * area is visible, this is simply the current size of {@link #mContentRect}. If the lib
     * is zoomed in 200% in both directions, the returned size will be twice as large horizontally
     * and vertically.
     */
    private void computeScrollSurfaceSize(Point out) {
        out.set((int) (mContentRect.width() * (Viewport.AXIS_X_MAX - Viewport.AXIS_X_MIN)
                        / mCurrentViewport.width()),
                (int) (mContentRect.height() * (Viewport.AXIS_Y_MAX - Viewport.AXIS_Y_MIN)
                        / mCurrentViewport.height()));
    }

    /**
     * Smoothly zooms the lib in one step.
     */
    public void zoomIn() {
        zoom(ZOOM_AMOUNT);
    }

    /**
     * Smoothly zooms the lib out one step.
     */
    public void zoomOut() {
        zoom(-ZOOM_AMOUNT);
    }

    public void zoom(float scalingFactor) {
        mScrollerStartViewport.set(mCurrentViewport);
        mZoomer.forceFinished(true);
        mZoomer.startZoom(scalingFactor);
        mZoomFocalPoint.set(
                (mCurrentViewport.right + mCurrentViewport.left) / 2,
                (mCurrentViewport.bottom + mCurrentViewport.top) / 2);
        triggerViewportChange();
    }

    public void zoomOut(@XForce int forceAlignX) {
        mScrollerStartViewport.set(mCurrentViewport);
        mZoomer.forceFinished(true);
        mZoomer.startZoom(-ZOOM_AMOUNT);

        float forceX;
        switch (forceAlignX) {
            case ForceAlign.LEFT:
                forceX = mCurrentViewport.left;
                break;
            case ForceAlign.RIGHT:
                forceX = mCurrentViewport.right;
                break;
            case ForceAlign.CENTER:
            default:
                forceX = (mCurrentViewport.right + mCurrentViewport.left) / 2;
                break;
        }
        mZoomFocalPoint.set(forceX,
                (mCurrentViewport.bottom + mCurrentViewport.top) / 2);
        postInvalidateOnAnimation();
    }

    /**
     * Smoothly zooms the lib in one step.
     */
    public void zoomIn(@XForce int forceAlignX) {
        mScrollerStartViewport.set(mCurrentViewport);
        mZoomer.forceFinished(true);
        mZoomer.startZoom(ZOOM_AMOUNT);

        float forceX;
        switch (forceAlignX) {
            case ForceAlign.LEFT:
                forceX = mCurrentViewport.left;
                break;
            case ForceAlign.RIGHT:
                forceX = mCurrentViewport.right;
                break;
            case ForceAlign.CENTER:
            default:
                forceX = (mCurrentViewport.right + mCurrentViewport.left) / 2;
                break;
        }

        mZoomFocalPoint.set(forceX,
                (mCurrentViewport.bottom + mCurrentViewport.top) / 2);
        triggerViewportChange();
    }

    @Override
    public void computeScroll() {
        super.computeScroll();

        boolean needsInvalidate = false;

        if (mScroller.computeScrollOffset()) {
            // The scroller isn't finished, meaning a fling or programmatic pan operation is
            // currently active.

            computeScrollSurfaceSize(mSurfaceSizeBuffer);
            int currX = mScroller.getCurrX();

            boolean canScrollX = (mCurrentViewport.left > Viewport.AXIS_X_MIN
                    || mCurrentViewport.right < Viewport.AXIS_X_MAX);

            if (canScrollX
                    && currX < 0
                    && mEdgeEffectLeft.isFinished()
                    && !mEdgeEffectLeftActive) {
                mEdgeEffectLeft.onAbsorb((int) mScroller.getCurrVelocity());
                mEdgeEffectLeftActive = true;
                needsInvalidate = true;
            } else if (canScrollX
                    && currX > (mSurfaceSizeBuffer.x - mContentRect.width())
                    && mEdgeEffectRight.isFinished()
                    && !mEdgeEffectRightActive) {
                mEdgeEffectRight.onAbsorb((int) mScroller.getCurrVelocity());
                mEdgeEffectRightActive = true;
                needsInvalidate = true;
            }

            float currXRange = Viewport.AXIS_X_MIN + (Viewport.AXIS_X_MAX - Viewport.AXIS_X_MIN)
                    * currX / mSurfaceSizeBuffer.x;
            setViewportBottomLeft(currXRange);
        }

        if (mZoomer.computeZoom()) {
            // Performs the zoom since a zoom is in progress (either programmatically or via
            // double-touch).
            float newWidth = (1f - mZoomer.getCurrZoom()) * mScrollerStartViewport.width();
            float newHeight = (1f - mZoomer.getCurrZoom()) * mScrollerStartViewport.height();
            float pointWithinViewportX = (mZoomFocalPoint.x - mScrollerStartViewport.left)
                    / mScrollerStartViewport.width();
            float pointWithinViewportY = (mZoomFocalPoint.y - mScrollerStartViewport.top)
                    / mScrollerStartViewport.height();
            mCurrentViewport.set(
                    mZoomFocalPoint.x - newWidth * pointWithinViewportX,
                    mZoomFocalPoint.y - newHeight * pointWithinViewportY,
                    mZoomFocalPoint.x + newWidth * (1 - pointWithinViewportX),
                    mZoomFocalPoint.y + newHeight * (1 - pointWithinViewportY));
            mCurrentViewport.constrainViewport();
            needsInvalidate = true;
        }

        if (needsInvalidate) {
            triggerViewportChange();
        }
    }

    /**
     * Sets the current viewport (defined by {@link #mCurrentViewport}) to the given
     * X and Y positions. Note that the Y value represents the topmost pixel position, and thus
     * the bottom of the {@link #mCurrentViewport} rectangle. For more details on why top and
     * bottom are flipped, see {@link #mCurrentViewport}.
     */
    private void setViewportBottomLeft(float x) {
        /**
         * Constrains within the scroll range. The scroll range is simply the viewport extremes
         * (AXIS_X_MAX, etc.) minus the viewport size. For example, if the extrema were 0 and 10,
         * and the viewport size was 2, the scroll range would be 0 to 8.
         */

        float curWidth = mCurrentViewport.width();
        x = Math.max(Viewport.AXIS_X_MIN, Math.min(x, Viewport.AXIS_X_MAX - curWidth));

        mCurrentViewport.left = x;
        mCurrentViewport.right = x + curWidth;
        mCurrentViewport.constrainViewport();
        triggerViewportChange();
    }

    /**
     * Sets the lib's current viewport.
     *
     * @see #getCurrentViewport()
     */
    public void setCurrentViewport(RectF viewport) {
        mCurrentViewport.set(viewport.left, viewport.top, viewport.right, viewport.bottom);
        mCurrentViewport.constrainViewport();
        triggerViewportChange();
    }

//    private int lastEvAction = -1;
//    private int lastPointerCount = -1;
    private boolean isScaling = false;
    private ScalingTimeCount scalingTimeCount;
    class ScalingTimeCount extends CountDownTimer {
        public ScalingTimeCount() {
            super(350, 350);
        }
        @Override
        public void onFinish() {
            isScaling = false;
        }
        @Override
        public void onTick(long millisUntilFinished) {}
    }
    @Override
    public boolean onTouchEvent(MotionEvent event) {

        if (event.getAction() == MotionEvent.ACTION_DOWN || event.getAction() == MotionEvent.ACTION_MOVE) {
            if (event.getAction() == MotionEvent.ACTION_DOWN) {
//                Log.v("Chart", "ACTION_DOWN: " + event.getPointerCount());
            }
            if (event.getAction() == MotionEvent.ACTION_MOVE) {
//                Log.d("Chart", "ACTION_MOVE: pointerCount: " + event.getPointerCount()
//                        + ", lastPointerCount: " + lastPointerCount
//                );
            }
            isTouching = true;
        } else if (event.getAction() == MotionEvent.ACTION_UP) {
//            Log.d("Chart", "ACTION_UP: pointerCount: " + event.getPointerCount()
//                    + ", lastPointerCount: " + lastPointerCount
//            );
            isTouching = false;
        }

        boolean retVal = event.getPointerCount() > 1 && mScaleGestureDetector.onTouchEvent(event);

        if (event.getAction() == MotionEvent.ACTION_UP) {
            if (isScaling) {
                scalingTimeCount = new ScalingTimeCount();
                scalingTimeCount.start();
            }
        }
        if (!isScaling) {
            retVal = mGestureDetector.onTouchEvent(event) || retVal;
        }

//        lastEvAction = event.getAction();
//        lastPointerCount = event.getPointerCount();

//        Log.d("Chart", "eventAction: " + event.getAction() + "pointerCount: " + event.getPointerCount()
//                + ", retVal: " + retVal
//                + ", isScaling: " + isScaling
////                + ", lastPointerCount: " + lastPointerCount
//        );
        if (isScaling) {
            return true;
        } else {
            return retVal || super.onTouchEvent(event);
        }
    }

    protected void setupEdgeEffect(Context context) {

        // Sets up edge effects
        mEdgeEffectLeft = new EdgeEffect(context);
        mEdgeEffectRight = new EdgeEffect(context);
    }

    /**
     * Draws the overscroll "glow" at the four edges of the lib region, if necessary. The edges
     * of the lib region are stored in {@link #mContentRect}.
     *
     * @see EdgeEffect
     */
    protected void drawEdgeEffectsUnclipped(Canvas canvas) {
        // The methods below rotate and translate the canvas as needed before drawing the glow,
        // since EdgeEffectCompat always draws a top-glow at 0,0.

        boolean needsInvalidate = false;

        if (!mEdgeEffectLeft.isFinished()) {
            final int restoreCount = canvas.save();
            canvas.translate(mContentRect.left, mContentRect.bottom);
            canvas.rotate(-90, 0, 0);
            mEdgeEffectLeft.setSize(mContentRect.height(), mContentRect.width());
            if (mEdgeEffectLeft.draw(canvas)) {
                needsInvalidate = true;
            }
            canvas.restoreToCount(restoreCount);
        }

        if (!mEdgeEffectRight.isFinished()) {
            final int restoreCount = canvas.save();
            canvas.translate(mContentRect.right, mContentRect.top);
            canvas.rotate(90, 0, 0);
            mEdgeEffectRight.setSize(mContentRect.height(), mContentRect.width());
            if (mEdgeEffectRight.draw(canvas)) {
                needsInvalidate = true;
            }
            canvas.restoreToCount(restoreCount);
        }

        if (needsInvalidate) {
            triggerViewportChange();
        }
    }

    private void releaseEdgeEffects() {
        mEdgeEffectLeftActive
                = mEdgeEffectRightActive
                = false;
        mEdgeEffectLeft.onRelease();
        mEdgeEffectRight.onRelease();
    }

    public AxisY getAxisLeft() {
        return mAxisLeft;
    }

    public AxisY getAxisRight() {
        return mAxisRight;
    }

    public AxisX getAxisTop() {
        return mAxisTop;
    }

    public AxisX getAxisBottom() {
        return mAxisBottom;
    }

    public void addOnViewportChangeListener(OnViewportChangeListener onViewportChangeListener) {
        synchronized (this) {
            this.mOnViewportChangeListeners.add(onViewportChangeListener);
        }
    }

    public boolean isScaleXEnable() {
        return mScaleXEnable;
    }

    public void setScaleXEnable(boolean scaleXEnable) {
        this.mScaleXEnable = scaleXEnable;
    }

    public void setDoubleTapToZoom(boolean doubleTapToZoom) {
        this.mDoubleTapToZoom = doubleTapToZoom;
    }

    public float getScaleSensitivity() {
        return scaleSensitivity;
    }

    public void setScaleSensitivity(float scaleSensitivity) {
        this.scaleSensitivity = scaleSensitivity;
    }

    public boolean isCanZoomIn() {
        return canZoomIn;
    }

    public void setCanZoomIn(boolean canZoomIn) {
        this.canZoomIn = canZoomIn;
    }

    public boolean isCanZoomOut() {
        return canZoomOut;
    }

    public void setCanZoomOut(boolean canZoomOut) {
        this.canZoomOut = canZoomOut;
    }

    public interface OnTouchPointChangeListener {
        void touch(float x, float y);
    }

    public void addOnTouchPointChangeListener(OnTouchPointChangeListener touchPointChangeListener) {
        synchronized (this) {
            this.mTouchPointChangeListeners.add(touchPointChangeListener);
        }
    }

    public void removeOnTouchPointChangeListener(OnTouchPointChangeListener touchPointChangeListener) {
        synchronized (this) {
            this.mTouchPointChangeListeners.remove(touchPointChangeListener);
        }
    }

    public interface OnTouchHighlightChangeListener {
        void highlight(float x, float y);
    }

    public void addOnTouchHighlightChangeListener(OnTouchHighlightChangeListener touchHighlightChangeListener) {
        synchronized (this) {
            this.mTouchHighlightChangeListeners.add(touchHighlightChangeListener);
        }
    }

    public void removeOnTouchHighlightChangeListener(OnTouchHighlightChangeListener touchHighlightChangeListener) {
        synchronized (this) {
            this.mTouchHighlightChangeListeners.remove(touchHighlightChangeListener);
        }
    }

    public void setDraggingToMoveEnable(boolean draggingToMoveEnable) {
        this.mDraggingToMoveEnable = draggingToMoveEnable;
    }

    public boolean isDraggingToMoveEnable() {
        return mDraggingToMoveEnable;
    }

    public boolean isMainChart() {
        return mIsMainChart;
    }

    public void setIsMainChart(boolean isMainChart) {
        this.mIsMainChart = isMainChart;
    }

    public boolean isHighlight() {
        return mIsHighlight;
    }

    public void setIsHighlight(boolean isHighlight) {
        this.mIsHighlight = isHighlight;
    }

    public boolean isLongPress() {
        return mIsLongPress;
    }

    public void setIsLongPress(boolean isLongPress) {
        this.mIsLongPress = isLongPress;
    }

    public void moveLeft() {
        moveLeft(0.2f);
    }

    public void moveRight() {
        moveRight(0.2f);
    }

    public void moveLeft(@FloatRange(from = 0f, to = 1.0f) float percent) {
        releaseEdgeEffects();
        computeScrollSurfaceSize(mSurfaceSizeBuffer);
        mScrollerStartViewport.set(mCurrentViewport);

        float moveDistance = mContentRect.width() * percent;
        int startX = (int) (mSurfaceSizeBuffer.x * (mScrollerStartViewport.left - Viewport.AXIS_X_MIN)
                / (Viewport.AXIS_X_MAX - Viewport.AXIS_X_MIN));
        if (!mScroller.isFinished()) {
            mScroller.forceFinished(true);
        }
        mScroller.startScroll(startX, 0, (int) -moveDistance, 0, 300);
        postInvalidateOnAnimation();
    }

    public void moveRight(@FloatRange(from = 0f, to = 1.0f) float percent) {
//        releaseEdgeEffects();
        computeScrollSurfaceSize(mSurfaceSizeBuffer);
        mScrollerStartViewport.set(mCurrentViewport);

        float moveDistance = mContentRect.width() * percent;
        int startX = (int) (mSurfaceSizeBuffer.x * (mScrollerStartViewport.left - Viewport.AXIS_X_MIN)
                / (Viewport.AXIS_X_MAX - Viewport.AXIS_X_MIN));
        if (!mScroller.isFinished()) {
            mScroller.forceFinished(true);
        }
        mScroller.startScroll(startX, 0, (int) moveDistance, 0, 300);
        postInvalidateOnAnimation();
    }

    public void setInternalViewportChangeListener(
            OnViewportChangeListener mInternalViewportChangeListener) {
        this.mInternalViewportChangeListener = mInternalViewportChangeListener;
    }

    public void setScaleGestureEnable(boolean mScaleGestureEnable) {
        this.mScaleGestureEnable = mScaleGestureEnable;
    }

    public int getFocusIndex() {
        return mFocusIndex;
    }

    public void setFocusIndex(int focusIndex) {
        this.mFocusIndex = focusIndex;
    }

    public boolean isScaleGestureEnable() {
        return mScaleGestureEnable;
    }

    public boolean isHighlightDisable() {
        return mHighlightDisable;
    }

    public void setHighlightDisable(boolean highlightDisable) {
        this.mHighlightDisable = highlightDisable;
    }

    public boolean isHighlightVolatile() {
        return mHighlightVolatile;
    }

    public void setHighlightVolatile(boolean highlightVolatile) {
        this.mHighlightVolatile = highlightVolatile;
    }

    public Zoomer getZoomer() {
        return mZoomer;
    }

    public boolean isTouching() {
        return isTouching;
    }

    public boolean getRangeEnable() {
        return isShowRange;
    }

    public void setRangeEnable(boolean showRange) {
        isShowRange = showRange;
    }

    public void setOnLoadMoreKlineListener(OnLoadMoreKlineListener onLoadMoreKlineListener) {
        this.mOnLoadMoreKlineListener = onLoadMoreKlineListener;
    }

    public void finishScroll() {
        if (!mScroller.isFinished()) {
            mScroller.forceFinished(true);
        }
    }
}


text:
'use strict';

/* Controllers */

angular.module('myApp.controllers', ['myApp.services']).controller('MapsController', function() {

    $(document).ready( function() {
        $('.nav-menu').smint({
            'scrollSpeed' : 1000
        });
    });

    var map;
    var autocomplete;

    function initialize() {
        var mapOptions = {
            center: new google.maps.LatLng(51.2, 10.4),
            zoom: 6,
            streetViewControl: false
        };

        map = new google.maps.Map(document.getElementById("map-canvas"), mapOptions);
        var input = document.getElementById('search-term');
        //map.controls[google.maps.ControlPosition.TOP_CENTER].push(input);

        autocomplete = new google.maps.places.Autocomplete(input,
              {
                componentRestrictions: { country: 'de' }
              });

        // When the user selects a place, mark it with a marker and
        // move to the place and zoom the map in.
        google.maps.event.addListener(autocomplete, 'place_changed', onPlaceChanged);
    }

    function onPlaceChanged() {
        var place = autocomplete.getPlace();
        if (place.geometry) {
            // move to the place and zoom in
            map.panTo(place.geometry.location);
            map.setZoom(15);

            // mark the place
            var placeMarker = new google.maps.Marker({
                position: place.geometry.location,
                animation: google.maps.Animation.DROP,
                icon: 'https://maps.gstatic.com/intl/en_us/mapfiles/marker_green.png'
            });

            placeMarker.setMap(map);
        }
    }

    google.maps.event.addDomListener(window, 'load', initialize);
}).
controller('MoviesController', ['themoviedbService', function(themoviedbService) {
    // get discover movies by different types of data like average rating, number of votes, genres and certifications.
    this.films = themoviedbService.query();
}]);


text:
package com.jtransc.charset;

import com.jtransc.ds.FastIntIntMap;

import java.io.ByteArrayOutputStream;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;

public class JTranscCharsetSingleByte extends JTranscCharset {
	final String decode;
	final FastIntIntMap encode;
	final byte invalidChar = (byte) '?';

	public JTranscCharsetSingleByte(String[] aliases, String chars) {
		super(aliases, 1, 1, 1);
		this.decode = chars;
		this.encode = new FastIntIntMap();
		for (int n = 0; n < chars.length(); n++) {
			this.encode.set(chars.charAt(n), n);
		}
	}

	@Override
    final public void encode(char[] in, int offset, int len, ByteArrayOutputStream out) {
		for (int n = 0; n < len; n++) {
			char c = in[offset + n];
			if (encode.has(c)) {
				out.write(encode.get(c));
			} else {
				out.write(invalidChar);
			}
		}
	}

	@Override
    final public void decode(byte[] in, int offset, int len, JTranscCharBuffer out) {
		for (int n = 0; n < len; n++) {
			int b = in[offset + n] & 0xFF;
			out.append(decode.charAt(b));
		}
	}

	@Override
	final public void decode(ByteBuffer in, CharBuffer out) {
		while (in.hasRemaining() && out.hasRemaining()) {
			int b = in.get() & 0xFF;
			out.append(decode.charAt(b));
		}
	}
}


text:
Locations List of {{campusId}}

<button type="button" (click)="download()" class="btn btn-info">Download All</button>

{{location.name}}

      <button (click)="delete(location);" class="btn btn-primary">Delete</button>

    ID:{{location.id}}
    Latitude:{{location.latitude}}
    Longitude:{{location.longitude}}


text:
<!DOCTYPE html>

  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Login System</title>
  <link rel="stylesheet" type="text/css" href="css/bootstrap.css">
  <link rel="stylesheet" type="text/css" href="css/styles.css">

Login

        <form name="loginform" class="form-group"
              ng-controller="LoginController as loginCtrl"
              ng-submit="loginCtrl.login(loginCtrl.credentials)">
          Email
          <input type="email" name="email"
              ng-model="loginCtrl.credentials.email" placeholder="Email"
              required/>
          Password
          <input type="password" name="password"
              ng-model="loginCtrl.credentials.password" placeholder="Password"
              required/>
          <input class="btn btn-primary" type="submit" value="Login">

        </form>
        <form ng-submit="view.setView('create-account')">
          <input class="btn btn-link" type="submit" value="Create New User">
        </form>

Welcome {{userData.activeUser.firstName}} {{userData.activeUser.lastName}}

        <form ng-submit="view.setView('account-settings')">
          <input class="btn" type="submit" value="Account Settings">
        </form>
        <form ng-submit="view.setView('login')">
          <input class="btn btn-link" type="submit" value="Log Out">
        </form>

Create Account

          <form name="form" ng-submit="form.$valid &&
                            userData.addUser(userData.user)" novalidate>
            <fieldset class="form-group">
              First name:

              <input type="text" name="firstname" ng-model="userData.user.firstName" placeholder="John" required>

              Last name:

              <input type="text" name="lastname" ng-model="userData.user.lastName" placeholder="Doe" required>

              Email:

              <input type="email" name="email" ng-model="userData.user.email" placeholder="johndoe@example.com" required>

              Password:

              <input type="password" name="password" ng-model="userData.user.password" placeholder="your cat's name" required>
            </fieldset>
            <input class="btn btn-primary" type="submit" value="Submit">
          </form>

          <form ng-submit="view.setView('login')">
            <input class="btn btn-link" type="submit" value="Back to login">
          </form>

Account Preview

          First name: {{userData.user.firstName}}

          Last name: {{userData.user.lastName}}

          Email: {{userData.user.email}}

Account Settings

        First name: {{userData.activeUser.firstName}}

        Last name: {{userData.activeUser.lastName}}

        Email: {{userData.activeUser.email}}

        <form ng-submit="userData.editUserFirstName(userData.updatingUser)">
          New first name:

          <input type="text" name="newfirstname" ng-model="userData.updatingUser.firstName" required>
          <input class="btn" type="submit" value="Submit">
        </form>
        <form ng-submit="userData.editUserLastName(userData.updatingUser)">
          New last name:

          <input type="text" name="newlastname" ng-model="userData.updatingUser.lastName" required>
          <input class="btn" type="submit" value="Submit">
        </form>
        <form ng-submit="userData.editUserEmail(userData.updatingUser)">
          New email:

          <input type="email" name="newemail" ng-model="userData.updatingUser.email" required>
          <input class="btn" type="submit" value="Submit">
        </form>
        <form ng-submit="userData.editUserPassword(userData.updatingUser)">
          New password:

          <input type="password" name="newpassword" ng-model="userData.updatingUser.password" required>
          <input class="btn" type="submit" value="Submit">
        </form>
        <form ng-submit="view.setView('logged-in')">
          <input class="btn btn-link" type="submit" value="Back">
        </form>
        <form ng-submit="view.setView('login')">
          <input class="btn btn-link" type="submit" value="Log Out">
        </form>

Delete User

        <form ng-submit="userData.deleteUser(userData.activeUser)">
          <input class="btn btn-danger" type="submit" value="DELETE USER">
        </form>


text:
using namespace std;
int main() {

  const std::shared_ptr<spdlog::logger> _logger =
      spdlog::stdout_logger_mt("mainConsole");

  _logger->info("Parsing started");

//  lp::Parser parser("/home/satya/LPProblems/QiTest.lp", true);
//    lp::Parser parser("/home/satya/LPProblems/test/afiro.lp", true);
//    lp::Parser parser("/home/satya/LPProblems/test/maros-r7.lp", false);
  // TODO Free and Fixed variables are not handled yet
  //  lp::Parser parser("/home/satya/LPProblems/test/test.lp", false);

  lpp::Parser parser("/home/satya/LPProblems/test/blend.lp", true);

  lpp::Problem problem = parser.getBlazeProblem();
  //
  cout << problem << endl;

  //  lp::ClassicalProblem cProblem = parser.getClassicalProblem();

  _logger->info("Parsing ended");

  //    cout << cProblem << endl;

  return 0;
}


text:
package al.jdi.core.tenant;

import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import javax.enterprise.inject.Produces;
import javax.inject.Qualifier;

import al.jdi.dao.model.Campanha;

public class TenantModule {

  @Retention(RUNTIME)
  @Target({METHOD, FIELD, PARAMETER, TYPE})
  @Qualifier
  public @interface TenantManagerService {
  }

  public enum TenantType {
    STANDALONE, MULTI
  }

  @Produces
  public Map<Campanha, Tenant> getTenantCollection() {
    return Collections.synchronizedMap(new HashMap<Campanha, Tenant>());
  }

  @Produces
  public TenantType getStartupType() {
    return TenantType.STANDALONE;
  }

}


text:
'use strict';

const Promise = require('bluebird');
const _ = require('lodash');

function waitForWorkerShutdown(context, eventName) {
    const shutdownTimeout = _.get(context, 'sysconfig.teraslice.shutdown_timeout', 30000);
    const events = context.apis.foundation.getSystemEvents();

    return new Promise((resolve, reject) => {
        const timeoutId = setTimeout(() => {
            events.removeListener(eventName, handler);
            reject(new Error('Timeout waiting for worker to shutdown'));
        }, shutdownTimeout);

        function handler(err) {
            clearTimeout(timeoutId);
            if (_.isError(err)) {
                reject(err);
            } else {
                resolve();
            }
        }
        events.once(eventName, handler);
    });
}

/* istanbul ignore next */
function shutdownHandler(context, shutdownFn) {
    const assignment = context.assignment || process.env.NODE_TYPE || process.env.assignment || 'unknown-assignment';

    const isProcessRestart = process.env.process_restart;
    const restartOnFailure = assignment !== 'exectution_controller';
    const api = {
        exiting: false,
        exit
    };

    const shutdownTimeout = _.get(context, 'sysconfig.teraslice.shutdown_timeout', 20 * 1000);

    const events = context.apis.foundation.getSystemEvents();
    const logger = context.apis.foundation.makeLogger({ module: `${assignment}:shutdown_handler` });

    if (assignment === 'execution_controller' && isProcessRestart) {
        logger.fatal('Execution Controller runtime error led to a restart, terminating execution with failed status, please use the recover api to return slicer to a consistent state');
        process.exit(0);
    }

    function flushLogs() {
        return Promise.resolve()
            .then(() => this.logger.flush())
            .then(() => Promise.delay(1000));
    }

    let startTime;

    function exitingIn() {
        if (!api.exiting) {
            return `exiting in ${shutdownTimeout}ms...`;
        }

        const elapsed = Date.now() - startTime;
        return `already shutting down, remaining ${shutdownTimeout - elapsed}ms`;
    }

    function exit(event, err) {
        if (api.exiting) return;

        api.exiting = true;
        startTime = Date.now();

        Promise.race([
            shutdownFn(event, err),
            Promise.delay(shutdownTimeout - 2000)
        ]).then(() => {
            logger.info(`${assignment} shutdown took ${Date.now() - startTime}ms`);
        }).catch((error) => {
            logger.error(`${assignment} while shutting down`, error);
        }).then(() => {
            const code = process.exitCode || 0;
            logger.trace(`flushing log and exiting with code ${code}`);
            return flushLogs()
                .finally(() => {
                    process.exit();
                });
        });
    }

    process.on('SIGINT', () => {
        logger.info(`${assignment} received process:SIGINT, ${exitingIn()}`);
        if (!api.exiting) {
            process.exitCode = 0;
        }
        exit('SIGINT');
    });

    process.on('SIGTERM', () => {
        logger.info(`${assignment} received process:SIGTERM, ${exitingIn()}`);
        if (!api.exiting) {
            process.exitCode = 0;
        }
        exit('SIGTERM');
    });

    process.on('uncaughtException', (err) => {
        logger.fatal(`${assignment} received an uncaughtException, ${exitingIn()}`, err);
        if (!api.exiting) {
            process.exitCode = restartOnFailure ? 1 : 0;
        }
        exit('uncaughtException', err);
    });

    process.once('unhandledRejection', (err) => {
        logger.fatal(`${assignment} received an unhandledRejection, ${exitingIn()}`, err);
        if (!api.exiting) {
            process.exitCode = restartOnFailure ? 1 : 0;
        }
        exit('unhandledRejection', err);
    });

    // See https://github.com/trentm/node-bunyan/issues/246
    function handleStdError(err) {
        if (err.code === 'EPIPE' || err.code === 'ERR_STREAM_DESTROYED') {
        // ignore
        } else {
            throw err;
        }
    }

    process.stdout.on('error', handleStdError);
    process.stderr.on('error', handleStdError);

    // event is fired from terafoundation when an error occurs during instantiation of a client
    events.once('client:initialization:error', (err) => {
        logger.fatal(`${assignment} received a client initialization error, ${exitingIn()}`, err);
        if (!api.exiting) {
            process.exitCode = restartOnFailure ? 1 : 0;
        }
        exit('client:initialization:error', err);
    });

    events.once('worker:shutdown:complete', (err) => {
        if (!api.exiting) {
            process.exitCode = 0;
        }
        if (err) {
            logger.fatal(`${assignment} shutdown error, ${exitingIn()}`, err);
        } else {
            logger.info(`${assignment} shutdown, ${exitingIn()}`);
        }
        exit('worker:shutdown:complete', err);
    });

    return api;
}

module.exports = {
    shutdownHandler,
    waitForWorkerShutdown,
};