<commit_before>{% load i18n %}

/* global
    inventreeLoad,
    inventreeSave,
*/

/* exported
    customGroupSorter,
    reloadtable,
    renderLink,
    reloadTableFilters,
*/

/**
 * Reload a named table
 * @param table
 */
function reloadtable(table) {
    $(table).bootstrapTable('refresh');
}

/**
 * Render a URL for display
 * @param {String} text
 * @param {String} url
 * @param {object} options
 * @returns link text
 */
function renderLink(text, url, options={}) {
    if (url === null || url === undefined || url === '') {
        return text;
    }

    var max_length = options.max_length || -1;

    // Shorten the displayed length if required
    if ((max_length > 0) && (text.length > max_length)) {
        var slice_length = (max_length - 3) / 2;

        var text_start = text.slice(0, slice_length);
        var text_end = text.slice(-slice_length);

        text = `${text_start}...${text_end}`;
    }

    return '' + text + '';
}

function enableButtons(elements, enabled) {
    for (let item of elements) {
        $(item).prop('disabled', !enabled);
    }
}

function linkButtonsToSelection(table, buttons) {
    /* Link a bootstrap-table object to one or more buttons.
     * The buttons will only be enabled if there is at least one row selected
     */

    if (typeof table === 'string') {
        table = $(table);
    }

    // Initially set the enable state of the buttons
    enableButtons(buttons, table.bootstrapTable('getSelections').length > 0);

    // Add a callback
    table.on('check.bs.table uncheck.bs.table check-some.bs.table uncheck-some.bs.table check-all.bs.table uncheck-all.bs.table', function() {
        enableButtons(buttons, table.bootstrapTable('getSelections').length > 0);
    });
}

/**
 * Returns true if the input looks like a valid number
 * @param {String} n
 * @returns
 */
function isNumeric(n) {
    return !isNaN(parseFloat(n)) && isFinite(n);
}

/*
 * Reload a table which has already been made into a bootstrap table.
 * New filters can be optionally provided, to change the query params.
 */
function reloadTableFilters(table, filters) {

    // Simply perform a refresh
    if (filters == null) {
        table.bootstrapTable('refresh');
        return;
    }

    // More complex refresh with new filters supplied
    var options = table.bootstrapTable('getOptions');

    // Construct a new list of filters to use for the query
    var params = {};

    for (var k in filters) {
        params[k] = filters[k];
    }

    // Original query params will override
    if (options.original != null) {
        for (var key in options.original) {
            params[key] = options.original[key];
        }
    }

    options.queryParams = function(tableParams) {
        return convertQueryParameters(tableParams, params);
    };

    table.bootstrapTable('refreshOptions', options);
    table.bootstrapTable('refresh', filters);
}

function visibleColumnString(columns) {
    /* Generate a list of "visible" columns to save to file. */

    var fields = [];

    columns.forEach(function(column) {
        if (column.switchable && column.visible) {
            fields.push(column.field);
        }
    });

    return fields.join(',');
}

/*
 * Convert bootstrap-table style parameters to "InvenTree" style
*/
function convertQueryParameters(params, filters) {

    // Override the way that we ask the server to sort results
    // It seems bootstrap-table does not offer a "native" way to do this...
    if ('sort' in params) {
        var order = params['order'];

        var ordering = params['sort'] || null;

        if (ordering) {
            if (order == 'desc') {
                ordering = `-${ordering}`;
            }

            params['ordering'] = ordering;
        }

        delete params['sort'];
        delete params['order'];

    }

    for (var key in filters) {
        params[key] = filters[key];
    }

    // Add "order" back in (if it was originally specified by InvenTree)
    // Annoyingly, "order" shadows some field names in InvenTree...
    if ('order' in filters) {
        params['order'] = filters['order'];
    }

    // Remove searchable[] array (generated by bootstrap-table)
    if ('searchable' in params) {
        delete params['searchable'];
    }

    if ('sortable' in params) {
        delete params['sortable'];
    }

    return params;
}

/* Wrapper function for bootstrapTable.
 * Sets some useful defaults, and manage persistent settings.
 */
$.fn.inventreeTable = function(options) {

    var table = this;

    var tableName = options.name || 'table';

    var varName = tableName + '-pagesize';

    // Pagingation options (can be server-side or client-side as specified by the caller)
    if (!options.disablePagination) {
        options.pagination = true;
        options.paginationVAlign = options.paginationVAlign || 'both';
        options.pageSize = options.pageSize || inventreeLoad(varName, 25);
        options.pageList = [25, 50, 100, 250, 'all'];
        options.totalField = 'count';
        options.dataField = 'results';
    }

    // Extract query params
    var filters = options.queryParams || options.filters || {};

    options.queryParams = function(params) {
        return convertQueryParameters(params, filters);
    };

    options.rememberOrder = true;

    if (options.sortable == null) {
        options.sortable = true;
    }

    if (options.search == null) {
        options.search = true;
    }

    if (options.showColumns == null) {
        options.showColumns = true;
    }

    // Callback to save pagination data
    options.onPageChange = function(number, size) {
        inventreeSave(varName, size);
    };

    // Callback when a column is changed
    options.onColumnSwitch = function() {

        var columns = table.bootstrapTable('getVisibleColumns');

        var text = visibleColumnString(columns);

        // Save visible columns
        inventreeSave(`table_columns_${tableName}`, text);
    };

    // Standard options for all tables
    table.bootstrapTable(options);

    // Load visible column list from memory
    // Load visible column list
    var visibleColumns = inventreeLoad(`table_columns_${tableName}`, null);

    // If a set of visible columns has been saved, load!
    if (visibleColumns) {
        var columns = visibleColumns.split(',');

        // Which columns are currently visible?
        var visible = table.bootstrapTable('getVisibleColumns');

        if (visible && Array.isArray(visible)) {
            visible.forEach(function(column) {

                // Visible field should *not* be visible! (hide it!)
                if (column.switchable && !columns.includes(column.field)) {
                    table.bootstrapTable('hideColumn', column.field);
                }
            });
        } else {
            console.log(`Could not get list of visible columns for column '${tableName}'`);
        }
    }

    // Optionally, link buttons to the table selection
    if (options.buttons) {
        linkButtonsToSelection(table, options.buttons);
    }
};

function customGroupSorter(sortName, sortOrder, sortData) {

    var order = sortOrder === 'desc' ? -1 : 1;

    sortData.sort(function(a, b) {

        // Extract default field values
        // Allow multi-level access if required
        // Ref: https://stackoverflow.com/a/6394168

        function extract(obj, i) {
            return obj[i];
        }

        var aa = sortName.split('.').reduce(extract, a);
        var bb = sortName.split('.').reduce(extract, b);

        // Extract parent information
        var aparent = a._data && a._data['parent-index'];
        var bparent = b._data && b._data['parent-index'];

        // If either of the comparisons are in a group
        if (aparent || bparent) {

            // If the parents are different (or one item does not have a parent,
            // then we need to extract the parent value for the selected column.

            if (aparent != bparent) {
                if (aparent) {
                    aa = a._data['table'].options.groupByFormatter(sortName, 0, a._data['group-data']);
                }

                if (bparent) {
                    bb = b._data['table'].options.groupByFormatter(sortName, 0, b._data['group-data']);
                }
            }
        }

        if (aa === undefined || aa === null) {
            aa = '';
        }
        if (bb === undefined || bb === null) {
            bb = '';
        }

        if (isNumeric(aa) && isNumeric(bb)) {
            if (aa < bb) {
                return order * -1;
            } else if (aa > bb) {
                return order;
            } else {
                return 0;
            }
        }

        aa = aa.toString();
        bb = bb.toString();

        var cmp = aa.localeCompare(bb);

        if (cmp === -1) {
            return order * -1;
        } else if (cmp === 1) {
            return order;
        } else {
            return 0;
        }
    });
}

// Expose default bootstrap table string literals to translation layer
(function($) {
    'use strict';

    $.fn.bootstrapTable.locales['en-US-custom'] = {
        formatLoadingMessage: function() {
            return '{% trans "Loading data" %}';
        },
        formatRecordsPerPage: function(pageNumber) {
            return `${pageNumber} {% trans "rows per page" %}`;
        },
        formatShowingRows: function(pageFrom, pageTo, totalRows) {
            return `{% trans "Showing" %} ${pageFrom} {% trans "to" %} ${pageTo} {% trans "of" %} ${totalRows} {% trans "rows" %}`;
        },
        formatSearch: function() {
            return '{% trans "Search" %}';
        },
        formatNoMatches: function() {
            return '{% trans "No matching results" %}';
        },
        formatPaginationSwitch: function() {
            return '{% trans "Hide/Show pagination" %}';
        },
        formatRefresh: function() {
            return '{% trans "Refresh" %}';
        },
        formatToggle: function() {
            return '{% trans "Toggle" %}';
        },
        formatColumns: function() {
            return '{% trans "Columns" %}';
        },
        formatAllRows: function() {
            return '{% trans "All" %}';
        },
    };

    $.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales['en-US-custom']);

})(jQuery);
<commit_msg>Retain "original" search parameter in query<commit_after>{% load i18n %}

/* global
    inventreeLoad,
    inventreeSave,
*/

/* exported
    customGroupSorter,
    reloadtable,
    renderLink,
    reloadTableFilters,
*/

/**
 * Reload a named table
 * @param table
 */
function reloadtable(table) {
    $(table).bootstrapTable('refresh');
}

/**
 * Render a URL for display
 * @param {String} text
 * @param {String} url
 * @param {object} options
 * @returns link text
 */
function renderLink(text, url, options={}) {
    if (url === null || url === undefined || url === '') {
        return text;
    }

    var max_length = options.max_length || -1;

    // Shorten the displayed length if required
    if ((max_length > 0) && (text.length > max_length)) {
        var slice_length = (max_length - 3) / 2;

        var text_start = text.slice(0, slice_length);
        var text_end = text.slice(-slice_length);

        text = `${text_start}...${text_end}`;
    }

    return '' + text + '';
}

function enableButtons(elements, enabled) {
    for (let item of elements) {
        $(item).prop('disabled', !enabled);
    }
}

function linkButtonsToSelection(table, buttons) {
    /* Link a bootstrap-table object to one or more buttons.
     * The buttons will only be enabled if there is at least one row selected
     */

    if (typeof table === 'string') {
        table = $(table);
    }

    // Initially set the enable state of the buttons
    enableButtons(buttons, table.bootstrapTable('getSelections').length > 0);

    // Add a callback
    table.on('check.bs.table uncheck.bs.table check-some.bs.table uncheck-some.bs.table check-all.bs.table uncheck-all.bs.table', function() {
        enableButtons(buttons, table.bootstrapTable('getSelections').length > 0);
    });
}

/**
 * Returns true if the input looks like a valid number
 * @param {String} n
 * @returns
 */
function isNumeric(n) {
    return !isNaN(parseFloat(n)) && isFinite(n);
}

/*
 * Reload a table which has already been made into a bootstrap table.
 * New filters can be optionally provided, to change the query params.
 */
function reloadTableFilters(table, filters) {

    // Simply perform a refresh
    if (filters == null) {
        table.bootstrapTable('refresh');
        return;
    }

    // More complex refresh with new filters supplied
    var options = table.bootstrapTable('getOptions');

    // Construct a new list of filters to use for the query
    var params = {};

    for (var k in filters) {
        params[k] = filters[k];
    }

    // Original query params will override
    if (options.original != null) {
        for (var key in options.original) {
            params[key] = options.original[key];
        }
    }

    options.queryParams = function(tableParams) {
        return convertQueryParameters(tableParams, params);
    };

    table.bootstrapTable('refreshOptions', options);
    table.bootstrapTable('refresh', filters);
}

function visibleColumnString(columns) {
    /* Generate a list of "visible" columns to save to file. */

    var fields = [];

    columns.forEach(function(column) {
        if (column.switchable && column.visible) {
            fields.push(column.field);
        }
    });

    return fields.join(',');
}

/*
 * Convert bootstrap-table style parameters to "InvenTree" style
*/
function convertQueryParameters(params, filters) {

    // Override the way that we ask the server to sort results
    // It seems bootstrap-table does not offer a "native" way to do this...
    if ('sort' in params) {
        var order = params['order'];

        var ordering = params['sort'] || null;

        if (ordering) {
            if (order == 'desc') {
                ordering = `-${ordering}`;
            }

            params['ordering'] = ordering;
        }

        delete params['sort'];
        delete params['order'];

    }

    for (var key in filters) {
        params[key] = filters[key];
    }

    // Add "order" back in (if it was originally specified by InvenTree)
    // Annoyingly, "order" shadows some field names in InvenTree...
    if ('order' in filters) {
        params['order'] = filters['order'];
    }

    // Remove searchable[] array (generated by bootstrap-table)
    if ('searchable' in params) {
        delete params['searchable'];
    }

    if ('sortable' in params) {
        delete params['sortable'];
    }

    // If "original_search" parameter is provided, add it to the "search"
    if ('original_search' in params) {
        var search = params['search'] || '';

        params['search'] = search + ' ' + params['original_search'];

        delete params['original_search'];
    }

    return params;
}

/* Wrapper function for bootstrapTable.
 * Sets some useful defaults, and manage persistent settings.
 */
$.fn.inventreeTable = function(options) {

    var table = this;

    var tableName = options.name || 'table';

    var varName = tableName + '-pagesize';

    // Pagingation options (can be server-side or client-side as specified by the caller)
    if (!options.disablePagination) {
        options.pagination = true;
        options.paginationVAlign = options.paginationVAlign || 'both';
        options.pageSize = options.pageSize || inventreeLoad(varName, 25);
        options.pageList = [25, 50, 100, 250, 'all'];
        options.totalField = 'count';
        options.dataField = 'results';
    }

    // Extract query params
    var filters = options.queryParams || options.filters || {};

    options.queryParams = function(params) {
        return convertQueryParameters(params, filters);
    };

    options.rememberOrder = true;

    if (options.sortable == null) {
        options.sortable = true;
    }

    if (options.search == null) {
        options.search = true;
    }

    if (options.showColumns == null) {
        options.showColumns = true;
    }

    // Callback to save pagination data
    options.onPageChange = function(number, size) {
        inventreeSave(varName, size);
    };

    // Callback when a column is changed
    options.onColumnSwitch = function() {

        var columns = table.bootstrapTable('getVisibleColumns');

        var text = visibleColumnString(columns);

        // Save visible columns
        inventreeSave(`table_columns_${tableName}`, text);
    };

    // Standard options for all tables
    table.bootstrapTable(options);

    // Load visible column list from memory
    // Load visible column list
    var visibleColumns = inventreeLoad(`table_columns_${tableName}`, null);

    // If a set of visible columns has been saved, load!
    if (visibleColumns) {
        var columns = visibleColumns.split(',');

        // Which columns are currently visible?
        var visible = table.bootstrapTable('getVisibleColumns');

        if (visible && Array.isArray(visible)) {
            visible.forEach(function(column) {

                // Visible field should *not* be visible! (hide it!)
                if (column.switchable && !columns.includes(column.field)) {
                    table.bootstrapTable('hideColumn', column.field);
                }
            });
        } else {
            console.log(`Could not get list of visible columns for column '${tableName}'`);
        }
    }

    // Optionally, link buttons to the table selection
    if (options.buttons) {
        linkButtonsToSelection(table, options.buttons);
    }
};

function customGroupSorter(sortName, sortOrder, sortData) {

    var order = sortOrder === 'desc' ? -1 : 1;

    sortData.sort(function(a, b) {

        // Extract default field values
        // Allow multi-level access if required
        // Ref: https://stackoverflow.com/a/6394168

        function extract(obj, i) {
            return obj[i];
        }

        var aa = sortName.split('.').reduce(extract, a);
        var bb = sortName.split('.').reduce(extract, b);

        // Extract parent information
        var aparent = a._data && a._data['parent-index'];
        var bparent = b._data && b._data['parent-index'];

        // If either of the comparisons are in a group
        if (aparent || bparent) {

            // If the parents are different (or one item does not have a parent,
            // then we need to extract the parent value for the selected column.

            if (aparent != bparent) {
                if (aparent) {
                    aa = a._data['table'].options.groupByFormatter(sortName, 0, a._data['group-data']);
                }

                if (bparent) {
                    bb = b._data['table'].options.groupByFormatter(sortName, 0, b._data['group-data']);
                }
            }
        }

        if (aa === undefined || aa === null) {
            aa = '';
        }
        if (bb === undefined || bb === null) {
            bb = '';
        }

        if (isNumeric(aa) && isNumeric(bb)) {
            if (aa < bb) {
                return order * -1;
            } else if (aa > bb) {
                return order;
            } else {
                return 0;
            }
        }

        aa = aa.toString();
        bb = bb.toString();

        var cmp = aa.localeCompare(bb);

        if (cmp === -1) {
            return order * -1;
        } else if (cmp === 1) {
            return order;
        } else {
            return 0;
        }
    });
}

// Expose default bootstrap table string literals to translation layer
(function($) {
    'use strict';

    $.fn.bootstrapTable.locales['en-US-custom'] = {
        formatLoadingMessage: function() {
            return '{% trans "Loading data" %}';
        },
        formatRecordsPerPage: function(pageNumber) {
            return `${pageNumber} {% trans "rows per page" %}`;
        },
        formatShowingRows: function(pageFrom, pageTo, totalRows) {
            return `{% trans "Showing" %} ${pageFrom} {% trans "to" %} ${pageTo} {% trans "of" %} ${totalRows} {% trans "rows" %}`;
        },
        formatSearch: function() {
            return '{% trans "Search" %}';
        },
        formatNoMatches: function() {
            return '{% trans "No matching results" %}';
        },
        formatPaginationSwitch: function() {
            return '{% trans "Hide/Show pagination" %}';
        },
        formatRefresh: function() {
            return '{% trans "Refresh" %}';
        },
        formatToggle: function() {
            return '{% trans "Toggle" %}';
        },
        formatColumns: function() {
            return '{% trans "Columns" %}';
        },
        formatAllRows: function() {
            return '{% trans "All" %}';
        },
    };

    $.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales['en-US-custom']);

})(jQuery);
<|endoftext|>


<commit_before>import { constant, isFunction } from 'lodash';
import { getConfig } from '../../modules/config';
import { selectOAuthToken, selectSessionToken } from '../../modules/auth';
import fetchGraphQLApi from './fetchGraphQLApi';

export default async function callGraphQLApi({
  actionTypes: [requestType, successType, failureType],
  query,
  variables,
  operationName,
  bailout = constant(false),
  dispatch,
  getState
}) {
  if (!isFunction(dispatch) || !isFunction(getState)) {
    throw new Error('callGraphQLApi requires dispatch and getState functions');
  }

  const state = getState();
  const config = getConfig(state);
  const endpoint = `${config.apiRoot}/${config.graphQLEndpoint}`;
  const token = selectOAuthToken(state) || selectSessionToken(state);

  const shouldBail = bailout(state);
  if (shouldBail) {
    return;
  }

  dispatch({ type: requestType, meta: { variables, operationName, query } });

  let response;
  try {
    response = await fetchGraphQLApi({
      endpoint,
      query,
      variables,
      operationName,
      token
    });
  } catch (e) {
    dispatch({
      type: failureType,
      error: true,
      payload: e,
      meta: { variables, operationName, query }
    });

    let error = new Error('API call failed');
    // wrap this single error for consistency with graphQL errors, which are always
    // wrapped.
    error.errors = [e];
    throw error;
  }

  if (response.errors && response.errors.length) {
    dispatch({
      type: failureType,
      error: true,
      payload: response.errors,
      meta: { variables, operationName, query }
    });

    let error = new Error('API response included errors');
    error.errors = response.errors;
    throw error;
  }

  dispatch({
    type: successType,
    payload: response.data,
    meta: { variables, operationName, query }
  });

  return response.data;
}
<commit_msg>fix export style due to babel bug<commit_after>import { constant, isFunction } from 'lodash';
import { getConfig } from '../../modules/config';
import { selectOAuthToken, selectSessionToken } from '../../modules/auth';
import fetchGraphQLApi from './fetchGraphQLApi';

async function callGraphQLApi({
  actionTypes: [requestType, successType, failureType],
  query,
  variables,
  operationName,
  bailout = constant(false),
  dispatch,
  getState
}) {
  if (!isFunction(dispatch) || !isFunction(getState)) {
    throw new Error('callGraphQLApi requires dispatch and getState functions');
  }

  const state = getState();
  const config = getConfig(state);
  const endpoint = `${config.apiRoot}/${config.graphQLEndpoint}`;
  const token = selectOAuthToken(state) || selectSessionToken(state);

  const shouldBail = bailout(state);
  if (shouldBail) {
    return;
  }

  dispatch({ type: requestType, meta: { variables, operationName, query } });

  let response;
  try {
    response = await fetchGraphQLApi({
      endpoint,
      query,
      variables,
      operationName,
      token
    });
  } catch (e) {
    dispatch({
      type: failureType,
      error: true,
      payload: e,
      meta: { variables, operationName, query }
    });

    let error = new Error('API call failed');
    // wrap this single error for consistency with graphQL errors, which are always
    // wrapped.
    error.errors = [e];
    throw error;
  }

  if (response.errors && response.errors.length) {
    dispatch({
      type: failureType,
      error: true,
      payload: response.errors,
      meta: { variables, operationName, query }
    });

    let error = new Error('API response included errors');
    error.errors = response.errors;
    throw error;
  }

  dispatch({
    type: successType,
    payload: response.data,
    meta: { variables, operationName, query }
  });

  return response.data;
}

export default callGraphQLApi;
<|endoftext|>


<commit_before>"use strict";

var _ = require("underscore");
var describedClass = require("../../lib/hdl/environment");
var Parser = require("../../lib/hdl/parser");

describe("Environment", function () {
  var subject, not, nand, and;

  beforeEach(function () {
    subject = new describedClass();

    not = Parser.parse("not", "       \n\
      inputs in                       \n\
      outputs out                     \n\
                                      \n\
      nand(a=in, b=in, out=out)       \n\
    ");

    nand = Parser.parse("nand", "     \n\
      inputs a, b                     \n\
      outputs out                     \n\
                                      \n\
      | a | b | out |                 \n\
      | 0 | 0 |  1  |                 \n\
      | 0 | 1 |  1  |                 \n\
      | 1 | 0 |  1  |                 \n\
      | 1 | 1 |  0  |                 \n\
    ");

    and = Parser.parse("and", "       \n\
      inputs a, b                     \n\
      outputs out                     \n\
                                      \n\
      not(in=x, out=out)              \n\
      nand(a=a, b=b, out=x)           \n\
    ");
  });

  describe("#addChip", function () {
    it("adds a chip to the environment", function () {
      subject.addChip("not", not);

      var graph = subject.graph;
      expect(graph.nodes.length).toEqual(5);
      expect(graph.edges.length).toEqual(5);
    });

    it("is idempotent", function () {
      subject.addChip("not", not);
      subject.addChip("not", not);
      subject.addChip("not", not);

      var graph = subject.graph;
      expect(graph.nodes.length).toEqual(5);
      expect(graph.edges.length).toEqual(5);
    });

    it("updates instances to point to the concrete chip", function () {
      subject.addChip("not", not);
      subject.addChip("nand", nand);
      subject.addChip("and", and);

      var graph = subject.graph;
      not = graph.findBy({ name: "not" });
      and = graph.findBy({ name: "and" });

      var instance = not.outEdges[0].destination;
      nand = instance.outEdges[3].destination;
      // edge redirector put the redirected edge at the end

      expect(nand.value.name).toEqual("nand");
      expect(nand.outEdges.length).toEqual(4);

      instance = and.outEdges[0].destination;
      not = instance.outEdges[2].destination;

      expect(not.value.name).toEqual("not");
      expect(not.outEdges.length).toEqual(1);

      instance = and.outEdges[1].destination;
      nand = instance.outEdges[3].destination;
      // edge redirector put the redirected edge at the end

      expect(nand.value.name).toEqual("nand");
      expect(nand.outEdges.length).toEqual(4);

      var nots = graph.where({ name: "not" });
      var nands = graph.where({ name: "nand" });
      var ands = graph.where({ name: "and" });

      expect(nots.length).toEqual(1);
      expect(nands.length).toEqual(1);
      expect(ands.length).toEqual(1);
    });
  });

  describe("#removeChip", function () {
    beforeEach(function () {
      subject.addChip("not", not);
    });

    it("removes a chip from the environment", function () {
      subject.removeChip("not");

      var graph = subject.graph;
      expect(graph.nodes.length).toEqual(0);
      expect(graph.edges.length).toEqual(0);
    });

    it("is idempotent", function () {
      subject.removeChip("not");
      subject.removeChip("not");
      subject.removeChip("not");

      var graph = subject.graph;
      expect(graph.nodes.length).toEqual(0);
      expect(graph.edges.length).toEqual(0);
    });

    it("updates instances to point to a reference to the chip", function () {
      subject.addChip("nand", nand);
      subject.addChip("and", and);

      subject.removeChip("nand");

      var graph = subject.graph;
      not = graph.findBy({ name: "not" });
      and = graph.findBy({ name: "and" });

      var instance = not.outEdges[0].destination;
      nand = instance.outEdges[3].destination;
      // edge redirector put the redirected edge at the end

      expect(nand.value.name).toEqual("nand");
      expect(nand.outEdges.length).toEqual(0);

      instance = and.outEdges[0].destination;
      not = instance.outEdges[2].destination;

      expect(not.value.name).toEqual("not");
      expect(not.outEdges.length).toEqual(1);

      instance = and.outEdges[1].destination;
      nand = instance.outEdges[3].destination;
      // edge redirector put the redirected edge at the end

      expect(nand.value.name).toEqual("nand");
      expect(nand.outEdges.length).toEqual(0);

      var nots = graph.where({ name: "not" });
      var nands = graph.where({ name: "nand" });
      var ands = graph.where({ name: "and" });

      expect(nots.length).toEqual(1);
      expect(nands.length).toEqual(1);
      expect(ands.length).toEqual(1);
    });

    it("does not remove chips that are depended on by others", function () {
      subject.addChip("nand", nand);
      subject.addChip("and", and);

      var graph = subject.graph;
      nand = graph.findBy({ name: "nand" });

      expect(nand.outEdges.length).toEqual(4);

      subject.removeChip("not");

      expect(nand.outEdges.length).toEqual(4);
    });
  });

  describe("integration test", function () {
    it("behaves as expected", function () {
      var graph = subject.graph;

      expect(graph.nodes.length).toEqual(0);
      expect(graph.edges.length).toEqual(0);

      subject.removeChip("and");
      subject.addChip("and", and);
      subject.removeChip("and");

      expect(graph.nodes.length).toEqual(0);
      expect(graph.edges.length).toEqual(0);

      subject.addChip("nand", nand);
      subject.addChip("and", and);
      subject.addChip("not", not);
      subject.addChip("not", not);
      subject.addChip("not", not);
      subject.removeChip("nand");
      subject.removeChip("and");
      subject.removeChip("and");
      subject.removeChip("and");
      subject.removeChip("not");

      expect(graph.nodes.length).toEqual(0);
      expect(graph.edges.length).toEqual(0);

      subject.addChip("nand", nand);

      expect(graph.nodes.length).toEqual(9);
      expect(graph.edges.length).toEqual(20);

      subject.addChip("not", not);

      expect(graph.nodes.length).toEqual(13);
      expect(graph.edges.length).toEqual(25);

      subject.addChip("and", and);

      expect(graph.nodes.length).toEqual(20);
      expect(graph.edges.length).toEqual(34);

      var nodeNames = _.map(graph.nodes, function (n) { return n.value.name; });
      expect(nodeNames).toEqual([
        "nand",
        "lookup",
        "a",
        "b",
        "out",
        "instance-0",
        "instance-1",
        "instance-2",
        "instance-3",
        "not",
        "in",
        "out",
        "instance-0",
        "and",
        "x",
        "out",
        "instance-0",
        "a",
        "b",
        "instance-1"
      ]);

      var xor = Parser.parse("xor", " \n\
        inputs a, b                   \n\
        outputs out                   \n\
                                      \n\
        | a | b | out |               \n\
        | 0 | 0 |  0  |               \n\
        | 0 | 1 |  1  |               \n\
        | 1 | 0 |  1  |               \n\
        | 1 | 1 |  0  |               \n\
      ");

      subject.addChip("xor", xor);

      var lookup = graph.findBy({ name: "lookup" });
      expect(lookup).toBeDefined();
      expect(lookup.inEdges.length).toEqual(8);

      subject.removeChip("nand");

      lookup = graph.findBy({ name: "lookup" });
      expect(lookup).toBeDefined();
      expect(lookup.inEdges.length).toEqual(4);

      subject.removeChip("xor");

      lookup = graph.findBy({ name: "lookup" });
      expect(lookup).toBeUndefined();

      expect(graph.nodes.length).toEqual(12);
      expect(graph.edges.length).toEqual(14);

      var alternativeAnd = Parser.parse("and", " \n\
        inputs a, b                              \n\
        outputs out                              \n\
                                                 \n\
        | a | b | out |                          \n\
        | 0 | 0 |  0  |                          \n\
        | 0 | 1 |  0  |                          \n\
        | 1 | 0 |  0  |                          \n\
        | 1 | 1 |  1  |                          \n\
      ");

      subject.addChip("and", alternativeAnd);

      var ands = graph.where({ name: "and" });
      expect(ands.length).toEqual(1);

      expect(graph.nodes.length).toEqual(14);
      expect(graph.edges.length).toEqual(25);
    });
  });
});
<commit_msg>Fix the environment tests after hooking in TopoSorter<commit_after>"use strict";

var _ = require("underscore");
var describedClass = require("../../lib/hdl/environment");
var Parser = require("../../lib/hdl/parser");

describe("Environment", function () {
  var subject, not, nand, and;

  beforeEach(function () {
    subject = new describedClass();

    not = Parser.parse("not", "       \n\
      inputs in                       \n\
      outputs out                     \n\
                                      \n\
      nand(a=in, b=in, out=out)       \n\
    ");

    nand = Parser.parse("nand", "     \n\
      inputs a, b                     \n\
      outputs out                     \n\
                                      \n\
      | a | b | out |                 \n\
      | 0 | 0 |  1  |                 \n\
      | 0 | 1 |  1  |                 \n\
      | 1 | 0 |  1  |                 \n\
      | 1 | 1 |  0  |                 \n\
    ");

    and = Parser.parse("and", "       \n\
      inputs a, b                     \n\
      outputs out                     \n\
                                      \n\
      not(in=x, out=out)              \n\
      nand(a=a, b=b, out=x)           \n\
    ");
  });

  describe("#addChip", function () {
    it("adds a chip to the environment", function () {
      subject.addChip("not", not);

      var graph = subject.graph;
      expect(graph.nodes.length).toEqual(5);
      expect(graph.edges.length).toEqual(5);
    });

    it("is idempotent", function () {
      subject.addChip("not", not);
      subject.addChip("not", not);
      subject.addChip("not", not);

      var graph = subject.graph;
      expect(graph.nodes.length).toEqual(5);
      expect(graph.edges.length).toEqual(5);
    });

    it("updates instances to point to the concrete chip", function () {
      subject.addChip("not", not);
      subject.addChip("nand", nand);
      subject.addChip("and", and);

      var graph = subject.graph;
      not = graph.findBy({ name: "not" });
      and = graph.findBy({ name: "and" });

      var instance = not.outEdges[0].destination;
      nand = instance.outEdges[3].destination;
      // edge redirector put the redirected edge at the end

      expect(nand.value.name).toEqual("nand");
      expect(nand.outEdges.length).toEqual(4);

      instance = and.outEdges[1].destination;
      // topo sorter put the instance in position 1
      not = instance.outEdges[2].destination;

      expect(not.value.name).toEqual("not");
      expect(not.outEdges.length).toEqual(1);

      instance = and.outEdges[0].destination;
      // topo sorter put the instance in position 0
      nand = instance.outEdges[3].destination;
      // edge redirector put the redirected edge at the end

      expect(nand.value.name).toEqual("nand");
      expect(nand.outEdges.length).toEqual(4);

      var nots = graph.where({ name: "not" });
      var nands = graph.where({ name: "nand" });
      var ands = graph.where({ name: "and" });

      expect(nots.length).toEqual(1);
      expect(nands.length).toEqual(1);
      expect(ands.length).toEqual(1);
    });
  });

  describe("#removeChip", function () {
    beforeEach(function () {
      subject.addChip("not", not);
    });

    it("removes a chip from the environment", function () {
      subject.removeChip("not");

      var graph = subject.graph;
      expect(graph.nodes.length).toEqual(0);
      expect(graph.edges.length).toEqual(0);
    });

    it("is idempotent", function () {
      subject.removeChip("not");
      subject.removeChip("not");
      subject.removeChip("not");

      var graph = subject.graph;
      expect(graph.nodes.length).toEqual(0);
      expect(graph.edges.length).toEqual(0);
    });

    it("updates instances to point to a reference to the chip", function () {
      subject.addChip("nand", nand);
      subject.addChip("and", and);

      subject.removeChip("nand");

      var graph = subject.graph;
      not = graph.findBy({ name: "not" });
      and = graph.findBy({ name: "and" });

      var instance = not.outEdges[0].destination;
      nand = instance.outEdges[3].destination;
      // edge redirector put the redirected edge at the end

      expect(nand.value.name).toEqual("nand");
      expect(nand.outEdges.length).toEqual(0);

      instance = and.outEdges[1].destination;
      // topo sorter put the instance in position 1
      not = instance.outEdges[2].destination;

      expect(not.value.name).toEqual("not");
      expect(not.outEdges.length).toEqual(1);

      instance = and.outEdges[0].destination;
      // topo sorter put the instance in position 0
      nand = instance.outEdges[3].destination;
      // edge redirector put the redirected edge at the end

      expect(nand.value.name).toEqual("nand");
      expect(nand.outEdges.length).toEqual(0);

      var nots = graph.where({ name: "not" });
      var nands = graph.where({ name: "nand" });
      var ands = graph.where({ name: "and" });

      expect(nots.length).toEqual(1);
      expect(nands.length).toEqual(1);
      expect(ands.length).toEqual(1);
    });

    it("does not remove chips that are depended on by others", function () {
      subject.addChip("nand", nand);
      subject.addChip("and", and);

      var graph = subject.graph;
      nand = graph.findBy({ name: "nand" });

      expect(nand.outEdges.length).toEqual(4);

      subject.removeChip("not");

      expect(nand.outEdges.length).toEqual(4);
    });
  });

  describe("integration test", function () {
    it("behaves as expected", function () {
      var graph = subject.graph;

      expect(graph.nodes.length).toEqual(0);
      expect(graph.edges.length).toEqual(0);

      subject.removeChip("and");
      subject.addChip("and", and);
      subject.removeChip("and");

      expect(graph.nodes.length).toEqual(0);
      expect(graph.edges.length).toEqual(0);

      subject.addChip("nand", nand);
      subject.addChip("and", and);
      subject.addChip("not", not);
      subject.addChip("not", not);
      subject.addChip("not", not);
      subject.removeChip("nand");
      subject.removeChip("and");
      subject.removeChip("and");
      subject.removeChip("and");
      subject.removeChip("not");

      expect(graph.nodes.length).toEqual(0);
      expect(graph.edges.length).toEqual(0);

      subject.addChip("nand", nand);

      expect(graph.nodes.length).toEqual(9);
      expect(graph.edges.length).toEqual(20);

      subject.addChip("not", not);

      expect(graph.nodes.length).toEqual(13);
      expect(graph.edges.length).toEqual(25);

      subject.addChip("and", and);

      expect(graph.nodes.length).toEqual(20);
      expect(graph.edges.length).toEqual(34);

      var nodeNames = _.map(graph.nodes, function (n) { return n.value.name; });
      expect(nodeNames).toEqual([
        "nand",
        "lookup",
        "a",
        "b",
        "out",
        "instance-0",
        "instance-1",
        "instance-2",
        "instance-3",
        "not",
        "in",
        "out",
        "instance-0",
        "and",
        "x",
        "out",
        "instance-0",
        "a",
        "b",
        "instance-1"
      ]);

      var xor = Parser.parse("xor", " \n\
        inputs a, b                   \n\
        outputs out                   \n\
                                      \n\
        | a | b | out |               \n\
        | 0 | 0 |  0  |               \n\
        | 0 | 1 |  1  |               \n\
        | 1 | 0 |  1  |               \n\
        | 1 | 1 |  0  |               \n\
      ");

      subject.addChip("xor", xor);

      var lookup = graph.findBy({ name: "lookup" });
      expect(lookup).toBeDefined();
      expect(lookup.inEdges.length).toEqual(8);

      subject.removeChip("nand");

      lookup = graph.findBy({ name: "lookup" });
      expect(lookup).toBeDefined();
      expect(lookup.inEdges.length).toEqual(4);

      subject.removeChip("xor");

      lookup = graph.findBy({ name: "lookup" });
      expect(lookup).toBeUndefined();

      expect(graph.nodes.length).toEqual(12);
      expect(graph.edges.length).toEqual(14);

      var alternativeAnd = Parser.parse("and", " \n\
        inputs a, b                              \n\
        outputs out                              \n\
                                                 \n\
        | a | b | out |                          \n\
        | 0 | 0 |  0  |                          \n\
        | 0 | 1 |  0  |                          \n\
        | 1 | 0 |  0  |                          \n\
        | 1 | 1 |  1  |                          \n\
      ");

      subject.addChip("and", alternativeAnd);

      var ands = graph.where({ name: "and" });
      expect(ands.length).toEqual(1);

      expect(graph.nodes.length).toEqual(14);
      expect(graph.edges.length).toEqual(25);
    });
  });
});
<|endoftext|>


<commit_before>export default {
  header: 'Bottom nav',
  headerText: 'The `v-bottom-nav` is an alternative to the sidebar. It is primarily used on mobile and comes in two variants, icons and text, and shift.',
  components: ['v-bottom-nav'],
  examples: [{
    iconsAndText: {
      header: 'Icons and text',
      desc: 'While the bottom nav is meant to be used with the `vue-router`, you can also programmatically control the active state of the buttons by using the `active.sync` prop. You can change a button\'s value by using its `value` attribute.'
    },
    colorAndShift: {
      header: 'Color & shift',
      desc: 'When using a colored background, it is recommended to use the `light` prop. The `shift` prop will hide the button text until active. Keep in mind, `v-btn` text is required to be wrapped in a `<span>` tag.'
    },
    toggle: {
      header: 'Toggle',
      desc: 'As with other Vuetify components, you can control the display state with `v-model`.'
    }
  }],
  props: [{
    active: 'Holds the value of the currently active button. If the button has no value supplied, its index will be used instead. This prop supports the **.sync** modifier.',
    shift: 'Hide text of button when not active'
  }]
}
<commit_msg>markup<commit_after>export default {
  header: 'Bottom nav',
  headerText: 'The `v-bottom-nav` is an alternative to the sidebar. It is primarily used on mobile and comes in two variants, icons and text, and shift.',
  components: ['v-bottom-nav'],
  examples: [{
    iconsAndText: {
      header: 'Icons and text',
      desc: 'While the bottom nav is meant to be used with the `vue-router`, you can also programmatically control the active state of the buttons by using the `active.sync` prop. You can change a button\'s value by using its `value` attribute.'
    },
    colorAndShift: {
      header: 'Color & shift',
      desc: 'When using a colored background, it is recommended to use the `light` prop. The `shift` prop will hide the button text until active. Keep in mind, `v-btn` text is required to be wrapped in a `<span>` tag.'
    },
    toggle: {
      header: 'Toggle',
      desc: 'As with other Vuetify components, you can control the display state with `v-model`.'
    }
  }],
  props: [{
    active: 'Holds the value of the currently active button. If the button has no value supplied, its index will be used instead. This prop supports the **.sync** modifier.',
    shift: 'Hide text of button when not active'
  }]
}
<|endoftext|>


<commit_before>tinymce.addI18n('it',{
"Cut": "Taglia",
"Header 2": "Header 2",
"Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": "Il tuo browser non supporta l'accesso diretto negli Appunti. Per favore usa i tasti di scelta rapida Ctrl+X\/C\/V.",
"Div": "Div",
"Paste": "Incolla",
"Close": "Chiudi",
"Font Family": "Famiglia font",
"Pre": "Pre",
"Align right": "Allinea a Destra",
"New document": "Nuovo Documento",
"Blockquote": "Blockquote",
"Numbered list": "Elenchi Numerati",
"Increase indent": "Aumenta Rientro",
"Formats": "Formattazioni",
"Headers": "Intestazioni",
"Select all": "Seleziona Tutto",
"Header 3": "Intestazione 3",
"Blocks": "Blocchi",
"Undo": "Indietro",
"Strikethrough": "Barrato",
"Bullet list": "Elenchi Puntati",
"Header 1": "Intestazione 1",
"Superscript": "Apice",
"Clear formatting": "Cancella Formattazione",
"Font Sizes": "Dimensioni font",
"Subscript": "Pedice",
"Header 6": "Intestazione 6",
"Redo": "Ripeti",
"Paragraph": "Paragrafo",
"Ok": "Ok",
"Bold": "Grassetto",
"Code": "Codice",
"Italic": "Corsivo",
"Align center": "Allinea al Cento",
"Header 5": "Intestazione 5",
"Decrease indent": "Riduci Rientro",
"Header 4": "Intestazione 4",
"Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.": "Incolla \u00e8 in modalit\u00e0 testo normale. I contenuti sono incollati come testo normale se non disattivi l'opzione.",
"Underline": "Sottolineato",
"Cancel": "Cancella",
"Justify": "Giustifica",
"Inline": "Inlinea",
"Copy": "Copia",
"Align left": "Allinea a Sinistra",
"Visual aids": "Elementi Visivi",
"Lower Greek": "Greek Minore",
"Square": "Quadrato",
"Default": "Default",
"Lower Alpha": "Alpha Minore",
"Circle": "Cerchio",
"Disc": "Disco",
"Upper Alpha": "Alpha Superiore",
"Upper Roman": "Roman Superiore",
"Lower Roman": "Roman Minore",
"Name": "Nome",
"Anchor": "Fissa",
"You have unsaved changes are you sure you want to navigate away?": "Non hai salvato delle modifiche, sei sicuro di andartene?",
"Restore last draft": "Ripristina l'ultima bozza.",
"Special character": "Carattere Speciale",
"Source code": "Codice Sorgente",
"Right to left": "Da Destra a Sinistra",
"Left to right": "Da Sinistra a Destra",
"Emoticons": "Emoction",
"Robots": "Robot",
"Document properties": "Propriet\u00e0 Documento",
"Title": "Titolo",
"Keywords": "Parola Chiave",
"Encoding": "Codifica",
"Description": "Descrizione",
"Author": "Autore",
"Fullscreen": "Schermo Intero",
"Horizontal line": "Linea Orizzontale",
"Horizontal space": "Spazio Orizzontale",
"Insert\/edit image": "Aggiungi\/Modifica Immagine",
"General": "Generale",
"Advanced": "Avanzato",
"Source": "Fonte",
"Border": "Bordo",
"Constrain proportions": "Mantieni Proporzioni",
"Vertical space": "Spazio Verticale",
"Image description": "Descrizione Immagine",
"Style": "Stile",
"Dimensions": "Dimenzioni",
"Insert image": "Inserisci immagine",
"Insert date\/time": "Inserisci Data\/Ora",
"Remove link": "Rimuovi link",
"Url": "Url",
"Text to display": "Testo da Visualizzare",
"Anchors": "Anchors",
"Insert link": "Inserisci il Link",
"New window": "Nuova Finestra",
"None": "No",
"The URL you entered seems to be an external link. Do you want to add the required http:\/\/ prefix?": "L'URL inserito sembra essere un collegamento esterno. Vuoi aggiungere il prefisso necessario http:\/\/?",
"Target": "Target",
"The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?": "L'URL inserito sembra essere un indirizzo email. Vuoi aggiungere il prefisso necessario mailto:?",
"Insert\/edit link": "Inserisci\/Modifica Link",
"Insert\/edit video": "Inserisci\/Modifica Video",
"Poster": "Anteprima",
"Alternative source": "Alternativo",
"Paste your embed code below:": "Incolla il codice d'incorporamento qui:",
"Insert video": "Inserisci Video",
"Embed": "Incorporare",
"Nonbreaking space": "Spazio unificatore",
"Page break": "Interruzione di pagina",
"Paste as text": "incolla come testo",
"Preview": "Anteprima",
"Print": "Stampa",
"Save": "Salva",
"Could not find the specified string.": "Impossibile trovare la parola specifica.",
"Replace": "Sostituisci",
"Next": "Successivo",
"Whole words": "Parole Sbagliate",
"Find and replace": "Trova e Sostituisci",
"Replace with": "Sostituisci Con",
"Find": "Trova",
"Replace all": "Sostituisci Tutto",
"Match case": "Maiuscole\/Minuscole ",
"Prev": "Precedente",
"Spellcheck": "Controllo ortografico",
"Finish": "Termina",
"Ignore all": "Ignora Tutto",
"Ignore": "Ignora",
"Insert row before": "Inserisci una Riga Prima",
"Rows": "Righe",
"Height": "Altezza",
"Paste row after": "Incolla una Riga Dopo",
"Alignment": "Allineamento",
"Column group": "Gruppo di Colonne",
"Row": "Riga",
"Insert column before": "Inserisci una Colonna Prima",
"Split cell": "Dividi Cella",
"Cell padding": "Padding della Cella",
"Cell spacing": "Spaziatura della Cella",
"Row type": "Tipo di Riga",
"Insert table": "Inserisci Tabella",
"Body": "Body",
"Caption": "Didascalia",
"Footer": "Footer",
"Delete row": "Cancella Riga",
"Paste row before": "Incolla una Riga Prima",
"Scope": "Campo",
"Delete table": "Cancella Tabella",
"Header cell": "cella d'intestazione",
"Column": "Colonna",
"Cell": "Cella",
"Header": "Header",
"Cell type": "Tipo di Cella",
"Copy row": "Copia Riga",
"Row properties": "Propriet\u00e0 della Riga",
"Table properties": "Propiet\u00e0 della Tabella",
"Row group": "Gruppo di Righe",
"Right": "Destra",
"Insert column after": "Inserisci una Colonna Dopo",
"Cols": "Colonne",
"Insert row after": "Inserisci una Riga Dopo",
"Width": "Larghezza",
"Cell properties": "Propiet\u00e0 della Cella",
"Left": "Sinistra",
"Cut row": "Taglia Riga",
"Delete column": "Cancella Colonna",
"Center": "Centro",
"Merge cells": "Unisci Cella",
"Insert template": "Inserisci Template",
"Templates": "Template",
"Background color": "Colore Background",
"Text color": "Colore Testo",
"Show blocks": "Mostra Blocchi",
"Show invisible characters": "Mostra Caratteri Invisibili",
"Words: {0}": "Parole: {0}",
"Insert": "Inserisci",
"File": "File",
"Edit": "Modifica",
"Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": "Rich Text Area. Premi ALT-F9 per il men\u00f9. Premi ALT-F10 per la barra degli strumenti. Premi ALT-0 per l'aiuto.",
"Tools": "Strumenti",
"View": "Visualizza",
"Table": "Tabella",
"Format": "Formato"
});<commit_msg>fixed a wrong translation<commit_after>tinymce.addI18n('it',{
"Cut": "Taglia",
"Header 2": "Header 2",
"Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": "Il tuo browser non supporta l'accesso diretto negli Appunti. Per favore usa i tasti di scelta rapida Ctrl+X\/C\/V.",
"Div": "Div",
"Paste": "Incolla",
"Close": "Chiudi",
"Font Family": "Famiglia font",
"Pre": "Pre",
"Align right": "Allinea a Destra",
"New document": "Nuovo Documento",
"Blockquote": "Blockquote",
"Numbered list": "Elenchi Numerati",
"Increase indent": "Aumenta Rientro",
"Formats": "Formattazioni",
"Headers": "Intestazioni",
"Select all": "Seleziona Tutto",
"Header 3": "Intestazione 3",
"Blocks": "Blocchi",
"Undo": "Indietro",
"Strikethrough": "Barrato",
"Bullet list": "Elenchi Puntati",
"Header 1": "Intestazione 1",
"Superscript": "Apice",
"Clear formatting": "Cancella Formattazione",
"Font Sizes": "Dimensioni font",
"Subscript": "Pedice",
"Header 6": "Intestazione 6",
"Redo": "Ripeti",
"Paragraph": "Paragrafo",
"Ok": "Ok",
"Bold": "Grassetto",
"Code": "Codice",
"Italic": "Corsivo",
"Align center": "Allinea al Cento",
"Header 5": "Intestazione 5",
"Decrease indent": "Riduci Rientro",
"Header 4": "Intestazione 4",
"Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.": "Incolla \u00e8 in modalit\u00e0 testo normale. I contenuti sono incollati come testo normale se non disattivi l'opzione.",
"Underline": "Sottolineato",
"Cancel": "Cancella",
"Justify": "Giustifica",
"Inline": "Inlinea",
"Copy": "Copia",
"Align left": "Allinea a Sinistra",
"Visual aids": "Elementi Visivi",
"Lower Greek": "Greek Minore",
"Square": "Quadrato",
"Default": "Default",
"Lower Alpha": "Alpha Minore",
"Circle": "Cerchio",
"Disc": "Disco",
"Upper Alpha": "Alpha Superiore",
"Upper Roman": "Roman Superiore",
"Lower Roman": "Roman Minore",
"Name": "Nome",
"Anchor": "Fissa",
"You have unsaved changes are you sure you want to navigate away?": "Non hai salvato delle modifiche, sei sicuro di andartene?",
"Restore last draft": "Ripristina l'ultima bozza.",
"Special character": "Carattere Speciale",
"Source code": "Codice Sorgente",
"Right to left": "Da Destra a Sinistra",
"Left to right": "Da Sinistra a Destra",
"Emoticons": "Emoction",
"Robots": "Robot",
"Document properties": "Propriet\u00e0 Documento",
"Title": "Titolo",
"Keywords": "Parola Chiave",
"Encoding": "Codifica",
"Description": "Descrizione",
"Author": "Autore",
"Fullscreen": "Schermo Intero",
"Horizontal line": "Linea Orizzontale",
"Horizontal space": "Spazio Orizzontale",
"Insert\/edit image": "Aggiungi\/Modifica Immagine",
"General": "Generale",
"Advanced": "Avanzato",
"Source": "Fonte",
"Border": "Bordo",
"Constrain proportions": "Mantieni Proporzioni",
"Vertical space": "Spazio Verticale",
"Image description": "Descrizione Immagine",
"Style": "Stile",
"Dimensions": "Dimensioni",
"Insert image": "Inserisci immagine",
"Insert date\/time": "Inserisci Data\/Ora",
"Remove link": "Rimuovi link",
"Url": "Url",
"Text to display": "Testo da Visualizzare",
"Anchors": "Anchors",
"Insert link": "Inserisci il Link",
"New window": "Nuova Finestra",
"None": "No",
"The URL you entered seems to be an external link. Do you want to add the required http:\/\/ prefix?": "L'URL inserito sembra essere un collegamento esterno. Vuoi aggiungere il prefisso necessario http:\/\/?",
"Target": "Target",
"The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?": "L'URL inserito sembra essere un indirizzo email. Vuoi aggiungere il prefisso necessario mailto:?",
"Insert\/edit link": "Inserisci\/Modifica Link",
"Insert\/edit video": "Inserisci\/Modifica Video",
"Poster": "Anteprima",
"Alternative source": "Alternativo",
"Paste your embed code below:": "Incolla il codice d'incorporamento qui:",
"Insert video": "Inserisci Video",
"Embed": "Incorporare",
"Nonbreaking space": "Spazio unificatore",
"Page break": "Interruzione di pagina",
"Paste as text": "incolla come testo",
"Preview": "Anteprima",
"Print": "Stampa",
"Save": "Salva",
"Could not find the specified string.": "Impossibile trovare la parola specifica.",
"Replace": "Sostituisci",
"Next": "Successivo",
"Whole words": "Parole Sbagliate",
"Find and replace": "Trova e Sostituisci",
"Replace with": "Sostituisci Con",
"Find": "Trova",
"Replace all": "Sostituisci Tutto",
"Match case": "Maiuscole\/Minuscole ",
"Prev": "Precedente",
"Spellcheck": "Controllo ortografico",
"Finish": "Termina",
"Ignore all": "Ignora Tutto",
"Ignore": "Ignora",
"Insert row before": "Inserisci una Riga Prima",
"Rows": "Righe",
"Height": "Altezza",
"Paste row after": "Incolla una Riga Dopo",
"Alignment": "Allineamento",
"Column group": "Gruppo di Colonne",
"Row": "Riga",
"Insert column before": "Inserisci una Colonna Prima",
"Split cell": "Dividi Cella",
"Cell padding": "Padding della Cella",
"Cell spacing": "Spaziatura della Cella",
"Row type": "Tipo di Riga",
"Insert table": "Inserisci Tabella",
"Body": "Body",
"Caption": "Didascalia",
"Footer": "Footer",
"Delete row": "Cancella Riga",
"Paste row before": "Incolla una Riga Prima",
"Scope": "Campo",
"Delete table": "Cancella Tabella",
"Header cell": "cella d'intestazione",
"Column": "Colonna",
"Cell": "Cella",
"Header": "Header",
"Cell type": "Tipo di Cella",
"Copy row": "Copia Riga",
"Row properties": "Propriet\u00e0 della Riga",
"Table properties": "Propiet\u00e0 della Tabella",
"Row group": "Gruppo di Righe",
"Right": "Destra",
"Insert column after": "Inserisci una Colonna Dopo",
"Cols": "Colonne",
"Insert row after": "Inserisci una Riga Dopo",
"Width": "Larghezza",
"Cell properties": "Propiet\u00e0 della Cella",
"Left": "Sinistra",
"Cut row": "Taglia Riga",
"Delete column": "Cancella Colonna",
"Center": "Centro",
"Merge cells": "Unisci Cella",
"Insert template": "Inserisci Template",
"Templates": "Template",
"Background color": "Colore Background",
"Text color": "Colore Testo",
"Show blocks": "Mostra Blocchi",
"Show invisible characters": "Mostra Caratteri Invisibili",
"Words: {0}": "Parole: {0}",
"Insert": "Inserisci",
"File": "File",
"Edit": "Modifica",
"Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": "Rich Text Area. Premi ALT-F9 per il men\u00f9. Premi ALT-F10 per la barra degli strumenti. Premi ALT-0 per l'aiuto.",
"Tools": "Strumenti",
"View": "Visualizza",
"Table": "Tabella",
"Format": "Formato"
});<|endoftext|>


<commit_before>/*
Script: MooEditable.UI.MenuList.js
	UI Class to create a menu list (select) element.

License:
	MIT-style license.

Copyright:
	Copyright (c) 2007-2009 [Lim Chee Aun](http://cheeaun.com).
*/

MooEditable.UI.MenuList = new Class({

	Implements: [Events, Options],

	options: {
		/*
		onAction: $empty,
		*/
		title: '',
		name: '',
		'class': '',
		title: '',
		list: []
	},

	initialize: function(options){
		this.setOptions(options);
		this.name = this.options.name;
		this.render();
	},

	toElement: function(){
		return this.el;
	},

	render: function(){
		var self = this;
		var html = '';
		this.options.list.each(function(item){
			html += '<option value="{value}">{text}</option>'.substitute(item);
		});
		this.el = new Element('select', {
			'class': self.options['class'],
			title: self.options.title,
			html: html,
			events: {
				change: self.action.bind(self)
			}
		});

		this.disabled = false;

		// add hover effect for IE
		if (Browser.Engine.trident) this.el.addEvents({
			mouseenter: function(e){ this.addClass('hover'); },
			mouseleave: function(e){ this.removeClass('hover'); }
		});

		return this;
	},

	action: function(e){
		e.stop();
		if (this.disabled) return;
		var name = e.target.value;
		this.fireEvent('action', [this, name]);
	},

	enable: function(){
		if (!this.disabled) return;
		this.disabled = false;
		this.el.set('disabled', false).removeClass('disabled').set('opacity', 1);
		return this;
	},

	disable: function(){
		if (this.disabled) return;
		this.disabled = true;
		this.el.set('disabled', true).addClass('disabled').set('opacity', 0.4);
		return this;
	},

	activate: function(value){
		if (this.disabled) return;
		var index = 0;
		if (value) this.options.list.each(function(item, i){
			if (item.value == value) index = i;
		});
		this.el.selectedIndex = index;
		return this;
	},

	deactivate: function(){
		this.el.selectedIndex = 0;
		this.el.removeClass('onActive');
		return this;
	}

});<commit_msg>Disabled attrs for MenuList.<commit_after>/*
Script: MooEditable.UI.MenuList.js
	UI Class to create a menu list (select) element.

License:
	MIT-style license.

Copyright:
	Copyright (c) 2007-2009 [Lim Chee Aun](http://cheeaun.com).
*/

MooEditable.UI.MenuList = new Class({

	Implements: [Events, Options],

	options: {
		/*
		onAction: $empty,
		*/
		title: '',
		name: '',
		'class': '',
		title: '',
		list: []
	},

	initialize: function(options){
		this.setOptions(options);
		this.name = this.options.name;
		this.render();
	},

	toElement: function(){
		return this.el;
	},

	render: function(){
		var self = this;
		var html = '';
		this.options.list.each(function(item){
			html += '<option value="{value}">{text}</option>'.substitute(item);
		});
		this.el = new Element('select', {
			'class': self.options['class'],
			title: self.options.title,
			html: html,
			events: {
				change: self.action.bind(self)
			}
		});

		this.disabled = false;

		// add hover effect for IE
		if (Browser.Engine.trident) this.el.addEvents({
			mouseenter: function(e){ this.addClass('hover'); },
			mouseleave: function(e){ this.removeClass('hover'); }
		});

		return this;
	},

	action: function(e){
		e.stop();
		if (this.disabled) return;
		var name = e.target.value;
		this.fireEvent('action', [this, name]);
	},

	enable: function(){
		if (!this.disabled) return;
		this.disabled = false;
		this.el.set('disabled', false).removeClass('disabled').set({
			disabled: false,
			opacity: 1
		});
		return this;
	},

	disable: function(){
		if (this.disabled) return;
		this.disabled = true;
		this.el.set('disabled', true).addClass('disabled').set({
			disabled: true,
			opacity: 0.4
		});
		return this;
	},

	activate: function(value){
		if (this.disabled) return;
		var index = 0;
		if (value) this.options.list.each(function(item, i){
			if (item.value == value) index = i;
		});
		this.el.selectedIndex = index;
		return this;
	},

	deactivate: function(){
		this.el.selectedIndex = 0;
		this.el.removeClass('onActive');
		return this;
	}

});<|endoftext|>


<commit_before>/* globals describe, it, expect, hot, expectObservable */
var Rx = require('../../dist/cjs/Rx.KitchenSink');
var Observable = Rx.Observable;

describe('Observable.prototype.find()', function () {
  function truePredicate(x) {
    return true;
  }

  it('should not emit if source does not emit', function () {
    var source = hot('-');
    var expected =   '-';

    expectObservable(source.find(truePredicate)).toBe(expected);
  });

  it('should return undefined if source is empty to match predicate', function () {
    var expected = '(x|)';

    expectObservable(Observable.empty().find(truePredicate)).toBe(expected, {x: undefined});
  });

  it('should return matching element from source emits single element', function () {
    var source = hot('--a--|');
    var expected =   '--(a|)';

    var predicate = function (value) {
      return value === 'a';
    };

    expectObservable(source.find(predicate)).toBe(expected);
  });

  it('should return undefined if element does not match with predicate', function () {
    var source = hot('--a--b--c--|');
    var expected =   '-----------(x|)';

    var predicate = function (value) {
      return value === 'z';
    };

    expectObservable(source.find(predicate)).toBe(expected, { x: undefined });
  });

  it('should raise if source raise error while element does not match with predicate', function () {
    var source = hot('--a--b--#');
    var expected =   '--------#';

    var predicate = function (value) {
      return value === 'z';
    };

    expectObservable(source.find(predicate)).toBe(expected);
  });

  it('should raise error if predicate throws error', function () {
    var source = hot('--a--b--c--|');
    var expected =   '--#';

    var predicate = function (value) {
      throw 'error';
    };

    expectObservable(source.find(predicate)).toBe(expected);
  });
});<commit_msg>test(find): add subscription assertions on find() tests<commit_after>/* globals describe, it, expect, cold, hot, expectObservable, expectSubscriptions */
var Rx = require('../../dist/cjs/Rx.KitchenSink');
var Observable = Rx.Observable;

describe('Observable.prototype.find()', function () {
  function truePredicate(x) {
    return true;
  }

  it('should not emit if source does not emit', function () {
    var source = hot('-');
    var subs =       '^';
    var expected =   '-';

    expectObservable(source.find(truePredicate)).toBe(expected);
    expectSubscriptions(source.subscriptions).toBe(subs);
  });

  it('should return undefined if source is empty to match predicate', function () {
    var source = cold('|');
    var subs =        '(^!)';
    var expected =    '(x|)';

    var result = source.find(truePredicate);

    expectObservable(result).toBe(expected, {x: undefined});
    expectSubscriptions(source.subscriptions).toBe(subs);
  });

  it('should return matching element from source emits single element', function () {
    var source = hot('--a--|');
    var subs =       '^ !';
    var expected =   '--(a|)';

    var predicate = function (value) {
      return value === 'a';
    };

    expectObservable(source.find(predicate)).toBe(expected);
    expectSubscriptions(source.subscriptions).toBe(subs);
  });

  it('should return undefined if element does not match with predicate', function () {
    var source = hot('--a--b--c--|');
    var subs =       '^          !';
    var expected =   '-----------(x|)';

    var predicate = function (value) {
      return value === 'z';
    };

    expectObservable(source.find(predicate)).toBe(expected, { x: undefined });
    expectSubscriptions(source.subscriptions).toBe(subs);
  });

  it('should raise if source raise error while element does not match with predicate', function () {
    var source = hot('--a--b--#');
    var subs =       '^       !';
    var expected =   '--------#';

    var predicate = function (value) {
      return value === 'z';
    };

    expectObservable(source.find(predicate)).toBe(expected);
    expectSubscriptions(source.subscriptions).toBe(subs);
  });

  it('should raise error if predicate throws error', function () {
    var source = hot('--a--b--c--|');
    var subs =       '^ !';
    var expected =   '--#';

    var predicate = function (value) {
      throw 'error';
    };

    expectObservable(source.find(predicate)).toBe(expected);
    expectSubscriptions(source.subscriptions).toBe(subs);
  });
});<|endoftext|>


<commit_before>/* **************************************************************

   Copyright 2013 Zoovy, Inc.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

************************************************************** */

//    !!! ->   TODO: replace 'username' in the line below with the merchants username.     <- !!!

var store_tracking = function(_app) {
	var r = {

////////////////////////////////////   CALLBACKS    \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\

	callbacks : {
		init : {
			onSuccess : function()	{
				var r = false;

				r = true;

				return r;
				},
			onError : function()	{
				_app.u.dump('BEGIN store_tracking.callbacks.init.onError');
				}
			},
		attachHandlers : {
			onSuccess : function(){
				_app.ext.order_create.checkoutCompletes.push(function(P){
					if(P && P.datapointer && _app.data[P.datapointer] && _app.data[P.datapointer].order){
						var order = _app.data[P.datapointer].order;
						var plugins = zGlobals.plugins;

						ga('require', 'ecommerce');

						//analytics tracking
						ga('ecommerce:addTransaction', {
							'id' : order.orderid,
							'revenue' : order.sum.item_total,
							'shipping' : order.sum.shp_total,
							'tax' : order.sum.tax_total
							});
						for(var i in order['@ITEMS']){
							var item = order['@ITEMS'][i];
							ga('ecommerce:addItem', {
								'id' : order.orderid,
								'name' : item.prod_name,
								'sku' : item.sku,
								'price' : item.base_price,
								'qty' : item.qty,
								})
							};

						ga('ecommerce:send');

						for(var i in plugins){
							if(_app.ext.store_tracking.trackers[i] && _app.ext.store_tracking.trackers[i].enable){
								_app.ext.store_tracking.trackers[i](order, plugins[i]);
								}
							}
						}
					});
				},
			onError : function()	{
				_app.u.dump('BEGIN store_tracking.callbacks.attachHandlers.onError');
				}
			}
		}, //callbacks

		trackers : {
			"adwords.google.com" : function(order, plugin){
				var labels = plugin.google_conversion_label.split(',');
				for(var i in labels){
					var globals = {
						google_conversion_id : plugin.google_conversion_id,
						google_conversion_language : "en",
						google_conversion_format: "3",
						google_conversion_color : "ffffff",
						google_conversion_label : labels[i].replace(/^\s+|\s+$/g, ''), //trims label of whitespace
						google_remarketing_only : "false",
						}
					if(plugin.dynamic_value){
						globals.google_conversion_value = order.sum.order_total;
						}
					_app.ext.store_tracking.u.addTrackingScript("//www.googleadservices.com/pagead/conversion.js", globals);
					}
				}
			},

		u : {
			addTrackingScript : function(scripts, globals){
				//allow for convenient passing of a single string instead of an array
				if(typeof scripts == "string"){scripts = [scripts];}

				var iframe = document.createElement("iframe");
				$(iframe).addClass("displayNone");
				$('body').append(iframe);

				//the iframe needs a timeout after being added to the DOM before we can access its contents
				setTimeout(function(){
					if(globals){
						var paramScript = iframe.contentWindow.document.createElement("script");
						paramScript.type = "text/javascript";
						paramScript.text = "";
						for(var index in globals){
							paramScript.text += index+" = "+globals[index]+";";
							}
						iframe.contentWindow.document.body.appendChild(paramScript);
						}
					for(var i in scripts){
						var script = iframe.contentWindow.document.createElement("script");
						script.type = "text/javascript";
						script.src = scripts[i];
						iframe.contentWindow.document.body.appendChild(script);
						}
					}, 250);
				}
			}, //u [utilities]

		} //r object.
	return r;
	}<commit_msg>google analytics conversion tracking<commit_after>/* **************************************************************

   Copyright 2013 Zoovy, Inc.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

************************************************************** */

//    !!! ->   TODO: replace 'username' in the line below with the merchants username.     <- !!!

var store_tracking = function(_app) {
	var r = {

////////////////////////////////////   CALLBACKS    \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\

	callbacks : {
		init : {
			onSuccess : function()	{
				var r = false;

				r = true;
				// _app.u.dump('store_tracking.init.onSuccess')

				return r;
				},
			onError : function()	{
				_app.u.dump('BEGIN store_tracking.callbacks.init.onError');
				}
			},
		attachHandlers : {
			onSuccess : function(){
				// _app.u.dump('PUSHING store_tracking.onSuccess');
				_app.ext.order_create.checkoutCompletes.push(function(P){

					// _app.u.dump('BEGIN store_tracking.onSuccess');

					if(P && P.datapointer && _app.data[P.datapointer] && _app.data[P.datapointer].order){
						var order = _app.data[P.datapointer].order;
						var plugins = zGlobals.plugins;
						// note: order is an object that references the raw (public) cart
						// order.our.xxxx  order[@ITEMS], etc.

						// data will appear in google analytics immediately after adding it (there is no delay)

						// _app.u.dump(order);
						// _app.u.dump(order.our);

						ga('require', 'ecommerce');

						//analytics tracking
						var r = {
							'id' : order.our.orderid,
							'revenue' : order.sum.items_total,
							'shipping' : order.sum.shp_total,
							'tax' : order.sum.tax_total
							};
						_app.u.dump(r);

						ga('ecommerce:addTransaction',r);
						for(var i in order['@ITEMS']){
							var item = order['@ITEMS'][i];
							ga('ecommerce:addItem', {
								'id' : order.our.orderid,
								'name' : item.prod_name,
								'sku' : item.sku,
								'price' : item.base_price,
								'qty' : item.qty,
								})
							};

						ga('ecommerce:send');
						_app.u.dump('FINISHED store_tracking.onSuccess (google analytics)');

						for(var i in plugins){
							if(_app.ext.store_tracking.trackers[i] && _app.ext.store_tracking.trackers[i].enable){
								_app.ext.store_tracking.trackers[i](order, plugins[i]);
								}
							}
						}
					});
				},
			onError : function()	{
				_app.u.dump('BEGIN store_tracking.callbacks.attachHandlers.onError');
				}
			}
		}, //callbacks

		trackers : {
			"adwords.google.com" : function(order, plugin){
				var labels = plugin.google_conversion_label.split(',');
				for(var i in labels){
					var globals = {
						google_conversion_id : plugin.google_conversion_id,
						google_conversion_language : "en",
						google_conversion_format: "3",
						google_conversion_color : "ffffff",
						google_conversion_label : labels[i].replace(/^\s+|\s+$/g, ''), //trims label of whitespace
						google_remarketing_only : "false",
						}
					if(plugin.dynamic_value){
						globals.google_conversion_value = order.sum.order_total;
						}
					_app.ext.store_tracking.u.addTrackingScript("//www.googleadservices.com/pagead/conversion.js", globals);
					}
				}
			},

		u : {
			addTrackingScript : function(scripts, globals){
				//allow for convenient passing of a single string instead of an array
				if(typeof scripts == "string"){scripts = [scripts];}

				var iframe = document.createElement("iframe");
				$(iframe).addClass("displayNone");
				$('body').append(iframe);

				//the iframe needs a timeout after being added to the DOM before we can access its contents
				setTimeout(function(){
					if(globals){
						var paramScript = iframe.contentWindow.document.createElement("script");
						paramScript.type = "text/javascript";
						paramScript.text = "";
						for(var index in globals){
							paramScript.text += index+" = "+globals[index]+";";
							}
						iframe.contentWindow.document.body.appendChild(paramScript);
						}
					for(var i in scripts){
						var script = iframe.contentWindow.document.createElement("script");
						script.type = "text/javascript";
						script.src = scripts[i];
						iframe.contentWindow.document.body.appendChild(script);
						}
					}, 250);
				}
			}, //u [utilities]

		} //r object.
	return r;
	}<|endoftext|>


<commit_before>'use strict';

describe('myApp.view2 module', function() {

  beforeEach(module('myApp.view2'));

  describe('view2 controller', function(){

    it('should ....', inject(function($controller) {
      //spec body
      var view2Ctrl = $controller('View2Ctrl');
      expect(view2Ctrl).toBeDefined();
    }));

  });
});<commit_msg>updated view2 tests<commit_after>'use strict';

describe('myApp.view2 module', function() {

  beforeEach(module('myApp.view2'));

  describe('view2 controller', function(){

    it('should ....', inject(function($controller, $rootScope) {
      //spec body
      var scope = $rootScope.$new()
      var view2Ctrl = $controller('View2Ctrl', {$scope:scope });
      expect(view2Ctrl).toBeDefined();
    }));

  });
});<|endoftext|>


<commit_before>/*global define*/
define([
        '../Core/defaultValue',
        '../Core/jsonp',
        '../Core/loadImage',
        '../Core/getImagePixels',
        '../Core/writeTextToCanvas',
        '../Core/DeveloperError',
        '../Core/Math',
        '../Core/BoundingSphere',
        '../Core/Cartesian2',
        '../Core/Cartesian3',
        '../Core/Cartographic',
        '../Core/Extent',
        '../Core/TaskProcessor',
        './Projections',
        './TileState',
        './TerrainProvider',
        './GeographicTilingScheme',
        './WebMercatorTilingScheme',
        '../ThirdParty/when'
    ], function(
        defaultValue,
        jsonp,
        loadImage,
        getImagePixels,
        writeTextToCanvas,
        DeveloperError,
        CesiumMath,
        BoundingSphere,
        Cartesian2,
        Cartesian3,
        Cartographic,
        Extent,
        TaskProcessor,
        Projections,
        TileState,
        TerrainProvider,
        GeographicTilingScheme,
        WebMercatorTilingScheme,
        when) {
    "use strict";

    /**
     * A {@link TerrainProvider} that produces geometry by tessellating height maps
     * retrieved from a Tile Map Service (TMS) server.
     *
     * @alias TileMapServiceTerrainProvider
     * @constructor
     *
     * @param {String} description.url The URL of the TMS service.
     * @param {Object} [description.proxy] A proxy to use for requests. This object is expected to have a getURL function which returns the proxied URL, if needed.
     *
     * @see TerrainProvider
     */
    function TileMapServiceTerrainProvider(description) {
        description = defaultValue(description, {});

        if (typeof description.url === 'undefined') {
            throw new DeveloperError('description.url is required.');
        }

        /**
         * The URL of the ArcGIS ImageServer.
         * @type {String}
         */
        this.url = description.url;

        /**
         * The tiling scheme used to tile the surface.
         *
         * @type TilingScheme
         */
        this.tilingScheme = new GeographicTilingScheme({
            numberOfLevelZeroTilesX : 2,
            numberOfLevelZeroTilesY : 1
        });
        this.maxLevel = 11;
        this.heightmapWidth = 64;
        this.levelZeroMaximumGeometricError = TerrainProvider.getEstimatedLevelZeroGeometricErrorForAHeightmap(this.tilingScheme.ellipsoid, this.heightmapWidth, this.tilingScheme.numberOfLevelZeroTilesX);

        this._proxy = description.proxy;

        this.ready = true;
    }

    /**
     * Gets the maximum geometric error allowed in a tile at a given level.
     *
     * @param {Number} level The tile level for which to get the maximum geometric error.
     * @returns {Number} The maximum geometric error.
     */
    TileMapServiceTerrainProvider.prototype.getLevelMaximumGeometricError = TerrainProvider.prototype.getLevelMaximumGeometricError;

    var requestsInFlight = 0;
    // Creating the geometry will require a request to the ImageServer, which will complete
    // asynchronously.  The question is, what do we do in the meantime?  The best thing to do is
    // to use terrain associated with the parent tile.  Ideally, we would be able to render
    // high-res imagery attached to low-res terrain.  In some ways, this is similar to the need
    // described in TerrainProvider of creating geometry for tiles at a higher level than
    // the terrain source actually provides.

    // In the short term, for simplicity:
    // 1. If a tile has geometry available but it has not yet been loaded, don't render the tile until
    //    the geometry has been loaded.
    // 2. If a tile does not have geometry available at all, do not render it or its siblings.
    // Longer term, #1 may be acceptable, but #2 won't be for the reasons described above.
    // To address #2, we can subdivide a mesh into its four children.  This will be fairly CPU
    // intensive, though, which is why we probably won't want to do it while waiting for the
    // actual data to load.  We could also potentially add fractal detail when subdividing.

    /**
     * Request the tile geometry from the remote server.  Once complete, the
     * tile state should be set to RECEIVED.  Alternatively, tile state can be set to
     * UNLOADED to indicate that the request should be attempted again next update, if the tile
     * is still needed.
     *
     * @param {Tile} The tile to request geometry for.
     */
    TileMapServiceTerrainProvider.prototype.requestTileGeometry = function(tile) {
        if (requestsInFlight > 6) {
            tile.state = TileState.UNLOADED;
            return;
        }

        ++requestsInFlight;

        var yTiles = this.tilingScheme.numberOfLevelZeroTilesY << tile.level;

        var url = this.url + '/' + tile.level + '/' + tile.x + '/' + (yTiles - tile.y - 1) + '.png';

        if (typeof this._proxy !== 'undefined') {
            url = this._proxy.getURL(url);
        }

        when(loadImage(url, true), function(image) {
            tile.geometry = image;
            tile.state = TileState.RECEIVED;
            --requestsInFlight;
        }, function(e) {
            /*global console*/
            console.error('failed to load tile geometry: ' + e);
            tile.state = TileState.FAILED;
            --requestsInFlight;
        });
    };

    var taskProcessor = new TaskProcessor('createVerticesFromHeightmap');

    /**
     * Transform the tile geometry from the format requested from the remote server
     * into a format suitable for resource creation.  Once complete, the tile
     * state should be set to TRANSFORMED.  Alternatively, tile state can be set to
     * RECEIVED to indicate that the transformation should be attempted again next update, if the tile
     * is still needed.
     *
     * @param {Context} context The context to use to create resources.
     * @param {Tile} tile The tile to transform geometry for.
     */
    TileMapServiceTerrainProvider.prototype.transformGeometry = function(context, tile) {
        // Get the height data from the image by copying it to a canvas.
        var image = tile.geometry;
//        var width = image.width;
//        var height = image.height;
//        var pixels = getImagePixels(image);
        var width = 129;
        var height = 129;
        var pixels = getImagePixels(image, width, height);

        var tilingScheme = this.tilingScheme;
        var ellipsoid = tilingScheme.ellipsoid;
        var extent = this.tilingScheme.tileXYToNativeExtent(tile.x, tile.y, tile.level);

        tile.center = ellipsoid.cartographicToCartesian(tile.extent.getCenter());

        var verticesPromise = taskProcessor.scheduleTask({
            heightmap : pixels,
            heightScale : 1000.0,
            heightOffset : 1000.0,
            bytesPerHeight : 3,
            stride : 4,
            width : width,
            height : height,
            extent : extent,
            relativeToCenter : tile.center,
            radiiSquared : ellipsoid.getRadiiSquared(),
            oneOverCentralBodySemimajorAxis : ellipsoid.getOneOverRadii().x,
            skirtHeight : Math.min(this.getLevelMaximumGeometricError(tile.level) * 10.0, 1000.0),
            isGeographic : true
        });

        if (typeof verticesPromise === 'undefined') {
            //postponed
            tile.state = TileState.RECEIVED;
            return;
        }

        when(verticesPromise, function(result) {
            console.log('Tile transformGeometry (' + tile.x + ', ' + tile.y + ', ' + tile.level + ') UDiff: ' + result.statistics.maxUDifference + ' VDiff: ' + result.statistics.maxVDifference);
            tile.geometry = undefined;
            tile.transformedGeometry = {
                vertices : result.vertices,
                statistics : result.statistics,
                indices : TerrainProvider.getRegularGridIndices(width + 2, height + 2)
            };
            tile.state = TileState.TRANSFORMED;
        }, function(e) {
            /*global console*/
            console.error('failed to transform geometry: ' + e);
            tile.state = TileState.FAILED;
        });
    };

    var scratch = new Cartesian3();

    /**
     * Create WebGL resources for the tile using whatever data the transformGeometry step produced.
     * Once complete, the tile state should be set to READY.  Alternatively, tile state can be set to
     * TRANSFORMED to indicate that resource creation should be attempted again next update, if the tile
     * is still needed.
     *
     * @param {Context} context The context to use to create resources.
     * @param {Tile} tile The tile to create resources for.
     */
    TileMapServiceTerrainProvider.prototype.createResources = function(context, tile) {
        var buffers = tile.transformedGeometry;
        tile.transformedGeometry = undefined;

        TerrainProvider.createTileEllipsoidGeometryFromBuffers(context, tile, buffers);
        tile.maxHeight = buffers.statistics.maxHeight;
        tile.boundingSphere3D = BoundingSphere.fromFlatArray(buffers.vertices, tile.center, 5);

        var ellipsoid = this.tilingScheme.ellipsoid;
        var extent = tile.extent;
        tile.southwestCornerCartesian = ellipsoid.cartographicToCartesian(extent.getSouthwest());
        tile.southeastCornerCartesian = ellipsoid.cartographicToCartesian(extent.getSoutheast());
        tile.northeastCornerCartesian = ellipsoid.cartographicToCartesian(extent.getNortheast());
        tile.northwestCornerCartesian = ellipsoid.cartographicToCartesian(extent.getNorthwest());

        tile.westNormal = Cartesian3.UNIT_Z.cross(tile.southwestCornerCartesian.negate(scratch), scratch).normalize();
        tile.eastNormal = tile.northeastCornerCartesian.negate(scratch).cross(Cartesian3.UNIT_Z, scratch).normalize();
        tile.southNormal = ellipsoid.geodeticSurfaceNormal(tile.southeastCornerCartesian).cross(tile.southwestCornerCartesian.subtract(tile.southeastCornerCartesian, scratch)).normalize();
        tile.northNormal = ellipsoid.geodeticSurfaceNormal(tile.northwestCornerCartesian).cross(tile.northeastCornerCartesian.subtract(tile.northwestCornerCartesian, scratch)).normalize();

        tile.state = TileState.READY;
    };

    /**
     * Populates a {@link Tile} with plane-mapped surface geometry from this
     * tile provider.
     *
     * @memberof ArcGisImageServerTerrainProvider
     *
     * @param {Context} context The rendered context to use to create renderer resources.
     * @param {Tile} tile The tile to populate with surface geometry.
     * @param {Projection} projection The map projection to use.
     * @returns {Boolean|Promise} A boolean value indicating whether the tile was successfully
     * populated with geometry, or a promise for such a value in the future.
     */
    TileMapServiceTerrainProvider.prototype.createTilePlaneGeometry = function(context, tile, projection) {
        throw new DeveloperError('Not supported yet.');
    };

    /**
     * DOC_TBA
     * @memberof ArcGisImageServerTerrainProvider
     */
    TileMapServiceTerrainProvider.prototype.getLogo = function() {
        return this._logo;
    };

    return TileMapServiceTerrainProvider;
});<commit_msg>Use the correct tile size in the TMS provider.<commit_after>/*global define*/
define([
        '../Core/defaultValue',
        '../Core/jsonp',
        '../Core/loadImage',
        '../Core/getImagePixels',
        '../Core/writeTextToCanvas',
        '../Core/DeveloperError',
        '../Core/Math',
        '../Core/BoundingSphere',
        '../Core/Cartesian2',
        '../Core/Cartesian3',
        '../Core/Cartographic',
        '../Core/Extent',
        '../Core/TaskProcessor',
        './Projections',
        './TileState',
        './TerrainProvider',
        './GeographicTilingScheme',
        './WebMercatorTilingScheme',
        '../ThirdParty/when'
    ], function(
        defaultValue,
        jsonp,
        loadImage,
        getImagePixels,
        writeTextToCanvas,
        DeveloperError,
        CesiumMath,
        BoundingSphere,
        Cartesian2,
        Cartesian3,
        Cartographic,
        Extent,
        TaskProcessor,
        Projections,
        TileState,
        TerrainProvider,
        GeographicTilingScheme,
        WebMercatorTilingScheme,
        when) {
    "use strict";

    /**
     * A {@link TerrainProvider} that produces geometry by tessellating height maps
     * retrieved from a Tile Map Service (TMS) server.
     *
     * @alias TileMapServiceTerrainProvider
     * @constructor
     *
     * @param {String} description.url The URL of the TMS service.
     * @param {Object} [description.proxy] A proxy to use for requests. This object is expected to have a getURL function which returns the proxied URL, if needed.
     *
     * @see TerrainProvider
     */
    function TileMapServiceTerrainProvider(description) {
        description = defaultValue(description, {});

        if (typeof description.url === 'undefined') {
            throw new DeveloperError('description.url is required.');
        }

        /**
         * The URL of the ArcGIS ImageServer.
         * @type {String}
         */
        this.url = description.url;

        /**
         * The tiling scheme used to tile the surface.
         *
         * @type TilingScheme
         */
        this.tilingScheme = new GeographicTilingScheme({
            numberOfLevelZeroTilesX : 2,
            numberOfLevelZeroTilesY : 1
        });
        this.maxLevel = 11;
        this.heightmapWidth = 64;
        this.levelZeroMaximumGeometricError = TerrainProvider.getEstimatedLevelZeroGeometricErrorForAHeightmap(this.tilingScheme.ellipsoid, this.heightmapWidth, this.tilingScheme.numberOfLevelZeroTilesX);

        this._proxy = description.proxy;

        this.ready = true;
    }

    /**
     * Gets the maximum geometric error allowed in a tile at a given level.
     *
     * @param {Number} level The tile level for which to get the maximum geometric error.
     * @returns {Number} The maximum geometric error.
     */
    TileMapServiceTerrainProvider.prototype.getLevelMaximumGeometricError = TerrainProvider.prototype.getLevelMaximumGeometricError;

    var requestsInFlight = 0;
    // Creating the geometry will require a request to the ImageServer, which will complete
    // asynchronously.  The question is, what do we do in the meantime?  The best thing to do is
    // to use terrain associated with the parent tile.  Ideally, we would be able to render
    // high-res imagery attached to low-res terrain.  In some ways, this is similar to the need
    // described in TerrainProvider of creating geometry for tiles at a higher level than
    // the terrain source actually provides.

    // In the short term, for simplicity:
    // 1. If a tile has geometry available but it has not yet been loaded, don't render the tile until
    //    the geometry has been loaded.
    // 2. If a tile does not have geometry available at all, do not render it or its siblings.
    // Longer term, #1 may be acceptable, but #2 won't be for the reasons described above.
    // To address #2, we can subdivide a mesh into its four children.  This will be fairly CPU
    // intensive, though, which is why we probably won't want to do it while waiting for the
    // actual data to load.  We could also potentially add fractal detail when subdividing.

    /**
     * Request the tile geometry from the remote server.  Once complete, the
     * tile state should be set to RECEIVED.  Alternatively, tile state can be set to
     * UNLOADED to indicate that the request should be attempted again next update, if the tile
     * is still needed.
     *
     * @param {Tile} The tile to request geometry for.
     */
    TileMapServiceTerrainProvider.prototype.requestTileGeometry = function(tile) {
        if (requestsInFlight > 6) {
            tile.state = TileState.UNLOADED;
            return;
        }

        ++requestsInFlight;

        var yTiles = this.tilingScheme.numberOfLevelZeroTilesY << tile.level;

        var url = this.url + '/' + tile.level + '/' + tile.x + '/' + (yTiles - tile.y - 1) + '.png';

        if (typeof this._proxy !== 'undefined') {
            url = this._proxy.getURL(url);
        }

        when(loadImage(url, true), function(image) {
            tile.geometry = image;
            tile.state = TileState.RECEIVED;
            --requestsInFlight;
        }, function(e) {
            /*global console*/
            console.error('failed to load tile geometry: ' + e);
            tile.state = TileState.FAILED;
            --requestsInFlight;
        });
    };

    var taskProcessor = new TaskProcessor('createVerticesFromHeightmap');

    /**
     * Transform the tile geometry from the format requested from the remote server
     * into a format suitable for resource creation.  Once complete, the tile
     * state should be set to TRANSFORMED.  Alternatively, tile state can be set to
     * RECEIVED to indicate that the transformation should be attempted again next update, if the tile
     * is still needed.
     *
     * @param {Context} context The context to use to create resources.
     * @param {Tile} tile The tile to transform geometry for.
     */
    TileMapServiceTerrainProvider.prototype.transformGeometry = function(context, tile) {
        // Get the height data from the image by copying it to a canvas.
        var image = tile.geometry;
        var width = image.width;
        var height = image.height;
        var pixels = getImagePixels(image);

        var tilingScheme = this.tilingScheme;
        var ellipsoid = tilingScheme.ellipsoid;
        var extent = this.tilingScheme.tileXYToNativeExtent(tile.x, tile.y, tile.level);

        tile.center = ellipsoid.cartographicToCartesian(tile.extent.getCenter());

        var verticesPromise = taskProcessor.scheduleTask({
            heightmap : pixels,
            heightScale : 1000.0,
            heightOffset : 1000.0,
            bytesPerHeight : 3,
            stride : 4,
            width : width,
            height : height,
            extent : extent,
            relativeToCenter : tile.center,
            radiiSquared : ellipsoid.getRadiiSquared(),
            oneOverCentralBodySemimajorAxis : ellipsoid.getOneOverRadii().x,
            skirtHeight : Math.min(this.getLevelMaximumGeometricError(tile.level) * 10.0, 1000.0),
            isGeographic : true
        });

        if (typeof verticesPromise === 'undefined') {
            //postponed
            tile.state = TileState.RECEIVED;
            return;
        }

        when(verticesPromise, function(result) {
            console.log('Tile transformGeometry (' + tile.x + ', ' + tile.y + ', ' + tile.level + ') UDiff: ' + result.statistics.maxUDifference + ' VDiff: ' + result.statistics.maxVDifference);
            tile.geometry = undefined;
            tile.transformedGeometry = {
                vertices : result.vertices,
                statistics : result.statistics,
                indices : TerrainProvider.getRegularGridIndices(width + 2, height + 2)
            };
            tile.state = TileState.TRANSFORMED;
        }, function(e) {
            /*global console*/
            console.error('failed to transform geometry: ' + e);
            tile.state = TileState.FAILED;
        });
    };

    var scratch = new Cartesian3();

    /**
     * Create WebGL resources for the tile using whatever data the transformGeometry step produced.
     * Once complete, the tile state should be set to READY.  Alternatively, tile state can be set to
     * TRANSFORMED to indicate that resource creation should be attempted again next update, if the tile
     * is still needed.
     *
     * @param {Context} context The context to use to create resources.
     * @param {Tile} tile The tile to create resources for.
     */
    TileMapServiceTerrainProvider.prototype.createResources = function(context, tile) {
        var buffers = tile.transformedGeometry;
        tile.transformedGeometry = undefined;

        TerrainProvider.createTileEllipsoidGeometryFromBuffers(context, tile, buffers);
        tile.maxHeight = buffers.statistics.maxHeight;
        tile.boundingSphere3D = BoundingSphere.fromFlatArray(buffers.vertices, tile.center, 5);

        var ellipsoid = this.tilingScheme.ellipsoid;
        var extent = tile.extent;
        tile.southwestCornerCartesian = ellipsoid.cartographicToCartesian(extent.getSouthwest());
        tile.southeastCornerCartesian = ellipsoid.cartographicToCartesian(extent.getSoutheast());
        tile.northeastCornerCartesian = ellipsoid.cartographicToCartesian(extent.getNortheast());
        tile.northwestCornerCartesian = ellipsoid.cartographicToCartesian(extent.getNorthwest());

        tile.westNormal = Cartesian3.UNIT_Z.cross(tile.southwestCornerCartesian.negate(scratch), scratch).normalize();
        tile.eastNormal = tile.northeastCornerCartesian.negate(scratch).cross(Cartesian3.UNIT_Z, scratch).normalize();
        tile.southNormal = ellipsoid.geodeticSurfaceNormal(tile.southeastCornerCartesian).cross(tile.southwestCornerCartesian.subtract(tile.southeastCornerCartesian, scratch)).normalize();
        tile.northNormal = ellipsoid.geodeticSurfaceNormal(tile.northwestCornerCartesian).cross(tile.northeastCornerCartesian.subtract(tile.northwestCornerCartesian, scratch)).normalize();

        tile.state = TileState.READY;
    };

    /**
     * Populates a {@link Tile} with plane-mapped surface geometry from this
     * tile provider.
     *
     * @memberof ArcGisImageServerTerrainProvider
     *
     * @param {Context} context The rendered context to use to create renderer resources.
     * @param {Tile} tile The tile to populate with surface geometry.
     * @param {Projection} projection The map projection to use.
     * @returns {Boolean|Promise} A boolean value indicating whether the tile was successfully
     * populated with geometry, or a promise for such a value in the future.
     */
    TileMapServiceTerrainProvider.prototype.createTilePlaneGeometry = function(context, tile, projection) {
        throw new DeveloperError('Not supported yet.');
    };

    /**
     * DOC_TBA
     * @memberof ArcGisImageServerTerrainProvider
     */
    TileMapServiceTerrainProvider.prototype.getLogo = function() {
        return this._logo;
    };

    return TileMapServiceTerrainProvider;
});<|endoftext|>