<commit_before>import resolve from 'rollup-plugin-node-resolve'
import commonjs from 'rollup-plugin-commonjs'
import sourceMaps from 'rollup-plugin-sourcemaps'
const pkg = require('./package.json')

const libraryName = 'react-rxjs'

export default {
  input: `compiled/${libraryName}.js`,
  output: [
    {
      name: 'umd',
      file: pkg.main + '/bundle-umd.js',
      format: 'umd'
    },
    {
      name: 'es',
      file: pkg.module + '/bundle-es.js',
      format: 'es'
    }
  ],
  sourceMap: true,
  // Indicate here external modules you don't wanna include in your bundle (i.e.: 'lodash')
  external: ["rxjs", "react"],
  plugins: [
    // Allow bundling cjs modules (unlike webpack, rollup doesn't understand cjs)
    commonjs(),
    // Allow node_modules resolution, so you can use 'external' to control
    // which external modules to include in the bundle
    // https://github.com/rollup/rollup-plugin-node-resolve#usage
    resolve(),

    // Resolve source maps to the original source
    sourceMaps()
  ]
}
<commit_msg>build: fixing rollup configuration<commit_after>import resolve from 'rollup-plugin-node-resolve'
import commonjs from 'rollup-plugin-commonjs'
import sourceMaps from 'rollup-plugin-sourcemaps'
const pkg = require('./package.json')

const libraryName = 'react-rxjs'

export default {
  input: `compiled/${libraryName}.js`,
  output: [
    {
      name: 'umd',
      file: pkg.main,
      format: 'umd'
    },
    {
      name: 'es',
      file: pkg.module,
      format: 'es'
    }
  ],
  sourceMap: true,
  // Indicate here external modules you don't wanna include in your bundle (i.e.: 'lodash')
  external: ["rxjs", "react"],
  plugins: [
    // Allow bundling cjs modules (unlike webpack, rollup doesn't understand cjs)
    commonjs(),
    // Allow node_modules resolution, so you can use 'external' to control
    // which external modules to include in the bundle
    // https://github.com/rollup/rollup-plugin-node-resolve#usage
    resolve(),

    // Resolve source maps to the original source
    sourceMaps()
  ]
}
<|endoftext|>


<commit_before>import json from 'rollup-plugin-json';

export default {
    input: 'index.mjs',
    output: {
        file: 'index.js',
        format: 'umd',
        indent: false,
        name: 'areaKeys'
    },
    plugins: [
        json({ indent: false })
    ]
};
<commit_msg>Actually it should be indent:''<commit_after>import json from 'rollup-plugin-json';

export default {
    input: 'index.mjs',
    output: {
        file: 'index.js',
        format: 'umd',
        indent: false,
        name: 'areaKeys'
    },
    plugins: [
        json({ indent: '' })
    ]
};
<|endoftext|>


<commit_before>import commonjs from "rollup-plugin-commonjs";
import nodeResolve from "rollup-plugin-node-resolve";

export default {
  entry: 'index.js',
  moduleName: 'd3',
  format: 'umd',
  globals: {
    'd3-geo': 'd3',
    'd3-array': 'd3'
  },
  dest: 'build/d3-cartogram.js',
  plugins: [
    nodeResolve({
        jsnext: true,
        main: true,
        browser: true,
        extensions: [".js", ".jsx"]
      }),
    commonjs({
      include: "node_modules/**",
      exclude: [ "node_modules/d3-geo/", "node_modules/d3-array/", "node_modules/buffer/", "node_modules/events/", "node_modules/util/"]

    })
  ]
};
<commit_msg>fix up rollup config<commit_after>import commonjs from "rollup-plugin-commonjs";
import nodeResolve from "rollup-plugin-node-resolve";

export default {
  entry: 'index.js',
  moduleName: 'topogram',
  format: 'umd',
  dest: 'build/topogram.js',
  plugins: [
    nodeResolve({
      jsnext: true,
      main: true,
      browser: true,
      extensions: ['.js'],
    }),
    commonjs({
      include: "node_modules/**",
      exclude: [
        "node_modules/d3-geo/",
        "node_modules/d3-array/",
        "node_modules/buffer/",
        "node_modules/events/",
        "node_modules/util/"
      ]
    })
  ]
};
<|endoftext|>


<commit_before>// @flow weak

import babel from 'rollup-plugin-babel';
import uglify from 'rollup-plugin-uglify';
import replace from 'rollup-plugin-replace';
import commonjs from 'rollup-plugin-commonjs';
import resolve from 'rollup-plugin-node-resolve';

const config = {
  input: 'src/index.js',
  name: 'react-move',
  globals: {
    react: 'React',
  },
  external: [
    'react',
  ],
  plugins: [
    babel({
      exclude: 'node_modules/**',
    }),
    resolve(),
    commonjs({
      include: /node_modules/,
    }),
    replace({
      'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
    }),
  ],
};

if (process.env.NODE_ENV === 'production') {
  config.plugins.push(uglify());
}

export default config;
<commit_msg>update rollup<commit_after>import babel from 'rollup-plugin-babel'
import replace from 'rollup-plugin-replace'
import commonjs from 'rollup-plugin-commonjs'
import nodeResolve from 'rollup-plugin-node-resolve'
import { sizeSnapshot } from 'rollup-plugin-size-snapshot'
import { terser } from 'rollup-plugin-terser'

import pkg from './package.json'

const input = 'src/index.js'
const globalName = 'ReactMove'

const globals = {
  react: 'React',
}

const umd = [
  {
    input,
    output: {
      file: `build/dist/${pkg.name}.js`,
      format: 'umd',
      exports: 'named',
      name: globalName,
      globals,
    },
    external: Object.keys(globals),
    plugins: [
      babel({
        runtimeHelpers: true,
        exclude: 'node_modules/**',
        presets: ['@babel/preset-react'],
        plugins: [
          '@babel/plugin-proposal-class-properties',
          ['transform-react-remove-prop-types', { mode: 'wrap' }],
          ['@babel/transform-runtime'],
        ],
      }),
      nodeResolve(),
      commonjs({
        include: /node_modules/,
      }),
      replace({ 'process.env.NODE_ENV': JSON.stringify('development') }),
      sizeSnapshot(),
    ],
  },
  {
    input,
    output: {
      file: `build/dist/${pkg.name}.min.js`,
      format: 'umd',
      exports: 'named',
      name: globalName,
      globals,
    },
    external: Object.keys(globals),
    plugins: [
      babel({
        runtimeHelpers: true,
        exclude: 'node_modules/**',
        presets: ['@babel/preset-react'],
        plugins: [
          '@babel/plugin-proposal-class-properties',
          [
            'transform-react-remove-prop-types',
            { mode: 'remove', removeImport: true },
          ],
          ['@babel/transform-runtime'],
        ],
      }),
      nodeResolve(),
      commonjs({
        include: /node_modules/,
      }),
      replace({ 'process.env.NODE_ENV': JSON.stringify('production') }),
      terser(),
      sizeSnapshot(),
    ],
  },
]

export default umd
<|endoftext|>


<commit_before>/**
 * Copyright (C) 2011 Instructure, Inc.
 *
 * This file is part of Canvas.
 *
 * Canvas is free software: you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License as published by the Free
 * Software Foundation, version 3 of the License.
 *
 * Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 * A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

// tinymce doesn't like its plugins being async,
// all dependencies must export to window

define([
  'compiled/editor/stocktiny',
  'i18n!editor',
  'jquery',
  'str/htmlEscape',
  'quizzes_new',
  'i18n!account_homepage',
  'jqueryui/dialog',
  'jquery.form',
  'jquery.instructure_misc_helpers'

], function(tinymce, I18n, $, htmlEscape) {
  var $box;

  var initted = false;

  var TRANSLATIONS = {
    click_to_embed: I18n.t('click_to_embed', 'Click to embed the image'),
    instructions: INST.htmlEscape(I18n.t('instructions', "Paste or type the URL of the image you'd like to embed:")),
    url: INST.htmlEscape(I18n.t('url', 'URL:')),
    alt_text: INST.htmlEscape(I18n.t('alt_text', 'Alternate Text:')),
    search_flickr: I18n.t('search_flickr', 'Search flickr creative commons'),
    loading: I18n.t('loading', 'Loading...'),
    embed_external: I18n.t('embed_external', 'Embed External Image'),
    embed_image: INST.htmlEscape(I18n.t('embed_image', 'Embed Image')),
    image_not_found: I18n.t('image_not_found', 'Image not found, please try a new URL')
  };

  function initShared () {
    var courseId = ENV.context_asset_string.split('_')[1]
    $box = $("<form id='background_image_uploader' action='/courses/" + courseId + "/student_files' method='POST' enctype='multipart/form-data' >" +
        "
" +
        "
" +
        "" +
        I18n.t('choose_a_picture', 'choose a picture:') +
        "	" +
        "" +
        "<input id='background_bg_image' name='attachment[uploaded_data]' type='file'>" +
        "	" +
        "
" +
        "
" +
        "" +
        "	" +
        "" +
        // "<input type='submit' value=" + I18n.t('#accounts.homepage.upload', 'Upload') + " class='btn confirm'>" +
        "	" +
        "
" +
        "
" +
        "</form>").hide();

    $('body').append($box);

    var $textUploading = $("上传中...");
    var $inputFile = $box.find("#background_bg_image");
    var $confirm = $box.find(".confirm");

    $('#background_bg_image').on('change', function(){
      $box.submit()
    })
    $box.on('submit', function(e) {
      e.preventDefault();
      $(this).ajaxSubmit({
        clearForm: true,
        dataType: 'json',
        beforeSubmit: function() {
          var imageValidated = validateUploadedImage( $inputFile.val() );
          if(imageValidated) $confirm.hide().after($textUploading);
          return imageValidated;
        },
        success: function(data) {
          var img = "";
          $editor.editorBox('insert_code', img);
          $confirm.show();
          $textUploading.remove();
        },
        complete: function(){
          afterUploadedImageSuccess();
        }
      });

    });

    $box.dialog({
      autoOpen: false,
      width: 425,
      title: TRANSLATIONS.embed_external,
      dialogClass: "instructure_upload_image"
    });
    initted = true;
  }

  tinymce.create('tinymce.plugins.InstructureUploadImage', {
    init: function (editor, url) {
      var thisEditor = $('#' + editor.id);

      editor.addCommand('instructureUploadImage', function (search) {
        if (!initted) initShared();
        $editor = thisEditor; // set shared $editor so images are pasted into the correct editor
        $box.dialog('open');
      });

      editor.addButton('instructure_upload_image', {
        title: '图片上传',
        cmd: 'instructureUploadImage',
        image: url + '/img/button.gif'
      });
    },

    getInfo: function () {
      return {
        longname: 'InstructureUploadImage',
        author: 'Rupert qin',
        authorurl: 'http://www.jiaoxuebang.com',
        infourl: 'http://www.jiaoxuebang.com',
        version: tinymce.majorVersion + '.' + tinymce.minorVersion
      };
    }
  });

  tinymce.PluginManager.add('instructure_upload_image', tinymce.plugins.InstructureUploadImage);
});

<commit_msg>fixes #838<commit_after>/**
 * Copyright (C) 2011 Instructure, Inc.
 *
 * This file is part of Canvas.
 *
 * Canvas is free software: you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License as published by the Free
 * Software Foundation, version 3 of the License.
 *
 * Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 * A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

// tinymce doesn't like its plugins being async,
// all dependencies must export to window

define([
  'compiled/editor/stocktiny',
  'i18n!editor',
  'jquery',
  'str/htmlEscape',
  'quizzes_new',
  'i18n!account_homepage',
  'jqueryui/dialog',
  'jquery.form',
  'jquery.instructure_misc_helpers'

], function(tinymce, I18n, $, htmlEscape) {
  var $box;

  var initted = false;

  var TRANSLATIONS = {
    click_to_embed: I18n.t('click_to_embed', 'Click to embed the image'),
    instructions: INST.htmlEscape(I18n.t('instructions', "Paste or type the URL of the image you'd like to embed:")),
    url: INST.htmlEscape(I18n.t('url', 'URL:')),
    alt_text: INST.htmlEscape(I18n.t('alt_text', 'Alternate Text:')),
    search_flickr: I18n.t('search_flickr', 'Search flickr creative commons'),
    loading: I18n.t('loading', 'Loading...'),
    embed_external: I18n.t('embed_external', 'Embed External Image'),
    embed_image: INST.htmlEscape(I18n.t('embed_image', 'Embed Image')),
    image_not_found: I18n.t('image_not_found', 'Image not found, please try a new URL')
  };

  function initShared () {
    var contextAsset = ENV.context_asset_string.split('_')
    var kind = contextAsset[0]
    var id = contextAsset[1]
    var url = kind == 'course' ? '/courses/' + id + '/student_files' : '/accounts/' + id + '/files'
    $box = $("<form id='background_image_uploader' action=" + url + " method='POST' enctype='multipart/form-data' >" +
        "
" +
        "
" +
        "" +
        I18n.t('choose_a_picture', 'choose a picture:') +
        "	" +
        "" +
        "<input id='background_bg_image' name='attachment[uploaded_data]' type='file'>" +
        "	" +
        "
" +
        "
" +
        "" +
        "	" +
        "" +
        // "<input type='submit' value=" + I18n.t('#accounts.homepage.upload', 'Upload') + " class='btn confirm'>" +
        "	" +
        "
" +
        "
" +
        "</form>").hide();

    $('body').append($box);

    var $textUploading = $("上传中...");
    var $inputFile = $box.find("#background_bg_image");
    var $confirm = $box.find(".confirm");

    $('#background_bg_image').on('change', function(){
      $box.submit()
    })
    $box.on('submit', function(e) {
      e.preventDefault();
      $(this).ajaxSubmit({
        clearForm: true,
        dataType: 'json',
        beforeSubmit: function() {
          var imageValidated = validateUploadedImage( $inputFile.val() );
          if(imageValidated) $confirm.hide().after($textUploading);
          return imageValidated;
        },
        success: function(data) {
          var img = "";
          $editor.editorBox('insert_code', img);
          $confirm.show();
          $textUploading.remove();
        },
        complete: function(){
          afterUploadedImageSuccess();
        }
      });

    });

    $box.dialog({
      autoOpen: false,
      width: 425,
      title: TRANSLATIONS.embed_external,
      dialogClass: "instructure_upload_image"
    });
    initted = true;
  }

  tinymce.create('tinymce.plugins.InstructureUploadImage', {
    init: function (editor, url) {
      var thisEditor = $('#' + editor.id);

      editor.addCommand('instructureUploadImage', function (search) {
        if (!initted) initShared();
        $editor = thisEditor; // set shared $editor so images are pasted into the correct editor
        $box.dialog('open');
      });

      editor.addButton('instructure_upload_image', {
        title: '图片上传',
        cmd: 'instructureUploadImage',
        image: url + '/img/button.gif'
      });
    },

    getInfo: function () {
      return {
        longname: 'InstructureUploadImage',
        author: 'Rupert qin',
        authorurl: 'http://www.jiaoxuebang.com',
        infourl: 'http://www.jiaoxuebang.com',
        version: tinymce.majorVersion + '.' + tinymce.minorVersion
      };
    }
  });

  tinymce.PluginManager.add('instructure_upload_image', tinymce.plugins.InstructureUploadImage);
});

<|endoftext|>


<commit_before>var booleanFromEnv = require('./config/booleanFromEnv')
var flattenBrowser = require('zuul/lib/flatten_browser')
var request = require('sync-request')
var assign = require('lodash').assign

// copied from https://github.com/defunctzombie/zuul/blob/18e1a674f54b7d131b5e5ff82b2a6a75a49ec0c4/lib/scout_browser.js#L42-L56
function format (obj) {
  var browsers = {}
  obj.forEach(function (info) {
    var name = info.api_name

    var browser = browsers[name] = browsers[name] || []
    browser.push({
      name: name,
      version: info.short_version,
      platform: info.os
    })
  })

  return browsers
}

function queryBrowsers (query, optionalKeys) {
  var res = request('GET', 'https://saucelabs.com/rest/v1/info/browsers/webdriver')
  var allBrowsers = JSON.parse(res.getBody('utf8'))
  var chosenBrowsers = flattenBrowser(query, format(allBrowsers))
  chosenBrowsers.map(function (browser) {
    assign(browser, optionalKeys)
    browser.browserName = browser.name
    delete browser.name
  })
  return chosenBrowsers
}

require('babel/register')({
  experimental: true,
  blacklist: [
    'regenerator'
  ]
})

var config = {
  //
  // ==================
  // Specify Test Files
  // ==================
  // Define which test specs should run. The pattern is relative to the location of this
  // file.
  //
  specs: [
    './test/**/*.js'
  ],
  // Patterns to exclude.
  exclude: [
    // 'path/to/excluded/files'
  ],
  //
  // ============
  // Capabilities
  // ============
  // Define your capabilities here. WebdriverIO can run multiple capabilties at the same
  // time. Depending on the number of capabilities WebdriverIO launches several test
  // sessions. Within your capabilities you can overwrite the spec and exclude option in
  // order to group specific specs to a specific capability.
  //
  // If you have trouble getting all important capabilities together check out Sauce Labs
  // platform configurator. A great tool to configure your capabilities.
  // https://docs.saucelabs.com/reference/platforms-configurator
  //
  capabilities: [{
    browserName: 'chrome',
    platform: 'MAC',
    chromeOptions: {
      binary: require('expand-home-dir')('~') + '/Applications/Google\ Chrome\ Canary.app/Contents/MacOS/Google\ Chrome\ Canary'
    }
  }
  // {
  //   browserName: 'phantomjs'
  // }
  ],
  //
  // ===================
  // Test Configurations
  // ===================
  // Define all options that are relevant for the WebdriverIO instance here
  //
  // Level of logging verbosity.
  logLevel: 'silent',
  //
  // Enables colors for log output
  coloredLogs: true,
  //
  // Saves a screenshot to a given path if a command fails.
  screenshotPath: './errorShots/',

  //
  // Default timeout for all waitForXXX commands.
  waitforTimeout: 5000,
  //
  // Initialise the browser instance with a WebdriverIO plugin. The object should have the
  // plugin name as key and the desired plugin options as property. Make sure you have
  // the plugin installed before running any tests. The following plugins are currently
  // available:
  // WebdriverCSS: https://github.com/webdriverio/webdrivercss
  // WebdriverRTC: https://github.com/webdriverio/webdriverrtc
  // Browserevent: https://github.com/webdriverio/browserevent
  // plugins: {
  //     webdrivercss: {
  //         screenshotRoot: 'my-shots',
  //         failedComparisonsRoot: 'diffs',
  //         misMatchTolerance: 0.05,
  //         screenWidth: [320,480,640,1024]
  //     },
  //     webdriverrtc: {},
  //     browserevent: {}
  // },
  //
  // Framework you want to run your specs with.
  // The following are supported: mocha, jasmine and cucumber
  // see also: http://webdriver.io/guide/testrunner/frameworks.html
  //
  // Make sure you have the node package for the specific framework installed before running
  // any tests. If not please install the following package:
  // Mocha: `$ npm install mocha`
  // Jasmine: `$ npm install jasmine`
  // Cucumber: `$ npm install cucumber`
  framework: 'mocha',
  //
  // Test reporter for stdout.
  // The following are supported: dot (default), spec and xunit
  // see also: http://webdriver.io/guide/testrunner/reporters.html
  reporter: 'spec',

  //
  // Options to be passed to Mocha.
  // See the full list at http://mochajs.org/
  mochaOpts: {
    ui: 'bdd'
    // 'check-leaks': true,
    // bail: true
  },

  // Shorten url command calls by setting a base url. If your url parameter starts with '/'
  // the base url gets prepended.
  baseUrl: 'http://localhost:5050'
}

if (booleanFromEnv('WDIO_SAUCELABS', false)) {
  //
  // =================
  // Service Providers
  // =================
  // WebdriverIO supports Sauce Labs, Browserstack and Testing Bot (other cloud providers
  // should work too though). These services define specific user and key (or access key)
  // values you need to put in here in order to connect to these services.
  //
  config.user = process.env.SAUCE_USERNAME
  config.key = process.env.SAUCE_ACCESS_KEY

  //
  // If you are using Sauce Labs WebdriverIO takes care about updating the job information
  // once the test is done. This option is set to `true` per default.
  //
  config.updateSauceJob = true
  // delete config.reporter

  config.capabilities = queryBrowsers([
    {name: 'internet explorer', version: '10..latest'},
    {name: 'firefox', version: '38..latest'},
    {name: 'chrome', version: '43..latest'},
    {name: 'safari', version: '8..latest'},
    {name: 'iphone', version: '8.4..latest'},
    {name: 'android', version: '4.4..latest'}
  ], {
    'tunnel-identifier': process.env.TRAVIS_JOB_NUMBER
  })
}

exports.config = config
<commit_msg>caido: dont test on android<commit_after>var booleanFromEnv = require('./config/booleanFromEnv')
var flattenBrowser = require('zuul/lib/flatten_browser')
var request = require('sync-request')
var assign = require('lodash').assign

// copied from https://github.com/defunctzombie/zuul/blob/18e1a674f54b7d131b5e5ff82b2a6a75a49ec0c4/lib/scout_browser.js#L42-L56
function format (obj) {
  var browsers = {}
  obj.forEach(function (info) {
    var name = info.api_name

    var browser = browsers[name] = browsers[name] || []
    browser.push({
      name: name,
      version: info.short_version,
      platform: info.os
    })
  })

  return browsers
}

function queryBrowsers (query, optionalKeys) {
  var res = request('GET', 'https://saucelabs.com/rest/v1/info/browsers/webdriver')
  var allBrowsers = JSON.parse(res.getBody('utf8'))
  var chosenBrowsers = flattenBrowser(query, format(allBrowsers))
  chosenBrowsers.map(function (browser) {
    assign(browser, optionalKeys)
    browser.browserName = browser.name
    delete browser.name
  })
  return chosenBrowsers
}

require('babel/register')({
  experimental: true,
  blacklist: [
    'regenerator'
  ]
})

var config = {
  //
  // ==================
  // Specify Test Files
  // ==================
  // Define which test specs should run. The pattern is relative to the location of this
  // file.
  //
  specs: [
    './test/**/*.js'
  ],
  // Patterns to exclude.
  exclude: [
    // 'path/to/excluded/files'
  ],
  //
  // ============
  // Capabilities
  // ============
  // Define your capabilities here. WebdriverIO can run multiple capabilties at the same
  // time. Depending on the number of capabilities WebdriverIO launches several test
  // sessions. Within your capabilities you can overwrite the spec and exclude option in
  // order to group specific specs to a specific capability.
  //
  // If you have trouble getting all important capabilities together check out Sauce Labs
  // platform configurator. A great tool to configure your capabilities.
  // https://docs.saucelabs.com/reference/platforms-configurator
  //
  capabilities: [{
    browserName: 'chrome',
    platform: 'MAC',
    chromeOptions: {
      binary: require('expand-home-dir')('~') + '/Applications/Google\ Chrome\ Canary.app/Contents/MacOS/Google\ Chrome\ Canary'
    }
  }
  // {
  //   browserName: 'phantomjs'
  // }
  ],
  //
  // ===================
  // Test Configurations
  // ===================
  // Define all options that are relevant for the WebdriverIO instance here
  //
  // Level of logging verbosity.
  logLevel: 'silent',
  //
  // Enables colors for log output
  coloredLogs: true,
  //
  // Saves a screenshot to a given path if a command fails.
  screenshotPath: './errorShots/',

  //
  // Default timeout for all waitForXXX commands.
  waitforTimeout: 1000,
  //
  // Initialise the browser instance with a WebdriverIO plugin. The object should have the
  // plugin name as key and the desired plugin options as property. Make sure you have
  // the plugin installed before running any tests. The following plugins are currently
  // available:
  // WebdriverCSS: https://github.com/webdriverio/webdrivercss
  // WebdriverRTC: https://github.com/webdriverio/webdriverrtc
  // Browserevent: https://github.com/webdriverio/browserevent
  // plugins: {
  //     webdrivercss: {
  //         screenshotRoot: 'my-shots',
  //         failedComparisonsRoot: 'diffs',
  //         misMatchTolerance: 0.05,
  //         screenWidth: [320,480,640,1024]
  //     },
  //     webdriverrtc: {},
  //     browserevent: {}
  // },
  //
  // Framework you want to run your specs with.
  // The following are supported: mocha, jasmine and cucumber
  // see also: http://webdriver.io/guide/testrunner/frameworks.html
  //
  // Make sure you have the node package for the specific framework installed before running
  // any tests. If not please install the following package:
  // Mocha: `$ npm install mocha`
  // Jasmine: `$ npm install jasmine`
  // Cucumber: `$ npm install cucumber`
  framework: 'mocha',
  //
  // Test reporter for stdout.
  // The following are supported: dot (default), spec and xunit
  // see also: http://webdriver.io/guide/testrunner/reporters.html
  reporter: 'spec',

  //
  // Options to be passed to Mocha.
  // See the full list at http://mochajs.org/
  mochaOpts: {
    ui: 'bdd'
    // 'check-leaks': true,
    // bail: true
  },

  // Shorten url command calls by setting a base url. If your url parameter starts with '/'
  // the base url gets prepended.
  baseUrl: 'http://localhost:5050'
}

if (booleanFromEnv('WDIO_SAUCELABS', false)) {
  //
  // =================
  // Service Providers
  // =================
  // WebdriverIO supports Sauce Labs, Browserstack and Testing Bot (other cloud providers
  // should work too though). These services define specific user and key (or access key)
  // values you need to put in here in order to connect to these services.
  //
  config.user = process.env.SAUCE_USERNAME
  config.key = process.env.SAUCE_ACCESS_KEY

  //
  // If you are using Sauce Labs WebdriverIO takes care about updating the job information
  // once the test is done. This option is set to `true` per default.
  //
  config.updateSauceJob = true
  // delete config.reporter
  config.runsWithSauce = true

  config.capabilities = queryBrowsers([
    {name: 'internet explorer', version: '10..latest'},
    {name: 'firefox', version: '38..latest'},
    {name: 'chrome', version: '43..latest'},
    {name: 'safari', version: '8..latest'},
    {name: 'iphone', version: '8.4..latest'}
  ], {
    'tunnel-identifier': process.env.TRAVIS_JOB_NUMBER,
    'idle-timeout': 900,
    name: 'lucibus/caido',
    build: process.env.TRAVIS_BUILD_NUMBER
  })
}

exports.config = config
<|endoftext|>


<commit_before>import React from 'react'
import {
	View,
	Text,
	StyleSheet,
	TouchableHighlight,
	ActivityIndicator
} from 'react-native'
import FAIcon from 'react-native-vector-icons/FontAwesome'

import schedule from '../../util/schedule'
import logger from '../../util/logger'
import Card from '../common/Card'
import LastUpdated from '../common/LastUpdated'
import css from '../../styles/css'
import COLOR from '../../styles/ColorConstants'

const ScheduleCard = ({
	coursesToShow,
	waitingData,
	lastUpdated,
	error,
	actionButton,
	activeCourse,
	currentTerm,
	onClickCourse
}) => {
	try {
		if (
			coursesToShow &&
			coursesToShow[activeCourse] &&
			currentTerm.term_code) {
			const currentCourse = coursesToShow[activeCourse]

			// Get values for view and account for optional values
			let classTime,
				classLocation,
				classEval

			if (currentCourse.time_string) {
				classTime = currentCourse.time_string
			} else {
				classTime = 'No Time Associated'
			}

			if (currentCourse.building) {
				classLocation = currentCourse.building + ' ' +
					currentCourse.room
			} else {
				classLocation = 'No Location Associated'
			}

			switch (currentCourse.grade_option) {
				case 'L': {
					classEval = 'Letter Grade'
					break
				}
				case 'P': {
					classEval = 'Pass/No Pass'
					break
				}
				case 'S': {
					classEval = 'Sat/Unsat'
					break
				}
				default: {
					classEval = 'Other'
				}
			}

			return (
				<Card id="schedule" title="Classes">
					<View>
						<View style={css.cc_container}>
							<View style={css.cc_leftHalf}>
								<View style={css.cc_leftHalf_upper}>
									<ScheduleText style={css.cc_leftHalf_upper_timeText}>
										{schedule.dayOfWeekInterpreter(currentCourse.day_code)}
									</ScheduleText>
									<ScheduleText style={css.cc_leftHalf_upper_classText_firstSection}>
										{currentCourse.subject_code + ' '
											+ currentCourse.course_code}
									</ScheduleText>
									<ScheduleText style={css.cc_leftHalf_upper_classText_secondSection}>
										{currentCourse.meeting_type}
									</ScheduleText>
								</View>
								<View style={css.cc_leftHalf_lower}>
									<ClassMetaWithIcon
										icon="clock-o"
										iconStyle={css.cc_icon_time}
										description="Start and Finish Time"
										value={classTime}
									/>
									<ClassMetaWithIcon
										icon="building-o"
										iconStyle={css.cc_icon_building}
										description="Class Room Location"
										value={classLocation}
									/>
									<ClassMetaWithIcon
										icon="check-square-o"
										iconStyle={css.cc_icon_lettergrade}
										description="Evaluation Option"
										value={classEval}
									/>
								</View>
							</View>
							<View style={css.cc_rightHalf}>
								<DayItem
									data={coursesToShow[0]}
									active={activeCourse === 0}
									onClick={onClickCourse}
									index={0}
								/>
								<DayItem
									data={coursesToShow[1]}
									active={activeCourse === 1}
									onClick={onClickCourse}
									index={1}
								/>
								<DayItem
									data={coursesToShow[2]}
									active={activeCourse === 2}
									onClick={onClickCourse}
									index={2}
								/>
								<DayItem
									data={coursesToShow[3]}
									active={activeCourse === 3}
									onClick={onClickCourse}
									index={3}
								/>
							</View>
						</View>
						<LastUpdatedMin lastUpdated={lastUpdated} error={error} />
						{actionButton}
					</View>
				</Card>
			)
		} else if (waitingData) {
			return <LoadingClasses lastUpdated={lastUpdated} error={error} />
		} else {
			return <NoClasses lastUpdated={lastUpdated} error={error} />
		}
	} catch (err) {
		logger.trackException(err)
		return <NoClasses lastUpdated={lastUpdated} error={error} />
	}
}

const LastUpdatedMin = ({ lastUpdated, error }) => (
	<LastUpdated
		style={css.cc_last_updated}
		lastUpdated={lastUpdated}
		error={
			(error === 'App update required.') ?
				('App update required.') :
				(null)
		}
		warning={
			(error) ?
				('We\'re having trouble updating right now.') :
				(null)
		}
	/>
)

const LoadingClasses = ({ lastUpdated, error }) => (
	<Card id="schedule" title="Classes">
		<View style={css.cc_loadingContainer}>
			<ActivityIndicator size="large" />
		</View>
	</Card>
)

const NoClasses = ({ lastUpdated, error }) => (
	<Card id="schedule" title="Classes">
		<View style={css.cc_loadingContainer}>
			<Text style={css.cc_noclasses}>There are no classes to display right now.</Text>
		</View>
		<LastUpdatedMin lastUpdated={lastUpdated} error={error} />
	</Card>
)

const ClassMetaWithIcon = ({ icon, iconStyle, description, value }) => (
	<View style={css.cc_leftHalf_lower_sections}>
		<FAIcon style={iconStyle} size={42} name={icon} />
		<View style={css.cc_leftHalf_lower_sections_text}>
			<ScheduleText style={css.cc_leftHalf_lower_sections_text_bottomSection}>
				{description}
			</ScheduleText>
			<ScheduleText style={css.cc_leftHalf_lower_sections_text_topSection}>
				{value}
			</ScheduleText>
		</View>
	</View>
)

const ScheduleText = ({ style, children }) => (
	<Text
		numberOfLines={1}
		ellipsizeMode="tail"
		allowFontScaling={false}
		style={[
			{
				lineHeight: (() => Math.round(StyleSheet.flatten(style).fontSize * (1.2)))(),
				color: COLOR.VDGREY
			},
			style
		]}
	>
		{children}
	</Text>
)

// Holds the view for an individual section/class
const DayItem = ({ active, data, onClick, index }) => {
	if (!data) return null

	const day = schedule.dayOfWeekInterpreter(data.day_code)

	let shortenedDay
	if (day === 'Other' ) shortenedDay = day
	else shortenedDay = day.substring(0,3)

	let hour = ''
	if (data.start_string) hour = ' @ ' + data.start_string

	return (
		<TouchableHighlight
			onPress={() => onClick(index)}
			underlayColor={COLOR.LGREY}
			activeOpacity={0.5}
			style={{ marginBottom: 8 }}
		>
			<View style={[css.cc_rightHalf_eachOfFourCards, active && css.cc_rightHalf_activeCard]}>
				<ScheduleText style={[css.cc_rightHalf_each_daytime_text, !active && css.cc_rightHalf_each_inActiveText]}>
					{ shortenedDay + hour }
				</ScheduleText>
				<ScheduleText style={[css.cc_rightHalf_each_class_text, !active && css.cc_rightHalf_each_inActiveText]}>
					{data.subject_code + ' ' + data.course_code}
				</ScheduleText>
			</View>
		</TouchableHighlight>
	)
}

export default ScheduleCard
<commit_msg>show view all button when a student has no classes that day - fixes #462<commit_after>import React from 'react'
import {
	View,
	Text,
	StyleSheet,
	TouchableHighlight,
	ActivityIndicator
} from 'react-native'
import FAIcon from 'react-native-vector-icons/FontAwesome'

import schedule from '../../util/schedule'
import logger from '../../util/logger'
import Card from '../common/Card'
import LastUpdated from '../common/LastUpdated'
import css from '../../styles/css'
import COLOR from '../../styles/ColorConstants'

const ScheduleCard = ({
	coursesToShow,
	waitingData,
	lastUpdated,
	error,
	actionButton,
	activeCourse,
	currentTerm,
	onClickCourse
}) => {
	try {
		if (
			coursesToShow &&
			coursesToShow[activeCourse] &&
			currentTerm.term_code) {
			const currentCourse = coursesToShow[activeCourse]

			// Get values for view and account for optional values
			let classTime,
				classLocation,
				classEval

			if (currentCourse.time_string) {
				classTime = currentCourse.time_string
			} else {
				classTime = 'No Time Associated'
			}

			if (currentCourse.building) {
				classLocation = currentCourse.building + ' ' +
					currentCourse.room
			} else {
				classLocation = 'No Location Associated'
			}

			switch (currentCourse.grade_option) {
				case 'L': {
					classEval = 'Letter Grade'
					break
				}
				case 'P': {
					classEval = 'Pass/No Pass'
					break
				}
				case 'S': {
					classEval = 'Sat/Unsat'
					break
				}
				default: {
					classEval = 'Other'
				}
			}

			return (
				<Card id="schedule" title="Classes">
					<View>
						<View style={css.cc_container}>
							<View style={css.cc_leftHalf}>
								<View style={css.cc_leftHalf_upper}>
									<ScheduleText style={css.cc_leftHalf_upper_timeText}>
										{schedule.dayOfWeekInterpreter(currentCourse.day_code)}
									</ScheduleText>
									<ScheduleText style={css.cc_leftHalf_upper_classText_firstSection}>
										{currentCourse.subject_code + ' '
											+ currentCourse.course_code}
									</ScheduleText>
									<ScheduleText style={css.cc_leftHalf_upper_classText_secondSection}>
										{currentCourse.meeting_type}
									</ScheduleText>
								</View>
								<View style={css.cc_leftHalf_lower}>
									<ClassMetaWithIcon
										icon="clock-o"
										iconStyle={css.cc_icon_time}
										description="Start and Finish Time"
										value={classTime}
									/>
									<ClassMetaWithIcon
										icon="building-o"
										iconStyle={css.cc_icon_building}
										description="Class Room Location"
										value={classLocation}
									/>
									<ClassMetaWithIcon
										icon="check-square-o"
										iconStyle={css.cc_icon_lettergrade}
										description="Evaluation Option"
										value={classEval}
									/>
								</View>
							</View>
							<View style={css.cc_rightHalf}>
								<DayItem
									data={coursesToShow[0]}
									active={activeCourse === 0}
									onClick={onClickCourse}
									index={0}
								/>
								<DayItem
									data={coursesToShow[1]}
									active={activeCourse === 1}
									onClick={onClickCourse}
									index={1}
								/>
								<DayItem
									data={coursesToShow[2]}
									active={activeCourse === 2}
									onClick={onClickCourse}
									index={2}
								/>
								<DayItem
									data={coursesToShow[3]}
									active={activeCourse === 3}
									onClick={onClickCourse}
									index={3}
								/>
							</View>
						</View>
						<LastUpdatedMin lastUpdated={lastUpdated} error={error} />
						{actionButton}
					</View>
				</Card>
			)
		} else if (waitingData) {
			return <LoadingClasses lastUpdated={lastUpdated} error={error} />
		} else {
			return <NoClasses lastUpdated={lastUpdated} error={error} actionButton={actionButton} />
		}
	} catch (err) {
		logger.trackException(err)
		return <NoClasses lastUpdated={lastUpdated} error={error} actionButton={actionButton} />
	}
}

const LastUpdatedMin = ({ lastUpdated, error }) => (
	<LastUpdated
		style={css.cc_last_updated}
		lastUpdated={lastUpdated}
		error={
			(error === 'App update required.') ?
				('App update required.') :
				(null)
		}
		warning={
			(error) ?
				('We\'re having trouble updating right now.') :
				(null)
		}
	/>
)

const LoadingClasses = ({ lastUpdated, error }) => (
	<Card id="schedule" title="Classes">
		<View style={css.cc_loadingContainer}>
			<ActivityIndicator size="large" />
		</View>
		<LastUpdatedMin lastUpdated={lastUpdated} error={error} />
	</Card>
)

const NoClasses = ({ lastUpdated, error, actionButton }) => (
	<Card id="schedule" title="Classes">
		<View style={css.cc_loadingContainer}>
			<Text style={css.cc_noclasses}>
				You do not have any classes today.
			</Text>
		</View>
		<LastUpdatedMin lastUpdated={lastUpdated} error={error} />
		{actionButton}
	</Card>
)

const ClassMetaWithIcon = ({ icon, iconStyle, description, value }) => (
	<View style={css.cc_leftHalf_lower_sections}>
		<FAIcon style={iconStyle} size={42} name={icon} />
		<View style={css.cc_leftHalf_lower_sections_text}>
			<ScheduleText style={css.cc_leftHalf_lower_sections_text_bottomSection}>
				{description}
			</ScheduleText>
			<ScheduleText style={css.cc_leftHalf_lower_sections_text_topSection}>
				{value}
			</ScheduleText>
		</View>
	</View>
)

const ScheduleText = ({ style, children }) => (
	<Text
		numberOfLines={1}
		ellipsizeMode="tail"
		allowFontScaling={false}
		style={[
			{
				lineHeight: (() => Math.round(StyleSheet.flatten(style).fontSize * (1.2)))(),
				color: COLOR.VDGREY
			},
			style
		]}
	>
		{children}
	</Text>
)

// Holds the view for an individual section/class
const DayItem = ({ active, data, onClick, index }) => {
	if (!data) return null

	const day = schedule.dayOfWeekInterpreter(data.day_code)

	let shortenedDay
	if (day === 'Other' ) shortenedDay = day
	else shortenedDay = day.substring(0,3)

	let hour = ''
	if (data.start_string) hour = ' @ ' + data.start_string

	return (
		<TouchableHighlight
			onPress={() => onClick(index)}
			underlayColor={COLOR.LGREY}
			activeOpacity={0.5}
			style={{ marginBottom: 8 }}
		>
			<View style={[css.cc_rightHalf_eachOfFourCards, active && css.cc_rightHalf_activeCard]}>
				<ScheduleText style={[css.cc_rightHalf_each_daytime_text, !active && css.cc_rightHalf_each_inActiveText]}>
					{ shortenedDay + hour }
				</ScheduleText>
				<ScheduleText style={[css.cc_rightHalf_each_class_text, !active && css.cc_rightHalf_each_inActiveText]}>
					{data.subject_code + ' ' + data.course_code}
				</ScheduleText>
			</View>
		</TouchableHighlight>
	)
}

export default ScheduleCard
<|endoftext|>


<commit_before>/*global define*/
define([
        './defaultValue',
        './DeveloperError',
        './Cartesian3',
        './Math',
        './Matrix4',
        './Ellipsoid',
        './ComponentDatatype',
        './PrimitiveType',
        './BoundingSphere',
        './GeometryAttribute',
        './GeometryIndices',
        './VertexFormat'
    ], function(
        defaultValue,
        DeveloperError,
        Cartesian3,
        CesiumMath,
        Matrix4,
        Ellipsoid,
        ComponentDatatype,
        PrimitiveType,
        BoundingSphere,
        GeometryAttribute,
        GeometryIndices,
        VertexFormat) {
    "use strict";

    var sphericalNormal = new Cartesian3();
    var normal = new Cartesian3();
    var tangent = new Cartesian3();
    var binormal = new Cartesian3();

    /**
     * Creates vertices and indices for an ellipsoid centered at the origin.
     *
     * @alias EllipsoidGeometry
     * @constructor
     *
     * @param {Ellipsoid} [options.ellipsoi=Ellipsoid.UNIT_SPHERE] The ellipsoid used to create vertex attributes.
     * @param {Number} [options.numberOfPartitions=32] The number of times to partition the ellipsoid in a plane formed by two radii in a single quadrant.
     * @param {VertexFormat} [options.vertexFormat=VertexFormat.DEFAULT] The vertex attributes to be computed.
     * @param {Matrix4} [options.modelMatrix] The model matrix for this ellipsoid.
     * @param {DOC_TBA} [options.pickData] DOC_TBA
     *
     * @exception {DeveloperError} options.numberOfPartitions must be greater than zero.
     *
     * @example
     * var ellipsoid = new EllipsoidGeometry({
     *     vertexFormat : VertexFormat.POSITION_ONLY,
     *     ellipsoid : new Ellipsoid(1000000.0, 500000.0, 500000.0),
     *     modelMatrix : Transforms.eastNorthUpToFixedFrame(center)
     * });
     */
    var EllipsoidGeometry = function(options) {
        options = defaultValue(options, defaultValue.EMPTY_OBJECT);

        var ellipsoid = defaultValue(options.ellipsoid, Ellipsoid.UNIT_SPHERE);
        var numberOfPartitions = defaultValue(options.numberOfPartitions, 32);

        var vertexFormat = defaultValue(options.vertexFormat, VertexFormat.DEFAULT);

        if (numberOfPartitions <= 0) {
            throw new DeveloperError('options.numberOfPartitions must be greater than zero.');
        }

        var positions = [];
        var indices = [];

        //
        // Initial cube.  In the plane, z = -1:
        //
        //                   +y
        //                    |
        //             Q2     * p3     Q1
        //                  / | \
        //              p0 *--+--* p2   +x
        //                  \ | /
        //             Q3     * p1     Q4
        //                    |
        //
        // Similarly, p4 to p7 are in the plane z = 1.
        //
        positions.push(new Cartesian3(-1, 0, -1));
        positions.push(new Cartesian3(0, -1, -1));
        positions.push(new Cartesian3(1, 0, -1));
        positions.push(new Cartesian3(0, 1, -1));
        positions.push(new Cartesian3(-1, 0, 1));
        positions.push(new Cartesian3(0, -1, 1));
        positions.push(new Cartesian3(1, 0, 1));
        positions.push(new Cartesian3(0, 1, 1));

        //
        // Edges
        //
        // 0 -> 1, 1 -> 2, 2 -> 3, 3 -> 0.  Plane z = -1
        // 4 -> 5, 5 -> 6, 6 -> 7, 7 -> 4.  Plane z = 1
        // 0 -> 4, 1 -> 5, 2 -> 6, 3 -> 7.  From plane z = -1 to plane z - 1
        //
        var edge0to1 = addEdgePositions(0, 1, numberOfPartitions, positions);
        var edge1to2 = addEdgePositions(1, 2, numberOfPartitions, positions);
        var edge2to3 = addEdgePositions(2, 3, numberOfPartitions, positions);
        var edge3to0 = addEdgePositions(3, 0, numberOfPartitions, positions);

        var edge4to5 = addEdgePositions(4, 5, numberOfPartitions, positions);
        var edge5to6 = addEdgePositions(5, 6, numberOfPartitions, positions);
        var edge6to7 = addEdgePositions(6, 7, numberOfPartitions, positions);
        var edge7to4 = addEdgePositions(7, 4, numberOfPartitions, positions);

        var edge0to4 = addEdgePositions(0, 4, numberOfPartitions, positions);
        var edge1to5 = addEdgePositions(1, 5, numberOfPartitions, positions);
        var edge2to6 = addEdgePositions(2, 6, numberOfPartitions, positions);
        var edge3to7 = addEdgePositions(3, 7, numberOfPartitions, positions);

        // Q3 Face
        addFaceTriangles(edge0to4, edge0to1, edge1to5, edge4to5, numberOfPartitions, positions, indices);
        // Q4 Face
        addFaceTriangles(edge1to5, edge1to2, edge2to6, edge5to6, numberOfPartitions, positions, indices);
        // Q1 Face
        addFaceTriangles(edge2to6, edge2to3, edge3to7, edge6to7, numberOfPartitions, positions, indices);
        // Q2 Face
        addFaceTriangles(edge3to7, edge3to0, edge0to4, edge7to4, numberOfPartitions, positions, indices);
        // Plane z = 1
        addFaceTriangles(edge7to4.slice(0).reverse(), edge4to5, edge5to6, edge6to7.slice(0).reverse(), numberOfPartitions, positions, indices);
        // Plane z = -1
        addFaceTriangles(edge1to2, edge0to1.slice(0).reverse(), edge3to0.slice(0).reverse(), edge2to3, numberOfPartitions, positions, indices);

        var attributes = {};

        var length = positions.length;
        var i;
        var j;

        if (vertexFormat.position) {
            // Expand cube into ellipsoid and flatten values
            var radii = ellipsoid.getRadii();
            var flattenedPositions = new Array(length * 3);

            for (i = j = 0; i < length; ++i) {
                var item = positions[i];
                Cartesian3.normalize(item, item);
                Cartesian3.multiplyComponents(item, radii, item);

                flattenedPositions[j++] = item.x;
                flattenedPositions[j++] = item.y;
                flattenedPositions[j++] = item.z;
            }

            attributes.position = new GeometryAttribute({
                componentDatatype : ComponentDatatype.FLOAT,
                componentsPerAttribute : 3,
                values : flattenedPositions
            });
        }

        if (vertexFormat.st) {
            var texCoords = new Array(length * 2);
            var oneOverRadii = ellipsoid.getOneOverRadii();

            for (i = j = 0; i < length; ++i) {
                Cartesian3.multiplyComponents(positions[i], oneOverRadii, sphericalNormal);
                Cartesian3.normalize(sphericalNormal, sphericalNormal);

                texCoords[j++] = Math.atan2(sphericalNormal.y, sphericalNormal.x) * CesiumMath.ONE_OVER_TWO_PI + 0.5;
                texCoords[j++] = Math.asin(sphericalNormal.z) * CesiumMath.ONE_OVER_PI + 0.5;
            }

            attributes.st = new GeometryAttribute({
                componentDatatype : ComponentDatatype.FLOAT,
                componentsPerAttribute : 2,
                values : texCoords
            });
        }

        if (vertexFormat.normal || vertexFormat.tangent || vertexFormat.binormal) {
            var normals = new Array(length * 3);
            var tangents = new Array(length * 3);
            var binormals = new Array(length * 3);

            for (i = j = 0; i < length; ++i, j += 3) {
                ellipsoid.geodeticSurfaceNormal(positions[i], normal);
                Cartesian3.cross(Cartesian3.UNIT_Z, normal, tangent);
                Cartesian3.cross(tangent, normal, binormal);

                normals[j] = normal.x;
                normals[j + 1] = normal.y;
                normals[j + 2] = normal.z;

                tangents[j] = tangent.x;
                tangents[j + 1] = tangent.y;
                tangents[j + 2] = tangent.z;

                binormals[j] = binormal.x;
                binormals[j + 1] = binormal.y;
                binormals[j + 2] = binormal.z;
            }

            if (vertexFormat.normal) {
                attributes.normal = new GeometryAttribute({
                    componentDatatype : ComponentDatatype.FLOAT,
                    componentsPerAttribute : 3,
                    values : normals
                });
            }

            if (vertexFormat.tangent) {
                attributes.tangent = new GeometryAttribute({
                    componentDatatype : ComponentDatatype.FLOAT,
                    componentsPerAttribute : 3,
                    values : tangents
                });
            }

            if (vertexFormat.binormal) {
                attributes.binormal = new GeometryAttribute({
                    componentDatatype : ComponentDatatype.FLOAT,
                    componentsPerAttribute : 3,
                    values : binormals
                });
            }
        }

        /**
         * An object containing {@link GeometryAttribute} properties named after each of the
         * true values of the {@link VertexFormat} option.
         *
         * @type Object
         */
        this.attributes = attributes;

        /**
         * An array of {@link GeometryIndices} defining primitives.
         *
         * @type Array
         */
        this.indexLists = [
            new GeometryIndices({
                primitiveType : PrimitiveType.TRIANGLES,
                values : indices
            })
        ];

        /**
         * A tight-fitting bounding sphere that encloses the vertices of the geometry.
         *
         * @type BoundingSphere
         */
        this.boundingSphere = BoundingSphere.fromEllipsoid(ellipsoid);

        /**
         * The 4x4 transformation matrix that transforms the geometry from model to world coordinates.
         * When this is the identity matrix, the geometry is drawn in world coordinates, i.e., Earth's WGS84 coordinates.
         * Local reference frames can be used by providing a different transformation matrix, like that returned
         * by {@link Transforms.eastNorthUpToFixedFrame}.
         *
         * @type Matrix4
         *
         * @see Transforms.eastNorthUpToFixedFrame
         */
        this.modelMatrix = defaultValue(options.modelMatrix, Matrix4.IDENTITY.clone());

        /**
         * DOC_TBA
         */
        this.pickData = options.pickData;
    };

    var scratchDirection = new Cartesian3();

    function addEdgePositions(i0, i1, numberOfPartitions, positions) {
        var indices = [];
        indices[0] = i0;
        indices[2 + (numberOfPartitions - 1) - 1] = i1;

        var origin = positions[i0];
        var direction = Cartesian3.subtract(positions[i1], positions[i0], scratchDirection);

        for ( var i = 1; i < numberOfPartitions; ++i) {
            var delta = i / numberOfPartitions;
            var position = Cartesian3.multiplyByScalar(direction, delta);
            Cartesian3.add(origin, position, position);

            indices[i] = positions.length;
            positions.push(position);
        }

        return indices;
    }

    var scratchX = new Cartesian3();
    var scratchY = new Cartesian3();
    var scratchOffsetX = new Cartesian3();
    var scratchOffsetY = new Cartesian3();

    function addFaceTriangles(leftBottomToTop, bottomLeftToRight, rightBottomToTop, topLeftToRight, numberOfPartitions, positions, indices) {
        var origin = positions[bottomLeftToRight[0]];
        var x = Cartesian3.subtract(positions[bottomLeftToRight[bottomLeftToRight.length - 1]], origin, scratchX);
        var y = Cartesian3.subtract(positions[topLeftToRight[0]], origin, scratchY);

        var bottomIndicesBuffer = [];
        var topIndicesBuffer = [];

        var bottomIndices = bottomLeftToRight;
        var topIndices = topIndicesBuffer;

        for ( var j = 1; j <= numberOfPartitions; ++j) {
            if (j !== numberOfPartitions) {
                if (j !== 1) {
                    //
                    // This copy could be avoided by ping ponging buffers.
                    //
                    bottomIndicesBuffer = topIndicesBuffer.slice(0);
                    bottomIndices = bottomIndicesBuffer;
                }

                topIndicesBuffer[0] = leftBottomToTop[j];
                topIndicesBuffer[numberOfPartitions] = rightBottomToTop[j];

                var deltaY = j / numberOfPartitions;
                var offsetY = Cartesian3.multiplyByScalar(y, deltaY, scratchOffsetY);

                for ( var i = 1; i < numberOfPartitions; ++i) {
                    var deltaX = i / numberOfPartitions;
                    var offsetX = Cartesian3.multiplyByScalar(x, deltaX, scratchOffsetX);
                    var position = Cartesian3.add(origin, offsetX);
                    Cartesian3.add(position, offsetY, position);

                    topIndicesBuffer[i] = positions.length;
                    positions.push(position);
                }
            } else {
                if (j !== 1) {
                    bottomIndices = topIndicesBuffer;
                }
                topIndices = topLeftToRight;
            }

            for ( var k = 0; k < numberOfPartitions; ++k) {
                indices.push(bottomIndices[k]);
                indices.push(bottomIndices[k + 1]);
                indices.push(topIndices[k + 1]);

                indices.push(bottomIndices[k]);
                indices.push(topIndices[k + 1]);
                indices.push(topIndices[k]);
            }
        }
    }

    return EllipsoidGeometry;
});<commit_msg>Updates based on review.<commit_after>/*global define*/
define([
        './defaultValue',
        './DeveloperError',
        './Cartesian3',
        './Math',
        './Matrix4',
        './Ellipsoid',
        './ComponentDatatype',
        './PrimitiveType',
        './BoundingSphere',
        './GeometryAttribute',
        './GeometryIndices',
        './VertexFormat'
    ], function(
        defaultValue,
        DeveloperError,
        Cartesian3,
        CesiumMath,
        Matrix4,
        Ellipsoid,
        ComponentDatatype,
        PrimitiveType,
        BoundingSphere,
        GeometryAttribute,
        GeometryIndices,
        VertexFormat) {
    "use strict";

    var scratchDirection = new Cartesian3();

    function addEdgePositions(i0, i1, numberOfPartitions, positions) {
        var indices = [];
        indices[0] = i0;
        indices[2 + (numberOfPartitions - 1) - 1] = i1;

        var origin = positions[i0];
        var direction = Cartesian3.subtract(positions[i1], positions[i0], scratchDirection);

        for ( var i = 1; i < numberOfPartitions; ++i) {
            var delta = i / numberOfPartitions;
            var position = Cartesian3.multiplyByScalar(direction, delta);
            Cartesian3.add(origin, position, position);

            indices[i] = positions.length;
            positions.push(position);
        }

        return indices;
    }

    var scratchX = new Cartesian3();
    var scratchY = new Cartesian3();
    var scratchOffsetX = new Cartesian3();
    var scratchOffsetY = new Cartesian3();

    function addFaceTriangles(leftBottomToTop, bottomLeftToRight, rightBottomToTop, topLeftToRight, numberOfPartitions, positions, indices) {
        var origin = positions[bottomLeftToRight[0]];
        var x = Cartesian3.subtract(positions[bottomLeftToRight[bottomLeftToRight.length - 1]], origin, scratchX);
        var y = Cartesian3.subtract(positions[topLeftToRight[0]], origin, scratchY);

        var bottomIndicesBuffer = [];
        var topIndicesBuffer = [];

        var bottomIndices = bottomLeftToRight;
        var topIndices = topIndicesBuffer;

        for ( var j = 1; j <= numberOfPartitions; ++j) {
            if (j !== numberOfPartitions) {
                if (j !== 1) {
                    //
                    // This copy could be avoided by ping ponging buffers.
                    //
                    bottomIndicesBuffer = topIndicesBuffer.slice(0);
                    bottomIndices = bottomIndicesBuffer;
                }

                topIndicesBuffer[0] = leftBottomToTop[j];
                topIndicesBuffer[numberOfPartitions] = rightBottomToTop[j];

                var deltaY = j / numberOfPartitions;
                var offsetY = Cartesian3.multiplyByScalar(y, deltaY, scratchOffsetY);

                for ( var i = 1; i < numberOfPartitions; ++i) {
                    var deltaX = i / numberOfPartitions;
                    var offsetX = Cartesian3.multiplyByScalar(x, deltaX, scratchOffsetX);
                    var position = Cartesian3.add(origin, offsetX);
                    Cartesian3.add(position, offsetY, position);

                    topIndicesBuffer[i] = positions.length;
                    positions.push(position);
                }
            } else {
                if (j !== 1) {
                    bottomIndices = topIndicesBuffer;
                }
                topIndices = topLeftToRight;
            }

            for ( var k = 0; k < numberOfPartitions; ++k) {
                indices.push(bottomIndices[k]);
                indices.push(bottomIndices[k + 1]);
                indices.push(topIndices[k + 1]);

                indices.push(bottomIndices[k]);
                indices.push(topIndices[k + 1]);
                indices.push(topIndices[k]);
            }
        }
    }

    var sphericalNormal = new Cartesian3();
    var normal = new Cartesian3();
    var tangent = new Cartesian3();
    var binormal = new Cartesian3();

    /**
     * Creates vertices and indices for an ellipsoid centered at the origin.
     *
     * @alias EllipsoidGeometry
     * @constructor
     *
     * @param {Ellipsoid} [options.ellipsoi=Ellipsoid.UNIT_SPHERE] The ellipsoid used to create vertex attributes.
     * @param {Number} [options.numberOfPartitions=32] The number of times to partition the ellipsoid in a plane formed by two radii in a single quadrant.
     * @param {VertexFormat} [options.vertexFormat=VertexFormat.DEFAULT] The vertex attributes to be computed.
     * @param {Matrix4} [options.modelMatrix] The model matrix for this ellipsoid.
     * @param {DOC_TBA} [options.pickData] DOC_TBA
     *
     * @exception {DeveloperError} options.numberOfPartitions must be greater than zero.
     *
     * @example
     * var ellipsoid = new EllipsoidGeometry({
     *     vertexFormat : VertexFormat.POSITION_ONLY,
     *     ellipsoid : new Ellipsoid(1000000.0, 500000.0, 500000.0),
     *     modelMatrix : Transforms.eastNorthUpToFixedFrame(center)
     * });
     */
    var EllipsoidGeometry = function(options) {
        options = defaultValue(options, defaultValue.EMPTY_OBJECT);

        var ellipsoid = defaultValue(options.ellipsoid, Ellipsoid.UNIT_SPHERE);
        var numberOfPartitions = defaultValue(options.numberOfPartitions, 32);

        var vertexFormat = defaultValue(options.vertexFormat, VertexFormat.DEFAULT);

        if (numberOfPartitions <= 0) {
            throw new DeveloperError('options.numberOfPartitions must be greater than zero.');
        }

        var positions = [];
        var indices = [];

        //
        // Initial cube.  In the plane, z = -1:
        //
        //                   +y
        //                    |
        //             Q2     * p3     Q1
        //                  / | \
        //              p0 *--+--* p2   +x
        //                  \ | /
        //             Q3     * p1     Q4
        //                    |
        //
        // Similarly, p4 to p7 are in the plane z = 1.
        //
        positions.push(new Cartesian3(-1, 0, -1));
        positions.push(new Cartesian3(0, -1, -1));
        positions.push(new Cartesian3(1, 0, -1));
        positions.push(new Cartesian3(0, 1, -1));
        positions.push(new Cartesian3(-1, 0, 1));
        positions.push(new Cartesian3(0, -1, 1));
        positions.push(new Cartesian3(1, 0, 1));
        positions.push(new Cartesian3(0, 1, 1));

        //
        // Edges
        //
        // 0 -> 1, 1 -> 2, 2 -> 3, 3 -> 0.  Plane z = -1
        // 4 -> 5, 5 -> 6, 6 -> 7, 7 -> 4.  Plane z = 1
        // 0 -> 4, 1 -> 5, 2 -> 6, 3 -> 7.  From plane z = -1 to plane z - 1
        //
        var edge0to1 = addEdgePositions(0, 1, numberOfPartitions, positions);
        var edge1to2 = addEdgePositions(1, 2, numberOfPartitions, positions);
        var edge2to3 = addEdgePositions(2, 3, numberOfPartitions, positions);
        var edge3to0 = addEdgePositions(3, 0, numberOfPartitions, positions);

        var edge4to5 = addEdgePositions(4, 5, numberOfPartitions, positions);
        var edge5to6 = addEdgePositions(5, 6, numberOfPartitions, positions);
        var edge6to7 = addEdgePositions(6, 7, numberOfPartitions, positions);
        var edge7to4 = addEdgePositions(7, 4, numberOfPartitions, positions);

        var edge0to4 = addEdgePositions(0, 4, numberOfPartitions, positions);
        var edge1to5 = addEdgePositions(1, 5, numberOfPartitions, positions);
        var edge2to6 = addEdgePositions(2, 6, numberOfPartitions, positions);
        var edge3to7 = addEdgePositions(3, 7, numberOfPartitions, positions);

        // Q3 Face
        addFaceTriangles(edge0to4, edge0to1, edge1to5, edge4to5, numberOfPartitions, positions, indices);
        // Q4 Face
        addFaceTriangles(edge1to5, edge1to2, edge2to6, edge5to6, numberOfPartitions, positions, indices);
        // Q1 Face
        addFaceTriangles(edge2to6, edge2to3, edge3to7, edge6to7, numberOfPartitions, positions, indices);
        // Q2 Face
        addFaceTriangles(edge3to7, edge3to0, edge0to4, edge7to4, numberOfPartitions, positions, indices);
        // Plane z = 1
        addFaceTriangles(edge7to4.slice(0).reverse(), edge4to5, edge5to6, edge6to7.slice(0).reverse(), numberOfPartitions, positions, indices);
        // Plane z = -1
        addFaceTriangles(edge1to2, edge0to1.slice(0).reverse(), edge3to0.slice(0).reverse(), edge2to3, numberOfPartitions, positions, indices);

        var attributes = {};

        var length = positions.length;
        var i;
        var j;

        if (vertexFormat.position) {
            // Expand cube into ellipsoid and flatten values
            var radii = ellipsoid.getRadii();
            var flattenedPositions = new Array(length * 3);

            for (i = j = 0; i < length; ++i) {
                var item = positions[i];
                Cartesian3.normalize(item, item);
                Cartesian3.multiplyComponents(item, radii, item);

                flattenedPositions[j++] = item.x;
                flattenedPositions[j++] = item.y;
                flattenedPositions[j++] = item.z;
            }

            attributes.position = new GeometryAttribute({
                componentDatatype : ComponentDatatype.FLOAT,
                componentsPerAttribute : 3,
                values : flattenedPositions
            });
        }

        if (vertexFormat.st) {
            var texCoords = new Array(length * 2);
            var oneOverRadii = ellipsoid.getOneOverRadii();

            for (i = j = 0; i < length; ++i) {
                Cartesian3.multiplyComponents(positions[i], oneOverRadii, sphericalNormal);
                Cartesian3.normalize(sphericalNormal, sphericalNormal);

                texCoords[j++] = Math.atan2(sphericalNormal.y, sphericalNormal.x) * CesiumMath.ONE_OVER_TWO_PI + 0.5;
                texCoords[j++] = Math.asin(sphericalNormal.z) * CesiumMath.ONE_OVER_PI + 0.5;
            }

            attributes.st = new GeometryAttribute({
                componentDatatype : ComponentDatatype.FLOAT,
                componentsPerAttribute : 2,
                values : texCoords
            });
        }

        if (vertexFormat.normal || vertexFormat.tangent || vertexFormat.binormal) {
            var normals = (vertexFormat.normal) ? new Array(length * 3) : undefined;
            var tangents = (vertexFormat.tangent) ? new Array(length * 3) : undefined;
            var binormals = (vertexFormat.binormal) ? new Array(length * 3) : undefined;

            for (i = j = 0; i < length; ++i, j += 3) {
                ellipsoid.geodeticSurfaceNormal(positions[i], normal);
                Cartesian3.cross(Cartesian3.UNIT_Z, normal, tangent);
                Cartesian3.cross(tangent, normal, binormal);

                if (vertexFormat.normal) {
                    normals[j] = normal.x;
                    normals[j + 1] = normal.y;
                    normals[j + 2] = normal.z;
                }

                if (vertexFormat.tangent) {
                    tangents[j] = tangent.x;
                    tangents[j + 1] = tangent.y;
                    tangents[j + 2] = tangent.z;
                }

                if (vertexFormat.binormal) {
                    binormals[j] = binormal.x;
                    binormals[j + 1] = binormal.y;
                    binormals[j + 2] = binormal.z;
                }
            }

            if (vertexFormat.normal) {
                attributes.normal = new GeometryAttribute({
                    componentDatatype : ComponentDatatype.FLOAT,
                    componentsPerAttribute : 3,
                    values : normals
                });
            }

            if (vertexFormat.tangent) {
                attributes.tangent = new GeometryAttribute({
                    componentDatatype : ComponentDatatype.FLOAT,
                    componentsPerAttribute : 3,
                    values : tangents
                });
            }

            if (vertexFormat.binormal) {
                attributes.binormal = new GeometryAttribute({
                    componentDatatype : ComponentDatatype.FLOAT,
                    componentsPerAttribute : 3,
                    values : binormals
                });
            }
        }

        /**
         * An object containing {@link GeometryAttribute} properties named after each of the
         * true values of the {@link VertexFormat} option.
         *
         * @type Object
         */
        this.attributes = attributes;

        /**
         * An array of {@link GeometryIndices} defining primitives.
         *
         * @type Array
         */
        this.indexLists = [
            new GeometryIndices({
                primitiveType : PrimitiveType.TRIANGLES,
                values : indices
            })
        ];

        /**
         * A tight-fitting bounding sphere that encloses the vertices of the geometry.
         *
         * @type BoundingSphere
         */
        this.boundingSphere = BoundingSphere.fromEllipsoid(ellipsoid);

        /**
         * The 4x4 transformation matrix that transforms the geometry from model to world coordinates.
         * When this is the identity matrix, the geometry is drawn in world coordinates, i.e., Earth's WGS84 coordinates.
         * Local reference frames can be used by providing a different transformation matrix, like that returned
         * by {@link Transforms.eastNorthUpToFixedFrame}.
         *
         * @type Matrix4
         *
         * @see Transforms.eastNorthUpToFixedFrame
         */
        this.modelMatrix = defaultValue(options.modelMatrix, Matrix4.IDENTITY.clone());

        /**
         * DOC_TBA
         */
        this.pickData = options.pickData;
    };

    return EllipsoidGeometry;
});<|endoftext|>


<commit_before>define( [
            'dojo/_base/declare',
            'dojo/_base/lang',
            'dojo/_base/array',
            'dojo/_base/url',
            'JBrowse/Store/NCList',
            'JBrowse/Store/SeqFeature/NCList',
            'JBrowse/Store/SeqFeature',
            'JBrowse/Store/DeferredStatsMixin',
            'JBrowse/Store/DeferredFeaturesMixin',
            'JBrowse/Util',
            'JBrowse/Model/XHRBlob',
            'JBrowse/Model/ArrayRepr',
            './GFF3/GFF3Parser'
        ],
        function(
            declare,
            lang,
            array,
            urlObj,
            NCList,
            NCListStore,
            SeqFeatureStore,
            DeferredStatsMixin,
            DeferredFeaturesMixin,
            Util,
            XHRBlob,
            ArrayRepr,
            GFF3Parser
        ) {

return declare([ NCListStore ],

 /**
  * @lends JBrowse.Store.SeqFeature.GFF3
  */
{

    //    "-chains-": { constructor: "manual" },
    constructor: function( args ) {
        // had to push some stuff that I'd like in constructor into _load instead, because need before rest of _load, but
        //   _load is getting called at end of NCList (superclass) constructor, so before this constructor called
        //   tried using manual constructor chaining, but this.inherited(args) didn't actually trigger
        //   recursive superclass chaining, just the first parent (NCList) constructor.
        //   Therefore SeqFeature, DeferredFeatureMixin, etc. weren't getting called, and manually
        //   calling every superclass/mixin would be asking for trouble later on...
        //
        // this.inherited(arguments);
    },

    _load: function() {
        var args = this.args;
        this.data = args.blob;
        this.name = args.name || ( this.data.url && new urlObj( this.data.url ).path.replace(/^.+\//,'') ) || 'anonymous';
        console.log("called GFF3 load");

        // load and index the gff3 here
        var store = this;
        if (this.data.blob instanceof File)  {
            var fil = this.data.blob;
            var reader = new FileReader();
            reader.onload = function(e)  {
                var content = e.target.result;
                console.log( "In GFF3 store, got the file: " + fil.name + ", type: " + fil.type + ", size: " + fil.size);
                store.loadContent(content);
            };
            reader.readAsText(fil);
            console.log("called reader.readAsText");
        }
        else if (this.data.url) {
            var gffurl = this.data.url;
            dojo.xhrGet( {
                url: gffurl,
                handleAs: "text",
                load: function(response, ioArgs) {
                    console.log( "In GFF3 store, got data from URL: ", gffurl);
                    store.loadContent(response);
                },
                error: function(response, ioArgs) {
                    console.error(response);
                    console.error(response.stack);
                }
            } );
        }
    },

    loadContent: function(content)  {
        var store = this;
        console.log("   content start: " + content.substr(0, 50));
        var gparser = new GFF3Parser();
        var gff3_json = gparser.parse(content);
        console.log("parsed GFF3:");
        console.log(gff3_json);
        var results = this._gff3toJbrowseJson(gff3_json, store.args);
        console.log("converted GFF3:");
        console.log(results);
        var trackInfo = results.trackInfo;
        var featArray = results.featArray;
        store.attrs = new ArrayRepr(trackInfo.intervals.classes);
        store.nclist.fill(featArray, store.attrs);

        // should also calculate the feature density (avg features per
        // bp) and store it in:
        //       store._stats.featureDensity
        store.globalStats.featureCount = trackInfo.featureCount;
        // average feature density per base
        store.globalStats.featureDensity = trackInfo.featureCount / store.refSeq.length;
        console.log("feature count: " + store.globalStats.featureCount);

        // when the store is ready to handle requests for stats and features, run:
        store._deferred.features.resolve({success: true});
        store._deferred.stats.resolve({success: true});
    },

    _gff3toJbrowseJson: function(parsedGFF3, params)  {
        var trackInfo = {};
        trackInfo["intervals"] = {};

        trackInfo["histograms"] = {
            "stats" : [
                {
                    "basesPerBin" : "1000000",
                    "max" : 1,
                    "mean" : 1
                }
            ],
            "meta" : [
                {
                    "basesPerBin" : "1000000",
                    "arrayParams" : {
                        "length" : 1,
                        "chunkSize" : 10000,
                        "urlTemplate" : "hist-1000000-{Chunk}.json"
                    }
                }
            ]
        };
        trackInfo["intervals"]["classes"] =
            [ {
                  "isArrayAttr" : {
                      "Subfeatures" : 1
                  },
                  "attributes" : [ "Start", "End", "Strand", "Source", "Phase", "Type", "Score", "Id", "Name", "Subfeatures" ]
              }, {
                  "isArrayAttr" : {
                  },
                  "attributes" : [ "Start", "End", "Strand", "Source", "Phase", "Type", "Score", "Id", "Name", "Subfeatures" ]
              }, {
                  "isArrayAttr" : {
                      "Sublist" : 1
                  },
                  "attributes" : [ "Start", "End", "Chunk" ]
              } ];

        trackInfo["intervals"]["lazyClass"] = 2;
        trackInfo["intervals"]["urlTemplate"] = "lf-{Chunk}.json";
        trackInfo["formatVersion"] = 1;

        var featureCount = 0;

        // first check if we have only one feature, in which case parsedData is an object not an array
        if ( typeof parsedGFF3.parsedData.length == 'undefined' ){
            trackInfo["featureCount"] = 1;
        }
        else {
            trackInfo["featureCount"] = parsedGFF3.parsedData.length;
        }

        // loop through each top level feature in parsedGFF3 and make array of featureArrays
        var allGff3Features = new Array; // this is an array of featureArrays containing info for all features in parsedGFF3
	for( var k = 0; k < parsedGFF3.parsedData.length; k++ ) {
	    var jbrowseFeat = this._convertParsedGFF3JsonToFeatureArray( parsedGFF3.parsedData[k] );
	    if (!! jbrowseFeat)  {
		for (l = 0; l < jbrowseFeat.length; l++){
		    allGff3Features.push( jbrowseFeat[l] );
		}
	    }
	}

        return { trackInfo:  trackInfo, featArray: allGff3Features };

    },

    /**
     *  takes one parsed GFF3 feature and all of its subfeatures (children/grandchildren/great-grandchildren/...)
     *  from a parsed GFF3 data struct (returned from GFF3toJson()), and returns a a two-level feature array for
     *  the lowest and next-lowest level. For example, given a data struct for a parsed gene/mRNA/exon GFF3
     *  it would return a two-level feature array for the all mRNA features and their exons.
     */
    _convertParsedGFF3JsonToFeatureArray: function(parsedGff3) {
        var featureArray = new Array();

        // figure out how many levels we are dealing with here, b/c we need to return
        // only the data for the lowest contained in the next lowest level, since Webapollo
        // can only deal with two-level features.
        var gff3Depth = this._determineParsedGff3Depth( parsedGff3 );

        // okay, we know the depth, go down to gff3Depth - 1, and pull the features at this
        // depth and their children.

        // get parents in parsedGff3.parsedData at depth - 1
        var theseParents = this._getFeaturesAtGivenDepth(parsedGff3, gff3Depth - 1);
        if (! theseParents || theseParents.length < 1)  {
            return featureArray;
        }

	for ( j = 0; j < theseParents.length; j++ ){
	    var thisItem = new Array();
	    // set to zero because we want jbrowse/webapollo to look at the first entry in attr array to
	    // look up what each of the following fields in thisItem mean
	    thisItem[0] = 0;

	    console.log("j: " + j);
	    //
	    // set parent info
	    //
	    var rawdata = theseParents[j].data[0].rawdata;
	    thisItem[1] = parseInt(rawdata[3])-1; // set start (-1 for converting from 1-based to 0-based)
	    thisItem[2] = parseInt(rawdata[4]); // set end
	    thisItem[3] = rawdata[6]; // set strand
	    thisItem[4] = rawdata[1]; // set source
	    thisItem[5] = rawdata[7]; // set phase
	    thisItem[6] = rawdata[2]; // set type
	    thisItem[7] = rawdata[5]; // set score
	    thisItem[8] = theseParents[j].ID; // set id

	    var parsedNinthField = this._parsedNinthGff3Field(rawdata[8]);
	    if ( !!parsedNinthField["Name"] ){
		thisItem[9] = parsedNinthField["Name"];
	    }
	    else  { thisItem[9] = null; }

	    //
	    // now set children info
	    //
	    var children = theseParents[j].children;
	    var subfeats = null; // make array for all child features
	    if ( theseParents[j].children && (theseParents[j].children.length > 0))  {
		subfeats = [];
		for (var i = 0; i < theseParents[j].children.length; i++ ){
		    var childData = theseParents[j].children[i].data[0].rawdata;
		    var subfeat = [];

		    subfeat[0] = 1; // ?
		    subfeat[1] = parseInt(childData[3])-1; // start  (-1 for converting from 1-based to 0-based)
		    subfeat[2] = parseInt(childData[4]); // end
		    subfeat[3] = childData[6]; // strand
		    subfeat[4] = childData[1]; // source
		    subfeat[5] = childData[7]; // phase
		    subfeat[6] = childData[2]; // type
		    subfeat[7] = childData[5]; // score

		    var childNinthField = this._parsedNinthGff3Field( childData[8] );
		    if ( !!childNinthField["ID"] ){
			subfeat[8] = childNinthField["ID"];
		    }
		    else  { subfeat[8] = null; }
		    if ( !!childNinthField["Name"] ){
			subfeat[9] = childNinthField["Name"];
		    }
                else  { subfeat[9] = null; }
		    subfeats[i] = subfeat;
		}
	    }
	    thisItem[10] = subfeats; // load up children

	    featureArray.push( thisItem );
	}

        return featureArray;
    },

    // recursive search of this feature to see how many levels there are,
    // helper for _convertParsedGFF3JsonToFeatureArray. This determines the
    // depth of the first feature it finds.
    _determineParsedGff3Depth: function(gffFeature) {
        var recursion_level = 0;
        var maximum_recursion_level = 20; // paranoid about infinite recursion
        var determineNumLevels = function(thisJsonFeature) {
            recursion_level++;
            if ( recursion_level > maximum_recursion_level ){
                return false;
            }
            // recurse if there there are children
            //if ( !! thisJsonFeature[0] && thisJsonFeature[0]["children"] != null && thisJsonFeature[0]["children"].length > 0 ){
            //    if ( determineNumLevels(thisJsonFeature[0]["children"][0] ) ){
            if ( thisJsonFeature.children != null && thisJsonFeature.children.length > 0 ){
                if ( determineNumLevels(thisJsonFeature.children[0]) ){
                    return true;
                }
            }
            return false;
        };
        // determineNumLevels( parsedGff3.parsedData[0] );
        determineNumLevels( gffFeature );
        return recursion_level;
    },

    // helper feature for _convertParsedGFF3JsonToFeatureArray
    // For a given top-level feature, returns descendant features at a given depth
    _getFeaturesAtGivenDepth: function(gffFeature, depth) {
        var recursion_level = 0;
	var maximum_recursion_level = 20; // paranoid about infinite recursion
        var getFeatures = function(thisJsonFeature, thisDepth, returnedFeatures) {
            if ( recursion_level > maximum_recursion_level ){
                return null;
            }
            // are we at the right depth?
            if ( recursion_level + 1 == thisDepth ){
                returnedFeatures.push( thisJsonFeature );
            }
            else if ( thisJsonFeature.children != null && thisJsonFeature.children.length > 0 ){
		recursion_level++;
		for (var m = 0; m < thisJsonFeature.children.length; m++){
                    getFeatures( thisJsonFeature.children[m], depth, returnedFeatures );
		}
            }
        };
        var results = [];
        getFeatures( gffFeature, depth, results );
        return results;
    },

    // helper feature for _convertParsedGFF3JsonToFeatureArray
    // that parsed ninth field of gff3 file
    _parsedNinthGff3Field: function(ninthField) {
        // parse info in 9th field to get name
        var ninthFieldArray = ninthField.split(";");
        var parsedNinthField = new Object;
        for (var j = 0; j < ninthFieldArray.length; j++){
            var keyVal = ninthFieldArray[j].split("=");
            parsedNinthField[ keyVal[0] ] = keyVal[1];
        }
        return parsedNinthField;
    }

});
});<commit_msg>Fixed bug in GFF3 parsing that caused errors in loading one-level (flat) features from GFF3 files.<commit_after>define( [
            'dojo/_base/declare',
            'dojo/_base/lang',
            'dojo/_base/array',
            'dojo/_base/url',
            'JBrowse/Store/NCList',
            'JBrowse/Store/SeqFeature/NCList',
            'JBrowse/Store/SeqFeature',
            'JBrowse/Store/DeferredStatsMixin',
            'JBrowse/Store/DeferredFeaturesMixin',
            'JBrowse/Util',
            'JBrowse/Model/XHRBlob',
            'JBrowse/Model/ArrayRepr',
            './GFF3/GFF3Parser'
        ],
        function(
            declare,
            lang,
            array,
            urlObj,
            NCList,
            NCListStore,
            SeqFeatureStore,
            DeferredStatsMixin,
            DeferredFeaturesMixin,
            Util,
            XHRBlob,
            ArrayRepr,
            GFF3Parser
        ) {

return declare([ NCListStore ],

 /**
  * @lends JBrowse.Store.SeqFeature.GFF3
  */
{

    //    "-chains-": { constructor: "manual" },
    constructor: function( args ) {
        // had to push some stuff that I'd like in constructor into _load instead, because need before rest of _load, but
        //   _load is getting called at end of NCList (superclass) constructor, so before this constructor called
        //   tried using manual constructor chaining, but this.inherited(args) didn't actually trigger
        //   recursive superclass chaining, just the first parent (NCList) constructor.
        //   Therefore SeqFeature, DeferredFeatureMixin, etc. weren't getting called, and manually
        //   calling every superclass/mixin would be asking for trouble later on...
        //
        // this.inherited(arguments);
    },

    _load: function() {
        var args = this.args;
        this.data = args.blob;
        this.name = args.name || ( this.data.url && new urlObj( this.data.url ).path.replace(/^.+\//,'') ) || 'anonymous';
        console.log("called GFF3 load");

        // load and index the gff3 here
        var store = this;
        if (this.data.blob instanceof File)  {
            var fil = this.data.blob;
            var reader = new FileReader();
            reader.onload = function(e)  {
                var content = e.target.result;
                console.log( "In GFF3 store, got the file: " + fil.name + ", type: " + fil.type + ", size: " + fil.size);
                store.loadContent(content);
            };
            reader.readAsText(fil);
            console.log("called reader.readAsText");
        }
        else if (this.data.url) {
            var gffurl = this.data.url;
            dojo.xhrGet( {
                url: gffurl,
                handleAs: "text",
                load: function(response, ioArgs) {
                    console.log( "In GFF3 store, got data from URL: ", gffurl);
                    store.loadContent(response);
                },
                error: function(response, ioArgs) {
                    console.error(response);
                    console.error(response.stack);
                }
            } );
        }
    },

    loadContent: function(content)  {
        var store = this;
        console.log("   content start: " + content.substr(0, 50));
        var gparser = new GFF3Parser();
        var gff3_json = gparser.parse(content);
        console.log("parsed GFF3:");
        console.log(gff3_json);
        var results = this._gff3toJbrowseJson(gff3_json, store.args);
        console.log("converted GFF3:");
        console.log(results);
        var trackInfo = results.trackInfo;
        var featArray = results.featArray;
        store.attrs = new ArrayRepr(trackInfo.intervals.classes);
        store.nclist.fill(featArray, store.attrs);

        // should also calculate the feature density (avg features per
        // bp) and store it in:
        //       store._stats.featureDensity
        store.globalStats.featureCount = trackInfo.featureCount;
        // average feature density per base
        store.globalStats.featureDensity = trackInfo.featureCount / store.refSeq.length;
        console.log("feature count: " + store.globalStats.featureCount);

        // when the store is ready to handle requests for stats and features, run:
        store._deferred.features.resolve({success: true});
        store._deferred.stats.resolve({success: true});
    },

    _gff3toJbrowseJson: function(parsedGFF3, params)  {
        var trackInfo = {};
        trackInfo["intervals"] = {};

        trackInfo["histograms"] = {
            "stats" : [
                {
                    "basesPerBin" : "1000000",
                    "max" : 1,
                    "mean" : 1
                }
            ],
            "meta" : [
                {
                    "basesPerBin" : "1000000",
                    "arrayParams" : {
                        "length" : 1,
                        "chunkSize" : 10000,
                        "urlTemplate" : "hist-1000000-{Chunk}.json"
                    }
                }
            ]
        };
        trackInfo["intervals"]["classes"] =
            [ {
                  "isArrayAttr" : {
                      "Subfeatures" : 1
                  },
                  "attributes" : [ "Start", "End", "Strand", "Source", "Phase", "Type", "Score", "Id", "Name", "Subfeatures" ]
              }, {
                  "isArrayAttr" : {
                  },
                  "attributes" : [ "Start", "End", "Strand", "Source", "Phase", "Type", "Score", "Id", "Name", "Subfeatures" ]
              }, {
                  "isArrayAttr" : {
                      "Sublist" : 1
                  },
                  "attributes" : [ "Start", "End", "Chunk" ]
              } ];

        trackInfo["intervals"]["lazyClass"] = 2;
        trackInfo["intervals"]["urlTemplate"] = "lf-{Chunk}.json";
        trackInfo["formatVersion"] = 1;

        var featureCount = 0;

        // first check if we have only one feature, in which case parsedData is an object not an array
        if ( typeof parsedGFF3.parsedData.length == 'undefined' ){
            trackInfo["featureCount"] = 1;
        }
        else {
            trackInfo["featureCount"] = parsedGFF3.parsedData.length;
        }

        // loop through each top level feature in parsedGFF3 and make array of featureArrays
        var allGff3Features = new Array; // this is an array of featureArrays containing info for all features in parsedGFF3
	for( var k = 0; k < parsedGFF3.parsedData.length; k++ ) {
	    var jbrowseFeat = this._convertParsedGFF3JsonToFeatureArray( parsedGFF3.parsedData[k] );
	    if (!! jbrowseFeat)  {
		for (l = 0; l < jbrowseFeat.length; l++){
		    allGff3Features.push( jbrowseFeat[l] );
		}
	    }
	}

        return { trackInfo:  trackInfo, featArray: allGff3Features };

    },

    /**
     *  takes one parsed GFF3 feature and all of its subfeatures (children/grandchildren/great-grandchildren/...)
     *  from a parsed GFF3 data struct (returned from GFF3toJson()), and returns a a two-level feature array for
     *  the lowest and next-lowest level. For example, given a data struct for a parsed gene/mRNA/exon GFF3
     *  it would return a two-level feature array for the all mRNA features and their exons.
     */
    _convertParsedGFF3JsonToFeatureArray: function(parsedGff3) {
        var featureArray = new Array();

        // figure out how many levels we are dealing with here, b/c we need to return
        // only the data for the lowest contained in the next lowest level, since Webapollo
        // can only deal with two-level features.
        var gff3Depth = this._determineParsedGff3Depth( parsedGff3 );

        // okay, we know the depth, go down to gff3Depth - 1, and pull the features at this
        // depth and their children.

        // get parents in parsedGff3.parsedData at depth - 1
        var theseParents;
        if (gff3Depth == 1)  {  theseParents = [ parsedGff3 ]; }
        else  { theseParents = this._getFeaturesAtGivenDepth(parsedGff3, gff3Depth - 1); }
        if (! theseParents || theseParents.length < 1)  {
            return featureArray;
        }

	for ( j = 0; j < theseParents.length; j++ ){
	    var thisItem = new Array();
	    // set to zero because we want jbrowse/webapollo to look at the first entry in attr array to
	    // look up what each of the following fields in thisItem mean
	    thisItem[0] = 0;

	    console.log("j: " + j);
	    //
	    // set parent info
	    //
	    var rawdata = theseParents[j].data[0].rawdata;
	    thisItem[1] = parseInt(rawdata[3])-1; // set start (-1 for converting from 1-based to 0-based)
	    thisItem[2] = parseInt(rawdata[4]); // set end
	    thisItem[3] = rawdata[6]; // set strand
	    thisItem[4] = rawdata[1]; // set source
	    thisItem[5] = rawdata[7]; // set phase
	    thisItem[6] = rawdata[2]; // set type
	    thisItem[7] = rawdata[5]; // set score
	    thisItem[8] = theseParents[j].ID; // set id

	    var parsedNinthField = this._parsedNinthGff3Field(rawdata[8]);
	    if ( !!parsedNinthField["Name"] ){
		thisItem[9] = parsedNinthField["Name"];
	    }
	    else  { thisItem[9] = null; }

	    //
	    // now set children info
	    //
	    var children = theseParents[j].children;
	    var subfeats = null; // make array for all child features
	    if ( theseParents[j].children && (theseParents[j].children.length > 0))  {
		subfeats = [];
		for (var i = 0; i < theseParents[j].children.length; i++ ){
		    var childData = theseParents[j].children[i].data[0].rawdata;
		    var subfeat = [];

		    subfeat[0] = 1; // ?
		    subfeat[1] = parseInt(childData[3])-1; // start  (-1 for converting from 1-based to 0-based)
		    subfeat[2] = parseInt(childData[4]); // end
		    subfeat[3] = childData[6]; // strand
		    subfeat[4] = childData[1]; // source
		    subfeat[5] = childData[7]; // phase
		    subfeat[6] = childData[2]; // type
		    subfeat[7] = childData[5]; // score

		    var childNinthField = this._parsedNinthGff3Field( childData[8] );
		    if ( !!childNinthField["ID"] ){
			subfeat[8] = childNinthField["ID"];
		    }
		    else  { subfeat[8] = null; }
		    if ( !!childNinthField["Name"] ){
			subfeat[9] = childNinthField["Name"];
		    }
                else  { subfeat[9] = null; }
		    subfeats[i] = subfeat;
		}
	    }
	    thisItem[10] = subfeats; // load up children

	    featureArray.push( thisItem );
	}

        return featureArray;
    },

    // recursive search of this feature to see how many levels there are,
    // helper for _convertParsedGFF3JsonToFeatureArray. This determines the
    // depth of the first feature it finds.
    _determineParsedGff3Depth: function(gffFeature) {
        var recursion_level = 0;
        var maximum_recursion_level = 20; // paranoid about infinite recursion
        var determineNumLevels = function(thisJsonFeature) {
            recursion_level++;
            if ( recursion_level > maximum_recursion_level ){
                return false;
            }
            // recurse if there there are children
            //if ( !! thisJsonFeature[0] && thisJsonFeature[0]["children"] != null && thisJsonFeature[0]["children"].length > 0 ){
            //    if ( determineNumLevels(thisJsonFeature[0]["children"][0] ) ){
            if ( thisJsonFeature.children != null && thisJsonFeature.children.length > 0 ){
                if ( determineNumLevels(thisJsonFeature.children[0]) ){
                    return true;
                }
            }
            return false;
        };
        // determineNumLevels( parsedGff3.parsedData[0] );
        determineNumLevels( gffFeature );
        return recursion_level;
    },

    // helper feature for _convertParsedGFF3JsonToFeatureArray
    // For a given top-level feature, returns descendant features at a given depth
    _getFeaturesAtGivenDepth: function(gffFeature, depth) {
        var recursion_level = 0;
	var maximum_recursion_level = 20; // paranoid about infinite recursion
        var getFeatures = function(thisJsonFeature, thisDepth, returnedFeatures) {
            if ( recursion_level > maximum_recursion_level ){
                return null;
            }
            // are we at the right depth?
            if ( recursion_level + 1 == thisDepth ){
                returnedFeatures.push( thisJsonFeature );
            }
            else if ( thisJsonFeature.children != null && thisJsonFeature.children.length > 0 ){
		recursion_level++;
		for (var m = 0; m < thisJsonFeature.children.length; m++){
                    getFeatures( thisJsonFeature.children[m], depth, returnedFeatures );
		}
            }
        };
        var results = [];
        getFeatures( gffFeature, depth, results );
        return results;
    },

    // helper feature for _convertParsedGFF3JsonToFeatureArray
    // that parsed ninth field of gff3 file
    _parsedNinthGff3Field: function(ninthField) {
        // parse info in 9th field to get name
        var ninthFieldArray = ninthField.split(";");
        var parsedNinthField = new Object;
        for (var j = 0; j < ninthFieldArray.length; j++){
            var keyVal = ninthFieldArray[j].split("=");
            parsedNinthField[ keyVal[0] ] = keyVal[1];
        }
        return parsedNinthField;
    }

});
});<|endoftext|>