<commit_before>import {LitElement, css, html, nothing} from 'lit';
import './chromedash-callout';
import {SHARED_STYLES} from '../sass/shared-css.js';

export class ChromedashProcessOverview extends LitElement {
  static get properties() {
    return {
      feature: {type: Object},
      process: {type: Array},
      progress: {type: Object},
      dismissedCues: {type: Object},
    };
  }

  constructor() {
    super();
    this.feature = {};
    this.process = [];
    this.progress = {};
    this.dismissedCues = {};
    this.item_stage_map = null; // null means uninitialized.
  }

  static prereqsId = 0;

  static get styles() {
    return [
      ...SHARED_STYLES,
      css`
      :host {
        display: block;
        position: relative;
        box-sizing: border-box;
        /* Don't do this, since it interferes with dialog placement.
        contain: content;  */
        overflow: hidden;
        background: inherit;
      }

      table {
        border-spacing: 0;
        width: 100%;
      }

      th {
        text-align: left;
        padding: var(--content-padding-half);
        background: var(--table-header-background);
      }

      td {
        padding: var(--content-padding-half) var(--content-padding) var(--content-padding) var(--content-padding-half);
        vertical-align: top;
        border-bottom: var(--table-divider);
        background: var(--table-row-background);
      }

      tr.active td {
        background: var(--light-accent-color);
      }

      td div.done:before {
        content: "\\2713";
        position: absolute;
        left: 0;
      }

      td div.pending:before {
        content: "\\25cb";
        position: absolute;
        left: 0;
      }

      td div.done, td div.pending {
        position: relative;
        padding-left: 1.2em;
      }

      ol {
        list-style: none;
        padding: 0;
      }

      ol li {
        margin-top: .5em;
      }

      .missing-prereqs-list {
        padding-bottom: 1em;
      }

      .missing-prereqs-list li {
        list-style: circle;
        margin-left: 2em;
      }

      .edit-progress-item {
        visibility: hidden;
        margin-left: var(--content-padding-half);
      }

      .pending:hover .edit-progress-item,
      .done:hover .edit-progress-item {
        visibility: visible;
      }
    `];
  }

  inFinalStage(stage) {
    const FINAL_STAGES = ['Shipped', 'Removed', 'Parked'];
    return (FINAL_STAGES.includes(this.feature.intent_stage) &&
            !FINAL_STAGES.includes(stage)); ;
  }

  /* A stage is "prior" if it would set a intent_stage that this feature
     has already passed. */
  isPriorStage(stage) {
    // if (this.inFinalStage(stage)) {
    //   return true;
    // }
    const stageOrder = this.process.stages.map(s => s.outgoing_stage);
    const viewedOutgoingStageIndex = stageOrder.indexOf(stage.outgoing_stage);
    const featureStageIndex = stageOrder.indexOf(this.feature.intent_stage_int);
    return (viewedOutgoingStageIndex < featureStageIndex);
  }

  /* A stage is "startable" if its incoming stage is the stage that the
     feature is on or has already passed, but its outgoing stage has
     not alrady been passed. */
  isStartableStage(stage) {
    if (this.inFinalStage(stage)) {
      return false;
    }
    const stageOrder = this.process.stages.map(s => s.outgoing_stage);
    const viewedIncomingStageIndex = stageOrder.indexOf(stage.incoming_stage);
    const viewedOutgoingStageIndex = stageOrder.indexOf(stage.outgoing_stage);
    const featureStageIndex = stageOrder.indexOf(this.feature.intent_stage_int);
    return (viewedIncomingStageIndex <= featureStageIndex &&
            viewedOutgoingStageIndex > featureStageIndex);
  }

  /* A stage is "future" if the feature has not yet reached its incoming stage. */
  isFutureStage(stage) {
    if (this.inFinalStage(stage)) {
      return false;
    }
    const stageOrder = this.process.stages.map(s => s.outgoing_stage);
    const viewedIncomingStageIndex = stageOrder.indexOf(stage.incoming_stage);
    const featureStageIndex = stageOrder.indexOf(this.feature.intent_stage_int);
    return (viewedIncomingStageIndex > featureStageIndex);
  }

  renderAction(action, stage) {
    const label = action.name;
    const url = action.url
      .replace('{feature_id}', this.feature.id)
      .replace('{outgoing_stage}', stage.outgoing_stage);
    const prereqItemsNames = action.prerequisites.filter(
      itemName => {
        return !this.progress.hasOwnProperty(itemName);
      });
    const prereqItems = prereqItemsNames.map(name => {
      // return {name, field, stage} for the named item.
      return this.item_stage_map[name];
    });
    const prereqsId = ChromedashProcessOverview.prereqsId++;
    const prereqsClass = `prereqs-${prereqsId}`;

    const checkCompletion = () => {
      if (prereqItems.length > 0) {
        // Open the dialog.
        this.shadowRoot.querySelector(`.${prereqsClass}`).show();
        return;
      } else {
        // Act like user clicked left button to go to the draft email window.
        const draftWindow = window.open(url, '_blank');
        draftWindow.focus();
      }
    };
    const dialog = html`
      <sl-dialog class="missing-prereqs ${prereqsClass}"
        label="Missing Prerequisites"
        style="--width:fit-content"
        @cancel=${this._cancelHandler}>
        Before you ${label}, you should first do the following:

          ${prereqItems.map((item) => html`

            ${item.stage.name}:
            ${item.name} ${this.renderEditLink(item.stage, item)}

`)}

        <sl-button href="${url}" target="_blank" variant="primary" size="small">
          Proceed to Draft Email
        </sl-button>
      </sl-dialog>
    `;

    return html`

        ${label}
        ${dialog}

`;
  }

  renderActions(stage) {
    if (stage.actions) {
      return html`

         ${stage.actions.map(act => this.renderAction(act, stage))}

`;
    } else {
      return nothing;
    }
  }

  renderEditLink(stage, item) {
    const featureId = this.feature.id;
    let editEl = nothing;
    if (item.field) {
      editEl = html`

          Edit

      `;
    }
    return editEl;
  }

  renderProgressItem(stage, item) {
    const editEl = this.renderEditLink(stage, item);

    if (!this.progress.hasOwnProperty(item.name)) {
      return html`

          ${item.name}
          ${editEl}

`;
    }

    const progressValue = this.progress[item.name];
    if (progressValue.startsWith('http://') ||
        progressValue.startsWith('https://')) {
      return html`

            ${item.name}

          ${editEl}

`;
    }

    return html`

        ${item.name}
        ${editEl}

`;
  }

  willUpdate() {
    if (this.process && this.item_stage_map == null) {
      // Make sure this.process.stages is an array.
      if (!this.process.stages) {
        this.process.stages = [];
      }

      // We will need to find the stages of prerequisites for actions of each stage.
      // So we will loop over all progress items of all stages one time
      // to rebuild this map at the start of each full page render.
      this.item_stage_map = {};
      this.process.stages.forEach(
        stage => stage.progress_items.forEach(
          item => {
            this.item_stage_map[item.name] = {...item, stage: stage};
          },
        ));
    }
  }

  render() {
    const featureId = this.feature.id;
    return html`

         Stage
         Progress

       ${this.process.stages.map(stage => html`

${stage.name}

${stage.description}

             ${stage.progress_items.map(item =>
                        this.renderProgressItem(stage, item))}

            ${this.feature.intent_stage_int == stage.outgoing_stage ?
              html`
Update
` :
              nothing }
            ${this.isPriorStage(stage) ?
              html`Revisit` :
              nothing }
            ${this.isStartableStage(stage) ?
              html`Start` :
              nothing }
            ${this.isFutureStage(stage) ?
              html`Preview` :
              nothing }

            ${this.renderActions(stage)}

       `)}

         Final review

          Edit all fields

    ${Object.keys(this.progress).length ? html`
      <chromedash-callout
        cue="progress-checkmarks" targetid="progress-header" signedin
        .dismissedCues=${this.dismissedCues}>
          Progress checkmarks appear in this column as you fill in
          fields of the feature entry.  However, you may start the next
          stage regardless of checkmarks.
      </chromedash-callout>` :
      nothing }

    `;
  }
}

customElements.define('chromedash-process-overview', ChromedashProcessOverview);
<commit_msg>Show "Edit" links for active stage and in missing prereqs dialog (#1891)<commit_after>import {LitElement, css, html, nothing} from 'lit';
import './chromedash-callout';
import {SHARED_STYLES} from '../sass/shared-css.js';

export class ChromedashProcessOverview extends LitElement {
  static get properties() {
    return {
      feature: {type: Object},
      process: {type: Array},
      progress: {type: Object},
      dismissedCues: {type: Object},
    };
  }

  constructor() {
    super();
    this.feature = {};
    this.process = [];
    this.progress = {};
    this.dismissedCues = {};
    this.item_stage_map = null; // null means uninitialized.
  }

  static prereqsId = 0;

  static get styles() {
    return [
      ...SHARED_STYLES,
      css`
      :host {
        display: block;
        position: relative;
        box-sizing: border-box;
        /* Don't do this, since it interferes with dialog placement.
        contain: content;  */
        overflow: hidden;
        background: inherit;
      }

      table {
        border-spacing: 0;
        width: 100%;
      }

      th {
        text-align: left;
        padding: var(--content-padding-half);
        background: var(--table-header-background);
      }

      td {
        padding: var(--content-padding-half) var(--content-padding) var(--content-padding) var(--content-padding-half);
        vertical-align: top;
        border-bottom: var(--table-divider);
        background: var(--table-row-background);
      }

      tr.active td {
        background: var(--light-accent-color);
      }

      td div.done:before {
        content: "\\2713";
        position: absolute;
        left: 0;
      }

      td div.pending:before {
        content: "\\25cb";
        position: absolute;
        left: 0;
      }

      td div.done, td div.pending {
        position: relative;
        padding-left: 1.2em;
      }

      ol {
        list-style: none;
        padding: 0;
      }

      ol li {
        margin-top: .5em;
      }

      .missing-prereqs-list {
        padding-bottom: 1em;
      }

      .missing-prereqs-list li {
        list-style: circle;
        margin-left: 2em;
      }

      .edit-progress-item {
        visibility: hidden;
        margin-left: var(--content-padding-half);
      }

      .active .edit-progress-item,
      .missing-prereqs .edit-progress-item,
      .pending:hover .edit-progress-item,
      .done:hover .edit-progress-item {
        visibility: visible;
      }
    `];
  }

  inFinalStage(stage) {
    const FINAL_STAGES = ['Shipped', 'Removed', 'Parked'];
    return (FINAL_STAGES.includes(this.feature.intent_stage) &&
            !FINAL_STAGES.includes(stage)); ;
  }

  /* A stage is "prior" if it would set a intent_stage that this feature
     has already passed. */
  isPriorStage(stage) {
    // if (this.inFinalStage(stage)) {
    //   return true;
    // }
    const stageOrder = this.process.stages.map(s => s.outgoing_stage);
    const viewedOutgoingStageIndex = stageOrder.indexOf(stage.outgoing_stage);
    const featureStageIndex = stageOrder.indexOf(this.feature.intent_stage_int);
    return (viewedOutgoingStageIndex < featureStageIndex);
  }

  /* A stage is "startable" if its incoming stage is the stage that the
     feature is on or has already passed, but its outgoing stage has
     not alrady been passed. */
  isStartableStage(stage) {
    if (this.inFinalStage(stage)) {
      return false;
    }
    const stageOrder = this.process.stages.map(s => s.outgoing_stage);
    const viewedIncomingStageIndex = stageOrder.indexOf(stage.incoming_stage);
    const viewedOutgoingStageIndex = stageOrder.indexOf(stage.outgoing_stage);
    const featureStageIndex = stageOrder.indexOf(this.feature.intent_stage_int);
    return (viewedIncomingStageIndex <= featureStageIndex &&
            viewedOutgoingStageIndex > featureStageIndex);
  }

  /* A stage is "future" if the feature has not yet reached its incoming stage. */
  isFutureStage(stage) {
    if (this.inFinalStage(stage)) {
      return false;
    }
    const stageOrder = this.process.stages.map(s => s.outgoing_stage);
    const viewedIncomingStageIndex = stageOrder.indexOf(stage.incoming_stage);
    const featureStageIndex = stageOrder.indexOf(this.feature.intent_stage_int);
    return (viewedIncomingStageIndex > featureStageIndex);
  }

  renderAction(action, stage) {
    const label = action.name;
    const url = action.url
      .replace('{feature_id}', this.feature.id)
      .replace('{outgoing_stage}', stage.outgoing_stage);
    const prereqItemsNames = action.prerequisites.filter(
      itemName => {
        return !this.progress.hasOwnProperty(itemName);
      });
    const prereqItems = prereqItemsNames.map(name => {
      // return {name, field, stage} for the named item.
      return this.item_stage_map[name];
    });
    const prereqsId = ChromedashProcessOverview.prereqsId++;
    const prereqsClass = `prereqs-${prereqsId}`;

    const checkCompletion = () => {
      if (prereqItems.length > 0) {
        // Open the dialog.
        this.shadowRoot.querySelector(`.${prereqsClass}`).show();
        return;
      } else {
        // Act like user clicked left button to go to the draft email window.
        const draftWindow = window.open(url, '_blank');
        draftWindow.focus();
      }
    };
    const dialog = html`
      <sl-dialog class="missing-prereqs ${prereqsClass}"
        label="Missing Prerequisites"
        style="--width:fit-content"
        @cancel=${this._cancelHandler}>
        Before you ${label}, you should first do the following:

          ${prereqItems.map((item) => html`

            ${item.stage.name}:
            ${item.name} ${this.renderEditLink(item.stage, item)}

`)}

        <sl-button href="${url}" target="_blank" variant="primary" size="small">
          Proceed to Draft Email
        </sl-button>
      </sl-dialog>
    `;

    return html`

        ${label}
        ${dialog}

`;
  }

  renderActions(stage) {
    if (stage.actions) {
      return html`

         ${stage.actions.map(act => this.renderAction(act, stage))}

`;
    } else {
      return nothing;
    }
  }

  renderEditLink(stage, item) {
    const featureId = this.feature.id;
    let editEl = nothing;
    if (item.field) {
      editEl = html`

          Edit

      `;
    }
    return editEl;
  }

  renderProgressItem(stage, item) {
    const editEl = this.renderEditLink(stage, item);

    if (!this.progress.hasOwnProperty(item.name)) {
      return html`

          ${item.name}
          ${editEl}

`;
    }

    const progressValue = this.progress[item.name];
    if (progressValue.startsWith('http://') ||
        progressValue.startsWith('https://')) {
      return html`

            ${item.name}

          ${editEl}

`;
    }

    return html`

        ${item.name}
        ${editEl}

`;
  }

  willUpdate() {
    if (this.process && this.item_stage_map == null) {
      // Make sure this.process.stages is an array.
      if (!this.process.stages) {
        this.process.stages = [];
      }

      // We will need to find the stages of prerequisites for actions of each stage.
      // So we will loop over all progress items of all stages one time
      // to rebuild this map at the start of each full page render.
      this.item_stage_map = {};
      this.process.stages.forEach(
        stage => stage.progress_items.forEach(
          item => {
            this.item_stage_map[item.name] = {...item, stage: stage};
          },
        ));
    }
  }

  render() {
    const featureId = this.feature.id;
    return html`

         Stage
         Progress

       ${this.process.stages.map(stage => html`

${stage.name}

${stage.description}

             ${stage.progress_items.map(item =>
                        this.renderProgressItem(stage, item))}

            ${this.feature.intent_stage_int == stage.outgoing_stage ?
              html`
Update
` :
              nothing }
            ${this.isPriorStage(stage) ?
              html`Revisit` :
              nothing }
            ${this.isStartableStage(stage) ?
              html`Start` :
              nothing }
            ${this.isFutureStage(stage) ?
              html`Preview` :
              nothing }

            ${this.renderActions(stage)}

       `)}

         Final review

          Edit all fields

    ${Object.keys(this.progress).length ? html`
      <chromedash-callout
        cue="progress-checkmarks" targetid="progress-header" signedin
        .dismissedCues=${this.dismissedCues}>
          Progress checkmarks appear in this column as you fill in
          fields of the feature entry.  However, you may start the next
          stage regardless of checkmarks.
      </chromedash-callout>` :
      nothing }

    `;
  }
}

customElements.define('chromedash-process-overview', ChromedashProcessOverview);
<|endoftext|>


<commit_before>var dataPromise = $.Deferred();
var sliderPromise = $.Deferred();

$(document).ready(function () {

	var slider = null;

	var range_all_sliders = {
		'min': [1950],
		'7.6923076923%': [1955, 500],
		'15.384615385%': [1960, 1000],
		'23.076923077%': [1965, 1500],
		'30.769230769%': [1970, 2000],
		'38.461538462%': [1975, 2500],
		'46.153846154%': [1980, 500],
		'53.846153846%': [1985, 1000],
		'61.538461538%': [1990, 1500],
		'69.230769321%': [1995, 2000],
		'76.923076923%': [2000, 2500],
		'84.615384615%': [2005, 1500],
		'92.307692308%': [2010, 2000],
		'max': [2015, 2500],
	};

	var reallyReady = function() {
    setTimeout(function(){
      slider = document.getElementById('slider');
      if (slider === null) {
        reallyReady();
      } else {
        noUiSlider.create(slider, {
          range: range_all_sliders,
          start: 2010,
          snap: true,
          pips: {
            mode: 'positions',
            behaviour: 'snap',
            values: [0, 7, 15, 23, 30, 38, 46, 53, 61, 69, 76, 84, 92, 100],
            density: 20,
            stepped: true
          }
        });
        sliderPromise.resolve();
      }
    }, 25);
  };
});
<commit_msg>Another try at really ready<commit_after>var dataPromise = $.Deferred();
var sliderPromise = $.Deferred();

$(document).ready(function () {

	var slider = null;

	var range_all_sliders = {
		'min': [1950],
		'7.6923076923%': [1955, 500],
		'15.384615385%': [1960, 1000],
		'23.076923077%': [1965, 1500],
		'30.769230769%': [1970, 2000],
		'38.461538462%': [1975, 2500],
		'46.153846154%': [1980, 500],
		'53.846153846%': [1985, 1000],
		'61.538461538%': [1990, 1500],
		'69.230769321%': [1995, 2000],
		'76.923076923%': [2000, 2500],
		'84.615384615%': [2005, 1500],
		'92.307692308%': [2010, 2000],
		'max': [2015, 2500],
	};

  var interval = setInterval(function(){
    slider = document.getElementById('slider');
    if (slider !== null) {
      clearInterval(interval);
      noUiSlider.create(slider, {
        range: range_all_sliders,
        start: 2010,
        snap: true,
        pips: {
          mode: 'positions',
          behaviour: 'snap',
          values: [0, 7, 15, 23, 30, 38, 46, 53, 61, 69, 76, 84, 92, 100],
          density: 20,
          stepped: true
        }
      });
      sliderPromise.resolve();
    }
  }, 25);
});
<|endoftext|>


<commit_before>/*!
 * Bootstrap-sync's Gruntfile
 * https://github.com/StevenBlack/bootstrap-sync
 * Copyright 2014-2015 Twitter, Inc.
 * Licensed under MIT (https://raw.githubusercontent.com/StevenBlack/bootstrap-sync/master/LICENSE-MIT)
 */
module.exports = function( grunt ) {
	'use strict';

	var optionsfile = 'gruntoptions.json';
	var _           = require('lodash');
	var pkg         = grunt.file.readJSON( 'package.json' );
	var options     = grunt.file.exists( optionsfile ) ? grunt.file.readJSON( optionsfile ) : {} ;
	var settings    = _.merge( {}, pkg.defaults, options );

	// Project configuration.
	grunt.initConfig({

		// Metadata.
		pkg: pkg,
		options: options,
		settings: settings,

		jqueryCheck: 'if (typeof jQuery === \'undefined\') { throw new Error(\'Bootstrap\\\'s JavaScript requires jQuery\') }\n\n' ,

		clean: {
			'bootstrap-source': [ '<%= settings.location.bootstrap.local %>/' ],
			'fonts': [ '<%= settings.location.deploy.fonts %>/' ],
			'css': [ '<%= settings.location.deploy.css %>/', "!<%= settings.location.deploy.css %>/main.css" ],
			'js': [ '<%= settings.location.deploy.js %>/' ]
		},

		copy: {
			'bootstrap-source': {
				nonull: true,
				expand: true,
				cwd: '<%= settings.location.bootstrap.authoritative %>/',
				src: [ 'fonts/*', 'js/*', 'less/**' ],
				dest: '<%= settings.location.bootstrap.local %>/'
			},
			'bootstrap-tweaks': {
				src: [ 'less/*' ],
				dest: '<%= settings.location.bootstrap.local %>/'
			},
			'bootstrap-fonts': {
				expand: true,
				flatten: true,
				src: [ '<%= settings.location.bootstrap.local %>/fonts/*' ],
				dest: '<%= settings.location.deploy.fonts %>/'
			},
			'fontawesome': {
				expand: true,
				flatten: true,
				src: [ '<%= settings.location.fontawesome.local %>/fonts/*' ],
				dest: '<%= settings.location.deploy.fonts %>/'
			}
		},

		concat: {
			options: {
				// Using the banner to inject a jQuery check.
				banner: '<%= jqueryCheck %>',
				stripBanners: false
			},
			bootstrapjs: {
				src: ( function() {
						var cwd = settings.location.bootstrap.local + '/';
						var arr = settings.task.concat.bootstrapjs.src;
						return arr.map(function(file) { return cwd + "/" + file; });
						}()
				),
				dest: '<%= settings.location.deploy.js %>/<%= settings.filename.js %>'
			}
		},

		uglify: {
			options: { report: 'min', compress: true },
			bootstrap: { src: [ '<%= concat.bootstrapjs.dest %>' ], dest: '<%= settings.location.deploy.js %>/<%= settings.filename.jsmin %>' }
		},

		less: {
			compileCore: {
				options: {
					strictMath: true,
					outputSourceFiles: true
				},
				files: { '<%= settings.location.deploy.css %>/<%= settings.filename.css %>': '<%= settings.location.bootstrap.local %>/less/<%= settings.filename.less %>' }
			}
		},

		cssmin: {
			combine: {
				files: {
					'<%= settings.location.deploy.css %>/<%= settings.filename.cssmin %>': [ '<%= settings.location.deploy.css %>/<%= settings.filename.css %>', '_font-awesome/css/font-awesome.css' ]
				}
			}
		}

	});

	// This one-liner replaces multiple grunt.loadNpmTasks() calls
	// See http://www.thomasboyt.com/2013/09/01/maintainable-grunt.html
	require('load-grunt-tasks')(grunt, { scope: 'devDependencies' });

	// Bootstrap tasks
	//    cleanup
	grunt.registerTask( 'clean-bootstrap', [ 'clean:bootstrap-source' ] );
	grunt.registerTask( 'clean-fonts', [ 'clean:fonts' ] );

	//    constructing
	grunt.registerTask( 'fetch-fresh-bootstrap', [ 'copy:bootstrap-source' ] );
	grunt.registerTask( 'apply-bootstrap-tweaks', [ 'copy:bootstrap-tweaks' ] );
	grunt.registerTask( 'update-fonts', [ 'clean-fonts', 'copy:bootstrap-fonts', 'copy:fontawesome' ] );
	grunt.registerTask( 'bootstrap', [ 'clean-bootstrap', 'fetch-fresh-bootstrap', 'apply-bootstrap-tweaks', 'update-fonts' ] );

	// Less and css tasks
	grunt.registerTask( 'clean-css', [ 'clean:css' ] );
	grunt.registerTask( 'less-compile', [ 'less:compileCore' ]);
	grunt.registerTask( 'css-minify', [ 'cssmin' ]);
	grunt.registerTask( 'css', [ 'clean-css', 'less-compile', 'css-minify']);

	// js tasks
	grunt.registerTask( 'clean-js', [ 'clean:js' ] );
	grunt.registerTask( 'js-bootstrap', ['clean-js', 'concat:bootstrapjs']);
	grunt.registerTask( 'js-minify', [ 'uglify:bootstrap']);
	grunt.registerTask( 'js', [ 'js-bootstrap', 'js-minify' ]);

	// all
	grunt.registerTask(  'clean-all', ['clean-bootstrap', 'clean-fonts', 'clean-css', 'clean-js' ]);
	grunt.registerTask(  'default', ['bootstrap', 'css', 'js' ]);

};

<commit_msg>Added grunt tasks for managing Fontawesome.<commit_after>/*!
 * Bootstrap-sync's Gruntfile
 * https://github.com/StevenBlack/bootstrap-sync
 * Copyright 2014-2015 Twitter, Inc.
 * Licensed under MIT (https://raw.githubusercontent.com/StevenBlack/bootstrap-sync/master/LICENSE-MIT)
 */
module.exports = function( grunt ) {
	'use strict';

	var optionsfile = 'gruntoptions.json';
	var _           = require('lodash');
	var pkg         = grunt.file.readJSON( 'package.json' );
	var options     = grunt.file.exists( optionsfile ) ? grunt.file.readJSON( optionsfile ) : {} ;
	var settings    = _.merge( {}, pkg.defaults, options );

	// Project configuration.
	grunt.initConfig({

		// Metadata.
		pkg: pkg,
		options: options,
		settings: settings,

		jqueryCheck: 'if (typeof jQuery === \'undefined\') { throw new Error(\'Bootstrap\\\'s JavaScript requires jQuery\') }\n\n' ,

		clean: {
			'bootstrap-source': [ '<%= settings.location.bootstrap.local %>/' ],
			'fonts': [ '<%= settings.location.deploy.fonts %>/' ],
			'css': [ '<%= settings.location.deploy.css %>/', "!<%= settings.location.deploy.css %>/main.css" ],
			'js': [ '<%= settings.location.deploy.js %>/' ]
		},

		copy: {
			'bootstrap-source': {
				nonull: true,
				expand: true,
				cwd: '<%= settings.location.bootstrap.authoritative %>/',
				src: [ 'fonts/*', 'js/*', 'less/**' ],
				dest: '<%= settings.location.bootstrap.local %>/'
			},
			'fontawesome-source': {
				nonull: true,
				expand: true,
				cwd: '<%= settings.location.fontawesome.authoritative %>/',
				src: [ 'fonts/*', 'css/*', 'less/*' ],
				dest: '<%= settings.location.fontawesome.local %>/'
			},
			'bootstrap-tweaks': {
				src: [ 'less/*' ],
				dest: '<%= settings.location.bootstrap.local %>/'
			},
			'bootstrap-fonts': {
				expand: true,
				flatten: true,
				src: [ '<%= settings.location.bootstrap.local %>/fonts/*' ],
				dest: '<%= settings.location.deploy.fonts %>/'
			},
			'fontawesome': {
				expand: true,
				flatten: true,
				src: [ '<%= settings.location.fontawesome.local %>/fonts/*' ],
				dest: '<%= settings.location.deploy.fonts %>/'
			}
		},

		concat: {
			options: {
				// Using the banner to inject a jQuery check.
				banner: '<%= jqueryCheck %>',
				stripBanners: false
			},
			bootstrapjs: {
				src: ( function() {
						var cwd = settings.location.bootstrap.local + '/';
						var arr = settings.task.concat.bootstrapjs.src;
						return arr.map(function(file) { return cwd + "/" + file; });
						}()
				),
				dest: '<%= settings.location.deploy.js %>/<%= settings.filename.js %>'
			}
		},

		uglify: {
			options: { report: 'min', compress: true },
			bootstrap: { src: [ '<%= concat.bootstrapjs.dest %>' ], dest: '<%= settings.location.deploy.js %>/<%= settings.filename.jsmin %>' }
		},

		less: {
			compileCore: {
				options: {
					strictMath: true,
					outputSourceFiles: true
				},
				files: { '<%= settings.location.deploy.css %>/<%= settings.filename.css %>': '<%= settings.location.bootstrap.local %>/less/<%= settings.filename.less %>' }
			}
		},

		cssmin: {
			combine: {
				files: {
					'<%= settings.location.deploy.css %>/<%= settings.filename.cssmin %>': [ '<%= settings.location.deploy.css %>/<%= settings.filename.css %>', '_font-awesome/css/font-awesome.css' ]
				}
			}
		}

	});

	// This one-liner replaces multiple grunt.loadNpmTasks() calls
	// See http://www.thomasboyt.com/2013/09/01/maintainable-grunt.html
	require('load-grunt-tasks')(grunt, { scope: 'devDependencies' });

	// Bootstrap tasks
	//    cleanup
	grunt.registerTask( 'clean-bootstrap', [ 'clean:bootstrap-source' ] );
	grunt.registerTask( 'clean-fonts', [ 'clean:fonts' ] );

	//    constructing
	grunt.registerTask( 'fetch-fresh-bootstrap', [ 'copy:bootstrap-source' ] );
	grunt.registerTask( 'fetch-fresh-fontawesome', [ 'copy:fontawesome-source' ] );
	grunt.registerTask( 'apply-bootstrap-tweaks', [ 'copy:bootstrap-tweaks' ] );
	grunt.registerTask( 'update-fonts', [ 'clean-fonts', 'copy:bootstrap-fonts', 'fetch-fresh-fontawesome', 'copy:fontawesome' ] );
	grunt.registerTask( 'bootstrap', [ 'clean-bootstrap', 'fetch-fresh-bootstrap', 'apply-bootstrap-tweaks', 'update-fonts' ] );

	// Less and css tasks
	grunt.registerTask( 'clean-css', [ 'clean:css' ] );
	grunt.registerTask( 'less-compile', [ 'less:compileCore' ]);
	grunt.registerTask( 'css-minify', [ 'cssmin' ]);
	grunt.registerTask( 'css', [ 'clean-css', 'less-compile', 'css-minify']);

	// js tasks
	grunt.registerTask( 'clean-js', [ 'clean:js' ] );
	grunt.registerTask( 'js-bootstrap', ['clean-js', 'concat:bootstrapjs']);
	grunt.registerTask( 'js-minify', [ 'uglify:bootstrap']);
	grunt.registerTask( 'js', [ 'js-bootstrap', 'js-minify' ]);

	// all
	grunt.registerTask(  'clean-all', ['clean-bootstrap', 'clean-fonts', 'clean-css', 'clean-js' ]);
	grunt.registerTask(  'default', ['bootstrap', 'css', 'js' ]);

};

<|endoftext|>


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

describe('Observable.prototype.defaultIfEmpty()', function () {
  it.asDiagram('defaultIfEmpty(\'x\')')('should return the argument if the Observable eventually completes empty', function () {
    var e1 =   hot('--------|   ');
    var e1subs =   '^       !   ';
    var expected = '--------(x|)';

    expectObservable(e1.defaultIfEmpty('x')).toBe(expected);
    expectSubscriptions(e1.subscriptions).toBe(e1subs);
  });

  it('should return the argument if Observable is empty', function () {
    var e1 =  cold('|');
    var e1subs =   '(^!)';
    var expected = '(x|)';

    expectObservable(e1.defaultIfEmpty('x')).toBe(expected);
    expectSubscriptions(e1.subscriptions).toBe(e1subs);
  });

  it('should return null if the Observable is empty and no arguments', function () {
    var e1 =  cold('|');
    var e1subs =   '(^!)';
    var expected = '(x|)';

    expectObservable(e1.defaultIfEmpty()).toBe(expected, { x: null });
    expectSubscriptions(e1.subscriptions).toBe(e1subs);
  });

  it('should return the Observable if not empty with a default value', function () {
    var e1 =   hot('--a--b--|');
    var e1subs =   '^       !';
    var expected = '--a--b--|';

    expectObservable(e1.defaultIfEmpty('x')).toBe(expected);
    expectSubscriptions(e1.subscriptions).toBe(e1subs);
  });

  it('should return the Observable if not empty with no default value', function () {
    var e1 =   hot('--a--b--|');
    var e1subs =   '^       !';
    var expected = '--a--b--|';

    expectObservable(e1.defaultIfEmpty()).toBe(expected);
    expectSubscriptions(e1.subscriptions).toBe(e1subs);
  });

  it('should error if the Observable errors', function () {
    var e1 =  cold('#');
    var e1subs =   '(^!)';
    var expected = '#';

    expectObservable(e1.defaultIfEmpty('x')).toBe(expected);
    expectSubscriptions(e1.subscriptions).toBe(e1subs);
  });
});<commit_msg>test(defaultIfEmpty): add unsubscription-related tests<commit_after>/* globals describe, it, expect, expectObservable, expectSubscriptions, cold, hot */
var Rx = require('../../dist/cjs/Rx');
var Observable = Rx.Observable;

describe('Observable.prototype.defaultIfEmpty()', function () {
  it.asDiagram('defaultIfEmpty(\'x\')')('should return the argument if the Observable eventually completes empty', function () {
    var e1 =   hot('--------|   ');
    var e1subs =   '^       !   ';
    var expected = '--------(x|)';

    expectObservable(e1.defaultIfEmpty('x')).toBe(expected);
    expectSubscriptions(e1.subscriptions).toBe(e1subs);
  });

  it('should return the argument if Observable is empty', function () {
    var e1 =  cold('|');
    var e1subs =   '(^!)';
    var expected = '(x|)';

    expectObservable(e1.defaultIfEmpty('x')).toBe(expected);
    expectSubscriptions(e1.subscriptions).toBe(e1subs);
  });

  it('should return null if the Observable is empty and no arguments', function () {
    var e1 =  cold('|');
    var e1subs =   '(^!)';
    var expected = '(x|)';

    expectObservable(e1.defaultIfEmpty()).toBe(expected, { x: null });
    expectSubscriptions(e1.subscriptions).toBe(e1subs);
  });

  it('should return the Observable if not empty with a default value', function () {
    var e1 =   hot('--a--b--|');
    var e1subs =   '^       !';
    var expected = '--a--b--|';

    expectObservable(e1.defaultIfEmpty('x')).toBe(expected);
    expectSubscriptions(e1.subscriptions).toBe(e1subs);
  });

  it('should return the Observable if not empty with no default value', function () {
    var e1 =   hot('--a--b--|');
    var e1subs =   '^       !';
    var expected = '--a--b--|';

    expectObservable(e1.defaultIfEmpty()).toBe(expected);
    expectSubscriptions(e1.subscriptions).toBe(e1subs);
  });

  it('should allow unsubscribing early and explicitly', function () {
    var e1 =   hot('--a--b--|');
    var e1subs =   '^   !    ';
    var expected = '--a--    ';
    var unsub =    '    !    ';

    var result = e1.defaultIfEmpty('x');

    expectObservable(result, unsub).toBe(expected);
    expectSubscriptions(e1.subscriptions).toBe(e1subs);
  });

  it('should not break unsubscription chains when unsubscribed explicitly', function () {
    var e1 =   hot('--a--b--|');
    var e1subs =   '^   !    ';
    var expected = '--a--    ';
    var unsub =    '    !    ';

    var result = e1
      .mergeMap(function (x) { return Observable.of(x); })
      .defaultIfEmpty('x')
      .mergeMap(function (x) { return Observable.of(x); });

    expectObservable(result, unsub).toBe(expected);
    expectSubscriptions(e1.subscriptions).toBe(e1subs);
  });

  it('should error if the Observable errors', function () {
    var e1 =  cold('#');
    var e1subs =   '(^!)';
    var expected = '#';

    expectObservable(e1.defaultIfEmpty('x')).toBe(expected);
    expectSubscriptions(e1.subscriptions).toBe(e1subs);
  });
});<|endoftext|>


<commit_before>/*
 @author Zakai Hamilton
 @component MediaFile
 */

screens.media.file = function MediaFile(me, packages) {
    const { core, storage, media, db } = packages;
    me.resolutions = ["800x600", "1024x768"];
    me.rootPath = "/Kab/concepts/private";
    me.cachePath = "cache";
    me.awsBucket = "screens";
    me.init = function () {
        const ffprobePath = require("@ffprobe-installer/ffprobe").path;
        me.ffmpeg = require("fluent-ffmpeg");
        me.ffmpeg.setFfprobePath(ffprobePath);
        me.os = require("os");
        me.tempDir = me.os.tmpdir();
        core.file.makeDir(me.cachePath);
        core.mutex.enable(me.id, true);
        core.broadcast.register(me, {
            startup: "media.file.groups"
        });
    };
    me.info = function (path) {
        return new Promise(resolve => {
            me.ffmpeg.ffprobe(path, function (err, info) {
                if (err) {
                    me.log_error("Cannot parse metadata for file: " + path + " error: " + err);
                    info = null;
                }
                resolve(info);
            });
        });
    };
    me.paths = function (groupName, path) {
        var paths = {
            local: me.cachePath + "/" + path,
            remote: me.rootPath + "/" + groupName + "/" + path
        };
        return paths;
    };
    me.download = async function (groupName, path) {
        var target = await me.manager.file.download(me.rootPath + "/" + groupName + "/" + path,
            me.cachePath + "/" + path);
        return target;
    };
    me.groups = async function (update = false) {
        var files = [];
        try {
            var unlock = await core.mutex.lock(me.id);
            files = await me.db.cache.file.listing(me.rootPath, update);
            for (let file of files) {
                file.path = me.rootPath + "/" + file.name;
                var sessions = await me.listing(file, update);
                sessions = sessions.sort((a, b) => a.label.localeCompare(b.label));
                sessions.reverse();
                file.sessions = sessions;
            }
            files = files.sort((a, b) => a.name.localeCompare(b.name));
            files.sort();
        }
        finally {
            unlock();
        }
        return files;
    };
    me.exists = async function (name) {
        var groups = await me.groups();
        for (var group of groups) {
            for (var session of group.sessions) {
                if (session.name.includes(name)) {
                    return group.name;
                }
            }
        }
        return null;
    };
    me.listing = async function (parent, update = false) {
        var files = await me.db.cache.file.listing(parent.path, update, async (file) => {
            let result = false;
            file.group = parent.name;
            file.session = core.path.fileName(file.name);
            file.extension = core.path.extension(file.name);
            file.label = core.string.title(core.path.fileName(file.name));
            file.remote = parent.path + "/" + file.name;
            file.local = me.cachePath + "/" + file.name;
            let awsPath = me.awsBucket + "/" + parent.name + "/" + file.name;
            if (!await me.storage.aws.exists(awsPath)) {
                me.log("Downloading file: " + file.local + ", size: " + file.size);
                await me.manager.file.download(file.remote, file.local);
                me.log("Uploading file: " + file.local + ", size: " + file.size);
                await me.storage.aws.uploadFile(file.local, awsPath);
                if (file.local.endsWith(".m4a")) {
                    me.log("Retrieving metadata for file: " + file.local);
                    var metadata = await me.info(file.local);
                    if (metadata) {
                        if (metadata.format) {
                            file.duration = metadata.format.duration;
                            file.durationText = core.string.formatDuration(file.duration);
                            result = true;
                            me.log("Found metadata for file: " + file.local);
                        }
                    }
                }
                await core.file.delete(file.local);
                me.log("Deleted file: " + file.local);
                me.log("Finished uploading file: " + file.local);
            }
            let resolutions = Array.from(file.resolutions);
            delete file.resolutions;
            if (file.local.endsWith(".mp4")) {
                file.resolutions = [];
                for (let resolution of me.resolutions) {
                    let path = me.awsBucket + "/" + file.group + "/" + file.session + "_" + resolution + ".mp4";
                    if (await me.storage.aws.exists(path)) {
                        file.resolutions.push(resolution);
                        me.log("Found resolution " + resolution + " for file: " + path);
                    }
                    else {
                        let result = await me.convertItem(resolution, file.group, file.session);
                        if (result) {
                            file.resolutions.push(resolution);
                        }
                    }
                }
                if (file.resolutions.length === resolutions.length) {
                    result = true;
                }
            }
            return result;
        });
        files.reverse();
        return files;
    };
    me.size = async function () {
        var info = { groups: {}, total: 0, count: 0 };
        var groups = await me.groups(true, true);
        for (let group of groups) {
            var files = group.sessions;
            ["m4a", "mp4"].map(extension => {
                let list = files.filter(file => file.extension === extension);
                var diskSize = list.reduce((total, item) => total + item.size, 0);
                let infoGroup = info.groups[group.name];
                if (!infoGroup) {
                    infoGroup = info.groups[group.name] = { total: 0, count: 0 };
                }
                infoGroup.total += diskSize;
                infoGroup.count += list.length;
                info.total += diskSize;
                info.total += list.length;
            });
        }
        for (let infoName in info.groups) {
            let group = info.groups[infoName];
            for (let key in group) {
                if (key === "total") {
                    continue;
                }
                group[key].total = core.string.formatBytes(group[key].total);
            }
            group.total = core.string.formatBytes(group.total);
        }
        info.total = core.string.formatBytes(info.total);
        return info;
    };
    me.updateListing = async function () {
        me.log("updateListing");
        var groups = await me.groups(true, true);
        for (let group of groups) {
            var files = group.sessions;
            var diskSize = files.reduce((total, item) => total + item.size, 0);
            me.log("Requires " + core.string.formatBytes(diskSize) + " Disk space for files");
            for (var file of files) {
                if (file.extension === "m4a") {
                    try {
                        if (!me.media.speech.exists(file.local)) {
                            me.log("transcribing: " + file.local);
                            await me.media.speech.transcribe(file.local);
                            var info = await me.manager.download.clean(me.tempDir, "flac");
                            me.log("cleaned cache, deleted: " + info.deleted + " failed: " + info.failed + " skipped: " + info.skipped);
                        }
                    }
                    catch (err) {
                        me.log_error("Failed to transcribe: " + file.local);
                    }
                }
            }
        }
        me.log("finished update");
    };
    me.streamingPath = function (group, name, extension, resolution) {
        let path = me.awsBucket + "/" + group + "/" + name + (resolution ? "_" + resolution : "") + "." + extension;
        return me.storage.aws.url(path);
    };
    me.convertItem = async function (resolution, group, session) {
        let result = false;
        try {
            var remote = me.awsBucket + "/" + group + "/" + session + ".mp4";
            var local = me.cachePath + "/" + session + ".mp4";
            var local_convert = me.cachePath + "/" + session + "_" + resolution + ".mp4";
            var remote_convert = me.awsBucket + "/" + group + "/" + session + "_" + resolution + ".mp4";
            if (!await core.file.exists(local_convert)) {
                if (!await core.file.exists(local)) {
                    me.log("downloading: " + remote + " to: " + local);
                    await storage.aws.downloadFile(remote, local);
                }
                me.log("converting: " + local + " to: " + local_convert);
                await media.ffmpeg.convert(local, local_convert, {
                    size: resolution
                });
            }
            me.log("uploading: " + local_convert + " to: " + remote_convert);
            await storage.aws.uploadFile(local_convert, remote_convert);
            me.log("deleting: " + local_convert);
            await core.file.delete(local_convert);
            me.log("deleting: " + local);
            await core.file.delete(local);
            me.log("finished: " + session);
            result = true;
        }
        catch (err) {
            me.log_error("Cannot convert session: " + session + " in group: " + group + " error: " + err);
        }
        return result;
    };
    me.convertListing = async function (resolution) {
        var groups = await me.groups();
        var argList = [];
        for (let group of groups) {
            var list = group.sessions.filter(session => session.extension === "mp4");
            for (let item of list) {
                var remote_convert = me.awsBucket + "/" + group.name + "/" + item.session + "_" + resolution + ".mp4";
                if (await storage.aws.exists(remote_convert)) {
                    continue;
                }
                argList.push({ group: group.name, session: item.session });
            }
        }
        await db.events.msg.sendParallel(argList);
    };
    return "server";
};
<commit_msg>bug fix<commit_after>/*
 @author Zakai Hamilton
 @component MediaFile
 */

screens.media.file = function MediaFile(me, packages) {
    const { core, storage, media, db } = packages;
    me.resolutions = ["800x600", "1024x768"];
    me.rootPath = "/Kab/concepts/private";
    me.cachePath = "cache";
    me.awsBucket = "screens";
    me.init = function () {
        const ffprobePath = require("@ffprobe-installer/ffprobe").path;
        me.ffmpeg = require("fluent-ffmpeg");
        me.ffmpeg.setFfprobePath(ffprobePath);
        me.os = require("os");
        me.tempDir = me.os.tmpdir();
        core.file.makeDir(me.cachePath);
        core.mutex.enable(me.id, true);
        core.broadcast.register(me, {
            startup: "media.file.groups"
        });
    };
    me.info = function (path) {
        return new Promise(resolve => {
            me.ffmpeg.ffprobe(path, function (err, info) {
                if (err) {
                    me.log_error("Cannot parse metadata for file: " + path + " error: " + err);
                    info = null;
                }
                resolve(info);
            });
        });
    };
    me.paths = function (groupName, path) {
        var paths = {
            local: me.cachePath + "/" + path,
            remote: me.rootPath + "/" + groupName + "/" + path
        };
        return paths;
    };
    me.download = async function (groupName, path) {
        var target = await me.manager.file.download(me.rootPath + "/" + groupName + "/" + path,
            me.cachePath + "/" + path);
        return target;
    };
    me.groups = async function (update = false) {
        var files = [];
        try {
            var unlock = await core.mutex.lock(me.id);
            files = await me.db.cache.file.listing(me.rootPath, update);
            for (let file of files) {
                file.path = me.rootPath + "/" + file.name;
                var sessions = await me.listing(file, update);
                sessions = sessions.sort((a, b) => a.label.localeCompare(b.label));
                sessions.reverse();
                file.sessions = sessions;
            }
            files = files.sort((a, b) => a.name.localeCompare(b.name));
            files.sort();
        }
        finally {
            unlock();
        }
        return files;
    };
    me.exists = async function (name) {
        var groups = await me.groups();
        for (var group of groups) {
            for (var session of group.sessions) {
                if (session.name.includes(name)) {
                    return group.name;
                }
            }
        }
        return null;
    };
    me.listing = async function (parent, update = false) {
        var files = await me.db.cache.file.listing(parent.path, update, async (file) => {
            let result = false;
            file.group = parent.name;
            file.session = core.path.fileName(file.name);
            file.extension = core.path.extension(file.name);
            file.label = core.string.title(core.path.fileName(file.name));
            file.remote = parent.path + "/" + file.name;
            file.local = me.cachePath + "/" + file.name;
            let awsPath = me.awsBucket + "/" + parent.name + "/" + file.name;
            if (!await me.storage.aws.exists(awsPath)) {
                me.log("Downloading file: " + file.local + ", size: " + file.size);
                await me.manager.file.download(file.remote, file.local);
                me.log("Uploading file: " + file.local + ", size: " + file.size);
                await me.storage.aws.uploadFile(file.local, awsPath);
                if (file.local.endsWith(".m4a")) {
                    me.log("Retrieving metadata for file: " + file.local);
                    var metadata = await me.info(file.local);
                    if (metadata) {
                        if (metadata.format) {
                            file.duration = metadata.format.duration;
                            file.durationText = core.string.formatDuration(file.duration);
                            result = true;
                            me.log("Found metadata for file: " + file.local);
                        }
                    }
                }
                await core.file.delete(file.local);
                me.log("Deleted file: " + file.local);
                me.log("Finished uploading file: " + file.local);
            }
            let resolutions = Array.from(file.resolutions);
            delete file.resolutions;
            if (file.local.endsWith(".mp4")) {
                file.resolutions = [];
                for (let resolution of me.resolutions) {
                    let path = me.awsBucket + "/" + file.group + "/" + file.session + "_" + resolution + ".mp4";
                    if (await me.storage.aws.exists(path)) {
                        file.resolutions.push(resolution);
                        me.log("Found resolution " + resolution + " for file: " + path);
                    }
                    else {
                        let result = await me.convertItem(resolution, file.group, file.session);
                        if (result) {
                            file.resolutions.push(resolution);
                        }
                    }
                }
                if (file.resolutions.length === resolutions.length) {
                    result = true;
                }
            }
            return result;
        });
        files.reverse();
        return files;
    };
    me.size = async function () {
        var info = { groups: {}, total: 0, count: 0 };
        var groups = await me.groups(true, true);
        for (let group of groups) {
            var files = group.sessions;
            ["m4a", "mp4"].map(extension => {
                let list = files.filter(file => file.extension === extension);
                var diskSize = list.reduce((total, item) => total + item.size, 0);
                let infoGroup = info.groups[group.name];
                if (!infoGroup) {
                    infoGroup = info.groups[group.name] = { total: 0, count: 0 };
                }
                infoGroup.total += diskSize;
                infoGroup.count += list.length;
                info.total += diskSize;
                info.total += list.length;
            });
        }
        for (let infoName in info.groups) {
            let group = info.groups[infoName];
            for (let key in group) {
                if (key === "total") {
                    continue;
                }
                group[key].total = core.string.formatBytes(group[key].total);
            }
            group.total = core.string.formatBytes(group.total);
        }
        info.total = core.string.formatBytes(info.total);
        return info;
    };
    me.updateListing = async function () {
        me.log("updateListing");
        var groups = await me.groups(true, true);
        for (let group of groups) {
            var files = group.sessions;
            var diskSize = files.reduce((total, item) => total + item.size, 0);
            me.log("Requires " + core.string.formatBytes(diskSize) + " Disk space for files");
            for (var file of files) {
                if (file.extension === "m4a") {
                    try {
                        if (!me.media.speech.exists(file.local)) {
                            me.log("transcribing: " + file.local);
                            await me.media.speech.transcribe(file.local);
                            var info = await me.manager.download.clean(me.tempDir, "flac");
                            me.log("cleaned cache, deleted: " + info.deleted + " failed: " + info.failed + " skipped: " + info.skipped);
                        }
                    }
                    catch (err) {
                        me.log_error("Failed to transcribe: " + file.local);
                    }
                }
            }
        }
        me.log("finished update");
    };
    me.streamingPath = function (group, name, extension, resolution) {
        let path = me.awsBucket + "/" + group + "/" + name + (resolution ? "_" + resolution : "") + "." + extension;
        return me.storage.aws.url(path);
    };
    me.convertItem = async function (resolution, group, session) {
        let result = false;
        try {
            var remote = me.awsBucket + "/" + group + "/" + session + ".mp4";
            var local = me.cachePath + "/" + session + ".mp4";
            var local_convert = me.cachePath + "/" + session + "_" + resolution + ".mp4";
            var remote_convert = me.awsBucket + "/" + group + "/" + session + "_" + resolution + ".mp4";
            if (await storage.aws.exists(remote_convert)) {
                return false;
            }
            if (!await core.file.exists(local_convert)) {
                if (!await core.file.exists(local)) {
                    me.log("downloading: " + remote + " to: " + local);
                    await storage.aws.downloadFile(remote, local);
                }
                me.log("converting: " + local + " to: " + local_convert);
                await media.ffmpeg.convert(local, local_convert, {
                    size: resolution
                });
            }
            me.log("uploading: " + local_convert + " to: " + remote_convert);
            await storage.aws.uploadFile(local_convert, remote_convert);
            me.log("deleting: " + local_convert);
            await core.file.delete(local_convert);
            me.log("deleting: " + local);
            await core.file.delete(local);
            me.log("finished: " + session);
            result = true;
        }
        catch (err) {
            me.log_error("Cannot convert session: " + session + " in group: " + group + " error: " + err);
        }
        return result;
    };
    me.convertListing = async function (resolution) {
        var groups = await me.groups();
        var argList = [];
        for (let group of groups) {
            var list = group.sessions.filter(session => session.extension === "mp4");
            for (let item of list) {
                var remote_convert = me.awsBucket + "/" + group.name + "/" + item.session + "_" + resolution + ".mp4";
                if (await storage.aws.exists(remote_convert)) {
                    continue;
                }
                argList.push({ group: group.name, session: item.session });
            }
        }
        await db.events.msg.sendParallel(argList);
    };
    return "server";
};
<|endoftext|>


<commit_before>// This file contains methods responsible for maintaining a TraversalContext.

import traverse from "../index";

export function call(key) {
  var node = this.node;
  if (!node) return;

  var opts = this.opts;

  for (var fns of [opts[key], opts[node.type] && opts[node.type][key]]){
    if (!fns) continue;

    for (var fn of (fns: Array)) {
      if (!fn) continue;

      let node = this.node;
      if (!node) return;

      var previousType = this.type;

      // call the function with the params (node, parent, scope, state)
      var replacement = fn.call(this, this, this.state);

      if (replacement) {
        this.replaceWith(replacement, true);
      }

      if (this.shouldStop || this.shouldSkip || this.removed) return;

      if (previousType !== this.type) {
        this.queueNode(this);
        return;
      }
    }
  }
}

export function isBlacklisted(): boolean {
  var blacklist = this.opts.blacklist;
  return blacklist && blacklist.indexOf(this.node.type) > -1;
}

export function visit(): boolean {
  if (this.isBlacklisted()) return false;
  if (this.opts.shouldSkip && this.opts.shouldSkip(this)) return false;

  this.call("enter");

  if (this.shouldSkip) {
    return this.shouldStop;
  }

  var node = this.node;
  var opts = this.opts;

  if (node) {
    if (Array.isArray(node)) {
      // traverse over these replacement nodes we purposely don't call exitNode
      // as the original node has been destroyed
      for (var i = 0; i < node.length; i++) {
        traverse.node(node[i], opts, this.scope, this.state, this, this.skipKeys);
      }
    } else {
      traverse.node(node, opts, this.scope, this.state, this, this.skipKeys);
      this.call("exit");
    }
  }

  return this.shouldStop;
}

export function skip() {
  this.shouldSkip = true;
}

export function skipKey(key) {
  this.skipKeys[key] = true;
}

export function stop() {
  this.shouldStop = true;
  this.shouldSkip = true;
}

export function setScope() {
  if (this.opts && this.opts.noScope) return;

  var target = this.context || this.parentPath;
  this.scope = this.getScope(target && target.scope);
  if (this.scope) this.scope.init();
}

export function setContext(context) {
  this.shouldSkip = false;
  this.shouldStop = false;
  this.removed    = false;
  this.skipKeys   = {};

  if (context) {
    this.context = context;
    this.state   = context.state;
    this.opts    = context.opts;
  }

  this.setScope();

  return this;
}

/**
 * Here we resync the node paths `key` and `container`. If they've changed according
 * to what we have stored internally then we attempt to resync by crawling and looking
 * for the new values.
 */

export function resync() {
  if (this.removed) return;

  this._resyncParent();
  this._resyncList();
  this._resyncKey();
  //this._resyncRemoved();
}

export function _resyncParent() {
  if (this.parentPath) {
    this.parent = this.parentPath.node;
  }
}

export function _resyncKey() {
  if (!this.container) return;

  if (this.node === this.container[this.key]) return;

  // grrr, path key is out of sync. this is likely due to a modification to the AST
  // not done through our path APIs

  if (Array.isArray(this.container)) {
    for (var i = 0; i < this.container.length; i++) {
      if (this.container[i] === this.node) {
        return this.setKey(i);
      }
    }
  } else {
    for (var key in this.container) {
      if (this.container[key] === this.node) {
        return this.setKey(key);
      }
    }
  }

  this.key = null;
}

export function _resyncList() {
  var listKey    = this.listKey;
  var parentPath = this.parentPath;
  if (!listKey || !parentPath || !parentPath.node) return;

  var newContainer = parentPath.node[listKey];
  if (this.container === newContainer) return;

  // container is out of sync. this is likely the result of it being reassigned

  if (newContainer) {
    this.container = newContainer;
  } else {
    this.container = null;
  }
}

export function _resyncRemoved() {
  if (this.key == null || !this.container || this.container[this.key] !== this.node) {
    this._markRemoved();
  }
}

export function shiftContext() {
  this.contexts.shift();
  this.setContext(this.contexts[0]);
}

export function unshiftContext(context) {
  this.contexts.unshift(context);
  this.setContext(context);
}

export function setup(parentPath, container, listKey, key) {
  this.inList    = !!listKey;
  this.listKey   = listKey;
  this.parentKey = listKey || key;
  this.container = container;

  this.parentPath = parentPath || this.parentPath;
  this.setKey(key);
}

export function setKey(key) {
  this.key  = key;
  this.node = this.container[this.key];
  this.type = this.node && this.node.type;
}

export function queueNode(path) {
  for (var context of (this.contexts: Array)) {
    if (context.queue) {
      context.queue.push(path);
    }
  }
}
<commit_msg>don't allow visitor methods to return a new node to replace<commit_after>// This file contains methods responsible for maintaining a TraversalContext.

import traverse from "../index";

export function call(key) {
  var node = this.node;
  if (!node) return;

  var opts = this.opts;

  for (var fns of [opts[key], opts[node.type] && opts[node.type][key]]){
    if (!fns) continue;

    for (var fn of (fns: Array)) {
      if (!fn) continue;

      let node = this.node;
      if (!node) return;

      var previousType = this.type;

      // call the function with the params (node, parent, scope, state)
      var replacement = fn.call(this, this, this.state);

      if (replacement) {
        throw new Error("Unexpected return value from visitor method");
      }

      if (this.shouldStop || this.shouldSkip || this.removed) return;

      if (previousType !== this.type) {
        this.queueNode(this);
        return;
      }
    }
  }
}

export function isBlacklisted(): boolean {
  var blacklist = this.opts.blacklist;
  return blacklist && blacklist.indexOf(this.node.type) > -1;
}

export function visit(): boolean {
  if (this.isBlacklisted()) return false;
  if (this.opts.shouldSkip && this.opts.shouldSkip(this)) return false;

  this.call("enter");

  if (this.shouldSkip) {
    return this.shouldStop;
  }

  var node = this.node;
  var opts = this.opts;

  if (node) {
    if (Array.isArray(node)) {
      // traverse over these replacement nodes we purposely don't call exitNode
      // as the original node has been destroyed
      for (var i = 0; i < node.length; i++) {
        traverse.node(node[i], opts, this.scope, this.state, this, this.skipKeys);
      }
    } else {
      traverse.node(node, opts, this.scope, this.state, this, this.skipKeys);
      this.call("exit");
    }
  }

  return this.shouldStop;
}

export function skip() {
  this.shouldSkip = true;
}

export function skipKey(key) {
  this.skipKeys[key] = true;
}

export function stop() {
  this.shouldStop = true;
  this.shouldSkip = true;
}

export function setScope() {
  if (this.opts && this.opts.noScope) return;

  var target = this.context || this.parentPath;
  this.scope = this.getScope(target && target.scope);
  if (this.scope) this.scope.init();
}

export function setContext(context) {
  this.shouldSkip = false;
  this.shouldStop = false;
  this.removed    = false;
  this.skipKeys   = {};

  if (context) {
    this.context = context;
    this.state   = context.state;
    this.opts    = context.opts;
  }

  this.setScope();

  return this;
}

/**
 * Here we resync the node paths `key` and `container`. If they've changed according
 * to what we have stored internally then we attempt to resync by crawling and looking
 * for the new values.
 */

export function resync() {
  if (this.removed) return;

  this._resyncParent();
  this._resyncList();
  this._resyncKey();
  //this._resyncRemoved();
}

export function _resyncParent() {
  if (this.parentPath) {
    this.parent = this.parentPath.node;
  }
}

export function _resyncKey() {
  if (!this.container) return;

  if (this.node === this.container[this.key]) return;

  // grrr, path key is out of sync. this is likely due to a modification to the AST
  // not done through our path APIs

  if (Array.isArray(this.container)) {
    for (var i = 0; i < this.container.length; i++) {
      if (this.container[i] === this.node) {
        return this.setKey(i);
      }
    }
  } else {
    for (var key in this.container) {
      if (this.container[key] === this.node) {
        return this.setKey(key);
      }
    }
  }

  this.key = null;
}

export function _resyncList() {
  var listKey    = this.listKey;
  var parentPath = this.parentPath;
  if (!listKey || !parentPath || !parentPath.node) return;

  var newContainer = parentPath.node[listKey];
  if (this.container === newContainer) return;

  // container is out of sync. this is likely the result of it being reassigned

  if (newContainer) {
    this.container = newContainer;
  } else {
    this.container = null;
  }
}

export function _resyncRemoved() {
  if (this.key == null || !this.container || this.container[this.key] !== this.node) {
    this._markRemoved();
  }
}

export function shiftContext() {
  this.contexts.shift();
  this.setContext(this.contexts[0]);
}

export function unshiftContext(context) {
  this.contexts.unshift(context);
  this.setContext(context);
}

export function setup(parentPath, container, listKey, key) {
  this.inList    = !!listKey;
  this.listKey   = listKey;
  this.parentKey = listKey || key;
  this.container = container;

  this.parentPath = parentPath || this.parentPath;
  this.setKey(key);
}

export function setKey(key) {
  this.key  = key;
  this.node = this.container[this.key];
  this.type = this.node && this.node.type;
}

export function queueNode(path) {
  for (var context of (this.contexts: Array)) {
    if (context.queue) {
      context.queue.push(path);
    }
  }
}
<|endoftext|>


<commit_before>/**
 * Ecommerce Classes
 */
inji.Ecommerce = {
  Cart: new function () {
    this.addItem = function (itemOfferPriceId, count) {
      inji.Server.request({
        url: 'ecommerce/cart/add',
        data: {
          itemOfferPriceId: itemOfferPriceId,
          count: count,
        },
        success: function (data) {
          console.log(data);
          inji.Server.request({
            url: 'ecommerce/cart/getCart',
            success: function (data) {
              $("#cart").html(data);
            }
          });
        }
      });
    }
    this.calcSum = function () {
      var form = $('.ecommerce .cart-order_page form');
      var formData = new FormData(form[0]);
      $('.ecommerce .cart-order_page').prepend($('

'));
      inji.Server.request({
        url: form.attr('action'),
        type: 'POST',
        data: formData,
        dataType: 'html',
        processData: false,
        success: function (data) {
          var html = $('
' + data.replace(/\n/g, " ") + '
');
          $('.ecommerce .cart-order_page').html(html.find('.ecommerce .cart-order_page'));
        }
      });
    }
    this.delItem = function (cart_item_id) {
      var form = $('.ecommerce .cart-order_page form');
      $('.cart_item_id' + cart_item_id).remove();
      var formData = new FormData(form[0]);
      $('.ecommerce .cart-order_page').prepend($('

'));
      inji.Server.request({
        url: form.attr('action'),
        type: 'POST',
        data: formData,
        dataType: 'html',
        processData: false,
        success: function (data) {
          var html = $('
' + data.replace(/\n/g, " ") + '
');
          $('.ecommerce .cart-order_page').html(html.find('.ecommerce .cart-order_page'));
        }
      });
    }
  }
}
inji.onLoad(function () {

  //plugin bootstrap minus and plus
  //http://jsfiddle.net/laelitenetwork/puJ6G/
  $('body').on('click', '.btn-number', function (e) {
    e.preventDefault();

    var fieldName = $(this).data('field');
    var type = $(this).data('type');
    var input = $("input[name='" + fieldName + "']");
    var currentVal = parseFloat(input.val());
    if (!isNaN(currentVal)) {
      if (type == 'minus') {

        if (currentVal > input.attr('min')) {
          input.val(currentVal - 1).change();
        }
        if (parseFloat(input.val()) == input.attr('min')) {
          $(this).attr('disabled', true);
        }

      } else if (type == 'plus') {

        if (currentVal < input.attr('max')) {
          input.val(currentVal + 1).change();
        }
        if (parseFloat(input.val()) == input.attr('max')) {
          $(this).attr('disabled', true);
        }

      }
    } else {
      input.val(0);
    }
  });
  $('body').on('focusin', '.input-number', function () {
    $(this).data('oldValue', $(this).val());
  });
  $('body').on('change', '.input-number', function () {

    var minValue = parseFloat($(this).attr('min'));
    var maxValue = parseFloat($(this).attr('max'));
    var valueCurrent = parseFloat($(this).val());

    var name = $(this).attr('name');
    if (valueCurrent >= minValue) {
      $(".btn-number[data-type='minus'][data-field='" + name + "']").removeAttr('disabled')
    } else {
      alert('Нельзя заказать меньше ' + minValue);
      $(this).val($(this).data('oldValue'));
    }
    if (valueCurrent <= maxValue) {
      $(".btn-number[data-type='plus'][data-field='" + name + "']").removeAttr('disabled')
    } else {
      alert('Извините, но больше нету');
      $(this).val($(this).data('oldValue'));
    }

  });

  $('body').on('keydown', ".input-number", function (e) {
    // Allow: backspace, delete, tab, escape, enter and .
    if ($.inArray(e.keyCode, [46, 8, 9, 27, 13, 190]) !== -1 ||
            // Allow: Ctrl+A
                    (e.keyCode == 65 && e.ctrlKey === true) ||
                    // Allow: home, end, left, right
                            (e.keyCode >= 35 && e.keyCode <= 39)) {
              // let it happen, don't do anything
              return;
            }
            // Ensure that it is a number and stop the keypress
            if ((e.shiftKey || (e.keyCode < 48 || e.keyCode > 57)) && (e.keyCode < 96 || e.keyCode > 105)) {
              e.preventDefault();
            }
          });

})
<commit_msg>adition cart replace widget selector<commit_after>/**
 * Ecommerce Classes
 */
inji.Ecommerce = {
  Cart: new function () {
    this.addItem = function (itemOfferPriceId, count) {
      inji.Server.request({
        url: 'ecommerce/cart/add',
        data: {
          itemOfferPriceId: itemOfferPriceId,
          count: count,
        },
        success: function (data) {
          console.log(data);
          inji.Server.request({
            url: 'ecommerce/cart/getCart',
            success: function (data) {
              $("#cart,.cartplace").html(data);
            }
          });
        }
      });
    }
    this.calcSum = function () {
      var form = $('.ecommerce .cart-order_page form');
      var formData = new FormData(form[0]);
      $('.ecommerce .cart-order_page').prepend($('

'));
      inji.Server.request({
        url: form.attr('action'),
        type: 'POST',
        data: formData,
        dataType: 'html',
        processData: false,
        success: function (data) {
          var html = $('
' + data.replace(/\n/g, " ") + '
');
          $('.ecommerce .cart-order_page').html(html.find('.ecommerce .cart-order_page'));
        }
      });
    }
    this.delItem = function (cart_item_id) {
      var form = $('.ecommerce .cart-order_page form');
      $('.cart_item_id' + cart_item_id).remove();
      var formData = new FormData(form[0]);
      $('.ecommerce .cart-order_page').prepend($('

'));
      inji.Server.request({
        url: form.attr('action'),
        type: 'POST',
        data: formData,
        dataType: 'html',
        processData: false,
        success: function (data) {
          var html = $('
' + data.replace(/\n/g, " ") + '
');
          $('.ecommerce .cart-order_page').html(html.find('.ecommerce .cart-order_page'));
        }
      });
    }
  }
}
inji.onLoad(function () {

  //plugin bootstrap minus and plus
  //http://jsfiddle.net/laelitenetwork/puJ6G/
  $('body').on('click', '.btn-number', function (e) {
    e.preventDefault();

    var fieldName = $(this).data('field');
    var type = $(this).data('type');
    var input = $("input[name='" + fieldName + "']");
    var currentVal = parseFloat(input.val());
    if (!isNaN(currentVal)) {
      if (type == 'minus') {

        if (currentVal > input.attr('min')) {
          input.val(currentVal - 1).change();
        }
        if (parseFloat(input.val()) == input.attr('min')) {
          $(this).attr('disabled', true);
        }

      } else if (type == 'plus') {

        if (currentVal < input.attr('max')) {
          input.val(currentVal + 1).change();
        }
        if (parseFloat(input.val()) == input.attr('max')) {
          $(this).attr('disabled', true);
        }

      }
    } else {
      input.val(0);
    }
  });
  $('body').on('focusin', '.input-number', function () {
    $(this).data('oldValue', $(this).val());
  });
  $('body').on('change', '.input-number', function () {

    var minValue = parseFloat($(this).attr('min'));
    var maxValue = parseFloat($(this).attr('max'));
    var valueCurrent = parseFloat($(this).val());

    var name = $(this).attr('name');
    if (valueCurrent >= minValue) {
      $(".btn-number[data-type='minus'][data-field='" + name + "']").removeAttr('disabled')
    } else {
      alert('Нельзя заказать меньше ' + minValue);
      $(this).val($(this).data('oldValue'));
    }
    if (valueCurrent <= maxValue) {
      $(".btn-number[data-type='plus'][data-field='" + name + "']").removeAttr('disabled')
    } else {
      alert('Извините, но больше нету');
      $(this).val($(this).data('oldValue'));
    }

  });

  $('body').on('keydown', ".input-number", function (e) {
    // Allow: backspace, delete, tab, escape, enter and .
    if ($.inArray(e.keyCode, [46, 8, 9, 27, 13, 190]) !== -1 ||
            // Allow: Ctrl+A
                    (e.keyCode == 65 && e.ctrlKey === true) ||
                    // Allow: home, end, left, right
                            (e.keyCode >= 35 && e.keyCode <= 39)) {
              // let it happen, don't do anything
              return;
            }
            // Ensure that it is a number and stop the keypress
            if ((e.shiftKey || (e.keyCode < 48 || e.keyCode > 57)) && (e.keyCode < 96 || e.keyCode > 105)) {
              e.preventDefault();
            }
          });

})
<|endoftext|>


<commit_before>const _ = require('lodash');
const async = require('async');

/**
 * Expose the strategy to load
 * built-in hooks
 */
module.exports = class Hook {

  constructor(definition) {
    /**
     * Default configuration for this hook
     * (should be overriden by hook definition)
     *
     * @return {}
     */
    this.defaults = {};
    this.config = {};

    // Merge default definition with overrides in the definition passed in.
    _.assign(this, definition);
  }

  initialize(cb) {
    return cb();
  }

  load(cb) {
    this.initialize(cb);
  }
};
<commit_msg>Remove useless pkg<commit_after>const _ = require('lodash');

/**
 * Expose the strategy to load
 * built-in hooks
 */
module.exports = class Hook {

  constructor(definition) {
    /**
     * Default configuration for this hook
     * (should be overriden by hook definition)
     *
     * @return {}
     */
    this.defaults = {};
    this.config = {};

    // Merge default definition with overrides in the definition passed in.
    _.assign(this, definition);
  }

  initialize(cb) {
    return cb();
  }

  load(cb) {
    this.initialize(cb);
  }
};
<|endoftext|>


<commit_before>$(document).ready(function(){

  //Clicking X closes popUp
  $('.escapeMe').on('click', function(){
    $('.popUp').hide();
  });
  //Reveals popUp
  $('#aboutMap').on('click', function(event){
    event.stopPropagation();
    $('#readFirst').show();
    $('#faqsPopUp').hide();
  });
  $('#faqs').on('click', function(event){
    event.stopPropagation();
    $('#faqsPopUp').show();
  });
  //clicking off the popUp hides it
  $(document).on('click', function(){
    $('.popUp').hide();
  });
  //clicking on the popUp does not hides it
  $('.popUp').on('click', function(e){
    e.stopPropagation();
    return false;
  });

//the map and where it centers and sets zoom level
var map = L.map('map').setView([44.514198, -89.740264], 8);

//the background layer
var Carto_Positron = L.tileLayer('http://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png', {
  attribution: '© OpenStreetMap contributors, © CartoDB',
  subdomains: 'abcd',
  minZoom: 0,
  maxZoom: 20,
  ext: 'png'
});
Carto_Positron.addTo(map);

//the three different layers we want to have in the map
var url = 'http://cidasddvasnwc.cr.usgs.gov:8082/geoserver/gwc/service/wms?service=wms&tiled=true';

//the better wms javascript for getfeatureinfo from wms
L.TileLayer.BetterWMS = L.TileLayer.WMS.extend({

  onAdd: function(map) {
    // Triggered when the layer is added to a map.
    //   Register a click listener, then do all the upstream WMS things
    L.TileLayer.WMS.prototype.onAdd.call(this, map);
    map.on('click', this.getFeatureInfo, this);
  },

  onRemove: function(map) {
    // Triggered when the layer is removed from a map.
    //   Unregister a click listener, then do all the upstream WMS things
    L.TileLayer.WMS.prototype.onRemove.call(this, map);
    map.off('click', this.getFeatureInfo, this);
  },

  getFeatureInfo: function(evt) {
    // Make an AJAX request to the server and hope for the best
    var url = this.getFeatureInfoUrl(evt.latlng),
      showResults = L.Util.bind(this.showGetFeatureInfo, this);
    $.ajax({
      url: url,
      success: function(data, status, xhr) {
        var err = typeof data === 'string' ? null : data;
        showResults(err, evt.latlng, data);
      },
      error: function(xhr, status, error) {
        showResults(error);
      }
    });
  },

  getFeatureInfoUrl: function(latlng) {
    // Construct a GetFeatureInfo request URL given a point
    var point = this._map.latLngToContainerPoint(latlng, this._map.getZoom()),
      size = this._map.getSize(),

      params = {
        request: 'GetFeatureInfo',
        service: 'WMS',
        srs: 'EPSG:4326',
        styles: this.wmsParams.styles,
        transparent: this.wmsParams.transparent,
        version: this.wmsParams.version,
        format: this.wmsParams.format,
        bbox: this._map.getBounds().toBBoxString(),
        height: size.y,
        width: size.x,
        layers: this.wmsParams.layers,
        query_layers: this.wmsParams.layers,
        info_format: 'text/html'
      };

    params[params.version === '1.3.0' ? 'i' : 'x'] = Math.floor(point.x);
    params[params.version === '1.3.0' ? 'j' : 'y'] = Math.floor(point.y);

    return this._url + L.Util.getParamString(params, this._url, true);
  },

  showGetFeatureInfo: function(err, latlng, content) {
    if (err) {
      console.log(err);
      return;
    } // do nothing if there's an error

    // Otherwise show the content in a popup, or something.
    // Check content.length() to see if it's more than 658ish characters, because actual features have more than that, empty responses from Geoserver have about that many characters
    console.log(content.length);
    if (content.length > 660) {
      L.popup({
          maxWidth: 800
        })
        .setLatLng(latlng)
        .setContent(content)
        .openOn(this._map);
    }
  }
});

//betterWMSing the three layers
L.tileLayer.betterWms = function(url, options) {
  return new L.TileLayer.BetterWMS(url, options);
};

// when the user changes baselayers, close the popup
map.on('baselayerchange', function(a) {
				console.log(a);
        map.closePopup();
    });

//putting the layers on the map with betterwms
//early 1989-2014
var early = L.tileLayer.betterWms(url, {
  layers: 'vizlab:predicted_species_1989-2014',
  transparent: true,
  format: 'image/png'
});
early.addTo(map);

//mid 2040-2064
var mid = L.tileLayer.betterWms(url, {
  layers: 'vizlab:predicted_species_2040-2064',
  transparent: true,
  format: 'image/png'
});

//late 2065-2089
var late = L.tileLayer.betterWms(url, {
  layers: 'vizlab:predicted_species_2065-2089',
  transparent: true,
  format: 'image/png'
});

/*
 * L.Control.WMSLegend is used to add a WMS Legend to the map
 */

L.Control.WMSLegend = L.Control.extend({
  options: {
    position: 'bottomright',
    uri: ''
  },

  onAdd: function() {
    var controlClassName = 'leaflet-control-wms-legend',
      legendClassName = 'wms-legend',
      stop = L.DomEvent.stopPropagation;
    this.container = L.DomUtil.create('div', controlClassName);
    this.img = L.DomUtil.create('img', legendClassName, this.container);
    this.img.src = uri;
    this.img.alt = 'Legend';

    L.DomEvent
      .on(this.img, 'click', this._click, this)
      .on(this.container, 'click', this._click, this)
      .on(this.img, 'mousedown', stop)
      .on(this.img, 'dblclick', stop)
      .on(this.img, 'click', L.DomEvent.preventDefault)
      .on(this.img, 'click', stop);
    this.height = null;
    this.width = null;
    return this.container;
  },
  _click: function(e) {
    L.DomEvent.stopPropagation(e);
    L.DomEvent.preventDefault(e);
    // toggle legend visibility
    var style = window.getComputedStyle(this.img);
    if (style.display === 'none') {
      this.container.style.height = this.height + 'px';
      this.container.style.width = this.width + 'px';
      this.img.style.display = this.displayStyle;
    } else {
      if (this.width === null && this.height === null) {
        // Only do inside the above check to prevent the container
        // growing on successive uses
        this.height = this.container.offsetHeight;
        this.width = this.container.offsetWidth;
      }
      this.displayStyle = this.img.style.display;
      this.img.style.display = 'none';
      this.container.style.height = '20px';
      this.container.style.width = '20px';
    }
  },
});

L.wmsLegend = function(uri) {
  var wmsLegendControl = new L.Control.WMSLegend;
  wmsLegendControl.options.uri = uri;
  map.addControl(wmsLegendControl);
  return wmsLegendControl;
};

uri = "http://cidasddvasnwc.cr.usgs.gov:8082/geoserver/gwc/service/wms?service=wms&request=GetLegendGraphic&format=image%2Fpng&width=20&height=20&layer=vizlab:predicted_species_1989-2014";
L.wmsLegend(uri);

// layer toggle
// Use basemaps instead of overlays because basemaps allows only one to be on at a time, and we always want one to be on. swap basemaps with overlays if you want checkboxes. collapsed false refers to the toggle not being hidden initially
var basemaps = {
  "1989-2014": early,
  "2040-2064": mid,
  "2065-2089": late
};
var layerControl2 = L.control.layers(basemaps, null, {
  collapsed: false
});
map.addControl(layerControl2);
});
<commit_msg>update geoserver<commit_after>$(document).ready(function(){

  //Clicking X closes popUp
  $('.escapeMe').on('click', function(){
    $('.popUp').hide();
  });
  //Reveals popUp
  $('#aboutMap').on('click', function(event){
    event.stopPropagation();
    $('#readFirst').show();
    $('#faqsPopUp').hide();
  });
  $('#faqs').on('click', function(event){
    event.stopPropagation();
    $('#faqsPopUp').show();
  });
  //clicking off the popUp hides it
  $(document).on('click', function(){
    $('.popUp').hide();
  });
  //clicking on the popUp does not hides it
  $('.popUp').on('click', function(e){
    e.stopPropagation();
    return false;
  });

//the map and where it centers and sets zoom level
var map = L.map('map').setView([44.514198, -89.740264], 8);

//the background layer
var Carto_Positron = L.tileLayer('http://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png', {
  attribution: '© OpenStreetMap contributors, © CartoDB',
  subdomains: 'abcd',
  minZoom: 0,
  maxZoom: 20,
  ext: 'png'
});
Carto_Positron.addTo(map);

//the three different layers we want to have in the map
var url = 'http://cidasddvasnwc.cr.usgs.gov:8082/geoserver/wms?service=wms&tiled=true';

//the better wms javascript for getfeatureinfo from wms
L.TileLayer.BetterWMS = L.TileLayer.WMS.extend({

  onAdd: function(map) {
    // Triggered when the layer is added to a map.
    //   Register a click listener, then do all the upstream WMS things
    L.TileLayer.WMS.prototype.onAdd.call(this, map);
    map.on('click', this.getFeatureInfo, this);
  },

  onRemove: function(map) {
    // Triggered when the layer is removed from a map.
    //   Unregister a click listener, then do all the upstream WMS things
    L.TileLayer.WMS.prototype.onRemove.call(this, map);
    map.off('click', this.getFeatureInfo, this);
  },

  getFeatureInfo: function(evt) {
    // Make an AJAX request to the server and hope for the best
    var url = this.getFeatureInfoUrl(evt.latlng),
      showResults = L.Util.bind(this.showGetFeatureInfo, this);
    $.ajax({
      url: url,
      success: function(data, status, xhr) {
        var err = typeof data === 'string' ? null : data;
        showResults(err, evt.latlng, data);
      },
      error: function(xhr, status, error) {
        showResults(error);
      }
    });
  },

  getFeatureInfoUrl: function(latlng) {
    // Construct a GetFeatureInfo request URL given a point
    var point = this._map.latLngToContainerPoint(latlng, this._map.getZoom()),
      size = this._map.getSize(),

      params = {
        request: 'GetFeatureInfo',
        service: 'WMS',
        srs: 'EPSG:4326',
        styles: this.wmsParams.styles,
        transparent: this.wmsParams.transparent,
        version: this.wmsParams.version,
        format: this.wmsParams.format,
        bbox: this._map.getBounds().toBBoxString(),
        height: size.y,
        width: size.x,
        layers: this.wmsParams.layers,
        query_layers: this.wmsParams.layers,
        info_format: 'text/html'
      };

    params[params.version === '1.3.0' ? 'i' : 'x'] = Math.floor(point.x);
    params[params.version === '1.3.0' ? 'j' : 'y'] = Math.floor(point.y);

    return this._url + L.Util.getParamString(params, this._url, true);
  },

  showGetFeatureInfo: function(err, latlng, content) {
    if (err) {
      console.log(err);
      return;
    } // do nothing if there's an error

    // Otherwise show the content in a popup, or something.
    // Check content.length() to see if it's more than 658ish characters, because actual features have more than that, empty responses from Geoserver have about that many characters

    if (content.length > 660) {
      L.popup({
          maxWidth: 800
        })
        .setLatLng(latlng)
        .setContent(content)
        .openOn(this._map);
    }
  }
});

//betterWMSing the three layers
L.tileLayer.betterWms = function(url, options) {
  return new L.TileLayer.BetterWMS(url, options);
};

// when the user changes baselayers, close the popup
map.on('baselayerchange', function(a) {

        map.closePopup();
    });

//putting the layers on the map with betterwms
//early 1989-2014
var early = L.tileLayer.betterWms(url, {
  layers: 'vizlab:predicted_species_1989-2014',
  transparent: true,
  format: 'image/png'
});
early.addTo(map);

//mid 2040-2064
var mid = L.tileLayer.betterWms(url, {
  layers: 'vizlab:predicted_species_2040-2064',
  transparent: true,
  format: 'image/png'
});

//late 2065-2089
var late = L.tileLayer.betterWms(url, {
  layers: 'vizlab:predicted_species_2065-2089',
  transparent: true,
  format: 'image/png'
});

/*
 * L.Control.WMSLegend is used to add a WMS Legend to the map
 */

L.Control.WMSLegend = L.Control.extend({
  options: {
    position: 'bottomright',
    uri: ''
  },

  onAdd: function() {
    var controlClassName = 'leaflet-control-wms-legend',
      legendClassName = 'wms-legend',
      stop = L.DomEvent.stopPropagation;
    this.container = L.DomUtil.create('div', controlClassName);
    this.img = L.DomUtil.create('img', legendClassName, this.container);
    this.img.src = uri;
    this.img.alt = 'Legend';

    L.DomEvent
      .on(this.img, 'click', this._click, this)
      .on(this.container, 'click', this._click, this)
      .on(this.img, 'mousedown', stop)
      .on(this.img, 'dblclick', stop)
      .on(this.img, 'click', L.DomEvent.preventDefault)
      .on(this.img, 'click', stop);
    this.height = null;
    this.width = null;
    return this.container;
  },
  _click: function(e) {
    L.DomEvent.stopPropagation(e);
    L.DomEvent.preventDefault(e);
    // toggle legend visibility
    var style = window.getComputedStyle(this.img);
    if (style.display === 'none') {
      this.container.style.height = this.height + 'px';
      this.container.style.width = this.width + 'px';
      this.img.style.display = this.displayStyle;
    } else {
      if (this.width === null && this.height === null) {
        // Only do inside the above check to prevent the container
        // growing on successive uses
        this.height = this.container.offsetHeight;
        this.width = this.container.offsetWidth;
      }
      this.displayStyle = this.img.style.display;
      this.img.style.display = 'none';
      this.container.style.height = '20px';
      this.container.style.width = '20px';
    }
  },
});

L.wmsLegend = function(uri) {
  var wmsLegendControl = new L.Control.WMSLegend;
  wmsLegendControl.options.uri = uri;
  map.addControl(wmsLegendControl);
  return wmsLegendControl;
};

uri = "http://cidasddvasnwc.cr.usgs.gov:8082/geoserver/gwc/service/wms?service=wms&request=GetLegendGraphic&format=image%2Fpng&width=20&height=20&layer=vizlab:predicted_species_1989-2014";
L.wmsLegend(uri);

// layer toggle
// Use basemaps instead of overlays because basemaps allows only one to be on at a time, and we always want one to be on. swap basemaps with overlays if you want checkboxes. collapsed false refers to the toggle not being hidden initially
var basemaps = {
  "1989-2014": early,
  "2040-2064": mid,
  "2065-2089": late
};
var layerControl2 = L.control.layers(basemaps, null, {
  collapsed: false
});
map.addControl(layerControl2);
});
<|endoftext|>


<commit_before>module.exports = function(grunt) {

    // Project configuration.
    grunt.initConfig({
        pkg: grunt.file.readJSON('package.json'),
        jshint: {
            files: ['gruntfile.js', 'index.js', 'js/**/*.js', 'tests/*.js'],
            options: {
                // options here to override JSHint defaults
                globals: {
                    console: true,
                    module: true,
                    document: true
                }
            }
        },
        browserify: {
            'build/pages.js': ['index.js']
        },
        clean: ['build'],
        copy: [
            { expand: true, flatten: true, src: ['html/index.html'], dest: 'build/' },
            { expand: true, flatten: true, src: ['lib/*'], dest: 'build/lib/' },
            { expand: true, flatten: true, src: ['css/*'], dest: 'build/css/' }
        ],
        simplemocha: {
            options: {
                globals: ['expect'],
                timeout: 3000,
                ignoreLeaks: false,
                ui: 'bdd',
                reporter: 'tap'
            },
            all: { src: ['tests/*.js'] }
        }
    });

    //Tasks
    grunt.registerTask('build', ['clean', 'jshint', 'simplemocha', 'copy', 'browserify']); //Generates build folder

    // Load the plugins
    grunt.loadNpmTasks('grunt-contrib-jshint');
    grunt.loadNpmTasks('grunt-contrib-clean');
    grunt.loadNpmTasks('grunt-contrib-copy');
    grunt.loadNpmTasks('grunt-simple-mocha');
    grunt.loadNpmTasks('grunt-browserify');
};
<commit_msg>new workflow<commit_after>module.exports = function(grunt) {

    // Project configuration.
    grunt.initConfig({
        pkg: grunt.file.readJSON('package.json'),
        jshint: {
            files: ['gruntfile.js', 'index.js', 'js/**/*.js', 'tests/*.js'],
            options: {
                // options here to override JSHint defaults
                globals: {
                    console: true,
                    module: true,
                    document: true
                }
            }
        },
        browserify: {
            'dist/app.js': ['index.js']
        },
        clean: ['dist'],
        copy: [
            { expand: true, flatten: true, src: ['html/index.html'], dest: 'build/' },
            { expand: true, flatten: true, src: ['lib/*'], dest: 'build/lib/' },
            { expand: true, flatten: true, src: ['css/*'], dest: 'build/css/' }
        ],
        simplemocha: {
            options: {
                globals: ['expect'],
                timeout: 3000,
                ignoreLeaks: false,
                ui: 'bdd',
                reporter: 'tap'
            },
            all: { src: ['tests/*.js'] }
        },
        less: {
            development: {
                options: {
                    compress: true,
                    yuicompress: true,
                    optimization: 2
                },
                files: {
                    "dist/css/creative.css": "less/creative.less" // destination file and source file
                }
            }
        }
    });

    //Tasks
    grunt.registerTask('dist', ['jshint', 'simplemocha', 'less', 'browserify']); //Generates build folder

    // Load the plugins
    grunt.loadNpmTasks('grunt-contrib-jshint');
    grunt.loadNpmTasks('grunt-contrib-clean');
    grunt.loadNpmTasks('grunt-contrib-copy');
    grunt.loadNpmTasks('grunt-simple-mocha');
    grunt.loadNpmTasks('grunt-browserify');
    grunt.loadNpmTasks('grunt-contrib-less');
};
<|endoftext|>


<commit_before>import React from "react";

import JSONTransform from "@nteract/transforms/lib/json";
import HTML from "@nteract/transforms/lib/html";
import Text from "@nteract/transforms/lib/text";

import Editor from "@nteract/notebook-preview/lib/editor";

const HokeyTable = props => (

          {props.columnNames.map(column => (
            {column.name}
          ))}

        {props.rows.map((row, idx) => (

            {row.map((item, colIdx) => {item}	)}

        ))}

);

const UnsupportedResult = props => (

UNSUPPORTED ZEPPELIN RESULT

    <JSONTransform data={props.result} />

);

const Result = props => {
  if (!props.result) {
    return null;
  }
  switch (props.result.type) {
    case "HTML":
      return ;
    case "TEXT":
      return <Text data={props.result.msg} />;
    case "TABLE":
      if (!props.result.columnNames || !props.result.rows) {
        return <UnsupportedResult result={props.result} />;
      }
      return (
        <HokeyTable
          columnNames={props.result.columnNames}
          rows={props.result.rows}
        />
      );
  }
  return <UnsupportedResult result={props.result} />;
};

const Paragraph = props => {
  return (

      <Editor
        completion
        input={props.text}
        language="scala"
        theme="composition"
        cellFocused={false}
        onChange={() => {}}
        onFocusChange={() => {}}
        channels={{}}
        cursorBlinkRate={0}
        executionState={"not connected"}
        editorFocused={false}
        focusAbove={() => {}}
        focusBelow={() => {}}
        style={{
          paddingBottom: "10px",
          paddingTop: "10px"
        }}
      />
      <Result result={props.result} />

  );
};

const ZeppelinView = props => {
  return (

{props.notebook.name}

      {props.notebook.paragraphs.map(p => <Paragraph key={p.id} {...p} />)}

  );
};

export default ZeppelinView;
<commit_msg>handle default unsupported case<commit_after>import React from "react";

import JSONTransform from "@nteract/transforms/lib/json";
import HTML from "@nteract/transforms/lib/html";
import Text from "@nteract/transforms/lib/text";

import Editor from "@nteract/notebook-preview/lib/editor";

const HokeyTable = props => (

          {props.columnNames.map(column => (
            {column.name}
          ))}

        {props.rows.map((row, idx) => (

            {row.map((item, colIdx) => {item}	)}

        ))}

);

const UnsupportedResult = props => (

UNSUPPORTED ZEPPELIN RESULT

      Post an issue to
      {" "}

        commuter

      {" "}
      to let us know about it

    <JSONTransform data={props.result} />

);

const Result = props => {
  if (!props.result) {
    return null;
  }
  switch (props.result.type) {
    case "HTML":
      return ;
    case "TEXT":
      return <Text data={props.result.msg} />;
    case "TABLE":
      if (!props.result.columnNames || !props.result.rows) {
        return <UnsupportedResult result={props.result} />;
      }
      return (
        <HokeyTable
          columnNames={props.result.columnNames}
          rows={props.result.rows}
        />
      );
    default:
      return <UnsupportedResult result={props.result} />;
  }
};

const Paragraph = props => {
  return (

      <Editor
        completion
        input={props.text}
        language="scala"
        theme="composition"
        cellFocused={false}
        onChange={() => {}}
        onFocusChange={() => {}}
        channels={{}}
        cursorBlinkRate={0}
        executionState={"not connected"}
        editorFocused={false}
        focusAbove={() => {}}
        focusBelow={() => {}}
        style={{
          paddingBottom: "10px",
          paddingTop: "10px"
        }}
      />
      <Result result={props.result} />

  );
};

const ZeppelinView = props => {
  return (

{props.notebook.name}

      {props.notebook.paragraphs.map(p => <Paragraph key={p.id} {...p} />)}

  );
};

export default ZeppelinView;
<|endoftext|>