text:
$(document).ready(function() {
    // Load core chart package
    google.charts.load('current', {'packages':['corechart']});
    // Set the callback
    google.charts.setOnLoadCallback(get_readout);

    window.GROUPING.refresh_function = get_readout;

    let matrix_item_id = get_matrix_item();
    let study_id = get_study_id();

    // If chips
    if ($('#id_series_data')[0] && $('#id_series_data').val().indexOf('"plates":{}') !== -1) {
        // Make the difference table
        // window.GROUPS.make_difference_table('chip');
        window.GROUPS.make_difference_table(
            {
                filter_key: 'matrix_item',
                filter_value: matrix_item_id,
                // Filter to chips
                restrict_to: 'chip',
            }
        );
    }
    // If plates AND THERE IS A FORM
    else if ($('#id_series_data')[0]) {
        // MAKE SURE TO RESTRICT TO THE CORRECT ORGAN MODEL
        // HUGELY IMPORTANT
        // Is pre-populated for form!
        let current_group_name = $('#id_group').find('option:selected').text();
        let current_organ_model_id = null;
        // Now we need to find the correct group
        // BARBARISM
        $.each(JSON.parse($('#id_series_data').val()).series_data, function(index, group) {
            if (group.name === current_group_name) {
                current_organ_model_id = group.organ_model_id;
            }
        });

        // Make the difference table
        // window.GROUPS.make_difference_table('plate', current_organ_model_id);
        window.GROUPS.make_difference_table(
            {
                filter_key: 'matrix_item',
                filter_value: matrix_item_id,
                // Filter to just plate
                restrict_to: 'plate',
                // Make sure to also pass the organ_model
                current_organ_model_id: current_organ_model_id
            }
        );
    }

    // var device = $('#id_device');
    // var organ_model = $('#id_organ_model');
    // var protocol = $('#id_organ_model_protocol');

    // window.device = device;
    // window.organ_model = organ_model;
    // window.organ_model_protocol = protocol;

    // var protocol_display = $('#protocol_display');
    //
    // var organ_model_div = $('#organ_model_div');
    // var protocol_div = $('#protocol_div');
    // var variance_div = $('#variance_div');

    // TODO BEGIN
    // Tracks the excluded of data to indicate whether to exclude or include in plots
    var dynamic_excluded_current = {};
    var dynamic_excluded_new = {};

    var first_run = true;

    window.CHARTS.call = 'fetch_data_points';
    window.CHARTS.matrix_item_id = matrix_item_id;

    // Name for the charts for binding events etc
    var charts_name = 'charts';

    var changes_to_chart_options = {
        chartArea: {
            // Slight change in width
            width: '78%',
            height: '65%'
        }
    };

    var current_data_table = null;

    function is_true(element, index, array) {
        if (!element && element !== 0) {
            return false;
        }
        else {
            return true;
        }
    }

    function data_format(value, ratio, id) {
        var format = d3.format(',.3f');
        if (value > 10000 || value < 0.01) {
            format = d3.format('.3e');
        }
        else if (value % 1 === 0) {
            format = d3.format(',d');
        }
        return format(value);
    }

    function get_study_id() {
        var study_id = Math.floor(window.location.href.split('/')[4]);
        if (study_id) {
            return study_id
        }
        else {
            return ''
        }
    }

    function get_matrix_item() {
        var current_id = Math.floor(window.location.href.split('/')[5]);

        if (!current_id) {
            current_id = '';
        }

        return current_id;
    }

    // PROCESS GET PARAMS INITIALLY
    window.GROUPING.process_get_params();
    // window.GROUPING.generate_get_params();

    function get_readout() {
        if (matrix_item_id) {
            // Get the table
            $.ajax({
                url: "/assays_ajax/",
                type: "POST",
                dataType: "json",
                data: {
                    // TODO TODO TODO CALL FOR DATA
                    call: 'fetch_item_data',
                    matrix_item: matrix_item_id,
                    csrfmiddlewaretoken: window.COOKIES.csrfmiddlewaretoken
                },
                success: function (json) {
                    var exist = true;
                    process_data(json, exist);
                },
                error: function (xhr, errmsg, err) {
                    console.log(xhr.status + ": " + xhr.responseText);
                }
            });
            // Get the plots
            plot_existing_data();
        }
    }

    function clear_new_data() {
        $('.new-value').each(function() {
            // Delete this value from data
            // delete data[$(this).attr('data-chart-index')];
            // Remove the row itself
            $(this).remove();
        });
    }

    // REMOVED FOR NOW, CONSIDER ADDING BACK EVENTUALLY
    // function validate_readout_file(include_table) {
    //     // Purge dynamic_excluded_new if table if being reset
    //     if (include_table) {
    //         dynamic_excluded_new = {};
    //     }
    //
    //     var dynamic_excluded = $.extend(true, {}, dynamic_excluded_current, dynamic_excluded_new);
    //
    //     var data = {
    //         call: 'validate_individual_chip_file',
    //         study: study_id,
    //         readout: matrix_item_id,
    //         csrfmiddlewaretoken: window.COOKIES.csrfmiddlewaretoken,
    //         dynamic_excluded: JSON.stringify(dynamic_excluded),
    //         include_table: include_table
    //     };
    //
    //     window.CHARTS.global_options = window.CHARTS.prepare_chart_options();
    //
    //     data = $.extend(data, options);
    //
    //     var serialized_data = $('form').serializeArray();
    //     var form_data = new FormData();
    //     $.each(serialized_data, function(index, field) {
    //         form_data.append(field.name, field.value);
    //     });
    //     form_data.append('file', $('#id_file')[0].files[0]);
    //
    //     $.each(data, function(index, contents) {
    //         form_data.append(index, contents);
    //     });
    //
    //     $.ajax({
    //         url: "/assays_ajax/",
    //         type: "POST",
    //         dataType: "json",
    //         cache: false,
    //         contentType: false,
    //         processData: false,
    //         data: form_data,
    //         success: function (json) {
    //             // console.log(json);
    //             if (json.errors) {
    //                 // Display errors
    //                 alert(json.errors);
    //                 // Remove file selection
    //                 $('#id_file').val('');
    //                 // $('#table_body').empty();
    //                 clear_new_data();
    //                 // plot();
    //                 plot_existing_data();
    //             }
    //             else {
    //                 var exist = false;
    //                 alert('Success! Please see "New Chip Data" below for preview.' +
    //                     '\n\nPlease note that changes will not be made until you press the "Submit" button at the bottom of the page.');
    //
    //                 if (json.number_of_conflicting_entries) {
    //                     alert(
    //                         '***Submitting this file will replace ' + json.number_of_conflicting_entries + ' point(s).***' +
    //                         '\n\nPlease note that changes will not be made until you press the "Submit" button at the bottom of the page.');
    //                 }
    //
    //                 if (include_table) {
    //                    process_data(json.table, exist);
    //                 }
    //
    //                 window.CHARTS.prepare_side_by_side_charts(json.charts, charts_name);
    //                 window.CHARTS.make_charts(json.charts, charts_name, changes_to_chart_options);
    //
    //                 // Recalculate responsive and fixed headers
    //                 $($.fn.dataTable.tables(true)).DataTable().responsive.recalc();
    //                 $($.fn.dataTable.tables(true)).DataTable().fixedHeader.adjust();
    //             }
    //         },
    //         error: function (xhr, errmsg, err) {
    //             alert('An unknown error has occurred. \nIf you have the file open, you may need to close it.');
    //             console.log(xhr.status + ": " + xhr.responseText);
    //             // Remove file selection
    //             $('#id_file').val('');
    //             // $('#table_body').empty();
    //             clear_new_data();
    //             // plot();
    //             plot_existing_data();
    //         }
    //     });
    // }

    var process_data = function (json, exist) {
        var table_body = $('#table_body');

        // Do not empty entire table, only delete new values
        // table_body.empty();
        clear_new_data();

        if (!json) {
            return;
        }

        // Current index for saving QC values
        var current_index = 0;

        // var table = '';

        // PLEASE NOTE THAT THE DATA POINTS ARE REVERSED
        var data_points = json.data_points.reverse();
        var study_assays = json.study_assays;
        var sample_locations = json.sample_locations;

        // TODO USE THE ACTUAL DATAPOINT PK FOR EXCLUSION
        $.each(data_points, function(index, data_point) {
            var name = data_point.name;

            var assay_plate_id = data_point.assay_plate_id;
            var assay_well_id = data_point.assay_well_id;

            var day = Math.floor(data_point.day);
            var hour = Math.floor(data_point.hour);
            var minute = Math.floor(data_point.minute);

            // Just convert to day for now
            var time_in_minutes = data_point.time_in_minutes;
            var time_in_days = time_in_minutes / 1440.0;

            var study_assay_id = data_point.study_assay_id;
            var target_name = study_assays[study_assay_id].target_name;
            var method_name = study_assays[study_assay_id].method_name;

            var sample_location_id = data_point.sample_location_id;
            var sample_location_name = sample_locations[sample_location_id].name;

            var value = data_point.value;
            var value_unit = study_assays[study_assay_id].unit;

            var caution_flag = data_point.caution_flag;
            var excluded = data_point.excluded;
            // var replaced = data_point.replaced;

            var notes = data_point.notes;
            var replicate = data_point.replicate;
            var update_number = data_point.update_number;

            var data_file_upload_url = data_point.data_file_upload_url;
            var data_file_upload_name = data_point.data_file_upload_name;

            var new_row = $('<tr>');
            //     .attr('data-chart-index', index);

            // Need to take a slice to avoid treating missing QC as invalid
            // Allow QC changes for NULL value row
            var every = [name, time_in_minutes, study_assay_id, sample_location_id].every(is_true);

            if (exist) {
                new_row.addClass('force-bg-success');
            }

            else {
                new_row.addClass('new-value');
            }

            if (!exist && !every) {
                new_row.addClass('force-bg-danger');
            }

            else if (value === null || value === '') {
                new_row.css('background', '#606060');
            }

            else if (excluded) {
                new_row.addClass('force-bg-danger');
            }

            else if (caution_flag) {
                new_row.addClass('force-bg-warning');
            }

            var col_name = $('<td>').text(name);

            var col_time = $('<td>').text('D' + day + ' H' + hour + ' M' + minute)
                .append($('<input>')
                    .addClass('time_in_minutes')
                    .val(time_in_minutes)
                    .hide()
                );

            var col_target = $('<td>').text(target_name);
            var col_method = $('<td>').text(method_name);
            var col_sample_location = $('<td>').text(sample_location_name);
            var col_value = $('<td>').text(value ? data_format(value) : value);
            var col_value_unit = $('<td>').text(value_unit);

            var col_caution_flag = $('<td>').text(caution_flag);

            var col_excluded = $('<td>');

            var excluded_input = $('<input>')
                .attr('type', 'checkbox')
                // .attr('id', i)
                .css('width', 50)
                .attr('data-matrix-item-pk', data_point.id)
                // .attr('name', 'assaydatapoint-' + data_point.id + '-exclude')
                // .attr('id', 'id_assaydatapoint-' + data_point.id + '-exclude')
                .addClass('excluded excluded-input');

            if (excluded) {
                excluded_input.prop('checked', true);
            }

            if (exist || every) {
                col_excluded.append(
                    excluded_input
                );
            }

            var col_notes = $('<td>').text(notes);

            var col_data_file_upload = $('<td>').append(
                $('<a>')
                    .text(data_file_upload_name)
                    .attr('href', data_file_upload_url)
            );

            new_row.append(
                col_name,
                col_time,
                col_target,
                col_method,
                col_sample_location,
                col_value,
                col_value_unit,
                col_caution_flag
            );

            // Technically a magic value SUBJECT TO CHANGE
            // Finds if there is a column to put exclude into
            if ($('#id_exclude_header')[0]) {
                new_row.append(col_excluded)
            }

            new_row.append(
                col_notes,
                col_data_file_upload
            );

            if (excluded) {
                new_row.addClass('initially-excluded')
            }

            table_body.prepend(new_row);
        });

        // Refresh exclusions
        toggle_excluded();

        var all_excluded = null;

        if (exist) {
            all_excluded = $('.excluded');
        }
        else {
            all_excluded = $('.new-value').find('.excluded');
        }

        // Bind change event to excluded
        all_excluded.change(function() {
            var current_value = $(this).prop('checked');
            var current_row = $(this).parent().parent();
            var current_pk = Math.floor($(this).attr('data-matrix-item-pk'));

            // Change color of parent if there is input
            if (current_value) {
                current_row.addClass('force-bg-danger');
                current_row.removeClass('unexcluded');
            }
            else if (!current_value && current_row.hasClass('initially-excluded')) {
                current_row.addClass('force-bg-info');
                current_row.addClass('unexcluded');
                current_row.removeClass('force-bg-success force-bg-danger');
            }
            else {
                current_row.removeClass('force-bg-danger');
            }

            if (exist) {
                // TODO
                dynamic_excluded_current[current_pk] = current_value;
            }
            else {
                // TODO
                dynamic_excluded_new[current_pk] = current_value;
            }

            // Validate again if there is a file
            // Only affects charts
            // refresh_chart_only();

            plot_existing_data();
            toggle_excluded();
        });

        var current_data_table_selector = $('#current_data_table');
        // Clear old (if present)
        current_data_table_selector.DataTable().destroy();

        // KILL ALL LINGERING HEADERS
        $('.fixedHeader-locked').remove();

        // Make the datatable
        current_data_table = current_data_table_selector.DataTable({
            dom: 'B<"row">frti',
            fixedHeader: {headerOffset: 50},
            iDisplayLength: -1,
            columnDefs: [
                {
                    "sType": "numeric",
                    "sSortDataType": "time-in-minutes",
                    "targets": [1]
                },
                {
                    sortable: false,
                    "targets": [8]
                }
            ]
        });

        // Add listener to search
        $('input[type=search]').change(function() {
            toggle_excluded();
        });

        // TODO DEFINITELY NOT DRY
        // Swap positions of filter and length selection; clarify filter
        $('.dataTables_filter').css('float', 'left').prop('title', 'Separate terms with a space to search multiple fields');
        $('.dataTables_length').css('float', 'right');
        // Reposition download/print/copy
        $('.DTTT_container').css('float', 'none');

        // Clarify usage of sort
        $('.sorting').prop('title', 'Click a column to change its sorting\n Hold shift and click columns to sort multiple');
        $('.sorting_asc').prop('title', 'Click a column to change its sorting\n Hold shift and click columns to sort multiple');
        $('.sorting_desc').prop('title', 'Click a column to change its sorting\n Hold shift and click columns to sort multiple');
    };

    function plot_existing_data() {
        var dynamic_excluded = $.extend(true, {}, dynamic_excluded_current, dynamic_excluded_new);

        var data = {
            call: 'fetch_data_points',
            study: study_id,
            matrix_item: matrix_item_id,
            csrfmiddlewaretoken: window.COOKIES.csrfmiddlewaretoken,
            criteria: JSON.stringify(window.GROUPING.group_criteria),
            post_filter: JSON.stringify(window.GROUPING.current_post_filter),
            full_post_filter: JSON.stringify(window.GROUPING.full_post_filter),
            dynamic_excluded: JSON.stringify(dynamic_excluded)
        };

        window.CHARTS.global_options = window.CHARTS.prepare_chart_options();
        var options = window.CHARTS.global_options.ajax_data;

        data = $.extend(data, options);

        // Show spinner
        window.spinner.spin(
            document.getElementById("spinner")
        );

        $.ajax({
            url: "/assays_ajax/",
            type: "POST",
            dataType: "json",
            data: data,
            success: function (json) {
                // Stop spinner
                window.spinner.stop();

                window.CHARTS.prepare_side_by_side_charts(json, charts_name);
                // TODO TODO TODO FIX FIX FIX
                // window.CHARTS.make_charts(json, charts_name, changes_to_chart_options);
                window.CHARTS.make_charts(json, charts_name, first_run);
                // Recalculate responsive and fixed headers
                $($.fn.dataTable.tables(true)).DataTable().responsive.recalc();
                $($.fn.dataTable.tables(true)).DataTable().fixedHeader.adjust();

                first_run = false;
            },
            error: function (xhr, errmsg, err) {
                first_run = false;

                // Stop spinner
                window.spinner.stop();

                console.log(xhr.status + ": " + xhr.responseText);
            }
        });
    }

    // var refresh_table_and_charts = function() {
    //     // Useless
    //     // if ($('#id_file')[0] && $('#id_file')[0].files[0]) {
    //     //     // resetChart();
    //     //     validate_readout_file('True');
    //     //     // getText(file);
    //     // }
    //     // else {
    //     //     plot_existing_data();
    //     // }
    //
    //     plot_existing_data();
    //     toggle_excluded();
    // };

    // Useless, odd
    // var refresh_chart_only = function() {
    //     // if ($('#id_file')[0] && $('#id_file')[0].files[0]) {
    //     //     // resetChart();
    //     //     validate_readout_file('');
    //     //     // getText(file);
    //     // }
    //     // else {
    //     //     plot_existing_data();
    //     // }
    //
    //     plot_existing_data();
    //     toggle_excluded();
    // };

    function toggle_excluded() {
        // Stop gap: magic string
        var include_all = $('#include_all').prop('checked');

        if (include_all) {
            $('.initially-excluded').show();
        }
        else {
            $('.initially-excluded').hide();
        }

        // Show initially-excluded items that have had their exclusion removed
        $('.unexcluded').show();
    }

    // Refresh on file change
    // $('#id_file').change(function(evt) {
    //     refresh_table_and_charts();
    // });
    //
    // // Refresh on change in overwrite option NEED REPLCATE TO BE ACCURATE
    // $('#id_overwrite_option').change(function() {
    //     refresh_table_and_charts();
    // });

    // JUNK: REMOVED!
    // Handling Device flow
    // Make sure global var exists before continuing
    // if (window.get_organ_models) {
    //     device.change(function() {
    //         // Get organ models
    //         window.get_organ_models(device.val());
    //     });

    //     window.get_organ_models(device.val());

    //     organ_model.change(function() {
    //         // Get and display correct protocol options
    //         window.get_protocols(organ_model.val());
    //     });

    //     window.get_protocols(organ_model.val());

    //     protocol.change(function() {
    //         window.display_protocol(protocol.val());
    //     });

    //     window.display_protocol(protocol.val());
    // }

    // Post submission operation
    // Special operations for pre-submission
    $('form').submit(function() {
        if (current_data_table) {
            current_data_table.search('');
            $('input[type=search]').val('');
            current_data_table.draw();
            $('.initially-excluded').show();
        }
        // Add the exclusions
        $('#id_dynamic_exclusion').val(JSON.stringify(dynamic_excluded_current));
    });

    // These operations are for the group stuff
    // Basically, I want some way to indicate the current group more easily
    // I COULD remove every other group, but that would mean they would have to go through each group individually
    // I COULD make the selected group appear at the top, but then the order would change and maybe people would be confused
    // I COULD have a special table that display a copy of just the selection
    // I COULD highlight the selected row in the table (doing this alone would make people mad, they would not want to scroll)
    // Anyway:
    // Wherein the term "highlight" is used in a looser sense

    // Also, uh... stop using var eventually
    // Proposed, not implemented yet
    // var current_group_table_body = $('#current_group_table_body');
    var difference_table_rows = $('#difference_table').find('tr');

    function highlight_selected_group() {
        // Get the current group name
        var current_group_name = $('#id_group').find('option:selected').text();

        // Remove highlight
        difference_table_rows.removeClass('success');

        // Iterate over every row
        difference_table_rows.each(function() {
            if ($(this).find('td').first().text() === current_group_name) {
                $(this).addClass('success');

                // Break
                return false;
            }
        });
    }

    $("#id_group").change(function() {
        highlight_selected_group();
    }).trigger('change');
});


text:
<?php

namespace Entity;

use ConnCrud\Read;
use ConnCrud\TableCrud;
use Helpers\Check;

abstract class EntityCopy extends EntityDelete
{
    /**
     * Deleta informações de uma entidade
     *
     * @param string $entity
     * @param mixed $data
     * @param bool $checkPermission
     * @return mixed
     */
    protected static function exeCopy(string $entity, $data, $checkPermission)
    {
        $result = null;
        $dicionario = Metadados::getDicionario($entity);

        if (is_int($data)) {
            $copy = new TableCrud($entity);
            $copy->load($data);
            if ($copy->exist())
                if (Entity::checkPermission($entity, $data, $checkPermission)) {
                    $result = self::copyEntity($entity, $copy->getDados(), $dicionario);
                } else {
                    self::$error[$entity]['id'] = "permissão negada";
                }
            else
                self::$error[$entity]['id'] = "id: {$data} não encontrado para cópia";

        } elseif (is_array($data)) {
            if (Check::isAssoc($data)) {
                $copy = new TableCrud($entity);
                $copy->loadArray($data);
                if ($copy->exist())
                    if (Entity::checkPermission($entity, $data['id'], $checkPermission)) {
                        $result = self::copyEntity($entity, $copy->getDados(), $dicionario);
                    } else {
                        self::$error[$entity]['id'] = "permissão negada";
                    }
                else
                    self::$error[$entity]['id'] = "datas não encontrado em " . $entity . " para cópia";

            } else {
                foreach ($data as $datum) {
                    if (!self::$error)
                        $result[] = self::exeCopy($entity, (int)$datum);
                }
            }
        }
        unset($result['id']);

        return self::$error ? null : $result;
    }

    /**
     * @param string $entity
     * @param array $dicionario
     * @param array $data
     * @return array
     */
    private static function copyEntity(string $entity, array $data, array $dicionario): array
    {
        foreach ($dicionario as $dic) {
            if ($dic['key'] === "extend" && !self::$error)
                $data[$dic['column']] = self::exeCopy($dic['relation'], (int)$data[$dic['column']]);

            elseif ($dic['key'] === "list" || $dic['key'] === "selecao")
                $data[$dic['column']] = self::copyList($dic['relation'], (int)$data[$dic['column']]);

            elseif ($dic['key'] === "extend_mult")
                $data[$dic['column']] = self::copyEntityMult($entity, $dic, $data['id']);

            elseif ($dic['key'] === "list_mult" || $dic['key'] === "selecao_mult")
                $data[$dic['column']] = self::copyListMult($entity, $dic, $data['id']);

            else
                $data[$dic['column']] = self::copyEntityData($entity, $dic, $data, $dicionario);
        }

        return $data;
    }

    /**
     * @param string $entity
     * @param array $dic
     * @param int $id
     * @return mixed
     */
    private static function copyListMult(string $entity, array $dic, int $id)
    {
        $datas = null;
        $read = new Read();
        $read->exeRead(PRE . $entity . "_" . $dic['relation'] . "_" . $dic['column'], "WHERE " . $entity . "_id = :id", "id={$id}");
        if ($read->getResult()) {
            foreach ($read->getResult() as $item) {
                $datas[] = self::copyList($dic['relation'], (int)$item[$dic['relation'] . "_id"]);
            }
        }

        return $datas;
    }

    /**
     * @param string $entity
     * @param int $id
     * @return mixed
     */
    private static function copyList(string $entity, int $id)
    {
        $copy = new TableCrud($entity);
        $copy->load($id);
        if ($copy->exist())
            return $copy->getDados()['id'];

        return null;
    }

    /**
     * @param string $entity
     * @param array $dic
     * @param array $data
     * @param array $dicionario
     * @return mixed
     */
    private static function copyEntityData(string $entity, array $dic, array $data, array $dicionario)
    {
        if ($dic['unique']) {
            $data[$dic['column']] = rand(0, 999999) . "-" . $data[$dic['column']];
            $read = new TableCrud(PRE . $entity);
            $read->loadArray([$dic['column'] => $data[$dic['column']]]);
            if ($read->exist())
                $data[$dic['column']] = rand(0, 999999) . "--" . $data[$dic['column']];
        }

        if ($dic['key'] === "link")
            $data[$dic['column']] = Check::name($data[$dicionario[Metadados::getInfo($entity)['title']]['column']]);

        return $data[$dic['column']];
    }

    /**
     * @param string $entity
     * @param array $dic
     * @param int $id
     * @return mixed
     */
    private static function copyEntityMult(string $entity, array $dic, int $id)
    {
        $datas = null;
        $read = new Read();
        $read->exeRead(PRE . $entity . "_" . $dic['relation'] . "_" . $dic['column'], "WHERE " . $entity . "_id = :id", "id={$id}");
        if ($read->getResult()) {
            foreach ($read->getResult() as $item) {
                if (!self::$error)
                    $datas[] = self::exeCopy($dic['relation'], (int)$item[$dic['relation'] . "_id"]);
            }
        }

        return $datas;
    }
}

redpajama_set_name: RedPajamaGithub


text:
@interface CellEntityMapper : NSObject <DVATableViewModelProtocol>
@property (nonatomic, retain) NSString * title;
@property (nonatomic, retain) NSString * subTitle;
@property (nonatomic, retain) NSNumber * section;
+(CellEntityMapper*)cellEntityMapperWithCellEntity:(CellEntity*)entity;
@end


text:
(function() {
  var express;

  express = require('express');

  module.exports = function(compound) {
    var app;
    app = compound.app;
    return app.configure('development', function() {
      app.enable('log actions');
      app.enable('env info');
      app.enable('watch');
      app.enable('force assets compilation');
      app.use(express.errorHandler({
        dumpExceptions: true,
        showStack: true
      }));
      return app.enable('quiet');
    });
  };

}).call(this);


text:
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//

#pragma once

#include <spdlog/sinks/base_sink.h>
#include <spdlog/details/null_mutex.h>
#include <spdlog/details/fastfile_helper.h>
#include <spdlog/fmt/fmt.h>

#include <algorithm>
#include <chrono>
#include <cstdio>
#include <ctime>
#include <mutex>
#include <string>
#include <cerrno>

namespace spdlog
{
namespace sinks
{
/*
 * Trivial file sink with single file as target
 */
template<class Mutex>
class simple_fastfile_sink : public base_sink < Mutex >
{
public:
    explicit simple_fastfile_sink(const filename_t &filename, bool truncate = false):_force_flush(false)
    {
        _fastfile_helper.open(filename, 256 * 1024 * 1024, truncate);
    }
    void flush() override
    {
        _fastfile_helper.flush();
    }
    void set_force_flush(bool force_flush)
    {
        _force_flush = force_flush;
    }

protected:
    void _sink_it(const details::log_msg& msg) override
    {
        _fastfile_helper.write(msg);
        if(_force_flush)
            _fastfile_helper.flush();
    }
private:
    details::fastfile_helper _fastfile_helper;
    bool _force_flush;
};

typedef simple_fastfile_sink<std::mutex> simple_fastfile_sink_mt;
typedef simple_fastfile_sink<details::null_mutex> simple_fastfile_sink_st;

/*
 * Rotating file sink based on size
 */
template<class Mutex>
class rotating_fastfile_sink : public base_sink < Mutex >
{
public:
    rotating_fastfile_sink(const filename_t &base_filename,
                       std::size_t max_size, std::size_t max_files) :
        _base_filename(base_filename),
        _max_size(max_size),
        _max_files(max_files),
        _current_size(0),
        _fastfile_helper()
    {
        _fastfile_helper.open(calc_filename(_base_filename, 0), max_size);
        _current_size = _fastfile_helper.size(); //expensive. called only once
    }

    void flush() override
    {
        _fastfile_helper.flush();
    }

protected:
    void _sink_it(const details::log_msg& msg) override
    {
        _current_size += msg.formatted.size();
        if (_current_size > _max_size)
        {
            _rotate();
            _current_size = msg.formatted.size();
        }
        _fastfile_helper.write(msg);
    }

private:
    static filename_t calc_filename(const filename_t& filename, std::size_t index)
    {
        std::conditional<std::is_same<filename_t::value_type, char>::value, fmt::MemoryWriter, fmt::WMemoryWriter>::type w;
        if (index)
            w.write(SPDLOG_FILENAME_T("{}.{}"), filename, index);
        else
            w.write(SPDLOG_FILENAME_T("{}"), filename);
        return w.str();
    }

    // Rotate files:
    // log.txt -> log.txt.1
    // log.txt.1 -> log.txt.2
    // log.txt.2 -> log.txt.3
    // lo3.txt.3 -> delete

    void _rotate()
    {
        using details::os::filename_to_str;
        _fastfile_helper.close();
        for (auto i = _max_files; i > 0; --i)
        {
            filename_t src = calc_filename(_base_filename, i - 1);
            filename_t target = calc_filename(_base_filename, i);

            if (details::file_helper::file_exists(target))
            {
                if (details::os::remove(target) != 0)
                {
                    throw spdlog_ex("rotating_fastfile_sink: failed removing " + filename_to_str(target), errno);
                }
            }
            if (details::file_helper::file_exists(src) && details::os::rename(src, target))
            {
                throw spdlog_ex("rotating_fastfile_sink: failed renaming " + filename_to_str(src) + " to " + filename_to_str(target), errno);
            }
        }
        _fastfile_helper.reopen(true);
    }
    filename_t _base_filename;
    std::size_t _max_size;
    std::size_t _max_files;
    std::size_t _current_size;
    details::fastfile_helper _fastfile_helper;
};

typedef rotating_fastfile_sink<std::mutex> rotating_fastfile_sink_mt;
typedef rotating_fastfile_sink<details::null_mutex>rotating_fastfile_sink_st;

/*
 * Rotating file sink based on date. rotates at midnight
 */
template<class Mutex, class FileNameCalc = default_daily_file_name_calculator>
class daily_fastfile_sink :public base_sink < Mutex >
{
public:
    //create daily file sink which rotates on given time
    daily_fastfile_sink(
        const filename_t& base_filename,
        int rotation_hour,
        int rotation_minute) : _base_filename(base_filename),
        _rotation_h(rotation_hour),
        _rotation_m(rotation_minute)
    {
        if (rotation_hour < 0 || rotation_hour > 23 || rotation_minute < 0 || rotation_minute > 59)
            throw spdlog_ex("daily_fastfile_sink: Invalid rotation time in ctor");
        _rotation_tp = _next_rotation_tp();
        _fastfile_helper.open(FileNameCalc::calc_filename(_base_filename));
    }

    void flush() override
    {
        _fastfile_helper.flush();
    }

protected:
    void _sink_it(const details::log_msg& msg) override
    {
        if (std::chrono::system_clock::now() >= _rotation_tp)
        {
            _fastfile_helper.open(FileNameCalc::calc_filename(_base_filename));
            _rotation_tp = _next_rotation_tp();
        }
        _fastfile_helper.write(msg);
    }

private:
    std::chrono::system_clock::time_point _next_rotation_tp()
    {
        auto now = std::chrono::system_clock::now();
        time_t tnow = std::chrono::system_clock::to_time_t(now);
        tm date = spdlog::details::os::localtime(tnow);
        date.tm_hour = _rotation_h;
        date.tm_min = _rotation_m;
        date.tm_sec = 0;
        auto rotation_time = std::chrono::system_clock::from_time_t(std::mktime(&date));
        if (rotation_time > now)
            return rotation_time;
        else
            return std::chrono::system_clock::time_point(rotation_time + std::chrono::hours(24));
    }

    filename_t _base_filename;
    int _rotation_h;
    int _rotation_m;
    std::chrono::system_clock::time_point _rotation_tp;
    details::fastfile_helper _fastfile_helper;
};

typedef daily_fastfile_sink<std::mutex> daily_fastfile_sink_mt;
typedef daily_fastfile_sink<details::null_mutex> daily_fastfile_sink_st;
}
}