<commit_before>var fs           = require('fs');
var util         = require('util');

var Readable     = require('readable-stream');

var Command  = require('./command.js');
var Packets  = require('../packets/index.js');
var compileParser = require('../compile_text_parser.js');
var ServerStatus = require('../constants/server_status.js');

var EmptyPacket = new Packets.Packet(0, new Buffer(4), 0, 4);

function Query(options, callback)
{
  Command.call(this);
  this.sql = options.sql;
  this.values = options.values;
  this.options = options;
  this.onResult = callback;
  this._fieldCount = 0;
  this._rowParser  = null;
  this._fields     = [];
  this._rows       = [];
  this._receivedFieldsCount = 0;
  this._resultIndex = 0;
  this._localStream = null;
  this._streamFactory = options.infileStreamFactory;
  this._connection = null;
}
util.inherits(Query, Command);

Query.prototype.start = function(packet, connection) {
  if (connection.config.debug) {
    console.log('        Sending query command: %s', this.sql);
  }
  this._connection = connection;
  var cmdPacket = new Packets.Query(this.sql);
  connection.writePacket(cmdPacket.toPacket(1));
  return Query.prototype.resultsetHeader;
};

Query.prototype.done = function() {
  var self = this;
  if (this.onResult) {
    var rows, fields;
    if (this._resultIndex === 0) {
      rows = this._rows[0];
      fields = this._fields[0];
    } else {
      rows = this._rows;
      fields = this._fields;
    }
    if (fields) {
      process.nextTick(function() {
        self.onResult(null, rows, fields);
      });
    } else {
      process.nextTick(function() {
        self.onResult(null, rows);
      });
    }
  }
  return null;
};

Query.prototype.doneInsert = function(rs) {
  if (this._localStreamError) {
    if (this.onResult) {
      this.onResult(this._localStreamError, rs);
    } else {
      this.emit('error', this._localStreamError);
    }
    return null;
  }
  this._rows.push(rs);
  this._fields.push(void(0));
  this.emit('result', rs);
  this.emit('fields', void(0));
  if (rs.serverStatus & ServerStatus.SERVER_MORE_RESULTS_EXISTS) {
    this._resultIndex++;
    return this.resultsetHeader;
  }
  return this.done();
};

Query.prototype.resultsetHeader = function(packet, connection) {
  var rs = new Packets.ResultSetHeader(packet, connection.config.bigNumberStrings);
  this._fieldCount = rs.fieldCount;
  if (connection.config.debug) {
    console.log('        Resultset header received, expecting ' + rs.fieldCount + ' column definition packets');
  }
  if (this._fieldCount === 0) {
    return this.doneInsert(rs);
  }
  if (this._fieldCount === null) {
    this._localStream = this._findOrCreateReadStream(rs.infileName);
    // start streaming, after last packet expect OK
    this._streamLocalInfile(connection);
    return this.infileOk;
  }

  this._receivedFieldsCount = 0;
  this._rows.push([]);
  this._fields.push([]);
  return this.readField;
};

// some code taken from https://github.com/felixge/node-mysql/pull/668
Query.prototype._findOrCreateReadStream = function(path) {
  if (this._streamFactory)
    return this._streamFactory(path);
  return fs.createReadStream(path, {
    'flag': 'r',
    'encoding': null,
    'autoClose': true
  });
};

Query.prototype._streamLocalInfile = function(connection) {
  var command = this;
  connection.stream.on('pause', function() {
    command._localStream.pause();
  });
  connection.stream.on('drain', function() {
    command._localStream.resume();
  });
  this._localStream.on('data', function (data) {
    var dataWithHeader = new Buffer(data.length + 4);
    data.copy(dataWithHeader, 4);
    connection.writePacket(new Packets.Packet(0, dataWithHeader, 0, dataWithHeader.length));
  });
  this._localStream.on('end', function (data) {
    connection.writePacket(EmptyPacket);
  });
  this._localStream.on('error', function(err) {
    command._localStreamError = err;
    command._localStream.emit('end');
  });
}

Query.prototype.readField = function(packet, connection) {

  this._receivedFieldsCount++;

  // Often there is much more data in the column definition than in the row itself
  // If you set manually _fields[0] to array of ColumnDefinition's (from previous call)
  // you can 'cache' result of parsing. Field packets still received, but ignored in that case
  // this is the reason _receivedFieldsCount exist (otherwise we could just use current length of fields array)

  if (this._fields[this._resultIndex].length != this._fieldCount) {
    var field = new Packets.ColumnDefinition(packet);
    this._fields[this._resultIndex].push(field);
    if (connection.config.debug) {
      console.log('        Column definition:');
      console.log('          name: ' + field.name);
      console.log('          type: ' + field.columnType);
      console.log('         flags: ' + field.flags);
    }
  }

  // last field received
  if (this._receivedFieldsCount == this._fieldCount) {
    var fields = this._fields[this._resultIndex];
    this.emit('fields', fields);
    var parserKey = connection.keyFromFields(fields, this.options);
    this._rowParser = connection.textProtocolParsers[parserKey];
    if (!this._rowParser) {
      this._rowParser = compileParser(fields, this.options, connection.config);
      connection.textProtocolParsers[parserKey] = this.rowParser;
    }
    return Query.prototype.fieldsEOF;
  }
  return Query.prototype.readField;
};

Query.prototype.fieldsEOF = function(packet, connection) {
  // check EOF
  if (!packet.isEOF())
    return connection.protocolError("Expected EOF packet");
  return this.row;
};

Query.prototype.row = function(packet)
{
  if (packet.isEOF()) {
    var status = packet.eofStatusFlags();
    var moreResults = status & ServerStatus.SERVER_MORE_RESULTS_EXISTS;
    if (moreResults) {
      this._resultIndex++;
      return Query.prototype.resultsetHeader;
    }
    return this.done();
  }

  var row = new this._rowParser(packet);
  if (this.onResult)
    this._rows[this._resultIndex].push(row);
  else
    this.emit('result', row);

  return Query.prototype.row;
};

Query.prototype.infileOk = function(packet, connection) {
  var rs = new Packets.ResultSetHeader(packet, connection.config.bigNumberStrings);
  return this.doneInsert(rs);
};

Query.prototype.stream = function(options) {
  var self = this,
      stream;

  options = options || {};
  options.objectMode = true;
  stream = new Readable(options);

  stream._read = function() {
    self._connection && self._connection.resume();
  };

  this.on('result',function(row) {
    if (!stream.push(row)) self._connection.pause();
    stream.emit('result',row);  // replicate old emitter
  });

  this.on('error',function(err) {
    stream.emit('error',err);  // Pass on any errors
  });

  this.on('end', function() {
    stream.emit('close');  // notify readers that query has completed
    stream.push(null);  // pushing null, indicating EOF
  });

  this.on('fields',function(fields) {
    stream.emit('fields',fields);  // replicate old emitter
  });

  return stream;
};

module.exports = Query;
<commit_msg>always emit fields before rows<commit_after>var fs           = require('fs');
var util         = require('util');

var Readable     = require('readable-stream');

var Command  = require('./command.js');
var Packets  = require('../packets/index.js');
var compileParser = require('../compile_text_parser.js');
var ServerStatus = require('../constants/server_status.js');

var EmptyPacket = new Packets.Packet(0, new Buffer(4), 0, 4);

function Query(options, callback)
{
  Command.call(this);
  this.sql = options.sql;
  this.values = options.values;
  this.options = options;
  this.onResult = callback;
  this._fieldCount = 0;
  this._rowParser  = null;
  this._fields     = [];
  this._rows       = [];
  this._receivedFieldsCount = 0;
  this._resultIndex = 0;
  this._localStream = null;
  this._streamFactory = options.infileStreamFactory;
  this._connection = null;
}
util.inherits(Query, Command);

Query.prototype.start = function(packet, connection) {
  if (connection.config.debug) {
    console.log('        Sending query command: %s', this.sql);
  }
  this._connection = connection;
  var cmdPacket = new Packets.Query(this.sql);
  connection.writePacket(cmdPacket.toPacket(1));
  return Query.prototype.resultsetHeader;
};

Query.prototype.done = function() {
  var self = this;
  if (this.onResult) {
    var rows, fields;
    if (this._resultIndex === 0) {
      rows = this._rows[0];
      fields = this._fields[0];
    } else {
      rows = this._rows;
      fields = this._fields;
    }
    if (fields) {
      process.nextTick(function() {
        self.onResult(null, rows, fields);
      });
    } else {
      process.nextTick(function() {
        self.onResult(null, rows);
      });
    }
  }
  return null;
};

Query.prototype.doneInsert = function(rs) {
  if (this._localStreamError) {
    if (this.onResult) {
      this.onResult(this._localStreamError, rs);
    } else {
      this.emit('error', this._localStreamError);
    }
    return null;
  }
  this._rows.push(rs);
  this._fields.push(void(0));
  this.emit('fields', void(0));
  this.emit('result', rs);
  if (rs.serverStatus & ServerStatus.SERVER_MORE_RESULTS_EXISTS) {
    this._resultIndex++;
    return this.resultsetHeader;
  }
  return this.done();
};

Query.prototype.resultsetHeader = function(packet, connection) {
  var rs = new Packets.ResultSetHeader(packet, connection.config.bigNumberStrings);
  this._fieldCount = rs.fieldCount;
  if (connection.config.debug) {
    console.log('        Resultset header received, expecting ' + rs.fieldCount + ' column definition packets');
  }
  if (this._fieldCount === 0) {
    return this.doneInsert(rs);
  }
  if (this._fieldCount === null) {
    this._localStream = this._findOrCreateReadStream(rs.infileName);
    // start streaming, after last packet expect OK
    this._streamLocalInfile(connection);
    return this.infileOk;
  }

  this._receivedFieldsCount = 0;
  this._rows.push([]);
  this._fields.push([]);
  return this.readField;
};

// some code taken from https://github.com/felixge/node-mysql/pull/668
Query.prototype._findOrCreateReadStream = function(path) {
  if (this._streamFactory)
    return this._streamFactory(path);
  return fs.createReadStream(path, {
    'flag': 'r',
    'encoding': null,
    'autoClose': true
  });
};

Query.prototype._streamLocalInfile = function(connection) {
  var command = this;
  connection.stream.on('pause', function() {
    command._localStream.pause();
  });
  connection.stream.on('drain', function() {
    command._localStream.resume();
  });
  this._localStream.on('data', function (data) {
    var dataWithHeader = new Buffer(data.length + 4);
    data.copy(dataWithHeader, 4);
    connection.writePacket(new Packets.Packet(0, dataWithHeader, 0, dataWithHeader.length));
  });
  this._localStream.on('end', function (data) {
    connection.writePacket(EmptyPacket);
  });
  this._localStream.on('error', function(err) {
    command._localStreamError = err;
    command._localStream.emit('end');
  });
}

Query.prototype.readField = function(packet, connection) {

  this._receivedFieldsCount++;

  // Often there is much more data in the column definition than in the row itself
  // If you set manually _fields[0] to array of ColumnDefinition's (from previous call)
  // you can 'cache' result of parsing. Field packets still received, but ignored in that case
  // this is the reason _receivedFieldsCount exist (otherwise we could just use current length of fields array)

  if (this._fields[this._resultIndex].length != this._fieldCount) {
    var field = new Packets.ColumnDefinition(packet);
    this._fields[this._resultIndex].push(field);
    if (connection.config.debug) {
      console.log('        Column definition:');
      console.log('          name: ' + field.name);
      console.log('          type: ' + field.columnType);
      console.log('         flags: ' + field.flags);
    }
  }

  // last field received
  if (this._receivedFieldsCount == this._fieldCount) {
    var fields = this._fields[this._resultIndex];
    this.emit('fields', fields);
    var parserKey = connection.keyFromFields(fields, this.options);
    this._rowParser = connection.textProtocolParsers[parserKey];
    if (!this._rowParser) {
      this._rowParser = compileParser(fields, this.options, connection.config);
      connection.textProtocolParsers[parserKey] = this.rowParser;
    }
    return Query.prototype.fieldsEOF;
  }
  return Query.prototype.readField;
};

Query.prototype.fieldsEOF = function(packet, connection) {
  // check EOF
  if (!packet.isEOF())
    return connection.protocolError("Expected EOF packet");
  return this.row;
};

Query.prototype.row = function(packet)
{
  if (packet.isEOF()) {
    var status = packet.eofStatusFlags();
    var moreResults = status & ServerStatus.SERVER_MORE_RESULTS_EXISTS;
    if (moreResults) {
      this._resultIndex++;
      return Query.prototype.resultsetHeader;
    }
    return this.done();
  }

  var row = new this._rowParser(packet);
  if (this.onResult)
    this._rows[this._resultIndex].push(row);
  else
    this.emit('result', row);

  return Query.prototype.row;
};

Query.prototype.infileOk = function(packet, connection) {
  var rs = new Packets.ResultSetHeader(packet, connection.config.bigNumberStrings);
  return this.doneInsert(rs);
};

Query.prototype.stream = function(options) {
  var self = this,
      stream;

  options = options || {};
  options.objectMode = true;
  stream = new Readable(options);

  stream._read = function() {
    self._connection && self._connection.resume();
  };

  this.on('result',function(row) {
    if (!stream.push(row)) self._connection.pause();
    stream.emit('result',row);  // replicate old emitter
  });

  this.on('error',function(err) {
    stream.emit('error',err);  // Pass on any errors
  });

  this.on('end', function() {
    stream.emit('close');  // notify readers that query has completed
    stream.push(null);  // pushing null, indicating EOF
  });

  this.on('fields',function(fields) {
    stream.emit('fields',fields);  // replicate old emitter
  });

  return stream;
};

module.exports = Query;
<|endoftext|>


<commit_before>const Errors                    = use('core/errors');

const DefaultProperty           = require('./default');

class DateProperty extends DefaultProperty {

    constructor() {
        super();

        this._addValidator((value, propertyName) => {
            const originalValue = value;

            if(typeof value == 'string'){
                value = new Date(value);
            }

            if (value && (!(value instanceof Date) ||  isNaN(value.getTime()))) {
                throw new Errors.Validation(`property ${propertyName} should be a valid DateTime, given '${originalValue}'`);
            }
        });

        this._inputModification = (value) => {
            return (typeof value === "object" && value instanceof Date) ? value : new Date(value + (value.length > 10 ? ' Z' : '') );
        };
    }

}

module.exports = DateProperty;<commit_msg>Fixed typo. Adding ability to be empty to date fields.<commit_after>const Errors                    = use('core/errors');

const DefaultProperty           = require('./default');

class DateProperty extends DefaultProperty {

    constructor() {
        super();

        this._addValidator((value, propertyName) => {
            const originalValue = value;

            if(typeof value == 'string'){
                value = new Date(value);
            }

            if (value && (!(value instanceof Date) ||  isNaN(value.getTime()))) {
                throw new Errors.Validation(`property ${propertyName} should be a valid DateTime, given '${originalValue}'`);
            }
        });

        this._inputModification = (value) => {
            if (!value) {
                return value;
            }
            return (typeof value === "object" && value instanceof Date) ? value : new Date(value + (value.length > 10 ? '' : ' Z') );
        };
    }

}

module.exports = DateProperty;<|endoftext|>


<commit_before>/**
 * @overview ccm component for fill-in-the-blank texts
 * @author André Kless <andre.kless@web.de> 2017
 * @license The MIT License (MIT)
 */

( function () {

  var ccm_version = '8.0.0';
  var ccm_url     = '../../ccm-developer/ccm/ccm.js';

  var component_name = 'cloze';
  var component_obj  = {

    name: component_name,

    config: {

      text: 'Hello, [[(W)o(rl)d]]!',
      html_templates: {
        main: {
          id: 'main',
          inner: {
            tag: 'form',
            id: 'form',
            inner: [
              { id: 'keywords' },
              { id: 'text' },
              { id: 'button' },
              { id: 'timer' }
            ],
            onsubmit: '%%'
          }
        },
        keyword: {
          class: 'keyword',
          inner: '%%'
        },
        button: {
          tag: 'input',
          type: 'submit',
          value: '%caption%'
        },
        timer: {
          tag: 'span',
          inner: '%%'
        }
      },
      css_layout: [ 'ccm.load', '../cloze/layouts/default.css' ]

  //  blank: true,
  //  ignore_case: true,
  //  keywords: [ 'keyword1', 'keyword2', ... ],
  //  points_per_gap: 1,
  //  time: 60,
  //  button_caption: 'finish',
  //  user: [ 'ccm.instance', '../user/ccm.user.js' ],
  //  logger: [ 'ccm.instance', '../log/ccm.log.js', [ ccm.get, '../log/configs.json', 'greedy' ] ],
  //  onchange: function ( instance, data ) { console.log( data ); }
  //  oninput: function ( instance, data ) { console.log( data ); }
  //  onfinish: function ( instance, results ) { console.log( results ); }

    },

    Instance: function () {

      var self = this;
      var my;             // contains privatized instance members
      var keywords = [];  // information data for each keyword

      this.init = function ( callback ) {

        // fill-in-the-blank text is given via inner HTML? => use it with higher priority
        if ( self.node && self.node.innerHTML.trim() ) self.text = self.node.innerHTML;

        callback();
      };

      this.ready = function ( callback ) {

        // privatize all possible instance members
        my = self.ccm.helper.privatize( self );

        var regex_keyword = /\[\[.+?\]\]/g;   // regular expression for finding all gaps/keywords in the text
        var regex_given = /\(.+?\)/g;         // regular expression for finding all given characters of a keyword

        // iterate all keywords in the text to determine the information data for each keyword
        ( my.text.match( regex_keyword ) || [] ).map( function ( keyword ) {

          // remove distinguishing characteristic '[[' and ']]'
          keyword = keyword.substr( 2, keyword.length - 4 );

          // replace all given characters of a keywords with '*'
          var keyw__d = keyword.replace( '*', '#' ).replace( regex_given, function ( given ) {
            var length = given.length - 2;
            given = '';
            for ( var i = 0; i < length; i++ ) given += '*';
            return given;
          } );

          // determine given characters and hold this information in a single number (disadvantage: possible positions
          var givens = 0;                                                      // for given letters in a word are 0-31
          for ( var i = 0; i < keyw__d.length; i++ )                           // because of data type limitations)
            if ( keyw__d.charAt( i ) === '*' ) givens += Math.pow( 2, i );

          // add keyword information data for current keyword
          keywords.push( {
            word: keyword.replace( regex_given, function ( given ) { return given.substr( 1, given.length - 2 ); } ),
            givens: givens
          } );

        } );

        // replace gaps/keywords with empty span elements
        my.text = my.text.replace( regex_keyword, '' );

        callback();
      };

      this.start = function ( callback ) {

        // initial result data
        var results = { points: 0, max_points: 0, details: [] };

        // prepare main HTML structure
        var main_elem = self.ccm.helper.html( my.html_templates.main, onFinish );

        var   text_elem  = main_elem.querySelector( '#text'   );  // container for text with containing gaps
        var button_elem  = main_elem.querySelector( '#button' );  // container for finish button
        var  timer_elem  = main_elem.querySelector( '#timer'  );  // container for timer
        var  timer_value = my.time;                               // timer value

        // add content for inner containers
        renderKeywords();
        renderText();
        renderButton();
        if ( my.time ) renderTimer(); else self.ccm.helper.removeElement( timer_elem );

        // remember start time
        var time = new Date().getTime();

        // set content of own website area
        self.ccm.helper.setContent( self.element, self.ccm.helper.protect( main_elem ) );

        // has logger instance? => log start event
        if ( self.logger ) self.logger.log( 'start', my );

        if ( callback ) callback();

        /**
         * @summary renders given keywords for text gaps
         * @description
         * Keywords could be given (individual) via instance configuration (my.keywords is string array)
         * or (automatic generated) via private variable 'keywords' (my.keywords is boolean true).
         */
        function renderKeywords() {

          var keywords_elem = main_elem.querySelector( '#keywords' );  // container for keywords
          var entries = [];                                            // inner container for each keyword

          // has given keywords? => create inner container for each keyword
          if ( my.keywords )
            ( Array.isArray( my.keywords ) ? my.keywords : keywords ).map( addKeyword );
          else
            return keywords_elem.parentNode.removeChild( keywords_elem );  // no given keywords? => remove container for keywords and abort

          // generated keyword list? => sort keywords lexicographical (keyword order gives no hint about correct solution)
          if ( my.keywords === true ) entries.sort( function ( a, b ) { return a.innerHTML.localeCompare( b.innerHTML ) } );

          // add each inner keyword container to container for keywords
          entries.map( function ( entry ) { keywords_elem.appendChild( entry ); } );

          /** adds a inner container for a keyword */
          function addKeyword( keyword ) {
            entries.push( self.ccm.helper.html( my.html_templates.keyword, Array.isArray( my.keywords ) ? keyword : keyword.word ) );
          }

        }

        /** renders the text with containing gaps */
        function renderText() {

          // render text with containing gaps
          text_elem.innerHTML = my.text;

          // render input field in each gap
          self.ccm.helper.makeIterable( main_elem.querySelectorAll( '.gap' ) ).map( function ( gap_elem, i ) {

            // blank input fields and shown keywords? => input fields should give no hint for the length of the searched word
            if ( my.blank && my.keywords ) return gap_elem.appendChild( self.ccm.helper.html( { tag: 'input', type: 'text', oninput: onInput, onchange: onChange } ) );

            // shorter access to keyword
            var keyword = keywords[ i ].word;

            // prepare ccm HTML data for input field
            var input = {
              tag: 'input',
              type: 'text',
              oninput: onInput,
              onchange: onChange,
              maxlength: keyword.length,
              size: keyword.length * 1.5  // works tolerably for words with a length up to 30
            };

            // no blank input fields? => set placeholder attribute
            if ( !my.blank ) {
              input.placeholder = '';
              for ( var j = 0; j < keyword.length; j++ )
                input.placeholder += Math.pow( 2, j ) & keywords[ i ].givens ? keyword.charAt( j ) : '_';
            }

            // render input field in the current gap
            gap_elem.appendChild( self.ccm.helper.html( input ) );

            /** onchange callback for input fields */
            function onChange() {

              var data = { gap: 1 + i, input: this.value };  // input field informations

              // has logger instance? => log change event
              if ( self.logger ) self.logger.log( 'change', data );

              // has individual change callback? => perform it
              if ( my.onchange ) my.onchange( self, data );

            }

            /** oninput callback for input fields */
            function onInput() {

              var data = { gap: 1 + i, input: this.value };  // input field informations

              // has logger instance? => log input event
              if ( self.logger ) self.logger.log( 'input', data );

              // has individual input callback? => perform it
              if ( my.oninput ) my.oninput( self, data );

            }

          } );

        }

        /** renders the finish button */
        function renderButton() {

          // set content of container for finish button
          self.ccm.helper.setContent( button_elem, self.ccm.helper.html( my.html_templates.button, {
            caption: my.button_caption,
            click:   onFinish
          } ) );

          // finish button is a input tag? => allow use of browser specific default caption
          var submit_elem = button_elem.querySelector( 'input[type=submit]' );
          if ( submit_elem && !my.button_caption ) submit_elem.removeAttribute( 'value' );

        }

        /** renders the timer */
        function renderTimer() {

          timer();  // start timer

          /** updates countdown timer */
          function timer() {

            // already finished? => remove timer
            if ( !main_elem.querySelector( '#timer' ) ) return;

            // (re)render timer value
            self.ccm.helper.setContent( timer_elem, self.ccm.helper.html( my.html_templates.timer, timer_value ) );

            // countdown
            if ( timer_value-- )
              self.ccm.helper.wait( 1000, timer );
            else if ( button_elem )
              onFinish();           // perform finish callback at timeout

          }

        }

        /** onclick callback for finish button */
        function onFinish( event ) {

          // prevent page reload
          if ( event ) event.preventDefault();

          time = new Date().getTime() - time;            // calculate result time
          button_elem.innerHTML = '';                    // remove button
          self.ccm.helper.removeElement( timer_elem  );  // remove timer container

          // has user instance? => login user
          if ( self.user ) self.user.login( proceed ); else proceed();

          function proceed() {

            // give visual feedback for correctness
            self.ccm.helper.makeIterable( main_elem.querySelectorAll( '.gap input' ) ).map( function ( gap, i ) {
              var correct = my.ignore_case ? gap.value.toLowerCase() === keywords[ i ].word.toLowerCase() : gap.value === keywords[ i ].word;
              gap.removeAttribute( 'placeholder' );
              gap.parentNode.className += correct ? ' correct' : ' wrong';

              // correct input? => give points
              if ( my.points_per_gap ) {
                results.max_points += my.points_per_gap;
                if ( correct ) results.points += my.points_per_gap;
              }

              // set detail informations for current gap result
              results.details.push( { input: gap.value, solution: keywords[ i ].word, correct: correct } );

            } );

            // finalize result data
            if ( !my.points_per_gap ) { delete results.points; delete results.max_points; }
            if ( self.user ) results.user = self.user.data().key;
            if (   my.time ) results.time_left = timer_value + 1;
            results.time = time;

            // has logger instance? => log finish event
            if ( self.logger ) self.logger.log( 'finish', results );

            // provide result data
            self.ccm.helper.onFinish( self, results );

          }

        }

      };

    }

  };

  var namespace = window.ccm && ccm.components[ component_name ]; if ( namespace ) { if ( namespace.ccm_version ) ccm_version = namespace.ccm_version; if ( namespace.ccm_url ) ccm_url = namespace.ccm_url; }
  if ( !window.ccm || !ccm[ ccm_version ] ) { var tag = document.createElement( 'script' ); document.head.appendChild( tag ); tag.onload = register; tag.src = ccm_url; } else register();
  function register() { ccm[ ccm_version ].component( component_obj ); }
}() );<commit_msg>minor changes<commit_after>/**
 * @overview ccm component for fill-in-the-blank texts
 * @author André Kless <andre.kless@web.de> 2017
 * @license The MIT License (MIT)
 */

( function () {

  var ccm_version = '8.0.0';
  var ccm_url     = '../../ccm-developer/ccm/ccm.js';

  var component_name = 'cloze';
  var component_obj  = {

    name: component_name,

    config: {

      text: 'Hello, [[(W)o(rl)d]]!',
      html_templates: {
        main: {
          id: 'main',
          inner: {
            tag: 'form',
            id: 'form',
            inner: [
              { id: 'keywords' },
              { id: 'text' },
              { id: 'button' },
              { id: 'timer' }
            ],
            onsubmit: '%%'
          }
        },
        keyword: {
          class: 'keyword',
          inner: '%%'
        },
        button: {
          tag: 'input',
          type: 'submit',
          value: '%caption%'
        },
        timer: {
          tag: 'span',
          inner: '%%'
        }
      },
      css_layout: [ 'ccm.load', '../cloze/layouts/default.css' ]

  //  blank: true,
  //  ignore_case: true,
  //  keywords: [ 'keyword1', 'keyword2', ... ],
  //  points_per_gap: 1,
  //  time: 60,
  //  button_caption: 'finish',
  //  user: [ 'ccm.instance', '../user/ccm.user.js' ],
  //  logger: [ 'ccm.instance', '../log/ccm.log.js', [ ccm.get, '../log/configs.json', 'greedy' ] ],
  //  onchange: function ( instance, data ) { console.log( data ); },
  //  oninput: function ( instance, data ) { console.log( data ); },
  //  onfinish: function ( instance, results ) { console.log( results ); }

    },

    Instance: function () {

      var self = this;
      var my;             // contains privatized instance members
      var keywords = [];  // information data for each keyword

      this.init = function ( callback ) {

        // fill-in-the-blank text is given via inner HTML? => use it with higher priority
        if ( self.node && self.node.innerHTML.trim() ) self.text = self.node.innerHTML;

        callback();
      };

      this.ready = function ( callback ) {

        // privatize all possible instance members
        my = self.ccm.helper.privatize( self );

        var regex_keyword = /\[\[.+?\]\]/g;   // regular expression for finding all gaps/keywords in the text
        var regex_given = /\(.+?\)/g;         // regular expression for finding all given characters of a keyword

        // iterate all keywords in the text to determine the information data for each keyword
        ( my.text.match( regex_keyword ) || [] ).map( function ( keyword ) {

          // remove distinguishing characteristic '[[' and ']]'
          keyword = keyword.substr( 2, keyword.length - 4 );

          // replace all given characters of a keywords with '*'
          var keyw__d = keyword.replace( '*', '#' ).replace( regex_given, function ( given ) {
            var length = given.length - 2;
            given = '';
            for ( var i = 0; i < length; i++ ) given += '*';
            return given;
          } );

          // determine given characters and hold this information in a single number (disadvantage: possible positions
          var givens = 0;                                                      // for given letters in a word are 0-31
          for ( var i = 0; i < keyw__d.length; i++ )                           // because of data type limitations)
            if ( keyw__d.charAt( i ) === '*' ) givens += Math.pow( 2, i );

          // add keyword information data for current keyword
          keywords.push( {
            word: keyword.replace( regex_given, function ( given ) { return given.substr( 1, given.length - 2 ); } ),
            givens: givens
          } );

        } );

        // replace gaps/keywords with empty span elements
        my.text = my.text.replace( regex_keyword, '' );

        callback();
      };

      this.start = function ( callback ) {

        // initial result data
        var results = { points: 0, max_points: 0, details: [] };

        // prepare main HTML structure
        var main_elem = self.ccm.helper.html( my.html_templates.main, onFinish );

        var   text_elem  = main_elem.querySelector( '#text'   );  // container for text with containing gaps
        var button_elem  = main_elem.querySelector( '#button' );  // container for finish button
        var  timer_elem  = main_elem.querySelector( '#timer'  );  // container for timer
        var  timer_value = my.time;                               // timer value

        // add content for inner containers
        renderKeywords();
        renderText();
        renderButton();
        if ( my.time ) renderTimer(); else self.ccm.helper.removeElement( timer_elem );

        // remember start time
        var time = new Date().getTime();

        // set content of own website area
        self.ccm.helper.setContent( self.element, self.ccm.helper.protect( main_elem ) );

        // has logger instance? => log start event
        if ( self.logger ) self.logger.log( 'start', my );

        if ( callback ) callback();

        /**
         * @summary renders given keywords for text gaps
         * @description
         * Keywords could be given (individual) via instance configuration (my.keywords is string array)
         * or (automatic generated) via private variable 'keywords' (my.keywords is boolean true).
         */
        function renderKeywords() {

          var keywords_elem = main_elem.querySelector( '#keywords' );  // container for keywords
          var entries = [];                                            // inner container for each keyword

          // has given keywords? => create inner container for each keyword
          if ( my.keywords )
            ( Array.isArray( my.keywords ) ? my.keywords : keywords ).map( addKeyword );
          else
            return keywords_elem.parentNode.removeChild( keywords_elem );  // no given keywords? => remove container for keywords and abort

          // generated keyword list? => sort keywords lexicographical (keyword order gives no hint about correct solution)
          if ( my.keywords === true ) entries.sort( function ( a, b ) { return a.innerHTML.localeCompare( b.innerHTML ) } );

          // add each inner keyword container to container for keywords
          entries.map( function ( entry ) { keywords_elem.appendChild( entry ); } );

          /** adds a inner container for a keyword */
          function addKeyword( keyword ) {
            entries.push( self.ccm.helper.html( my.html_templates.keyword, Array.isArray( my.keywords ) ? keyword : keyword.word ) );
          }

        }

        /** renders the text with containing gaps */
        function renderText() {

          // render text with containing gaps
          text_elem.innerHTML = my.text;

          // render input field in each gap
          self.ccm.helper.makeIterable( main_elem.querySelectorAll( '.gap' ) ).map( function ( gap_elem, i ) {

            // blank input fields and shown keywords? => input fields should give no hint for the length of the searched word
            if ( my.blank && my.keywords ) return gap_elem.appendChild( self.ccm.helper.html( { tag: 'input', type: 'text', oninput: onInput, onchange: onChange } ) );

            // shorter access to keyword
            var keyword = keywords[ i ].word;

            // prepare ccm HTML data for input field
            var input = {
              tag: 'input',
              type: 'text',
              oninput: onInput,
              onchange: onChange,
              maxlength: keyword.length,
              size: keyword.length * 1.5  // works tolerably for words with a length up to 30
            };

            // no blank input fields? => set placeholder attribute
            if ( !my.blank ) {
              input.placeholder = '';
              for ( var j = 0; j < keyword.length; j++ )
                input.placeholder += Math.pow( 2, j ) & keywords[ i ].givens ? keyword.charAt( j ) : '_';
            }

            // render input field in the current gap
            gap_elem.appendChild( self.ccm.helper.html( input ) );

            /** onchange callback for input fields */
            function onChange() {

              var data = { gap: 1 + i, input: this.value };  // input field informations

              // has logger instance? => log change event
              if ( self.logger ) self.logger.log( 'change', data );

              // has individual change callback? => perform it
              if ( my.onchange ) my.onchange( self, data );

            }

            /** oninput callback for input fields */
            function onInput() {

              var data = { gap: 1 + i, input: this.value };  // input field informations

              // has logger instance? => log input event
              if ( self.logger ) self.logger.log( 'input', data );

              // has individual input callback? => perform it
              if ( my.oninput ) my.oninput( self, data );

            }

          } );

        }

        /** renders the finish button */
        function renderButton() {

          // set content of container for finish button
          self.ccm.helper.setContent( button_elem, self.ccm.helper.html( my.html_templates.button, {
            caption: my.button_caption,
            click:   onFinish
          } ) );

          // finish button is a input tag? => allow use of browser specific default caption
          var submit_elem = button_elem.querySelector( 'input[type=submit]' );
          if ( submit_elem && !my.button_caption ) submit_elem.removeAttribute( 'value' );

        }

        /** renders the timer */
        function renderTimer() {

          timer();  // start timer

          /** updates countdown timer */
          function timer() {

            // already finished? => remove timer
            if ( !main_elem.querySelector( '#timer' ) ) return;

            // (re)render timer value
            self.ccm.helper.setContent( timer_elem, self.ccm.helper.html( my.html_templates.timer, timer_value ) );

            // countdown
            if ( timer_value-- )
              self.ccm.helper.wait( 1000, timer );
            else if ( button_elem )
              onFinish();           // perform finish callback at timeout

          }

        }

        /** onclick callback for finish button */
        function onFinish( event ) {

          // prevent page reload
          if ( event ) event.preventDefault();

          time = new Date().getTime() - time;            // calculate result time
          button_elem.innerHTML = '';                    // remove button
          self.ccm.helper.removeElement( timer_elem  );  // remove timer container

          // has user instance? => login user
          if ( self.user ) self.user.login( proceed ); else proceed();

          function proceed() {

            // give visual feedback for correctness
            self.ccm.helper.makeIterable( main_elem.querySelectorAll( '.gap input' ) ).map( function ( gap, i ) {
              var correct = my.ignore_case ? gap.value.toLowerCase() === keywords[ i ].word.toLowerCase() : gap.value === keywords[ i ].word;
              gap.removeAttribute( 'placeholder' );
              gap.parentNode.className += correct ? ' correct' : ' wrong';

              // correct input? => give points
              if ( my.points_per_gap ) {
                results.max_points += my.points_per_gap;
                if ( correct ) results.points += my.points_per_gap;
              }

              // set detail informations for current gap result
              results.details.push( { input: gap.value, solution: keywords[ i ].word, correct: correct } );

            } );

            // finalize result data
            if ( !my.points_per_gap ) { delete results.points; delete results.max_points; }
            if ( self.user ) results.user = self.user.data().key;
            if (   my.time ) results.time_left = timer_value + 1;
            results.time = time;

            // has logger instance? => log finish event
            if ( self.logger ) self.logger.log( 'finish', results );

            // provide result data
            self.ccm.helper.onFinish( self, results );

          }

        }

      };

    }

  };

  var namespace = window.ccm && ccm.components[ component_name ]; if ( namespace ) { if ( namespace.ccm_version ) ccm_version = namespace.ccm_version; if ( namespace.ccm_url ) ccm_url = namespace.ccm_url; }
  if ( !window.ccm || !ccm[ ccm_version ] ) { var tag = document.createElement( 'script' ); document.head.appendChild( tag ); tag.onload = register; tag.src = ccm_url; } else register();
  function register() { ccm[ ccm_version ].component( component_obj ); }
}() );<|endoftext|>


<commit_before>/**
 * @author Pedro Sanders
 * @since v1
 */
const getConfig = require('@routr/core/config_util')
const isEmpty = require('@routr/utils/obj_util')

const String = Java.type('java.lang.String')
const SubnetUtils = Java.type('org.apache.commons.net.util.SubnetUtils')

const cidrPattern = /^([0-9]{1,3}\.){3}[0-9]{1,3}(\/([0-9]|[1-2][0-9]|3[0-2]))?$/
const ipPattern = /^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/

class IPUtil {

    constructor(config) {
        if (!isEmpty(config)) {
            this.config = config
        } else {
            this.config = getConfig()
        }
        this.localnets = this.config.spec.localnets
    }

    isLocalnet(address) {
        const localnets = this.localnets
        if (isEmpty(localnets)) throw "No localnets found"

        for (const x in localnets) {
            const subnetUtils = IPUtil.getSubnetUtils(localnets[x])
            if (subnetUtils.getInfo().isInRange(address)) return true
        }
        return false
    }

    static getSubnetUtils(net) {
        let subnetUtils

        if (IPUtil.isIp(net)) {
            subnetUtils = new SubnetUtils(`${net}/31`)
        } else if (IPUtil.isCidr(net)) {
            subnetUtils = new SubnetUtils(net)
        } else if (IPUtil.isIpAndMask(net)) {
            const s = net.split('/')
            subnetUtils = new SubnetUtils(s[0], s[1])
        } else {
            throw new java.lang.RuntimeException('Invalid rule notation. Must be IPv4 value, CIDR, or Ip/Mask notation.')
        }

        subnetUtils.setInclusiveHostCount(true)
        return subnetUtils
    }

    static isIp(v) {
        return ipPattern.test(v)
    }

    static isCidr(v) {
        return cidrPattern.test(v) && v.includes('/')
    }

    static isIpAndMask(v) {
        const s = v.split('/')
        if (s.length !== 2) return false
        if (IPUtil.isIp(s[0]) && IPUtil.isIp(s[1])) return true
        return false
    }
}

module.exports = IPUtil
<commit_msg>Cleanup<commit_after>/**
 * @author Pedro Sanders
 * @since v1
 */
const getConfig = require('@routr/core/config_util')
const isEmpty = require('@routr/utils/obj_util')

const SubnetUtils = Java.type('org.apache.commons.net.util.SubnetUtils')

const cidrPattern = /^([0-9]{1,3}\.){3}[0-9]{1,3}(\/([0-9]|[1-2][0-9]|3[0-2]))?$/
const ipPattern = /^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/

class IPUtil {

    constructor(config) {
        if (!isEmpty(config)) {
            this.config = config
        } else {
            this.config = getConfig()
        }
        this.localnets = this.config.spec.localnets
    }

    isLocalnet(address) {
        const localnets = this.localnets
        if (isEmpty(localnets)) throw "No localnets found"

        for (const x in localnets) {
            const subnetUtils = IPUtil.getSubnetUtils(localnets[x])
            if (subnetUtils.getInfo().isInRange(address)) return true
        }
        return false
    }

    static getSubnetUtils(net) {
        let subnetUtils

        if (IPUtil.isIp(net)) {
            subnetUtils = new SubnetUtils(`${net}/31`)
        } else if (IPUtil.isCidr(net)) {
            subnetUtils = new SubnetUtils(net)
        } else if (IPUtil.isIpAndMask(net)) {
            const s = net.split('/')
            subnetUtils = new SubnetUtils(s[0], s[1])
        } else {
            throw new java.lang.RuntimeException('Invalid rule notation. Must be IPv4 value, CIDR, or Ip/Mask notation.')
        }

        subnetUtils.setInclusiveHostCount(true)
        return subnetUtils
    }

    static isIp(v) {
        return ipPattern.test(v)
    }

    static isCidr(v) {
        return cidrPattern.test(v) && v.includes('/')
    }

    static isIpAndMask(v) {
        const s = v.split('/')
        if (s.length !== 2) return false
        if (IPUtil.isIp(s[0]) && IPUtil.isIp(s[1])) return true
        return false
    }
}

module.exports = IPUtil
<|endoftext|>


<commit_before>/*!
 * Superjoin module loader
 * Copyright by Andi Heinkelein <andi.oxidant@noname-media.com>
 *
 * @module Superjoin
 */
(function(window) {
    'use strict';

    /**
     * Load a module
     *
     * Loads a local or npm module. If the module name starts with an . a local module will be loaded.
     *
     * @param  {string} module Loads a module
     * @return {any}      Returns the loaded module.
     */
    var require = function(file) {
        console.log('REQUIRE', file, this);
        if (require.alias && require.alias[file]) {
            file = require.alias[file];
        }

        var module = {
            exports: {},
            file: file
        };

        file = require.resolve(file, this ? this.file : null);

        var requireFunc = require.bind({
            file: file
        });

        if (window.require.cache[file]) {
            console.log(' ... get from cache', file);

            if (window.require.cache[file].obj) {
                return window.require.cache[file].obj;
            }

            window.require.cache[file].fn(module, module.exports, requireFunc);
            window.require.cache[file].obj = module.exports;
            return window.require.cache[file].obj;
        }

        if (!window.require.autoload || (window.require.autoload && file.charAt(0) !== '.')) {
            throw new Error('Module ' + file + ' not found!');
        }

        var remoteFile = location.protocol
            .concat('//', location.host)
            .concat(file.substr(1));

        console.log(' ... load from remote', remoteFile);
        var xhr = new XMLHttpRequest();
        xhr.open('GET', remoteFile, false);
        xhr.send();
        if (xhr.status !== 200) {
            throw new Error('Could not load module "' + file + '"! Response error: ' +
                xhr.status + ' ' + xhr.statusText);
        }
        var source = xhr.responseText;

        var fn;
        try {
            //jshint evil:true
            fn = eval('(function(module, exports, require) {\n' +
                (/\.json$/.test(file) ? 'module.exports = ' : '') +
                source + '\n})\n\n//# sourceURL=' + file);
        }
        catch (err) {
            throw new Error(err + ' in ' + file);
        }

        fn(module, module.exports, require.bind(requireFunc));
        window.require.cache[file] = {
            fn: fn,
            calls: 1,
            obj: module.exports,
            loaded: true
        };

        return window.require.cache[file].obj;
    };

    require.resolve = function(path, parent) {
        var resolved = [];
        if (path.charAt(0) === '.') {
            var newPath = parent || '.';
            newPath = newPath.split('/');
            newPath.pop();
            newPath = newPath.concat(path.split('/'));

            newPath.forEach(function(p) {
                if (p === '..') {
                    resolved.pop();
                    return;
                }
                else if (p === '.' || p === '') {
                    return;
                }

                resolved.push(p);
            });

            if (!parent ||parent.charAt(0) === '.') {
                resolved.unshift('.');
            }
        }
        else {
            console.log(' ... resolve path to', path);
            return path;
        }

        resolved = resolved.join('/');
        if (!/\.js(on)?$/.test(resolved)) {
            resolved += '.js';
        }

        console.log(' ... resolve path to', resolved);
        return resolved;
    };

    require.register = function(alias, path, fn) {
        if (arguments.length === 2) {
            fn = path;
            path = alias;
            alias= null;
        }

        require.cache[path] = {fn: fn, calls: 0};
        if (alias) {
            require.alias[alias] = path;
        }
    };

    require.cache = {};
    require.alias = {};

    window.require = require;

})(window);

<commit_msg>Remove logs<commit_after>/*!
 * Superjoin module loader
 * Copyright by Andi Heinkelein <andi.oxidant@noname-media.com>
 *
 * @module Superjoin
 */
(function(window) {
    'use strict';

    /**
     * Load a module
     *
     * Loads a local or npm module. If the module name starts with an . a local module will be loaded.
     *
     * @param  {string} module Loads a module
     * @return {any}      Returns the loaded module.
     */
    var require = function(file) {
        // console.log('REQUIRE', file, this);
        if (require.alias && require.alias[file]) {
            file = require.alias[file];
        }

        var module = {
            exports: {},
            file: file
        };

        file = require.resolve(file, this ? this.file : null);

        var requireFunc = require.bind({
            file: file
        });

        if (window.require.cache[file]) {
            // console.log(' ... get from cache', file);

            if (window.require.cache[file].obj) {
                return window.require.cache[file].obj;
            }

            window.require.cache[file].fn(module, module.exports, requireFunc);
            window.require.cache[file].obj = module.exports;
            return window.require.cache[file].obj;
        }

        if (!window.require.autoload || (window.require.autoload && file.charAt(0) !== '.')) {
            throw new Error('Module ' + file + ' not found!');
        }

        var remoteFile = location.protocol
            .concat('//', location.host)
            .concat(file.substr(1));

        // console.log(' ... load from remote', remoteFile);
        var xhr = new XMLHttpRequest();
        xhr.open('GET', remoteFile, false);
        xhr.send();
        if (xhr.status !== 200) {
            throw new Error('Could not load module "' + file + '"! Response error: ' +
                xhr.status + ' ' + xhr.statusText);
        }
        var source = xhr.responseText;

        var fn;
        try {
            //jshint evil:true
            fn = eval('(function(module, exports, require) {\n' +
                (/\.json$/.test(file) ? 'module.exports = ' : '') +
                source + '\n})\n\n//# sourceURL=' + file);
        }
        catch (err) {
            throw new Error(err + ' in ' + file);
        }

        fn(module, module.exports, require.bind(requireFunc));
        window.require.cache[file] = {
            fn: fn,
            calls: 1,
            obj: module.exports,
            loaded: true
        };

        return window.require.cache[file].obj;
    };

    require.resolve = function(path, parent) {
        var resolved = [];
        if (path.charAt(0) === '.') {
            var newPath = parent || '.';
            newPath = newPath.split('/');
            newPath.pop();
            newPath = newPath.concat(path.split('/'));

            newPath.forEach(function(p) {
                if (p === '..') {
                    resolved.pop();
                    return;
                }
                else if (p === '.' || p === '') {
                    return;
                }

                resolved.push(p);
            });

            if (!parent ||parent.charAt(0) === '.') {
                resolved.unshift('.');
            }
        }
        else {
            // console.log(' ... resolve path to', path);
            return path;
        }

        resolved = resolved.join('/');
        if (!/\.js(on)?$/.test(resolved)) {
            resolved += '.js';
        }

        // console.log(' ... resolve path to', resolved);
        return resolved;
    };

    require.register = function(alias, path, fn) {
        if (arguments.length === 2) {
            fn = path;
            path = alias;
            alias= null;
        }

        require.cache[path] = {fn: fn, calls: 0};
        if (alias) {
            require.alias[alias] = path;
        }
    };

    require.cache = {};
    require.alias = {};

    window.require = require;

})(window);

<|endoftext|>


<commit_before>/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/
'use strict';
Object.defineProperty(exports, "__esModule", { value: true });
const documentdb_1 = require("documentdb");
function createDefaultConfig(quality) {
    return {
        id: quality,
        frozen: false
    };
}
function getConfig(quality) {
    const client = new documentdb_1.DocumentClient(process.env['AZURE_DOCUMENTDB_ENDPOINT'], { masterKey: process.env['AZURE_DOCUMENTDB_MASTERKEY'] });
    const collection = 'dbs/builds/colls/config';
    const query = {
        query: `SELECT TOP 1 * FROM c WHERE c.id = @quality`,
        parameters: [
            { name: '@quality', value: quality }
        ]
    };
    return new Promise((c, e) => {
        client.queryDocuments(collection, query).toArray((err, results) => {
            if (err && err.code !== 409) {
                return e(err);
            }
            c(!results || results.length === 0 ? createDefaultConfig(quality) : results[0]);
        });
    });
}
getConfig(process.argv[2])
    .then(config => {
    console.log(config.frozen);
    process.exit(0);
})
    .catch(err => {
    console.error(err);
    process.exit(1);
});
<commit_msg>Resolve another conflict<commit_after><|endoftext|>


<commit_before>var url = require('url');
var nw = require('nw.gui');

var win = nw.Window.get();
var nativeMenuBar = new nw.Menu({ type: "menubar" });

if (nativeMenuBar.createMacBuiltin) {
  nativeMenuBar.createMacBuiltin("whatsApp Desktop");
}

win.menu = nativeMenuBar;

window.onload = function() {
  var view = document.getElementById('wv1');

  //this events are here to repaint the frame :bug from react version used by whatsapp.web
  win.on('closed', function(view) {
    console.log('closed');
  });
  win.on('loaded', function(view) {
    console.log('loaded');
  });
  win.on('  document-end', function(view) {
    console.log('document-end');
  });
  win.on('loading', function(view){
    console.log('loading');
  });
  win.on('document-start', function(view){
    console.log('document-start');
  })

};

<commit_msg>function windows close<commit_after>var url = require('url');
var nw = require('nw.gui');

var win = nw.Window.get();
var nativeMenuBar = new nw.Menu({ type: "menubar" });

var platform = process.platform;
platform = /^win/.test(platform) ? 'win32'
         : /^darwin/.test(platform) ? 'osx64'
         : 'linux' + (process.arch == 'ia32' ? '32' : '64');

var isOSX = platform === 'osx64';
var isWindows = platform === 'win32';
var isLinux = platform.indexOf('linux') === 0;

if (nativeMenuBar.createMacBuiltin) {
  nativeMenuBar.createMacBuiltin("whatsApp Desktop");
}

win.menu = nativeMenuBar;

window.onload = function() {
  var view = document.getElementById('wv1');

  //this events are here to repaint the frame :bug from react version used by whatsapp.web
  win.on('closed', function(view) {
    console.log('closed');
  });
  win.on('loaded', function(view) {
    console.log('loaded');
  });
  win.on('  document-end', function(view) {
    console.log('document-end');
  });
  win.on('loading', function(view){
    console.log('loading');
  });
  win.on('document-start', function(view){
    console.log('document-start');
  })

};

// Don't quit the app when the window is closed
win.on('close', function(quit) {
  if (quit) {
    win.close(true);
  } else {
    // On Linux, just minimize the window
    if (isLinux) {
      win.minimize();
    } else {
      win.hide();
    }
  }
});

<|endoftext|>


<commit_before>class Retinize {
  constructor(element) {
    // Return unless we have an element
    if (!element || element === '') {
      return;
    }

    let elements = [];
    if (typeof element === 'string') {
      elements = document.querySelectorAll('div');
    } else {
      elements.push(element);
    }

    [].forEach.call(elements, (node) => {
      Retinize.convertToCanvas(node);
    });
  }

  static convertToCanvas(element) {
    const canvas = document.createElement('canvas');
    canvas.id = element.id;
    canvas.title = element.title;
    canvas.alt = element.alt;
    canvas.className = element.className;

    canvas.width = element.width * window.devicePixelRatio;
    canvas.height = element.height * window.devicePixelRatio;
    canvas.style.width = `${element.width}px`;
    canvas.style.height = `${element.height}px`;

    const context = canvas.getContext('2d');
    context.imageSmoothingEnabled = false;
    context.mozImageSmoothingEnabled = false;
    context.webkitImageSmoothingEnabled = false;
    context.scale(window.devicePixelRatio, window.devicePixelRatio);
    context.drawImage(element, 0, 0);

    element.parentNode.replaceChild(canvas, element);
  }
}
<commit_msg>Fix selector issue.<commit_after>class Retinize {
  constructor(element) {
    // Return unless we have an element
    if (!element || element === '') {
      return;
    }

    let elements = [];
    if (typeof element === 'string') {
      elements = document.querySelectorAll(element);
    } else {
      elements.push(element);
    }

    [].forEach.call(elements, (node) => {
      Retinize.convertToCanvas(node);
    });
  }

  static convertToCanvas(element) {
    const canvas = document.createElement('canvas');
    canvas.id = element.id;
    canvas.title = element.title;
    canvas.alt = element.alt;
    canvas.className = element.className;

    canvas.width = element.width * window.devicePixelRatio;
    canvas.height = element.height * window.devicePixelRatio;
    canvas.style.width = `${element.width}px`;
    canvas.style.height = `${element.height}px`;

    const context = canvas.getContext('2d');
    context.imageSmoothingEnabled = false;
    context.mozImageSmoothingEnabled = false;
    context.webkitImageSmoothingEnabled = false;
    context.scale(window.devicePixelRatio, window.devicePixelRatio);
    context.drawImage(element, 0, 0);

    element.parentNode.replaceChild(canvas, element);
  }
}
<|endoftext|>


<commit_before>import path from 'path';
import { app, BrowserWindow, ipcMain, Menu } from 'electron';
import environment from '../../common/environment';
import ipcApi from '../ipc';
import { runtimeFolderPath } from '../config';
import RendererErrorHandler from '../utils/rendererErrorHandler';

const rendererErrorHandler = new RendererErrorHandler();

export const createMainWindow = (isInSafeMode) => {
  const windowOptions = {
    show: false,
    width: 1150,
    height: 870,
    webPreferences: {
      webviewTag: false,
    }
  };

  if (process.platform === 'linux') {
    windowOptions.icon = path.join(process.env.DAEDALUS_INSTALL_DIRECTORY, 'icon.png');
  }

  // Construct new BrowserWindow
  const window = new BrowserWindow(windowOptions);

  rendererErrorHandler.setup(window, createMainWindow);

  window.setMinimumSize(900, 600);

  // Initialize our ipc api methods that can be called by the render processes
  ipcApi({ window });

  // Provide render process with an api to resize the main window
  ipcMain.on('resize-window', (event, { width, height, animate }) => {
    if (event.sender !== window.webContents) return;
    window.setSize(width, height, animate);
  });

  if (environment.isDev()) {
    window.webContents.openDevTools();
    // Focus the main window after dev tools opened
    window.webContents.on('devtools-opened', () => {
      window.focus();
      setImmediate(() => {
        window.focus();
      });
    });
  }

  window.loadURL(`file://${__dirname}/../renderer/index.html`);
  window.on('page-title-updated', event => { event.preventDefault(); });

  let title = environment.getBuildLabel();
  if (isInSafeMode) title += ' [GPU safe mode]';
  window.setTitle(title);

  window.webContents.on('context-menu', (e, props) => {
    const contextMenuOptions = [
      { label: 'Copy', accelerator: 'CmdOrCtrl+C', role: 'copy' },
      { label: 'Paste', accelerator: 'CmdOrCtrl+V', role: 'paste' },
    ];

    if (environment.isDev() || environment.isTest()) {
      const { x, y } = props;
      contextMenuOptions.push({
        label: 'Inspect element',
        click() {
          window.inspectElement(x, y);
        }
      });
    }

    Menu.buildFromTemplate(contextMenuOptions).popup(window);
  });

  window.webContents.on('did-finish-load', () => {
    if (environment.isTest()) {
      window.showInactive(); // show without focusing the window
    } else {
      window.show(); // show also focuses the window
    }
  });

  window.on('closed', () => {
    app.quit();
  });

  window.webContents.on('did-fail-load', (err) => {
    rendererErrorHandler.onError('did-fail-load', err);
  });

  window.webContents.on('crashed', (err) => {
    rendererErrorHandler.onError('crashed', err);
  });

  return window;
};
<commit_msg>Remove unused runtimeFolderPath import<commit_after>import path from 'path';
import { app, BrowserWindow, ipcMain, Menu } from 'electron';
import environment from '../../common/environment';
import ipcApi from '../ipc';
import RendererErrorHandler from '../utils/rendererErrorHandler';

const rendererErrorHandler = new RendererErrorHandler();

export const createMainWindow = (isInSafeMode) => {
  const windowOptions = {
    show: false,
    width: 1150,
    height: 870,
    webPreferences: {
      webviewTag: false,
    }
  };

  if (process.platform === 'linux') {
    windowOptions.icon = path.join(process.env.DAEDALUS_INSTALL_DIRECTORY, 'icon.png');
  }

  // Construct new BrowserWindow
  const window = new BrowserWindow(windowOptions);

  rendererErrorHandler.setup(window, createMainWindow);

  window.setMinimumSize(900, 600);

  // Initialize our ipc api methods that can be called by the render processes
  ipcApi({ window });

  // Provide render process with an api to resize the main window
  ipcMain.on('resize-window', (event, { width, height, animate }) => {
    if (event.sender !== window.webContents) return;
    window.setSize(width, height, animate);
  });

  if (environment.isDev()) {
    window.webContents.openDevTools();
    // Focus the main window after dev tools opened
    window.webContents.on('devtools-opened', () => {
      window.focus();
      setImmediate(() => {
        window.focus();
      });
    });
  }

  window.loadURL(`file://${__dirname}/../renderer/index.html`);
  window.on('page-title-updated', event => { event.preventDefault(); });

  let title = environment.getBuildLabel();
  if (isInSafeMode) title += ' [GPU safe mode]';
  window.setTitle(title);

  window.webContents.on('context-menu', (e, props) => {
    const contextMenuOptions = [
      { label: 'Copy', accelerator: 'CmdOrCtrl+C', role: 'copy' },
      { label: 'Paste', accelerator: 'CmdOrCtrl+V', role: 'paste' },
    ];

    if (environment.isDev() || environment.isTest()) {
      const { x, y } = props;
      contextMenuOptions.push({
        label: 'Inspect element',
        click() {
          window.inspectElement(x, y);
        }
      });
    }

    Menu.buildFromTemplate(contextMenuOptions).popup(window);
  });

  window.webContents.on('did-finish-load', () => {
    if (environment.isTest()) {
      window.showInactive(); // show without focusing the window
    } else {
      window.show(); // show also focuses the window
    }
  });

  window.on('closed', () => {
    app.quit();
  });

  window.webContents.on('did-fail-load', (err) => {
    rendererErrorHandler.onError('did-fail-load', err);
  });

  window.webContents.on('crashed', (err) => {
    rendererErrorHandler.onError('crashed', err);
  });

  return window;
};
<|endoftext|>


<commit_before>/*
	JsonML_DOM.js

	Created: 2007-02-15-2235

	Released under an open-source license:
	http://jsonml.org/License.htm
*/

if ("undefined" === typeof window.JsonML) {
	window.JsonML = {};
}
/*JsonML*/ JsonML.parseDOM = function(/*DOM*/ elem) {
	if (!elem) {
		return null;
	}

	var i;
	switch (elem.nodeType) {
		case 1: // element
			var jml = [elem.tagName];
			var a = elem.attributes;
			var att = {};
			var hasAttrib = false;
			for (i=0; i<a.length; i++) {
				if (a[i].specified) {
					if (a[i].name === "style") {
						att["style"] = elem.style.cssText ? elem.style.cssText : a[i].value;
					} else if ("string" === typeof a[i].value) {
						att[a[i].name] = a[i].value;
					}
					hasAttrib = true;
				}
			}
			if (hasAttrib) {
				jml.push(att);
			}
			if (elem.hasChildNodes()) {
				for (i=0; i<elem.childNodes.length; i++) {
					var c = elem.childNodes[i];
					c = JsonML.parseDOM(c);
					if (c) {
						jml.push(c);
					}
				}
			}
			return jml;
		case 3: // text node
			return elem.nodeValue;
		default: // comments, etc.
			return null;
	}
};<commit_msg>- adding document fragment support<commit_after>/*
	JsonML_DOM.js

	Created: 2007-02-15-2235
	Modified: 2008-08-31-1813

	Released under an open-source license:
	http://jsonml.org/License.htm
*/

if ("undefined" === typeof window.JsonML) {
	window.JsonML = {};
}
/*JsonML*/ JsonML.parseDOM = function(/*DOM*/ elem) {
	if (!elem) {
		return null;
	}

	var i;
	switch (elem.nodeType) {
		case 1: // element
		case 11: // documentFragment
			var jml = [elem.tagName||""];
			var a = elem.attributes;
			var att = {};
			var hasAttrib = false;
			for (i=0; i<a.length; i++) {
				if (a[i].specified) {
					if (a[i].name === "style") {
						att["style"] = elem.style.cssText ? elem.style.cssText : a[i].value;
					} else if ("string" === typeof a[i].value) {
						att[a[i].name] = a[i].value;
					}
					hasAttrib = true;
				}
			}
			if (hasAttrib) {
				jml.push(att);
			}
			if (elem.hasChildNodes()) {
				for (i=0; i<elem.childNodes.length; i++) {
					var c = elem.childNodes[i];
					c = JsonML.parseDOM(c);
					if (c) {
						jml.push(c);
					}
				}
			}
			return jml;
		case 3: // text node
			return elem.nodeValue;
		default: // comments, etc.
			return null;
	}
};

/*JsonML*/ JsonML.parseHTML = function(/*string*/ html) {
	var elem = document.createElement("div");
	elem.innerHTML = html;
	var jml = JsonML.parseDOM(elem);
	if (jml.length === 2) {
		return jml[1];
	}

	// make wrapper a document fragment
	jml[0] = "";
	return jml;
};<|endoftext|>


<commit_before>import Ember from 'ember';
import layout from '../templates/components/sl-menu-item';

/**
 * @module
 * @augments ember/Component
 */
export default Ember.Component.extend({

    // -------------------------------------------------------------------------
    // Dependencies

    // -------------------------------------------------------------------------
    // Attributes

    /** @type {String[]} */
    classNameBindings: [
        'active',
        'hasSubItems:has-sub-menu',
        'item.selected:active'
    ],

    /** @type {String[]} */
    classNames: [
        'sl-menu-item'
    ],

    /** @type {Object} */
    layout,

    /** @type {String} */
    tagName: 'li',

    // -------------------------------------------------------------------------
    // Actions

    /** @type {Object} */
    actions: {

        /**
         * Click event handler
         *
         * @function actions:clickLink
         * @returns {undefined}
         */
        clickLink() {
            const action = this.get( 'item.action' );

            if ( action ) {
                this.sendAction( 'action', action, this.get( 'item.data' ) );
            }
        },

        /**
         * Handle sub menu item actions
         *
         * @function actions:handleAction
         * @param {String} actionName - The name of an action to pass
         * @param {*} data - Any data to also pass
         * @returns {undefined}
         */
        handleAction( actionName, data ) {
            this.sendAction( 'action', actionName, data );
        }
    },

    // -------------------------------------------------------------------------
    // Events

    /**
     * mouseEnter event handler
     *
     * @function
     * @returns {undefined}
     */
    mouseEnter() {
        this.set( 'active', true );
    },

    /**
     * mouseLeave event handler
     *
     * @function
     * @returns {undefined}
     */
    mouseLeave() {
        this.set( 'active', false );
    },

    // -------------------------------------------------------------------------
    // Properties

    /**
     * Whether the menu item is currently active
     *
     * @type {Boolean}
     */
    active: false,

    /**
     * The menu item object
     *
     * @type {?Object}
     */
    item: null,

    // -------------------------------------------------------------------------
    // Observers

    /**
     * Whether or not the `item` has a sub-array of items
     *
     * @function
     * @returns {Boolean} - True if the item has sub-items
     */
    hasSubItems: Ember.computed(
        'item',
        function() {
            return !!this.get( 'item.items' );
        }
    ),

    /**
     * Wrap the item's items array as an Ember.Array
     *
     * @function
     * @returns {?ember/Array}
     */
    subItems: Ember.computed(
        'item',
        function() {
            const subItems = this.get( 'item.items' );

            if ( subItems ) {
                return new Ember.A( subItems );
            }
        }
    )

    // -------------------------------------------------------------------------
    // Methods

});
<commit_msg>Add default return of null<commit_after>import Ember from 'ember';
import layout from '../templates/components/sl-menu-item';

/**
 * @module
 * @augments ember/Component
 */
export default Ember.Component.extend({

    // -------------------------------------------------------------------------
    // Dependencies

    // -------------------------------------------------------------------------
    // Attributes

    /** @type {String[]} */
    classNameBindings: [
        'active',
        'hasSubItems:has-sub-menu',
        'item.selected:active'
    ],

    /** @type {String[]} */
    classNames: [
        'sl-menu-item'
    ],

    /** @type {Object} */
    layout,

    /** @type {String} */
    tagName: 'li',

    // -------------------------------------------------------------------------
    // Actions

    /** @type {Object} */
    actions: {

        /**
         * Click event handler
         *
         * @function actions:clickLink
         * @returns {undefined}
         */
        clickLink() {
            const action = this.get( 'item.action' );

            if ( action ) {
                this.sendAction( 'action', action, this.get( 'item.data' ) );
            }
        },

        /**
         * Handle sub menu item actions
         *
         * @function actions:handleAction
         * @param {String} actionName - The name of an action to pass
         * @param {*} data - Any data to also pass
         * @returns {undefined}
         */
        handleAction( actionName, data ) {
            this.sendAction( 'action', actionName, data );
        }
    },

    // -------------------------------------------------------------------------
    // Events

    /**
     * mouseEnter event handler
     *
     * @function
     * @returns {undefined}
     */
    mouseEnter() {
        this.set( 'active', true );
    },

    /**
     * mouseLeave event handler
     *
     * @function
     * @returns {undefined}
     */
    mouseLeave() {
        this.set( 'active', false );
    },

    // -------------------------------------------------------------------------
    // Properties

    /**
     * Whether the menu item is currently active
     *
     * @type {Boolean}
     */
    active: false,

    /**
     * The menu item object
     *
     * @type {?Object}
     */
    item: null,

    // -------------------------------------------------------------------------
    // Observers

    /**
     * Whether or not the `item` has a sub-array of items
     *
     * @function
     * @returns {Boolean} - True if the item has sub-items
     */
    hasSubItems: Ember.computed(
        'item',
        function() {
            return !!this.get( 'item.items' );
        }
    ),

    /**
     * Wrap the item's items array as an Ember.Array
     *
     * @function
     * @returns {?ember/Array}
     */
    subItems: Ember.computed(
        'item',
        function() {
            const subItems = this.get( 'item.items' );
            let items = null;

            if ( subItems ) {
                items = new Ember.A( subItems );
            }

            return items;
        }
    )

    // -------------------------------------------------------------------------
    // Methods

});
<|endoftext|>


<commit_before>import assert from 'assert'

import { specificResourceToUri, uriToSpecificResource } from '../src'

// Examples from the spec:
// https://www.w3.org/TR/selectors-states/#json-examples-converted-to-fragment-identifiers
// One difference with the spec: we percent-encode the characters < > [ ] inside fragments.
const pairs = {

    'Example 2 <=> 16: Fragment selector': {
        uri: 'http://example.org/video1#selector(type=FragmentSelector,conformsTo=http://www.w3.org/TR/media-frags/,value=t%3D30%2C60)',
        obj: {
            "source": "http://example.org/video1",
            "selector": {
              "type": "FragmentSelector",
              "conformsTo": "http://www.w3.org/TR/media-frags/",
              "value": "t=30,60"
            }
        }
    },

    'Example 3 <=> 17: CSS selector': {
        uri: 'http://example.org/page1.html#selector(type=CssSelector,value=%23elemid%20%3E%20.elemclass%20+%20p)',
        obj: {
            "source": "http://example.org/page1.html",
            "selector": {
              "type": "CssSelector",
              "value": "#elemid > .elemclass + p"
            }
        }
    },

    'Example 4 <=> 18: XPath selector': {
        uri: 'http://example.org/page1.html#selector(type=XPathSelector,value=/html/body/p%5B2%5D/table/tr%5B2%5D/td%5B3%5D/span)',
        obj: {
            "source": "http://example.org/page1.html",
            "selector": {
              "type": "XPathSelector",
              "value": "/html/body/p[2]/table/tr[2]/td[3]/span"
            }
        }
    },

    'Example 5 <=> 19: TextQuote selector': {
        uri: 'http://example.org/page1#selector(type=TextQuoteSelector,exact=annotation,prefix=this%20is%20an%20,suffix=%20that%20has%20some)',
        obj: {
            "source": "http://example.org/page1",
            "selector": {
              "type": "TextQuoteSelector",
              "exact": "annotation",
              "prefix": "this is an ",
              "suffix": " that has some"
            }
        }
    },

    'Example 6 <=> 20: TextPosition selector': {
        uri: 'http://example.org/ebook1#selector(type=TextPositionSelector,start=412,end=795)',
        obj: {
            "source": "http://example.org/ebook1",
            "selector": {
              "type": "TextPositionSelector",
              "start": 412,
              "end": 795
            }
        }
    },

    'Example 7 <=> 21: Data position selector': {
        uri: 'http://example.org/diskimg1#selector(type=DataPositionSelector,start=4096,end=4104)',
        obj: {
            "source": "http://example.org/diskimg1",
            "selector": {
              "type": "DataPositionSelector",
              "start": 4096,
              "end": 4104
            }
        }
    },

    'Example 8 <=> 22: SVG selector; external SVG': {
        uri: 'http://example.org/map1#selector(type=SvgSelector,id=http://example.org/svg1)',
        obj: {
            "source": "http://example.org/map1",
            "selector": {
              "type": "SvgSelector",
              "id": "http://example.org/svg1"
            }
        }
    },

    'Example 9 <=> 23: SVG selector; embedded SVG': {
        uri: 'http://example.org/map1#selector(type=SvgSelector,value=%3Csvg:svg%3E%20...%20%3C/svg:svg%3E)',
        obj: {
            "source": "http://example.org/map1",
            "selector": {
              "type": "SvgSelector",
              "value": "<svg:svg> ... </svg:svg>"
            }
        }
    },

    'Example 10 <=> 24: Range selector': {
        uri: 'http://example.org/page1.html#selector(type=RangeSelector,startSelector=selector(type=XPathSelector,value=//table%5B1%5D/tr%5B1%5D/td%5B2%5D),endSelector=selector(type=XPathSelector,value=//table%5B1%5D/tr%5B1%5D/td%5B4%5D))',
        obj: {
            "source": "http://example.org/page1.html",
            "selector": {
              "type": "RangeSelector",
              "startSelector": {
                "type": "XPathSelector",
                "value": "//table[1]/tr[1]/td[2]"
              },
              "endSelector": {
                "type": "XPathSelector",
                "value": "//table[1]/tr[1]/td[4]"
              }
            }
        }
    },

    'Example 11 <=> 25: Selector refinement': {
        uri: 'http://example.org/page1#selector(type=FragmentSelector,value=para5,refinedBy=selector(type=TextQuoteSelector,exact=Selected%20Text,prefix=text%20before%20the%20,suffix=%20and%20text%20after%20it))',
        obj: {
            "source": "http://example.org/page1",
            "selector": {
              "type": "FragmentSelector",
              "value": "para5",
              "refinedBy": {
                "type": "TextQuoteSelector",
                "exact": "Selected Text",
                "prefix": "text before the ",
                "suffix": " and text after it"
              }
            }
        }
    },

    'Example 13 <=> 26: Time state': {
        uri: 'http://example.org/page1#state(type=TimeState,cached=http://archive.example.org/copy1,sourceDate=2015-07-20T13:30:00Z)',
        obj: {
            "source": "http://example.org/page1",
            "state": {
              "type": "TimeState",
              "cached": "http://archive.example.org/copy1",
              "sourceDate": "2015-07-20T13:30:00Z"
            }
        }
    },

    'Example 14 <=> 27: HTTP request state': {
        uri: 'http://example.org/resource1#state(type=HttpRequestState,value=Accept:%20application/pdf)',
        obj: {
            "source": "http://example.org/resource1",
            "state": {
              "type": "HttpRequestState",
              "value": "Accept: application/pdf"
            }
        }
    },

    'Example 15 <=> 28: Refinement of states': {
        uri: 'http://example.org/ebook1#state(type=TimeState,sourceDate=2016-02-01T12:05:23Z,refinedBy=state(type=HttpRequestState,value=Accept:%20application/epub+zip))',
        obj: {
            "source": "http://example.org/ebook1",
            "state": {
              "type": "TimeState",
              "sourceDate": "2016-02-01T12:05:23Z",
              "refinedBy": {
                "type": "HttpRequestState",
                "value": "Accept: application/epub+zip"
              }
            }
        }
    },

    'Example 29: Serializing IRI to URL (and vice versa)': {
        uri: 'http://jp.example.org/page1#selector(type=TextQuoteSelector,exact=%E3%83%9A%E3%83%B3%E3%82%92,prefix=%E7%A7%81%E3%81%AF%E3%80%81,suffix=%E6%8C%81%E3%81%A3%E3%81%A6%E3%81%84%E3%81%BE%E3%81%99)',
        obj: {
            selector: {
                type: 'TextQuoteSelector',
                exact: 'ペンを',
                prefix: '私は、',
                suffix: '持っています',
            },
            source: "http://jp.example.org/page1",
        }
    },

    'Fragment identifier without URI': {
        uri: '#selector(type=TextQuoteSelector,start=12,end=795)',
        obj: {
            "selector": {
                "type": "TextQuoteSelector",
                "start": 12,
                "end": 795
            },
            "source": ""
        }
    },

    'URI without fragment identifier': {
        uri: 'https://example.org',
        obj: {
            "source": "https://example.org"
        }
    },
}

const specialCasesToStringify = {
    'Value with parentheses (to be percent-encoded)': {
        uri: '#selector(type=TextQuoteSelector,exact=example%20%28with%20parentheses%29)',
        obj: {
            selector: {
                type: 'TextQuoteSelector',
                exact: 'example (with parentheses)',
            },
        },
    },
}

const specialCasesToParse = {
    'One closing parenthesis inside a value': {
        uri: '#selector(type=TextQuoteSelector,exact=(not)%20a%20problem)',
        obj: {
            source: '',
            selector: {
                type: 'TextQuoteSelector',
                exact: '(not) a problem',
            },
        },
    },
}

const specialCasesToParseThatFail = {
    'Two closing parentheses inside a value': {
        uri: '#selector(type=TextQuoteSelector,exact=Hey))%20this%20breaks)',
        obj: {
            source: '',
            selector: {
                type: 'TextQuoteSelector',
                exact: 'Hey)) this breaks',
            },
        },
    },

    'Two closing parentheses: one of value, one of selector': {
        uri: '#selector(type=TextQuoteSelector,exact=example%20(that%20fails))',
        obj: {
            source: '',
            selector: {
                type: 'TextQuoteSelector',
                exact: 'example (that fails)',
            },
        },
    },

    'Three closing parentheses: one of the value, two of nested selectors': {
        uri: `
            #selector(
                type=RangeSelector,
                startSelector=selector(type=TextQuoteSelector,exact=(but),
                endSelector=selector(type=TextQuoteSelector,exact=crazy))
            )
            `.replace(/\s/g, ''),
        obj: {
            source: '',
            selector: {
                type: 'RangeSelector',
                startSelector: {
                    type: 'TextQuoteSelector',
                    exact: '(but',
                },
                endSelector: {
                    type: 'TextQuoteSelector',
                    exact: 'crazy)',
                },
            },
        },
    },
};

describe('specificResourceToUri', () => {
    const examples = Object.assign({} , pairs, specialCasesToStringify)
    for (const [name, example] of Object.entries(examples)) {
        it(`should properly convert: '${name}'`, () => {
            let uri = specificResourceToUri(example.obj)
            assert.equal(uri, example.uri)
        })
    }
})

describe('uriToSpecificResource', () => {
    for (let name in pairs) {
        it(`should properly convert: '${name}'`, () => {
            let obj = uriToSpecificResource(pairs[name].uri)
            assert.deepEqual(obj, pairs[name].obj)
        })
    }

    it('should cleanly handle other types of fragment identifiers', () => {
        const obj = uriToSpecificResource('https://example.com/page#section4')
        const expected = {
            source: 'https://example.com/page',
            selector: {
                type: 'FragmentSelector',
                value: 'section4',
            }
        }
        assert.deepEqual(obj, expected)
    })

    for (const [name, example] of Object.entries(specialCasesToParse)) {
        it(`should parse special case: '${name}'`, () => {
            let obj = uriToSpecificResource(example.uri)
            assert.deepEqual(obj, example.obj)
        })
    }

    // FIXME These tests are known to fail. Seems impossible to parse
    // them with PEG.js. See <https://github.com/w3c/web-annotation/issues/443>
    for (const [name, example] of Object.entries(specialCasesToParseThatFail)) {
        it.skip(`should parse special case: '${name}'`, () => {
            let obj = uriToSpecificResource(example.uri)
            assert.deepEqual(obj, example.obj)
        })
    }
})
<commit_msg>make sense<commit_after>import assert from 'assert'

import { specificResourceToUri, uriToSpecificResource } from '../src'

// Examples from the spec:
// https://www.w3.org/TR/selectors-states/#json-examples-converted-to-fragment-identifiers
// One difference with the spec: we percent-encode the characters < > [ ] inside fragments.
const pairs = {

    'Example 2 <=> 16: Fragment selector': {
        uri: 'http://example.org/video1#selector(type=FragmentSelector,conformsTo=http://www.w3.org/TR/media-frags/,value=t%3D30%2C60)',
        obj: {
            "source": "http://example.org/video1",
            "selector": {
              "type": "FragmentSelector",
              "conformsTo": "http://www.w3.org/TR/media-frags/",
              "value": "t=30,60"
            }
        }
    },

    'Example 3 <=> 17: CSS selector': {
        uri: 'http://example.org/page1.html#selector(type=CssSelector,value=%23elemid%20%3E%20.elemclass%20+%20p)',
        obj: {
            "source": "http://example.org/page1.html",
            "selector": {
              "type": "CssSelector",
              "value": "#elemid > .elemclass + p"
            }
        }
    },

    'Example 4 <=> 18: XPath selector': {
        uri: 'http://example.org/page1.html#selector(type=XPathSelector,value=/html/body/p%5B2%5D/table/tr%5B2%5D/td%5B3%5D/span)',
        obj: {
            "source": "http://example.org/page1.html",
            "selector": {
              "type": "XPathSelector",
              "value": "/html/body/p[2]/table/tr[2]/td[3]/span"
            }
        }
    },

    'Example 5 <=> 19: TextQuote selector': {
        uri: 'http://example.org/page1#selector(type=TextQuoteSelector,exact=annotation,prefix=this%20is%20an%20,suffix=%20that%20has%20some)',
        obj: {
            "source": "http://example.org/page1",
            "selector": {
              "type": "TextQuoteSelector",
              "exact": "annotation",
              "prefix": "this is an ",
              "suffix": " that has some"
            }
        }
    },

    'Example 6 <=> 20: TextPosition selector': {
        uri: 'http://example.org/ebook1#selector(type=TextPositionSelector,start=412,end=795)',
        obj: {
            "source": "http://example.org/ebook1",
            "selector": {
              "type": "TextPositionSelector",
              "start": 412,
              "end": 795
            }
        }
    },

    'Example 7 <=> 21: Data position selector': {
        uri: 'http://example.org/diskimg1#selector(type=DataPositionSelector,start=4096,end=4104)',
        obj: {
            "source": "http://example.org/diskimg1",
            "selector": {
              "type": "DataPositionSelector",
              "start": 4096,
              "end": 4104
            }
        }
    },

    'Example 8 <=> 22: SVG selector; external SVG': {
        uri: 'http://example.org/map1#selector(type=SvgSelector,id=http://example.org/svg1)',
        obj: {
            "source": "http://example.org/map1",
            "selector": {
              "type": "SvgSelector",
              "id": "http://example.org/svg1"
            }
        }
    },

    'Example 9 <=> 23: SVG selector; embedded SVG': {
        uri: 'http://example.org/map1#selector(type=SvgSelector,value=%3Csvg:svg%3E%20...%20%3C/svg:svg%3E)',
        obj: {
            "source": "http://example.org/map1",
            "selector": {
              "type": "SvgSelector",
              "value": "<svg:svg> ... </svg:svg>"
            }
        }
    },

    'Example 10 <=> 24: Range selector': {
        uri: 'http://example.org/page1.html#selector(type=RangeSelector,startSelector=selector(type=XPathSelector,value=//table%5B1%5D/tr%5B1%5D/td%5B2%5D),endSelector=selector(type=XPathSelector,value=//table%5B1%5D/tr%5B1%5D/td%5B4%5D))',
        obj: {
            "source": "http://example.org/page1.html",
            "selector": {
              "type": "RangeSelector",
              "startSelector": {
                "type": "XPathSelector",
                "value": "//table[1]/tr[1]/td[2]"
              },
              "endSelector": {
                "type": "XPathSelector",
                "value": "//table[1]/tr[1]/td[4]"
              }
            }
        }
    },

    'Example 11 <=> 25: Selector refinement': {
        uri: 'http://example.org/page1#selector(type=FragmentSelector,value=para5,refinedBy=selector(type=TextQuoteSelector,exact=Selected%20Text,prefix=text%20before%20the%20,suffix=%20and%20text%20after%20it))',
        obj: {
            "source": "http://example.org/page1",
            "selector": {
              "type": "FragmentSelector",
              "value": "para5",
              "refinedBy": {
                "type": "TextQuoteSelector",
                "exact": "Selected Text",
                "prefix": "text before the ",
                "suffix": " and text after it"
              }
            }
        }
    },

    'Example 13 <=> 26: Time state': {
        uri: 'http://example.org/page1#state(type=TimeState,cached=http://archive.example.org/copy1,sourceDate=2015-07-20T13:30:00Z)',
        obj: {
            "source": "http://example.org/page1",
            "state": {
              "type": "TimeState",
              "cached": "http://archive.example.org/copy1",
              "sourceDate": "2015-07-20T13:30:00Z"
            }
        }
    },

    'Example 14 <=> 27: HTTP request state': {
        uri: 'http://example.org/resource1#state(type=HttpRequestState,value=Accept:%20application/pdf)',
        obj: {
            "source": "http://example.org/resource1",
            "state": {
              "type": "HttpRequestState",
              "value": "Accept: application/pdf"
            }
        }
    },

    'Example 15 <=> 28: Refinement of states': {
        uri: 'http://example.org/ebook1#state(type=TimeState,sourceDate=2016-02-01T12:05:23Z,refinedBy=state(type=HttpRequestState,value=Accept:%20application/epub+zip))',
        obj: {
            "source": "http://example.org/ebook1",
            "state": {
              "type": "TimeState",
              "sourceDate": "2016-02-01T12:05:23Z",
              "refinedBy": {
                "type": "HttpRequestState",
                "value": "Accept: application/epub+zip"
              }
            }
        }
    },

    'Example 29: Serializing IRI to URL (and vice versa)': {
        uri: 'http://jp.example.org/page1#selector(type=TextQuoteSelector,exact=%E3%83%9A%E3%83%B3%E3%82%92,prefix=%E7%A7%81%E3%81%AF%E3%80%81,suffix=%E6%8C%81%E3%81%A3%E3%81%A6%E3%81%84%E3%81%BE%E3%81%99)',
        obj: {
            selector: {
                type: 'TextQuoteSelector',
                exact: 'ペンを',
                prefix: '私は、',
                suffix: '持っています',
            },
            source: "http://jp.example.org/page1",
        }
    },

    'Fragment identifier without URI': {
        uri: '#selector(type=TextPositionSelector,start=12,end=795)',
        obj: {
            "selector": {
                "type": "TextPositionSelector",
                "start": 12,
                "end": 795
            },
            "source": ""
        }
    },

    'URI without fragment identifier': {
        uri: 'https://example.org',
        obj: {
            "source": "https://example.org"
        }
    },
}

const specialCasesToStringify = {
    'Value with parentheses (to be percent-encoded)': {
        uri: '#selector(type=TextQuoteSelector,exact=example%20%28with%20parentheses%29)',
        obj: {
            selector: {
                type: 'TextQuoteSelector',
                exact: 'example (with parentheses)',
            },
        },
    },
}

const specialCasesToParse = {
    'One closing parenthesis inside a value': {
        uri: '#selector(type=TextQuoteSelector,exact=(not)%20a%20problem)',
        obj: {
            source: '',
            selector: {
                type: 'TextQuoteSelector',
                exact: '(not) a problem',
            },
        },
    },
}

const specialCasesToParseThatFail = {
    'Two closing parentheses inside a value': {
        uri: '#selector(type=TextQuoteSelector,exact=Hey))%20this%20breaks)',
        obj: {
            source: '',
            selector: {
                type: 'TextQuoteSelector',
                exact: 'Hey)) this breaks',
            },
        },
    },

    'Two closing parentheses: one of value, one of selector': {
        uri: '#selector(type=TextQuoteSelector,exact=example%20(that%20fails))',
        obj: {
            source: '',
            selector: {
                type: 'TextQuoteSelector',
                exact: 'example (that fails)',
            },
        },
    },

    'Three closing parentheses: one of the value, two of nested selectors': {
        uri: `
            #selector(
                type=RangeSelector,
                startSelector=selector(type=TextQuoteSelector,exact=(but),
                endSelector=selector(type=TextQuoteSelector,exact=crazy))
            )
            `.replace(/\s/g, ''),
        obj: {
            source: '',
            selector: {
                type: 'RangeSelector',
                startSelector: {
                    type: 'TextQuoteSelector',
                    exact: '(but',
                },
                endSelector: {
                    type: 'TextQuoteSelector',
                    exact: 'crazy)',
                },
            },
        },
    },
};

describe('specificResourceToUri', () => {
    const examples = Object.assign({} , pairs, specialCasesToStringify)
    for (const [name, example] of Object.entries(examples)) {
        it(`should properly convert: '${name}'`, () => {
            let uri = specificResourceToUri(example.obj)
            assert.equal(uri, example.uri)
        })
    }
})

describe('uriToSpecificResource', () => {
    for (let name in pairs) {
        it(`should properly convert: '${name}'`, () => {
            let obj = uriToSpecificResource(pairs[name].uri)
            assert.deepEqual(obj, pairs[name].obj)
        })
    }

    it('should cleanly handle other types of fragment identifiers', () => {
        const obj = uriToSpecificResource('https://example.com/page#section4')
        const expected = {
            source: 'https://example.com/page',
            selector: {
                type: 'FragmentSelector',
                value: 'section4',
            }
        }
        assert.deepEqual(obj, expected)
    })

    for (const [name, example] of Object.entries(specialCasesToParse)) {
        it(`should parse special case: '${name}'`, () => {
            let obj = uriToSpecificResource(example.uri)
            assert.deepEqual(obj, example.obj)
        })
    }

    // FIXME These tests are known to fail. Seems impossible to parse
    // them with PEG.js. See <https://github.com/w3c/web-annotation/issues/443>
    for (const [name, example] of Object.entries(specialCasesToParseThatFail)) {
        it.skip(`should parse special case: '${name}'`, () => {
            let obj = uriToSpecificResource(example.uri)
            assert.deepEqual(obj, example.obj)
        })
    }
})
<|endoftext|>