<commit_before>var vco1 = new VCO();
var vco2 = new VCO();
var vco3 = new VCO();
var vcf = new VCF();
var vca = new VCA();
var eg = new EG();
var mixer = new Mixer();

var Synth = function() {
  this.receive = function(array) {
    console.log(array);
    for (var i = 0; i < array.length; i++) {
      this.receiveMIDIByte(array[i]);
    }
  };

  this.receiveMIDIByte = function(b) {
    if (this.IsDataByte(b)) {
      if (this.systemExclusive) {
        // do nothing
      } else if (this.systemDataRemaining != 0) {
        this.systemDataRemaining--;
      } else if (this.runningStatus == (NOTE_ON | midiCh)) {
        if (!this.IsDataByte(this.firstData)) {
          this.firstData = b;
        } else if (b == 0) {
          this.noteOff(this.firstData);
          this.firstData = DATA_BYTE_INVALID;
        } else {
          this.noteOn(this.firstData);
          this.firstData = DATA_BYTE_INVALID;
        }
      } else if (this.runningStatus == (NOTE_OFF | midiCh)) {
        if (!this.IsDataByte(this.firstData)) {
          this.firstData = b;
        } else {
          this.noteOff(this.firstData);
          this.firstData = DATA_BYTE_INVALID;
        }
      } else if (this.runningStatus == (CONTROL_CHANGE | midiCh)) {
        if (!this.IsDataByte(this.firstData)) {
          this.firstData = b;
        } else {
          this.controlChange(this.firstData, b);
          this.firstData = DATA_BYTE_INVALID;
        }
      }
    } else if (this.IsStatusByte(b)) {
      this.runningStatus = b;
      this.firstData = DATA_BYTE_INVALID;
    } else if (this.IsSystemMessage(b)) {
      switch (b) {
      case EOX:
        this.systemExclusive = false;
        this.systemDataRemaining = 0;
        break;
      case SONG_SELECT:
      case TIME_CODE:
        this.systemDataRemaining = 1;
        break;
      case SONG_POSITION:
        this.systemDataRemaining = 2;
        break;
      case SYSTEM_EXCLUSIVE:
        this.systemExclusive = true;
        break;
      }
    }
  };

  this.clock = function() {
    var level = mixer.clock(vco1.clock(), vco2.clock(), vco3.clock());
    egOutput = eg.clock();
    level = vcf.clock(level, egOutput);
    level = vca.clock(level, egOutput);
    return level;
  };

  this.IsRealTimeMessage = function(b) {
    return b >= REAL_TIME_MESSAGE_MIN;
  };

  this.IsSystemMessage = function(b) {
    return b >= SYSTEM_MESSAGE_MIN;
  };

  this.IsStatusByte = function(b) {
    return b >= STATUS_BYTE_MIN;
  };

  this.IsDataByte = function(b) {
    return b <= DATA_BYTE_MAX;
  };

  this.noteOn = function(noteNumber) {
    pitch2 = noteNumber + vco2.coarseTune();
    if (pitch2 < (NOTE_NUMBER_MIN + 64) ||
        pitch2 > (NOTE_NUMBER_MAX + 64)) {
      return;
    }

    pitch3 = noteNumber + vco3.coarseTune();
    if (pitch3 < (NOTE_NUMBER_MIN + 64) ||
        pitch3 > (NOTE_NUMBER_MAX + 64)) {
      return;
    }

    this.noteNumber = noteNumber;
    vco1.noteOn(this.noteNumber);
    vco2.noteOn(this.noteNumber);
    vco3.noteOn(this.noteNumber);
    eg.noteOn();
  };

  this.noteOff = function(noteNumber) {
    if (noteNumber == this.noteNumber) {
      eg.noteOff();
    }
  };

  this.soundOff = function() {
    eg.soundOff();
  };

  this.resetPhase = function() {
    vco1.resetPhase();
    vco2.resetPhase();
    vco3.resetPhase();
  };

  this.controlChange = function(controllerNumber, value) {
    switch (controllerNumber) {
    case ALL_NOTES_OFF:
      this.allNotesOff(value);
      break;
    case VCO_1_WAVEFORM:
      this.setVCO1Waveform(value);
      break;
    case VCO_1_COARSE_TUNE:
      this.setVCO1CoarseTune(value);
      break;
    case VCO_2_WAVEFORM:
      this.setVCO2Waveform(value);
      break;
    case VCO_2_COARSE_TUNE:
      this.setVCO2CoarseTune(value);
      break;
    case VCO_2_FINE_TUNE:
      this.setVCO2FineTune(value);
      break;
    case VCO_3_WAVEFORM:
      this.setVCO3Waveform(value);
      break;
    case VCO_3_COARSE_TUNE:
      this.setVCO3CoarseTune(value);
      break;
    case VCO_3_FINE_TUNE:
      this.setVCO3FineTune(value);
      break;
    case VCF_CUTOFF_FREQUENCY:
      this.setVCFCutoffFrequency(value);
      break;
    case VCF_RESONANCE:
      this.setVCFResonance(value);
      break;
    case VCF_ENVELOPE_AMOUNT:
      this.setVCFEnvelopeAmount(value);
      break;
    case EG_ATTACK_TIME:
      this.setEGAttackTime(value);
      break;
    case EG_DECAY_TIME:
      this.setEGDecayTime(value);
      break;
    case EG_SUSTAIN_LEVEL:
      this.setEGSustainLevel(value);
      break;
    }
  };

  this.setVCO1Waveform = function(value) {
    this.soundOff();
    vco1.setWaveform(value);
    this.resetPhase();
  };

  this.setVCO1CoarseTune = function(value) {
    this.soundOff();
    vco1.setCoarseTune(value);
    this.resetPhase();
  };

  this.setVCO2Waveform = function(value) {
    this.soundOff();
    vco2.setWaveform(value);
    this.resetPhase();
  };

  this.setVCO2CoarseTune = function(value) {
    this.soundOff();
    vco2.setCoarseTune(value);
    this.resetPhase();
  };

  this.setVCO2FineTune = function(value) {
    this.soundOff();
    vco2.setFineTune(value);
    this.resetPhase();
  };

  this.setVCO3Waveform = function(value) {
    this.soundOff();
    vco3.setWaveform(value);
    this.resetPhase();
  };

  this.setVCO3CoarseTune = function(value) {
    this.soundOff();
    vco3.setCoarseTune(value);
    this.resetPhase();
  };

  this.setVCO3FineTune = function(value) {
    this.soundOff();
    vco3.setFineTune(value);
    this.resetPhase();
  };

  this.setVCFCutoffFrequency = function(value) {
    vcf.setCutoffFrequency(value);
  };

  this.setVCFResonance = function(value) {
    vcf.setResonance(value);
  };

  this.setVCFEnvelopeAmount = function(value) {
    vcf.setEnvelopeAmount(value);
  };

  this.setEGAttackTime = function(value) {
    eg.setAttackTime(value);
  };

  this.setEGDecayTime = function(value) {
    eg.setDecayTime(value);
  };

  this.setEGSustainLevel = function(value) {
    eg.setSustainLevel(value);
  };

  this.allNotesOff = function(value) {
    eg.noteOff();
  };

  this.systemExclusive     = false;
  this.systemDataRemaining = 0;
  this.runningStatus       = STATUS_BYTE_INVALID;
  this.firstData           = DATA_BYTE_INVALID;
  this.noteNumber          = 60;
};
<commit_msg>Fix a problem of noteOn<commit_after>var vco1 = new VCO();
var vco2 = new VCO();
var vco3 = new VCO();
var vcf = new VCF();
var vca = new VCA();
var eg = new EG();
var mixer = new Mixer();

var Synth = function() {
  this.receive = function(array) {
    console.log(array);
    for (var i = 0; i < array.length; i++) {
      this.receiveMIDIByte(array[i]);
    }
  };

  this.receiveMIDIByte = function(b) {
    if (this.IsDataByte(b)) {
      if (this.systemExclusive) {
        // do nothing
      } else if (this.systemDataRemaining != 0) {
        this.systemDataRemaining--;
      } else if (this.runningStatus == (NOTE_ON | midiCh)) {
        if (!this.IsDataByte(this.firstData)) {
          this.firstData = b;
        } else if (b == 0) {
          this.noteOff(this.firstData);
          this.firstData = DATA_BYTE_INVALID;
        } else {
          this.noteOn(this.firstData);
          this.firstData = DATA_BYTE_INVALID;
        }
      } else if (this.runningStatus == (NOTE_OFF | midiCh)) {
        if (!this.IsDataByte(this.firstData)) {
          this.firstData = b;
        } else {
          this.noteOff(this.firstData);
          this.firstData = DATA_BYTE_INVALID;
        }
      } else if (this.runningStatus == (CONTROL_CHANGE | midiCh)) {
        if (!this.IsDataByte(this.firstData)) {
          this.firstData = b;
        } else {
          this.controlChange(this.firstData, b);
          this.firstData = DATA_BYTE_INVALID;
        }
      }
    } else if (this.IsStatusByte(b)) {
      this.runningStatus = b;
      this.firstData = DATA_BYTE_INVALID;
    } else if (this.IsSystemMessage(b)) {
      switch (b) {
      case EOX:
        this.systemExclusive = false;
        this.systemDataRemaining = 0;
        break;
      case SONG_SELECT:
      case TIME_CODE:
        this.systemDataRemaining = 1;
        break;
      case SONG_POSITION:
        this.systemDataRemaining = 2;
        break;
      case SYSTEM_EXCLUSIVE:
        this.systemExclusive = true;
        break;
      }
    }
  };

  this.clock = function() {
    var level = mixer.clock(vco1.clock(), vco2.clock(), vco3.clock());
    egOutput = eg.clock();
    level = vcf.clock(level, egOutput);
    level = vca.clock(level, egOutput);
    return level;
  };

  this.IsRealTimeMessage = function(b) {
    return b >= REAL_TIME_MESSAGE_MIN;
  };

  this.IsSystemMessage = function(b) {
    return b >= SYSTEM_MESSAGE_MIN;
  };

  this.IsStatusByte = function(b) {
    return b >= STATUS_BYTE_MIN;
  };

  this.IsDataByte = function(b) {
    return b <= DATA_BYTE_MAX;
  };

  this.noteOn = function(noteNumber) {
    pitch1 = noteNumber + vco1.coarseTune();
    if (pitch1 < (NOTE_NUMBER_MIN + 64) ||
        pitch1 > (NOTE_NUMBER_MAX + 64)) {
      return;
    }

    pitch2 = noteNumber + vco2.coarseTune();
    if (pitch2 < (NOTE_NUMBER_MIN + 64) ||
        pitch2 > (NOTE_NUMBER_MAX + 64)) {
      return;
    }

    pitch3 = noteNumber + vco3.coarseTune();
    if (pitch3 < (NOTE_NUMBER_MIN + 64) ||
        pitch3 > (NOTE_NUMBER_MAX + 64)) {
      return;
    }

    this.noteNumber = noteNumber;
    vco1.noteOn(this.noteNumber);
    vco2.noteOn(this.noteNumber);
    vco3.noteOn(this.noteNumber);
    eg.noteOn();
  };

  this.noteOff = function(noteNumber) {
    if (noteNumber == this.noteNumber) {
      eg.noteOff();
    }
  };

  this.soundOff = function() {
    eg.soundOff();
  };

  this.resetPhase = function() {
    vco1.resetPhase();
    vco2.resetPhase();
    vco3.resetPhase();
  };

  this.controlChange = function(controllerNumber, value) {
    switch (controllerNumber) {
    case ALL_NOTES_OFF:
      this.allNotesOff(value);
      break;
    case VCO_1_WAVEFORM:
      this.setVCO1Waveform(value);
      break;
    case VCO_1_COARSE_TUNE:
      this.setVCO1CoarseTune(value);
      break;
    case VCO_2_WAVEFORM:
      this.setVCO2Waveform(value);
      break;
    case VCO_2_COARSE_TUNE:
      this.setVCO2CoarseTune(value);
      break;
    case VCO_2_FINE_TUNE:
      this.setVCO2FineTune(value);
      break;
    case VCO_3_WAVEFORM:
      this.setVCO3Waveform(value);
      break;
    case VCO_3_COARSE_TUNE:
      this.setVCO3CoarseTune(value);
      break;
    case VCO_3_FINE_TUNE:
      this.setVCO3FineTune(value);
      break;
    case VCF_CUTOFF_FREQUENCY:
      this.setVCFCutoffFrequency(value);
      break;
    case VCF_RESONANCE:
      this.setVCFResonance(value);
      break;
    case VCF_ENVELOPE_AMOUNT:
      this.setVCFEnvelopeAmount(value);
      break;
    case EG_ATTACK_TIME:
      this.setEGAttackTime(value);
      break;
    case EG_DECAY_TIME:
      this.setEGDecayTime(value);
      break;
    case EG_SUSTAIN_LEVEL:
      this.setEGSustainLevel(value);
      break;
    }
  };

  this.setVCO1Waveform = function(value) {
    this.soundOff();
    vco1.setWaveform(value);
    this.resetPhase();
  };

  this.setVCO1CoarseTune = function(value) {
    this.soundOff();
    vco1.setCoarseTune(value);
    this.resetPhase();
  };

  this.setVCO2Waveform = function(value) {
    this.soundOff();
    vco2.setWaveform(value);
    this.resetPhase();
  };

  this.setVCO2CoarseTune = function(value) {
    this.soundOff();
    vco2.setCoarseTune(value);
    this.resetPhase();
  };

  this.setVCO2FineTune = function(value) {
    this.soundOff();
    vco2.setFineTune(value);
    this.resetPhase();
  };

  this.setVCO3Waveform = function(value) {
    this.soundOff();
    vco3.setWaveform(value);
    this.resetPhase();
  };

  this.setVCO3CoarseTune = function(value) {
    this.soundOff();
    vco3.setCoarseTune(value);
    this.resetPhase();
  };

  this.setVCO3FineTune = function(value) {
    this.soundOff();
    vco3.setFineTune(value);
    this.resetPhase();
  };

  this.setVCFCutoffFrequency = function(value) {
    vcf.setCutoffFrequency(value);
  };

  this.setVCFResonance = function(value) {
    vcf.setResonance(value);
  };

  this.setVCFEnvelopeAmount = function(value) {
    vcf.setEnvelopeAmount(value);
  };

  this.setEGAttackTime = function(value) {
    eg.setAttackTime(value);
  };

  this.setEGDecayTime = function(value) {
    eg.setDecayTime(value);
  };

  this.setEGSustainLevel = function(value) {
    eg.setSustainLevel(value);
  };

  this.allNotesOff = function(value) {
    eg.noteOff();
  };

  this.systemExclusive     = false;
  this.systemDataRemaining = 0;
  this.runningStatus       = STATUS_BYTE_INVALID;
  this.firstData           = DATA_BYTE_INVALID;
  this.noteNumber          = 60;
};
<|endoftext|>


<commit_before>

/*
 *  Some presets
 */

var kick = {
  type: 'sine',
  frequency: 100,
  duration: .3,
  vol: 1,
  ramp: {
    to: 70
  },
  env: {
    decay: 20
  }
};

var snare = {
  type: 'square',
  frequency: 100,
  duration: .05,
  vol: 1,
  env: {
    attack: 10,
    decay: 20
  }
};

var beep_a = {
  type: 'triangle',
  frequency: 440,
  duration: .2,
  vol: 1,
  filter: {
    frequency: 1000,
    type: 'highpass',
    gain: 25
  }
};

var beep_d = {
  type: 'triangle',
  frequency: 587.33,
  duration: .2,
  vol: 1,
  filter: {
    frequency: 1000,
    type: 'highpass',
    gain: 25
  }
};

var beep_fsharp = {
  type: 'triangle',
  frequency: 739.99,
  duration: .2,
  vol: 0.1,
  filter: {
    frequency: 1000,
    type: 'highpass',
    gain: 25
  }
};

/*
 *  Declare namespace
 */

var Synth = function(){
  this.context = new AudioContext();
};

/*
 *  Accepts a "sound" object and plays it
 */

Synth.prototype.play = function(sound){

  var self  = this,
      osc   = self.context.createOscillator(),
      decay = 0,
      connection;

      // Supported: ['sine', 'triangle', 'sawtooth', 'square']
      osc.type = sound.type;
      osc.frequency.setValueAtTime(sound.frequency, self.context.currentTime);
      connection = osc;

      // Manipulate frequency over time
      if(sound.ramp){

        var bendAt = sound.ramp.at || sound.duration;

        connection.frequency.linearRampToValueAtTime(
          sound.ramp.to,
          self.context.currentTime + bendAt
        );
      }

      // Apply filter if requested
      if(sound.filter){
        var filter = self.context.createBiquadFilter();

        filter.type = sound.filter.type;
        filter.frequency.value = sound.filter.frequency;
        filter.gain.value = sound.filter.gain;

        connection.connect(filter);
        connection = filter;

      }

      if(sound.env){
        var gainNode   = self.context.createGain(),
            attackPeak = self.context.currentTime + ((sound.env.attack/100) * sound.duration);

        if(sound.env.attack){
          gainNode.gain.value = 0;
          gainNode.gain.setValueAtTime(0.0, self.context.currentTime);
          gainNode.gain.linearRampToValueAtTime(sound.vol, attackPeak);
        }

        if(sound.env.decay){
          decay = (100/sound.env.decay) * sound.duration;
          gainNode.gain.setTargetAtTime(0.0, self.context.currentTime + sound.duration, 0.5);
        }

        connection.connect(gainNode);
        connection = gainNode;
      }

      connection.connect(self.context.destination);
      osc.start(self.context.currentTime);
      osc.stop(self.context.currentTime + sound.duration + decay);

};

/*
 *  Calculates BPM
 */

Synth.prototype.calculateBpm = function(bpm){

  var second = 1000,
      minute = second * 60
      bpms   = minute/bpm;

  return bpms;
}

/*
 *  Accepts an array of sounds to sequence and a bpm
 */

Synth.prototype.sequence = function(queue, bpm, loops){

  var self = this;

  // Get BPM delay in milliseconds
  var calculated_bpm = self.calculateBpm(bpm);

  // Play each sound, then wait for the offset
  for(i=0; i < queue.length; i++){

    (function(offset){

      setTimeout(function(){
        self.play(queue[offset]);

      }, offset * calculated_bpm)

    })(i);
  }
};

<commit_msg>updated with working attack + delay<commit_after>/*
 *  Declare namespace
 */

var Synth = function(){
  this.context = new AudioContext();
};

/*
 *  Some presets
 */

  Synth.presets = {
    kick: {
      type: 'sine',
      frequency: 100,
      duration: .3,
      vol: 1,
      ramp: {
        to: 70
      },
      env: {
        decay: 20
      }
    },
    snare: {
      type: 'square',
      frequency: 100,
      duration: .05,
      vol: 1,
      env: {
        attack: 10,
        decay: 20
      }
    },
    beeper: {
      type: 'triangle',
      frequency: 440,
      duration: .2,
      vol: 1,
      filter: {
        frequency: 1000,
        type: 'highpass',
        gain: 25
      },
      env: {
        decay: 15
      }
    }
  };

/*
 *  Accepts a "sound" object and plays it
 */

  Synth.prototype.play = function(sound){

    var self  = this,
        osc   = self.context.createOscillator(),
        decay = 0,
        connection;

        // Supported: ['sine', 'triangle', 'sawtooth', 'square']
        osc.type = sound.type;
        osc.frequency.setValueAtTime(sound.frequency, self.context.currentTime);
        connection = osc;

        // Manipulate frequency over time
        if(sound.ramp){

          var bendAt = sound.ramp.at || sound.duration;

          connection.frequency.linearRampToValueAtTime(
            sound.ramp.to,
            self.context.currentTime + bendAt
          );
        }

        // Apply filter if requested
        if(sound.filter){
          var filter = self.context.createBiquadFilter();

          filter.type = sound.filter.type;
          filter.frequency.value = sound.filter.frequency;
          filter.gain.value = sound.filter.gain;

          connection.connect(filter);
          connection = filter;

        }

        if(sound.env){
          var gainNode   = self.context.createGain(),
              attackPeak = self.context.currentTime + ((sound.env.attack/100) * sound.duration);

          if(sound.env.attack){
            gainNode.gain.value = 0;
            gainNode.gain.setValueAtTime(0.0, self.context.currentTime);
            gainNode.gain.linearRampToValueAtTime(sound.vol, attackPeak);
          }

          if(sound.env.decay){
            decay = (sound.env.decay/100) * sound.duration + 0.2;
            gainNode.gain.setTargetAtTime(0.0, self.context.currentTime + sound.duration, 0.5);
          }

          connection.connect(gainNode);
          connection = gainNode;
        }

        connection.connect(self.context.destination);
        osc.start(self.context.currentTime);
        osc.stop(self.context.currentTime + sound.duration + decay);

  };

/*
 *  Calculates BPM
 */

  Synth.prototype.calculateBpm = function(bpm){

    var second = 1000,
        minute = second * 60
        bpms   = minute/bpm;

    return bpms;
  }

/*
 *  Accepts an array of sounds to sequence and a bpm
 */

  Synth.prototype.sequence = function(queue, bpm, loops){

    var self = this;

    // Get BPM delay in milliseconds
    var calculated_bpm = self.calculateBpm(bpm);

    // Play each sound, then wait for the offset
    for(i=0; i < queue.length; i++){

      (function(offset){

        setTimeout(function(){
          self.play(queue[offset]);

        }, offset * calculated_bpm)

      })(i);
    }
  };

<|endoftext|>


<commit_before>M.wrap('github/jillix/table/v0.0.1/table.js', function (require, module, exports) {

var View = require('github/jillix/view/v0.0.1/view');

function createTemplates (schema) {

    // create headers and rows
    var columns = {
        headers: '
',
        rows: '
'
    };

    for (var field in schema) {
        columns.headers += '' + field + '	';
        columns.rows += '{' + field + '}	';
    }
    columns.headers += '
';
    columns.rows += '
';

    return columns;
}

function clickRowHander (state, source, id) {
    return function () {
        state.emit('/editor/' + source + '/' + id);
    };
}

function load () {
    var self = this;

    // render items
    self.item.model(getModelFromUrl(), function (err, model) {

        if (err || !model) {
            return;
        }

        self.model = model;

        // render title
        if (self.title) {
            self.title.template.render([{title: model.name}]);
        }

        var templates = createTemplates(model.schema);

        // render header
        if (self.head) {
            self.head.template.set(templates.headers);
            self.head.template.render();
        }

        if (self.item) {
            self.item.template.set(templates.rows);
            model.read({q: {}, o: {}}, function (err, data) {

                if (err || !data) {
                    data = [err] || ['no data'];
                }

                self.item.template.render(data);

                // add clicks to rows
                var rows = self.item.template.dom.querySelectorAll('tr');
                for (var i = 0; i < rows.length; ++i) {
                    rows[i].addEventListener('click', clickRowHander(self.item.state, self.model.name, data[i]._id), false);
                }
            });
        }
    });
}

function getModelFromUrl (model) {
    return location.pathname.split('/')[2];
}

function init () {
    var self = this;
    var config = self.mono.config.data;

    // state handler
    self.load = load;

    // init view
    if (config && config.layout) {
        var V = View(self);

        V.load(config.layout, function (err, layout) {

            if (err) {
                return;
            }

            // save view instance
            self.layout = layout;

            if (self.layout.template) {

                // render layout view
                self.layout.template.render();

                // load controller
                var count = 0;
                var handler = function (err) {
                    if (++count === 3) {
                        self.layout.model(getModelFromUrl(), function (err, model) {

                            if (!err) {
                                layout.state.emit();
                            }

                            self.emit('ready');
                        });
                    }
                };

                // load title
                if (config.title) {
                    V.load(config.title, function (err, title) {
                        self.title = title;
                        handler(err);
                    });
                } else {
                    handler();
                }

                // load headers
                if (config.head) {
                    V.load(config.head, function (err, head) {
                        self.head = head;
                        handler(err);
                    });
                } else {
                    handler();
                }

                // load items
                if (config.item) {
                    V.load(config.item, function (err, item) {
                        self.item = item;
                        handler(err);
                    });
                } else {
                    handler();
                }
            }
        });
    }
}

module.exports = init;

return module;

});
<commit_msg>check if item view exist before try to use it<commit_after>M.wrap('github/jillix/table/v0.0.1/table.js', function (require, module, exports) {

var View = require('github/jillix/view/v0.0.1/view');

function createTemplates (schema) {

    // create headers and rows
    var columns = {
        headers: '
',
        rows: '
'
    };

    for (var field in schema) {
        columns.headers += '' + field + '	';
        columns.rows += '{' + field + '}	';
    }
    columns.headers += '
';
    columns.rows += '
';

    return columns;
}

function clickRowHander (state, source, id) {
    return function () {
        state.emit('/editor/' + source + '/' + id);
    };
}

function load () {
    var self = this;

    // state can be emitted before the view is ready
    if (!self.item) {
        return;
    }

    // render items
    self.item.model(getModelFromUrl(), function (err, model) {

        if (err || !model) {
            return;
        }

        self.model = model;

        // render title
        if (self.title) {
            self.title.template.render([{title: model.name}]);
        }

        var templates = createTemplates(model.schema);

        // render header
        if (self.head) {
            self.head.template.set(templates.headers);
            self.head.template.render();
        }

        if (self.item) {
            self.item.template.set(templates.rows);
            model.read({q: {}, o: {}}, function (err, data) {

                if (err || !data) {
                    data = [err] || ['no data'];
                }

                self.item.template.render(data);

                // add clicks to rows
                var rows = self.item.template.dom.querySelectorAll('tr');
                for (var i = 0; i < rows.length; ++i) {
                    rows[i].addEventListener('click', clickRowHander(self.item.state, self.model.name, data[i]._id), false);
                }
            });
        }
    });
}

function getModelFromUrl (model) {
    return location.pathname.split('/')[2];
}

function init () {
    var self = this;
    var config = self.mono.config.data;

    // state handler
    self.load = load;

    // init view
    if (config && config.layout) {
        var V = View(self);

        V.load(config.layout, function (err, layout) {

            if (err) {
                return;
            }

            // save view instance
            self.layout = layout;

            if (self.layout.template) {

                // render layout view
                self.layout.template.render();

                // load controller
                var count = 0;
                var handler = function (err) {
                    if (++count === 3) {
                        self.layout.model(getModelFromUrl(), function (err, model) {

                            if (!err) {
                                layout.state.emit();
                            }

                            self.emit('ready');
                        });
                    }
                };

                // load title
                if (config.title) {
                    V.load(config.title, function (err, title) {
                        self.title = title;
                        handler(err);
                    });
                } else {
                    handler();
                }

                // load headers
                if (config.head) {
                    V.load(config.head, function (err, head) {
                        self.head = head;
                        handler(err);
                    });
                } else {
                    handler();
                }

                // load items
                if (config.item) {
                    V.load(config.item, function (err, item) {
                        self.item = item;
                        handler(err);
                    });
                } else {
                    handler();
                }
            }
        });
    }
}

module.exports = init;

return module;

});
<|endoftext|>


<commit_before>/* eslint-disable no-console */
/*
 * This script parses the yarn audit JSON results to find security advisories
 * that affect modules in our dependencies list that are moderate or higher
 * and aren't in our exceptions list
 */
const { spawn } = require('child_process');

const packageJSON = require('../package.json');

const exceptionSet = new Set([
  'https://npmjs.com/advisories/577',
  'https://npmjs.com/advisories/157',
]);

const severitySet = new Set(['high', 'critical', 'moderate']);

const dependencySet = new Set(Object.keys(packageJSON.dependencies));

function getAffectedModule(data) {
  return data.resolution.path.split('>')[0];
}

function processAuditResults(audit) {
  // The output isn't valid JSON, it's a list of JSON
  // objects separated by newlines
  const advisories = audit
    .trim()
    .split('\n')
    .map(a => JSON.parse(a));

  const validAdvisories = advisories.filter(adv => {
    if (adv.type === 'auditAdvisory') {
      const advisoryData = adv.data.advisory;
      const affectedModule = getAffectedModule(adv.data);
      return (
        !exceptionSet.has(advisoryData.url) &&
        severitySet.has(advisoryData.severity) &&
        dependencySet.has(affectedModule)
      );
    }

    return false;
  });

  if (validAdvisories.length) {
    validAdvisories.forEach(adv => {
      console.log(`
Security advisory:
  Title: ${adv.data.advisory.title}
  Module name: ${adv.data.advisory.module_name}
  Dependency: ${getAffectedModule(adv.data)}
  Path: ${adv.data.resolution.path}
  Severity: ${adv.data.advisory.severity}
  Details: ${adv.data.advisory.url}
      `);
    });
  } else {
    console.log(
      'No security advisories rated moderate or higher found for non-dev dependencies.',
    );
  }

  process.exit(validAdvisories.length);
}

function runAudit() {
  const child = spawn('yarn', ['audit', '--json']);
  let auditOutput = '';

  child.stdout.setEncoding('utf8');

  child.stdout.on('data', data => {
    auditOutput += data;
  });

  child.stderr.on('data', data => {
    console.error(data);
  });

  child.on('close', () => {
    processAuditResults(auditOutput);
  });
}

runAudit();
<commit_msg>Temporarily ignore security advisory (#9573)<commit_after>/* eslint-disable no-console */
/*
 * This script parses the yarn audit JSON results to find security advisories
 * that affect modules in our dependencies list that are moderate or higher
 * and aren't in our exceptions list
 */
const { spawn } = require('child_process');

const packageJSON = require('../package.json');

const exceptionSet = new Set([
  'https://npmjs.com/advisories/577',
  'https://npmjs.com/advisories/157',
  'https://npmjs.com/advisories/782',
]);

const severitySet = new Set(['high', 'critical', 'moderate']);

const dependencySet = new Set(Object.keys(packageJSON.dependencies));

function getAffectedModule(data) {
  return data.resolution.path.split('>')[0];
}

function processAuditResults(audit) {
  // The output isn't valid JSON, it's a list of JSON
  // objects separated by newlines
  const advisories = audit
    .trim()
    .split('\n')
    .map(a => JSON.parse(a));

  const validAdvisories = advisories.filter(adv => {
    if (adv.type === 'auditAdvisory') {
      const advisoryData = adv.data.advisory;
      const affectedModule = getAffectedModule(adv.data);
      return (
        !exceptionSet.has(advisoryData.url) &&
        severitySet.has(advisoryData.severity) &&
        dependencySet.has(affectedModule)
      );
    }

    return false;
  });

  if (validAdvisories.length) {
    validAdvisories.forEach(adv => {
      console.log(`
Security advisory:
  Title: ${adv.data.advisory.title}
  Module name: ${adv.data.advisory.module_name}
  Dependency: ${getAffectedModule(adv.data)}
  Path: ${adv.data.resolution.path}
  Severity: ${adv.data.advisory.severity}
  Details: ${adv.data.advisory.url}
      `);
    });
  } else {
    console.log(
      'No security advisories rated moderate or higher found for non-dev dependencies.',
    );
  }

  process.exit(validAdvisories.length);
}

function runAudit() {
  const child = spawn('yarn', ['audit', '--json']);
  let auditOutput = '';

  child.stdout.setEncoding('utf8');

  child.stdout.on('data', data => {
    auditOutput += data;
  });

  child.stderr.on('data', data => {
    console.error(data);
  });

  child.on('close', () => {
    processAuditResults(auditOutput);
  });
}

runAudit();
<|endoftext|>


<commit_before>function TempoEvent(type, item, element) {
    this.type = type;
    this.item = item;
    this.element = element;

    return this;
}

TempoEvent.Types = {
    RENDER_STARTING : 'render_starting',
    ITEM_RENDER_STARTING : 'item_render_starting',
    ITEM_RENDER_COMPLETE : 'item_render_complete',
    RENDER_COMPLETE : 'render_complete'
};

var Tempo = (function (tempo) {

    /*!
     * Helpers
     */
    var utils = {
        startsWith : function (str, prefix) {
            return (str.indexOf(prefix) === 0);
        },

        replaceVariable : function (item, str) {
            return str.replace(/\{\{([A-Za-z0-9\._\[\]]*?)\}\}/g, function (match, variable) {
				var val = null;
				if (utils.typeOf(item) === 'array') {
					val = eval('item' + variable);
				} else {
					val = eval('item.' + variable);
				}
                if (val !== undefined) {
                    return val;
                }
                return '';
            });
        },

        clearContainer : function (el) {
            if (el !== undefined && el.childNodes !== undefined) {
                for (var i = el.childNodes.length; i >= 0; i--) {
                    if (el.childNodes[i] !== undefined && el.childNodes[i].getAttribute !== undefined && el.childNodes[i].getAttribute('data-template') !== null) {
                        el.childNodes[i].parentNode.removeChild(el.childNodes[i]);
                    }
                }
            }
        },

        isNested : function (el) {
            var p = el.parentNode;
            while (p) {
                if (p.getAttribute !== undefined && p.getAttribute('data-template') !== null) {
                    return true;
                }
                p = p.parentNode;
            }
            return false;
        },

        equalsIgnoreCase : function (str1, str2) {
            return str1.toLowerCase() === str2.toLowerCase();
        },

        getElement : function (template, html) {
            if (utils.equalsIgnoreCase(template.tagName, 'tr')) {
                // Wrapping to get around read-only innerHTML
                var el = document.createElement('div');
                el.innerHTML = '

' + html + '

';
                var depth = 3;
                while (depth--) {
                    el = el.lastChild;
                }
                return el;
            } else {
                // No need to wrap
                template.innerHTML = html;
                return template;
            }
        },

        typeOf : function (obj) {
            if (typeof(obj) === "object") {
                if (obj === null) {
                    return "null";
                }
                if (obj.constructor === ([]).constructor) {
                    return "array";
                }
                if (obj.constructor === (new Date()).constructor) {
                    return "date";
                }
                if (obj.constructor === (new RegExp()).constructor) {
                    return "regex";
                }
                return "object";
            }
            return typeof(obj);
        },

        notify : function (listener, event) {
            if (listener !== undefined) {
                listener(event);
            }
        }
    };

    function Templates(nestedItem) {
        this.defaultTemplate = null;
        this.namedTemplates = {};
        this.container = null;
		this.nestedItem = nestedItem !== undefined ? nestedItem : null;

        return this;
    }

    Templates.prototype = {
        parse: function (container) {
            this.container = container;
            var children = container.getElementsByTagName('*');

            for (var i = 0; i < children.length; i++) {
                if (children[i].getAttribute('data-template') !== null && (this.nestedItem === children[i].getAttribute('data-template') || children[i].getAttribute('data-template') === '' && !utils.isNested(children[i]))) {
                    this.createTemplate(children[i]);
                }
            }

			// If there is no default template (data-template) then create one from container
			if (this.defaultTemplate === null) {
				// Creating a template inside the container
				var el = document.createElement('div');
				el.setAttribute('data-template', '');
				el.innerHTML = this.container.innerHTML;

				// Clearing container before adding the wrapped contents
				this.container.innerHTML = '';

				// There is now a default template present with a data-template attribute
				this.container.appendChild(el);
				this.createTemplate(el);
			}

            utils.clearContainer(this.container);
        },

        createTemplate : function (node) {
            var element = node.cloneNode(true);

            // Clear display: none;
            if (element.style.removeAttribute) {
                element.style.removeAttribute("display");
            }
            else {
                element.style.removeProperty("display");
            }

            // Remapping container element in case template
            // is deep in container
			this.container = node.parentNode;

            // Element is a template
			var nonDefault = false;
            for (var a = 0; a < element.attributes.length; a++) {
                var attr = element.attributes[a];
                // If attribute
                if (utils.startsWith(attr.name, 'data-if-')) {
                    var val;
                    if (attr.value === '') {
                        val = true;
                    } else {
                        val = '\'' + attr.value + '\'';
                    }
                    this.namedTemplates[attr.name.substring(8, attr.name.length) + '==' + val] = element;
                    element.removeAttribute(attr.name);
					nonDefault = true;
                }
            }

            // Setting as default template, last one wins
            if (!nonDefault) {
				this.defaultTemplate = element;
			}
        },

        templateFor: function (item) {
            for (var templateName in this.namedTemplates) {
                if (eval('item.' + templateName)) {
                    return this.namedTemplates[templateName].cloneNode(true);
                }
            }
            if (this.defaultTemplate) {
                return this.defaultTemplate.cloneNode(true);
            }
        }
    };

    /*!
     * Renderer for populating containers with data using templates.
     */
    function Renderer(templates) {
        this.templates = templates;
        this.listener = undefined;
        this.started = false;

        return this;
    }

    Renderer.prototype = {
        notify : function (listener) {
            this.listener = listener;

            return this;
        },

        starting : function () {
            // Use this to manually fire the RENDER_STARTING event e.g. just before you issue an AJAX request
            // Useful if you're not calling prepare immediately before render
            this.started = true;
            utils.notify(this.listener, new TempoEvent(TempoEvent.Types.RENDER_STARTING, undefined, undefined));

            return this;
        },

        render : function (data) {
            // Check if starting event was manually fired
            if (!this.started) {
                utils.notify(this.listener, new TempoEvent(TempoEvent.Types.RENDER_STARTING, undefined, undefined));
            }

            utils.clearContainer(this.templates.container);

            if (data) {
                // If object then wrapping in an array
                if (utils.typeOf(data) === 'object') {
                    data = [data];
                }

                var fragment = document.createDocumentFragment();

                for (var i = 0; i < data.length; i++) {
                    this.renderItem(this, data[i], fragment);
                }

                this.templates.container.appendChild(fragment);
            }

            utils.notify(this.listener, new TempoEvent(TempoEvent.Types.RENDER_COMPLETE, undefined, undefined));

            return this;
        },

        renderItem : function (renderer, item, fragment) {
            var template = renderer.templates.templateFor(item);
            if (template && item) {
                utils.notify(this.listener, new TempoEvent(TempoEvent.Types.ITEM_RENDER_STARTING, item, template));

                var nestedDeclaration = template.innerHTML.match(/data-template="(.*?)"/g);
				if (nestedDeclaration) {
					for (var i = 0; i < nestedDeclaration.length; i++) {
						var nested = nestedDeclaration[i].match(/"(.*?)"/)[1];

						var t = new Templates(nested);
	                    t.parse(template);

	                    var r = new Renderer(t);
	                    r.render(eval('item.' + nested));
					}
				}

                // Dealing with HTML as a String from now on (to be reviewed)
				// Attribute values are escaped in FireFox so making sure there are no escaped tags
                var html = template.innerHTML.replace(/%7B%7B/g, '{{').replace(/%7D%7D/g, '}}');

                // Tags
                for (var p in renderer.tags) {
                    html = html.replace(new RegExp(renderer.tags[p].regex, 'gi'), renderer.tags[p].handler(renderer, item));
                }

                // Content
                html = utils.replaceVariable(item, html);

                // Template class attribute
                if (template.getAttribute('class')) {
                    template.className = utils.replaceVariable(item, template.className);
                }

                // Template id
                if (template.getAttribute('id')) {
                    template.id = utils.replaceVariable(item, template.id);
                }

                fragment.appendChild(utils.getElement(template, html));

                utils.notify(this.listener, new TempoEvent(TempoEvent.Types.ITEM_RENDER_COMPLETE, item, template));
            }
        },

        tags : [
            // If tag
            {'regex': '\\{\\{if (.*?)\\}\\}(.*?)\\{\\{endif\\}\\}', 'handler': function (renderer, item) {
                return function (match, condition, content) {
                    var member_regex = '';
                    for (var member in item) {
                        if (member_regex.length > 0) {
                            member_regex += '|';
                        }
                        member_regex += member;
                    }

                    condition = condition.replace(/&/g, '&');
                    condition = condition.replace(new RegExp(member_regex, 'gi'), function (match) {
                        return 'item.' + match;
                    });
					alert(condition);
                    if (eval(condition)) {
                        return content;
                    }

                    return '';
                };
            }
            }
        ]
    };

    /*!
     * Prepare a container for rendering, gathering templates and
     * clearing afterwards.
     */
    tempo.prepare = function (container) {
        if (typeof container === 'string') {
            container = document.getElementById(container);
        }

        var templates = new Templates(false);
        templates.parse(container);

        return new Renderer(templates);
    };

    return tempo;

})(Tempo || {});
<commit_msg>testing<commit_after>function TempoEvent(type, item, element) {
    this.type = type;
    this.item = item;
    this.element = element;

    return this;
}

TempoEvent.Types = {
    RENDER_STARTING : 'render_starting',
    ITEM_RENDER_STARTING : 'item_render_starting',
    ITEM_RENDER_COMPLETE : 'item_render_complete',
    RENDER_COMPLETE : 'render_complete'
};

var Tempo = (function (tempo) {

    /*!
     * Helpers
     */
    var utils = {
        startsWith : function (str, prefix) {
            return (str.indexOf(prefix) === 0);
        },

        replaceVariable : function (item, str) {
            return str.replace(/\{\{([A-Za-z0-9\._\[\]]*?)\}\}/g, function (match, variable) {
				var val = null;
				if (utils.typeOf(item) === 'array') {
					val = eval('item' + variable);
				} else {
					val = eval('item.' + variable);
				}
                if (val !== undefined) {
                    return val;
                }
                return '';
            });
        },

        clearContainer : function (el) {
            if (el !== undefined && el.childNodes !== undefined) {
                for (var i = el.childNodes.length; i >= 0; i--) {
                    if (el.childNodes[i] !== undefined && el.childNodes[i].getAttribute !== undefined && el.childNodes[i].getAttribute('data-template') !== null) {
                        el.childNodes[i].parentNode.removeChild(el.childNodes[i]);
                    }
                }
            }
        },

        isNested : function (el) {
            var p = el.parentNode;
            while (p) {
                if (p.getAttribute !== undefined && p.getAttribute('data-template') !== null) {
                    return true;
                }
                p = p.parentNode;
            }
            return false;
        },

        equalsIgnoreCase : function (str1, str2) {
            return str1.toLowerCase() === str2.toLowerCase();
        },

        getElement : function (template, html) {
            if (utils.equalsIgnoreCase(template.tagName, 'tr')) {
                // Wrapping to get around read-only innerHTML
                var el = document.createElement('div');
                el.innerHTML = '

' + html + '

';
                var depth = 3;
                while (depth--) {
                    el = el.lastChild;
                }
                return el;
            } else {
                // No need to wrap
                template.innerHTML = html;
                return template;
            }
        },

        typeOf : function (obj) {
            if (typeof(obj) === "object") {
                if (obj === null) {
                    return "null";
                }
                if (obj.constructor === ([]).constructor) {
                    return "array";
                }
                if (obj.constructor === (new Date()).constructor) {
                    return "date";
                }
                if (obj.constructor === (new RegExp()).constructor) {
                    return "regex";
                }
                return "object";
            }
            return typeof(obj);
        },

        notify : function (listener, event) {
            if (listener !== undefined) {
                listener(event);
            }
        }
    };

    function Templates(nestedItem) {
        this.defaultTemplate = null;
        this.namedTemplates = {};
        this.container = null;
		this.nestedItem = nestedItem !== undefined ? nestedItem : null;

        return this;
    }

    Templates.prototype = {
        parse: function (container) {
            this.container = container;
            var children = container.getElementsByTagName('*');

            for (var i = 0; i < children.length; i++) {
                if (children[i].getAttribute('data-template') !== null && (this.nestedItem === children[i].getAttribute('data-template') || children[i].getAttribute('data-template') === '' && !utils.isNested(children[i]))) {
                    this.createTemplate(children[i]);
                }
            }

			// If there is no default template (data-template) then create one from container
			if (this.defaultTemplate === null) {
				// Creating a template inside the container
				var el = document.createElement('div');
				el.setAttribute('data-template', '');
				el.innerHTML = this.container.innerHTML;

				// Clearing container before adding the wrapped contents
				this.container.innerHTML = '';

				// There is now a default template present with a data-template attribute
				this.container.appendChild(el);
				this.createTemplate(el);
			}

            utils.clearContainer(this.container);
        },

        createTemplate : function (node) {
            var element = node.cloneNode(true);

            // Clear display: none;
            if (element.style.removeAttribute) {
                element.style.removeAttribute("display");
            }
            else {
                element.style.removeProperty("display");
            }

            // Remapping container element in case template
            // is deep in container
			this.container = node.parentNode;

            // Element is a template
			var nonDefault = false;
            for (var a = 0; a < element.attributes.length; a++) {
                var attr = element.attributes[a];
                // If attribute
                if (utils.startsWith(attr.name, 'data-if-')) {
                    var val;
                    if (attr.value === '') {
                        val = true;
                    } else {
                        val = '\'' + attr.value + '\'';
                    }
                    this.namedTemplates[attr.name.substring(8, attr.name.length) + '==' + val] = element;
                    element.removeAttribute(attr.name);
					nonDefault = true;
                }
            }

            // Setting as default template, last one wins
            if (!nonDefault) {
				this.defaultTemplate = element;
			}
        },

        templateFor: function (item) {
            for (var templateName in this.namedTemplates) {
                if (eval('item.' + templateName)) {
                    return this.namedTemplates[templateName].cloneNode(true);
                }
            }
            if (this.defaultTemplate) {
                return this.defaultTemplate.cloneNode(true);
            }
        }
    };

    /*!
     * Renderer for populating containers with data using templates.
     */
    function Renderer(templates) {
        this.templates = templates;
        this.listener = undefined;
        this.started = false;

        return this;
    }

    Renderer.prototype = {
        notify : function (listener) {
            this.listener = listener;

            return this;
        },

        starting : function () {
            // Use this to manually fire the RENDER_STARTING event e.g. just before you issue an AJAX request
            // Useful if you're not calling prepare immediately before render
            this.started = true;
            utils.notify(this.listener, new TempoEvent(TempoEvent.Types.RENDER_STARTING, undefined, undefined));

            return this;
        },

        render : function (data) {
            // Check if starting event was manually fired
            if (!this.started) {
                utils.notify(this.listener, new TempoEvent(TempoEvent.Types.RENDER_STARTING, undefined, undefined));
            }

            utils.clearContainer(this.templates.container);

            if (data) {
                // If object then wrapping in an array
                if (utils.typeOf(data) === 'object') {
                    data = [data];
                }

                var fragment = document.createDocumentFragment();

                for (var i = 0; i < data.length; i++) {
                    this.renderItem(this, data[i], fragment);
                }

                this.templates.container.appendChild(fragment);
            }

            utils.notify(this.listener, new TempoEvent(TempoEvent.Types.RENDER_COMPLETE, undefined, undefined));

            return this;
        },

        renderItem : function (renderer, item, fragment) {
            var template = renderer.templates.templateFor(item);
            if (template && item) {
                utils.notify(this.listener, new TempoEvent(TempoEvent.Types.ITEM_RENDER_STARTING, item, template));

                var nestedDeclaration = template.innerHTML.match(/data-template="(.*?)"/g);
				if (nestedDeclaration) {
					for (var i = 0; i < nestedDeclaration.length; i++) {
						var nested = nestedDeclaration[i].match(/"(.*?)"/)[1];

						var t = new Templates(nested);
	                    t.parse(template);

	                    var r = new Renderer(t);
	                    r.render(eval('item.' + nested));
					}
				}

                // Dealing with HTML as a String from now on (to be reviewed)
				// Attribute values are escaped in FireFox so making sure there are no escaped tags
                var html = template.innerHTML.replace(/%7B%7B/g, '{{').replace(/%7D%7D/g, '}}');

                // Tags
                for (var p in renderer.tags) {
					alert(renderer.tags[p].regex)
                    html = html.replace(new RegExp(renderer.tags[p].regex, 'gi'), renderer.tags[p].handler(renderer, item));
                }

                // Content
                html = utils.replaceVariable(item, html);

                // Template class attribute
                if (template.getAttribute('class')) {
                    template.className = utils.replaceVariable(item, template.className);
                }

                // Template id
                if (template.getAttribute('id')) {
                    template.id = utils.replaceVariable(item, template.id);
                }

                fragment.appendChild(utils.getElement(template, html));

                utils.notify(this.listener, new TempoEvent(TempoEvent.Types.ITEM_RENDER_COMPLETE, item, template));
            }
        },

        tags : [
            // If tag
            {'regex': '\\{\\{if (.*?)\\}\\}(.*?)\\{\\{endif\\}\\}', 'handler': function (renderer, item) {
                return function (match, condition, content) {
                    var member_regex = '';
                    for (var member in item) {
                        if (member_regex.length > 0) {
                            member_regex += '|';
                        }
                        member_regex += member;
                    }

                    condition = condition.replace(/&/g, '&');
                    condition = condition.replace(new RegExp(member_regex, 'gi'), function (match) {
                        return 'item.' + match;
                    });
					alert(condition);
                    if (eval(condition)) {
                        return content;
                    }

                    return '';
                };
            }
            }
        ]
    };

    /*!
     * Prepare a container for rendering, gathering templates and
     * clearing afterwards.
     */
    tempo.prepare = function (container) {
        if (typeof container === 'string') {
            container = document.getElementById(container);
        }

        var templates = new Templates(false);
        templates.parse(container);

        return new Renderer(templates);
    };

    return tempo;

})(Tempo || {});
<|endoftext|>


<commit_before>var BoardModule = (function() {

  var board = $('#board');
  var cells = [];
  var levelLink = $('#level');
  var overlay = $('#overlay');
  var resetLink = $('#reset');

  var active = false;
  var level; //actually contains the level data
  var numLevels = -1; //to store the total number of levels

  var reset = function() {
    render(level);
  }

  resetLink.on('click', reset);

  //populates cells with the actual cells on the board
  for(var i = 0; i < 4; ++i) {
    cells.push([]);
    for(var j = 0; j < 4; ++j) {
      cells[i].push($('td[data-x="' + i + '"][data-y="' + j + '"]'));
    }
  }

  //goes through the model(the story), draws the board accordingly,
  //and checks if it's a win scenario
  var update = function() {
    $('td.selected').removeClass('selected');

    cells[level.selected.x][level.selected.y].addClass('selected');

    //check if it's a win
    if(isWin()) {
      board.fadeOut(options['fade'], function() {
        mediator.publish('board_level_complete');
      })
    }
  }

  function isWin() {
    var value = cell(0,0);
    for(var i = 0; i < 3; ++i) {
      for(var j = 0; j < 3; ++j) {
        if(cell(i,j) != value)
          return false
      }
    }
    return true;
  }

    //selects the cell to the left of the current cell
  function left() {
    if(active && level.selected.x > 0) {
      select(--level.selected.x, level.selected.y);
      update();
    }
  }

  //selects the cell above the current cell
  function up() {
    if(active && level.selected.y > 0) {
      select(level.selected.x, --level.selected.y);
      update();
    }
  }

  //selects the cell to the right of the current cell
  function right() {
    if(active && level.selected.x < 2) {
      select(++level.selected.x, level.selected.y);
      update();
    }
  }

  //selects the cell under the current cell
  function down() {
    if(active && level.selected.y < 2) {
      select(level.selected.x, ++level.selected.y);
      update();
    }
  }

  //selects a cell and increases its value
  function select(x, y) {
    if(cells[level.selected.x][level.selected.y].hasClass('black')) {
      cell(level.selected.x, level.selected.y, cell(level.selected.x, level.selected.y)+1);
    }
    else if(cells[level.selected.x][level.selected.y].hasClass('white')) {
      cell(level.selected.x, level.selected.y, cell(level.selected.x, level.selected.y)-1);
    }
    else {
      cell(level.selected.x, level.selected.y, cell(level.selected.x, level.selected.y)+1);
    }
  }

  //gets or sets a cells
  //input: -the x/y location of a cell
  //       -the value to put into the cell(optional)
  //returns: -the contents of the cell(if no value is given)
  //         -nothing, if a value is given
  function cell(x, y, value) {
    //either gets the contents of x, y or sets them
    if(arguments.length == 3)
      cells[x][y].html(value);
    else
      return parseInt(cells[x][y].html());
  }

  var render = function(data) {
    //hide the overlay if needbe
    mediator.publish('overlay_set_inactive');

    //store the level
    level = data;

    //parse its contents
    for(var i = 0; i < level.contents.length; ++i) {
      var x = i % 3;
      var y = Math.floor(i / 3);
      cell(x, y, level.contents[i]);
      if(level.mode == "b&w") {
        if(level.colors[i] == "b") {
          cells[x][y].removeClass('white');
          cells[x][y].addClass('black');
        }
        else {
          cells[x][y].removeClass('black');
          cells[x][y].addClass('white')
        }
      }
    }

    //set the currently selected cell
    level.selected = {
      x: data.initialSelected.x,
      y: data.initialSelected.y
    };

    //put the level number in the corner
    levelLink.html('level ' + level.number + '/' + numLevels); //hard code the levels?

    //fade in the level
    board.fadeIn(options['fade']);
    active = true;

    //update the screen
    update();

    //add the anchor to the url
    document.location.hash = "#" + level.number; //TODO: move this elsewhere
  };

  var setNumLevels = function(num) { numLevels = num; }

  var setInactive = function() {
    board.fadeOut(options['fade']);
    active = false;
  }

  return {
    render: render,
    up: up,
    down: down,
    left: left,
    right: right,
    setNumLevels: setNumLevels,
    setInactive: setInactive
  }
}())

//add the mediator to the module
mediator.installTo(BoardModule);

//subscribe to messages
BoardModule.subscribe('board_render', BoardModule.render);
BoardModule.subscribe('board_set_inactive', BoardModule.setNumLevels);
BoardModule.subscribe('controls_key_down', BoardModule.down);
BoardModule.subscribe('controls_key_left', BoardModule.left);
BoardModule.subscribe('controls_key_right', BoardModule.right);
BoardModule.subscribe('controls_key_up', BoardModule.up);
BoardModule.subscribe('story_num_levels', BoardModule.setNumLevels);<commit_msg>quality edited code/comments<commit_after>// board.js(BoardModule)

var BoardModule = (function() {

  // Components of the DOM
  var board = $('#board');
  var cells = [];
  var levelLink = $('#level');
  var overlay = $('#overlay');
  var resetLink = $('#reset');

  // Variables for the page
  var active = false;
  var level; // Contains the level data
  var numLevels = -1;

  // Resets the level to its original state
  var reset = function() {
    render(level);
  }

  // Populates cells array with links to cells in DOM
  for(var i = 0; i < 4; ++i) {
    cells.push([]);
    for(var j = 0; j < 4; ++j) {
      cells[i].push($('td[data-x="' + i + '"][data-y="' + j + '"]'));
    }
  }

  // Updates the board, called whenever a change is made
  var update = function() {
    $('td.selected').removeClass('selected');

    cells[level.selected.x][level.selected.y].addClass('selected');

    if(isWin()) {
      board.fadeOut(options['fade'], function() {
        mediator.publish('board_level_complete');
      })
    }
  }

  // Looks for a winning condition on the board, returns true or false
  function isWin() {
    var value = cell(0,0);
    for(var i = 0; i < 3; ++i) {
      for(var j = 0; j < 3; ++j) {
        if(cell(i,j) != value)
          return false
      }
    }
    return true;
  }

  // Selects the cell to the left of the current cell
  function left() {
    if(active && level.selected.x > 0) {
      select(--level.selected.x, level.selected.y);
      update();
    }
  }

  // Selects the cell above the current cell
  function up() {
    if(active && level.selected.y > 0) {
      select(level.selected.x, --level.selected.y);
      update();
    }
  }

  // Selects the cell to the right of the current cell
  function right() {
    if(active && level.selected.x < 2) {
      select(++level.selected.x, level.selected.y);
      update();
    }
  }

  // Selects the cell under the current cell
  function down() {
    if(active && level.selected.y < 2) {
      select(level.selected.x, ++level.selected.y);
      update();
    }
  }

  // Selects a cell and modifies it's value if necessary
  function select(x, y) {
    var sel = level.selected;
    if(cells[sel.x][sel.y].hasClass('black')) {
      cell(sel.x, sel.y, cell(sel.x, sel.y)+1);
    }
    else if(cells[sel.x][sel.y].hasClass('white')) {
      cell(sel.x, sel.y, cell(sel.x, sel.y)-1);
    }
    else {
      cell(sel.x, sel.y, cell(sel.x, sel.y)+1);
    }
  }

  // Sets the value of a cell at x, y. If no value given, returns the value
  function cell(x, y, value) {
    if(arguments.length == 3)
      cells[x][y].html(value);
    else
      return parseInt(cells[x][y].html());
  }

  // Initially draws the level's cells
  var render = function(data) {
    // Deactivate previous overlays
    mediator.publish('overlay_set_inactive');

    level = data;

    // Parse the level data
    for(var i = 0; i < level.contents.length; ++i) {
      var x = i % 3;
      var y = Math.floor(i / 3);
      cell(x, y, level.contents[i]);
      if(level.mode == "b&w") {
        if(level.colors[i] == "b") {
          cells[x][y].removeClass('white');
          cells[x][y].addClass('black');
        }
        else {
          cells[x][y].removeClass('black');
          cells[x][y].addClass('white')
        }
      }
    }

    level.selected = {
      x: data.initialSelected.x,
      y: data.initialSelected.y
    };

    // Set the level text
    levelLink.html('level ' + level.number + '/' + numLevels);

    // Fade in once populated
    board.fadeIn(options['fade']);
    active = true;

    // Update to select the appropriate cell
    update();

    // Append the level number to the URL
    document.location.hash = "#" + level.number; //TODO: move this elsewhere
  };

  // Can be called by other modules, setting the total number of levels
  var setNumLevels = function(num) { numLevels = num; }

  // Fades out the board and sets it as inactive
  var setInactive = function() {
    board.fadeOut(options['fade']);
    active = false;
  }

  // Event bindings
  resetLink.on('click', reset);

  // The facade
  return {
    render: render,
    up: up,
    down: down,
    left: left,
    right: right,
    setNumLevels: setNumLevels,
    setInactive: setInactive
  }
}())

// Add the mediator to the module
mediator.installTo(BoardModule);

// Subscribe to messages

// Draw the board when told
BoardModule.subscribe('board_render', BoardModule.render);

// Listen to be told when to deactivate the view
BoardModule.subscribe('board_set_inactive', BoardModule.setNumLevels);

// Listen to the keyboard so the selector can be moved
BoardModule.subscribe('controls_key_down', BoardModule.down);
BoardModule.subscribe('controls_key_left', BoardModule.left);
BoardModule.subscribe('controls_key_right', BoardModule.right);
BoardModule.subscribe('controls_key_up', BoardModule.up);

// Set the number of levels in this module
BoardModule.subscribe('story_num_levels', BoardModule.setNumLevels);<|endoftext|>


<commit_before>/*global define: true */

define(["./Route"], function (Route) {
    "use strict";

    return function (routeMap) {
        var currentRouteName = null,
            routes = [],
            mapItemName = null,

            addRoute = function (mapItemName, route) {
                routes[mapItemName] = route;
            };

        for (mapItemName in routeMap) {
            if (routeMap.hasOwnProperty(mapItemName)) {
                addRoute(mapItemName, routeMap[mapItemName]);
            }
        }

        return {
            addRoute: function (mapItemName, route) {
                addRoute(mapItemName, route);
            },

            route: function (request) {
                var routeName, paramName, routeParams = [];

                for (routeName in routes) {
                    if (routes.hasOwnProperty(routeName)) {
                        // find a matching route to the current PATH_INFO
                        routeParams = routes[routeName].match(request.getPathname());
                        if (routeParams) {
                            // route found
                            currentRouteName = routeName;
                            for (paramName in routeParams) {
                                if (routeParams.hasOwnProperty(paramName)) {
                                    // inject returning values to the request object.
                                    request.setPathParam(paramName, routeParams[paramName]);
                                }
                            }
                            return request;
                        }
                    }
                }
                return null;
            },

            getCurrentRoute: function () {
                return routes[currentRouteName] || null;
            },

            getCurrentRouteName: function () {
                return currentRouteName;
            },

            getRoute: function (name) {
                if (!routes[name]) {
                    throw new Error('Route does not exist: ' + name);
                }
                return routes[name];
            }
        };
    };
});<commit_msg>Dont throw exception on nonexisting route<commit_after>/*global define: true */

define(["./Route"], function (Route) {
    "use strict";

    return function (routeMap) {
        var currentRouteName = null,
            routes = [],
            mapItemName = null,

            addRoute = function (mapItemName, route) {
                routes[mapItemName] = route;
            };

        for (mapItemName in routeMap) {
            if (routeMap.hasOwnProperty(mapItemName)) {
                addRoute(mapItemName, routeMap[mapItemName]);
            }
        }

        return {
            addRoute: function (mapItemName, route) {
                addRoute(mapItemName, route);
            },

            route: function (request) {
                var routeName, paramName, routeParams = [];

                for (routeName in routes) {
                    if (routes.hasOwnProperty(routeName)) {
                        // find a matching route to the current PATH_INFO
                        routeParams = routes[routeName].match(request.getPathname());
                        if (routeParams) {
                            // route found
                            currentRouteName = routeName;
                            for (paramName in routeParams) {
                                if (routeParams.hasOwnProperty(paramName)) {
                                    // inject returning values to the request object.
                                    request.setPathParam(paramName, routeParams[paramName]);
                                }
                            }
                            return request;
                        }
                    }
                }
                return null;
            },

            getCurrentRoute: function () {
                return routes[currentRouteName] || null;
            },

            getCurrentRouteName: function () {
                return currentRouteName;
            },

            getRoute: function (name) {
                return routes[name] || undefined;
            }
        };
    };
});<|endoftext|>


<commit_before>/** @module deliteful/Select */
define([
	"dcl/dcl",
	"dojo/dom-class", // TODO: replace (when replacement confirmed)
	"delite/register",
	"delite/FormWidget",
	"delite/StoreMap",
	"delite/Selection",
	"delite/handlebars!./Select/Select.html",
	"delite/theme!./Select/themes/{{theme}}/Select.css"
], function (dcl, domClass, register,
	FormWidget, StoreMap, Selection, template) {

	/**
	 * A form-aware and store-aware widget leveraging the native HTML5 `<select>`
	 * element.
	 * It has the following characteristics:
	 * * The corresponding custom tag is `<d-select>`.
	 * * Store support (limitation: to avoid graphic glitches, the updates to the
	 * store should not be done while the native dropdown of the select is open).
	 * The attributes of data items used for the label and value of option elements
	 * can be customized using the `labelAttr` and `valueAttr` properties, or using
	 * a `labelFunc` and `valueFunc` (for details, see the documentation of the
	 * `delite/StoreMap` superclass).
	 * * The item rendering has the limitations of the `<option>` elements of the
	 * native `<select>`, in particular it is text-only.
	 *
	 * TODO: improve doc.
	 *
	 * Remarks:
	 * * The option items must be added, removed or updated exclusively using
	 * the store API. Direct operations using the DOM API are not supported.
	 * * The handling of the selected options of the underlying native `<select>`
	 * must be done using the API inherited by deliteful/Select from delite/Selection.
	 *
	 * @example
Using store custom element in markup

	 * JS:
	 * require(["delite/register", "deliteful/Select", "requirejs-domready/domReady!"],
	 *   function (register) {
	 *     register.parse();
	 *   });
	 * HTML:
	 * <d-store id="myStore">
	 *    {text: "Option 1", value: "1"}
	 *    ...
	 * </d-store>
	 * <d-select id="select" store="myStore"></d-select>
	 * @example
Using programmatically created store

	 * JS:
	 * require(["delite/register", "dstore/Memory", "dstore/Trackable",
	 *         "deliteful/Select", "requirejs-domready/domReady!"],
	 *   function (register, Memory, Trackable) {
	 *     register.parse();
	 *     var store = new (Memory.createSubclass(Trackable))({});
	 *     select1.store = store;
	 *     store.add({text: "Option 1", value: "1"});
	 *     ...
	 *   });
	 * HTML:
	 * <d-select selectionMode="multiple" id="select"></d-select>
	 *
	 * @class module:deliteful/Select
	 * @augments module:delite/FormWidget
	 * @augments module:delite/StoreMap
	 * @augments module:delite/Selection
	 */
	return register("d-select", [HTMLElement, FormWidget, StoreMap, Selection],
		/** @lends module:deliteful/Select# */ {

		// Note: the properties `store` and `query` are inherited from delite/Store, and
		// the property `disabled` is inherited from delite/FormWidget.

		/**
		 * The number of rows that should be visible at one time when the widget
		 * is presented as a scrollable list box. Corresponds to the `size` attribute
		 * of the underlying native HTML `<select>`.
		 * @member {number}
		 * @default 0
		 */
		size: 0,

		/**
		 * The name of the property of store items which contains the text
		 * of Select's options.
		 * @member {string}
		 * @default "text"
		 */
		textAttr: "text",

		/**
		 * The name of the property of store items which contains the value
		 * of Select's options.
		 * @member {string}
		 * @default "value"
		 */
		valueAttr: "value",

		/**
		 * The name of the property of store items which contains the disabled
		 * value of Select's options. To disable a given option, the `disabled`
		 * property of the corresponding data item must be set to a truthy value.
		 * Otherwise, the option is enabled if data item property is absent, or
		 * its value is falsy or the string "false".
		 * @member {string}
		 * @default "disabled"
		 */
		disabledAttr: "disabled",

		baseClass: "d-select",

		/**
		 * The chosen selection mode.
		 *
		 * Valid values are:
		 *
		 * 1. "single": Only one option can be selected at a time.
		 * 2. "multiple": Several options can be selected (by taping or using the
		 * control key modifier).
		 *
		 * Changing this value impacts the currently selected items to adapt the
		 * selection to the new mode. However, regardless of the selection mode,
		 * it is always possible to set several selected items using the
		 * `selectedItem` or `selectedItems` properties.
		 * The mode will be enforced only when using `setSelected` and/or
		 * `selectFromEvent` APIs.
		 *
		 * @member {string} module:deliteful/Select#selectionMode
		 * @default "single"
		 */
		// The purpose of the above pseudo-property is to adjust the documentation
		// of selectionMode as provided by delite/Selection.

		template: template,

		attachedCallback: function () {
			// To provide graphic feedback for focus, react to focus/blur events
			// on the underlying native select. The CSS class is used instead
			// of the focus pseudo-class because the browsers give the focus
			// to the underlying select, not to the widget.
			this.on("focus", function (evt) {
				domClass.toggle(this, "d-select-focus", evt.type === "focus");
			}.bind(this), this.valueNode);
			this.on("blur", function (evt) {
				domClass.toggle(this, "d-select-focus", evt.type === "focus");
			}.bind(this), this.valueNode);

			// Keep delite/Selection's selectedItem/selectedItems in sync after
			// interactive selection of options.
			this.on("change", function (event) {
				var selectedItems = this.selectedItems,
					selectedOptions = this.valueNode.selectedOptions;
				// HTMLSelectElement.selectedOptions is not present in all browsers...
				// At least IE10/Win misses it. Hence:
				if (selectedOptions === undefined) {
					// Convert to array
					var options = Array.prototype.slice.call(this.valueNode.options);
					selectedOptions = options.filter(function (option) {
						return option.selected;
					});
				} else {
					// convert HTMLCollection into array (to be able to use array.indexOf)
					selectedOptions = Array.prototype.slice.call(selectedOptions);
				}
				var nSelectedItems = selectedItems ? selectedItems.length : 0,
					nSelectedOptions = selectedOptions ? selectedOptions.length : 0;
				var i;
				var selectedOption, selectedItem;
				// Identify the options which changed their selection state. Two steps:
				// Step 1. Search options previously selected (currently in widget.selectedItems)
				// which are no longer selected in the native select.
				for (i = 0; i < nSelectedItems; i++) {
					selectedItem = selectedItems[i];
					if (selectedOptions.indexOf(selectedItem.__visualItem) === -1) {
						this.selectFromEvent(event, selectedItem, selectedItem.__visualItem, true);
					}
				}
				// Step 2. Search options newly selected in the native select which are not
				// present in the current selection (widget.selectedItems).
				for (i = 0; i < nSelectedOptions; i++) {
					selectedOption = selectedOptions[i];
					if (selectedItems.indexOf(selectedOption.__dataItem) === - 1) {
						this.selectFromEvent(event, selectedOption.__dataItem, selectedOption, true);
					}
				}

				// Update widget's value after interactive selection
				this._set("value", this.valueNode.value);
			}.bind(this), this.valueNode);

			// Thanks to the custom getter defined in deliteful/Select for widget's
			// `value` property, there is no need to add code for keeping the
			// property in sync after a form reset.
		},

		hasSelectionModifier: function () {
			// Override of the method from delite/Selection because the
			// default implementation is inappropriate: the "change" event
			// has no key modifier.
			return this.selectionMode === "multiple";
		},

		refreshRendering: function (props) {
			if ("renderItems" in props) {
				// Populate the select with the items retrieved from the store.
				var renderItems = this.renderItems;
				var n = renderItems ? renderItems.length : 0;
				// TODO: CHECKME/IMPROVEME. Also called after adding, deleting or updating just one item.
				// Worth optimizing to avoid recreating from scratch?
				this.valueNode.innerHTML = ""; // Remove the existing options from the DOM
				if (n > 0) {
					var fragment = this.ownerDocument.createDocumentFragment();
					var renderItem, option;
					for (var i = 0; i < n; i++) {
						renderItem = renderItems[i];
						option = this.ownerDocument.createElement("option");
						// to allow retrieving the data item from the option element
						option.__dataItem = renderItem.__item; // __item is set by StoreMap.itemToRenderItem()
						// to allow retrieving the option element from widget's selectedItems
						// (which are data items, not render items).
						option.__dataItem.__visualItem = option;

						// According to http://www.w3.org/TR/html5/forms.html#the-option-element, we
						// could use equivalently the label or the text IDL attribute of the option element.
						// However, using the label attr. breaks the rendering in FF29/Win7!
						// This is https://bugzilla.mozilla.org/show_bug.cgi?id=40545.
						// Hence don't do
						// option.label = renderItem.label;
						// Instead:
						if (renderItem.text !== undefined) { // optional
							option.text = renderItem.text;
						}
						if (renderItem.value !== undefined) { // optional
							option.setAttribute("value", renderItem.value);
						}
						// The selection API (delite/Selection) needs to be called consistently
						// for data items, not for render items.
						// renderItem.__item is the data item instance for which
						// StoreMap.itemToRenderItem() has created the render item.
						// For now there is no public API for accessing it.
						if (this.isSelected(renderItem.__item)) { // delite/Selection's API
							option.setAttribute("selected", "true");
						}
						if (renderItem.disabled !== undefined &&
							!!renderItem.disabled && renderItem.disabled !== "false") { // optional
							// Note that for an enabled option the attribute must NOT be set
							// (<option disabled="false"> is a disabled option!)
							option.setAttribute("disabled", "true");
						}

						fragment.appendChild(option);
					}
					this.valueNode.appendChild(fragment);

					if (this.selectionMode === "single") {
						// Since there is no native "change" event initially, initialize
						// the delite/Selection's selectedItem property with the currently
						// selected option of the native select.
						this.selectedItem =
							this.valueNode.options[this.valueNode.selectedIndex].__dataItem;
					} // else for the native multi-select: it does not have any
					// option selected by default.

					// Initialize widget's value
					this._set("value", this.valueNode.value);
				}
			}
		},

		getIdentity: function (dataItem) {
			// Override of delite/Selection's method
			return this.store.getIdentity(dataItem);
		},

		updateRenderers: function () {
			// Override of delite/Selection's method
			// Trigger rerendering from scratch:
			this.notifyCurrentValue("renderItems");
		},

		_setValueAttr: function (value) {
			if (this.valueNode) {
				this.valueNode.value = value;
			}
			this._set("value", value);
		},

		_setSelectionModeAttr: dcl.superCall(function (sup) {
			// Override of the setter from delite/Selection to forbid the values
			// "none" and "radio"
			return function (value) {
				if (value !== "single" && value !== "multiple") {
					throw new TypeError("'" + value +
						"' not supported for selectionMode; keeping the previous value of '" +
						this.selectionMode + "'");
				} else {
					this._set("selectionMode", value);
				}
				sup.call(this, value);
			};
		})
	});
});
<commit_msg>Select: small API doc improvements.<commit_after>/** @module deliteful/Select */
define([
	"dcl/dcl",
	"dojo/dom-class", // TODO: replace (when replacement confirmed)
	"delite/register",
	"delite/FormWidget",
	"delite/StoreMap",
	"delite/Selection",
	"delite/handlebars!./Select/Select.html",
	"delite/theme!./Select/themes/{{theme}}/Select.css"
], function (dcl, domClass, register,
	FormWidget, StoreMap, Selection, template) {

	/**
	 * A form-aware and store-aware widget leveraging the native HTML5 `<select>`
	 * element.
	 * It has the following characteristics:
	 * * The corresponding custom tag is `<d-select>`.
	 * * Allows to select one or more items among a number of options (in single
	 * or multiple selection mode; see `selectionMode`).
	 * * Store support (limitation: to avoid graphic glitches, the updates to the
	 * store should not be done while the native dropdown of the select is open).
	 * The attributes of data items used for the label and value of option elements
	 * can be customized using the `labelAttr` and `valueAttr` properties, or using
	 * a `labelFunc` and `valueFunc` (for details, see the documentation of the
	 * `delite/StoreMap` superclass).
	 * * Form support (inherits from `delite/FormWidget`).
	 * * The item rendering has the limitations of the `<option>` elements of the
	 * native `<select>`, in particular it is text-only.
	 *
	 * Remarks:
	 * * The option items must be added, removed or updated exclusively using
	 * the store API. Direct operations using the DOM API are not supported.
	 * * The handling of the selected options of the underlying native `<select>`
	 * must be done using the API inherited by deliteful/Select from delite/Selection.
	 *
	 * @example
Using store custom element in markup

	 * JS:
	 * require(["delite/register", "deliteful/Select", "requirejs-domready/domReady!"],
	 *   function (register) {
	 *     register.parse();
	 *   });
	 * HTML:
	 * <d-store id="myStore">
	 *    {text: "Option 1", value: "1"}
	 *    ...
	 * </d-store>
	 * <d-select id="select" store="myStore"></d-select>
	 * @example
Using programmatically created store

	 * JS:
	 * require(["delite/register", "dstore/Memory", "dstore/Trackable",
	 *         "deliteful/Select", "requirejs-domready/domReady!"],
	 *   function (register, Memory, Trackable) {
	 *     register.parse();
	 *     var store = new (Memory.createSubclass(Trackable))({});
	 *     select1.store = store;
	 *     store.add({text: "Option 1", value: "1"});
	 *     ...
	 *   });
	 * HTML:
	 * <d-select selectionMode="multiple" id="select"></d-select>
	 *
	 * @class module:deliteful/Select
	 * @augments module:delite/FormWidget
	 * @augments module:delite/StoreMap
	 * @augments module:delite/Selection
	 */
	return register("d-select", [HTMLElement, FormWidget, StoreMap, Selection],
		/** @lends module:deliteful/Select# */ {

		// TODO: improve doc.

		// Note: the properties `store` and `query` are inherited from delite/Store, and
		// the property `disabled` is inherited from delite/FormWidget.

		/**
		 * The number of rows that should be visible at one time when the widget
		 * is presented as a scrollable list box. Corresponds to the `size` attribute
		 * of the underlying native HTML `<select>`.
		 * @member {number}
		 * @default 0
		 */
		size: 0,

		/**
		 * The name of the property of store items which contains the text
		 * of Select's options.
		 * @member {string}
		 * @default "text"
		 */
		textAttr: "text",

		/**
		 * The name of the property of store items which contains the value
		 * of Select's options.
		 * @member {string}
		 * @default "value"
		 */
		valueAttr: "value",

		/**
		 * The name of the property of store items which contains the disabled
		 * value of Select's options. To disable a given option, the `disabled`
		 * property of the corresponding data item must be set to a truthy value.
		 * Otherwise, the option is enabled if data item property is absent, or
		 * its value is falsy or the string "false".
		 * @member {string}
		 * @default "disabled"
		 */
		disabledAttr: "disabled",

		baseClass: "d-select",

		/**
		 * The chosen selection mode.
		 *
		 * Valid values are:
		 *
		 * 1. "single": Only one option can be selected at a time.
		 * 2. "multiple": Several options can be selected (by taping or using the
		 * control key modifier).
		 *
		 * Changing this value impacts the currently selected items to adapt the
		 * selection to the new mode. However, regardless of the selection mode,
		 * it is always possible to set several selected items using the
		 * `selectedItem` or `selectedItems` properties.
		 * The mode will be enforced only when using `setSelected` and/or
		 * `selectFromEvent` APIs.
		 *
		 * @member {string} module:deliteful/Select#selectionMode
		 * @default "single"
		 */
		// The purpose of the above pseudo-property is to adjust the documentation
		// of selectionMode as provided by delite/Selection.

		template: template,

		attachedCallback: function () {
			// To provide graphic feedback for focus, react to focus/blur events
			// on the underlying native select. The CSS class is used instead
			// of the focus pseudo-class because the browsers give the focus
			// to the underlying select, not to the widget.
			this.on("focus", function (evt) {
				domClass.toggle(this, "d-select-focus", evt.type === "focus");
			}.bind(this), this.valueNode);
			this.on("blur", function (evt) {
				domClass.toggle(this, "d-select-focus", evt.type === "focus");
			}.bind(this), this.valueNode);

			// Keep delite/Selection's selectedItem/selectedItems in sync after
			// interactive selection of options.
			this.on("change", function (event) {
				var selectedItems = this.selectedItems,
					selectedOptions = this.valueNode.selectedOptions;
				// HTMLSelectElement.selectedOptions is not present in all browsers...
				// At least IE10/Win misses it. Hence:
				if (selectedOptions === undefined) {
					// Convert to array
					var options = Array.prototype.slice.call(this.valueNode.options);
					selectedOptions = options.filter(function (option) {
						return option.selected;
					});
				} else {
					// convert HTMLCollection into array (to be able to use array.indexOf)
					selectedOptions = Array.prototype.slice.call(selectedOptions);
				}
				var nSelectedItems = selectedItems ? selectedItems.length : 0,
					nSelectedOptions = selectedOptions ? selectedOptions.length : 0;
				var i;
				var selectedOption, selectedItem;
				// Identify the options which changed their selection state. Two steps:
				// Step 1. Search options previously selected (currently in widget.selectedItems)
				// which are no longer selected in the native select.
				for (i = 0; i < nSelectedItems; i++) {
					selectedItem = selectedItems[i];
					if (selectedOptions.indexOf(selectedItem.__visualItem) === -1) {
						this.selectFromEvent(event, selectedItem, selectedItem.__visualItem, true);
					}
				}
				// Step 2. Search options newly selected in the native select which are not
				// present in the current selection (widget.selectedItems).
				for (i = 0; i < nSelectedOptions; i++) {
					selectedOption = selectedOptions[i];
					if (selectedItems.indexOf(selectedOption.__dataItem) === - 1) {
						this.selectFromEvent(event, selectedOption.__dataItem, selectedOption, true);
					}
				}

				// Update widget's value after interactive selection
				this._set("value", this.valueNode.value);
			}.bind(this), this.valueNode);

			// Thanks to the custom getter defined in deliteful/Select for widget's
			// `value` property, there is no need to add code for keeping the
			// property in sync after a form reset.
		},

		hasSelectionModifier: function () {
			// Override of the method from delite/Selection because the
			// default implementation is inappropriate: the "change" event
			// has no key modifier.
			return this.selectionMode === "multiple";
		},

		refreshRendering: function (props) {
			if ("renderItems" in props) {
				// Populate the select with the items retrieved from the store.
				var renderItems = this.renderItems;
				var n = renderItems ? renderItems.length : 0;
				// TODO: CHECKME/IMPROVEME. Also called after adding, deleting or updating just one item.
				// Worth optimizing to avoid recreating from scratch?
				this.valueNode.innerHTML = ""; // Remove the existing options from the DOM
				if (n > 0) {
					var fragment = this.ownerDocument.createDocumentFragment();
					var renderItem, option;
					for (var i = 0; i < n; i++) {
						renderItem = renderItems[i];
						option = this.ownerDocument.createElement("option");
						// to allow retrieving the data item from the option element
						option.__dataItem = renderItem.__item; // __item is set by StoreMap.itemToRenderItem()
						// to allow retrieving the option element from widget's selectedItems
						// (which are data items, not render items).
						option.__dataItem.__visualItem = option;

						// According to http://www.w3.org/TR/html5/forms.html#the-option-element, we
						// could use equivalently the label or the text IDL attribute of the option element.
						// However, using the label attr. breaks the rendering in FF29/Win7!
						// This is https://bugzilla.mozilla.org/show_bug.cgi?id=40545.
						// Hence don't do
						// option.label = renderItem.label;
						// Instead:
						if (renderItem.text !== undefined) { // optional
							option.text = renderItem.text;
						}
						if (renderItem.value !== undefined) { // optional
							option.setAttribute("value", renderItem.value);
						}
						// The selection API (delite/Selection) needs to be called consistently
						// for data items, not for render items.
						// renderItem.__item is the data item instance for which
						// StoreMap.itemToRenderItem() has created the render item.
						// For now there is no public API for accessing it.
						if (this.isSelected(renderItem.__item)) { // delite/Selection's API
							option.setAttribute("selected", "true");
						}
						if (renderItem.disabled !== undefined &&
							!!renderItem.disabled && renderItem.disabled !== "false") { // optional
							// Note that for an enabled option the attribute must NOT be set
							// (<option disabled="false"> is a disabled option!)
							option.setAttribute("disabled", "true");
						}

						fragment.appendChild(option);
					}
					this.valueNode.appendChild(fragment);

					if (this.selectionMode === "single") {
						// Since there is no native "change" event initially, initialize
						// the delite/Selection's selectedItem property with the currently
						// selected option of the native select.
						this.selectedItem =
							this.valueNode.options[this.valueNode.selectedIndex].__dataItem;
					} // else for the native multi-select: it does not have any
					// option selected by default.

					// Initialize widget's value
					this._set("value", this.valueNode.value);
				}
			}
		},

		getIdentity: function (dataItem) {
			// Override of delite/Selection's method
			return this.store.getIdentity(dataItem);
		},

		updateRenderers: function () {
			// Override of delite/Selection's method
			// Trigger rerendering from scratch:
			this.notifyCurrentValue("renderItems");
		},

		_setValueAttr: function (value) {
			if (this.valueNode) {
				this.valueNode.value = value;
			}
			this._set("value", value);
		},

		_setSelectionModeAttr: dcl.superCall(function (sup) {
			// Override of the setter from delite/Selection to forbid the values
			// "none" and "radio"
			return function (value) {
				if (value !== "single" && value !== "multiple") {
					throw new TypeError("'" + value +
						"' not supported for selectionMode; keeping the previous value of '" +
						this.selectionMode + "'");
				} else {
					this._set("selectionMode", value);
				}
				sup.call(this, value);
			};
		})
	});
});
<|endoftext|>


<commit_before>const assert = require('assert');

class PirateRepository {

	search(query) {
		console.log(query)
	}

	searchMedia(query) {
		var options = {
			uri: 'http://10.0.0.41:32400/search?query=' + query,
			headers: {
				'Accept': 'application/json'
			},
			json: true
		}

		return rp(options)
		  .then((result) => {
		  	var seasonedMediaObjects = result.MediaContainer.Metadata.reduce(function(match, media_item) {
		  		if (media_item.type === 'movie' || media_item.type === 'show') {
		  			match.push(convertPlexToSeasoned(media_item));
		  		}
		  		return match;
		  	}, []);
		  	return seasonedMediaObjects;
		  })
		  .catch((err) => {
		  	throw new Error(err);
		  })
	}
}

module.exports = PirateRepository;<commit_msg>Now makes a async call for python script and returns the ouput of the script when finished as a json object.<commit_after>const assert = require('assert');
var PythonShell = require('python-shell');
var async = require('async');

async function find(searchterm, callback) {
  var PythonShell = require('python-shell');

  var options = {
		// pythonPath: '/usr/bin/python3',
		pythonPath: '/Library/Frameworks/Python.framework/Versions/3.6/bin/python3',
		args: [searchterm]
	}

	PythonShell.run('../app/pirateSearch.py', options, callback);
  // PythonShell does not support return
};

async function SearchPiratebay(query) {
	return await new Promise((resolve) => {
		return find(query, function(err, results) {
			resolve(JSON.parse(results, null, '\t'));
		})
	})
}

module.exports = { SearchPiratebay }<|endoftext|>