<commit_before>i18n.en = {
  root: {
    fullName: 'English',
    ok: 'OK',
    main: {
      legend: 'Legend',
      diagram: 'Diagram',
      mapView: 'Map view',
      favoriteView: 'Favorites',
      settings: 'Settings',
      stationSelection: 'Select a station',
      chartView: 'Chart view',
      allPhenomena: 'All Phenomena',
      phenomenon: 'Phenomenon',
      favoritesList: 'Favorites',
      importFavorites: 'Import',
      exportFavorites: 'Export',
      importExportHelp: 'To import a file, please choose a file you exported before.',
      noFileSelected: 'No file selected'
    },
    chart: {
      noTimeseriesSelected: 'You have selected no timeseries, the selected timeseries have no values in the given time range or the timeseries are hidden.',
      outsideOfDataRange: 'Outside of data range!',
      annotation: 'Data without warranty!',
      monthNames: {
        0: 'Jan',
        1: 'Feb',
        2: 'Mar',
        3: 'Apr',
        4: 'May',
        5: 'Jun',
        6: 'Jul',
        7: 'Aug',
        8: 'Sep',
        9: 'Oct',
        10: 'Nov',
        11: 'Dec'
      }
    },
    table: {
      time: 'Time'
    },
    map: {
      userLocation: 'Here is your current location',
      stationSelection: {
        station: 'Station',
        selectAllTimeseries: 'select all timeseries'
      },
      stationLocation: {
        station: 'Station',
        timeseries: 'Timeseries',
        provider: 'Provider',
        jumpBackToChart: 'back to chart'
      },
      providerList: {
        provider: 'Provider',
        stations: 'Stations',
        timeseries: 'Timeseries',
        phenomena: 'Phenomena'
      },
      search: {
        label: 'search for address ...',
        noResult: 'Sorry, that address could not be found.'
      }
    },
    listSelection: {
      header: 'Select timeseries by list',
      headers: {
        category: 'Category',
        station: 'Station',
        phenomenon: 'Phenomenon',
        procedure: 'Sensor'
      },
      warning: {
        moreThanOneTimeseries: 'found more than one timeseries'
      }
    },
    legend: {
      entry: {
        noData: 'no Data available',
        jumpToLastValue: 'jump to last value',
        firstValueAt: 'First value at',
        lastValueAt: 'Last value at'
      }
    },
    export: {
      label: 'Data as CSV (Zip Archive)'
    },
    timeSelection: {
      header: 'Time Range',
      presetsHeader: 'presets',
      presets: {
        lastHour: 'last hour',
        today: 'today',
        yesterday: 'yesterday',
        todayYesterday: 'today & yesterday',
        thisWeek: 'this week',
        lastWeek: 'last week',
        thisMonth: 'this month',
        lastMonth: 'last month',
        thisYear: 'this year',
        lastYear: 'last year'
      },
      custom: {
        header: 'custom',
        start: 'Start date',
        end: 'End date'
      },
      warning: {
        startBeforeEnd: 'The start date can not be greater then the end date',
        maxTimeRange: 'The time range can not be greater then one year'
      }
    },
    styleChange: {
      header: 'Change style',
      currentColor: 'Current color',
      selectColor: 'Select a new color',
      selectBarInterval: 'Select the bar interval',
      barChartInterval: {
        hour: 'Hour',
        day: 'Day',
        week: 'Week',
        month: 'Month'
      },
      zeroScaled: 'zero scaled Y-axis',
      groupedAxis: 'grouped axis'
    },
    settings: {
      header: 'Settings',
      chooseLanguage: 'Switch language',
      requiresRestart: 'Needs Restart!',
      permalink: {
        create: 'Create a permalink as',
        inWindow: 'link in a new window',
        inMail: 'link in an email',
        inClipboard: 'Link to clipboard',
        clipboardInfo: 'Copy to clipboard:',
        inQrCode: 'as QR-Code',
        favorite: 'Save working environment as favorite entry'
      },
      clusterMarker: 'cluster marker',
      markerWithLastInfo: {
        header: 'marker with last value information',
        label: 'attention - some data provider are very slow'
      },
      saveStatus: {
        header: 'Save environment',
        label: 'All timeseries, the selected timespan and the settings are saved continuous.'
      },
      resetStatus: 'Reset environment',
      generalizeData: 'generalize Data',
      imprint: {
        header: 'Imprint',
        github: 'Find this project at GitHub',
        text: '
52°North GmbH is responsible for this website.

52°North Initiative for Geospatial Open Source Software GmbH
Martin-Luther-King-Weg 24
48155 Muenster, Germany
'
      }
    },
    permalink: {
      noMatchingTimeseriesFound: 'No matching timeseries is found.'
    },
    guide: {
      start: {
        request: 'When you start this guide, the the current state will be reset.'
      },
      step1: {
        header: 'JavaScript Client - Guided Tour',
        text: 'This tour gives in a few steps an overview how to use this client. First we add a timeseries from the map.'
      },
      step2: {
        header: 'Go to the map',
        text: 'Here we switch the view to get a map.'
      },
      step3: {
        header: 'Map view',
        text: 'This is the map view. In the map you can see markers or markergroups.'
      },
      step4: {
        header: 'Change Provider',
        text: 'Here you can select another timeseries provider.'
      },
      step5: {
        header: 'Show location',
        text: 'And here you can locate your device on the map.'
      },
      step6: {
        header: 'List selection',
        text: 'Here you can select a timeseries out of ordered lists.'
      },
      step7: {
        header: 'Select a station',
        text: 'Please select now a station on the map.'
      },
      step8: {
        header: 'Select timeseries',
        text: 'Select this checkbox. If there is only one timeseries for this station, the checkbox is already checked. Now you can go on with the "OK" button to load the timeseries.'
      },
      step9: {
        header: 'Legend entry',
        text: 'Here you see the added time series. You can delete or locate the time series or change the color.'
      },
      step10: {
        header: 'Chart',
        text: 'This is the chart of the selected time series.'
      },
      step11: {
        header: 'Change time',
        text: 'Here you can change the time extent for your selected time series.'
      },
      step12: {
        header: 'Table View',
        text: 'Here you get a table of the raw data values to your selected time series.'
      },
      step13: {
        header: 'Favorite management',
        text: 'The legend entries/timeseries could be saved as favorites. In this view all favorites are listed and could be maintained.'
      },
      step14: {
        header: 'Finished',
        text: 'Well done!
 This client is a product of 52°North GmbH. You can find the source code on GitHub.'
      }
    },
    favorite: {
      firstValueAt: 'First value at',
      lastValueAt: 'Last value at',
      label: 'favorite',
      edit: {
        header: 'Edit favorite'
      },
      group: {
        add: 'The status '{0}' is added to the favorite list.',
        exists: 'This status still exists.',
        noTimeseries: 'Currently no timeseries are selected.',
        notSupported: 'The provider of an entry of the status '{0}' isn't supported and can't be loaded.'
      },
      single: {
        add: 'A new favorite '{0}' is added to the list.',
        remove: 'The favorite '{0}' is removed.',
        exists: 'This favorite still exists.',
        notSupported: 'The provider of the favorite '{0}' isn't supported and can't be loaded.'
      },
      import: {
        override: 'Do you want to override your current favorites?',
        wrongFile: 'Could not read the file',
        noValidJson: 'The JSON file is not valid!',
        header: 'Import favorites',
        text: 'Here you can import your exported favorites. Just paste the JSON in this text field:'
      },
      export: {
        header: 'Export favorites',
        text: 'Here you can export your favorites. Just copy the JSON out of this textbox and save it in a file to import it later:'
      },
      error: {
        fileApiNotSupported: 'The File APIs are not fully supported in this browser.'
      }
    },
    inform: {
      error: 'An error occured: ',
      warn: 'Please remember that: '
    }
  },
  de: true,
  bg: true,
  cs: true,
  da: true,
  el: true,
  es: true,
  et: true,
  fi: true,
  fr: true,
  ga: true,
  hr: true,
  hu: true,
  it: true,
  lt: true,
  lv: true,
  mt: true,
  nl: true,
  pl: true,
  pt: true,
  ro: true,
  sk: true,
  sl: true,
  sv: true
};
<commit_msg>fixed en.js file<commit_after>i18n.en = {
  fullName: 'English',
  ok: 'OK',
  main: {
    legend: 'Legend',
    diagram: 'Diagram',
    mapView: 'Map view',
    favoriteView: 'Favorites',
    settings: 'Settings',
    stationSelection: 'Select a station',
    chartView: 'Chart view',
    allPhenomena: 'All Phenomena',
    phenomenon: 'Phenomenon',
    favoritesList: 'Favorites',
    importFavorites: 'Import',
    exportFavorites: 'Export',
    importExportHelp: 'To import a file, please choose a file you exported before.',
    noFileSelected: 'No file selected'
  },
  chart: {
    noTimeseriesSelected: 'You have selected no timeseries, the selected timeseries have no values in the given time range or the timeseries are hidden.',
    outsideOfDataRange: 'Outside of data range!',
    annotation: 'Data without warranty!',
    monthNames: {
      0: 'Jan',
      1: 'Feb',
      2: 'Mar',
      3: 'Apr',
      4: 'May',
      5: 'Jun',
      6: 'Jul',
      7: 'Aug',
      8: 'Sep',
      9: 'Oct',
      10: 'Nov',
      11: 'Dec'
    }
  },
  table: {
    time: 'Time'
  },
  map: {
    userLocation: 'Here is your current location',
    stationSelection: {
      station: 'Station',
      selectAllTimeseries: 'select all timeseries'
    },
    stationLocation: {
      station: 'Station',
      timeseries: 'Timeseries',
      provider: 'Provider',
      jumpBackToChart: 'back to chart'
    },
    providerList: {
      provider: 'Provider',
      stations: 'Stations',
      timeseries: 'Timeseries',
      phenomena: 'Phenomena'
    },
    search: {
      label: 'search for address ...',
      noResult: 'Sorry, that address could not be found.'
    }
  },
  listSelection: {
    header: 'Select timeseries by list',
    headers: {
      category: 'Category',
      station: 'Station',
      phenomenon: 'Phenomenon',
      procedure: 'Sensor'
    },
    warning: {
      moreThanOneTimeseries: 'found more than one timeseries'
    }
  },
  legend: {
    entry: {
      noData: 'no Data available',
      jumpToLastValue: 'jump to last value',
      firstValueAt: 'First value at',
      lastValueAt: 'Last value at'
    }
  },
  export: {
    label: 'Data as CSV (Zip Archive)'
  },
  timeSelection: {
    header: 'Time Range',
    presetsHeader: 'presets',
    presets: {
      lastHour: 'last hour',
      today: 'today',
      yesterday: 'yesterday',
      todayYesterday: 'today & yesterday',
      thisWeek: 'this week',
      lastWeek: 'last week',
      thisMonth: 'this month',
      lastMonth: 'last month',
      thisYear: 'this year',
      lastYear: 'last year'
    },
    custom: {
      header: 'custom',
      start: 'Start date',
      end: 'End date'
    },
    warning: {
      startBeforeEnd: 'The start date can not be greater then the end date',
      maxTimeRange: 'The time range can not be greater then one year'
    }
  },
  styleChange: {
    header: 'Change style',
    currentColor: 'Current color',
    selectColor: 'Select a new color',
    selectBarInterval: 'Select the bar interval',
    barChartInterval: {
      hour: 'Hour',
      day: 'Day',
      week: 'Week',
      month: 'Month'
    },
    zeroScaled: 'zero scaled Y-axis',
    groupedAxis: 'grouped axis'
  },
  settings: {
    header: 'Settings',
    chooseLanguage: 'Switch language',
    requiresRestart: 'Needs Restart!',
    permalink: {
      create: 'Create a permalink as',
      inWindow: 'link in a new window',
      inMail: 'link in an email',
      inClipboard: 'Link to clipboard',
      clipboardInfo: 'Copy to clipboard:',
      inQrCode: 'as QR-Code',
      favorite: 'Save working environment as favorite entry'
    },
    clusterMarker: 'cluster marker',
    markerWithLastInfo: {
      header: 'marker with last value information',
      label: 'attention - some data provider are very slow'
    },
    saveStatus: {
      header: 'Save environment',
      label: 'All timeseries, the selected timespan and the settings are saved continuous.'
    },
    resetStatus: 'Reset environment',
    generalizeData: 'generalize Data',
    imprint: {
      header: 'Imprint',
      github: 'Find this project at GitHub',
      text: '
52°North GmbH is responsible for this website.

52°North Initiative for Geospatial Open Source Software GmbH
Martin-Luther-King-Weg 24
48155 Muenster, Germany
'
    }
  },
  permalink: {
    noMatchingTimeseriesFound: 'No matching timeseries is found.'
  },
  guide: {
    start: {
      request: 'When you start this guide, the the current state will be reset.'
    },
    step1: {
      header: 'JavaScript Client - Guided Tour',
      text: 'This tour gives in a few steps an overview how to use this client. First we add a timeseries from the map.'
    },
    step2: {
      header: 'Go to the map',
      text: 'Here we switch the view to get a map.'
    },
    step3: {
      header: 'Map view',
      text: 'This is the map view. In the map you can see markers or markergroups.'
    },
    step4: {
      header: 'Change Provider',
      text: 'Here you can select another timeseries provider.'
    },
    step5: {
      header: 'Show location',
      text: 'And here you can locate your device on the map.'
    },
    step6: {
      header: 'List selection',
      text: 'Here you can select a timeseries out of ordered lists.'
    },
    step7: {
      header: 'Select a station',
      text: 'Please select now a station on the map.'
    },
    step8: {
      header: 'Select timeseries',
      text: 'Select this checkbox. If there is only one timeseries for this station, the checkbox is already checked. Now you can go on with the "OK" button to load the timeseries.'
    },
    step9: {
      header: 'Legend entry',
      text: 'Here you see the added time series. You can delete or locate the time series or change the color.'
    },
    step10: {
      header: 'Chart',
      text: 'This is the chart of the selected time series.'
    },
    step11: {
      header: 'Change time',
      text: 'Here you can change the time extent for your selected time series.'
    },
    step12: {
      header: 'Table View',
      text: 'Here you get a table of the raw data values to your selected time series.'
    },
    step13: {
      header: 'Favorite management',
      text: 'The legend entries/timeseries could be saved as favorites. In this view all favorites are listed and could be maintained.'
    },
    step14: {
      header: 'Finished',
      text: 'Well done!
 This client is a product of 52°North GmbH. You can find the source code on GitHub.'
    }
  },
  favorite: {
    firstValueAt: 'First value at',
    lastValueAt: 'Last value at',
    label: 'favorite',
    edit: {
      header: 'Edit favorite'
    },
    group: {
      add: 'The status '{0}' is added to the favorite list.',
      exists: 'This status still exists.',
      noTimeseries: 'Currently no timeseries are selected.',
      notSupported: 'The provider of an entry of the status '{0}' isn't supported and can't be loaded.'
    },
    single: {
      add: 'A new favorite '{0}' is added to the list.',
      remove: 'The favorite '{0}' is removed.',
      exists: 'This favorite still exists.',
      notSupported: 'The provider of the favorite '{0}' isn't supported and can't be loaded.'
    },
    import: {
      override: 'Do you want to override your current favorites?',
      wrongFile: 'Could not read the file',
      noValidJson: 'The JSON file is not valid!',
      header: 'Import favorites',
      text: 'Here you can import your exported favorites. Just paste the JSON in this text field:'
    },
    export: {
      header: 'Export favorites',
      text: 'Here you can export your favorites. Just copy the JSON out of this textbox and save it in a file to import it later:'
    },
    error: {
      fileApiNotSupported: 'The File APIs are not fully supported in this browser.'
    }
  },
  inform: {
    error: 'An error occured: ',
    warn: 'Please remember that: '
  }
};
<|endoftext|>


<commit_before>define(['backbone', 'models/event/event'], function(Backbone, Marionette, Event) {
    return Backbone.Collection.extend({
        model: Event
    });
});
<commit_msg>Fixes busted imports (no longer import Marionette)<commit_after>define(['backbone', 'models/event/event'], function(Backbone, Event) {
    return Backbone.Collection.extend({
        model: Event
    });
});
<|endoftext|>


<commit_before>import chalk from 'chalk';
import table from 'table';
import _ from 'lodash';
import pluralize from 'pluralize';

let drawReport,
    drawTable;

/**
 * @param {Array} results
 * @returns {string}
 */
drawReport = (results) => {
    let files;

    files = _.map(results, (result) => {
        if (!result.messages.length) {
            return '';
        }

        return '\n' + result.filePath + '\n\n' + drawTable(result.messages);
    });

    files = _.filter(files);

    return files.join('\n');
};

/**
 * @param {Array} messages
 * @returns {string}
 */
drawTable = (messages) => {
    let rows;

    rows = [];

    if (messages.length === 0) {
        return '';
    }

    rows.push([
        chalk.bold('Line'),
        chalk.bold('Column'),
        chalk.bold('Type'),
        chalk.bold('Message'),
        chalk.bold('Rule ID')
    ]);

    _.forEach(messages, (message) => {
        let messageType;

        if (message.fatal || message.severity === 2) {
            messageType = chalk.red('error');
        } else {
            messageType = chalk.yellow('warning');
        }

        rows.push([
            message.line || 0,
            message.column || 0,
            messageType,
            message.message.replace(/\.$/, ''),
            message.ruleId || ''
        ]);
    });

    return table(rows, {
        columns: {
            0: {
                width: 8,
                wrapWord: true
            },
            1: {
                width: 8,
                wrapWord: true
            },
            2: {
                width: 8,
                wrapWord: true
            },
            3: {
                width: 50,
                paddingRight: 5,
                wrapWord: true
            },
            4: {
                width: 20,
                wrapWord: true
            }
        },
        drawHorizontalLine: (index) => {
            return true;
        }
    });
};

/**
 * @typedef {Object} report
 * @property {number} errorCount
 * @property {number} warningCount
 * @property {Object[]} results
 */

/**
 * @param {report} report
 * @returns {string}
 */
export default (report) => {
    let result;

    result = '';

    if (report.errorCount || report.warningCount) {
        result = drawReport(report.results);
    }

    result += '\n' + table([
        [
            chalk.red(pluralize('Error', report.errorCount, true))
        ],
        [
            chalk.yellow(pluralize('Warning', report.warningCount, true))
        ]
    ], {
        columns: {
            0: {
                width: 110,
                wrapWord: true
            }
        },
        drawHorizontalLine: (index) => {
            return true;
        }
    });

    return result;
};
<commit_msg>There must be no row borders. Makes the output too verbose.<commit_after>import chalk from 'chalk';
import table from 'table';
import _ from 'lodash';
import pluralize from 'pluralize';

let drawReport,
    drawTable;

/**
 * @param {Array} results
 * @returns {string}
 */
drawReport = (results) => {
    let files;

    files = _.map(results, (result) => {
        if (!result.messages.length) {
            return '';
        }

        return '\n' + result.filePath + '\n\n' + drawTable(result.messages);
    });

    files = _.filter(files);

    return files.join('\n');
};

/**
 * @param {Array} messages
 * @returns {string}
 */
drawTable = (messages) => {
    let rows;

    rows = [];

    if (messages.length === 0) {
        return '';
    }

    rows.push([
        chalk.bold('Line'),
        chalk.bold('Column'),
        chalk.bold('Type'),
        chalk.bold('Message'),
        chalk.bold('Rule ID')
    ]);

    _.forEach(messages, (message) => {
        let messageType;

        if (message.fatal || message.severity === 2) {
            messageType = chalk.red('error');
        } else {
            messageType = chalk.yellow('warning');
        }

        rows.push([
            message.line || 0,
            message.column || 0,
            messageType,
            message.message.replace(/\.$/, ''),
            message.ruleId || ''
        ]);
    });

    return table(rows, {
        columns: {
            0: {
                width: 8,
                wrapWord: true
            },
            1: {
                width: 8,
                wrapWord: true
            },
            2: {
                width: 8,
                wrapWord: true
            },
            3: {
                width: 50,
                paddingRight: 5,
                wrapWord: true
            },
            4: {
                width: 20,
                wrapWord: true
            }
        },
        drawHorizontalLine: (index) => {
            return index === 1;
        }
    });
};

/**
 * @typedef {Object} report
 * @property {number} errorCount
 * @property {number} warningCount
 * @property {Object[]} results
 */

/**
 * @param {report} report
 * @returns {string}
 */
export default (report) => {
    let result;

    result = '';

    if (report.errorCount || report.warningCount) {
        result = drawReport(report.results);
    }

    result += '\n' + table([
        [
            chalk.red(pluralize('Error', report.errorCount, true))
        ],
        [
            chalk.yellow(pluralize('Warning', report.warningCount, true))
        ]
    ], {
        columns: {
            0: {
                width: 110,
                wrapWord: true
            }
        },
        drawHorizontalLine: (index) => {
            return true;
        }
    });

    return result;
};
<|endoftext|>


<commit_before>var store = {
    "Castle Creek": {
        name: "Castle Creek",
        description: "A sample ST-Sim library developed for a semi-arid shrub-steppe ecosystem in southwest Idaho (Castle Creek).",
        author: "Michael S. O'Donnell",
        date: "2015",
        extent: {
            "type": "Feature",
            "geometry": {
                "type": "Polygon",
                "coordinates": [[
                [-116.60960551441471, 42.7996938297675],
                [-116.27533823026967, 42.7996938297675],
                [-116.27533823026967, 42.55790050289854],
                [-116.60960551441471, 42.55790050289854]
                ]]
            }
        },
        zoom: 11,
        require_reporting_unit: false,
        default_region: '',
        management_actions_filter: {
            "Thin-Mech-Chem": "Thin-Mech-Chem",
            "SENN-Maintenance": "SENN-Maintenance",
            "Restoration Tree Encroached L": "Restoration Tree Encroached L",
            "Restoration Tree Encroached H": "Restoration Tree Encroached H",
            "Restoration Depleted Sage L": "Restoration Depleted Sage L",
            "Restoration Depleted Sage H": "Restoration Depleted Sage H",
            "Restoration Depleted Sage": "Restoration Depeleted Sage",
            "Restoration Annual Grass L": "Restoration Annual Grass L",
            "Restoration Annual Grass H": "Restoration Annual Grass H",
            "Restoration Annual Grass": "Restoration Annual Grass",
            "Reference Restoration L": "Reference Restoration L",
            "Reference Restoration H": "Referenc Restoration H",
            "CWG-Seed": "CWG-Seed",
            "CWG-Restoration": "CWG-Restoration",
            "Replacement Fire": "Prescribed Fire"
        },
        stratum_service: null,
        stateclass_service: null,
        timesteps: 'Years'
    },
    "LANDFIRE": {
        name: "LANDFIRE",
        description: "LANDFIRE BpS Models",
        author: "LANDFIRE",
        date: "[object]",
        extent: null,
        zoom: 10,
        require_reporting_unit: true,
        default_region: 'Watersheds',
        management_actions_filter: {},
        stratum_service: {
            url: 'http://landfire.cr.usgs.gov/arcgis/services/Landfire/US_130/MapServer/WMSServer?',
            layers: "US_130BPS",
            wms: true
        },
        stateclass_service: {
            url: 'http://landfire.cr.usgs.gov/arcgis/services/Landfire/US_130/MapServer/WMSServer?',
            layers: "US_130SCLASS",
            wms: true
        },
        timesteps: 'Years'
    }
};

var downloadCsvURL = '/api/download-csv/';
var requestPDFDataURL = '/api/request-pdf/';
var requestSpatialDataURL = '/api/request-spatial-data/';

// Available ST-Sim reports to be downloaded.
var availableReports = {

    // PDF report
    'overview': {
        'label': 'Overview',
        'ext': '.pdf',
        'url': requestPDFDataURL
    },

    // Spatial data download
    'spatial-data': {
        'label': 'Spatial Data',
        'ext': '.zip',
        'url': requestSpatialDataURL
    },

    // CSV reports
    'stateclass-summary' : {
        'label': 'Stateclass',
        'ext': '.csv',
        'url': downloadCsvURL
    },
    'transition-summary' : {
        'label': 'Transitions',
        'ext': '.csv',
        'url': downloadCsvURL
    },
    'transition-stateclass-summary' : {
        'label': 'Transitions by Stateclass',
        'ext': '.csv',
        'url': downloadCsvURL
    }
};
<commit_msg>Added more options to UI config.<commit_after>var store = {
    "Castle Creek": {
        name: "Castle Creek",
        description: "A sample ST-Sim library developed for a semi-arid shrub-steppe ecosystem in southwest Idaho (Castle Creek).",
        author: "Michael S. O'Donnell",
        date: "2015",
        extent: {
            "type": "Feature",
            "geometry": {
                "type": "Polygon",
                "coordinates": [[
                [-116.60960551441471, 42.7996938297675],
                [-116.27533823026967, 42.7996938297675],
                [-116.27533823026967, 42.55790050289854],
                [-116.60960551441471, 42.55790050289854]
                ]]
            }
        },
        zoom: 11,
        enable3D: true,
        spatial: true,
        require_reporting_unit: false,
        default_region: '',
        management_actions_filter: {
            "Thin-Mech-Chem": "Thin-Mech-Chem",
            "SENN-Maintenance": "SENN-Maintenance",
            "Restoration Tree Encroached L": "Restoration Tree Encroached L",
            "Restoration Tree Encroached H": "Restoration Tree Encroached H",
            "Restoration Depleted Sage L": "Restoration Depleted Sage L",
            "Restoration Depleted Sage H": "Restoration Depleted Sage H",
            "Restoration Depleted Sage": "Restoration Depeleted Sage",
            "Restoration Annual Grass L": "Restoration Annual Grass L",
            "Restoration Annual Grass H": "Restoration Annual Grass H",
            "Restoration Annual Grass": "Restoration Annual Grass",
            "Reference Restoration L": "Reference Restoration L",
            "Reference Restoration H": "Referenc Restoration H",
            "CWG-Seed": "CWG-Seed",
            "CWG-Restoration": "CWG-Restoration",
            "Replacement Fire": "Prescribed Fire"
        },
        stratum_service: null,
        stateclass_service: null,
        timesteps: 'Years'
    },
    "LANDFIRE": {
        name: "LANDFIRE",
        description: "Biophysical Settings Quantitative Models",
        author: "USGS",
        date: "2014",
        extent: null,
        zoom: 10,
        enable3D: false,
        spatial: false,
        require_reporting_unit: true,
        default_region: 'Watersheds',
        management_actions_filter: {},
        stratum_service: {
            url: 'http://landfire.cr.usgs.gov/arcgis/services/Landfire/US_130/MapServer/WMSServer?',
            layers: "US_130BPS",
            wms: true
        },
        stateclass_service: {
            url: 'http://landfire.cr.usgs.gov/arcgis/services/Landfire/US_130/MapServer/WMSServer?',
            layers: "US_130SCLASS",
            wms: true
        },
        timesteps: 'Years'
    }
};

var downloadCsvURL = '/api/download-csv/';
var requestPDFDataURL = '/api/request-pdf/';
var requestSpatialDataURL = '/api/request-spatial-data/';

// Available ST-Sim reports to be downloaded.
var availableReports = {

    // PDF report
    'overview': {
        'label': 'Overview',
        'ext': '.pdf',
        'url': requestPDFDataURL
    },

    // Spatial data download
    'spatial-data': {
        'label': 'Spatial Data',
        'ext': '.zip',
        'url': requestSpatialDataURL
    },

    // CSV reports
    'stateclass-summary' : {
        'label': 'Stateclass',
        'ext': '.csv',
        'url': downloadCsvURL
    },
    'transition-summary' : {
        'label': 'Transitions',
        'ext': '.csv',
        'url': downloadCsvURL
    },
    'transition-stateclass-summary' : {
        'label': 'Transitions by Stateclass',
        'ext': '.csv',
        'url': downloadCsvURL
    }
};
<|endoftext|>


<commit_before><commit_msg>Update ogario.v4.js<commit_after><|endoftext|>


<commit_before><commit_msg>Improve error message<commit_after><|endoftext|>


<commit_before>/* Copyright (c) 2012 Pierre Urban - www.qualiptive.com
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 * ##################
 * PLUGIN INFORMATION
 * ##################
 * Name: Adaptive Modal
 * Description: Adaptive Modal is a jQuery plugin to display multiple modal windows
 * Author: Pierre Urban
 * Licence: MIT (http://www.opensource.org/licenses/mit-license.php)
 * Version: 0.0.1
 * More: based from http://docs.jquery.com/Plugins/Authoring
 */

;(function ($) {

  var pluginName = 'adaptiveModal';

  var methods = {
    init : function (options) {

      // Extend default settings with options parameter
      var settings = $.extend({
            name : 'adaptive-modal',
            duration : 150,
            opacity: 0.8
          }, options),
          overlay = $('

'),
          modal = $('

');

      // Append the overlay, set its opacity, hide it, bind to it a click event to close the modal
      $('body').append(
        overlay.css('opacity', settings.opacity)
          .hide()
          .click(function (e) {
            closeModal(modal, overlay, settings);
          })
      );
      // Append the modal and hide it
      $('body').append(
        modal.hide()
      );

      // Return 'this' for chaining
      return this.each(function () {

        var $this = $(this),
            data = $this.data(pluginName);

        // If the plugin hasn't been initialized yet it creates the data
        if (!data) {
          data = $this.data(pluginName, {
            settings : settings,
            overlay : overlay,
            modal : modal
          });
        };
        data = $this.data(pluginName);

        // Bind a click event
        $this.bind('click.' + pluginName, function (e) {
          e.preventDefault();

          // Display overlay
          overlay.fadeIn(150);

          // Insert the corresponding content and display modal: 1) retrieve the modal content div
          var modal_content = modal.find('#' + settings.name + '-content');
          // Empty modal content div
          modal_content.empty();
          // Move the concerned element inside the modal content div
          $('.' + settings.name + '[data-' + settings.name  + '-id="' + $(this).attr('data-' + settings.name + '-id') + '"]').removeClass(settings.name).appendTo(modal_content);
          modal.fadeIn(150);
          $('.' + settings.name + '-close').click(function (e) {
            e.preventDefault();
            closeModal(modal, overlay, settings);
          });
        });

        // Events management sample:
        $(document).bind('keydown.' + pluginName, { pluginData : data }, keydownManagement);
      });
    },
    destroy : function () {
      return this.each(function (){

        var $this = $(this),
            data = $this.data(pluginName);

        $this.removeData(pluginName);

        $(window).unbind('.' + pluginName);
      })
    }
  };

  var keydownManagement = function (e) {
    // Escape key
    if (e.keyCode == 27) {
      closeModal(e.data.pluginData.modal, e.data.pluginData.overlay, e.data.pluginData.settings);
    };
  },
  closeModal = function (modal, overlay, settings) {
    var modalTmp = modal.find('[data-' + settings.name  + '-id]').addClass(settings.name);

    modal.fadeOut(settings.duration);
    overlay.fadeOut(settings.duration);

    $('[data-' + settings.name  + '-id="' + modalTmp.attr('data-' + settings.name + '-id') + '"]').not(modalTmp).after(modalTmp);
  };

  $.fn[pluginName] = function(method) {
    if (methods[method]) {
      return methods[method].apply(this, Array.prototype.slice.call( arguments, 1));
    } else if (typeof method === 'object' || ! method) {
      return methods.init.apply( this, arguments );
    } else {
      $.error('Method ' +  method + ' does not exist on jQuery.' + pluginName);
    }
  };
})(jQuery);
<commit_msg>Add a scroll effect to the top. Hide the modal's content at the end of the animation.<commit_after>/* Copyright (c) 2012 Pierre Urban - www.qualiptive.com
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 * ##################
 * PLUGIN INFORMATION
 * ##################
 * Name: Adaptive Modal
 * Description: Adaptive Modal is a jQuery plugin to display multiple modal windows
 * Author: Pierre Urban
 * Licence: MIT (http://www.opensource.org/licenses/mit-license.php)
 * Version: 0.0.1
 * More: based from http://docs.jquery.com/Plugins/Authoring
 */

;(function ($) {

  var pluginName = 'adaptiveModal';

  var methods = {
    init : function (options) {

      // Extend default settings with options parameter
      var settings = $.extend({
            name : 'adaptive-modal',
            duration : 150,
            opacity: 0.8
          }, options),
          overlay = $('

'),
          modal = $('

');

      // Append the overlay, set its opacity, hide it, bind to it a click event to close the modal
      $('body').append(
        overlay.css('opacity', settings.opacity)
          .hide()
          .click(function (e) {
            closeModal(modal, overlay, settings);
          })
      );
      // Append the modal and hide it
      $('body').append(
        modal.hide()
      );

      // Return 'this' for chaining
      return this.each(function () {

        var $this = $(this),
            data = $this.data(pluginName);

        // If the plugin hasn't been initialized yet it creates the data
        if (!data) {
          data = $this.data(pluginName, {
            settings : settings,
            overlay : overlay,
            modal : modal
          });
        };
        data = $this.data(pluginName);

        // Bind a click event
        $this.bind('click.' + pluginName, function (e) {
          e.preventDefault();

          // Display overlay
          overlay.fadeIn(150);

          // Insert the corresponding content and display modal: 1) retrieve the modal content div
          var modal_content = modal.find('#' + settings.name + '-content');
          // Empty modal content div
          modal_content.empty();
          // Move the concerned element inside the modal content div
          $('.' + settings.name + '[data-' + settings.name  + '-id="' + $(this).attr('data-' + settings.name + '-id') + '"]').removeClass(settings.name).appendTo(modal_content);
          modal.fadeIn(150);
          $('html, body').animate({scrollTop:0}, 'slow');
          $('.' + settings.name + '-close').click(function (e) {
            e.preventDefault();
            closeModal(modal, overlay, settings);
          });
        });

        // Events management sample:
        $(document).bind('keydown.' + pluginName, { pluginData : data }, keydownManagement);
      });
    },
    destroy : function () {
      return this.each(function (){

        var $this = $(this),
            data = $this.data(pluginName);

        $this.removeData(pluginName);

        $(window).unbind('.' + pluginName);
      })
    }
  };

  var keydownManagement = function (e) {
    // Escape key
    if (e.keyCode == 27) {
      closeModal(e.data.pluginData.modal, e.data.pluginData.overlay, e.data.pluginData.settings);
    };
  },
  closeModal = function (modal, overlay, settings) {
    var modalTmp = modal.find('[data-' + settings.name  + '-id]');

    modal.fadeOut(settings.duration, function () {
      modalTmp.addClass(settings.name);
      $('[data-' + settings.name  + '-id="' + modalTmp.attr('data-' + settings.name + '-id') + '"]').not(modalTmp).after(modalTmp);
    });
    overlay.fadeOut(settings.duration);
  };

  $.fn[pluginName] = function(method) {
    if (methods[method]) {
      return methods[method].apply(this, Array.prototype.slice.call( arguments, 1));
    } else if (typeof method === 'object' || ! method) {
      return methods.init.apply( this, arguments );
    } else {
      $.error('Method ' +  method + ' does not exist on jQuery.' + pluginName);
    }
  };
})(jQuery);
<|endoftext|>


<commit_before>// * ———————————————————————————————————————————————————————— * //
// * 	render
// *	renders all the static files - no server started
// * ———————————————————————————————————————————————————————— * //

var action = function () {}

var Promise = require('bluebird')

var logger = require(enduro.enduro_path + '/libs/logger')
var juicebox = require(enduro.enduro_path + '/libs/juicebox/juicebox')
var global_data = require(enduro.enduro_path + '/libs/global_data')
var helper_handler = require(enduro.enduro_path + '/libs/helper_handler')
var components_handler = require(enduro.enduro_path + '/libs/components_handler')
var enduro_render = require(enduro.enduro_path + '/libs/enduro_render')
var gulp = require(enduro.enduro_path + '/gulpfile')
var pregenerator = require(enduro.enduro_path + '/libs/pregenerator/pregenerator')
var abstractor = require(enduro.enduro_path + '/libs/abstractor/abstractor')
var ab_tester = require(enduro.enduro_path + '/libs/ab_testing/ab_tester')
var markdownifier = require(enduro.enduro_path + '/libs/markdown/markdownifier')

action.prototype.action = function (callback, dont_do_juice_pull) {

	logger.init('Enduro', 'enduro_render_events')
	return Promise.resolve()
		.then(() => {
			if (!dont_do_juice_pull && !enduro.flags.nojuice) {
				return juicebox.pull(false)
			} else {
				return new Promise.resolve()
			}
		})
		.then(() => {
			return global_data.get_global_data()
		})
		.then(() => {
			return components_handler.read_components()
		})
		.then(() => {
			return helper_handler.read_helpers()
		})
		.then(() => {
			return abstractor.init()
		})
		.then(() => {
			return markdownifier.precompute()
		})
		.then(() => {
			return ab_tester.generate_global_ab_list()
		})
		.then(() => {
			return pregenerator.pregenerate()
		})
		.then(() => {
			return new Promise(function (resolve, reject) {
				return gulp.start('preproduction', () => {
					resolve()
				})
			})
		})
		.then(() => {
			return enduro_render.render()
		})
		.then(() => {
			return new Promise(function (resolve, reject) {
				return gulp.start('production', () => {
					resolve()
				})
			})
		})
		.then(() => {
			logger.end('enduro_render_events')
			if (callback) {
				callback()
			}
		})
}

module.exports = new action()<commit_msg>added global logging<commit_after>// * ———————————————————————————————————————————————————————— * //
// * 	render
// *	renders all the static files - no server started
// * ———————————————————————————————————————————————————————— * //

var action = function () {}

var Promise = require('bluebird')

var logger = require(enduro.enduro_path + '/libs/logger')
var juicebox = require(enduro.enduro_path + '/libs/juicebox/juicebox')
var global_data = require(enduro.enduro_path + '/libs/global_data')
var helper_handler = require(enduro.enduro_path + '/libs/helper_handler')
var components_handler = require(enduro.enduro_path + '/libs/components_handler')
var enduro_render = require(enduro.enduro_path + '/libs/enduro_render')
var gulp = require(enduro.enduro_path + '/gulpfile')
var pregenerator = require(enduro.enduro_path + '/libs/pregenerator/pregenerator')
var abstractor = require(enduro.enduro_path + '/libs/abstractor/abstractor')
var ab_tester = require(enduro.enduro_path + '/libs/ab_testing/ab_tester')
var markdownifier = require(enduro.enduro_path + '/libs/markdown/markdownifier')

action.prototype.action = function (callback, dont_do_juice_pull) {

	logger.init('Enduro', 'enduro_render_events')
	return Promise.resolve()
		.then(() => {
			if (!dont_do_juice_pull && !enduro.flags.nojuice) {
				return juicebox.pull(false)
			} else {
				return new Promise.resolve()
			}
		})
		.then(() => {
			console.log('global loading')
			return global_data.get_global_data()
		})
		.then(() => {
			return components_handler.read_components()
		})
		.then(() => {
			return helper_handler.read_helpers()
		})
		.then(() => {
			return abstractor.init()
		})
		.then(() => {
			return markdownifier.precompute()
		})
		.then(() => {
			return ab_tester.generate_global_ab_list()
		})
		.then(() => {
			return pregenerator.pregenerate()
		})
		.then(() => {
			return new Promise(function (resolve, reject) {
				return gulp.start('preproduction', () => {
					resolve()
				})
			})
		})
		.then(() => {
			return enduro_render.render()
		})
		.then(() => {
			return new Promise(function (resolve, reject) {
				return gulp.start('production', () => {
					resolve()
				})
			})
		})
		.then(() => {
			logger.end('enduro_render_events')
			if (callback) {
				callback()
			}
		})
}

module.exports = new action()<|endoftext|>


<commit_before>/**
 * @URL https://github.com/csetea/magpieJS
 * @license MIT
 */
// Based on pagejs, context extended with
//* query (object that contains the query parameteres)
//* hashPathname (analog 'pathname')
//* hashQuerystring (analog 'querystring')
//* hashQuery (object that contains the query parameteres from hash)
define([ 'magpie/log!magpie/html5/router', 'module', 'magpie/util/config', 'page','page/query', 'require', 'magpie/dom/inject','magpie/html5/customElement/_ieVersion','magpie/html5/customElement'],
		function(log, module, config, page, qs, require, inject, ieVersion) {

	/*jshint -W004 */
	var config =config(module,{
		init: function(){},
		autoStart: true,
//		mergeHashQuery: false,
//		mergeHashPath: false,
//		handlers: []
		handlers: [
		           function(ctx, next){	if (log.isTrace){log.trace('reached the last handler, ctx:',ctx);}next();}]
	});

	var router={
			start: function(callback){
				if (ieVersion == 8 || ieVersion == 9){
					// polyfill hisotry api
					//TODO configurable config?path?shim? history impl provider ....
					require([ 'lib/HTML5-History-API/history.min'],function(){
						page.start();
						if (callback instanceof Function){
							callback(router);
						}
					});

				}else{
					page.start();
					window.onhashchange = function(){
						page(window.location.hash);
					};
					if (callback instanceof Function){
						callback(router);
					}
				}
			},

			ctx:null,

			visitHashQuery: function (){
				var paramMap = this.ctx.hashQuery;
				var hash='?';
				var index= 0;
				for(p in paramMap){
					if (index>0){
						hash+='&'
					}
					if (paramMap[p]!=null && paramMap[p] !=''){
						hash+=p+'='+paramMap[p];
					}
					index++;
				}
				window.location.hash= hash;

			}
		};

	page( function(ctx, _next){
		  ctx.query = qs.parse(ctx.querystring);
		  ctx.hashQuery={};
		  ctx.hashPathname =ctx.hash.replace(/\?.*/,function(hashQuerystring){
			  ctx.hashQuerystring=hashQuerystring;
			  hashQuerystring = hashQuerystring.replace(/\?/,'');
			  ctx.hashQuery = qs.parse(hashQuerystring);
			  return '';
		  });

		  if (log.isTrace){
			  log.trace(ctx);
		  }
		  ctx.log = log;

		  router.ctx=ctx;

		  // simple lazy implementation of Express style middle ware next callback chain
		  var handlerIndex = 0;
		  var next = function (){
			  var handler = config.handlers[handlerIndex];
			  if (handler){
				  handlerIndex++;
				  if (handlerIndex == config.handlers.length){
					  // at least do not break page.js callback
					  handler(ctx, _next);
				  }else{
					  handler(ctx, next);
				  }
			  }else{
				  // at least do not break page.js callback
				  _next();
			  }
		  };
		  next();

	});

	config.init();

	if (config.autoStart){
		router.start();
	}

	return router;

});<commit_msg>makeup visitHashQuery()<commit_after>/**
 * @URL https://github.com/csetea/magpieJS
 * @license MIT
 */
// Based on pagejs, context extended with
//* query (object that contains the query parameteres)
//* hashPathname (analog 'pathname')
//* hashQuerystring (analog 'querystring')
//* hashQuery (object that contains the query parameteres from hash)
define([ 'magpie/log!magpie/html5/router', 'module', 'magpie/util/config', 'page','page/query', 'require', 'magpie/dom/inject','magpie/html5/customElement/_ieVersion','magpie/html5/customElement'],
		function(log, module, config, page, qs, require, inject, ieVersion) {

	/*jshint -W004 */
	var config =config(module,{
		init: function(){},
		autoStart: true,
//		mergeHashQuery: false,
//		mergeHashPath: false,
//		handlers: []
		handlers: [
		           function(ctx, next){	if (log.isTrace){log.trace('reached the last handler, ctx:',ctx);}next();}]
	});

	var router={
			start: function(callback){
				if (ieVersion == 8 || ieVersion == 9){
					// polyfill hisotry api
					//TODO configurable config?path?shim? history impl provider ....
					require([ 'lib/HTML5-History-API/history.min'],function(){
						page.start();
						if (callback instanceof Function){
							callback(router);
						}
					});

				}else{
					page.start();
					window.onhashchange = function(){
						page(window.location.hash);
					};
					if (callback instanceof Function){
						callback(router);
					}
				}
			},

			ctx:null,

			visitHashQuery: function (){
				var paramMap = this.ctx.hashQuery;
				var hash='?';
				var index= 0;
				for(p in paramMap){
					var ignore = paramMap[p]==null || paramMap[p] =='';
					if (!ignore){
						if (index>0){
							hash+='&'
						}
						hash+=p+'='+paramMap[p];
						index++;
					}
				}
				window.location.hash= hash;

			}
		};

	page( function(ctx, _next){
		  ctx.query = qs.parse(ctx.querystring);
		  ctx.hashQuery={};
		  ctx.hashPathname =ctx.hash.replace(/\?.*/,function(hashQuerystring){
			  ctx.hashQuerystring=hashQuerystring;
			  hashQuerystring = hashQuerystring.replace(/\?/,'');
			  ctx.hashQuery = qs.parse(hashQuerystring);
			  return '';
		  });

		  if (log.isTrace){
			  log.trace(ctx);
		  }
		  ctx.log = log;

		  router.ctx=ctx;

		  // simple lazy implementation of Express style middle ware next callback chain
		  var handlerIndex = 0;
		  var next = function (){
			  var handler = config.handlers[handlerIndex];
			  if (handler){
				  handlerIndex++;
				  if (handlerIndex == config.handlers.length){
					  // at least do not break page.js callback
					  handler(ctx, _next);
				  }else{
					  handler(ctx, next);
				  }
			  }else{
				  // at least do not break page.js callback
				  _next();
			  }
		  };
		  next();

	});

	config.init();

	if (config.autoStart){
		router.start();
	}

	return router;

});<|endoftext|>


<commit_before>var path = require('path');
var koa = require('koa');
var serve = require('koa-static');
var subdomain = require('koa-sub-domain');
var mount = require('koa-mount');
var session = require('koa-session');
var bodyParser = require('koa-bodyparser');
var randtoken = require('random-token').create('LDS'); // salt
var auth = require('./auth');
var router = require('./router');

var styleguide = require('@daytona/lds-styleguide');
var api = require('@daytona/lds-api');
var editor = require('@daytona/lds-editor');
var cms = require('@daytona/lds-cms');
var parseLds = require('@daytona/lds-parser');
var Engine = require('@daytona/lds-engine');

var view = require('../controllers/view');
var pageNotFound = require('../controllers/404');
var objectDeepMap = require('../lib/object-deep-map');

function Server(config) {
  if (!config.engine || !config.engine.render) {
    throw new Error('No templating engine specified');
  }

  var host = process.env.HOST || 'localhost';
  var port = process.env.PORT || config.port || 4000;

  //if (!config.namespace) {
    var namespace = 'lds';
  //}

  var engine = new Engine(config.engine);
  var app = koa();
  app.keys = ['secret lds project'];

  var lds = parseLds.sync(config);
  var token = randtoken(16);

  function reParse (callback) {
    console.log('Re-parsing structure');
    lds = parseLds.sync(config);
    if (typeof(callback) === 'function') {
      callback();
    }
    return;
  }

  app.use(session(app));

  app.use(function* (next) {
    this[namespace] = lds;
    this.parse = reParse;
    yield next;
  });

  app
    .use(bodyParser())
    // Serve static files from /dist folder
    .use(pageNotFound) // Handle 404 after parsing every other middleware, if no match trigger 404
    .use(mount(config.path.public, serve(path.join(config.path.dirname, config.path.dist))))
    .use(engine.setup(namespace));
    //.use(extendLds(config))

  if (config.login && process.env.NODE_ENV === 'production') {
    app.use(auth(config.login, token));
  }

  app
    .use(mount('/styleguide', styleguide))
    .use(mount('/api', api.app))
    .use(mount('/playground', editor))
    .use(mount('/cms', cms))
    .use(mount('/info', function* infoView(next) {
      this.showinfo = true;
      yield next;
    }))
    .use(mount('/info', view))
    .use(view)

    .listen(port);

  console.log('HTTP-Server running at port ', port);
  objectDeepMap(lds.structure.views, (value) => {
    if (value && value.isLDSObject && value.template) {
      console.log(`${value.name}: http://${host}:${port}${value.id.replace(/^\/views/, '')}`);
    }
    return value;
  });
  console.log(`Styleguide: http://${host}:${port}/styleguide`);

  return {
    parse: reParse,
    app
  };
};

module.exports = Server;
<commit_msg>removed lds-cms<commit_after>var path = require('path');
var koa = require('koa');
var serve = require('koa-static');
var subdomain = require('koa-sub-domain');
var mount = require('koa-mount');
var session = require('koa-session');
var bodyParser = require('koa-bodyparser');
var randtoken = require('random-token').create('LDS'); // salt
var auth = require('./auth');
var router = require('./router');

var styleguide = require('@daytona/lds-styleguide');
var api = require('@daytona/lds-api');
var editor = require('@daytona/lds-editor');
var parseLds = require('@daytona/lds-parser');
var Engine = require('@daytona/lds-engine');

var view = require('../controllers/view');
var pageNotFound = require('../controllers/404');
var objectDeepMap = require('../lib/object-deep-map');

function Server(config) {
  if (!config.engine || !config.engine.render) {
    throw new Error('No templating engine specified');
  }

  var host = process.env.HOST || 'localhost';
  var port = process.env.PORT || config.port || 4000;

  //if (!config.namespace) {
    var namespace = 'lds';
  //}

  var engine = new Engine(config.engine);
  var app = koa();
  app.keys = ['secret lds project'];

  var lds = parseLds.sync(config);
  var token = randtoken(16);

  function reParse (callback) {
    console.log('Re-parsing structure');
    lds = parseLds.sync(config);
    if (typeof(callback) === 'function') {
      callback();
    }
    return;
  }

  app.use(session(app));

  app.use(function* (next) {
    this[namespace] = lds;
    this.parse = reParse;
    yield next;
  });

  app
    .use(bodyParser())
    // Serve static files from /dist folder
    .use(pageNotFound) // Handle 404 after parsing every other middleware, if no match trigger 404
    .use(mount(config.path.public, serve(path.join(config.path.dirname, config.path.dist))))
    .use(engine.setup(namespace));
    //.use(extendLds(config))

  if (config.login && process.env.NODE_ENV === 'production') {
    app.use(auth(config.login, token));
  }

  app
    .use(mount('/styleguide', styleguide))
    .use(mount('/api', api.app))
    .use(mount('/playground', editor))
    .use(mount('/info', function* infoView(next) {
      this.showinfo = true;
      yield next;
    }))
    .use(mount('/info', view))
    .use(view)

    .listen(port);

  console.log('HTTP-Server running at port ', port);
  objectDeepMap(lds.structure.views, (value) => {
    if (value && value.isLDSObject && value.template) {
      console.log(`${value.name}: http://${host}:${port}${value.id.replace(/^\/views/, '')}`);
    }
    return value;
  });
  console.log(`Styleguide: http://${host}:${port}/styleguide`);

  return {
    parse: reParse,
    app
  };
};

module.exports = Server;
<|endoftext|>


<commit_before>var compose = (function () {

var exports = {};
var is_composing_message = false;

function show(tabname, focus_area) {
    if (tabname === "stream") {
        $('#private-message').hide();
        $('#stream-message').show();
        $("#stream_toggle").addClass("active");
        $("#private_message_toggle").removeClass("active");
    } else {
        $('#private-message').show();
        $('#stream-message').hide();
        $("#stream_toggle").removeClass("active");
        $("#private_message_toggle").addClass("active");
    }
    $("#send-status").removeClass(status_classes).hide();
    $('#compose').css({visibility: "visible"});
    $("#new_message_content").trigger("autosize");
    $('.message_comp').slideDown(100, function () {
        // If the compose box is obscuring the currently selected message,
        // scroll up until the message is no longer occluded.
        if (selected_message_id === -1) {
            // If there's no selected message, there's no need to
            // scroll the compose box to avoid it.
            return;
        }
        var cover = selected_message.offset().top + selected_message.height()
            - $("#compose").offset().top;
        if (cover > 0) {
            disable_pointer_movement = true;
            // We use $('html, body') because you can't animate window.scrollTop
            // on Chrome (http://bugs.jquery.com/ticket/10419).
            $('html, body').animate({
                scrollTop: viewport.scrollTop() + cover + 5
            }, {
                complete: function () {
                    // The complete callback is actually called before the
                    // scrolling has completed, so we try to let scrolling
                    // finish before allowing pointer movements again or the
                    // pointer may still move.
                    setTimeout(function () {
                        disable_pointer_movement = false;
                    }, 50);
                }
            });
        }
    });
    focus_area.focus();
    focus_area.select();
    // Disable the notifications bar if it overlaps with the composebox
    notifications_bar.maybe_disable();
}

// In an attempt to decrease mixing, make the composebox's
// stream bar look like what you're replying to.
// (In particular, if there's a color associated with it,
//  have that color be reflected here too.)
exports.decorate_stream_bar = function (stream_name) {
    var color = subs.get_color(stream_name);
    $("#stream-message .message_header_stream").css("background-color", color);
};

exports.start = function (msg_type, opts) {
    if (reload.is_in_progress()) {
        return;
    }

    compose.clear();

    var default_stream = '';
    if (msg_type === 'stream' && lurk_stream !== undefined)
        default_stream = lurk_stream;
    opts = $.extend({ message_type:     msg_type,
                      stream:           default_stream,
                      subject:          '',
                      private_message_recipient: ''
                    }, opts);

    compose.stream_name(opts.stream);
    compose.subject(opts.subject);
    compose.recipient(opts.private_message_recipient);
    // If the user opens the compose box, types some text, and then clicks on a
    // different stream/subject, we want to keep the text in the compose box
    if (opts.message !== undefined) {
        compose.message_content(opts.message);
    }

    ui.change_tab_to("#home");

    var focus_area;
    if (opts.stream && ! opts.subject) {
        focus_area = 'subject';
    } else if (opts.stream || opts.private_message_recipient) {
        focus_area = 'new_message_content';
    }

    if (msg_type === 'stream') {
        show('stream', $("#" + (focus_area || 'stream')));
    } else {
        show('private', $("#" + (focus_area || 'private_message_recipient')));
    }

    is_composing_message = msg_type;
    exports.decorate_stream_bar(opts.stream);
    $(document).trigger($.Event('compose_started.zephyr', opts));
};

exports.cancel = function () {
    compose.hide();
    is_composing_message = false;
    $(document).trigger($.Event('compose_canceled.zephyr'));
};

var send_options;

function send_message() {
    var send_status = $('#send-status');

    // TODO: this should be collapsed with the code in composebox_typeahead.js
    var recipients = compose.recipient().split(/\s*[,;]\s*/);

    var request = {client: 'website',
                   type:        compose.composing(),
                   subject:     compose.subject(),
                   content:     compose.message_content()};
    if (request.type === "private") {
        request.to = JSON.stringify(recipients);
    } else {
        request.to = JSON.stringify([compose.stream_name()]);
    }

    $.ajax({
        dataType: 'json', // This seems to be ignored. We still get back an xhr.
        url: '/json/send_message',
        type: 'POST',
        data: request,
        success: function (resp, statusText, xhr) {
            compose.clear();
            send_status.hide();
            is_composing_message = false;
            compose.hide();
            $("#compose-send-button").removeAttr('disabled');
        },
        error: function (xhr, error_type) {
            if (error_type !== 'timeout' && reload.is_pending()) {
                // The error might be due to the server changing
                reload.initiate({immediate: true, send_after_reload: true});
                return;
            }
            var response = "Error sending message";
            if (xhr.status.toString().charAt(0) === "4") {
                // Only display the error response for 4XX, where we've crafted
                // a nice response.
                response += ": " + $.parseJSON(xhr.responseText).msg;
            }
            show(is_composing_message, $("#new_message_content"));
            send_status.removeClass(status_classes)
                       .addClass('alert-error')
                       .text(response)
                       .append($('<span />')
                           .addClass('send-status-close').html('×')
                           .click(function () { send_status.stop(true).fadeOut(500); }))
                       .stop(true).fadeTo(0,1);

            $("#compose-send-button").removeAttr('disabled');
        }
    });

    send_status.hide();
}

exports.finish = function () {
    if (! compose.validate()) {
        return false;
    }
    send_message();
    // TODO: Do we want to fire the event even if the send failed due
    // to a server-side error?
    $(document).trigger($.Event('compose_finished.zephyr'));
    return true;
};

$(function () {
    $("#compose form").on("submit", function (e) {
       e.preventDefault();
       compose.finish();
    });
});

exports.hide = function () {
    $('input, textarea, button').blur();
    $('.message_comp').slideUp(100,
                              function() { $('#compose').css({visibility: "hidden"});});
    notifications_bar.enable();
};

exports.clear = function () {
    $("#compose").find('input[type=text], textarea').val('');
};

// Set the mode of a compose already in progress.
// Does not clear the input fields.
exports.set_mode = function (mode) {
    if (!is_composing_message) {
        exports.start(mode);
    }
    if (mode === 'private') {
        show('private', $("#private_message_recipient"));
        is_composing_message = "private";
    } else {
        show('stream', $(lurk_stream !== undefined ? "#subject" : "#stream"));
        is_composing_message = "stream";
    }
};

exports.composing = function () {
    return is_composing_message;
};

function get_or_set(fieldname, keep_outside_whitespace) {
    // We can't hoist the assignment of 'elem' out of this lambda,
    // because the DOM element might not exist yet when get_or_set
    // is called.
    return function (newval) {
        var elem = $('#'+fieldname);
        var oldval = elem.val();
        if (newval !== undefined) {
            elem.val(newval);
        }
        return keep_outside_whitespace ? oldval : $.trim(oldval);
    };
}

exports.stream_name     = get_or_set('stream');
exports.subject         = get_or_set('subject');
exports.message_content = get_or_set('new_message_content', true);
exports.recipient       = get_or_set('private_message_recipient');

function compose_error(error_text, bad_input) {
    $('#send-status').removeClass(status_classes)
               .addClass('alert-error')
               .text(error_text)
               .stop(true).fadeTo(0, 1);
    $("#compose-send-button").removeAttr('disabled');
    bad_input.focus().select();
}

// *Synchronously* check if a stream exists.
exports.check_stream_existence = function (stream_name) {
    var result = "error";
    var error_xhr = "";
    $.ajax({
        type: "POST",
        url: "/json/subscriptions/exists",
        data: {'stream': stream_name},
        async: false,
        success: function (data) {
            if (!data.exists) {
                // The stream doesn't exist
                result = "does-not-exist";
            } else if (data.subscribed) {
                result = "subscribed";
            } else {
                result = "not-subscribed";
            }
        },
        error: function (xhr) {
            result = "error";
            error_xhr = xhr;
        }
    });
    return [result, error_xhr];
};

// Checks if a stream exists. If not, displays an error and returns
// false.
function check_stream_for_send(stream_name) {
    var stream_check = exports.check_stream_existence(stream_name);
    var result = stream_check[0];
    var xhr = stream_check[1];

    if (result === "error") {
        ui.report_error("Error checking subscription", xhr, $("#home-error"));
        $("#stream").focus();
        $("#compose-send-button").removeAttr('disabled');
    } else {
        if (result === "does-not-exist") {
           $('#send-status').removeClass(status_classes);
                $('#stream-dne-name').text(stream_name);
                $('#stream-dne').show();
                $("#compose-send-button").removeAttr('disabled');
                exports.hide();
                $('#create-it').focus();
        }
        $("#home-error").hide();
    }

    return result;
}

function validate_stream_message() {
    var stream_name = exports.stream_name();
    if (stream_name === "") {
        compose_error("Please specify a stream", $("#stream"));
        return false;
    }

    if (exports.subject() === "") {
        compose_error("Please specify a subject", $("#subject"));
        return false;
    }

    if (!subs.have(stream_name)) {
        switch(check_stream_for_send(stream_name)) {
        case "does-not-exist":
        case "error":
            return false;
        case "subscribed":
            // You're actually subscribed to the stream, but this
            // browser window doesn't know it.
            return true;
        case "not-subscribed":
            if (lurk_stream !== undefined &&
                lurk_stream.toLowerCase() === stream_name.toLowerCase()) {
                // Just subscribe them.
                subs.subscribe_for_send(stream_name);
                // When the subscription request completes,
                // subscribe_for_send will send our message (like when
                // the user clicks on subscribe-and-send).
                return false;
            }

            $('#send-status').removeClass(status_classes);
            $('#stream-nosub-name').text(stream_name);
            $('#stream-nosub').show();
            $("#compose-send-button").removeAttr('disabled');
            exports.hide();
            $('#sub-it').focus();
            return false;
        }
    }

    return true;
}

function validate_private_message() {
    if (exports.recipient() === "") {
        compose_error("Please specify at least one recipient", $("#private_message_recipient"));
        return false;
    }

    return true;
}

exports.validate = function () {
    $("#compose-send-button").attr('disabled', 'disabled').blur();

    if (exports.message_content() === "") {
        compose_error("You have nothing to send!", $("#new_message_content"));
        return false;
    }

    if (exports.composing() === 'private') {
        return validate_private_message();
    } else {
        return validate_stream_message();
    }
};

$(function () {
    $("#new_message_content").autosize();
});

return exports;

}());
<commit_msg>Make 'New stream' and 'New PM' buttons work when not on home tab.<commit_after>var compose = (function () {

var exports = {};
var is_composing_message = false;

function show(tabname, focus_area) {
    if (tabname === "stream") {
        $('#private-message').hide();
        $('#stream-message').show();
        $("#stream_toggle").addClass("active");
        $("#private_message_toggle").removeClass("active");
    } else {
        $('#private-message').show();
        $('#stream-message').hide();
        $("#stream_toggle").removeClass("active");
        $("#private_message_toggle").addClass("active");
    }
    $("#send-status").removeClass(status_classes).hide();
    $('#compose').css({visibility: "visible"});
    $("#new_message_content").trigger("autosize");
    $('.message_comp').slideDown(100, function () {
        // If the compose box is obscuring the currently selected message,
        // scroll up until the message is no longer occluded.
        if (selected_message_id === -1) {
            // If there's no selected message, there's no need to
            // scroll the compose box to avoid it.
            return;
        }
        var cover = selected_message.offset().top + selected_message.height()
            - $("#compose").offset().top;
        if (cover > 0) {
            disable_pointer_movement = true;
            // We use $('html, body') because you can't animate window.scrollTop
            // on Chrome (http://bugs.jquery.com/ticket/10419).
            $('html, body').animate({
                scrollTop: viewport.scrollTop() + cover + 5
            }, {
                complete: function () {
                    // The complete callback is actually called before the
                    // scrolling has completed, so we try to let scrolling
                    // finish before allowing pointer movements again or the
                    // pointer may still move.
                    setTimeout(function () {
                        disable_pointer_movement = false;
                    }, 50);
                }
            });
        }
    });
    focus_area.focus();
    focus_area.select();
    // Disable the notifications bar if it overlaps with the composebox
    notifications_bar.maybe_disable();
}

// In an attempt to decrease mixing, make the composebox's
// stream bar look like what you're replying to.
// (In particular, if there's a color associated with it,
//  have that color be reflected here too.)
exports.decorate_stream_bar = function (stream_name) {
    var color = subs.get_color(stream_name);
    $("#stream-message .message_header_stream").css("background-color", color);
};

exports.start = function (msg_type, opts) {
    if (reload.is_in_progress()) {
        return;
    }

    compose.clear();

    var default_stream = '';
    if (msg_type === 'stream' && lurk_stream !== undefined)
        default_stream = lurk_stream;
    opts = $.extend({ message_type:     msg_type,
                      stream:           default_stream,
                      subject:          '',
                      private_message_recipient: ''
                    }, opts);

    compose.stream_name(opts.stream);
    compose.subject(opts.subject);
    compose.recipient(opts.private_message_recipient);
    // If the user opens the compose box, types some text, and then clicks on a
    // different stream/subject, we want to keep the text in the compose box
    if (opts.message !== undefined) {
        compose.message_content(opts.message);
    }

    ui.change_tab_to("#home");

    var focus_area;
    if (opts.stream && ! opts.subject) {
        focus_area = 'subject';
    } else if (opts.stream || opts.private_message_recipient) {
        focus_area = 'new_message_content';
    }

    if (msg_type === 'stream') {
        show('stream', $("#" + (focus_area || 'stream')));
    } else {
        show('private', $("#" + (focus_area || 'private_message_recipient')));
    }

    is_composing_message = msg_type;
    exports.decorate_stream_bar(opts.stream);
    $(document).trigger($.Event('compose_started.zephyr', opts));
};

exports.cancel = function () {
    compose.hide();
    is_composing_message = false;
    $(document).trigger($.Event('compose_canceled.zephyr'));
};

var send_options;

function send_message() {
    var send_status = $('#send-status');

    // TODO: this should be collapsed with the code in composebox_typeahead.js
    var recipients = compose.recipient().split(/\s*[,;]\s*/);

    var request = {client: 'website',
                   type:        compose.composing(),
                   subject:     compose.subject(),
                   content:     compose.message_content()};
    if (request.type === "private") {
        request.to = JSON.stringify(recipients);
    } else {
        request.to = JSON.stringify([compose.stream_name()]);
    }

    $.ajax({
        dataType: 'json', // This seems to be ignored. We still get back an xhr.
        url: '/json/send_message',
        type: 'POST',
        data: request,
        success: function (resp, statusText, xhr) {
            compose.clear();
            send_status.hide();
            is_composing_message = false;
            compose.hide();
            $("#compose-send-button").removeAttr('disabled');
        },
        error: function (xhr, error_type) {
            if (error_type !== 'timeout' && reload.is_pending()) {
                // The error might be due to the server changing
                reload.initiate({immediate: true, send_after_reload: true});
                return;
            }
            var response = "Error sending message";
            if (xhr.status.toString().charAt(0) === "4") {
                // Only display the error response for 4XX, where we've crafted
                // a nice response.
                response += ": " + $.parseJSON(xhr.responseText).msg;
            }
            show(is_composing_message, $("#new_message_content"));
            send_status.removeClass(status_classes)
                       .addClass('alert-error')
                       .text(response)
                       .append($('<span />')
                           .addClass('send-status-close').html('×')
                           .click(function () { send_status.stop(true).fadeOut(500); }))
                       .stop(true).fadeTo(0,1);

            $("#compose-send-button").removeAttr('disabled');
        }
    });

    send_status.hide();
}

exports.finish = function () {
    if (! compose.validate()) {
        return false;
    }
    send_message();
    // TODO: Do we want to fire the event even if the send failed due
    // to a server-side error?
    $(document).trigger($.Event('compose_finished.zephyr'));
    return true;
};

$(function () {
    $("#compose form").on("submit", function (e) {
       e.preventDefault();
       compose.finish();
    });
});

exports.hide = function () {
    $('input, textarea, button').blur();
    $('.message_comp').slideUp(100,
                              function() { $('#compose').css({visibility: "hidden"});});
    notifications_bar.enable();
};

exports.clear = function () {
    $("#compose").find('input[type=text], textarea').val('');
};

// Set the mode of a compose already in progress.
// Does not clear the input fields.
exports.set_mode = function (mode) {
    ui.change_tab_to('#home');
    if (!is_composing_message) {
        exports.start(mode);
    }
    if (mode === 'private') {
        show('private', $("#private_message_recipient"));
        is_composing_message = "private";
    } else {
        show('stream', $(lurk_stream !== undefined ? "#subject" : "#stream"));
        is_composing_message = "stream";
    }
};

exports.composing = function () {
    return is_composing_message;
};

function get_or_set(fieldname, keep_outside_whitespace) {
    // We can't hoist the assignment of 'elem' out of this lambda,
    // because the DOM element might not exist yet when get_or_set
    // is called.
    return function (newval) {
        var elem = $('#'+fieldname);
        var oldval = elem.val();
        if (newval !== undefined) {
            elem.val(newval);
        }
        return keep_outside_whitespace ? oldval : $.trim(oldval);
    };
}

exports.stream_name     = get_or_set('stream');
exports.subject         = get_or_set('subject');
exports.message_content = get_or_set('new_message_content', true);
exports.recipient       = get_or_set('private_message_recipient');

function compose_error(error_text, bad_input) {
    $('#send-status').removeClass(status_classes)
               .addClass('alert-error')
               .text(error_text)
               .stop(true).fadeTo(0, 1);
    $("#compose-send-button").removeAttr('disabled');
    bad_input.focus().select();
}

// *Synchronously* check if a stream exists.
exports.check_stream_existence = function (stream_name) {
    var result = "error";
    var error_xhr = "";
    $.ajax({
        type: "POST",
        url: "/json/subscriptions/exists",
        data: {'stream': stream_name},
        async: false,
        success: function (data) {
            if (!data.exists) {
                // The stream doesn't exist
                result = "does-not-exist";
            } else if (data.subscribed) {
                result = "subscribed";
            } else {
                result = "not-subscribed";
            }
        },
        error: function (xhr) {
            result = "error";
            error_xhr = xhr;
        }
    });
    return [result, error_xhr];
};

// Checks if a stream exists. If not, displays an error and returns
// false.
function check_stream_for_send(stream_name) {
    var stream_check = exports.check_stream_existence(stream_name);
    var result = stream_check[0];
    var xhr = stream_check[1];

    if (result === "error") {
        ui.report_error("Error checking subscription", xhr, $("#home-error"));
        $("#stream").focus();
        $("#compose-send-button").removeAttr('disabled');
    } else {
        if (result === "does-not-exist") {
           $('#send-status').removeClass(status_classes);
                $('#stream-dne-name').text(stream_name);
                $('#stream-dne').show();
                $("#compose-send-button").removeAttr('disabled');
                exports.hide();
                $('#create-it').focus();
        }
        $("#home-error").hide();
    }

    return result;
}

function validate_stream_message() {
    var stream_name = exports.stream_name();
    if (stream_name === "") {
        compose_error("Please specify a stream", $("#stream"));
        return false;
    }

    if (exports.subject() === "") {
        compose_error("Please specify a subject", $("#subject"));
        return false;
    }

    if (!subs.have(stream_name)) {
        switch(check_stream_for_send(stream_name)) {
        case "does-not-exist":
        case "error":
            return false;
        case "subscribed":
            // You're actually subscribed to the stream, but this
            // browser window doesn't know it.
            return true;
        case "not-subscribed":
            if (lurk_stream !== undefined &&
                lurk_stream.toLowerCase() === stream_name.toLowerCase()) {
                // Just subscribe them.
                subs.subscribe_for_send(stream_name);
                // When the subscription request completes,
                // subscribe_for_send will send our message (like when
                // the user clicks on subscribe-and-send).
                return false;
            }

            $('#send-status').removeClass(status_classes);
            $('#stream-nosub-name').text(stream_name);
            $('#stream-nosub').show();
            $("#compose-send-button").removeAttr('disabled');
            exports.hide();
            $('#sub-it').focus();
            return false;
        }
    }

    return true;
}

function validate_private_message() {
    if (exports.recipient() === "") {
        compose_error("Please specify at least one recipient", $("#private_message_recipient"));
        return false;
    }

    return true;
}

exports.validate = function () {
    $("#compose-send-button").attr('disabled', 'disabled').blur();

    if (exports.message_content() === "") {
        compose_error("You have nothing to send!", $("#new_message_content"));
        return false;
    }

    if (exports.composing() === 'private') {
        return validate_private_message();
    } else {
        return validate_stream_message();
    }
};

$(function () {
    $("#new_message_content").autosize();
});

return exports;

}());
<|endoftext|>


<commit_before>(function() {
  var out$ = typeof exports != 'undefined' && exports || typeof define != 'undefined' && {} || this;

  var doctype = '<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">';

  function isExternal(url) {
    return url && url.lastIndexOf('http',0) == 0 && url.lastIndexOf(window.location.host) == -1;
  }

  function inlineImages(el, callback) {
    var images = el.querySelectorAll('image');
    var left = images.length;
    if (left == 0) {
      callback();
    }
    for (var i = 0; i < images.length; i++) {
      (function(image) {
        var href = image.getAttributeNS("http://www.w3.org/1999/xlink", "href");
        if (href) {
          if (isExternal(href.value)) {
            console.warn("Cannot render embedded images linking to external hosts: "+href.value);
            return;
          }
        }
        var canvas = document.createElement('canvas');
        var ctx = canvas.getContext('2d');
        var img = new Image();
        href = href || image.getAttribute('href');
        img.src = href;
        img.onload = function() {
          canvas.width = img.width;
          canvas.height = img.height;
          ctx.drawImage(img, 0, 0);
          image.setAttributeNS("http://www.w3.org/1999/xlink", "href", canvas.toDataURL('image/png'));
          left--;
          if (left == 0) {
            callback();
          }
        }
        img.onerror = function() {
          console.log("Could not load "+href);
          left--;
          if (left == 0) {
            callback();
          }
        }
      })(images[i]);
    }
  }

  function styles(el, selectorRemap) {
    var css = "";
    var sheets = document.styleSheets;
    for (var i = 0; i < sheets.length; i++) {
      try {
        var rules = sheets[i].cssRules;
      } catch (e) {
        console.warn("Stylesheet could not be loaded: "+sheets[i].href);
        continue;
      }

      if (rules != null) {
        for (var j = 0; j < rules.length; j++) {
          var rule = rules[j];
          if (typeof(rule.style) != "undefined") {
            var match = null;
            try {
              match = el.querySelector(rule.selectorText);
            } catch(err) {
              console.warn('Invalid CSS selector "' + rule.selectorText + '"', err);
            }
            if (match) {
              var selector = selectorRemap ? selectorRemap(rule.selectorText) : rule.selectorText;
              css += selector + " { " + rule.style.cssText + " }\n";
            } else if(rule.cssText.match(/^@font-face/)) {
              css += rule.cssText + '\n';
            }
          }
        }
      }
    }
    return css;
  }

  function getDimension(el, clone, dim) {
    var v = (el.viewBox && el.viewBox.baseVal && el.viewBox.baseVal[dim]) ||
      (clone.getAttribute(dim) !== null && !clone.getAttribute(dim).match(/%$/) && parseInt(clone.getAttribute(dim))) ||
      el.getBoundingClientRect()[dim] ||
      parseInt(clone.style[dim]) ||
      parseInt(window.getComputedStyle(el).getPropertyValue(dim));
    return (typeof v === 'undefined' || v === null || isNaN(parseFloat(v))) ? 0 : v;
  }

  function reEncode(data) {
    data = encodeURIComponent(data);
    data = data.replace(/%([0-9A-F]{2})/g, function(match, p1) {
      var c = String.fromCharCode('0x'+p1);
      return c === '%' ? '%25' : c;
    });
    return decodeURIComponent(data);
  }

  out$.svgAsDataUri = function(el, options, cb) {
    options = options || {};
    options.scale = options.scale || 1;
    var xmlns = "http://www.w3.org/2000/xmlns/";

    inlineImages(el, function() {
      var outer = document.createElement("div");
      var clone = el.cloneNode(true);
      var width, height;
      if(el.tagName == 'svg') {
        width = options.width || getDimension(el, clone, 'width');
        height = options.height || getDimension(el, clone, 'height');
      } else if(el.getBBox) {
        var box = el.getBBox();
        width = box.x + box.width;
        height = box.y + box.height;
        clone.setAttribute('transform', clone.getAttribute('transform').replace(/translate\(.*?\)/, ''));

        var svg = document.createElementNS('http://www.w3.org/2000/svg','svg')
        svg.appendChild(clone)
        clone = svg;
      } else {
        console.error('Attempted to render non-SVG element', el);
        return;
      }

      clone.setAttribute("version", "1.1");
      clone.setAttributeNS(xmlns, "xmlns", "http://www.w3.org/2000/svg");
      clone.setAttributeNS(xmlns, "xmlns:xlink", "http://www.w3.org/1999/xlink");
      clone.setAttribute("width", width * options.scale);
      clone.setAttribute("height", height * options.scale);
      clone.setAttribute("viewBox", [
        options.left || 0,
        options.top || 0,
        width,
        height
      ].join(" "));

      outer.appendChild(clone);

      var css = styles(el, options.selectorRemap);
      var s = document.createElement('style');
      s.setAttribute('type', 'text/css');
      s.innerHTML = "<![CDATA[\n" + css + "\n]]>";
      var defs = document.createElement('defs');
      defs.appendChild(s);
      clone.insertBefore(defs, clone.firstChild);

      var svg = doctype + outer.innerHTML;
      var uri = 'data:image/svg+xml;base64,' + window.btoa(reEncode(svg));
      if (cb) {
        cb(uri);
      }
    });
  }

  out$.svgAsPngUri = function(el, options, cb) {
    out$.svgAsDataUri(el, options, function(uri) {
      var image = new Image();
      image.onload = function() {
        var canvas = document.createElement('canvas');
        canvas.width = image.width;
        canvas.height = image.height;
        var context = canvas.getContext('2d');
        if(options && options.backgroundColor){
          context.fillStyle = options.backgroundColor;
          context.fillRect(0, 0, canvas.width, canvas.height);
        }
        context.drawImage(image, 0, 0);
        var a = document.createElement('a'), png;
        try {
          png = canvas.toDataURL('image/png');
        } catch (e) {
          if ((typeof SecurityError !== 'undefined' && e instanceof SecurityError) || e.name == "SecurityError") {
            console.error("Rendered SVG images cannot be downloaded in this browser.");
            return;
          } else {
            throw e;
          }
        }
        cb(png);
      }
      image.src = uri;
    });
  }

  out$.saveSvgAsPng = function(el, name, options) {
    options = options || {};
    out$.svgAsPngUri(el, options, function(uri) {
      var a = document.createElement('a');
      a.download = name;
      a.href = uri;
      document.body.appendChild(a);
      a.addEventListener("click", function(e) {
        a.parentNode.removeChild(a);
      });
      a.click();
    });
  }

  // if define is defined create as an AMD module
  if (typeof define !== 'undefined') {
    define(function() {
      return out$;
    });
  }

})();
<commit_msg>Catch rule.selectorText throwing an error.<commit_after>(function() {
  var out$ = typeof exports != 'undefined' && exports || typeof define != 'undefined' && {} || this;

  var doctype = '<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">';

  function isExternal(url) {
    return url && url.lastIndexOf('http',0) == 0 && url.lastIndexOf(window.location.host) == -1;
  }

  function inlineImages(el, callback) {
    var images = el.querySelectorAll('image');
    var left = images.length;
    if (left == 0) {
      callback();
    }
    for (var i = 0; i < images.length; i++) {
      (function(image) {
        var href = image.getAttributeNS("http://www.w3.org/1999/xlink", "href");
        if (href) {
          if (isExternal(href.value)) {
            console.warn("Cannot render embedded images linking to external hosts: "+href.value);
            return;
          }
        }
        var canvas = document.createElement('canvas');
        var ctx = canvas.getContext('2d');
        var img = new Image();
        href = href || image.getAttribute('href');
        img.src = href;
        img.onload = function() {
          canvas.width = img.width;
          canvas.height = img.height;
          ctx.drawImage(img, 0, 0);
          image.setAttributeNS("http://www.w3.org/1999/xlink", "href", canvas.toDataURL('image/png'));
          left--;
          if (left == 0) {
            callback();
          }
        }
        img.onerror = function() {
          console.log("Could not load "+href);
          left--;
          if (left == 0) {
            callback();
          }
        }
      })(images[i]);
    }
  }

  function styles(el, selectorRemap) {
    var css = "";
    var sheets = document.styleSheets;
    for (var i = 0; i < sheets.length; i++) {
      try {
        var rules = sheets[i].cssRules;
      } catch (e) {
        console.warn("Stylesheet could not be loaded: "+sheets[i].href);
        continue;
      }

      if (rules != null) {
        for (var j = 0; j < rules.length; j++) {
          var rule = rules[j];
          if (typeof(rule.style) != "undefined") {
            var match, selectorText;

            try {
              selectorText = rule.selectorText;
            } catch(err) {
              console.warn('The following CSS rule has an invalid selector: "' + rule + '"', err);
            }

            try {
              if (selectorText) {
                match = el.querySelector(selectorText);
              }
            } catch(err) {
              console.warn('Invalid CSS selector "' + selectorText + '"', err);
            }

            if (match) {
              var selector = selectorRemap ? selectorRemap(rule.selectorText) : rule.selectorText;
              css += selector + " { " + rule.style.cssText + " }\n";
            } else if(rule.cssText.match(/^@font-face/)) {
              css += rule.cssText + '\n';
            }
          }
        }
      }
    }
    return css;
  }

  function getDimension(el, clone, dim) {
    var v = (el.viewBox && el.viewBox.baseVal && el.viewBox.baseVal[dim]) ||
      (clone.getAttribute(dim) !== null && !clone.getAttribute(dim).match(/%$/) && parseInt(clone.getAttribute(dim))) ||
      el.getBoundingClientRect()[dim] ||
      parseInt(clone.style[dim]) ||
      parseInt(window.getComputedStyle(el).getPropertyValue(dim));
    return (typeof v === 'undefined' || v === null || isNaN(parseFloat(v))) ? 0 : v;
  }

  function reEncode(data) {
    data = encodeURIComponent(data);
    data = data.replace(/%([0-9A-F]{2})/g, function(match, p1) {
      var c = String.fromCharCode('0x'+p1);
      return c === '%' ? '%25' : c;
    });
    return decodeURIComponent(data);
  }

  out$.svgAsDataUri = function(el, options, cb) {
    options = options || {};
    options.scale = options.scale || 1;
    var xmlns = "http://www.w3.org/2000/xmlns/";

    inlineImages(el, function() {
      var outer = document.createElement("div");
      var clone = el.cloneNode(true);
      var width, height;
      if(el.tagName == 'svg') {
        width = options.width || getDimension(el, clone, 'width');
        height = options.height || getDimension(el, clone, 'height');
      } else if(el.getBBox) {
        var box = el.getBBox();
        width = box.x + box.width;
        height = box.y + box.height;
        clone.setAttribute('transform', clone.getAttribute('transform').replace(/translate\(.*?\)/, ''));

        var svg = document.createElementNS('http://www.w3.org/2000/svg','svg')
        svg.appendChild(clone)
        clone = svg;
      } else {
        console.error('Attempted to render non-SVG element', el);
        return;
      }

      clone.setAttribute("version", "1.1");
      clone.setAttributeNS(xmlns, "xmlns", "http://www.w3.org/2000/svg");
      clone.setAttributeNS(xmlns, "xmlns:xlink", "http://www.w3.org/1999/xlink");
      clone.setAttribute("width", width * options.scale);
      clone.setAttribute("height", height * options.scale);
      clone.setAttribute("viewBox", [
        options.left || 0,
        options.top || 0,
        width,
        height
      ].join(" "));

      outer.appendChild(clone);

      var css = styles(el, options.selectorRemap);
      var s = document.createElement('style');
      s.setAttribute('type', 'text/css');
      s.innerHTML = "<![CDATA[\n" + css + "\n]]>";
      var defs = document.createElement('defs');
      defs.appendChild(s);
      clone.insertBefore(defs, clone.firstChild);

      var svg = doctype + outer.innerHTML;
      var uri = 'data:image/svg+xml;base64,' + window.btoa(reEncode(svg));
      if (cb) {
        cb(uri);
      }
    });
  }

  out$.svgAsPngUri = function(el, options, cb) {
    out$.svgAsDataUri(el, options, function(uri) {
      var image = new Image();
      image.onload = function() {
        var canvas = document.createElement('canvas');
        canvas.width = image.width;
        canvas.height = image.height;
        var context = canvas.getContext('2d');
        if(options && options.backgroundColor){
          context.fillStyle = options.backgroundColor;
          context.fillRect(0, 0, canvas.width, canvas.height);
        }
        context.drawImage(image, 0, 0);
        var a = document.createElement('a'), png;
        try {
          png = canvas.toDataURL('image/png');
        } catch (e) {
          if ((typeof SecurityError !== 'undefined' && e instanceof SecurityError) || e.name == "SecurityError") {
            console.error("Rendered SVG images cannot be downloaded in this browser.");
            return;
          } else {
            throw e;
          }
        }
        cb(png);
      }
      image.src = uri;
    });
  }

  out$.saveSvgAsPng = function(el, name, options) {
    options = options || {};
    out$.svgAsPngUri(el, options, function(uri) {
      var a = document.createElement('a');
      a.download = name;
      a.href = uri;
      document.body.appendChild(a);
      a.addEventListener("click", function(e) {
        a.parentNode.removeChild(a);
      });
      a.click();
    });
  }

  // if define is defined create as an AMD module
  if (typeof define !== 'undefined') {
    define(function() {
      return out$;
    });
  }
})();
<|endoftext|>