<commit_before>var diddy = new Object();

diddy.systemMillisecs=function(){
	return new Date().getTime();
};

diddy.flushKeys=function(){
	for( var i = 0; i < 512; ++i )
	{
		bb_input_device.keyStates[i]=0;
	}
};

diddy.getUpdateRate=function(){
	return bb_app_device.updateRate;
};

diddy.showMouse=function()
{
	document.getElementById("GameCanvas").style.cursor='default';
}

diddy.setMouse=function(x, y)
{

}
diddy.showKeyboard=function()
{
}
diddy.launchBrowser=function(address)
{
}
diddy.launchEmail=function(email, subject, text)
{
}

diddy.hideMouse=function()
{
	document.getElementById("GameCanvas").style.cursor= "url('data:image/cur;base64,AAACAAEAICAAAAAAAACoEAAAFgAAACgAAAAgAAAAQAAAAAEAIAAAAAAAgBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA55ZXBgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOeWVxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADnllcGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////9////////////////////+////////f/////////8%3D'), auto";
}
<commit_msg>Added functionality for LaunchBrowser and LaunchEmail for HTML5. LaunchBrowser may get stopped by popup blockers!<commit_after>var diddy = new Object();

diddy.systemMillisecs=function(){
	return new Date().getTime();
};

diddy.flushKeys=function(){
	for( var i = 0; i < 512; ++i )
	{
		bb_input_device.keyStates[i]=0;
	}
};

diddy.getUpdateRate=function(){
	return bb_app_device.updateRate;
};

diddy.showMouse=function()
{
	document.getElementById("GameCanvas").style.cursor='default';
}

diddy.setMouse=function(x, y)
{

}
diddy.showKeyboard=function()
{
}
diddy.launchBrowser=function(address)
{
	window.open(address);
}
diddy.launchEmail=function(email, subject, text)
{
	location.href="mailto:"+email+"&subject="+subject+"&body="+text+"";
}

diddy.hideMouse=function()
{
	document.getElementById("GameCanvas").style.cursor= "url('data:image/cur;base64,AAACAAEAICAAAAAAAACoEAAAFgAAACgAAAAgAAAAQAAAAAEAIAAAAAAAgBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA55ZXBgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOeWVxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADnllcGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////9////////////////////+////////f/////////8%3D'), auto";
}
<|endoftext|>


<commit_before>// @flow
import getComputedStyle from './getComputedStyle';

export default (element: Element): boolean =>
  getComputedStyle(element).display.startsWith('table');
<commit_msg>Revert "fix: detect CSS tables"<commit_after>// @flow
import getNodeName from './getNodeName';

export default (element: Element): boolean =>
  ['table', 'td', 'th'].includes(getNodeName(element));
<|endoftext|>


<commit_before>(function process( /*RESTAPIRequest*/ request, /*RESTAPIResponse*/ response) {
    var pollId = request.pathParams.poll_id;
    var pollHelper = new x_snc_polls.PollData_Creator();

    // Validate if poll record exists
    var pollRecord = new GlideRecord("x_snc_polls_poll");
    pollRecord.get(pollId);

    var questionData = request.body.data;

    // Create question record and choices
    pollHelper.createQuestions(questionData, pollId);

    // Set response details
    response.setStatus(204);
})(request, response);
<commit_msg>Formatting<commit_after>(function process( /*RESTAPIRequest*/ request, /*RESTAPIResponse*/ response) {
	var pollId = request.pathParams.poll_id;
	var pollHelper = new x_snc_polls.PollData_Creator();

	// Validate if poll record exists
	var pollRecord = new GlideRecord("x_snc_polls_poll");
	pollRecord.get(pollId);

	var questionData = request.body.data;

	// Create question record and choices
	pollHelper.createQuestions(questionData, pollId);

	// Set response details
	response.setStatus(204);
})(request, response);
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2016-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @flow
 */

import {SecurityError, MessageError} from '../errors.js';
import type {FetchedOverride} from '../types.js';
import type {HashStream} from '../util/crypto.js';
import * as crypto from '../util/crypto.js';
import BaseFetcher from './base-fetcher.js';
import * as fsUtil from '../util/fs.js';

const through = require('through2');
const zlib = require('zlib');
const path = require('path');
const tar = require('tar');
const url = require('url');
const fs = require('fs');

export default class TarballFetcher extends BaseFetcher {
  createExtractor(mirrorPath: ?string, resolve: Function, reject: Function): {
    validateStream: HashStream,
    extractor: stream$Readable,
  } {
    const validateStream = crypto.hashStreamValidation();

    const extractor = tar.Extract({path: this.dest, strip: 1})
      .on('error', reject)
      .on('end', () => {
        const expectHash = this.hash;
        const actualHash = validateStream.getHash();
        if (!expectHash || expectHash === actualHash) {
          resolve({
            hash: actualHash,
            resolved: mirrorPath ? `${mirrorPath}#${actualHash}` : null,
          });
        } else {
          reject(new SecurityError(
            `Bad hash. Expected ${expectHash} but got ${actualHash} `,
          ));
        }
      });

    return {validateStream, extractor};
  }

  async fetchFromLocal(parts: Object): Promise<FetchedOverride> {
    let {reference: ref, config, registry} = this;

    // path to the local tarball
    let localTarball;
    let isOfflineTarball = false;

    const relativeFileLoc = parts.pathname && path.join(config.cwd, parts.pathname);
    if (relativeFileLoc && await fsUtil.exists(relativeFileLoc)) {
      // this is a reference to a file relative to the cwd
      localTarball = relativeFileLoc;
    } else {
      // generate a offline cache location
      localTarball = path.resolve(config.getOfflineMirrorPath(registry, null), ref);
      isOfflineTarball = true;
    }

    if (!(await fsUtil.exists(localTarball))) {
      throw new MessageError(`${ref}: Tarball is not in network and can't be located in cache`);
    }

    return new Promise((resolve, reject) => {
      let {validateStream, extractor} = this.createExtractor(null, resolve, reject);

      // flow gets confused with the pipe/on types chain
      const cachedStream: Object = fs.createReadStream(localTarball);

      const decompressStream = zlib.createUnzip();

      // nicer errors for corrupted compressed tarballs
      decompressStream.on('error', function(err) {
        let msg = `${err.message}. `;
        if (isOfflineTarball) {
          msg += `Mirror tarball appears to be corrupt. You can resolve this by running:\n\n` +
                 `  $ rm -rf ${localTarball}\n` +
                 '  $ kpm install --save';
        } else {
          msg += `Error decompressing ${localTarball}, it appears to be corrupt.`;
        }
        reject(new MessageError(msg));
      });

      cachedStream
        .pipe(validateStream)
        .pipe(decompressStream)
        .on('error', reject)
        .pipe(extractor);
    });
  }

  async fetchFromExternal(): Promise<FetchedOverride> {
    let {reference: ref, config, registry} = this;

    return this.config.requestManager.request({
      url: ref,
      headers: {
        'Accept-Encoding': 'gzip',
        'Accept': 'application/octet-stream',
      },
      buffer: true,
      process: (req, resolve, reject) => {
        // should we save this to the offline cache?
        const mirrorPath = config.getOfflineMirrorPath(registry, ref);
        let mirrorTarballStream;
        let overwriteResolved;
        if (mirrorPath) {
          overwriteResolved = path.relative(config.getOfflineMirrorPath(registry), mirrorPath);
          mirrorTarballStream = fs.createWriteStream(mirrorPath);
          mirrorTarballStream.on('error', reject);
        }
        const mirrorSaver = through(function(chunk, enc, callback) {
          if (mirrorTarballStream) {
            mirrorTarballStream.write(chunk, enc);
          }
          callback(null, chunk);
        });

        //
        let {validateStream, extractor} = this.createExtractor(overwriteResolved, resolve, reject);

        //
        req
          .pipe(validateStream)
          .pipe(mirrorSaver)
          .pipe(zlib.createUnzip())
          .on('error', reject)
          .pipe(extractor);
      },
    });
  }

  async _fetch(): Promise<FetchedOverride> {
    const parts = url.parse(this.reference);
    if (parts.protocol === null) {
      return this.fetchFromLocal(parts);
    } else {
      return this.fetchFromExternal();
    }
  }
}
<commit_msg>support ungzipped tarballs - fixes #260<commit_after>/**
 * Copyright (c) 2016-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @flow
 */

import {SecurityError, MessageError} from '../errors.js';
import type {FetchedOverride} from '../types.js';
import type {HashStream} from '../util/crypto.js';
import * as crypto from '../util/crypto.js';
import BaseFetcher from './base-fetcher.js';
import * as fsUtil from '../util/fs.js';

const through = require('through2');
const zlib = require('zlib');
const path = require('path');
const tar = require('tar');
const url = require('url');
const fs = require('fs');

function hasGzipHeader(chunk: Buffer): boolean {
  return chunk[0] === 0x1F && chunk[1] === 0x8B && chunk[2] === 0x08;
}

function degzipper(factory) {
  let readHeader = false;
  let isGzip = false;

  let stream = through(function (chunk, enc, callback) {
    if (!readHeader) {
      readHeader = true;
      isGzip = hasGzipHeader(chunk);
      if (isGzip) {
        factory(stream.pipe(zlib.createUnzip()));
      } else {
        factory(stream);
      }
    }

    callback(null, chunk);
  });
  return stream;
}

export default class TarballFetcher extends BaseFetcher {
  createExtractor(mirrorPath: ?string, resolve: Function, reject: Function): {
    validateStream: HashStream,
    extractor: stream$Readable,
  } {
    const validateStream = crypto.hashStreamValidation();

    const extractor = tar.Extract({path: this.dest, strip: 1})
      .on('error', reject)
      .on('end', () => {
        const expectHash = this.hash;
        const actualHash = validateStream.getHash();
        if (!expectHash || expectHash === actualHash) {
          resolve({
            hash: actualHash,
            resolved: mirrorPath ? `${mirrorPath}#${actualHash}` : null,
          });
        } else {
          reject(new SecurityError(
            `Bad hash. Expected ${expectHash} but got ${actualHash} `,
          ));
        }
      });

    return {validateStream, extractor};
  }

  async fetchFromLocal(parts: Object): Promise<FetchedOverride> {
    let {reference: ref, config, registry} = this;

    // path to the local tarball
    let localTarball;
    let isOfflineTarball = false;

    const relativeFileLoc = parts.pathname && path.join(config.cwd, parts.pathname);
    if (relativeFileLoc && await fsUtil.exists(relativeFileLoc)) {
      // this is a reference to a file relative to the cwd
      localTarball = relativeFileLoc;
    } else {
      // generate a offline cache location
      localTarball = path.resolve(config.getOfflineMirrorPath(registry, null), ref);
      isOfflineTarball = true;
    }

    if (!(await fsUtil.exists(localTarball))) {
      throw new MessageError(`${ref}: Tarball is not in network and can't be located in cache`);
    }

    return new Promise((resolve, reject) => {
      let {validateStream, extractor} = this.createExtractor(null, resolve, reject);

      // flow gets confused with the pipe/on types chain
      const cachedStream: Object = fs.createReadStream(localTarball);

      const decompressStream = degzipper((stream) => {
        stream
          .on('error', reject)
          .pipe(extractor);
      });

      // nicer errors for corrupted compressed tarballs
      decompressStream.on('error', function(err) {
        let msg = `${err.message}. `;
        if (isOfflineTarball) {
          msg += `Mirror tarball appears to be corrupt. You can resolve this by running:\n\n` +
                 `  $ rm -rf ${localTarball}\n` +
                 '  $ kpm install --save';
        } else {
          msg += `Error decompressing ${localTarball}, it appears to be corrupt.`;
        }
        reject(new MessageError(msg));
      });

      cachedStream
        .pipe(validateStream)
        .pipe(decompressStream);
    });
  }

  async fetchFromExternal(): Promise<FetchedOverride> {
    let {reference: ref, config, registry} = this;

    return this.config.requestManager.request({
      url: ref,
      headers: {
        'Accept-Encoding': 'gzip',
        'Accept': 'application/octet-stream',
      },
      buffer: true,
      process: (req, resolve, reject) => {
        // should we save this to the offline cache?
        const mirrorPath = config.getOfflineMirrorPath(registry, ref);
        let mirrorTarballStream;
        let overwriteResolved;
        if (mirrorPath) {
          overwriteResolved = path.relative(config.getOfflineMirrorPath(registry), mirrorPath);
          mirrorTarballStream = fs.createWriteStream(mirrorPath);
          mirrorTarballStream.on('error', reject);
        }
        const mirrorSaver = through(function(chunk, enc, callback) {
          if (mirrorTarballStream) {
            mirrorTarballStream.write(chunk, enc);
          }
          callback(null, chunk);
        });

        //
        let {validateStream, extractor} = this.createExtractor(overwriteResolved, resolve, reject);

        //
        req
          .pipe(validateStream)
          .pipe(mirrorSaver)
          .pipe(degzipper((stream) => {
            stream
              .on('error', reject)
              .pipe(extractor);
          }));
      },
    });
  }

  async _fetch(): Promise<FetchedOverride> {
    const parts = url.parse(this.reference);
    if (parts.protocol === null) {
      return this.fetchFromLocal(parts);
    } else {
      return this.fetchFromExternal();
    }
  }
}
<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2017 The FOAM Authors. All Rights Reserved.
 * http://www.apache.org/licenses/LICENSE-2.0
 */

foam.CLASS({
  package: 'foam.u2.view',
  name: 'FObjectView',
  extends: 'foam.u2.View',

  documentation: 'View for editing FObjects.',

  imports: [
    'strategizer'
  ],

  properties: [
    {
      class: 'String',
      name: 'objectClass',
      label: '',
      visibilityExpression: function(choices) {
        return choices.length > 1 ?
          foam.u2.Visibility.RW :
          foam.u2.Visibility.HIDDEN;
      },
      view: function(_, x) {
        return foam.u2.view.ChoiceView.create({
          placeholder: '--',
          choices$: x.data.choices$
        }, x);
      },
      postSet: function(oldValue, newValue) {
        if ( newValue !== oldValue ) {
          var m = this.__context__.lookup(newValue, true);
          if ( m ) {
            var n = m.create(null, this);
            n.copyFrom(this.data);
            this.data = n;
          }
        }
      }
    },
    {
      class: 'FObjectProperty',
      name: 'data',
      label: '',
      postSet: function(_, data) {
        if ( ! data ) {
          this.objectClass = undefined;
        } else if ( data.cls_.id != this.objectClass ) {
          this.objectClass = data.cls_.id;
        }
      }
    },
    {
      class: 'Class',
      name: 'of'
    },
    {
      class: 'Array',
      name: 'choices',
      documentation: `
        A list of choices for a ChoiceView containing models related to the
        model in the 'of' property. The user can choose to create an instance
        of one of the models in this list.
      `
    }
  ],

  methods: [
    function init() {
      this.of$.sub(this.updateChoices);
      this.updateChoices();
    },

    function updateChoices() {
      if ( this.of == null ) {
        this.choices = [];
        return;
      }

      // If this view is being used in a nanos application, then use the
      // strategizer service to populate the list of choices. Otherwise
      // populate the list of choices using models related to 'of' via the
      // implements and extends relations.
      if ( this.strategizer != null ) {
        this.strategizer.query(null, this.of.id).then((strategyReferences) => {
          this.choices = strategyReferences.map((sr) => [sr.strategy.id, sr.strategy.id]);
        });
      } else {
        this.choices = this.choicesFallback(this.of);
      }
    },

    function initE() {
      this.SUPER();
      this
        .tag(foam.u2.detail.VerticalDetailView, {
          data: this,
          sections: [{
            properties: [this.OBJECT_CLASS, this.DATA]
          }]
        });
    },

    function choicesFallback(of) {
      /**
       * Return a list of choices for a ChoiceView containing models related to
       * 'of' via the implements and extends relations. Does not include
       * interfaces or abstract models in the list of choices.
       */
      if ( ! of ) return [];

      var modelIdToDeps = Object.values(foam.USED)
        .concat(Object.values(foam.UNUSED))
        .reduce((map, m) => {
          // QUESTION: If we're filtering out instances of InterfaceModel
          // below, why do we care about getting the list of things the model
          // implements? Won't they all be interfaces? Or are some of them
          // mixins?
          var deps = m.implements
            ? m.implements.map((imp) => {
              return foam.String.isInstance(imp) ? imp : imp.path;
            })
            : [];
          if ( m.extends ) deps.push(m.extends);
          var id = m.id || m.package + '.' + m.name;
          map[id] = deps;
          return map;
        }, {});

      var choices = {};
      choices[of.id] = true;

      while ( true ) {
        var prev = Object.keys(choices).length;
        for ( var [id, deps] of Object.entries(modelIdToDeps) ) {
          if ( deps.filter((d) => choices[d]).length ) choices[id] = true;
        }
        if ( prev == Object.keys(choices).length ) break;
      }

      return Object.keys(choices)
        .map((id) => foam.lookup(id).model_)
        .filter((m) => ! foam.core.InterfaceModel.isInstance(m))
        .filter((m) => ! m.abstract )
        .map((m) => [m.id, m.label]);
    }
  ]
});
<commit_msg>Use name instead of full id as label for choices in FObjectView<commit_after>/**
 * @license
 * Copyright 2017 The FOAM Authors. All Rights Reserved.
 * http://www.apache.org/licenses/LICENSE-2.0
 */

foam.CLASS({
  package: 'foam.u2.view',
  name: 'FObjectView',
  extends: 'foam.u2.View',

  documentation: 'View for editing FObjects.',

  imports: [
    'strategizer'
  ],

  properties: [
    {
      class: 'String',
      name: 'objectClass',
      label: '',
      visibilityExpression: function(choices) {
        return choices.length > 1 ?
          foam.u2.Visibility.RW :
          foam.u2.Visibility.HIDDEN;
      },
      view: function(_, x) {
        return foam.u2.view.ChoiceView.create({
          placeholder: '--',
          choices$: x.data.choices$
        }, x);
      },
      postSet: function(oldValue, newValue) {
        if ( newValue !== oldValue ) {
          var m = this.__context__.lookup(newValue, true);
          if ( m ) {
            var n = m.create(null, this);
            n.copyFrom(this.data);
            this.data = n;
          }
        }
      }
    },
    {
      class: 'FObjectProperty',
      name: 'data',
      label: '',
      postSet: function(_, data) {
        if ( ! data ) {
          this.objectClass = undefined;
        } else if ( data.cls_.id != this.objectClass ) {
          this.objectClass = data.cls_.id;
        }
      }
    },
    {
      class: 'Class',
      name: 'of'
    },
    {
      class: 'Array',
      name: 'choices',
      documentation: `
        A list of choices for a ChoiceView containing models related to the
        model in the 'of' property. The user can choose to create an instance
        of one of the models in this list.
      `
    }
  ],

  methods: [
    function init() {
      this.of$.sub(this.updateChoices);
      this.updateChoices();
    },

    function updateChoices() {
      if ( this.of == null ) {
        this.choices = [];
        return;
      }

      // If this view is being used in a nanos application, then use the
      // strategizer service to populate the list of choices. Otherwise
      // populate the list of choices using models related to 'of' via the
      // implements and extends relations.
      if ( this.strategizer != null ) {
        this.strategizer.query(null, this.of.id).then((strategyReferences) => {
          this.choices = strategyReferences.map((sr) => [sr.strategy.id, sr.strategy.name]);
        });
      } else {
        this.choices = this.choicesFallback(this.of);
      }
    },

    function initE() {
      this.SUPER();
      this
        .tag(foam.u2.detail.VerticalDetailView, {
          data: this,
          sections: [{
            properties: [this.OBJECT_CLASS, this.DATA]
          }]
        });
    },

    function choicesFallback(of) {
      /**
       * Return a list of choices for a ChoiceView containing models related to
       * 'of' via the implements and extends relations. Does not include
       * interfaces or abstract models in the list of choices.
       */
      if ( ! of ) return [];

      var modelIdToDeps = Object.values(foam.USED)
        .concat(Object.values(foam.UNUSED))
        .reduce((map, m) => {
          // QUESTION: If we're filtering out instances of InterfaceModel
          // below, why do we care about getting the list of things the model
          // implements? Won't they all be interfaces? Or are some of them
          // mixins?
          var deps = m.implements
            ? m.implements.map((imp) => {
              return foam.String.isInstance(imp) ? imp : imp.path;
            })
            : [];
          if ( m.extends ) deps.push(m.extends);
          var id = m.id || m.package + '.' + m.name;
          map[id] = deps;
          return map;
        }, {});

      var choices = {};
      choices[of.id] = true;

      while ( true ) {
        var prev = Object.keys(choices).length;
        for ( var [id, deps] of Object.entries(modelIdToDeps) ) {
          if ( deps.filter((d) => choices[d]).length ) choices[id] = true;
        }
        if ( prev == Object.keys(choices).length ) break;
      }

      return Object.keys(choices)
        .map((id) => foam.lookup(id).model_)
        .filter((m) => ! foam.core.InterfaceModel.isInstance(m))
        .filter((m) => ! m.abstract )
        .map((m) => [m.id, m.label]);
    }
  ]
});
<|endoftext|>


<commit_before>var gunzip = require('zlib').gunzip,
	request = require('request'),
	assembleGadget = require('./factory').assembleGadget,
	error = require('../lib/error');

module.exports = assembleGadget({
	name: 'SeNotifications',
	account: 'StackExchange',
	uri: 'http://stackexchange.com/',
	update: function(app, callback) {
		request({
			url: 'https://api.stackexchange.com/2.1/inbox/unread?filter=total',
			qs: {
				pagesize: 100,
				access_token: this.user.accounts.stackexchange.token,
				key: app.set('stackexchange-key')
			},
			headers: { 'Accept-Encoding': 'gzip' },
			encoding: null,
			strictSSL: true
		}, function(httpErr, res, data) {
			//Handle HTTP errors later; attempt to gunzip first

			if (res.headers && res.headers['content-encoding'] != 'gzip') {
				return error('Unsupported content-encoding', res, callback);
			}

			gunzip(data, function(gunzipErr, buffer) {
				//Gunzip failed; report HTTP error if any,
				//otherwise, report gunzip error
				if (gunzipErr) {
					return error(httpErr, res, callback) ||
						error(gunzipErr, res, callback);
				}

				res.body = buffer.toString();

				//Gunzip succeeded; check for HTTP error
				if (error(httpErr, res, callback)) return;

				try {
					var doc = JSON.parse(res.body);
					callback(null, { value: doc.total });
				} catch (err) {
					error(err, res, callback);
				}
			});
		});
	},
	intervals: [
		     3 * 60 * 60,        5 * 60, //3h after login, update every 5m
		    24 * 60 * 60,       20 * 60, //1d after login, update every 20m
		7 * 24 * 60 * 60,   2 * 60 * 60 // 1w after login, update every 2h
	]
});<commit_msg>Added cautionary check to avoid crashes in case SE might return no response<commit_after>var gunzip = require('zlib').gunzip,
	request = require('request'),
	assembleGadget = require('./factory').assembleGadget,
	error = require('../lib/error');

module.exports = assembleGadget({
	name: 'SeNotifications',
	account: 'StackExchange',
	uri: 'http://stackexchange.com/',
	update: function(app, callback) {
		request({
			url: 'https://api.stackexchange.com/2.1/inbox/unread?filter=total',
			qs: {
				pagesize: 100,
				access_token: this.user.accounts.stackexchange.token,
				key: app.set('stackexchange-key')
			},
			headers: { 'Accept-Encoding': 'gzip' },
			encoding: null,
			strictSSL: true
		}, function(httpErr, res, data) {
			//Handle HTTP errors later; attempt to gunzip first
			if (res && res.headers && res.headers['content-encoding'] != 'gzip') {
				return error('Unsupported content-encoding', res, callback);
			}

			gunzip(data, function(gunzipErr, buffer) {
				//Gunzip failed; report HTTP error if any,
				//otherwise, report gunzip error
				if (gunzipErr) {
					return error(httpErr, res, callback) ||
						error(gunzipErr, res, callback);
				}

				res.body = buffer.toString();

				//Gunzip succeeded; check for HTTP error
				if (error(httpErr, res, callback)) return;

				try {
					var doc = JSON.parse(res.body);
					callback(null, { value: doc.total });
				} catch (err) {
					error(err, res, callback);
				}
			});
		});
	},
	intervals: [
		     3 * 60 * 60,        5 * 60, //3h after login, update every 5m
		    24 * 60 * 60,       20 * 60, //1d after login, update every 20m
		7 * 24 * 60 * 60,   2 * 60 * 60 // 1w after login, update every 2h
	]
});<|endoftext|>


<commit_before>(function(){
'use strict';

/* Directives */
    var genoBrowserDirectives = angular.module('genoBrowserDirectives', ['genoBrowserControllers','genoBrowserServices', 'ui.bootstrap', 'angularFileUpload']);

    genoBrowserDirectives.directive('gbWigPlot', function(){
        return {
            restrict:'E',
            templateUrl:'partials/wig-plot.html'
        };
    });

    genoBrowserDirectives.directive('viewList',['$location', 'Views', 'Tracks', '$modal', function($location, Views, Tracks, $modal){
        return {
            restrict: 'E',
            templateUrl: 'partials/views.html',
            link: function (scope, element, attrs) {
                // First see if the route indicates a loaded view
                var location_view_id = parseInt($location.path().slice(-1)[0]);
                scope.views = Views.query(function(views){
                    // Find the view with a matching id and set it as loaded
                    var loaded_view = views.filter(function(element){
                        return element.view_id === location_view_id;
                    })[0];
                    // It will be set as undefined if no view is currently loaded
                    scope.loaded_view = loaded_view;
                });

                // Start off with no views selected
                scope.selected_view = null;

                // use this to select a view, called when the user clicks a view
                scope.selectView = function (view) {
                    // Set selected_view pointer to view
                    scope.selected_view = view;
                    // and the track_ids to the view's track_ids
                    scope.track_ids = view.track_ids;
                };

                // This is used by ng-class to check if a view is active
                scope.isSelectedView = function (view) {
                    return scope.selected_view === view;
                };

                // This is used by ng-class to check if a view is loaded
                // it gets a filled star if it is
                scope.isLoaded = function (view) {
                    return view === scope.loaded_view;
                };

                // This is called when a user clicks on a view's trash can
                scope.removeView = function (view) {
                    // Send DELETE request
                    view.$delete(function() {
                        // When we get a positive response
                        // Get a new list of views from the server
                        // The deleted view should be gone
                        scope.views = Views.query();
                        // If the deleted view was selected, clear the tracks pane
                        if(scope.isSelectedView(view)){
                            scope.track_ids = [];
                        }
                    });

                };

                // This is called when a user clicks on a view's edit button
                scope.editView = function(view){
                    // Select the view that will be edited
                    scope.selectView(view);
                    // Use the view_name as a starting point for editing
                    scope.edit_view_name = view.view_name;
                    // Get a list of all tracks for the dropdown
                    scope.all_tracks = Tracks.query();
                    // Open the view edit modal
                    $modal.open({
                        templateUrl:'partials/edit_view_modal.html',
                        scope:scope
                    }).result.then(function(result){
                            // After the modal is submitted
                            // Set the view's attributes to the edited values
                            view.view_name = result.view_name;
                            view.track_ids = [result.initial_track.track_id];
                            // Send PUT request with new values
                            view.$update();
                        })
                };

                // This is called when a user clicks the X on a view
                scope.removeTrackFromView = function(track){
                    // Remove the track from the list of track_ids watched by the trackList directive
                    scope.track_ids.splice(scope.track_ids.indexOf(track.track_id),1);
                    // Send PUT request with track_ids minus the removed one
                    scope.selected_view.$update();
                };

                // This is called when a user submits the add track modal
                scope.addTrackToView = function(track){
                    // Add the id to the list of track_ids watched by the trackList directive
                    scope.track_ids.push(track.track_id);
                    // PUT the new track_ids to the view
                    scope.selected_view.$update();
                };

                // This is called when the user clicks on the star
                scope.load = function (view) {
                    // Set the view_id to be loaded in the URL
                    // This change will be detected by the plotting controllers
                    $location.path('/view/' + view.view_id);
                    // Remember which view was loaded so we can quickly check
                    scope.loaded_view = view;
                };

                // This is called when the user clicks the add view button +
                scope.addView = function(){
                    // Deselect views
                    scope.selected_view = null;
                    // Get a current list of all tracks available as initial track
                    scope.all_tracks = Tracks.query();
                    // Open the add view modal
                    $modal.open({
                        templateUrl:'partials/add_view_modal.html',
                        scope:scope
                    }).result.then(function(result){
                            // When the user submits
                            // Create a new view based on the form data that gets passed back on $close
                            Views.create({track_ids:[result.initial_track.track_id], view_name:result.view_name}, function(){
                                // After confirmation that the view has been created
                                // Refresh the list of views
                                scope.views = Views.query();
                            });
                        });
                };
            },
            // Start an isolated scope
            scope:{}
        };
    }]);

    genoBrowserDirectives.directive('trackList', ['Tracks', '$modal', '$upload', function(Tracks, $modal, $upload){
       return {
           restrict: 'E',
           templateUrl: 'partials/tracks.html',
           link: function(scope,element,attr){
               // Deselect tracks
               scope.selected_track = null;

               // Watch the track_ids attribute, controlled mostly by viewList
               scope.$watch('track_ids',function(newValue){
                   // On change of a view's tracks
                   // If track_ids is valid
                   if(newValue) {
                       // deselect tracks
                       scope.selected_track = null;
                       // Clear tracks from track pane
                       scope.tracks = [];
                       // For every track in track_ids
                       newValue.forEach(function (track_id, index) {
                           // if track_id is valid
                           if(track_id || track_id === 0){
                               // GET the track data for track_id
                               Tracks.get({track_id: track_id}, function (data) {
                                   // Push the result to tracks, which is used by ngRepeat
                                   scope.tracks.push(data);
                               }, function (response) {
                                   // Ignore 404s
                                   if (response.status === 404) {

                                   }
                               });
                           }
                       });
                   }
                   else{
                       // New track_ids array is invalid
                       // Deselect tracks
                       scope.selected_track = null;
                       // Clear tracks pane
                       scope.tracks = [];
                   }
                   //Watch for changes in array equality, not just pointer
               }, true);

               // This is called when the user clicks on a track
               scope.selectTrack = function(track){
                   scope.selected_track = track;
               };

               // This is used by ngClass to see whether to apply the active class and highlight
               scope.isSelectedTrack = function(track){
                   return track === scope.selected_track;
               };

               // This is called when the user clicks on the add track button
               scope.addTrack = function(){
                   // Get a list of all tracks for the add exisiting track dropdown
                   scope.all_tracks = Tracks.query();
                   // Open the add track modal
                   $modal.open({
                       templateUrl:'partials/add_track_modal.html',
                       scope:scope
                   }).result.then(function(result){
                           // After the user submits the form
                           // If the user added an existing track
                           if(result.track) {
                               scope.addTrackToView(result.track);
                           }
                           else{
                               // The user submitted a file
                               // Upload the file
                               $upload.upload({
                                   file: result.file,
                                   fileFormDataName: 'file',
                                   url: '/api/files',
                                   fields: {
                                       track_name: result.track_name || '',
                                       type: result.track_type
                                   }
                               }).then(function(success){
                                   // After the upload is complete
                                   // Get the track_id for the recently uploaded file returned by the API
                                   var new_track_id = success.data.track_ids[0];
                                   if(new_track_id && new_track_id !== 0) {
                                       // Modify the selected view and PUT the changes
                                       scope.addTrackToView({track_id:new_track_id});
                                   }
                               });
                           }

                       });
               };

               // This is called when the user clicks on the edit button
               scope.editTrack = function(track){
                   // Select the track to be edited
                   scope.selectTrack(track);
                   // GET a list of all tracks for the dropdown
                   scope.all_tracks = Tracks.query();
                   // Open the edit track modal
                   $modal.open({
                       templateUrl:'partials/edit_track_modal.html',
                       scope:scope
                   }).result.then(function(result){
                           // After the user submits the form
                           // Make modifications to the selected view
                           scope.selected_track.track_name = result.track_name;
                           // PUT the changes to server
                           scope.selected_track.$update();
                       });
               };

               // This is called when the user clicks the trash can
               scope.deleteTrack = function(track){
                   // DELETE the track
                   track.$delete(function() {
                       // After confirmation of deletion
                       // Remove the track from list of tracks used by ngRepeat
                       scope.tracks.splice(scope.tracks.indexOf(track));
                       // If the track was selected before being deleted
                       if(scope.isSelectedTrack(track)){
                           // Deselect tracks
                           scope.selected_track = null;
                       }
                       // Refresh the selected view, it shouldn't have the deleted track_id now
                       scope.selected_view.get();
                   });
               };
           },
           // Inherit scope from viewList
           scope:true
       };
    }]);

})();
<commit_msg>Fix bug with adding and removing tracks<commit_after>(function(){
'use strict';

/* Directives */
    var genoBrowserDirectives = angular.module('genoBrowserDirectives', ['genoBrowserControllers','genoBrowserServices', 'ui.bootstrap', 'angularFileUpload']);

    genoBrowserDirectives.directive('gbWigPlot', function(){
        return {
            restrict:'E',
            templateUrl:'partials/wig-plot.html'
        };
    });

    genoBrowserDirectives.directive('viewList',['$location', 'Views', 'Tracks', '$modal', function($location, Views, Tracks, $modal){
        return {
            restrict: 'E',
            templateUrl: 'partials/views.html',
            link: function (scope, element, attrs) {
                // First see if the route indicates a loaded view
                var location_view_id = parseInt($location.path().slice(-1)[0]);
                scope.views = Views.query(function(views){
                    // Find the view with a matching id and set it as loaded
                    var loaded_view = views.filter(function(element){
                        return element.view_id === location_view_id;
                    })[0];
                    // It will be set as undefined if no view is currently loaded
                    scope.loaded_view = loaded_view;
                });

                // Start off with no views selected
                scope.selected_view = null;

                // use this to select a view, called when the user clicks a view
                scope.selectView = function (view) {
                    // Set selected_view pointer to view
                    scope.selected_view = view;
                    // and the track_ids to the view's track_ids
                    scope.track_ids = view.track_ids;
                };

                // This is used by ng-class to check if a view is active
                scope.isSelectedView = function (view) {
                    return scope.selected_view === view;
                };

                // This is used by ng-class to check if a view is loaded
                // it gets a filled star if it is
                scope.isLoaded = function (view) {
                    return view === scope.loaded_view;
                };

                // This is called when a user clicks on a view's trash can
                scope.removeView = function (view) {
                    // Send DELETE request
                    view.$delete(function() {
                        // When we get a positive response
                        // Get a new list of views from the server
                        // The deleted view should be gone
                        scope.views = Views.query();
                        // If the deleted view was selected, clear the tracks pane
                        if(scope.isSelectedView(view)){
                            scope.track_ids = [];
                        }
                    });

                };

                // This is called when a user clicks on a view's edit button
                scope.editView = function(view){
                    // Select the view that will be edited
                    scope.selectView(view);
                    // Use the view_name as a starting point for editing
                    scope.edit_view_name = view.view_name;
                    // Get a list of all tracks for the dropdown
                    scope.all_tracks = Tracks.query();
                    // Open the view edit modal
                    $modal.open({
                        templateUrl:'partials/edit_view_modal.html',
                        scope:scope
                    }).result.then(function(result){
                            // After the modal is submitted
                            // Set the view's attributes to the edited values
                            view.view_name = result.view_name;
                            view.track_ids = [result.initial_track.track_id];
                            // Send PUT request with new values
                            view.$update();
                        })
                };

                // This is called when a user clicks the X on a view
                scope.removeTrackFromView = function(track){
                    // Remove the track from the list of track_ids watched by the trackList directive
                    scope.track_ids.splice(scope.track_ids.indexOf(track.track_id),1);
                    // Send PUT request with track_ids minus the removed one
                    scope.selected_view.track_ids = scope.track_ids;
                    scope.selected_view.$update();
                };

                // This is called when a user submits the add track modal
                scope.addTrackToView = function(track){
                    // Add the id to the list of track_ids watched by the trackList directive
                    scope.track_ids.push(track.track_id);
                    // PUT the new track_ids to the view
                    scope.selected_view.track_ids = scope.track_ids;
                    scope.selected_view.$update();
                };

                // This is called when the user clicks on the star
                scope.load = function (view) {
                    // Set the view_id to be loaded in the URL
                    // This change will be detected by the plotting controllers
                    $location.path('/view/' + view.view_id);
                    // Remember which view was loaded so we can quickly check
                    scope.loaded_view = view;
                };

                // This is called when the user clicks the add view button +
                scope.addView = function(){
                    // Deselect views
                    scope.selected_view = null;
                    // Get a current list of all tracks available as initial track
                    scope.all_tracks = Tracks.query();
                    // Open the add view modal
                    $modal.open({
                        templateUrl:'partials/add_view_modal.html',
                        scope:scope
                    }).result.then(function(result){
                            // When the user submits
                            // Create a new view based on the form data that gets passed back on $close
                            Views.create({track_ids:[result.initial_track.track_id], view_name:result.view_name}, function(){
                                // After confirmation that the view has been created
                                // Refresh the list of views
                                scope.views = Views.query();
                            });
                        });
                };
            },
            // Start an isolated scope
            scope:{}
        };
    }]);

    genoBrowserDirectives.directive('trackList', ['Tracks', '$modal', '$upload', function(Tracks, $modal, $upload){
       return {
           restrict: 'E',
           templateUrl: 'partials/tracks.html',
           link: function(scope,element,attr){
               // Deselect tracks
               scope.selected_track = null;

               // Watch the track_ids attribute, controlled mostly by viewList
               scope.$watch('track_ids',function(newValue){
                   // On change of a view's tracks
                   // If track_ids is valid
                   if(newValue) {
                       // deselect tracks
                       scope.selected_track = null;
                       // Clear tracks from track pane
                       scope.tracks = [];
                       // For every track in track_ids
                       newValue.forEach(function (track_id, index) {
                           // if track_id is valid
                           if(track_id || track_id === 0){
                               // GET the track data for track_id
                               Tracks.get({track_id: track_id}, function (data) {
                                   // Push the result to tracks, which is used by ngRepeat
                                   scope.tracks.push(data);
                               }, function (response) {
                                   // Ignore 404s
                                   if (response.status === 404) {

                                   }
                               });
                           }
                       });
                   }
                   else{
                       // New track_ids array is invalid
                       // Deselect tracks
                       scope.selected_track = null;
                       // Clear tracks pane
                       scope.tracks = [];
                   }
                   //Watch for changes in array equality, not just pointer
               }, true);

               // This is called when the user clicks on a track
               scope.selectTrack = function(track){
                   scope.selected_track = track;
               };

               // This is used by ngClass to see whether to apply the active class and highlight
               scope.isSelectedTrack = function(track){
                   return track === scope.selected_track;
               };

               // This is called when the user clicks on the add track button
               scope.addTrack = function(){
                   // Get a list of all tracks for the add exisiting track dropdown
                   scope.all_tracks = Tracks.query();
                   // Open the add track modal
                   $modal.open({
                       templateUrl:'partials/add_track_modal.html',
                       scope:scope
                   }).result.then(function(result){
                           // After the user submits the form
                           // If the user added an existing track
                           if(result.track) {
                               scope.addTrackToView(result.track);
                           }
                           else{
                               // The user submitted a file
                               // Upload the file
                               $upload.upload({
                                   file: result.file,
                                   fileFormDataName: 'file',
                                   url: '/api/files',
                                   fields: {
                                       track_name: result.track_name || '',
                                       type: result.track_type
                                   }
                               }).then(function(success){
                                   // After the upload is complete
                                   // Get the track_id for the recently uploaded file returned by the API
                                   var new_track_id = success.data.track_ids[0];
                                   if(new_track_id && new_track_id !== 0) {
                                       // Modify the selected view and PUT the changes
                                       scope.addTrackToView({track_id:new_track_id});
                                   }
                               });
                           }

                       });
               };

               // This is called when the user clicks on the edit button
               scope.editTrack = function(track){
                   // Select the track to be edited
                   scope.selectTrack(track);
                   // GET a list of all tracks for the dropdown
                   scope.all_tracks = Tracks.query();
                   // Open the edit track modal
                   $modal.open({
                       templateUrl:'partials/edit_track_modal.html',
                       scope:scope
                   }).result.then(function(result){
                           // After the user submits the form
                           // Make modifications to the selected view
                           scope.selected_track.track_name = result.track_name;
                           // PUT the changes to server
                           scope.selected_track.$update();
                       });
               };

               // This is called when the user clicks the trash can
               scope.deleteTrack = function(track){
                   // DELETE the track
                   track.$delete(function() {
                       // After confirmation of deletion
                       // Remove the track from list of tracks used by ngRepeat
                       scope.tracks.splice(scope.tracks.indexOf(track));
                       // If the track was selected before being deleted
                       if(scope.isSelectedTrack(track)){
                           // Deselect tracks
                           scope.selected_track = null;
                       }
                       // Refresh the selected view, it shouldn't have the deleted track_id now
                       scope.selected_view.get();
                   });
               };
           },
           // Inherit scope from viewList
           scope:true
       };
    }]);

})();
<|endoftext|>


<commit_before>(function(){
'use strict';

/* Directives */
    var genoBrowserDirectives = angular.module('genoBrowserDirectives', ['genoBrowserControllers','genoBrowserServices', 'ui.bootstrap', 'angularFileUpload']);

    genoBrowserDirectives.directive('gbWigPlot', function($compile){
        return {
            restrict:'E',
            templateUrl:'partials/wig-plot.html',
            link: function(scope, element, attrs){
                scope.plotBounds = function(){

                }
            }
        };
    });

    genoBrowserDirectives.directive("userToolbar", ['$window', 'API',
        function ($window, API) {
            return {
                restrict: "E",
                templateUrl: "/partials/user_toolbar.html",
                link: function (scope, element, attrs) {
                    scope.user = {
                        'username':'',
                        'password':''
                    };

                    scope.isAuthenticated = function() {
                        return $window.sessionStorage.token;
                    };

                    scope.login = function() {
                        API.authenticate(scope.user, function(data) {
                            $window.sessionStorage.token = data.token;
                        }, function (response) {
                            delete $window.sessionStorage.token;
                        });
                    };

                    scope.logout = function() {
                        delete $window.sessionStorage.token;
                    };
                }
            };
        }
    ]);

    genoBrowserDirectives.directive('viewList',['$location', 'Views', 'Tracks', '$modal', '$route', function($location, Views, Tracks, $modal, $route){
        return {
            restrict: 'E',
            templateUrl: 'partials/views.html',
            link: function (scope, element, attrs) {
                // First see if the route indicates a loaded view
                var location_view_id = parseInt($location.path().slice(-1)[0]);
                scope.views = Views.query(function(views) {
                    // Find the view with a matching id and set it as loaded
                    var loaded_view = views.filter(function(element){
                        return element.view_id === location_view_id;
                    })[0];
                    // It will be set as undefined if no view is currently loaded
                    scope.loaded_view = loaded_view;
                });

                // Start off with no views selected
                scope.selected_view = null;

                // use this to select a view, called when the user clicks a view
                scope.selectView = function (view) {
                    // Set selected_view pointer to view
                    scope.selected_view = view;
                    // and the track_ids to the view's track_ids
                    scope.track_ids = view.track_ids;
                };

                // This is used by ng-class to check if a view is active
                scope.isSelectedView = function (view) {
                    return scope.selected_view === view;
                };

                // This is used by ng-class to check if a view is loaded
                // it gets a filled star if it is
                scope.isLoaded = function (view) {
                    return view === scope.loaded_view;
                };

                // This is called when a user clicks on a view's trash can
                scope.removeView = function (view) {
                    // Send DELETE request
                    view.$delete(function() {
                        // When we get a positive response
                        // Get a new list of views from the server
                        // The deleted view should be gone
                        scope.views = Views.query();
                        // If the deleted view was selected, clear the tracks pane
                        if(scope.isSelectedView(view)){
                            scope.track_ids = [];
                        }
                    });

                };

                // This is called when a user clicks on a view's edit button
                scope.editView = function(view){
                    // Select the view that will be edited
                    scope.selectView(view);
                    // Use the view_name as a starting point for editing
                    scope.edit_view_name = view.view_name;
                    // Get a list of all tracks for the dropdown
                    scope.all_tracks = Tracks.query();
                    // Open the view edit modal
                    $modal.open({
                        templateUrl:'partials/edit_view_modal.html',
                        scope:scope
                    }).result.then(function(result){
                            // After the modal is submitted
                            // Set the view's attributes to the edited values
                            view.view_name = result.view_name;
                            view.track_ids = [result.initial_track.track_id];
                            // Send PUT request with new values
                            view.$update();
                            $route.reload();
                        })
                };

                // This is called when a user clicks the X on a view
                scope.removeTrackFromView = function(track){
                    // Remove the track from the list of track_ids watched by the trackList directive
                    scope.track_ids.splice(scope.track_ids.indexOf(track.track_id),1);
                    // Send PUT request with track_ids minus the removed one
                    scope.selected_view.track_ids = scope.track_ids;
                    scope.selected_view.$update();
                    $route.reload();
                };

                // This is called when a user submits the add track modal
                scope.addTrackToView = function(track){
                    // Add the id to the list of track_ids watched by the trackList directive
                    scope.track_ids.push(track.track_id);
                    // PUT the new track_ids to the view
                    scope.selected_view.track_ids = scope.track_ids;
                    scope.selected_view.$update();
                    $route.reload();
                };

                // This is called when the user clicks on the star
                scope.load = function (view) {
                    // Set the view_id to be loaded in the URL
                    // This change will be detected by the plotting controllers
                    $location.path('/view/' + view.view_id);
                    $route.reload();
                    // Remember which view was loaded so we can quickly check
                    scope.loaded_view = view;

                };

                // This is called when the user clicks the add view button +
                scope.addView = function(){
                    // Deselect views
                    scope.selected_view = null;
                    // Get a current list of all tracks available as initial track
                    scope.all_tracks = Tracks.query();
                    // Open the add view modal
                    $modal.open({
                        templateUrl:'partials/add_view_modal.html',
                        scope:scope
                    }).result.then(function(result){
                            // When the user submits
                            // Create a new view based on the form data that gets passed back on $close
                            Views.create({track_ids:[result.initial_track.track_id], view_name:result.view_name}, function(){
                                // After confirmation that the view has been created
                                // Refresh the list of views
                                scope.views = Views.query();
                                $route.reload();
                            });
                        });
                };
            },
            // Start an isolated scope
            scope:{}
        };
    }]);

    genoBrowserDirectives.directive('trackList', ['Tracks', '$modal', '$upload', function(Tracks, $modal, $upload){
       return {
           restrict: 'E',
           templateUrl: 'partials/tracks.html',
           link: function(scope,element,attr){
               // Deselect tracks
               scope.selected_track = null;

               // Watch the track_ids attribute, controlled mostly by viewList
               scope.$watch('track_ids',function(newValue){
                   // On change of a view's tracks
                   // If track_ids is valid
                   if(newValue) {
                       // deselect tracks
                       scope.selected_track = null;
                       // Clear tracks from track pane
                       scope.tracks = [];
                       // For every track in track_ids
                       newValue.forEach(function (track_id, index) {
                           // if track_id is valid
                           if(track_id || track_id === 0){
                               // GET the track data for track_id
                               Tracks.get({track_id: track_id}, function (data) {
                                   // Push the result to tracks, which is used by ngRepeat
                                   scope.tracks.push(data);
                               }, function (response) {
                                   // Ignore 404s
                                   if (response.status === 404) {

                                   }
                               });
                           }
                       });
                   }
                   else{
                       // New track_ids array is invalid
                       // Deselect tracks
                       scope.selected_track = null;
                       // Clear tracks pane
                       scope.tracks = [];
                   }
                   //Watch for changes in array equality, not just pointer
               }, true);

               // This is called when the user clicks on a track
               scope.selectTrack = function(track){
                   scope.selected_track = track;
               };

               // This is used by ngClass to see whether to apply the active class and highlight
               scope.isSelectedTrack = function(track){
                   return track === scope.selected_track;
               };

               // This is called when the user clicks on the add track button
               scope.addTrack = function(){
                   // Get a list of all tracks for the add exisiting track dropdown
                   scope.all_tracks = Tracks.query();
                   // Open the add track modal
                   $modal.open({
                       templateUrl:'partials/add_track_modal.html',
                       scope:scope
                   }).result.then(function(result){
                           // After the user submits the form
                           // If the user added an existing track
                           if(result.track) {
                               scope.addTrackToView(result.track);
                           }
                           else{
                               // The user submitted a file
                               // Upload the file
                               $upload.upload({
                                   file: result.file,
                                   fileFormDataName: 'file',
                                   url: '/api/files',
                                   fields: {
                                       track_name: result.track_name || '',
                                       type: result.track_type
                                   }
                               }).then(function(success){
                                   // After the upload is complete
                                   // Get the track_id for the recently uploaded file returned by the API
                                   var new_track_id = success.data.track_ids[0];
                                   if(new_track_id && new_track_id !== 0) {
                                       // Modify the selected view and PUT the changes
                                       scope.addTrackToView({track_id:new_track_id});
                                   }
                               });
                           }

                       });
               };

               // This is called when the user clicks on the edit button
               scope.editTrack = function(track){
                   // Select the track to be edited
                   scope.selectTrack(track);
                   // GET a list of all tracks for the dropdown
                   scope.all_tracks = Tracks.query();
                   // Open the edit track modal
                   $modal.open({
                       templateUrl:'partials/edit_track_modal.html',
                       scope:scope
                   }).result.then(function(result){
                           // After the user submits the form
                           // Make modifications to the selected view
                           scope.selected_track.track_name = result.track_name;
                           // PUT the changes to server
                           scope.selected_track.$update();
                       });
               };

               // This is called when the user clicks the trash can
               scope.deleteTrack = function(track){
                   // DELETE the track
                   track.$delete(function() {
                       // After confirmation of deletion
                       // Remove the track from list of tracks used by ngRepeat
                       scope.tracks.splice(scope.tracks.indexOf(track));
                       // If the track was selected before being deleted
                       if(scope.isSelectedTrack(track)){
                           // Deselect tracks
                           scope.selected_track = null;
                       }
                       // Refresh the selected view, it shouldn't have the deleted track_id now
                       scope.selected_view.get();
                   });
               };
           },
           // Inherit scope from viewList
           scope:true
       };
    }]);

    genoBrowserDirectives.directive('gbTrack', ['Tracks', function(Tracks){
        return {
            restrict:'E',
            templateUrl:'partials/track.html',
            scope:{
                trackId:'@'
            },
            link: function(scope, element, attrs){
                scope.track = Tracks.get({track_id:attrs.trackId});
            }
        }
    }]);

    genoBrowserDirectives.directive('gbBedPlot', function(){
        return {
            restrict:'E',
            templateUrl:'partials/bed-plot.html'
        };
    });

    //genoBrowserDirectives.directive('gbBedPlot', function(){
    //    return {
    //        restrict:'E',
    //        templateUrl:'partials/bed-plot.html'
    //    };
    //});

})();
<commit_msg>Reload page on login/logout<commit_after>(function(){
'use strict';

/* Directives */
    var genoBrowserDirectives = angular.module('genoBrowserDirectives', ['genoBrowserControllers','genoBrowserServices', 'ui.bootstrap', 'angularFileUpload']);

    genoBrowserDirectives.directive('gbWigPlot', function($compile){
        return {
            restrict:'E',
            templateUrl:'partials/wig-plot.html',
            link: function(scope, element, attrs){
                scope.plotBounds = function(){

                }
            }
        };
    });

    genoBrowserDirectives.directive("userToolbar", ['$window', 'API',
        function ($window, API) {
            return {
                restrict: "E",
                templateUrl: "/partials/user_toolbar.html",
                link: function (scope, element, attrs) {
                    scope.user = {
                        'username':'',
                        'password':''
                    };

                    scope.isAuthenticated = function() {
                        return $window.sessionStorage.token;
                    };

                    scope.login = function() {
                        API.authenticate(scope.user, function(data) {
                            $window.sessionStorage.token = data.token;
                        }, function (response) {
                            delete $window.sessionStorage.token;
                        });
                        $window.location.reload();
                    };

                    scope.logout = function() {
                        delete $window.sessionStorage.token;
                        $window.location.reload();
                    };
                }
            };
        }
    ]);

    genoBrowserDirectives.directive('viewList',['$location', 'Views', 'Tracks', '$modal', '$route', function($location, Views, Tracks, $modal, $route){
        return {
            restrict: 'E',
            templateUrl: 'partials/views.html',
            link: function (scope, element, attrs) {
                // First see if the route indicates a loaded view
                var location_view_id = parseInt($location.path().slice(-1)[0]);
                scope.views = Views.query(function(views) {
                    // Find the view with a matching id and set it as loaded
                    var loaded_view = views.filter(function(element){
                        return element.view_id === location_view_id;
                    })[0];
                    // It will be set as undefined if no view is currently loaded
                    scope.loaded_view = loaded_view;
                });

                // Start off with no views selected
                scope.selected_view = null;

                // use this to select a view, called when the user clicks a view
                scope.selectView = function (view) {
                    // Set selected_view pointer to view
                    scope.selected_view = view;
                    // and the track_ids to the view's track_ids
                    scope.track_ids = view.track_ids;
                };

                // This is used by ng-class to check if a view is active
                scope.isSelectedView = function (view) {
                    return scope.selected_view === view;
                };

                // This is used by ng-class to check if a view is loaded
                // it gets a filled star if it is
                scope.isLoaded = function (view) {
                    return view === scope.loaded_view;
                };

                // This is called when a user clicks on a view's trash can
                scope.removeView = function (view) {
                    // Send DELETE request
                    view.$delete(function() {
                        // When we get a positive response
                        // Get a new list of views from the server
                        // The deleted view should be gone
                        scope.views = Views.query();
                        // If the deleted view was selected, clear the tracks pane
                        if(scope.isSelectedView(view)){
                            scope.track_ids = [];
                        }
                    });

                };

                // This is called when a user clicks on a view's edit button
                scope.editView = function(view){
                    // Select the view that will be edited
                    scope.selectView(view);
                    // Use the view_name as a starting point for editing
                    scope.edit_view_name = view.view_name;
                    // Get a list of all tracks for the dropdown
                    scope.all_tracks = Tracks.query();
                    // Open the view edit modal
                    $modal.open({
                        templateUrl:'partials/edit_view_modal.html',
                        scope:scope
                    }).result.then(function(result){
                            // After the modal is submitted
                            // Set the view's attributes to the edited values
                            view.view_name = result.view_name;
                            view.track_ids = [result.initial_track.track_id];
                            // Send PUT request with new values
                            view.$update();
                            $route.reload();
                        })
                };

                // This is called when a user clicks the X on a view
                scope.removeTrackFromView = function(track){
                    // Remove the track from the list of track_ids watched by the trackList directive
                    scope.track_ids.splice(scope.track_ids.indexOf(track.track_id),1);
                    // Send PUT request with track_ids minus the removed one
                    scope.selected_view.track_ids = scope.track_ids;
                    scope.selected_view.$update();
                    $route.reload();
                };

                // This is called when a user submits the add track modal
                scope.addTrackToView = function(track){
                    // Add the id to the list of track_ids watched by the trackList directive
                    scope.track_ids.push(track.track_id);
                    // PUT the new track_ids to the view
                    scope.selected_view.track_ids = scope.track_ids;
                    scope.selected_view.$update();
                    $route.reload();
                };

                // This is called when the user clicks on the star
                scope.load = function (view) {
                    // Set the view_id to be loaded in the URL
                    // This change will be detected by the plotting controllers
                    $location.path('/view/' + view.view_id);
                    $route.reload();
                    // Remember which view was loaded so we can quickly check
                    scope.loaded_view = view;

                };

                // This is called when the user clicks the add view button +
                scope.addView = function(){
                    // Deselect views
                    scope.selected_view = null;
                    // Get a current list of all tracks available as initial track
                    scope.all_tracks = Tracks.query();
                    // Open the add view modal
                    $modal.open({
                        templateUrl:'partials/add_view_modal.html',
                        scope:scope
                    }).result.then(function(result){
                            // When the user submits
                            // Create a new view based on the form data that gets passed back on $close
                            Views.create({track_ids:[result.initial_track.track_id], view_name:result.view_name}, function(){
                                // After confirmation that the view has been created
                                // Refresh the list of views
                                scope.views = Views.query();
                                $route.reload();
                            });
                        });
                };
            },
            // Start an isolated scope
            scope:{}
        };
    }]);

    genoBrowserDirectives.directive('trackList', ['Tracks', '$modal', '$upload', function(Tracks, $modal, $upload){
       return {
           restrict: 'E',
           templateUrl: 'partials/tracks.html',
           link: function(scope,element,attr){
               // Deselect tracks
               scope.selected_track = null;

               // Watch the track_ids attribute, controlled mostly by viewList
               scope.$watch('track_ids',function(newValue){
                   // On change of a view's tracks
                   // If track_ids is valid
                   if(newValue) {
                       // deselect tracks
                       scope.selected_track = null;
                       // Clear tracks from track pane
                       scope.tracks = [];
                       // For every track in track_ids
                       newValue.forEach(function (track_id, index) {
                           // if track_id is valid
                           if(track_id || track_id === 0){
                               // GET the track data for track_id
                               Tracks.get({track_id: track_id}, function (data) {
                                   // Push the result to tracks, which is used by ngRepeat
                                   scope.tracks.push(data);
                               }, function (response) {
                                   // Ignore 404s
                                   if (response.status === 404) {

                                   }
                               });
                           }
                       });
                   }
                   else{
                       // New track_ids array is invalid
                       // Deselect tracks
                       scope.selected_track = null;
                       // Clear tracks pane
                       scope.tracks = [];
                   }
                   //Watch for changes in array equality, not just pointer
               }, true);

               // This is called when the user clicks on a track
               scope.selectTrack = function(track){
                   scope.selected_track = track;
               };

               // This is used by ngClass to see whether to apply the active class and highlight
               scope.isSelectedTrack = function(track){
                   return track === scope.selected_track;
               };

               // This is called when the user clicks on the add track button
               scope.addTrack = function(){
                   // Get a list of all tracks for the add exisiting track dropdown
                   scope.all_tracks = Tracks.query();
                   // Open the add track modal
                   $modal.open({
                       templateUrl:'partials/add_track_modal.html',
                       scope:scope
                   }).result.then(function(result){
                           // After the user submits the form
                           // If the user added an existing track
                           if(result.track) {
                               scope.addTrackToView(result.track);
                           }
                           else{
                               // The user submitted a file
                               // Upload the file
                               $upload.upload({
                                   file: result.file,
                                   fileFormDataName: 'file',
                                   url: '/api/files',
                                   fields: {
                                       track_name: result.track_name || '',
                                       type: result.track_type
                                   }
                               }).then(function(success){
                                   // After the upload is complete
                                   // Get the track_id for the recently uploaded file returned by the API
                                   var new_track_id = success.data.track_ids[0];
                                   if(new_track_id && new_track_id !== 0) {
                                       // Modify the selected view and PUT the changes
                                       scope.addTrackToView({track_id:new_track_id});
                                   }
                               });
                           }

                       });
               };

               // This is called when the user clicks on the edit button
               scope.editTrack = function(track){
                   // Select the track to be edited
                   scope.selectTrack(track);
                   // GET a list of all tracks for the dropdown
                   scope.all_tracks = Tracks.query();
                   // Open the edit track modal
                   $modal.open({
                       templateUrl:'partials/edit_track_modal.html',
                       scope:scope
                   }).result.then(function(result){
                           // After the user submits the form
                           // Make modifications to the selected view
                           scope.selected_track.track_name = result.track_name;
                           // PUT the changes to server
                           scope.selected_track.$update();
                       });
               };

               // This is called when the user clicks the trash can
               scope.deleteTrack = function(track){
                   // DELETE the track
                   track.$delete(function() {
                       // After confirmation of deletion
                       // Remove the track from list of tracks used by ngRepeat
                       scope.tracks.splice(scope.tracks.indexOf(track));
                       // If the track was selected before being deleted
                       if(scope.isSelectedTrack(track)){
                           // Deselect tracks
                           scope.selected_track = null;
                       }
                       // Refresh the selected view, it shouldn't have the deleted track_id now
                       scope.selected_view.get();
                   });
               };
           },
           // Inherit scope from viewList
           scope:true
       };
    }]);

    genoBrowserDirectives.directive('gbTrack', ['Tracks', function(Tracks){
        return {
            restrict:'E',
            templateUrl:'partials/track.html',
            scope:{
                trackId:'@'
            },
            link: function(scope, element, attrs){
                scope.track = Tracks.get({track_id:attrs.trackId});
            }
        }
    }]);

    genoBrowserDirectives.directive('gbBedPlot', function(){
        return {
            restrict:'E',
            templateUrl:'partials/bed-plot.html'
        };
    });

    //genoBrowserDirectives.directive('gbBedPlot', function(){
    //    return {
    //        restrict:'E',
    //        templateUrl:'partials/bed-plot.html'
    //    };
    //});

})();
<|endoftext|>