text:
using namespace std;
namespace coela {
namespace gain_utils {
//=====================================================================================================================

void append_histogram_data_from_float_bitmap_region(const CcdImage<float>& bmp,
        const PixelRange& rgn, HistogramContainer14bit& hist)
{
    assert(hist.minimum_has_been_set());
    assert(rgn.is_valid());
    for (int y=rgn.low.y; y<=rgn.high.y; ++y) {
        for (int x=rgn.low.x; x<=rgn.high.x; ++x) {
            hist.count_rounded_value(bmp.pix(x,y));
        }
    }//end pixel scan
    return;
}

void append_histogram_data_from_float_bitmap_region(const CcdImage<float>& bmp,
        const PixelRange& rgn, HistogramContainer10bit& hist)
{
    assert(hist.minimum_has_been_set());
    assert(rgn.is_valid());
    for (int y=rgn.low.y; y<=rgn.high.y; ++y) {
        for (int x=rgn.low.x; x<=rgn.high.x; ++x) {
            hist.count_rounded_value(bmp.pix(x,y));
        }
    }//end pixel scan
    return;
}

map<int,long> load_histogram_data_from_file(const string& filename)
{
    ifstream datafile(filename.c_str());
    if (!datafile) { throw runtime_error("Could not load histogram data from \""+filename+"\""); }
    int value; long count;
    map <int,long> histogram_data;
    while ((datafile>>value)) {
        datafile>>count;
        histogram_data[value] = count;
    }
    return histogram_data;
}

double histogram_differences_squared(const map<int,long>& data,
                                     const map<int,double>& model)
{
    assert(data.size()==model.size());
    double diff_sq_sum=0.0;
    double diff;
    for (map<int,long>::const_iterator it=data.begin(); it!=data.end(); ++it) {
        map<int,double>::const_iterator model_it = model.find(it->first);
        if (model_it==model.end()) { throw runtime_error("Gain utils: model/data mismatch during fitting"); }
        diff = it->second - model_it->second;
        diff_sq_sum += diff*diff;
    }
    return diff_sq_sum;
}

double poisson_noise_weighted_histogram_difference(const map<int,long>& data,
        const map<int,double>& model)
{
    assert(data.size()>=model.size());
    double diff_sq_sum=0.0;
    double diff;

//    pair<int,long> data_min_pair = get_min_value_pair(data);
//    pair<int,double> model_min_pair = get_min_value_pair(model);
//    cerr<<"Data / model min "<< data_min_pair.first<<" / "<< model_min_pair.first<<endl;

    for (map<int,double>::const_iterator model_it=model.begin(); model_it!=model.end();
            ++model_it) {
//        map<int,double>::const_iterator model_it = model.find(it->first);
//        if (model_it==model.end()) throw runtime_error("Gain utils: model/data mismatch during fitting");
        map<int,long>::const_iterator data_it = data.find(model_it->first);
        if (data_it==data.end()) throw
            runtime_error("Gain utils: model/data mismatch during fitting;"
                          "could not find datapoint for value " + string_utils::itoa(model_it->first));
        diff = (data_it->second - model_it->second);
        diff_sq_sum += diff*diff / max(data_it->second,
                                       1l);  //Poisson distribution for each histogram entry, so variance == probability
//        diff_sq_sum += pow(fabs(diff),1.5) / sqrt(model_it->second); //This method less sensitive to noise spikes at the end of the histogram section
    }
    return diff_sq_sum;
}

double log_space_histogram_difference(const map<int,long>& data,
                                      const map<int,double>& model)
{
    assert(data.size()>=model.size());
    double diff_sq_sum=0.0;
    double diff;
    for (map<int,double>::const_iterator model_it=model.begin(); model_it!=model.end();
            ++model_it) {
        map<int,long>::const_iterator data_it = data.find(model_it->first);
        if (data_it==data.end()) throw
            runtime_error("Gain utils: model/data mismatch during fitting;"
                          "could not find datapoint for value " + string_utils::itoa(model_it->first));
        diff = (log(data_it->second) - log(model_it->second));
        diff_sq_sum += diff*diff ;
    }
    return diff_sq_sum;
}

map<int, double> convolve_histogram_with_gaussian(const map<int, double>& input_hist,
        const double readout_sigma,
        const int kernel_half_width)
{
    map<int, double> readout_kernel;

    const double unity_area_gaussian_height = 1.0 / (sqrt(2.0*M_PI)*readout_sigma);

    const int kernel_min(-kernel_half_width), kernel_max(kernel_half_width);
    for (int value = kernel_min ; value <= kernel_max; ++value) {
        readout_kernel[value] = misc_math::gaussian_1d_function(value,
                                unity_area_gaussian_height,
                                readout_sigma);
    }

    const int input_min= get_min_value_pair(input_hist).first ;
    const int input_max= get_max_value_pair(input_hist).first ;

//    cerr<<"Kernel min / max" << kernel_min <<" / "<< kernel_max<<endl;
//    cerr<<"Input min / max" << input_min <<" / "<< input_max<<endl;

    map<int, double> convolved_hist;
    for (map<int,double>::const_iterator input_it=input_hist.begin();
            input_it!=input_hist.end(); ++input_it) {
        const int input_value= input_it->first;
        if (input_value + kernel_min >= input_min &&
                input_value + kernel_max <= input_max) {
            if (convolved_hist.find(input_value) == input_hist.end()) {
                convolved_hist[input_value ] = 0.0;
            }
            for (map<int,double>::const_iterator kernel_it=readout_kernel.begin();
                    kernel_it!=readout_kernel.end(); ++kernel_it) {

                int kernel_offset_input = kernel_it->first + input_value;
                convolved_hist[ input_value ] +=
                    input_hist.find(kernel_offset_input)->second * kernel_it->second;

            }
        }
//        else{
//            cerr<<"rejecting input val " << input_value<<endl;
//        }

    }
    return convolved_hist;
}

//==================================================================================

double GaussianHistogramFitFCN::operator()(const std::vector<double>& gauss_pars) const
{
    assert(gauss_pars.size()==3);
    map<int,double> model=get_model_histogram(gauss_pars);
//            return histogram_differences_squared(data, model);
//            cerr<<"Pars: "<< gauss_pars[0]<<" " <<gauss_pars[1]<<" "<<gauss_pars[2]<<endl;
    return poisson_noise_weighted_histogram_difference(data, model);

}

map<int,double> GaussianHistogramFitFCN::get_model_histogram(
    const std::vector<double>& gauss_pars) const
{
    map<int,double>model;
    for (map<int,long>::const_iterator it=data.begin(); it!=data.end(); ++it) {
        model[it->first] = misc_math::gaussian_1d_function((double)it->first - gauss_pars[0],
                           gauss_pars[1],
                           gauss_pars[2]);  //FIXME -- should perhaps be measuring distance from centre of bin? (so +0.5 to it->first). but not sure.
    }
    return model;
}

//==================================================================================
map<int,double> ExponentialHistogramFitFCN::get_model_histogram(
    const std::vector<double>& exp_pars) const
{
    assert(exp_pars.size()==2);
    map<int,double>model;
    const double& amplitude = exp_pars[0];
    const double& gain = exp_pars[1];
    for (map<int,long>::const_iterator it=data.begin(); it!=data.end(); ++it) {
        model[it->first] = amplitude*exp(-1.0*it->first/gain);
    }
    return model;
}

double  ExponentialHistogramFitFCN::operator()(const std::vector<double>& exp_pars)
const
{
    assert(exp_pars.size()==2);
    map<int,double> model=get_model_histogram(exp_pars);
//    return log_space_histogram_difference(data, model);
    return poisson_noise_weighted_histogram_difference(data, model) / (model.size() - 1);

}
//==================================================================================
//map<int,double> full_EMCCD_low_light_level_histogram_model::get_model_histogram(
//        const GainData& inf){
//
//}
//

//==================================================================================
FullEmccdHistogramFitFCN::FullEmccdHistogramFitFCN(const map<int,long>& histogram)
    :
    error_def(1.0), data_(histogram)
{
    fit_rgn_min_ = get_min_value_pair(data_).first;
    fit_rgn_max_ = get_max_value_pair(data_).first;
}

FullEmccdHistogramFitFCN::FullEmccdHistogramFitFCN(const map<int,long>& histogram,
        const int fit_region_min, const int fit_region_max):
    error_def(1.0), data_(histogram),
    fit_rgn_min_(fit_region_min), fit_rgn_max_(fit_region_max)
{}

double FullEmccdHistogramFitFCN::operator()(const std::vector<double>& pars) const
{
    assert(pars.size()==npars_);

//    cout<<"Params: ";
//    for (size_t i=0; i!=pars.size();++i){
//        cout<<pars[i]<<" ";
//    }
//
    map<int,double> model = get_model_histogram(pars);
    double val = poisson_noise_weighted_histogram_difference(data_, model);
//
//    cout<<" : "<<val;
//    cout<<endl;
//
    double normalised = val / (model.size() - (npars_ - 1));

    return normalised;
}
vector<double> FullEmccdHistogramFitFCN::generate_pars_vec(const GainData& inf)
{
    vector<double> pars;
    pars.push_back(inf.bias_pedestal);
    pars.push_back(inf.N_dark_pix);
    pars.push_back(inf.readout_sigma);
    pars.push_back(inf.N_light_pix);
    pars.push_back(inf.gain);
    pars.push_back(inf.N_serial_CIC_pix);
//    pars.push_back(inf.serial_CIC_gain);
    return pars;
}

map<int,double> FullEmccdHistogramFitFCN::get_CICIR_model_histogram(
    const double gain,
    const double N_CICIR_pix,
    const int N_EM_stages,
    const int max_val_to_generate)
{

    int min_N_stages=1;
    double prob_per_stage = pow(gain, 1.0/N_EM_stages);

    map<int,double> gain_for_N_stages;
    for (int stages_passed = 1; stages_passed<=N_EM_stages; ++stages_passed) {
        gain_for_N_stages[stages_passed] = pow(prob_per_stage, stages_passed);
    }

//    cerr<<"gain at 604:"<< gain_for_N_stages[604]<<endl;
//    const double frequency_normalisation =  N_CICIR_pix ;
    const double frequency_normalisation = N_CICIR_pix / (N_EM_stages - min_N_stages);

    map<int,double> CICIR_histogram;
    for (int register_output_val=1; register_output_val<=max_val_to_generate;
            ++register_output_val) {
        double output_frequency=0.0;
        for (int CICIR_stages_passed = min_N_stages; CICIR_stages_passed<=N_EM_stages;
                ++CICIR_stages_passed) {
            const double & g = gain_for_N_stages[CICIR_stages_passed];

            output_frequency +=  exp((0.5-register_output_val)/g) / g;
        }
        CICIR_histogram[register_output_val]= frequency_normalisation * output_frequency;
    }
    return CICIR_histogram;
}

map<int,double> FullEmccdHistogramFitFCN::get_model_histogram(
    const std::vector<double>& pars) const
{
    assert(pars.size()==npars_);

    const double& bias_pedestal = pars[0];
    const double& dark_pix = pars[1];
    const double& RO_sigma = pars[2];
    const double& N_photon_events = pars[3];
    const double& phot_gain = pars[4];
    const double& N_serial_CIC_pix = pars[5];
//    const double& serial_CIC_gain = pars[6];
//    const double serial_CIC_gain = sqrt(phot_gain);

    int convolution_half_width=60;

//   int data_start = get_min_value_pair(data).first;
    int data_end = get_max_value_pair(data_).first;
    int tail_range = data_end - bias_pedestal;

    double total_pix_calc = N_photon_events + N_serial_CIC_pix + dark_pix;
    double photon_freq_est = N_photon_events / total_pix_calc;
//   cerr<<"Photon freq est: " << photon_freq_est<<", calc total: " << total_pix_calc<<endl;

    //See Basden et al, 2003 for equations

//   double serial_CIC_amplitude =
//    N_serial_CIC_pix * exp(0.5/serial_CIC_gain)/ serial_CIC_gain;

    double p1_amplitude, p2_amplitude;
    if (photon_freq_est>0) {
        boost::math::poisson_distribution<> pois_dist(photon_freq_est);
        double p1_prob = boost::math::pdf(pois_dist, 1);
        double p2_prob = boost::math::pdf(pois_dist, 2);

        //Note exp( 0.5 / phot_gain) term corrects ~1% normalisation error;
        // since integral from 1 to +inf of the PDF otherwise  =  exp(-1/g)
        p1_amplitude = (p1_prob / (p1_prob +p2_prob)) *
                       N_photon_events * exp(0.5/phot_gain) /  phot_gain;

        //Note normalisation correction not reqd here, more complex to calc. but also much smaller effect.
        p2_amplitude = (p2_prob / (p1_prob +p2_prob)) *
                       N_photon_events / (phot_gain*phot_gain);
    } else {
        p1_amplitude=0.0;
        p2_amplitude=0.0;
    }

    map<int,double> register_output_model;
    int fit_rgn_extension_below_bias_pedestal = bias_pedestal - fit_rgn_min_;
    if (fit_rgn_extension_below_bias_pedestal > 0) {
        for (int i= -(convolution_half_width + fit_rgn_extension_below_bias_pedestal); i<0; ++i) {
            register_output_model[i]=0;
        }
    } else {
        for (int i= -convolution_half_width; i<0; ++i) {
            register_output_model[i]=0;
        }
    }

    register_output_model[0]  = dark_pix;

    map<int,double> CICIR_register_component =
        FullEmccdHistogramFitFCN::get_CICIR_model_histogram(
            phot_gain, N_serial_CIC_pix,
            FullEmccdHistogramFitFCN::N_EM_serial_register_stages,
            tail_range + convolution_half_width
        );

    for (int register_output_val=1; register_output_val<=tail_range + convolution_half_width;
            ++register_output_val) {
        double photon_exponential =  exp(-1.0* register_output_val /phot_gain);
        //Contribution from 1 and 2 photo-electron events
        register_output_model[register_output_val] =
            p1_amplitude*photon_exponential;
        register_output_model[register_output_val] +=
            p2_amplitude*(register_output_val - 1)*photon_exponential;

        //Contribution from CICIR events
//        register_output_model[register_output_val] +=
//                serial_CIC_amplitude*exp(  -1.0* register_output_val /serial_CIC_gain );
        register_output_model[register_output_val] +=
            CICIR_register_component[register_output_val];
    }

    map<int,double> RO_model =
        convolve_histogram_with_gaussian(register_output_model, RO_sigma,
                                         convolution_half_width);

    map<int,double> biased_RO_model;
    for (map<int,double>::const_iterator it=RO_model.begin(); it!=RO_model.end(); ++it) {
        int output_value = it->first + bias_pedestal;
        if (output_value>=fit_rgn_min_ && output_value <= fit_rgn_max_) {
            biased_RO_model[output_value] = it->second;
        }
    }

    return biased_RO_model;
}

//==================================================================================

//double calculate_thresholded_SNR(const double readout_noise_in_ADU,
//                                const double mean_photon_gain_in_ADU,
//                                const double CIC_event_rate_per_pixel_readout,
//                                const double light_level,
//                                const double threshold_in_photo_electrons,
//                                const bool output_to_screen){
//    map<int,long> histogram_min_max;
//    histogram_min_max[-readout_noise_in_ADU*5]=0;
//    histogram_min_max[10000]=0;
//
//    FullEmccdHistogramFitFCN full_model(histogram_min_max);
//    GainData full_pars;
//    full_pars.bias_pedestal = 0.0;
//    full_pars.readout_sigma = readout_noise_in_ADU;
//    full_pars.gain = mean_photon_gain_in_ADU;
//    full_pars.N_light_pix = 0.0;
//    full_pars.N_serial_CIC_pix = 0.0;
//    full_pars.N_dark_pix = 0.0;
////                - mean_photon_gain_in_ADU*CIC_event_rate_per_pixel_readout);
//
//    GainData photon_hist_pars(full_pars);
//    photon_hist_pars.N_light_pix=1.0;
//    map<int,double> light_model = full_model.get_model_histogram(
//        full_model.generate_pars_vec(photon_hist_pars));
//
//    double all_counts = gain_utils::sum_counts_in_histogram(light_model);
//    double thresh_counts = gain_utils::sum_counts_in_histogram_above_threshold(
//            light_model, threshold_in_photo_electrons*mean_photon_gain_in_ADU);
//
//    double pass_rate_for_photon_events = thresh_counts / all_counts;
//
//    if (output_to_screen){
////        gain_utils::write_histogram_data_to_file(light_model, "photons_only.txt");
//        cerr<<"photons hist sum:" << all_counts << endl;
//        cerr<<"Filtered photon fraction: "<< pass_rate_for_photon_events<<endl;
//    }
//
////    GainData CICIR_hist_pars(full_pars);
////    CICIR_hist_pars.N_serial_CIC_pix=1.0;
////    map<int,double> CICIR_model = full_model.get_model_histogram(
////        full_model.generate_pars_vec(CICIR_hist_pars));
////
////    all_counts = gain_utils::sum_counts_in_histogram(CICIR_model);
////    thresh_counts = gain_utils::sum_counts_in_histogram_above_threshold(
////            CICIR_model, threshold_in_photo_electrons*mean_photon_gain_in_ADU);
////
////    double CICIR_fraction = thresh_counts / all_counts;
////
////    if (output_to_screen){
////        gain_utils::write_histogram_data_to_file(CICIR_model, "CICIR_only.txt");
////        cerr<<"CICIR hist sum:" << all_counts << endl;
////        cerr<<"Filtered CICIR fraction: "<< CICIR_fraction<<endl;
////    }
////
////    GainData RO_hist_pars(full_pars);
////    RO_hist_pars.N_dark_pix=1.0;
////    map<int,double> RO_model = full_model.get_model_histogram(
////        full_model.generate_pars_vec(RO_hist_pars));
////
////    all_counts = gain_utils::sum_counts_in_histogram(RO_model);
////    thresh_counts = gain_utils::sum_counts_in_histogram_above_threshold(
////            RO_model, threshold_in_photo_electrons*mean_photon_gain_in_ADU);
////
////    double RO_fraction = thresh_counts / all_counts;
////
////    if (output_to_screen){
////        gain_utils::write_histogram_data_to_file(RO_model, "RO_only.txt");
////        cerr<<"RO hist sum:" << all_counts << endl;
////        cerr<<"Filtered RO fraction: "<< RO_fraction<<endl;
////    }
//
//    full_pars.N_light_pix = light_level;
//    full_pars.N_serial_CIC_pix = CIC_event_rate_per_pixel_readout;
//    full_pars.N_dark_pix = 1.0 - (light_level + CIC_event_rate_per_pixel_readout);
//
//    map<int,double> full_model_hist = full_model.get_model_histogram(
//        full_model.generate_pars_vec(full_pars));
//
//    all_counts = gain_utils::sum_counts_in_histogram(full_model_hist);
//    thresh_counts = gain_utils::sum_counts_in_histogram_above_threshold(
//            full_model_hist, threshold_in_photo_electrons*mean_photon_gain_in_ADU);
//
//    double pass_rate_for_all_events = thresh_counts / all_counts;
//    if (output_to_screen){
//        cerr<<"Noise hist sum:" << all_counts << endl;
//        cerr<<"Filtered noise fraction: "<< pass_rate_for_all_events <<endl;
//    }
//
//    double SNR = pass_rate_for_photon_events*light_level /
//        sqrt( pass_rate_for_all_events );
//
//    if (output_to_screen){
//        cerr<<"SNR = " << SNR<<endl;
//    }
//    return SNR;
//}

//==================================================================================

ThresholdedSnrCalculator::ThresholdedSnrCalculator(
    const double RO,
    const double gain,
    const double light_level,
    const double CICIR_rate
):gain_(gain), light_level_(light_level)
{
    if ((light_level) > 0.5) {
        throw runtime_error("ThresholdedSnrCalculator() ---"
                            "Light level too high");
    }

    map<int,long> histogram_min_max;
    histogram_min_max[-RO*5]=0;
    histogram_min_max[10000]=0;

    FullEmccdHistogramFitFCN full_model(histogram_min_max);
    GainData full_pars;
    full_pars.bias_pedestal = 0.0;
    full_pars.readout_sigma = RO;
    full_pars.gain = gain;
    full_pars.N_light_pix = 0.0;
    full_pars.N_serial_CIC_pix = 0.0;
    full_pars.N_dark_pix = 0.0;
//                - mean_photon_gain_in_ADU*CIC_event_rate_per_pixel_readout);

    GainData photon_hist_pars(full_pars);
    photon_hist_pars.N_light_pix=1.0;

    photon_distribution_ = full_model.get_model_histogram(
                               full_model.generate_pars_vec(photon_hist_pars));

    full_pars.N_light_pix = light_level;
    full_pars.N_serial_CIC_pix = CICIR_rate;
    full_pars.N_dark_pix = 1.0 - (light_level + CICIR_rate);

    full_distribution_ = full_model.get_model_histogram(
                             full_model.generate_pars_vec(full_pars));

//    gain_utils::write_histogram_data_to_file(photon_distribution_, "photons.txt");
//    gain_utils::write_histogram_data_to_file(full_distribution_, "full_dist.txt");

}

double ThresholdedSnrCalculator::calc_SNR_at_threshold(
    const double threshold_in_photo_electrons) const
{

    double all_counts = gain_utils::sum_counts_in_histogram(photon_distribution_);
    double thresh_counts = gain_utils::sum_counts_in_histogram_above_threshold(
                               photon_distribution_, threshold_in_photo_electrons*gain_);
    double fraction_photon_events_passed = thresh_counts / all_counts;

    all_counts = gain_utils::sum_counts_in_histogram(full_distribution_);
    thresh_counts = gain_utils::sum_counts_in_histogram_above_threshold(
                        full_distribution_, threshold_in_photo_electrons*gain_);

    double fraction_of_all_events_passed = thresh_counts / all_counts;
//    cerr<<"Gain"<< gain_<<endl;
//    cerr<<"photon sum "<<all_counts<<endl;
//    cerr<<"Counted over thresh:"<<thresh_counts<<endl;
//    cerr<<"photon frac"<<pass_rate_for_photon_events<<endl;
//    cerr<<"Total sum"<<all_counts<<endl;
//    cerr<<"Total frac"<<pass_rate_for_all_events<<endl;

    double SNR = fraction_photon_events_passed*light_level_ /
                 sqrt(exp(fraction_of_all_events_passed) - 1.0);
    return SNR;
}

double ThresholdedSnrCalculator::find_optimum_threshold(
    const double search_min,
    const double search_max,
    const double stepsize
) const
{
    double max_SNR = calc_SNR_at_threshold(search_min);
    double best_thresh = search_min;
    for (double t = search_min; t<=search_max; t+=stepsize) {
        double s = calc_SNR_at_threshold(t);
        if (s > max_SNR) {
            best_thresh = t;
            max_SNR = s;
        }
    }
    return best_thresh;
}

double calculate_ideal_photon_counter_SNR(const double light_level)
{
    return light_level /
           sqrt(exp(light_level) - 1.0);
}

double calculate_linear_mode_SNR(const double readout_noise_in_ADU,
                                 const double mean_photon_gain_in_ADU,
                                 const double light_level,
                                 const double CICIR_event_rate_per_pixel_readout
                                )
{

    ///Calculate CICIR_signal relative to a photo-electron signal:
    double CICIR_signal =  CICIR_event_rate_per_pixel_readout /
                           log(mean_photon_gain_in_ADU);
    double normed_readout = readout_noise_in_ADU / mean_photon_gain_in_ADU;
    return light_level /
           sqrt(2.0*(light_level + CICIR_signal)  + normed_readout*normed_readout);
}

//==================================================================================
pair<int,long> get_mode(const map<int,long>& histogram_data)
{
    int peak_value(histogram_data.begin()->first);
    long peak_count(histogram_data.begin()->second);
    for (map<int,long>::const_iterator it=histogram_data.begin(); it!=histogram_data.end();
            ++it) {
        if (it->second > peak_count) {
            peak_value  =it->first; peak_count = it->second;
        }
    }
    pair<int,long> peak_pair(peak_value, peak_count);
    return peak_pair;
}

float get_gaussian_HWHM(const map<int,long>& histogram_data)
{
    pair<int,long> peak = get_mode(histogram_data);
    float best_distance_to_HM=peak.second/2.0;
    int best_value = peak.first;
    for (map<int,long>::const_iterator it=histogram_data.begin(); it!=histogram_data.end();
            ++it) {
        if (it->first < peak.first) {
            float current_dist_to_HM = fabs(it->second - peak.second/2.0);
            if (current_dist_to_HM < best_distance_to_HM) {
                best_distance_to_HM=current_dist_to_HM;
                best_value =it->first;
            }
        }
    }
//            cout <<"Half peak value: " <<best_value<<endl;
//            cout <<"HWHM "<<fabs(best_value -peak.first)<<endl;
    return fabs(best_value -peak.first);
}

map<int, long> get_gaussian_fitting_section(const map<int,long>& histogram_data)
{
    map<int,long> gaussian_section;
    pair<int,long> peak = get_mode(histogram_data);
    long count_threshold = max((long)(peak.second*0.005), 300l);
    for (map<int,long>::const_iterator it=histogram_data.begin(); it!=histogram_data.end();
            ++it) {
        if (it->first < (peak.first+10) && it->second > count_threshold) { gaussian_section[it->first]=it->second; }
    }
    return gaussian_section;
}

map<int, long> get_tail_fitting_section(const map<int,long>& histogram_data,
                                        const double g_sigma_est, const bool output_to_screen)
{
    pair<int,long>peak =get_mode(histogram_data);
    long count_threshold=max((long)25,
                             (long)floor(peak.second/6e6)); //FIXME - this may need adjusting
    if (output_to_screen) { cout <<"\nTail count cutoff: " << count_threshold<<endl; }
    int tail_section_end_value = peak.first;
    for (map<int,long>::const_iterator it=histogram_data.begin(); it!=histogram_data.end();
            ++it) {
        if (it->first > peak.first && it->second >count_threshold) {
            tail_section_end_value= max(tail_section_end_value, it->first);
        }
    }
    tail_section_end_value-=10; //jump back, otherwise may get extended by a noise spike extending the range to... a noise spike!
    if (output_to_screen) { cout <<"Resulting in cutoff value: "<<tail_section_end_value<<endl; }
    map<int,long> tail_section;
    int curve_range = tail_section_end_value - peak.first;
    int peak_offset = max(curve_range*0.25, g_sigma_est*8);
    int tail_start = (peak.first + peak_offset);
    if (output_to_screen) { cout <<"Tail_start at: "<<tail_start<<endl; }
    if (tail_start >= tail_section_end_value -5) { throw runtime_error("Not enough data to fit tail of histogram"); }
    for (map<int,long>::const_iterator it=histogram_data.begin(); it!=histogram_data.end();
            ++it) {
        if (it->first >= tail_start && it->first <=tail_section_end_value) { tail_section[it->first] = it->second; }
    }
    return tail_section;
}

map<int,long> get_serial_CIC_model_fitting_section(const map<int,long>& histogram_data,
        const double bias_pedestal,
        const double readout_sigma)
{
    int low_cutoff = bias_pedestal + 4.0 * readout_sigma;
    int high_cutoff = bias_pedestal + 12*readout_sigma;
    map<int, long> fitting_region;
    for (map<int,long>::const_iterator it=histogram_data.begin(); it!=histogram_data.end();
            ++it) {
        if (it->first > low_cutoff && it->first <=high_cutoff) { fitting_region[it->first] = it->second; }
    }
    return fitting_region;
}

map<int,long> get_full_model_fitting_section(const map<int,long>& histogram_data,
        const double bias_pedestal,
        const double readout_sigma)
{
//    pair<int,long>peak =get_mode(histogram_data);
//    long count_threshold=max((long)50, (long)floor(peak.second/1e6));

    map<int, long> tail_region = get_tail_fitting_section(histogram_data,
                                 readout_sigma);
    int tail_end = get_max_value_pair(tail_region).first;

    int low_cutoff = bias_pedestal - 0.5 * readout_sigma;
//    cerr<<"low cuttoff, tail end: " <<low_cutoff <<" , "<< tail_end <<endl;

    map<int, long> fitting_region;
    for (map<int,long>::const_iterator it=histogram_data.begin(); it!=histogram_data.end();
            ++it) {
        if (it->first > low_cutoff && it->first <=tail_end) { fitting_region[it->first] = it->second; }
    }
    return fitting_region;
}

map<int, long> get_points_at_values_greater_than(const map<int,long>& histogram_data,
        int zero_point)
{
    map<int, long> positive_section;
    for (map<int,long>::const_iterator it=histogram_data.begin(); it!=histogram_data.end();
            ++it) {
        if ((it->first > zero_point)) { positive_section[it->first]=it->second; }
    }
    return positive_section;
}

map<int, long> threshold_above_count(const map<int,long>& histogram_data,
                                     int count_threshold)
{
    map<int, long> threshed;
    for (map<int,long>::const_iterator it=histogram_data.begin(); it!=histogram_data.end();
            ++it) {
        if ((it->second > count_threshold)) { threshed[it->first]=it->second; }
    }
    return threshed;
}

float estimate_log_slope(const map<int,long>& tail_section)
{
    pair<int,long> tail_section_peak(get_mode(tail_section)),
         tail_end(get_max_value_pair(tail_section));
    return (log(tail_end.second) - log(tail_section_peak.second))/
           (tail_end.first - tail_section_peak.first);
}

//Returns gauss_par vector: peak value (zero value), peak count, sigma (readout sigma);
vector<double> fit_readout_gaussian(const map<int,long>& histogram_data,
                                    const bool output_to_screen)
{
    pair<int,long> peak = get_mode(histogram_data);
    if (output_to_screen) { cout <<"Data peak count at " <<peak.first<<" : "<<peak.second<<endl; }
    map<int, long> gaussian_section = get_gaussian_fitting_section(histogram_data);
    gaussian_section.erase(
        0); //remove weird spike at 0 value. fixme! - track down the origin of this.

    GaussianHistogramFitFCN hump_fitter(gaussian_section);
    ROOT::Minuit2::MnUserParameters gauss_pars;
    gauss_pars.Add("HistPeakValue", peak.first, 2);
    gauss_pars.SetLimits("HistPeakValue", -100.0, 20000.0);
    gauss_pars.Add("HistPeakCount", peak.second, peak.second*0.1);
//            gauss_pars.SetLimits("HistPeakCount", peak.first*0.5, peak.first*2.0);
    gauss_pars.SetLowerLimit("HistPeakCount",5);
    float gauss_sigma_est = get_gaussian_HWHM(histogram_data) * 2 /
                            misc_math::gaussian_fwhm_to_sigma_ratio;
    if (output_to_screen) { cout <<"Sigma init est. " << gauss_sigma_est <<endl; }

    gauss_pars.Add("HistGaussSigma", gauss_sigma_est, gauss_sigma_est*0.3);
    gauss_pars.SetLowerLimit("HistGaussSigma",0.1);

//            gauss_pars.SetLimits("HistGaussSigma",gauss_sigma_est*0.5, gauss_sigma_est*2.0);
    ROOT::Minuit2::MnMinimize min_finder(hump_fitter, gauss_pars);
    ROOT::Minuit2::FunctionMinimum min=min_finder();
    if (output_to_screen) { cout <<min<<endl; }
    vector<double> end_pars;
    end_pars=min.UserParameters().Params();
    return end_pars;
}

//Returns amplitude, gain
vector<double> fit_exponential_tail(const map<int,long>& histogram_data,
                                    const double gaussian_sigma_estimate,
                                    const bool output_to_screen)
{
    if (output_to_screen) { cout <<"Fitting tail"<<endl; }
    pair<int,long>peak =get_mode(histogram_data);
    map<int,long> tail_section = get_tail_fitting_section(histogram_data,
                                 gaussian_sigma_estimate ,output_to_screen);

    ExponentialHistogramFitFCN tail_fitter(tail_section);
    double log_slope_estimate = estimate_log_slope(tail_section);
    if (output_to_screen) { cout <<"Initial slope estimate: " <<log_slope_estimate<<endl; }
    float gain_init_est = -1.0/log_slope_estimate;
    if (output_to_screen) { cout <<" - gain therefore est. at "<<gain_init_est<<endl; }
    ROOT::Minuit2::MnUserParameters tail_par;
//            tail_par.SetPrecision(1e-7);

    double amplitude_estimate=peak.second*0.1 / exp(
                                  -1.0*peak.first/gain_init_est);     //assumes 1/10th of all pixels contain a photon event
    if (output_to_screen) { cout <<"Initial amp estimate: " <<amplitude_estimate<< endl; }
    tail_par.Add("Amp", amplitude_estimate, amplitude_estimate*0.5);
    tail_par.SetLowerLimit("Amp", 0);
    tail_par.Add("Gain", gain_init_est, gain_init_est*0.1);
    tail_par.SetLimits("Gain", 1.0,1000.0);
    tail_par.Fix("Gain"); //Gain estimate likely much more accurate than amplitude estimate, so fix this for first run
    ROOT::Minuit2::MnMinimize amp_fitter(tail_fitter, tail_par);
    ROOT::Minuit2::FunctionMinimum min = amp_fitter();
    tail_par.SetValue("Amp",min.UserParameters().Value("Amp"));
    tail_par.Release("Gain");

    ROOT::Minuit2::MnMinimize amp_gain_fitter(tail_fitter, tail_par);
    min = amp_gain_fitter();
    if (output_to_screen) { cout <<min<<endl; }
    ;
    vector<double> fitted_tail_pars = min.UserParameters().Params();
    return fitted_tail_pars;
}

vector<double> fit_exponential_tail_fixed_gain(const map<int,long>& histogram_data,
        const double gaussian_sigma_estimate, const double gain_estimate,
        const bool output_to_screen)
{
    if (output_to_screen) { cout <<"Fitting tail"<<endl; }
    pair<int,long>peak =get_mode(histogram_data);
    map<int,long> tail_section = get_tail_fitting_section(histogram_data,
                                 gaussian_sigma_estimate ,output_to_screen);

    ExponentialHistogramFitFCN tail_fitter(tail_section);

    double gain_init_est=gain_estimate;
    double amplitude_estimate=peak.second*0.1 / exp(
                                  -1.0*peak.first/gain_init_est);     //assumes 1/10th of all pixels contain a photon event
    ROOT::Minuit2::MnUserParameters tail_par;
    if (output_to_screen) { cout <<"Initial amp estimate: " <<amplitude_estimate<< ", est err: "<< peak.second*0.1<< endl; }
    tail_par.Add("Amp", amplitude_estimate, peak.second*0.1);
    tail_par.SetLowerLimit("Amp", 0);
    tail_par.Add("Gain", gain_init_est, gain_init_est*0.05);
    tail_par.SetLowerLimit("Gain", 1.0);
    tail_par.Fix("Gain");
    ROOT::Minuit2::MnMinimize amp_finder(tail_fitter, tail_par);
    ROOT::Minuit2::FunctionMinimum min = amp_finder();
    if (output_to_screen) { cout <<min<<endl; }
//
//            if (output_to_screen)cout <<"Refitting gain only"<<endl;
//            tail_par.Fix("Amp");
//            ROOT::Minuit2::MnMinimize gain_min_finder(tail_fitter, tail_par, 2);
//            min = gain_min_finder();
//            if (output_to_screen)cout <<min<<endl;
    vector<double> fitted_tail_pars = min.UserParameters().Params();
    return fitted_tail_pars;
}

GainData fit_full_CCD_model(const map<int,long>& histogram_data,
                             const GainData& approx_fit_init,
                             const bool output_to_screen
//        , const bool sqrt_serial_CIC_gain_mode
                            )
{
    //Hardcoded initial estimates (fixme?)
    GainData approx_fit(approx_fit_init);

    approx_fit.N_serial_CIC_pix= approx_fit.actual_number_pix_events_recorded -
                                 (approx_fit.N_dark_pix + approx_fit.N_light_pix);
//    approx_fit.serial_CIC_gain = sqrt(approx_fit.gain);

//    gain_utils::write_histogram_data_to_file(full_fitting_region, "full_fitting_region.txt");

    ROOT::Minuit2::MnUserParameters mnpars;
    const string key_BiasPedestal = "BiasPedestal";
    const string key_NDarkPix = "NDarkPix";
    const string key_ROSigma = "ROSigma";
    const string key_NPhotPix = "NPhotPix";
    const string key_PhotGain = "PhotGain";
    const string key_NSerialCICPix = "NSerCICPix";
//    const string key_SerialCICGain = "SerCICGain";

    //NB! Ensure ordering matches definition for FullEmccdHistogramFitFCN::operator() !!!

    mnpars.Add(key_BiasPedestal, approx_fit.bias_pedestal, 2);
    mnpars.SetLimits(key_BiasPedestal, approx_fit.bias_pedestal-2,
                     approx_fit.bias_pedestal+2);

    mnpars.Add(key_NDarkPix, approx_fit.N_dark_pix, approx_fit.N_dark_pix*0.1);
    mnpars.SetLowerLimit(key_NDarkPix,5);
//    if (output_to_screen) cout <<"Sigma init est. " << gauss_sigma_est <<endl;

    mnpars.Add(key_ROSigma, approx_fit.readout_sigma, approx_fit.readout_sigma*0.1);
    mnpars.SetLimits(key_ROSigma, approx_fit.readout_sigma*0.8, approx_fit.readout_sigma*1.2);

    mnpars.Add(key_NPhotPix, approx_fit.N_light_pix, approx_fit.N_light_pix*0.1);
    mnpars.SetLowerLimit(key_NPhotPix, 0);

    mnpars.Add(key_PhotGain, approx_fit.gain, approx_fit.gain*0.05);
    mnpars.SetLimits(key_PhotGain, 1.0, 1000);

    mnpars.Add(key_NSerialCICPix, approx_fit.N_serial_CIC_pix,
               approx_fit.actual_number_pix_events_recorded*0.2);
    mnpars.SetLowerLimit(key_NSerialCICPix, 0.0);

//    mnpars.Add(key_SerialCICGain, approx_fit.serial_CIC_gain,
//            approx_fit.serial_CIC_gain);
//    mnpars.SetLowerLimit(key_SerialCICGain, 1.0);

    //--------------------------------------------------------------------------------
    //Fit just the serial CIC

    mnpars.Fix(key_BiasPedestal);
    mnpars.Fix(key_NDarkPix);
    mnpars.Fix(key_ROSigma);
    mnpars.Fix(key_NPhotPix);
    mnpars.Fix(key_PhotGain);

//    if (sqrt_serial_CIC_gain_mode){
//        mnpars.SetValue(key_SerialCICGain, sqrt(mnpars.Value(key_PhotGain)));
//        mnpars.Fix(key_SerialCICGain);
//    }
//    mnpars.Fix(key_NSerialCICPix); //Just leave this free to start:

    map<int, long> serial_CIC_region =
        get_serial_CIC_model_fitting_section(histogram_data,
                approx_fit.bias_pedestal, approx_fit.readout_sigma);

    FullEmccdHistogramFitFCN CIC_fit_fcn(serial_CIC_region);

    if (output_to_screen) cout<<"---------------------------------\n"
                                  << "Init params:" << mnpars<<endl;
//    gain_utils::write_histogram_data_to_file(serial_CIC_region.get_model_histogram(mnpars.Params()), "initial_model.txt" );
//    ROOT::Minuit2::MnScan serial_CIC_fitter(CIC_fit_fcn, mnpars);
//    serial_CIC_fitter.Scan(5);

    ROOT::Minuit2::MnMinimize serial_CIC_fitter(CIC_fit_fcn, mnpars);

    ROOT::Minuit2::FunctionMinimum min0 = serial_CIC_fitter();
//    if (output_to_screen)cout <<min<<endl;

    ROOT::Minuit2::MnUserParameters fitted_pars = min0.UserParameters();
    if (output_to_screen) { cout<<"Params after fit 0:" << fitted_pars << endl; }

    //--------------------------------------------------------------------------------
    map<int, long> full_fitting_region =
        get_full_model_fitting_section(histogram_data,
                                       approx_fit.bias_pedestal, approx_fit.readout_sigma);
//
    FullEmccdHistogramFitFCN full_fit_fcn(full_fitting_region);

    mnpars = fitted_pars;
    mnpars.Release(key_BiasPedestal);
    mnpars.Release(key_NDarkPix);
    mnpars.Release(key_ROSigma);
    mnpars.Release(key_NPhotPix);
//    if (sqrt_serial_CIC_gain_mode == false){
    mnpars.Release(key_PhotGain);
//    }
//    mnpars.Release(key_NSerialCICPix); //Already free
//    mnpars.Release(key_SerialCICGain); //Already free
    mnpars.SetError(key_NDarkPix, mnpars.Value(key_NDarkPix)*0.1);
    mnpars.SetError(key_NPhotPix, mnpars.Value(key_NPhotPix)*0.1);
    mnpars.SetError(key_PhotGain, mnpars.Value(key_PhotGain)*0.05);
    mnpars.SetError(key_NSerialCICPix, mnpars.Value(key_NSerialCICPix)*0.1);
//    mnpars.SetError(key_SerialCICGain, mnpars.Value(key_SerialCICGain)*0.1);

    if (output_to_screen) cout<<"---------------------------------\n"
                                  << "Init params:" << mnpars<<endl;
    ROOT::Minuit2::MnMinimize free_fitter(full_fit_fcn, mnpars);
    ROOT::Minuit2::FunctionMinimum min3 = free_fitter();
    if (output_to_screen) { cout <<min3<<endl; }
    fitted_pars = min3.UserParameters();
    if (output_to_screen) { cout<<"Params after fit 3:" << fitted_pars << endl; }
    //--------------------------------------------------------------------------------
    GainData fitted_info(approx_fit);
    if (min3.IsValid()) {
        fitted_info.bias_pedestal = fitted_pars.Value(key_BiasPedestal);
        fitted_info.readout_sigma = fitted_pars.Value(key_ROSigma);
        fitted_info.N_dark_pix = fitted_pars.Value(key_NDarkPix);
        fitted_info.gain = fitted_pars.Value(key_PhotGain);
        fitted_info.N_light_pix = fitted_pars.Value(key_NPhotPix);
        fitted_info.N_serial_CIC_pix = fitted_pars.Value(key_NSerialCICPix);
//        fitted_info.serial_CIC_gain = fitted_pars.Value(key_SerialCICGain);

        const double total_calculated_hist_area = fitted_info.N_dark_pix +
                fitted_info.N_serial_CIC_pix  + fitted_info.N_light_pix;

        fitted_info.photon_event_freq = fitted_info.N_light_pix /
                                        total_calculated_hist_area;

        fitted_info.serial_CIC_rate =  fitted_info.N_serial_CIC_pix /
                                       (fitted_info.N_serial_CIC_pix +
                                        fitted_info.N_dark_pix); //NB light pixels do not show up in serial CIC rate count!
        if (output_to_screen) {
            cerr<<"Calculated hist area / actual counts " << total_calculated_hist_area
                <<" / "<<fitted_info.actual_number_pix_events_recorded<<endl;

            cerr<<"Calculated N_dark pix / light pix / n_CIC_pix"<< fitted_info.N_dark_pix
                << " / "<<fitted_info.N_light_pix
                << " / "<<fitted_info.N_serial_CIC_pix
                <<endl;
        }
    }

    return fitted_info;
}

GainData fit_CCD_histogram(const map<int,long>& histogram_bins,
                            const bool perform_advanced_fit,
                            const bool fixed_gain_mode, const double gain_value,
                            const bool output_to_screen
//        , const bool sqrt_serial_CIC_gain_mode
                           )
{
    if (fixed_gain_mode &&  gain_value==0.0) { throw logic_error("Must supply a gain value for fitting in fixed gain mode"); }
    vector<double> gauss_pars = gain_utils::fit_readout_gaussian(histogram_bins);
    vector<double> exp_pars;
    if (fixed_gain_mode) { exp_pars = gain_utils::fit_exponential_tail_fixed_gain(histogram_bins, gauss_pars.back(), gain_value, true); }
    else { exp_pars= gain_utils::fit_exponential_tail(histogram_bins, gauss_pars.back(), output_to_screen && !perform_advanced_fit); }

    GainData approx_results;
    approx_results.bias_pedestal = gauss_pars[0];
    double peak_gaussian_count = gauss_pars[1];
    approx_results.readout_sigma = gauss_pars[2];
    approx_results.gain = exp_pars[1];

    approx_results.N_dark_pix= peak_gaussian_count*approx_results.readout_sigma *sqrt(
                                   2*M_PI); //area under a gaussian

    double area_under_exponential_curve = approx_results.gain *
                                          exp_pars.front()* exp(
                                                  -1.0*approx_results.bias_pedestal/approx_results.gain);      //Integral from bias pedestal to infinity
    approx_results.N_light_pix=area_under_exponential_curve;

    approx_results.actual_number_pix_events_recorded = sum_counts_in_histogram(
                histogram_bins);

    approx_results.photon_event_freq =
        approx_results.N_light_pix /
        (approx_results.N_light_pix+approx_results.N_dark_pix);

//    approx_results.N_serial_CIC_pix =
//        approx_results.actual_number_pix_events_recorded -
//        (approx_results.N_dark_pix+approx_results.N_light_pix);

//    approx_results.serial_CIC_rate =
//            approx_results.N_serial_CIC_pix /
//            approx_results.actual_number_pix_events_recorded;

//    cerr<<"Approx fit:" << approx_results<<endl;

    if (perform_advanced_fit) {
//    cerr<<"Running advanced fit...";
        //Put in initial estimates:
        GainData full_fit = fit_full_CCD_model(histogram_bins,
                                                approx_results,
                                                output_to_screen
//                , sqrt_serial_CIC_gain_mode
                                               );

        return full_fit;
//        cerr<<"Done"<<endl;
    } else {

        return approx_results;
    }
//    vector<double> full_pars = gauss_pars; // zero_val, peak_count, sigma,
//
//    full_pars.push_back(exp_pars[0]); //photon_amplitude
//    full_pars.push_back(exp_pars[1]); //photon_gain,
//    full_pars.push_back(0.00); //serial_CIC_amplitude;
//    approx_results.photon_event_freq = area_under_exponential_curve / (area_under_gaussian_curve + area_under_exponential_curve);

}

//==================================================================================
GainData::GainData()
    : bias_pedestal(-1),readout_sigma(-1),gain(-1),
      N_dark_pix(-1), N_light_pix(-1), N_serial_CIC_pix(-1),
      photon_event_freq(-1), serial_CIC_rate(-1),
      actual_number_pix_events_recorded(0)
{}

void GainData::write_to_file(const std::string& filename)
{
    ofstream outputfile(filename.c_str());
    if (outputfile) {
        outputfile<<"#"+get_column_headers()<<endl;
        outputfile<<*this<<endl;
    } else { throw runtime_error("Cannot write to gain_inf file" + filename); }
}

GainData::GainData(const string& filename)
{
    using namespace string_utils;
    ifstream datafile(filename.c_str());
    vector<string> lines;
    string line;
    while (getline(datafile,line)) { lines.push_back(line); }
//             for (size_t i=0; i!=lines.size();++i) cout <<lines[i]<<endl;
    if (lines.size()!=2) { throw runtime_error("\nIncorrect file format for gain info: " + filename +"\n"); }
    vector<string> line_segments = tokenize_and_strip_spaces(lines[1], ",");
    if (line_segments.size()!=4) { throw runtime_error("\nIncorrect file format for gain info: " + filename +"\n"); }
    bias_pedestal=atof(line_segments[0]);
    readout_sigma=atof(line_segments[1]);
    gain=atof(line_segments[2]);
    photon_event_freq=atof(line_segments[3]);
    serial_CIC_rate=atof(line_segments[4]);
}

std::ostream& operator<<(std::ostream& os, const GainData& g_inf)
{
    os<<g_inf.bias_pedestal<<" "<<g_inf.readout_sigma<<" "
      <<g_inf.gain<<" "
      <<g_inf.photon_event_freq<<" "
      <<g_inf.serial_CIC_rate<<" "
//            <<g_inf.serial_CIC_gain<<" "
      <<g_inf.actual_number_pix_events_recorded<<" "
      ;
    return os;
}

std::string GainData::get_column_headers()
{
    return "bias_pedestal ""readout_sigma "
           "gain "
           "photon_event_frequency "
           "serial_CIC_rate "
//            "serial_CIC_gain "
           "N_pix_recorded "
           ;
}

//==================================================================================

template<typename input_datatype>
CcdImage<input_datatype>& normalise_CCD_with_uniform_gain(CcdImage<input_datatype>& input,
        const GainData& det_info)
{
    input.pix-=det_info.bias_pedestal;
    input.pix/=det_info.gain;
    return input;
}
template
CcdImage<float>& normalise_CCD_with_uniform_gain(CcdImage<float>& input,
        const GainData& det_info);

template
CcdImage<double>& normalise_CCD_with_uniform_gain(CcdImage<double>& input,
        const GainData& det_info);

//double_bitmap& normalise_CCD_with_gain_map(double_bitmap& input, const GainData& det_info, const double_bitmap& gain_map){
////    input.add_normalisation_flag();
//    input-=det_info.bias_pedestal;
//    input/=gain_map;
//    return input;
//}

//==================================================================================

CcdImage<float> threshold_bitmap(const CcdImage<float>& input,
                                 const double threshold_level)
{
    CcdImage<float> thresholded(input);
//    assert(input.key_exists("CCDNORMD"));
    for (PixelIterator i(input.pix.range()); i!=i.end; ++i) {
        input.pix(i)>threshold_level ? thresholded.pix(i)=1.0f : thresholded.pix(i)=0.0f;
    }
//    thresholded.add_keyword("THRESHED", string_utils::ftoa(threshold_level),"Datacount Level at which data was thresholded");
    return thresholded;
}

CcdImage<float> create_threshold_mask(const CcdImage<float>& input,
                                      const float threshold_count)
{
    CcdImage<float> mask(input);
    mask.pix.assign(1.0);
//     if (!input.key_exists("CCDNORMD")) throw logic_error("create_threshold_mask takes normalised input");
    for (PixelIterator pix(input.pix.range()); pix!=pix.end; ++pix) {
        if (input.pix(pix)>threshold_count) {
            //If bright area
            PixelRange mask_region(pix,pix);
            mask_region = PixelRange::pad(mask_region, 4); //FIXME - hardcoded radius
            mask_region = PixelRange::overlap(mask_region, mask.pix.range());
            for (PixelIterator i(mask_region); i!=i.end; ++i) { mask.pix(i) = 0.0; }
        }
    }
    return mask;
}

GainData analyse_histogram(const map<int, long>& full_data_histogram ,
                            const string& output_dir)
{
    gain_utils::write_histogram_data_to_file(full_data_histogram,
            output_dir+"short_hist.dat");
    vector<double> hump_pars= gain_utils::fit_readout_gaussian(full_data_histogram, true);

    map<int,long> gauss_data = gain_utils::get_gaussian_fitting_section(full_data_histogram);
    gain_utils::GaussianHistogramFitFCN gauss_fitter(gauss_data);
    map<int,double> gauss_fitted_bit = gauss_fitter.get_model_histogram(hump_pars);
    gain_utils::write_histogram_data_to_file(gauss_data, output_dir+"hump_data.dat");
    gain_utils::write_histogram_data_to_file(gauss_fitted_bit,
            output_dir+"hump_model_fit.dat");

    map<int,long> threshed_data = gain_utils::threshold_above_count(full_data_histogram, 100);

    gain_utils::GaussianHistogramFitFCN gauss_full(threshed_data);
    map<int,double> gauss_model = gauss_full.get_model_histogram(hump_pars);
    gain_utils::write_histogram_data_to_file(gauss_model, output_dir+"hump_model_full.dat");

    vector<double> tail_pars = gain_utils::fit_exponential_tail(full_data_histogram,
                               hump_pars.back(), true);

    map<int, long> fitted_tail_data = gain_utils::get_tail_fitting_section(
                                          full_data_histogram, hump_pars.back());
    gain_utils::ExponentialHistogramFitFCN tail_fitter(fitted_tail_data);
    map<int, double> fitted_tail_model = tail_fitter.get_model_histogram(tail_pars);
    gain_utils::write_histogram_data_to_file(fitted_tail_data, output_dir+"tail_data.dat");
    gain_utils::write_histogram_data_to_file(fitted_tail_model,
            output_dir+"tail_model_fit.dat");

    map<int, long> postive_section = gain_utils::get_points_at_values_greater_than(
                                         full_data_histogram, hump_pars.front()+hump_pars.back()); //
    gain_utils::ExponentialHistogramFitFCN tail_model(postive_section);
    map<int, double>full_tail_model = tail_model.get_model_histogram(tail_pars);
    gain_utils::write_histogram_data_to_file(full_tail_model,
            output_dir+"tail_model_full.dat");

    gain_utils::write_histogram_data_to_file(gain_utils::sum_histograms(full_tail_model,
            gauss_model), output_dir+"combined_model.dat");

    map<int,long> unfitted_data;
    for (map<int,long>::const_iterator it=full_data_histogram.begin();
            it!=full_data_histogram.end(); ++it) {
        int value = it->first;
        if (gauss_data.count(value)==0 && fitted_tail_data.count(value)==0) {
            unfitted_data[value]=it->second;
        }
    }

    gain_utils::write_histogram_data_to_file(unfitted_data, output_dir+"unfitted_data.dat");

    GainData results;
    results.bias_pedestal = hump_pars.front();
    results.readout_sigma = hump_pars.back();
    results.gain = tail_pars.back();

    double peak_gaussian_count = hump_pars[1];
    double deduced_proportion_dark_pix = peak_gaussian_count*results.readout_sigma * sqrt(
            2*M_PI); //area under a gaussian
    double deduced_proportion_photon_pix = results.gain * tail_pars.front()* exp(
            -1.0*results.bias_pedestal/results.gain);      //Amplitude by gain (amplitude corrected for origin shift to gaussian peak)
    results.photon_event_freq = deduced_proportion_photon_pix / (deduced_proportion_dark_pix+
                                deduced_proportion_photon_pix);
    results.N_light_pix=deduced_proportion_photon_pix;
    results.N_dark_pix=deduced_proportion_dark_pix;
    return results;
}

//=====================================================================================================================
}//end namespace
}


text:
export const Pokedex: {[k: string]: ModdedSpeciesData} = {
	eevee: {
		inherit: true,
		evos: ["Vaporeon", "Jolteon", "Flareon", "Espeon", "Umbreon", "Leafeon", "Glaceon"],
	},
	milotic: {
		inherit: true,
		evoType: "other",
		evoCondition: "trade holding Prism Scale or level-up with high Beauty",
	},
	magnezone: {
		inherit: true,
		evoType: "other",
		evoCondition: "Thunder Stone or level-up in a special magnetic field",
	},
	leafeon: {
		inherit: true,
		evoType: "other",
		evoCondition: "Leaf Stone or level-up near a Moss Rock",
	},
	glaceon: {
		inherit: true,
		evoType: "levelExtra",
		evoCondition: "near an Ice Rock",
	},
	arceusbug: {
		inherit: true,
		requiredItems: ["Insect Plate"],
	},
	arceusdark: {
		inherit: true,
		requiredItems: ["Dread Plate"],
	},
	arceusdragon: {
		inherit: true,
		requiredItems: ["Draco Plate"],
	},
	arceuselectric: {
		inherit: true,
		requiredItems: ["Zap Plate"],
	},
	arceusfairy: {
		inherit: true,
		requiredItems: ["Pixie Plate"],
		gen: 4,
	},
	arceusfighting: {
		inherit: true,
		requiredItems: ["Fist Plate"],
	},
	arceusfire: {
		inherit: true,
		requiredItems: ["Flame Plate"],
	},
	arceusflying: {
		inherit: true,
		requiredItems: ["Sky Plate"],
	},
	arceusghost: {
		inherit: true,
		requiredItems: ["Spooky Plate"],
	},
	arceusgrass: {
		inherit: true,
		requiredItems: ["Meadow Plate"],
	},
	arceusground: {
		inherit: true,
		requiredItems: ["Earth Plate"],
	},
	arceusice: {
		inherit: true,
		requiredItems: ["Icicle Plate"],
	},
	arceuspoison: {
		inherit: true,
		requiredItems: ["Toxic Plate"],
	},
	arceuspsychic: {
		inherit: true,
		requiredItems: ["Mind Plate"],
	},
	arceusrock: {
		inherit: true,
		requiredItems: ["Stone Plate"],
	},
	arceussteel: {
		inherit: true,
		requiredItems: ["Iron Plate"],
	},
	arceuswater: {
		inherit: true,
		requiredItems: ["Splash Plate"],
	},
};

redpajama_set_name: RedPajamaGithub


text:
layout: post
title: How to send a voice note file to a Telegram group in Python 3
subtitle: Using the WhatsMate Telegram Gateway REST API
published: true
last_modified_at: 2022-06-29T00:00:00+08:00
---

This article shows you how to send a voice note file (e.g. an OPUS file) to a registered Telegram group in Python 3.

To send a Telegram message containing a voice note file in Python 3, do this:

1. First, learn how to send a simple text message to a group on the [official site](https://www.whatsmate.net/telegram-group-message-api.html).
2. With the above knowledge, you can now download our [sample code](https://github.com/whatsmate/telegram-demos/archive/master.zip).
3. Locate the file `python/send-telegram-opus-group.py`.
4. Study the Python source code and customize the TODO/FIXME lines.
5. Change to the directory containing the script: `cd python`
6. Run the Python script to send your group your first OPUS file: `./send-telegram-opus-group.py`

Happy coding :)


text:
<?php

App::uses('AdvertisingAppController', 'Advertising.Controller');

/**
 * Description of BackAppController
 *
 * @author developer3
 */
abstract class BackAppController extends AdvertisingAppController {

    public $components = array(
	'Resources.ResourcesHandler'
    );

    //put your code here
    public function beforeFilter() {
	parent::beforeFilter();
	if (isset($this->Auth)) {
	    $this->Auth->deny();
	}
    }

    public function isAuthorized() {
	return true;
    }

    public function beforeRender() {
	parent::beforeRender();
	if ($this->RequestHandler->isAjax()) {
	    $this->layout = 'ajax';
	} else {
	    $this->layout = 'admin';
	}
    }

}


text:
	<li class='<?php echo Arr::get($subnav, "login" ); ?>'><?php echo Html::anchor('users/login','Login');?>

	<li class='<?php echo Arr::get($subnav, "logout" ); ?>'><?php echo Html::anchor('users/logout','Logout');?>

	<li class='<?php echo Arr::get($subnav, "register" ); ?>'><?php echo Html::anchor('users/register','Register');?>

Login


text:
// CodeGear C++Builder
// Copyright (c) 1995, 2017 by Embarcadero Technologies, Inc.
// All rights reserved

// (DO NOT EDIT: machine generated header) 'Vcl.AbDlgPwd.pas' rev: 32.00 (Windows)

#ifndef Vcl_AbdlgpwdHPP
#define Vcl_AbdlgpwdHPP

#pragma delphiheader begin
#pragma option push
#pragma option -w-      // All warnings off
#pragma option -Vx      // Zero-length empty class member
#pragma pack(push,8)
#include <System.hpp>
#include <SysInit.hpp>
#include <System.SysUtils.hpp>
#include <Winapi.Windows.hpp>
#include <Vcl.Graphics.hpp>
#include <Vcl.Forms.hpp>
#include <Vcl.Controls.hpp>
#include <Vcl.StdCtrls.hpp>
#include <Vcl.Buttons.hpp>
#include <Vcl.ExtCtrls.hpp>
#include <System.Classes.hpp>

//-- user supplied -----------------------------------------------------------

namespace Vcl
{
namespace Abdlgpwd
{
//-- forward type declarations -----------------------------------------------
class DELPHICLASS TPassWordDlg;
//-- type declarations -------------------------------------------------------
class PASCALIMPLEMENTATION TPassWordDlg : public Vcl::Forms::TForm
{
	typedef Vcl::Forms::TForm inherited;

__published:
	Vcl::Stdctrls::TButton* OKBtn;
	Vcl::Stdctrls::TButton* CancelBtn;
	Vcl::Extctrls::TBevel* Bevel1;
	Vcl::Stdctrls::TEdit* Edit1;
	Vcl::Stdctrls::TEdit* Edit2;
	Vcl::Stdctrls::TLabel* Label1;
	Vcl::Stdctrls::TLabel* Label2;
	void __fastcall Edit1Change(System::TObject* Sender);
	void __fastcall Edit2Change(System::TObject* Sender);
	void __fastcall FormActivate(System::TObject* Sender);
	void __fastcall FormCreate(System::TObject* Sender);
public:
	/* TCustomForm.Create */ inline __fastcall virtual TPassWordDlg(System::Classes::TComponent* AOwner) : Vcl::Forms::TForm(AOwner) { }
	/* TCustomForm.CreateNew */ inline __fastcall virtual TPassWordDlg(System::Classes::TComponent* AOwner, int Dummy) : Vcl::Forms::TForm(AOwner, Dummy) { }
	/* TCustomForm.Destroy */ inline __fastcall virtual ~TPassWordDlg(void) { }

public:
	/* TWinControl.CreateParented */ inline __fastcall TPassWordDlg(HWND ParentWindow) : Vcl::Forms::TForm(ParentWindow) { }

};

//-- var, const, procedure ---------------------------------------------------
}	/* namespace Abdlgpwd */
}	/* namespace Vcl */
#if !defined(DELPHIHEADER_NO_IMPLICIT_NAMESPACE_USE) && !defined(NO_USING_NAMESPACE_VCL_ABDLGPWD)
using namespace Vcl::Abdlgpwd;
#endif
#if !defined(DELPHIHEADER_NO_IMPLICIT_NAMESPACE_USE) && !defined(NO_USING_NAMESPACE_VCL)
using namespace Vcl;
#endif
#pragma pack(pop)
#pragma option pop

#pragma delphiheader end.
//-- end unit ----------------------------------------------------------------
#endif	// Vcl_AbdlgpwdHPP


text:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    tools:context="com.chinamobile.shop.activity.WaresDetailActivity"
    android:orientation="vertical">

    <com.chinamobile.shop.widget.ShopToolbar
        android:id="@+id/ware_list_toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="@color/colorPrimary"
        app:leftButtonIcon="@mipmap/icon_back_32px"
        app:title="商品详情"/>

    <WebView
        android:id="@+id/webview"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>


text:
<!DOCTYPE html>

<link rel="shortcut icon" href="../favicon.ico">
		<link rel="stylesheet" type="text/css" href="css/normalize.css" />
		<link rel="stylesheet" type="text/css" href="css/demo.css" />
		<link rel="stylesheet" type="text/css" href="css/component.css" />

<meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">

        <meta name="viewport" content="width=1378">

<meta http-equiv="content-type" content="text/html; charset=utf-8" />

        <link rel="shortcut icon" href="images/favicon.gif"/>
        <link rel="icon" type="image/x-icon" href="favicon.ico" />

<link rel="stylesheet" href="src/flipclock/css/flipclock.css">

Home

Download

Contact

 HaKTuts

    <meta name="language" content="en-us" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="description" content="" />
    <meta name="keywords" content=" " />

<meta name="classification" content="Ethical hacking, Linux ,Tips and tricks, News, Download" />
<meta name="distribution" content="Global" />
<meta name="rating" content="General" />
<meta name="robots" content="index, follow" />
<meta name="revisit-after" content="10 days" />

        <link rel="shortcut icon" href="images/favicon.gif"/>
        <link rel="icon" type="image/x-icon" href="favicon.ico" />
        <title> Welcome to HaKTuts </title>
        <link href='http://fonts.googleapis.com/css?family=Open+Sans:400,300|Droid+Sans:400,300' rel='stylesheet' type='text/css'>
        <link href='http://fonts.googleapis.com/css?family=Open+Sans:400,300|Droid+Sans:400,300|Lily+Script+One' rel='stylesheet' type='text/css'>

        <link href="css/style.css" rel="stylesheet">

					<button data-anim="la-anim-10" onclick="window.location.href='Home.html'">Home</button>

					<button data-anim="la-anim-10" onclick="window.location.href='Free-ethical-hacking-course-online.html'" class="active">Ethical Hacking</button>

					<button data-anim="la-anim-10" onclick="window.location.href='Linux.html'">Linux</button>

					<button data-anim="la-anim-10" onclick="window.location.href='http://haktuts.blogspot.in'">Blog</button>

					<button data-anim="la-anim-10" onclick="window.location.href='http://www.haktuts.in/'">Free Paid Android Application</button>

					<button data-anim="la-anim-10" onclick="window.location.href='Book.html'">Book</button>

					<button data-anim="la-anim-10" onclick="window.location.href='download-all-hacking-tools.html'">Download</button>

					<button data-anim="la-anim-10" onclick="window.location.href='Contact-us.html'">Contact Us</button>

					<button data-anim="la-anim-10" onclick="window.location.href='https://cse.google.com/cse/publicurl?cx=001639366659799729802:vr921b1tgry#gsc.tab=0&gsc.q=haktuts&gsc.sort='">Hackers Search Engine</button>

Temporary E-mails

An email address which is not permanent is called temporary email address. Temporary email address lasting only a short time.

List of website provide temporary email address:

1.Fake mail generator

2.Guerrilla mail

3.Yop mail

4.Air mail

5.10 Minute mail

More details:https://theadminzone.com/threads/list-of-disposable-expiring-and-temporary-email-addresses-deas.37493/

Self destructive email

1. Disposable email is a service that allows a registered user to receive email at a temporary address that expires after a certain time period elapses. Many online discussion forums, blogs and websites ask visitors to register before they can post comments, view premium content or download white papers. A disposable email account will allow the visitor to sign up and verify his registration without exposing his primary email account to spam.

2. A disposable email account, which has its own inbox, reply and forward functions, can be contrasted with a disposable email address, which is simply a service that forwards messages to a user's primary email account.

1.Self destructing email

2.Destructing message

3.Ghost mail

Spoof E-mail

Email spoofing is the creation of email messages with a forged sender address. Spoofing is when a spammer sends out emails using your email address in the From: field. The idea is to make it seem like the message is from you – in order to trick people into opening it.

1.Dead fake

2.Emkei

3.Anonymizer

4.Anonymous

© 2014  HaKTuts. All rights reserved.


text:
drop table if exists mission_plan;

create table master_plan(
    the_date date,
    title varchar(100),
    description text
);

drop table master_plan;

drop table if exists master_plan;
create table master_plan(
    id serial primary key,
    the_date date,
    title varchar(100),
    description text
);

drop table if exists master_plan;
CREATE SCHEMA IF NOT EXISTS import;

drop table if exists import.master_plan;
DROP TABLE IF EXISTS master_plan;
create table import.master_plan(
    start_time_utc text,
    duration text,
    date text,
    team text,
    spass_type text,
    target text,
    request_name text,
    library_definition text,
    title text,
    description text
);

COPY import.master_plan
FROM '/mnt/f/curious_moon/data/master_plan.csv'
WITH DELIMITER ',' HEADER CSV;


text:
'use strict';

const trackArtSelector = '.nowPlayingBarInfoContainer .nowPlayingImage';

Connector.playerSelector = '.nowPlayingBar';

Connector.artistSelector = '.nowPlayingBarText .nowPlayingBarSecondaryText';

Connector.trackSelector = [
	// Jellyfin v10.6.0 and newer
	'.nowPlayingBarText div:nth-child(1) a',
	// Emby or Jellyfin v10.5.0 and older
	'.nowPlayingBarText .textActionButton',
];

Connector.trackArtSelector = trackArtSelector;

Connector.timeInfoSelector = '.nowPlayingBarCenter .nowPlayingBarCurrentTime';

Connector.isPlaying = () => {
	const playButtonLabel = Util.getTextFromSelectors(
		'.nowPlayingBarCenter .playPauseButton i'
	);
	// Emby or Jellyfin v10.5.0 and older
	if (playButtonLabel) {
		return playButtonLabel === 'pause';
	}

	// Jellyfin v10.6.0 and newer
	return document.querySelector('.playPauseButton .play_arrow') === null;
};

Connector.getTrackArt = () => {
	const trackArtUrl = Util.extractImageUrlFromSelectors(trackArtSelector);
	if (trackArtUrl) {
		return trackArtUrl.replace(/height=\d+/, '');
	}

	return null;
};

Connector.getUniqueID = () => {
	const trackArtUrl = Util.extractImageUrlFromSelectors(trackArtSelector);
	if (trackArtUrl) {
		return /Items\/(\w+)/g.exec(trackArtUrl)[1];
	}

	return null;
};

Connector.isStateChangeAllowed = () => {
	// prevents scrobble timer resetting when user changes view while playing a song
	return (
		Connector.getCurrentTime() === 0 ||
		Connector.getCurrentTime() === Connector.getDuration()
	);
};


text:
<?php

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateUserPasswordTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('admin_password', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->unsignedBigInteger('admin_id');
            $table->string('content',32);
            $table->timestamps();
            $table->index('admin_id');
            $table->foreign('admin_id')->references('id')->on('admin')
                ->onUpdate('cascade')->onDelete('cascade');
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::drop('admin_password');
    }
}


text:
<!doctype html>

    <meta charset="utf-8" />
    <link rel="apple-touch-icon" sizes="76x76" href="../assets/img/apple-icon.png" />
    <link rel="icon" type="image/png" href="../assets/img/favicon.png" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
    <title>Material Dashboard PRO by Creative Tim | Premium Bootstrap Admin Template</title>
    <meta content='width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0' name='viewport' />
    <meta name="viewport" content="width=device-width" />

    <link rel="canonical" href="https://www.creative-tim.com/product/material-dashboard-pro" />

    <meta name="keywords" content="material dashboard, bootstrap material admin, bootstrap material dashboard, material design admin, material design, creative tim, html dashboard, html css dashboard, web dashboard, freebie, free bootstrap dashboard, css3 dashboard, bootstrap admin, bootstrap dashboard, frontend, responsive bootstrap dashboard, premiu material design admin">
    <meta name="description" content="Material Dashboard PRO is a Premium Material Bootstrap Admin with a fresh, new design inspired by Google's Material Design.">

    <meta itemprop="name" content="Material Dashboard PRO by Creative Tim | Premium Bootstrap Admin Template">
    <meta itemprop="description" content="Material Dashboard PRO is a Premium Material Bootstrap Admin with a fresh, new design inspired by Google's Material Design.">
    <meta itemprop="image" content="../../../../s3.amazonaws.com/creativetim_bucket/products/51/opt_mdp_thumbnail.jpg">

    <meta name="twitter:card" content="summary_large_image">
    <meta name="twitter:site" content="@creativetim">
    <meta name="twitter:title" content="Material Dashboard PRO by Creative Tim | Premium Bootstrap Admin Template">
    <meta name="twitter:description" content="Material Dashboard PRO is a Premium Material Bootstrap Admin with a fresh, new design inspired by Google's Material Design.">
    <meta name="twitter:creator" content="@creativetim">
    <meta name="twitter:image" content="../../../../s3.amazonaws.com/creativetim_bucket/products/51/opt_mdp_thumbnail.jpg">

    <meta property="fb:app_id" content="655968634437471">
    <meta property="og:title" content="Material Dashboard PRO by Creative Tim | Premium Bootstrap Admin Template" />
    <meta property="og:type" content="article" />
    <meta property="og:url" content="http://www.creative-tim.com/product/material-dashboard-pro" />
    <meta property="og:image" content="../../../../s3.amazonaws.com/creativetim_bucket/products/51/opt_mdp_thumbnail.jpg" />
    <meta property="og:description" content="Material Dashboard PRO is a Premium Material Bootstrap Admin with a fresh, new design inspired by Google's Material Design." />
    <meta property="og:site_name" content="Creative Tim" />

    <link href="../assets/css/bootstrap.min.css" rel="stylesheet" />

    <link href="../assets/css/material-dashboard.css" rel="stylesheet" />

    <link href="../assets/css/demo.css" rel="stylesheet" />

    <link href="../../../../maxcdn.bootstrapcdn.com/font-awesome/latest/css/font-awesome.min.css" rel="stylesheet">
    <link rel="stylesheet" type="text/css" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700|Material+Icons" />

                    Creative Tim

                    Ct

                            Tania Andrew

                                    My Profile

                                    Edit Profile

                                    Settings

                            dashboard

Dashboard

                            image

Pages

                                    Pricing

                                    Timeline

                                    Login Page

                                    Register Page

                                    Lock Screen Page

                                    User Profile

                            apps

Components

                                    Buttons

                                    Grid System

                                    Panels

                                    Sweet Alert

                                    Notifications

                                    Icons

                                    Typography

                            content_paste

Forms

                                    Regular Forms

                                    Extended Forms

                                    Validation Forms

                                    Wizard

                            grid_on

Tables

                                    Regular Tables

                                    Extended Tables

                                    DataTables.net

                            place

Maps

                                    Google Maps

                                    Full Screen Map

                                    Vector Map

                            widgets

Widgets

                            timeline

Charts

                            date_range

Calendar

                        <button id="minimizeSidebar" class="btn btn-round btn-white btn-fill btn-just-icon">
                            more_vert
                            view_list
                        </button>

                        <button type="button" class="navbar-toggle" data-toggle="collapse">
                            Toggle navigation

                        </button>
                         Extended Tables

                                    dashboard

Dashboard

                                    notifications
                                    5

                                        Notifications

                                        Mike John responded to your email

                                        You have 5 new tasks

                                        You're now friend with Andrew

                                        Another Notification

                                        Another One

                                    person

Profile

                        <form class="navbar-form navbar-right" role="search">

                                <input type="text" class="form-control" placeholder="Search">

                            <button type="submit" class="btn btn-white btn-round btn-just-icon">
                                search

                            </button>
                        </form>

                                    assignment

Simple Table

                                                    #
                                                    Name
                                                    Job Position
                                                    Since
                                                    Salary
                                                    Actions

                                                    1
                                                    Andrew Mike
                                                    Develop
                                                    2013
                                                    € 99,225

                                                        <button type="button" rel="tooltip" class="btn btn-info">
                                                            person
                                                        </button>
                                                        <button type="button" rel="tooltip" class="btn btn-success">
                                                            edit
                                                        </button>
                                                        <button type="button" rel="tooltip" class="btn btn-danger">
                                                            close
                                                        </button>

                                                    2
                                                    John Doe
                                                    Design
                                                    2012
                                                    € 89,241

                                                        <button type="button" rel="tooltip" class="btn btn-info btn-round">
                                                            person
                                                        </button>
                                                        <button type="button" rel="tooltip" class="btn btn-success btn-round">
                                                            edit
                                                        </button>
                                                        <button type="button" rel="tooltip" class="btn btn-danger btn-round">
                                                            close
                                                        </button>

                                                    3
                                                    Alex Mike
                                                    Design
                                                    2010
                                                    € 92,144

                                                        <button type="button" rel="tooltip" class="btn btn-info btn-simple">
                                                            person
                                                        </button>
                                                        <button type="button" rel="tooltip" class="btn btn-success btn-simple">
                                                            edit
                                                        </button>
                                                        <button type="button" rel="tooltip" class="btn btn-danger btn-simple">
                                                            close
                                                        </button>

                                                    4
                                                    Mike Monday
                                                    Marketing
                                                    2013
                                                    € 49,990

                                                        <button type="button" rel="tooltip" class="btn btn-info btn-round">
                                                            person
                                                        </button>
                                                        <button type="button" rel="tooltip" class="btn btn-success btn-round">
                                                            edit
                                                        </button>
                                                        <button type="button" rel="tooltip" class="btn btn-danger btn-round">
                                                            close
                                                        </button>

                                                    5
                                                    Paul Dickens
                                                    Communication
                                                    2015
                                                    € 69,201

                                                        <button type="button" rel="tooltip" class="btn btn-info">
                                                            person
                                                        </button>
                                                        <button type="button" rel="tooltip" class="btn btn-success">
                                                            edit
                                                        </button>
                                                        <button type="button" rel="tooltip" class="btn btn-danger">
                                                            close
                                                        </button>

                                    assignment

Striped Table

                                                    #

                                                    Product Name
                                                    Type
                                                    Qty
                                                    Price
                                                    Amount

                                                    1

                                                                <input type="checkbox" name="optionsCheckboxes" checked>

                                                    Moleskine Agenda
                                                    Office
                                                    25
                                                    € 49
                                                    € 1,225

                                                    2

                                                                <input type="checkbox" name="optionsCheckboxes" checked>

                                                    Stabilo Pen
                                                    Office
                                                    30
                                                    € 10
                                                    € 300

                                                    3

                                                                <input type="checkbox" name="optionsCheckboxes" checked>

                                                    A4 Paper Pack
                                                    Office
                                                    50
                                                    € 10.99
                                                    € 109

                                                    4

                                                                <input type="checkbox" name="optionsCheckboxes">

                                                    Apple iPad
                                                    Meeting
                                                    10
                                                    € 499.00
                                                    € 4,990

                                                    5

                                                                <input type="checkbox" name="optionsCheckboxes">

                                                    Apple iPhone
                                                    Communication
                                                    10
                                                    € 599.00
                                                    € 5,999

                                                        Total

                                                        €12,999

                                    assignment

Shopping Cart Table

                                                    Product
                                                    Color
                                                    Size
                                                    Price
                                                    Qty
                                                    Amount

                                                        Spring Jacket

                                                        by Dolce&Gabbana

                                                        Red

                                                        M

                                                        €549

                                                        1

                                                            <button class="btn btn-round btn-info btn-xs"> remove </button>
                                                            <button class="btn btn-round btn-info btn-xs"> add </button>

                                                        €549

                                                        <button type="button" rel="tooltip" data-placement="left" title="Remove item" class="btn btn-simple">
                                                            close
                                                        </button>

                                                        Short Pants

                                                        by Pucci

                                                        Purple

                                                        M

                                                        €499

                                                        2

                                                            <button class="btn btn-round btn-info btn-xs"> remove </button>
                                                            <button class="btn btn-round btn-info btn-xs"> add </button>

                                                        €998

                                                        <button type="button" rel="tooltip" data-placement="left" title="Remove item" class="btn btn-simple">
                                                            close
                                                        </button>

                                                        Pencil Skirt

                                                        by Valentino

                                                        White

                                                        XL

                                                        €799

                                                        1

                                                            <button class="btn btn-round btn-info btn-xs"> remove </button>
                                                            <button class="btn btn-round btn-info btn-xs"> add </button>

                                                        €799

                                                        <button type="button" rel="tooltip" data-placement="left" title="Remove item" class="btn btn-simple">
                                                            close
                                                        </button>

                                                        Total

                                                        €2,346

                                                        <button type="button" class="btn btn-info btn-round">Complete Purchase keyboard_arrow_right</button>

                                    Home

                                    Company

                                    Portfolio

                                    Blog

                        ©

                        Creative Tim, made with love for a better web

 Sidebar Filters

Sidebar Background

Sidebar Mini

                                <input type="checkbox" unchecked="">

Sidebar Image

                                <input type="checkbox" checked="">

Images

                        Buy Now

                        Get Free Demo

Thank you for 95 shares!

                    <button id="twitter" class="btn btn-social btn-twitter btn-round"> · 45</button>
                    <button id="facebook" class="btn btn-social btn-facebook btn-round"> ·50</button>


text:
.. _writing_modules:

.. index:: Modules, Modules, Custom module

Writing CasperJS modules
========================

As of 1.1, CasperJS relies on PhantomJS' native ``require()`` function internally though it had to be patched in order to allow requiring casper modules using their full name, eg. ``require('casper')``.

So if you plan to write your own modules and uses casperjs' ones from them, be sure to call the ``patchRequire()`` function::

    // my module, stored in universe.js
    // patching phantomjs' require()
    var require = patchRequire(require);

    // now you're ready to go
    var utils = require('utils');
    var magic = 42;
    exports.answer = function() {
        return utils.format("it's %d", magic);
    };

.. warning::

    When using CoffeeScript ``global.require`` must be passed to ``patchRequire()`` instead of just ``require``.

From your root casper script::

    var universe = require('./universe');
    console.log(universe.answer()); // prints "It's 42"

.. versionadded:: 1.1.

.. hint::

    Like PhantomJS, CasperJS allows using nodejs modules installed through npm_.

As an example, let's install the underscore_ library:
.. _npm: https://npmjs.org/

.. code-block:: text

    $ npm install underscore

Then, ``require`` it like you would with any other nodejs compliant module::

    //npm-underscore-test.js
    var _ = require('underscore');
    var casper = require('casper').create();
    var urls = _.uniq([
      'http://google.com/',
      'http://docs.casperjs.org/',
      'http://google.com/'
    ]);

    casper.start().eachThen(urls, function(response) {
      this.thenOpen(response.data, function(response) {
        this.echo(this.getTitle());
      });
    });

    casper.run();

Finaly, you'll probably get something like this:

.. code-block:: text

    $ casperjs npm-underscore-test.js
    Google
    CasperJS documentation | CasperJS 1.1.0-DEV documentation


text:
package org.monarchinitiative.phenotefx.model;

import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;

public class HPO {

    /* HPO id string */
    private StringProperty hpoId = new SimpleStringProperty(this, "hpoId", "");
    public String getHpoId() {return hpoId.get();}
    public void setHpoId(String newHpoId) {hpoId.set(newHpoId);}
    public StringProperty hpoIdProperty() {return hpoId;}

    /* HPO term name */
    private StringProperty hpoName = new SimpleStringProperty(this, "hpoName", "");
    public String getHpoName() {return hpoName.get();}
    public void setHpoName(String newHpoName) {hpoName.set(newHpoName);}
    public StringProperty hpoNameProperty() {return hpoName;}

}


text:
ACCEPTED

#### According to
Index Fungorum

#### Published in
Nova Acta R. Soc. Scient. upsal. , Ser. 3 1: 116 (1851)

#### Original name
Clavaria polita Fr.

### Remarks
null


text:
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')

describe ::YARD::Amp::ParsingHelpers, '#clean_string' do
  include YARD::Amp::ParsingHelpers
  it "cleans normal symbols" do
    clean_string(":some_symbol").should == "some_symbol"
  end

  it "cleans quoted symbols" do
    clean_string(":\"long symbol\"").should == "long symbol"
  end

  it "cleans normal strings" do
    clean_string("\"a big long string\"").should == "a big long string"
  end

  it "cleans special-quoted strings" do
    clean_string("%Q{some big long string}").should == "some big long string"
  end

  it "cleans heredocs" do
    clean_string("<<-EOF\nsome string\n another lines\n  another line\nEOF").should == "\nsome string\n another lines\n  another line"
  end
end

describe ::YARD::Amp::ParsingHelpers, '#split_by_comma_smart' do
  include YARD::Amp::ParsingHelpers
  it "splits simple strings" do
    split_by_comma_smart(":hello, :world, :im_mike").should == [":hello", " :world", " :im_mike"]
  end

  it "splits slightly tougher strings" do
    split_by_comma_smart(":hello, \"a big long, string\", :is_nice").should == [":hello", " \"a big long, string\"", " :is_nice"]
  end
end

if RUBY19
  describe ::YARD::Amp::ParsingHelpers, '#parse_hash' do
    include YARD::Amp::ParsingHelpers
    it "parses hashes into hash objects" do
      ast = YARD::Parser::SourceParser.parse_string("{\"hello\" => \"world\"}").ast.first
      parse_hash(ast).should == {"hello" => "world"}
    end

    it "parses hashes with symbols into string-based hashes" do
      ast = YARD::Parser::SourceParser.parse_string("{:\"no-color\" => true}").ast.first
      parse_hash(ast).should == {"no-color" => "true"}
    end
  end
end


text:
/*
 * Original file at https://gist.github.com/JakeWharton/11274467
 *
 * Licensed under Apache License, Version 2.0
 */
package com.volkhart.androidutil.text;

import android.text.SpannableStringBuilder;

import java.util.ArrayDeque;
import java.util.Deque;

import static android.text.Spanned.SPAN_INCLUSIVE_EXCLUSIVE;

/**
 * A {@link SpannableStringBuilder} wrapper whose API doesn't make me want to stab my eyes out.
 *

 * Example usage:
 *
 {@code Truss t = new Truss()}
 *
 {@code .append("Thanks Jake, ")}
 *
 {@code .pushSpan(new StyleSpan(android.graphics.Typeface.BOLD))}
 *
 {@code .append("Truss saves time")}
 *
 {@code .popSpan()}
 *
 {@code .append(" and you are great.");}
 *
 {@code TextView name = (TextView)findViewById(R.id.tvname);}
 *
 {@code name.setText(t.build());}
 *

 *
results in:
 Thanks Jake, Truss saves time and you are great.
 */
public class Truss {
    private final SpannableStringBuilder builder;
    private final Deque stack;

    public Truss() {
        builder = new SpannableStringBuilder();
        stack = new ArrayDeque<>();
    }

    public Truss append(String string) {
        builder.append(string);
        return this;
    }

    public Truss append(CharSequence charSequence) {
        builder.append(charSequence);
        return this;
    }

    public Truss append(char c) {
        builder.append(c);
        return this;
    }

    public Truss append(int number) {
        builder.append(String.valueOf(number));
        return this;
    }

    /**
     * Starts {@code span} at the current position in the builder.
     */
    public Truss pushSpan(Object span) {
        stack.addLast(new Span(builder.length(), span));
        return this;
    }

    /**
     * End the most recently pushed span at the current position in the builder.
     */
    public Truss popSpan() {
        Span span = stack.removeLast();
        builder.setSpan(span.span, span.start, builder.length(), SPAN_INCLUSIVE_EXCLUSIVE);
        return this;
    }

    /**
     * Create the final {@link CharSequence}, popping any remaining spans.
     */
    public CharSequence build() {
        while (!stack.isEmpty()) {
            popSpan();
        }
        return builder; // TODO make immutable copy?
    }

    private static final class Span {
        final int start;
        final Object span;

        public Span(int start, Object span) {
            this.start = start;
            this.span = span;
        }
    }
}


text:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using App.Context;
using App.Entity;
using Microsoft.EntityFrameworkCore.Migrations;
using App.Utils;

namespace App.Migrations.Seed
{
    /// <summary>
    /// Class UserContextSeed
    ///
    /// Author: Claudiu Nicola
    /// </summary>
    public static class UserContextSeed
    {
        /// <summary>
        /// This method is used at startup of App
        /// for populate db with dummy data.
        /// Usage: UserContextSeed.Seed()
        ///
        /// </summary>
        public static void Seed()
        {
            using (var db = new AppContext())
            {
                var encrypter = new EncryptDecrypt();

                var chair = new Role("Chair", "chair");
                var author = new Role("Author", "author");
                var speaker = new Role("Speaker", "speaker");
                var listner = new Role("Listner", "listner");
                var reviewer = new Role("Reviewer", "reviewer");
                if (!db.Roles.Any())
                {
                    db.Roles.Add(chair);
                    db.Roles.Add(author);
                    db.Roles.Add(speaker);
                    db.Roles.Add(listner);
                    db.Roles.Add(reviewer);
                }

                var user1 = new User("Andu", "Popa", "popa@gmail.com", encrypter.encryptPassword("parola"), "ro");
                var userRole = new UserRole() {Role = chair, RoleId = chair.RoleId, User = user1, UserId = user1.UserId};
                user1.UserRoles = new List<UserRole>() {userRole};

                var user2 = new User("Haba", "Baba", "haba@gmail.com", encrypter.encryptPassword("parola"), "ro");
                var userRole2 = new UserRole() { Role = reviewer, RoleId = reviewer.RoleId, User = user2, UserId = user2.UserId };
                user2.UserRoles = new List<UserRole>() { userRole2 };

                var user3 = new User("Yolo", "Swag", "swag@gmail.com", encrypter.encryptPassword("parola"), "ro");
                var userRole3 = new UserRole() { Role = reviewer, RoleId = reviewer.RoleId, User = user3, UserId = user3.UserId };
                user3.UserRoles = new List<UserRole>() { userRole3 };

                if (!db.Users.Any())
                {
                    db.Users.Add(user1);
                    db.Users.Add(user2);
                    db.Users.Add(user3);
                }

                db.SaveChanges();
            }
        }
    }
}


text:
package com.rho.sync;
import org.json.me.RhoJSONException;
import org.json.me.RhoJSONObject;

class JSONEntry
{
    RhoJSONObject m_object;

	JSONEntry(RhoJSONObject obj)
	{
	    m_object = obj;
	}

	JSONEntry(String szData)throws RhoJSONException
	{
	    m_object = new RhoJSONObject(szData);
	}

	boolean isEmpty()
	{
	    return m_object == null;
	}

	boolean hasName(String name)
	{
		return m_object.has(name);
	}

	static String quoteValue(String str)
	{
		return RhoJSONObject.quote(str);
	}

	String getString(String name)throws RhoJSONException
	{
	    String szRes = null;
	    if ( m_object.has(name))
	    	szRes = m_object.getString(name);

	    return szRes;
	}

	String getString()
	{
		return m_object.toString();
	}

	int getInt(String name)throws RhoJSONException
	{
	    int nRes = 0;
	    if ( m_object.has(name))
	    	nRes = m_object.getInt(name);

	    return nRes;
	}

	long getLong(String name)throws RhoJSONException
	{
	    long nRes = 0;
	    if ( m_object.has(name))
	    	nRes = m_object.getLong(name);

	    return nRes;
	}

	long getUInt64(String name)throws RhoJSONException
	{
	    return getLong(name);
	}

	JSONEntry getEntry(String name)throws RhoJSONException
	{
	    return new JSONEntry((RhoJSONObject) m_object.get(name));
	}
}


text:
import vcr
import unittest
from mtgsdk import Type

class TestType(unittest.TestCase):
    def test_all_returns_types(self):
        with vcr.use_cassette('fixtures/types.yaml'):
            types = Type.all()

            #API returns some erroneous values, but this line is correct
            #Remove temporary line and uncomment this line when API is updated
            # self.assertEqual(["Artifact","Card","Conspiracy","Creature","Emblem","Enchantment","Host","Instant","Land","Phenomenon","Plane","Planeswalker","Scheme","Sorcery","Summon","Tribal","Vanguard","You'll"], types)
            self.assertEqual(["Artifact","Conspiracy","Creature","Enchantment","Hero","instant","Instant","Land","Phenomenon","Plane","Planeswalker","Scheme","Sorcery","Summon","Tribal","Vanguard","You'll"], types)


text:
@interface SimpleAssembly : TyphoonAssembly

@property TyphoonAssembly *assemblyA;

@end


text:
class CreateApplications < ActiveRecord::Migration
  def change
    create_table :applications do |t|
      t.integer :user_id
      t.integer :course_id
      t.integer :priority

      t.timestamps
    end
  end
end