<commit_before>// @ts-check
(function(window, document){

  // prerequisites
  if ( ! ( 'querySelectorAll' in document ) ||
       ! ( 'filter' in [] ) ||
       ! ( 'content' in document.createElement('template') ) ){ return; }

  if ( ! ( 'JekyllWebmentionIO' in window ) ){ window.JekyllWebmentionIO = {}; }

  //
  // Public Properties
  //
  JekyllWebmentionIO.existing_webmentions = [];

  //
  // Public Methods
  //

  JekyllWebmentionIO.processWebmentions = function( data ){
    // console.log( 'incoming webmentions', data.links );
    if ( data && ! ( 'error' in data ) )
    {
      var webmentions = data.links.reverse();

      webmentions = rationalizeIds( webmentions );

      webmentions = removeDuplicates( webmentions );

      // We may not need to proceed if we had them all
      if ( webmentions.length )
      {
        webmentions = addMetadata( webmentions );

        // hande them out
        doleOutWebmentions( webmentions );

        // reset the counters
        if ( this.counter_update_event )
        {
          document.dispatchEvent( this.counter_update_event );
        }
      }
      else
      {
        // console.log( 'no new webmentions to add' );
      }
    }
  };

  //
  // Private Properties
  //

  var webmention_receivers = {},
      templates = {};

  //
  // Private Methods
  //

  // Gathers embewdded templates
  function collectTemplates()
  {
    var $templates = document.querySelectorAll( 'template[id^=webmention-]' ),
        t = $templates.length,
        $template;

    while ( t-- )
    {
      $template = $templates[t];
      // We only need the list (if one exists)
      if ( $template.content.querySelector('ol') )
      {
        templates[$template.id] = $template.content.querySelector('ol');
      }
      else
      {
        templates[$template.id] = $template.content;
      }
    }
    $template = null;
  }

  // Collects webmentions that are already on the page
  function collectExistingWebmentions()
  {
    var $existing_webmentions = document.querySelectorAll( '[id^=webmention-]' ),
        e = $existing_webmentions.length;

    while ( e-- )
    {
      JekyllWebmentionIO.existing_webmentions.push(
        $existing_webmentions[e]
            .getAttribute( 'id' )
            .replace( 'webmention-', '' )
      );
    }

    $existing_webmentions = null;
  }

  function identifyWebmentionCollections()
  {
    var $webmention_collections = document.querySelectorAll( '.webmentions' ),
        w = $webmention_collections.length,
        $webmention_collection,
        type,
        types, t;

    // Assign the type & template if we can determine it
    while ( w-- )
    {
      $webmention_collection = $webmention_collections[w];

      // Assign the type
      type = 'webmentions'; // Generic
      if ( $webmention_collection.className.indexOf('webmentions--') > -1 )
      {
        type = $webmention_collection.className.match(/webmentions\-\-(.*)/)[1];
      }
      $webmention_collection.type = type;

      // Assign the template
      if ( templates['webmention-' + type] )
      {
        $webmention_collection.template = templates['webmention-' + type];
      }

      // Add to the queues
      if ( 'dataset' in $webmention_collection &&
          'webmentionTypes' in $webmention_collection.dataset )
      {
        types = $webmention_collection.dataset.webmentionTypes.split(',');
      }
      else
      {
        types = [ type ];
      }
      t = types.length;
      while (t--)
      {
        type = types[t];
        if ( ! ( type in webmention_receivers ) )
        {
          webmention_receivers[type] = [];
        }
        webmention_receivers[type].push( $webmention_collection );
      }
    }

    $webmention_collection = null;
  }

  // Divvies up the webmentions and populate the lists
  function doleOutWebmentions( webmentions )
  {
    var i = 0, j,
        webmention,
        incoming = {},
        queue_keys = Object.keys( webmention_receivers ),
        plural_type,
        typeFilter = function(key) {
          return JekyllWebmentionIO.types[key] === this.type;
        },
        typeFilterLoop;

    // set up the queues
    i = queue_keys.length;
    while( i--)
    {
      incoming[queue_keys[i]] = [];
    }

    // Assign the webmentions to their respective queues
    i = webmentions.length;

    while ( i-- )
    {
      webmention = webmentions[i];
      // reverse lookup to get the plural from the singular
      typeFilterLoop = typeFilter.bind(webmention);
      plural_type = Object.keys(JekyllWebmentionIO.types)
                          .filter(typeFilterLoop)[0];

      // Is there a specific queue requesting this?
      if ( queue_keys.indexOf( plural_type ) > -1 )
      {
        incoming[plural_type].push( webmention );
      }

      // If there’s a generic, add it there too
      if ( incoming.webmentions )
      {
        incoming.webmentions.push( webmention );
      }
    }

    // Now hand them out
    i = queue_keys.length;
    while( i-- )
    {
      j = webmention_receivers[queue_keys[i]].length;
      while ( j-- )
      {
        // No point passing nothing
        if ( incoming[queue_keys[i]].length > 0 )
        {
          addWebmentionsToCollection( incoming[queue_keys[i]], webmention_receivers[queue_keys[i]][j] );
        }
      }
    }

  }

  function addWebmentionsToCollection( mentions, $webmention_collection )
  {
    if ( mentions.length < 1 )
    {
      console.warn( 'No webmentions to add, check your application code' );
      return;
    }

    if ( ! $webmention_collection.template )
    {
      console.error( 'No template found for this webmention group', $webmention_collection );
      return;
    }

    if ( ! ( 'Liquid' in window ) )
    {
      console.error( 'Liquid parsing engine is not available' );
      return;
    }

    var $list = $webmention_collection.querySelector('.webmentions__list'),
        template = $webmention_collection.template,
        mode = 'append',
        html;

    // Already working with a list
    if ( $list )
    {
      template = Liquid.parse( template.innerHTML );
    }
    // Need a list
    else
    {
      template = Liquid.parse( template.outerHTML );
      mode = 'replace';
    }

    // append
    html = template.render({ 'webmentions': mentions });
    if ( mode == 'append' )
    {
      $list.innerHTML += html;
    }
    else
    {
      $webmention_collection.innerHTML = html;
    }

    // console.log( 'Successfully added', mentions.length );
  }

  // Uses the ID attribute for everything except tweets
  function rationalizeIds( webmentions )
  {
    // console.log( 'rationizing IDs' );
    var i = webmentions.length,
        id,
        url;

    while ( i-- )
    {
      id = webmentions[i].id;
      url = webmentions[i].data.url || webmentions[i].source;
      if ( url && url.indexOf( 'twitter.com/' ) > -1 )
      {
        // Unique tweets gets unique IDs
        if ( url.indexOf( '#favorited-by' ) < 0 )
        {
          id = url.replace( /^.*?status\/(\d+)$/, '$1' );
        }
      }
      // coerce to a string
      webmentions[i].id = id + '';
    }

    //console.log( webmentions.length, 'IDs rationalized' );
    return webmentions;
  }

  // Removes duplicate webmentions
  function removeDuplicates( webmentions )
  {
    // console.log( 'removing duplicates' );
    // going backwards, so reverse things to start out
    webmentions.reverse();

    var unique_webmentions = [],
        i = webmentions.length,
        id;

    while ( i-- )
    {
      if ( JekyllWebmentionIO.existing_webmentions.indexOf( webmentions[i].id ) < 0 )
      {
        unique_webmentions.push(webmentions[i]);
        JekyllWebmentionIO.existing_webmentions.push(webmentions[i].id);
      }
    }

    // console.log( 'removed', webmentions.length - unique_webmentions.length, 'duplicates', unique_webmentions );
    return unique_webmentions;
  }

  // Adds the necessary metadata to each webmention object for the liquid templates
  function addMetadata( webmentions )
  {
    // console.log( 'adding metadata' );
    // going backwards, so reverse things to start out
    webmentions.reverse();

    var i = webmentions.length,
        webmention,
        webmention_object,
        uri,
        source,
        pubdate,
        type,
        title,
        content,
        read = function( html_source ){
          if ( html_source )
          {
            updateTitle( this.id, this.uri, html_source );
          }
        },
        loop_read;

    while ( i-- )
    {
      webmention = webmentions[i];

      uri = webmention.data.url || webmention.source;

      source = false;
      if ( uri.indexOf('twitter.com/') )
      {
        source = 'twitter';
      }
      else if ( uri.indexOf('/googleplus/') > -1 )
      {
        source = 'googleplus';
      }

      pubdate = webmention.data.published_ts;
      if ( ! pubdate && webmention.verified_date )
      {
        pubdate = webmention.verified_date;
      }
      if ( pubdate )
      {
        pubdate = (new Date(pubdate)).getTime();
      }

      webmention_object = {
        id:      webmention.id,
        url:     uri,
        source:  source,
        pubdate: pubdate,
        raw:     webmentions[i]
      };

      if ( 'author' in webmention.data )
      {
        webmention_object.author = webmentions[i].data.author;
      }

      type = webmentions[i].activity.type;
      if ( ! type )
      {
        if ( source == 'googleplus' )
        {
          if ( uri.indexOf('/like/') > -1 )
          {
            type = 'like';
          }
          else if ( uri.indexOf( '/repost/' ) > -1 )
          {
            type = 'repost';
          }
          else if ( uri.indexOf( '/comment/' ) > -1 )
          {
            type = 'reply';
          }
          else
          {
            type = 'link';
          }
        }
        else
        {
          type = 'post';
        }
      }
      webmention_object.type = type;

      // Posts
      title = false;
      if ( type == 'post' )
      {
        loop_read = read.bind({
          id: webmention_object.id,
          uri: uri
        });
        readWebPage( uri, loop_read );
      }

      content = webmention.data.content;
      if ( type != 'bookmark' && type != 'link' && type != 'post' && type != 'reply' )
      {
        content = webmention.activity.sentence_html;
      }
      webmention_object.content = content;

      // replace the existing webmention
      webmentions[i] = webmention_object;
    }

    // console.log( 'added metadata to', webmentions.length, 'webmentions' );
    return webmentions;
  }

  // Async update of the title
  function updateTitle( webmention_id, url, html_source )
  {
    var $webmention = document.querySelector( '#webmention-' + webmention_id ),
        $current_title = $webmention.querySelector( '.webmention__title' ),
        $page = document.createElement('html'),
        title = '',
        $link_title,
        $title,
        $h1;

    $page.innerHTML = html_source;
    $title = $page.querySelector('title');
    $h1 = $page.querySelector('h1');

    if ( $current_title.length < 0 )
    {
      $current_title = $webmention.querySelector( '.webmention__content' );
    }

    if ( $current_title.length > 0 )
    {
      if ( $title.length > 0 )
      {
        title = $title.innerText;
      }
      else
      {
        if ( $h1.length > 0 )
        {
          title = $h1.innerHTML;
        }
        else
        {
          title = 'No title available';
        }
      }

      if ( title )
      {
        // cleanup
        title = title.replace( /<\/?[^>]+?>}/, '' );
        $link_title = document.createElement('a');
        $link_title.href = url;
        $link_title.appendChild( document.createTextNode( title ) );
        // replace title contents
        $current_title.innerHTML = $link_title.outerHTML;
      }
    }
  }

  // Synchromous XHR proxied through whateverorigin.org
  function readWebPage( uri, callback )
  {
      if ( 'XMLHttpRequest' in window )
      {
        var XHR = new XMLHttpRequest();
        readWebPage = function( uri, callback ){
          var done = false;
          uri = '//whateverorigin.org/get?url=' + encodeURIComponent( uri );
          XHR.onreadystatechange = function() {
            if ( this.readyState == 4 && ! done ) {
              done = true;
              callback( XHR.responseText );
            }
          };
          XHR.onabort = function() {
            if ( ! done )
            {
              done = true;
              callback( false );
            }
          };
          XHR.onerror = XHR.onabort;
          XHR.open( 'GET', uri );
          XHR.send( null );
        };
      }
      else
      {
        readWebPage = function( uri, callback ){
          callback( false );
        };
      }
      return readWebPage( uri, callback );
  }

  // init
  collectTemplates();
  collectExistingWebmentions();
  identifyWebmentionCollections();

}(this, this.document));<commit_msg>Turning off TS checking<commit_after>// #@ts-check
(function(window, document){

  // prerequisites
  if ( ! ( 'querySelectorAll' in document ) ||
       ! ( 'filter' in [] ) ||
       ! ( 'content' in document.createElement('template') ) ){ return; }

  if ( ! ( 'JekyllWebmentionIO' in window ) ){ window.JekyllWebmentionIO = {}; }

  //
  // Public Properties
  //
  JekyllWebmentionIO.existing_webmentions = [];

  //
  // Public Methods
  //

  JekyllWebmentionIO.processWebmentions = function( data ){
    // console.log( 'incoming webmentions', data.links );
    if ( data && ! ( 'error' in data ) )
    {
      var webmentions = data.links.reverse();

      webmentions = rationalizeIds( webmentions );

      webmentions = removeDuplicates( webmentions );

      // We may not need to proceed if we had them all
      if ( webmentions.length )
      {
        webmentions = addMetadata( webmentions );

        // hande them out
        doleOutWebmentions( webmentions );

        // reset the counters
        if ( this.counter_update_event )
        {
          document.dispatchEvent( this.counter_update_event );
        }
      }
      else
      {
        // console.log( 'no new webmentions to add' );
      }
    }
  };

  //
  // Private Properties
  //

  var webmention_receivers = {},
      templates = {};

  //
  // Private Methods
  //

  // Gathers embewdded templates
  function collectTemplates()
  {
    var $templates = document.querySelectorAll( 'template[id^=webmention-]' ),
        t = $templates.length,
        $template;

    while ( t-- )
    {
      $template = $templates[t];
      // We only need the list (if one exists)
      if ( $template.content.querySelector('ol') )
      {
        templates[$template.id] = $template.content.querySelector('ol');
      }
      else
      {
        templates[$template.id] = $template.content;
      }
    }
    $template = null;
  }

  // Collects webmentions that are already on the page
  function collectExistingWebmentions()
  {
    var $existing_webmentions = document.querySelectorAll( '[id^=webmention-]' ),
        e = $existing_webmentions.length;

    while ( e-- )
    {
      JekyllWebmentionIO.existing_webmentions.push(
        $existing_webmentions[e]
            .getAttribute( 'id' )
            .replace( 'webmention-', '' )
      );
    }

    $existing_webmentions = null;
  }

  function identifyWebmentionCollections()
  {
    var $webmention_collections = document.querySelectorAll( '.webmentions' ),
        w = $webmention_collections.length,
        $webmention_collection,
        type,
        types, t;

    // Assign the type & template if we can determine it
    while ( w-- )
    {
      $webmention_collection = $webmention_collections[w];

      // Assign the type
      type = 'webmentions'; // Generic
      if ( $webmention_collection.className.indexOf('webmentions--') > -1 )
      {
        type = $webmention_collection.className.match(/webmentions\-\-(.*)/)[1];
      }
      $webmention_collection.type = type;

      // Assign the template
      if ( templates['webmention-' + type] )
      {
        $webmention_collection.template = templates['webmention-' + type];
      }

      // Add to the queues
      if ( 'dataset' in $webmention_collection &&
          'webmentionTypes' in $webmention_collection.dataset )
      {
        types = $webmention_collection.dataset.webmentionTypes.split(',');
      }
      else
      {
        types = [ type ];
      }
      t = types.length;
      while (t--)
      {
        type = types[t];
        if ( ! ( type in webmention_receivers ) )
        {
          webmention_receivers[type] = [];
        }
        webmention_receivers[type].push( $webmention_collection );
      }
    }

    $webmention_collection = null;
  }

  // Divvies up the webmentions and populate the lists
  function doleOutWebmentions( webmentions )
  {
    var i = 0, j,
        webmention,
        incoming = {},
        queue_keys = Object.keys( webmention_receivers ),
        plural_type,
        typeFilter = function(key) {
          return JekyllWebmentionIO.types[key] === this.type;
        },
        typeFilterLoop;

    // set up the queues
    i = queue_keys.length;
    while( i--)
    {
      incoming[queue_keys[i]] = [];
    }

    // Assign the webmentions to their respective queues
    i = webmentions.length;

    while ( i-- )
    {
      webmention = webmentions[i];
      // reverse lookup to get the plural from the singular
      typeFilterLoop = typeFilter.bind(webmention);
      plural_type = Object.keys(JekyllWebmentionIO.types)
                          .filter(typeFilterLoop)[0];

      // Is there a specific queue requesting this?
      if ( queue_keys.indexOf( plural_type ) > -1 )
      {
        incoming[plural_type].push( webmention );
      }

      // If there’s a generic, add it there too
      if ( incoming.webmentions )
      {
        incoming.webmentions.push( webmention );
      }
    }

    // Now hand them out
    i = queue_keys.length;
    while( i-- )
    {
      j = webmention_receivers[queue_keys[i]].length;
      while ( j-- )
      {
        // No point passing nothing
        if ( incoming[queue_keys[i]].length > 0 )
        {
          addWebmentionsToCollection( incoming[queue_keys[i]], webmention_receivers[queue_keys[i]][j] );
        }
      }
    }

  }

  function addWebmentionsToCollection( mentions, $webmention_collection )
  {
    if ( mentions.length < 1 )
    {
      console.warn( 'No webmentions to add, check your application code' );
      return;
    }

    if ( ! $webmention_collection.template )
    {
      console.error( 'No template found for this webmention group', $webmention_collection );
      return;
    }

    if ( ! ( 'Liquid' in window ) )
    {
      console.error( 'Liquid parsing engine is not available' );
      return;
    }

    var $list = $webmention_collection.querySelector('.webmentions__list'),
        template = $webmention_collection.template,
        mode = 'append',
        html;

    // Already working with a list
    if ( $list )
    {
      template = Liquid.parse( template.innerHTML );
    }
    // Need a list
    else
    {
      template = Liquid.parse( template.outerHTML );
      mode = 'replace';
    }

    // append
    html = template.render({ 'webmentions': mentions });
    if ( mode == 'append' )
    {
      $list.innerHTML += html;
    }
    else
    {
      $webmention_collection.innerHTML = html;
    }

    // console.log( 'Successfully added', mentions.length );
  }

  // Uses the ID attribute for everything except tweets
  function rationalizeIds( webmentions )
  {
    // console.log( 'rationizing IDs' );
    var i = webmentions.length,
        id,
        url;

    while ( i-- )
    {
      id = webmentions[i].id;
      url = webmentions[i].data.url || webmentions[i].source;
      if ( url && url.indexOf( 'twitter.com/' ) > -1 )
      {
        // Unique tweets gets unique IDs
        if ( url.indexOf( '#favorited-by' ) < 0 )
        {
          id = url.replace( /^.*?status\/(\d+)$/, '$1' );
        }
      }
      // coerce to a string
      webmentions[i].id = id + '';
    }

    //console.log( webmentions.length, 'IDs rationalized' );
    return webmentions;
  }

  // Removes duplicate webmentions
  function removeDuplicates( webmentions )
  {
    // console.log( 'removing duplicates' );
    // going backwards, so reverse things to start out
    webmentions.reverse();

    var unique_webmentions = [],
        i = webmentions.length,
        id;

    while ( i-- )
    {
      if ( JekyllWebmentionIO.existing_webmentions.indexOf( webmentions[i].id ) < 0 )
      {
        unique_webmentions.push(webmentions[i]);
        JekyllWebmentionIO.existing_webmentions.push(webmentions[i].id);
      }
    }

    // console.log( 'removed', webmentions.length - unique_webmentions.length, 'duplicates', unique_webmentions );
    return unique_webmentions;
  }

  // Adds the necessary metadata to each webmention object for the liquid templates
  function addMetadata( webmentions )
  {
    // console.log( 'adding metadata' );
    // going backwards, so reverse things to start out
    webmentions.reverse();

    var i = webmentions.length,
        webmention,
        webmention_object,
        uri,
        source,
        pubdate,
        type,
        title,
        content,
        read = function( html_source ){
          if ( html_source )
          {
            updateTitle( this.id, this.uri, html_source );
          }
        },
        loop_read;

    while ( i-- )
    {
      webmention = webmentions[i];

      uri = webmention.data.url || webmention.source;

      source = false;
      if ( uri.indexOf('twitter.com/') )
      {
        source = 'twitter';
      }
      else if ( uri.indexOf('/googleplus/') > -1 )
      {
        source = 'googleplus';
      }

      pubdate = webmention.data.published_ts;
      if ( ! pubdate && webmention.verified_date )
      {
        pubdate = webmention.verified_date;
      }
      if ( pubdate )
      {
        pubdate = (new Date(pubdate)).getTime();
      }

      webmention_object = {
        id:      webmention.id,
        url:     uri,
        source:  source,
        pubdate: pubdate,
        raw:     webmentions[i]
      };

      if ( 'author' in webmention.data )
      {
        webmention_object.author = webmentions[i].data.author;
      }

      type = webmentions[i].activity.type;
      if ( ! type )
      {
        if ( source == 'googleplus' )
        {
          if ( uri.indexOf('/like/') > -1 )
          {
            type = 'like';
          }
          else if ( uri.indexOf( '/repost/' ) > -1 )
          {
            type = 'repost';
          }
          else if ( uri.indexOf( '/comment/' ) > -1 )
          {
            type = 'reply';
          }
          else
          {
            type = 'link';
          }
        }
        else
        {
          type = 'post';
        }
      }
      webmention_object.type = type;

      // Posts
      title = false;
      if ( type == 'post' )
      {
        loop_read = read.bind({
          id: webmention_object.id,
          uri: uri
        });
        readWebPage( uri, loop_read );
      }

      content = webmention.data.content;
      if ( type != 'bookmark' && type != 'link' && type != 'post' && type != 'reply' )
      {
        content = webmention.activity.sentence_html;
      }
      webmention_object.content = content;

      // replace the existing webmention
      webmentions[i] = webmention_object;
    }

    // console.log( 'added metadata to', webmentions.length, 'webmentions' );
    return webmentions;
  }

  // Async update of the title
  function updateTitle( webmention_id, url, html_source )
  {
    var $webmention = document.querySelector( '#webmention-' + webmention_id ),
        $current_title = $webmention.querySelector( '.webmention__title' ),
        $page = document.createElement('html'),
        title = '',
        $link_title,
        $title,
        $h1;

    $page.innerHTML = html_source;
    $title = $page.querySelector('title');
    $h1 = $page.querySelector('h1');

    if ( $current_title.length < 0 )
    {
      $current_title = $webmention.querySelector( '.webmention__content' );
    }

    if ( $current_title.length > 0 )
    {
      if ( $title.length > 0 )
      {
        title = $title.innerText;
      }
      else
      {
        if ( $h1.length > 0 )
        {
          title = $h1.innerHTML;
        }
        else
        {
          title = 'No title available';
        }
      }

      if ( title )
      {
        // cleanup
        title = title.replace( /<\/?[^>]+?>}/, '' );
        $link_title = document.createElement('a');
        $link_title.href = url;
        $link_title.appendChild( document.createTextNode( title ) );
        // replace title contents
        $current_title.innerHTML = $link_title.outerHTML;
      }
    }
  }

  // Synchromous XHR proxied through whateverorigin.org
  function readWebPage( uri, callback )
  {
      if ( 'XMLHttpRequest' in window )
      {
        var XHR = new XMLHttpRequest();
        readWebPage = function( uri, callback ){
          var done = false;
          uri = '//whateverorigin.org/get?url=' + encodeURIComponent( uri );
          XHR.onreadystatechange = function() {
            if ( this.readyState == 4 && ! done ) {
              done = true;
              callback( XHR.responseText );
            }
          };
          XHR.onabort = function() {
            if ( ! done )
            {
              done = true;
              callback( false );
            }
          };
          XHR.onerror = XHR.onabort;
          XHR.open( 'GET', uri );
          XHR.send( null );
        };
      }
      else
      {
        readWebPage = function( uri, callback ){
          callback( false );
        };
      }
      return readWebPage( uri, callback );
  }

  // init
  collectTemplates();
  collectExistingWebmentions();
  identifyWebmentionCollections();

}(this, this.document));<|endoftext|>


<commit_before>const assert = require('assert');
const shuffle = require('array-shuffle');
const math = require('mathjs');
const chunk = require('lodash/chunk');
const random = require('lodash/random');

const generateTestInput = () => chunk(
	shuffle([
		random(1, 9),
		...Array(11)
			.fill()
			.map(() => random(1, 99)),
	]),
	3
);

const getDeterminant = (vectors) => {
	const [A, B, C, D] = vectors;
	return math.det([
		math.subtract(B, A),
		math.subtract(C, A),
		math.subtract(D, A),
	]);
};

module.exports.generateInput = () => {
	let vectors = null;
	let determinant = null;
	while (true) {
		vectors = generateTestInput();
		determinant = getDeterminant(vectors);
		if (determinant % 6 === 0 && Math.abs(determinant) >= 30000) {
			break;
		}
	}

	const validVectors =
		determinant > 0
			? vectors
			: [vectors[0], vectors[1], vectors[3], vectors[2]];

	return validVectors
		.map(
			(vector) => `${vector
				.map((value) => value.toString(10).padStart(2, '0'))
				.join(' ')}\n`
		)
		.join('');
};

module.exports.isValidAnswer = (input, output) => {
	if (process.env.NODE_ENV !== 'production') {
		// return true;
	}

	const answer = getDeterminant(chunk(input.split(/\s/), 3)) / 6;
	assert(Number.isInteger(answer));
	assert(answer >= 5000);

	const correctOutput = answer.toString();

	// Trim
	const trimmedOutput = output
		.toString()
		.trim()
		.replace(/^0+/, '');
	console.log('info:', {input, correctOutput, output, trimmedOutput});

	return trimmedOutput === correctOutput;
};
<commit_msg>Fix d-dmd runner<commit_after>const assert = require('assert');
const shuffle = require('array-shuffle');
const math = require('mathjs');
const chunk = require('lodash/chunk');
const random = require('lodash/random');

const generateTestInput = () => chunk(
	shuffle([
		random(1, 9),
		...Array(11)
			.fill()
			.map(() => random(1, 99)),
	]),
	3
);

const getDeterminant = (vectors) => {
	const [A, B, C, D] = vectors;
	return math.det([
		math.subtract(B, A),
		math.subtract(C, A),
		math.subtract(D, A),
	]);
};

module.exports.generateInput = () => {
	let vectors = null;
	let determinant = null;
	while (true) {
		vectors = generateTestInput();
		determinant = getDeterminant(vectors);
		if (determinant % 6 === 0 && Math.abs(determinant) >= 30000) {
			break;
		}
	}

	const validVectors =
		determinant > 0
			? vectors
			: [vectors[0], vectors[1], vectors[3], vectors[2]];

	return validVectors
		.map(
			(vector) => `${vector
				.map((value) => value.toString(10).padStart(2, '0'))
				.join(' ')}\n`
		)
		.join('');
};

module.exports.isValidAnswer = (input, output) => {
	if (process.env.NODE_ENV !== 'production') {
		return true;
	}

	const answer = getDeterminant(chunk(input.split(/\s/), 3)) / 6;
	assert(Number.isInteger(answer));
	assert(answer >= 5000);

	const correctOutput = answer.toString();

	// Trim
	const trimmedOutput = output
		.toString()
		.trim()
		.replace(/^0+/, '');
	console.log('info:', {input, correctOutput, output, trimmedOutput});

	return trimmedOutput === correctOutput;
};
<|endoftext|>


<commit_before>'use strict';
var util = require('util');
var EventEmitter = require('events').EventEmitter;
var msgpack = require('msgpack-lite');
var net = require('net');
var stream = require('stream');
var crypto = require('crypto');
var FluentLoggerError = require('./logger-error');
var EventTime = require('./event-time').EventTime;

var codec = msgpack.createCodec();
codec.addExtPacker(0x00, EventTime, EventTime.pack);
codec.addExtUnpacker(0x00, EventTime.unpack);

function FluentSender(tag_prefix, options){
  options = options || {};
  this.tag_prefix = tag_prefix;
  this.host = options.host || 'localhost';
  this.port = options.port || 24224;
  this.path = options.path;
  this.timeout = options.timeout || 3.0;
  this.reconnectInterval = options.reconnectInterval || 600000; // Default is 10 minutes
  this.requireAckResponse = options.requireAckResponse;
  this.ackResponseTimeout = options.ackResponseTimeout || 190000; // Default is 190 seconds
  this.internalLogger = options.internalLogger || console;
  this._timeResolution = options.milliseconds ? 1 : 1000;
  this._socket = null;
  this._data = null;
  this._sendQueue = []; // queue for items waiting for being sent.
  this._eventEmitter = new EventEmitter();
}

FluentSender.prototype.emit = function(/*[label] <data>, [timestamp], [callback] */){
  var label, data, timestamp, callback;
  var args = Array.prototype.slice.call(arguments);
  // Label must be string always
  if (typeof args[0] === 'string') label = args.shift();

  // Data can be almost anything
  data = args.shift();

  // Date can be either timestamp number or Date object
  if (typeof args[0] !== 'function') timestamp = args.shift();

  // Last argument is an optional callback
  if (typeof args[0] === 'function') callback = args.shift();

  var self = this;
  var item = self._makePacketItem(label, data, timestamp);

  var error;
  var options;
  if (item.tag === null) {
    options = {
      tag_prefix: self.tag_prefix,
      label: label
    };
    error = new FluentLoggerError.MissingTag('tag is missing', options);
    self._handleEvent('error', error, callback);
    return;
  }
  if (typeof item.data !== 'object') {
    options = {
      tag_prefix: self.tag_prefix,
      label: label,
      record: item.data
    };
    error = new FluentLoggerError.DataTypeError('data must be an object', options);
    self._handleEvent('error', error, callback);
    return;
  }

  item.callback = callback;

  self._sendQueue.push(item);
  self._connect(function(){
    self._flushSendQueue();
  });
};

['addListener', 'on', 'once', 'removeListener', 'removeAllListeners', 'setMaxListeners', 'getMaxListeners'].forEach(function(attr, i){
  FluentSender.prototype[attr] = function(){
    return this._eventEmitter[attr].apply(this._eventEmitter, Array.prototype.slice.call(arguments));
  };
});

FluentSender.prototype.end = function(label, data, callback){
  var self = this;
  if ((label != null && data != null)) {
    self.emit(label, data, function(err) {
      self._close();
      if (err) {
        self._handleEvent('error', err, callback);
      } else {
        callback && callback();
      }
    });
  } else {
    process.nextTick(function() {
      self._close();
      callback && callback();
    });
  }
};

FluentSender.prototype._close = function() {
  if (this._socket) {
    this._socket.end();
    this._socket = null;
  }
};

FluentSender.prototype._makePacketItem = function(label, data, time){
  var self = this;
  var tag = null;
  if (self.tag_prefix && label) {
    tag = [self.tag_prefix, label].join('.');
  } else if (self.tag_prefix) {
    tag = self.tag_prefix;
  } else if (label) {
    tag = label;
  }

  if (typeof time !== 'number' && !(time instanceof EventTime)) {
    time = Math.floor((time ? time.getTime() : Date.now()) / this._timeResolution);
  }

  var packet = [tag, time, data];
  var options = {};
  if (self.requireAckResponse) {
    options = {
      chunk: crypto.randomBytes(16).toString('base64')
    };
    packet.push(options);
  }
  return {
    packet: msgpack.encode(packet, { codec: codec }),
    tag: tag,
    time: time,
    data: data,
    options: options
  };
};

FluentSender.prototype._connect = function(callback){
  var self = this;
  if (self._socket === null) {
    self._socket = new net.Socket();
    self._socket.setTimeout(self.timeout);
    self._socket.on('error', function(err) {
      if (self._socket) {
        self._socket.destroy();
        self._socket = null;
        self._handleEvent('error', err);
      }
    });
    self._socket.on('connect', function() {
      self._handleEvent('connect');
    });
    if (self.path) {
      self._socket.connect(self.path, callback);
    } else {
      self._socket.connect(self.port, self.host, callback);
    }
  } else {
    if (!self._socket.writable) {
      self._socket.destroy();
      self._socket = null;
      process.nextTick(function() {
        self._connect(callback);
      });
    } else {
      process.nextTick(function() {
        callback();
      });
    }
  }
};

FluentSender.prototype._flushSendQueue = function() {
  var self = this;
  if (self._flushingSendQueue)
    return;

  self._flushingSendQueue = true;
  process.nextTick(function waitToWrite() {
    if (!self._socket) {
      self._flushingSendQueue = false;
      return;
    }

    if (self._socket.writable) {
      self._doFlushSendQueue();
    } else {
      process.nextTick(waitToWrite);
    }
  });
};

FluentSender.prototype._doFlushSendQueue = function() {
  var self = this;
  var item = self._sendQueue.shift();
  var timeoutId = null;
  if (item === undefined) {
    self._flushingSendQueue = false;
    // nothing written;
  } else {
    self._socket.write(new Buffer(item.packet), function(){
      if (self.requireAckResponse) {
        self._socket.once('data', function(data) {
          timeoutId && clearTimeout(timeoutId);
          var response = msgpack.decode(data, { codec: codec });
          if (response.ack !== item.options.chunk) {
            var error = new FluentLoggerError.ResponseError('ack in response and chunk id in sent data are different',
                                                            { ack: response.ack, chunk: item.options.chunk });
            self._handleEvent('error', error, item.callback);
          }
          item.callback && item.callback();
          process.nextTick(function() {
            self._doFlushSendQueue(); // if socket is still available
          });
        });
        timeoutId = setTimeout(function() {
          var error = new FluentLoggerError.ResponseTimeout('ack response timeout');
          self._handleEvent('error', error, item.callback);
        }, self.ackResponseTimeout);
      } else {
        item.callback && item.callback();
        process.nextTick(function() {
          self._doFlushSendQueue(); // if socket is still available
        });
      }
    });
    // TODO: how should we recorver if dequeued items are not sent.
  }
};

FluentSender.prototype._handleEvent = function _handleEvent(signal, data, callback) {
  var self = this;
  callback && callback(data);
  if (self._eventEmitter.listenerCount(signal) > 0) {
    self._eventEmitter.emit(signal, data);
  }
};

FluentSender.prototype._setupErrorHandler = function _setupErrorHandler() {
  var self = this;
  if (!self.reconnectInterval) {
    return;
  }
  self.on('error', function(error) {
    self._flushingSendQueue = false;
    self.internalLogger.error('Fluentd error', error);
    self.internalLogger.info('Fluentd will reconnect after ' + self.reconnectInterval / 1000 + ' seconds');
    setTimeout(function() {
      self.internalLogger.info('Fluentd is reconnecting...');
      self._connect(function() {
        self.internalLogger.info('Fluentd reconnection finished!!');
      });
    }, self.reconnectInterval);
  });
};

FluentSender.prototype.toStream = function(options) {
  if (typeof options === 'string') {
    options = {label: options};
  } else {
    options = options || {};
  }
  var label = options.label;
  if (!label) {
    throw new Error('label is needed');
  }
  var defaultEncoding = options.encoding || 'UTF-8';
  var self = this;
  var writable = new stream.Writable();
  var dataString = '';
  writable._write = function(chunk, encoding, callback) {
    var dataArray = chunk.toString(defaultEncoding).split(/\n/);
    function next() {
      if (dataArray.length) {
        dataString += dataArray.shift();
      }
      if (!dataArray.length) {
        process.nextTick(callback);
        return;
      }
      self.emit(label, { message: dataString }, function(err) {
        if (err) {
          self._handleEvent('error', err, callback);
          return;
        }
        dataString = '';
        next();
      });
    };
    next();
  };
  return writable;
};

module.exports = exports = {};
exports.FluentSender = FluentSender;
<commit_msg>Remove redundant `var self = this;` assignment<commit_after>'use strict';
var util = require('util');
var EventEmitter = require('events').EventEmitter;
var msgpack = require('msgpack-lite');
var net = require('net');
var stream = require('stream');
var crypto = require('crypto');
var FluentLoggerError = require('./logger-error');
var EventTime = require('./event-time').EventTime;

var codec = msgpack.createCodec();
codec.addExtPacker(0x00, EventTime, EventTime.pack);
codec.addExtUnpacker(0x00, EventTime.unpack);

function FluentSender(tag_prefix, options){
  options = options || {};
  this.tag_prefix = tag_prefix;
  this.host = options.host || 'localhost';
  this.port = options.port || 24224;
  this.path = options.path;
  this.timeout = options.timeout || 3.0;
  this.reconnectInterval = options.reconnectInterval || 600000; // Default is 10 minutes
  this.requireAckResponse = options.requireAckResponse;
  this.ackResponseTimeout = options.ackResponseTimeout || 190000; // Default is 190 seconds
  this.internalLogger = options.internalLogger || console;
  this._timeResolution = options.milliseconds ? 1 : 1000;
  this._socket = null;
  this._data = null;
  this._sendQueue = []; // queue for items waiting for being sent.
  this._eventEmitter = new EventEmitter();
}

FluentSender.prototype.emit = function(/*[label] <data>, [timestamp], [callback] */){
  var label, data, timestamp, callback;
  var args = Array.prototype.slice.call(arguments);
  // Label must be string always
  if (typeof args[0] === 'string') label = args.shift();

  // Data can be almost anything
  data = args.shift();

  // Date can be either timestamp number or Date object
  if (typeof args[0] !== 'function') timestamp = args.shift();

  // Last argument is an optional callback
  if (typeof args[0] === 'function') callback = args.shift();

  var self = this;
  var item = self._makePacketItem(label, data, timestamp);

  var error;
  var options;
  if (item.tag === null) {
    options = {
      tag_prefix: self.tag_prefix,
      label: label
    };
    error = new FluentLoggerError.MissingTag('tag is missing', options);
    self._handleEvent('error', error, callback);
    return;
  }
  if (typeof item.data !== 'object') {
    options = {
      tag_prefix: self.tag_prefix,
      label: label,
      record: item.data
    };
    error = new FluentLoggerError.DataTypeError('data must be an object', options);
    self._handleEvent('error', error, callback);
    return;
  }

  item.callback = callback;

  self._sendQueue.push(item);
  self._connect(function(){
    self._flushSendQueue();
  });
};

['addListener', 'on', 'once', 'removeListener', 'removeAllListeners', 'setMaxListeners', 'getMaxListeners'].forEach(function(attr, i){
  FluentSender.prototype[attr] = function(){
    return this._eventEmitter[attr].apply(this._eventEmitter, Array.prototype.slice.call(arguments));
  };
});

FluentSender.prototype.end = function(label, data, callback){
  var self = this;
  if ((label != null && data != null)) {
    self.emit(label, data, function(err) {
      self._close();
      if (err) {
        self._handleEvent('error', err, callback);
      } else {
        callback && callback();
      }
    });
  } else {
    process.nextTick(function() {
      self._close();
      callback && callback();
    });
  }
};

FluentSender.prototype._close = function() {
  if (this._socket) {
    this._socket.end();
    this._socket = null;
  }
};

FluentSender.prototype._makePacketItem = function(label, data, time){
  var tag = null;
  if (this.tag_prefix && label) {
    tag = [this.tag_prefix, label].join('.');
  } else if (this.tag_prefix) {
    tag = this.tag_prefix;
  } else if (label) {
    tag = label;
  }

  if (typeof time !== 'number' && !(time instanceof EventTime)) {
    time = Math.floor((time ? time.getTime() : Date.now()) / this._timeResolution);
  }

  var packet = [tag, time, data];
  var options = {};
  if (this.requireAckResponse) {
    options = {
      chunk: crypto.randomBytes(16).toString('base64')
    };
    packet.push(options);
  }
  return {
    packet: msgpack.encode(packet, { codec: codec }),
    tag: tag,
    time: time,
    data: data,
    options: options
  };
};

FluentSender.prototype._connect = function(callback){
  var self = this;
  if (self._socket === null) {
    self._socket = new net.Socket();
    self._socket.setTimeout(self.timeout);
    self._socket.on('error', function(err) {
      if (self._socket) {
        self._socket.destroy();
        self._socket = null;
        self._handleEvent('error', err);
      }
    });
    self._socket.on('connect', function() {
      self._handleEvent('connect');
    });
    if (self.path) {
      self._socket.connect(self.path, callback);
    } else {
      self._socket.connect(self.port, self.host, callback);
    }
  } else {
    if (!self._socket.writable) {
      self._socket.destroy();
      self._socket = null;
      process.nextTick(function() {
        self._connect(callback);
      });
    } else {
      process.nextTick(function() {
        callback();
      });
    }
  }
};

FluentSender.prototype._flushSendQueue = function() {
  var self = this;
  if (self._flushingSendQueue)
    return;

  self._flushingSendQueue = true;
  process.nextTick(function waitToWrite() {
    if (!self._socket) {
      self._flushingSendQueue = false;
      return;
    }

    if (self._socket.writable) {
      self._doFlushSendQueue();
    } else {
      process.nextTick(waitToWrite);
    }
  });
};

FluentSender.prototype._doFlushSendQueue = function() {
  var self = this;
  var item = self._sendQueue.shift();
  var timeoutId = null;
  if (item === undefined) {
    self._flushingSendQueue = false;
    // nothing written;
  } else {
    self._socket.write(new Buffer(item.packet), function(){
      if (self.requireAckResponse) {
        self._socket.once('data', function(data) {
          timeoutId && clearTimeout(timeoutId);
          var response = msgpack.decode(data, { codec: codec });
          if (response.ack !== item.options.chunk) {
            var error = new FluentLoggerError.ResponseError('ack in response and chunk id in sent data are different',
                                                            { ack: response.ack, chunk: item.options.chunk });
            self._handleEvent('error', error, item.callback);
          }
          item.callback && item.callback();
          process.nextTick(function() {
            self._doFlushSendQueue(); // if socket is still available
          });
        });
        timeoutId = setTimeout(function() {
          var error = new FluentLoggerError.ResponseTimeout('ack response timeout');
          self._handleEvent('error', error, item.callback);
        }, self.ackResponseTimeout);
      } else {
        item.callback && item.callback();
        process.nextTick(function() {
          self._doFlushSendQueue(); // if socket is still available
        });
      }
    });
    // TODO: how should we recorver if dequeued items are not sent.
  }
};

FluentSender.prototype._handleEvent = function _handleEvent(signal, data, callback) {
  var self = this;
  callback && callback(data);
  if (self._eventEmitter.listenerCount(signal) > 0) {
    self._eventEmitter.emit(signal, data);
  }
};

FluentSender.prototype._setupErrorHandler = function _setupErrorHandler() {
  var self = this;
  if (!self.reconnectInterval) {
    return;
  }
  self.on('error', function(error) {
    self._flushingSendQueue = false;
    self.internalLogger.error('Fluentd error', error);
    self.internalLogger.info('Fluentd will reconnect after ' + self.reconnectInterval / 1000 + ' seconds');
    setTimeout(function() {
      self.internalLogger.info('Fluentd is reconnecting...');
      self._connect(function() {
        self.internalLogger.info('Fluentd reconnection finished!!');
      });
    }, self.reconnectInterval);
  });
};

FluentSender.prototype.toStream = function(options) {
  if (typeof options === 'string') {
    options = {label: options};
  } else {
    options = options || {};
  }
  var label = options.label;
  if (!label) {
    throw new Error('label is needed');
  }
  var defaultEncoding = options.encoding || 'UTF-8';
  var self = this;
  var writable = new stream.Writable();
  var dataString = '';
  writable._write = function(chunk, encoding, callback) {
    var dataArray = chunk.toString(defaultEncoding).split(/\n/);
    function next() {
      if (dataArray.length) {
        dataString += dataArray.shift();
      }
      if (!dataArray.length) {
        process.nextTick(callback);
        return;
      }
      self.emit(label, { message: dataString }, function(err) {
        if (err) {
          self._handleEvent('error', err, callback);
          return;
        }
        dataString = '';
        next();
      });
    };
    next();
  };
  return writable;
};

module.exports = exports = {};
exports.FluentSender = FluentSender;
<|endoftext|>


<commit_before>/* -*- Mode: Javascript; js-indent-level: 2 -*- */

var naan = require('naan');
var async = require('async');
var request = require('request');
var _ = require('underscore');
var util = require('util');

var defaultOptions = {
    // Location of the server
    endpoint: 'http://localhost:7474'

    // The key to use when inserting an id into objects.
  , id: 'id'
}, optionKeys = Object.keys(defaultOptions);

// Bind all functions of an object to a context
var bindAllTo = function(context, all) {
  return _.functions(all).reduce(function(bound, key) {
    bound[key] = all[key].bind(context);
    return bound;
  }, _.clone(all));
}

function Seraph(options) {
  if (typeof options === 'string') {
    options = { endpoint: options };
  };
  this.options = _.extend({}, defaultOptions, options);

  _.bindAll(this);

  this.node = bindAllTo(this, require('./node'));
  this.rel = bindAllTo(this, require('./relationship'));
  var indexGeneric = bindAllTo(this, require('./index'));

  // Alias & curry seraph.index on seraph.node & seraph.rel
  this.node.index = naan.curry(indexGeneric.add, 'node');
  this.rel.index = naan.curry(indexGeneric.add, 'relationship');
  naan.ecrock(this.node.index, indexGeneric, naan.curry, 'node');
  naan.ecrock(this.rel.index, indexGeneric, naan.curry, 'relationship');

  _.extend(this, this.node);
}

/**
 * Create an operation that can later be passed to call().
 *
 * Path is relative to the service endpoint - `node` gets
 * transformed to `<options.endpoint>/data/db/node`.
 *
 * If `method` is not supplied, it will default GET, unless `data`
 * is supplied, in which case it will default to 'POST'.
 *
 * seraph#operation(opts, path, [method='get'], [data]);
 */
Seraph.prototype.operation = function(path, method, data) {
  // Get args in the right order
  if (typeof data === 'undefined') {
    data = null;
  }
  if (typeof method === 'object') {
    data = method;
    method = 'POST';
  }
  if (typeof method === 'undefined') {
    method = 'GET';
  }

  // Ensure we have a usable HTTP verb.
  if (typeof method !== 'string') {
    throw new Error('Invalid HTTP Verb - ' + method);
  } else {
    method = method.toUpperCase();
  }

  return {
    'method': method,
    'to'    : path,
    'body'  : data
  };
};

/**
 * Like `async.map`, run `fn` once per element of `params`.  Unlike
 * `async.map`, throttle this through an `async.queue`.
 * `done(err, data)` will be called on completion, where `data`
 * is the result from each of the function calls, in the exact same
 * order as in the `params` array.
 */
Seraph.prototype.throttleMap = function(params, fn, done) {
  var dead = false;
  var results = [];
  var q = async.queue(function worker(task, callback) {
    if (dead) return;
    fn(task, callback);
  }, 10);
  q.drain = function () {
    if (dead) return;
    done(null, results);
  };
  params.forEach(function (param, idx) {
    q.push(param, function (err, data) {
      if (dead) return;
      if (err) {
        dead = true;
        done(err);
      }
      results[idx] = data;
    });
  });
};

/**
 * Function to call an HTTP request to the rest service.
 *
 * Requires an operation object of form:
 *   { method: 'PUT'|'POST'|'GET'|'DELETE'
 *   , to    : path,
 *   , body  : object }
 *
 * Operation objects are easily created by seraph#operation.
 *
 * seraph#call(operation, callback);
 */
Seraph.prototype.call = function(operation, callback) {
  // Ensure callback is callable. Throw instead of calling back if none.
  if (typeof callback !== 'function') {
    callback = function(err) {
      if (err) throw err;
    }
  }

  var requestOpts = {
    uri: this.options.endpoint + '/db/data/' + operation.to,
    method: operation.method,
    headers: { 'Accept': 'application/json' }
  };

  if (operation.body) requestOpts.json = operation.body;
  callback = _.bind(callback, this);

  // Allows mocking
  (this._request || request)(requestOpts, function(err, response, body) {
    if (err) {
      callback(err);
    } else if (response.statusCode < 200 || response.statusCode >= 300) {
      callback(body || response.statusCode);
    } else {
      if (typeof body === 'string') {
        try {
          body = JSON.parse(body);
        } catch (e) {
          return callback(e);
        }
      }

      callback(null, body, response);
    }
  });
};

/**
 * If `obj` is an object, return the value of key <options.id>. Otherwise,
 * return `obj`.
 *
 * If `requireData` is truthy, `obj` must be an object, otherwise undefined is
 * returned.
 */
Seraph.prototype._getId = function(obj, requireData) {
  if (requireData) {
    return typeof obj === 'object' ? obj[this.options.id] : undefined;
  } else {
    return typeof obj === 'object' ? obj[this.options.id] : obj;
  }
};

/**
 * Take the end off a url and parse it as an int
 */
Seraph.prototype._extractId = function(location) {
  var matches = location.match(/\/(\d+)$/);
  if (!matches) {
    return null;
  }

  return parseInt(matches[1], 10);
};

/**
 * Infer whether or not the given object is a node
 */
Seraph.nodeFlags = [
  'outgoing_relationships',
  'incoming_relationships',
  'all_relationships',
  'data',
  'properties',
  'self'
];
Seraph.prototype._isNode = function(node) {
  if (!node || typeof node !== 'object') {
    return false;
  }

  var inNode = node.hasOwnProperty.bind(node);
  return Seraph.nodeFlags.every(inNode) &&
         typeof node.data === 'object';
};

/**
 * Infer whether or not the given object is a relationship
 */
Seraph.relationshipFlags = [
  'start',
  'data',
  'self',
  'properties',
  'end'
];
Seraph.prototype._isRelationship = function(rel) {
  if (!rel || typeof rel !== 'object') {
    return false;
  }

  var inRelationship = rel.hasOwnProperty.bind(rel);
  return Seraph.relationshipFlags.every(inRelationship) &&
         typeof rel.data === 'object';
};

/**
 * Returns the url to an entity given an id
 */
Seraph.prototype._location = function(type, id) {
  return util.format('%s/data/db/%s/%d', this.options.endpoint, type, id);
};

/**
 * Create a relationship object from the given relationship data returned from
 * the neo4j server
 */
Seraph.prototype._createRelationshipObject = function(relationshipData) {
  var relationshipObj = {
    start: this._extractId(relationshipData.start),
    end: this._extractId(relationshipData.end),
    type: relationshipData.type,
    properties: relationshipData.data
  };

  relationshipObj[this.options.id] = this._extractId(relationshipData.self);

  return relationshipObj;
};

/**
 * Create a node object from the given node data return from the neo4j server
 */
Seraph.prototype._createNodeObject = function(nodeData) {
  var nodeObj = nodeData.data || {};
  nodeObj[this.options.id] = this._extractId(nodeData.self);

  return nodeObj;
};

  /**
   * Perform a cypher query. Maps to POST cypher
   */
Seraph.prototype.queryRaw = function(query, params, callback) {
  if (typeof query !== 'string') {
    return callback(new Error('Invalid Query'));
  }
  if (typeof params !== 'object') {
    if (typeof params === 'function') {
      callback = params;
    }
    params = {};
  }

  query = { query: query, params: params };
  var op = this.operation('cypher', query);
  this.call(op, function(err, result) {
    if (err) {
      callback(err);
    } else {
      callback(null, result);
    }
  });
};

/**
 * Perform a cypher query and map the columns and results together.
 */
Seraph.prototype.query = function(query, params, callback) {
  if (typeof params !== 'object') {
    if (typeof params === 'function') {
      callback = params;
    }
    params = {};
  }

  var self = this;
  this.queryRaw(query, params, function(err, result) {
    if (err) {
      return callback(err);
    }

    var namedResults = result.data.map(function(row) {
      return result.columns.reduce(function(rowObj, columnName, columnIndex) {
        var resultItem = row[columnIndex];
        function extractAttributes(item) {
          if (self._isNode(item))
            return self._createNodeObject(item);
          else if (self._isRelationship(item))
            return self._createRelationshipObject(item);
          return item;
        }
        if (Array.isArray(resultItem))
          rowObj[columnName] = resultItem.map(extractAttributes);
        else
          rowObj[columnName] = extractAttributes(resultItem);

        return rowObj;
      }, {});
    });

    if (result.columns.length === 1) {
      namedResults = namedResults.map(function(namedResult) {
        return namedResult[result.columns[0]];
      });
    }

    callback(null, namedResults);
  });
};

function BatchSeraph(options) {
  var self = this;

  function wrapFunctions(parent, target) {
    var derived = target || {};
    Object.keys(parent).forEach(function(key) {
      var valueType = typeof parent[key];

      if (valueType === 'function') {
        derived[key] = wrapFunction(parent[key]);

        if (Object.keys(parent[key]).length > 0) {
          derived[key] = wrapFunctions(parent[key], derived[key]);
        }
      } else if (valueType === 'object') {
        derived[key] = wrapFunctions(parent[key]);
      } else {
        derived[key] = parent[key];
      }
    });
    return derived;
  }

  function wrapFunction(fn) {
    fn = naan.rcurry(fn, function(err, result) {
      self.results.push(result);
    });
    return function() {
      self.operationQueue = [];

      fn.apply(this, [].slice.apply(arguments));

      var operationIds = _.pluck(self.operationQueue, 'id');
      delete self.operationQueue;

      switch (operationIds.length) {
        case  0: return undefined;
        case  1: return operationIds[0];
        default: return operationIds;
      }
    };
  }

  this.super = new Seraph(options);
  this.__proto__ = wrapFunctions(this.super);
  this.processors = [];
  this.operations = [];
  this.results = [];

  this.super.call = function(operation, processor) {
    operation.id = self.operations.length;
    if (!operation.body) delete operation.body;

    self.operations.push(operation);
    self.processors.push(processor);
    self.operationQueue.push(operation);
  }
}

Seraph.prototype.batch = function(operations, callback) {
  var batchSeraph = new BatchSeraph(this.options);
  operations(batchSeraph);

  var op = this.operation('batch', 'POST', batchSeraph.operations);
  this.call(op, function(err, results) {
    if (err) {
      return callback(err);
    }

    results.forEach(function(result) {
      batchSeraph.processors[result.id](null, result.body || {});
    });

    callback(null, batchSeraph.results);
  });
};

module.exports = function(options) {
  return new Seraph(options);
};
<commit_msg>Neo4j-1.8M04 drops parallel relationship delete requests BUT gives OK back.  Sometimes it also gets into a corrupt state and must be restarted.<commit_after>/* -*- Mode: Javascript; js-indent-level: 2 -*- */

var naan = require('naan');
var async = require('async');
var request = require('request');
var _ = require('underscore');
var util = require('util');

var defaultOptions = {
    // Location of the server
    endpoint: 'http://localhost:7474'

    // The key to use when inserting an id into objects.
  , id: 'id'
}, optionKeys = Object.keys(defaultOptions);

// Bind all functions of an object to a context
var bindAllTo = function(context, all) {
  return _.functions(all).reduce(function(bound, key) {
    bound[key] = all[key].bind(context);
    return bound;
  }, _.clone(all));
}

function Seraph(options) {
  if (typeof options === 'string') {
    options = { endpoint: options };
  };
  this.options = _.extend({}, defaultOptions, options);

  _.bindAll(this);

  this.node = bindAllTo(this, require('./node'));
  this.rel = bindAllTo(this, require('./relationship'));
  var indexGeneric = bindAllTo(this, require('./index'));

  // Alias & curry seraph.index on seraph.node & seraph.rel
  this.node.index = naan.curry(indexGeneric.add, 'node');
  this.rel.index = naan.curry(indexGeneric.add, 'relationship');
  naan.ecrock(this.node.index, indexGeneric, naan.curry, 'node');
  naan.ecrock(this.rel.index, indexGeneric, naan.curry, 'relationship');

  _.extend(this, this.node);
}

/**
 * Create an operation that can later be passed to call().
 *
 * Path is relative to the service endpoint - `node` gets
 * transformed to `<options.endpoint>/data/db/node`.
 *
 * If `method` is not supplied, it will default GET, unless `data`
 * is supplied, in which case it will default to 'POST'.
 *
 * seraph#operation(opts, path, [method='get'], [data]);
 */
Seraph.prototype.operation = function(path, method, data) {
  // Get args in the right order
  if (typeof data === 'undefined') {
    data = null;
  }
  if (typeof method === 'object') {
    data = method;
    method = 'POST';
  }
  if (typeof method === 'undefined') {
    method = 'GET';
  }

  // Ensure we have a usable HTTP verb.
  if (typeof method !== 'string') {
    throw new Error('Invalid HTTP Verb - ' + method);
  } else {
    method = method.toUpperCase();
  }

  return {
    'method': method,
    'to'    : path,
    'body'  : data
  };
};

/**
 * Like `async.map`, run `fn` once per element of `params`.  Unlike
 * `async.map`, throttle this through an `async.queue`.
 * `done(err, data)` will be called on completion, where `data`
 * is the result from each of the function calls, in the exact same
 * order as in the `params` array.
 */
Seraph.prototype.throttleMap = function(params, fn, done) {
  var dead = false;
  var results = [];
  var q = async.queue(function worker(task, callback) {
    if (dead) return;
    fn(task, callback);
  }, 1);
  q.drain = function () {
    if (dead) return;
    done(null, results);
  };
  params.forEach(function (param, idx) {
    q.push(param, function (err, data) {
      if (dead) return;
      if (err) {
        dead = true;
        done(err);
      }
      results[idx] = data;
    });
  });
};

/**
 * Function to call an HTTP request to the rest service.
 *
 * Requires an operation object of form:
 *   { method: 'PUT'|'POST'|'GET'|'DELETE'
 *   , to    : path,
 *   , body  : object }
 *
 * Operation objects are easily created by seraph#operation.
 *
 * seraph#call(operation, callback);
 */
Seraph.prototype.call = function(operation, callback) {
  // Ensure callback is callable. Throw instead of calling back if none.
  if (typeof callback !== 'function') {
    callback = function(err) {
      if (err) throw err;
    }
  }

  var requestOpts = {
    uri: this.options.endpoint + '/db/data/' + operation.to,
    method: operation.method,
    headers: { 'Accept': 'application/json' }
  };

  if (operation.body) requestOpts.json = operation.body;
  callback = _.bind(callback, this);

  // Allows mocking
  (this._request || request)(requestOpts, function(err, response, body) {
    if (err) {
      callback(err);
    } else if (response.statusCode < 200 || response.statusCode >= 300) {
      callback(body || response.statusCode);
    } else {
      if (typeof body === 'string') {
        try {
          body = JSON.parse(body);
        } catch (e) {
          return callback(e);
        }
      }

      callback(null, body, response);
    }
  });
};

/**
 * If `obj` is an object, return the value of key <options.id>. Otherwise,
 * return `obj`.
 *
 * If `requireData` is truthy, `obj` must be an object, otherwise undefined is
 * returned.
 */
Seraph.prototype._getId = function(obj, requireData) {
  if (requireData) {
    return typeof obj === 'object' ? obj[this.options.id] : undefined;
  } else {
    return typeof obj === 'object' ? obj[this.options.id] : obj;
  }
};

/**
 * Take the end off a url and parse it as an int
 */
Seraph.prototype._extractId = function(location) {
  var matches = location.match(/\/(\d+)$/);
  if (!matches) {
    return null;
  }

  return parseInt(matches[1], 10);
};

/**
 * Infer whether or not the given object is a node
 */
Seraph.nodeFlags = [
  'outgoing_relationships',
  'incoming_relationships',
  'all_relationships',
  'data',
  'properties',
  'self'
];
Seraph.prototype._isNode = function(node) {
  if (!node || typeof node !== 'object') {
    return false;
  }

  var inNode = node.hasOwnProperty.bind(node);
  return Seraph.nodeFlags.every(inNode) &&
         typeof node.data === 'object';
};

/**
 * Infer whether or not the given object is a relationship
 */
Seraph.relationshipFlags = [
  'start',
  'data',
  'self',
  'properties',
  'end'
];
Seraph.prototype._isRelationship = function(rel) {
  if (!rel || typeof rel !== 'object') {
    return false;
  }

  var inRelationship = rel.hasOwnProperty.bind(rel);
  return Seraph.relationshipFlags.every(inRelationship) &&
         typeof rel.data === 'object';
};

/**
 * Returns the url to an entity given an id
 */
Seraph.prototype._location = function(type, id) {
  return util.format('%s/data/db/%s/%d', this.options.endpoint, type, id);
};

/**
 * Create a relationship object from the given relationship data returned from
 * the neo4j server
 */
Seraph.prototype._createRelationshipObject = function(relationshipData) {
  var relationshipObj = {
    start: this._extractId(relationshipData.start),
    end: this._extractId(relationshipData.end),
    type: relationshipData.type,
    properties: relationshipData.data
  };

  relationshipObj[this.options.id] = this._extractId(relationshipData.self);

  return relationshipObj;
};

/**
 * Create a node object from the given node data return from the neo4j server
 */
Seraph.prototype._createNodeObject = function(nodeData) {
  var nodeObj = nodeData.data || {};
  nodeObj[this.options.id] = this._extractId(nodeData.self);

  return nodeObj;
};

  /**
   * Perform a cypher query. Maps to POST cypher
   */
Seraph.prototype.queryRaw = function(query, params, callback) {
  if (typeof query !== 'string') {
    return callback(new Error('Invalid Query'));
  }
  if (typeof params !== 'object') {
    if (typeof params === 'function') {
      callback = params;
    }
    params = {};
  }

  query = { query: query, params: params };
  var op = this.operation('cypher', query);
  this.call(op, function(err, result) {
    if (err) {
      callback(err);
    } else {
      callback(null, result);
    }
  });
};

/**
 * Perform a cypher query and map the columns and results together.
 */
Seraph.prototype.query = function(query, params, callback) {
  if (typeof params !== 'object') {
    if (typeof params === 'function') {
      callback = params;
    }
    params = {};
  }

  var self = this;
  this.queryRaw(query, params, function(err, result) {
    if (err) {
      return callback(err);
    }

    var namedResults = result.data.map(function(row) {
      return result.columns.reduce(function(rowObj, columnName, columnIndex) {
        var resultItem = row[columnIndex];
        function extractAttributes(item) {
          if (self._isNode(item))
            return self._createNodeObject(item);
          else if (self._isRelationship(item))
            return self._createRelationshipObject(item);
          return item;
        }
        if (Array.isArray(resultItem))
          rowObj[columnName] = resultItem.map(extractAttributes);
        else
          rowObj[columnName] = extractAttributes(resultItem);

        return rowObj;
      }, {});
    });

    if (result.columns.length === 1) {
      namedResults = namedResults.map(function(namedResult) {
        return namedResult[result.columns[0]];
      });
    }

    callback(null, namedResults);
  });
};

function BatchSeraph(options) {
  var self = this;

  function wrapFunctions(parent, target) {
    var derived = target || {};
    Object.keys(parent).forEach(function(key) {
      var valueType = typeof parent[key];

      if (valueType === 'function') {
        derived[key] = wrapFunction(parent[key]);

        if (Object.keys(parent[key]).length > 0) {
          derived[key] = wrapFunctions(parent[key], derived[key]);
        }
      } else if (valueType === 'object') {
        derived[key] = wrapFunctions(parent[key]);
      } else {
        derived[key] = parent[key];
      }
    });
    return derived;
  }

  function wrapFunction(fn) {
    fn = naan.rcurry(fn, function(err, result) {
      self.results.push(result);
    });
    return function() {
      self.operationQueue = [];

      fn.apply(this, [].slice.apply(arguments));

      var operationIds = _.pluck(self.operationQueue, 'id');
      delete self.operationQueue;

      switch (operationIds.length) {
        case  0: return undefined;
        case  1: return operationIds[0];
        default: return operationIds;
      }
    };
  }

  this.super = new Seraph(options);
  this.__proto__ = wrapFunctions(this.super);
  this.processors = [];
  this.operations = [];
  this.results = [];

  this.super.call = function(operation, processor) {
    operation.id = self.operations.length;
    if (!operation.body) delete operation.body;

    self.operations.push(operation);
    self.processors.push(processor);
    self.operationQueue.push(operation);
  }
}

Seraph.prototype.batch = function(operations, callback) {
  var batchSeraph = new BatchSeraph(this.options);
  operations(batchSeraph);

  var op = this.operation('batch', 'POST', batchSeraph.operations);
  this.call(op, function(err, results) {
    if (err) {
      return callback(err);
    }

    results.forEach(function(result) {
      batchSeraph.processors[result.id](null, result.body || {});
    });

    callback(null, batchSeraph.results);
  });
};

module.exports = function(options) {
  return new Seraph(options);
};
<|endoftext|>


<commit_before>const Ajv = require('ajv');
const {
  Map,
  OrderedMap,
  Range,
} = require('immutable');
const math   = require('mathjs');
const moment = require('moment');

const Ratio = require('./ratio');

class Series {
  constructor(options = {}) {
    const now      = moment().startOf('second');
    const defaults = {
      from    : moment(now).subtract(1, 'hour').toISOString(),
      until   : now.toISOString(),
      interval: 1 * 60, // seconds
    };
    const schema = {
      $schema   : 'http://json-schema.org/schema#',
      type      : 'object',
      properties: {
        from    : {type: ['integer', 'string'], format: 'date-time', default: defaults.from },
        until   : {type: ['integer', 'string'], format: 'date-time', default: defaults.until},
        interval: {type: 'integer', default: defaults.interval},
      },
      additionalProperties: false,
    };
    const ajv     = new Ajv({useDefaults: true});
    const isValid = ajv.validate(schema, options);
    if (!isValid) {
      const error = ajv.errors[0];
      throw Error(`options${error.dataPath} ${error.message}`);
    }

    this.from     = moment(options.from );
    this.until    = moment(options.until);
    this.interval = moment.duration(options.interval, 'seconds');
  }

  _trigonometric(func, options = {}) {
    const defaults = {
      keyName: 'value',

      coefficient: 1.0,
      constant   : 0.0,
      period     : 1 * 60 * 60, // seconds
    };
    const schema = {
      $schema   : 'http://json-schema.org/schema#',
      type: 'object',
      properties: {
        keyName: {type: 'string', default: defaults.keyName},

        coefficient: {type: 'number', default: defaults.coefficient},
        constant   : {type: 'number', default: defaults.constant   },
        period     : {type: 'integer', default: defaults.period},
      },
      additionalProperties: false,
    }
    const ajv     = new Ajv({useDefaults: true});
    const isValid = ajv.validate(schema, options);
    if (!isValid) {
      const error = ajv.errors[0];
      throw Error(`options${error.dataPath} ${error.message}`);
    }

    const scale = 2 * Math.PI / options.period;
    return this._range()
      .reduce((map, t) => map.set(t, func(t * scale)), OrderedMap())
      .map((v) => options.coefficient * v + options.constant)
      .map((v) => math.round(v, 2))
      .map((v, t) => this._toElem(t, options.keyName, v))
      .toList()
      .toJS();
  }

  cos(options) {
    return this._trigonometric(Math.cos, options);
  }

  sin(options) {
    return this._trigonometric(Math.sin, options);
  }

  ratio(params, options = {}) {
    const ratio = new Ratio(params);
    const schema = {
      type      : 'object',
      properties: {
        keyName: {type: 'string', default: 'value'},
      },
      additionalProperties: false,
    };
    const ajv     = new Ajv({useDefaults: true});
    const isValid = ajv.validate(schema, options);
    if (!isValid) {
      const error = ajv.errors[0];
      throw Error(`options${error.dataPath} ${error.message}`);
    }

    return this._range()
      .map((t) => this._toElem(t, options.keyName, ratio.sample()))
      .toJS();
  }

  _range() {
    return Range(this.from.unix(), this.until.unix() + 1, this.interval.asSeconds());
  }

  _toElem(unix, keyName, value) {
    return Map({timestamp: moment(unix * 1000).toISOString()}).set(keyName, value);
  }
}

module.exports = Series;
<commit_msg>Do not use OrderedMap<commit_after>const Ajv = require('ajv');
const {
  Map,
  Range,
} = require('immutable');
const math   = require('mathjs');
const moment = require('moment');

const Ratio = require('./ratio');

class Series {
  constructor(options = {}) {
    const now      = moment().startOf('second');
    const defaults = {
      from    : moment(now).subtract(1, 'hour').toISOString(),
      until   : now.toISOString(),
      interval: 1 * 60, // seconds
    };
    const schema = {
      $schema   : 'http://json-schema.org/schema#',
      type      : 'object',
      properties: {
        from    : {type: ['integer', 'string'], format: 'date-time', default: defaults.from },
        until   : {type: ['integer', 'string'], format: 'date-time', default: defaults.until},
        interval: {type: 'integer', default: defaults.interval},
      },
      additionalProperties: false,
    };
    const ajv     = new Ajv({useDefaults: true});
    const isValid = ajv.validate(schema, options);
    if (!isValid) {
      const error = ajv.errors[0];
      throw Error(`options${error.dataPath} ${error.message}`);
    }

    this.from     = moment(options.from );
    this.until    = moment(options.until);
    this.interval = moment.duration(options.interval, 'seconds');
  }

  _trigonometric(func, options = {}) {
    const defaults = {
      keyName: 'value',

      coefficient: 1.0,
      constant   : 0.0,
      period     : 1 * 60 * 60, // seconds
    };
    const schema = {
      $schema   : 'http://json-schema.org/schema#',
      type: 'object',
      properties: {
        keyName: {type: 'string', default: defaults.keyName},

        coefficient: {type: 'number', default: defaults.coefficient},
        constant   : {type: 'number', default: defaults.constant   },
        period     : {type: 'integer', default: defaults.period},
      },
      additionalProperties: false,
    }
    const ajv     = new Ajv({useDefaults: true});
    const isValid = ajv.validate(schema, options);
    if (!isValid) {
      const error = ajv.errors[0];
      throw Error(`options${error.dataPath} ${error.message}`);
    }

    const scale = 2 * Math.PI / options.period;
    return this._range()
      .map((unix) => {
        const value   = options.coefficient * func(unix * scale) + options.constant;
        const rounded = math.round(value, 2);
        return this._toElem(unix, options.keyName, rounded);
      })
      .toJSON();
  }

  cos(options) {
    return this._trigonometric(Math.cos, options);
  }

  sin(options) {
    return this._trigonometric(Math.sin, options);
  }

  ratio(params, options = {}) {
    const ratio = new Ratio(params);
    const schema = {
      type      : 'object',
      properties: {
        keyName: {type: 'string', default: 'value'},
      },
      additionalProperties: false,
    };
    const ajv     = new Ajv({useDefaults: true});
    const isValid = ajv.validate(schema, options);
    if (!isValid) {
      const error = ajv.errors[0];
      throw Error(`options${error.dataPath} ${error.message}`);
    }

    return this._range()
      .map((unix) => this._toElem(unix, options.keyName, ratio.sample()))
      .toJSON();
  }

  _range() {
    return Range(this.from.unix(), this.until.unix() + 1, this.interval.asSeconds());
  }

  _toElem(unix, keyName, value) {
    return Map({timestamp: moment(unix * 1000).toISOString()}).set(keyName, value).toJSON();
  }
}

module.exports = Series;
<|endoftext|>


<commit_before>'use strict';

var path = require('path');
var http = require('http');
var browserify = require('browserify');
var debug = require('debug')('sslr');
var engineIO = require('engine.io');

function resolveOptions(opts) {
  var optName;
  var options = {
    port: '49000'
  };

  for (optName in opts) {
    options[optName] =  opts[optName];
  }

  return options;
}

function broadcastMessage(wsServer, message, data) {
  var clientId;
  var clientsHash = wsServer.clients;
  var msgPacket = JSON.stringify({ message: message, data: data });

  for (clientId in clientsHash) {
    clientsHash[clientId].send(msgPacket);
  }

  debug('notified ' + wsServer.clientsCount + ' clients');
}

function Server(opts) {
  if (!(this instanceof Server)) {
    return new Server(opts);
  }

  this.options = resolveOptions(opts);
  this.httpServer = null;
  this.wsServer = null;
}

Server.prototype.start = function (callback) {
  if ('function' !== typeof callback) {
    callback = function () {};
  }

  if (this.wsServer !== null) {
    callback(new Error('Server must be stopped before starting again'));
    return;
  }

  this.httpServer = http.createServer(function (req, res) {
    var browserifyInst, scriptStream;

    switch (req.url) {
      case '/require-module':
        browserifyInst = browserify();
        browserifyInst.require(path.join(__dirname, '/clients/require-module.js'), { expose: 'sslr' });
        scriptStream = browserifyInst.bundle();
      break;
      default:
    }

    if (scriptStream) {
      res.writeHead(200, {
        'Content-Type': 'application/javascript'
      });

      scriptStream.pipe(res, { end: false });
      scriptStream.on('end', function () {
        res.end();
      });
    } else {
      res.writeHead(501, 'not implemented');
      res.end();
    }
  });

  this.httpServer.listen(this.options.port);
  this.wsServer = new engineIO.attach(this.httpServer, this.options);
  callback();
};

Server.prototype.stop = function (callback) {
  if ('function' !== typeof callback) {
    callback = function () {};
  }

  if (this.wsServer) {
    this.wsServer.close();
    this.httpServer.close();
    this.wsServer = null;
    this.httpServer = null;
    callback();
  } else {
    callback(new Error('Server is not started'));
  }
};

Server.prototype.notifyReload = function (callback) {
  if ('function' !== typeof callback) {
    callback = function () {};
  }

  if (this.wsServer) {
    debug('notifying connected clients');
    broadcastMessage(this.wsServer, 'reload', { type: '*' });
    callback();
  } else {
    callback(new Error('Server is not started'));
  }
};

module.exports = Server;
<commit_msg>Updated name of the browserify exported module<commit_after>'use strict';

var path = require('path');
var http = require('http');
var browserify = require('browserify');
var debug = require('debug')('u-lr');
var engineIO = require('engine.io');

function resolveOptions(opts) {
  var optName;
  var options = {
    port: '49000'
  };

  for (optName in opts) {
    options[optName] =  opts[optName];
  }

  return options;
}

function broadcastMessage(wsServer, message, data) {
  var clientId;
  var clientsHash = wsServer.clients;
  var msgPacket = JSON.stringify({ message: message, data: data });

  for (clientId in clientsHash) {
    clientsHash[clientId].send(msgPacket);
  }

  debug('notified ' + wsServer.clientsCount + ' clients');
}

function Server(opts) {
  if (!(this instanceof Server)) {
    return new Server(opts);
  }

  this.options = resolveOptions(opts);
  this.httpServer = null;
  this.wsServer = null;
}

Server.prototype.start = function (callback) {
  if ('function' !== typeof callback) {
    callback = function () {};
  }

  if (this.wsServer !== null) {
    callback(new Error('Server must be stopped before starting again'));
    return;
  }

  this.httpServer = http.createServer(function (req, res) {
    var browserifyInst, scriptStream;

    switch (req.url) {
      case '/require-module':
        browserifyInst = browserify();
        browserifyInst.require(path.join(__dirname, '/clients/require-module.js'), { expose: 'u-lr' });
        scriptStream = browserifyInst.bundle();
      break;
      default:
    }

    if (scriptStream) {
      res.writeHead(200, {
        'Content-Type': 'application/javascript'
      });

      scriptStream.pipe(res, { end: false });
      scriptStream.on('end', function () {
        res.end();
      });
    } else {
      res.writeHead(501, 'not implemented');
      res.end();
    }
  });

  this.httpServer.listen(this.options.port);
  this.wsServer = new engineIO.attach(this.httpServer, this.options);
  callback();
};

Server.prototype.stop = function (callback) {
  if ('function' !== typeof callback) {
    callback = function () {};
  }

  if (this.wsServer) {
    this.wsServer.close();
    this.httpServer.close();
    this.wsServer = null;
    this.httpServer = null;
    callback();
  } else {
    callback(new Error('Server is not started'));
  }
};

Server.prototype.notifyReload = function (callback) {
  if ('function' !== typeof callback) {
    callback = function () {};
  }

  if (this.wsServer) {
    debug('notifying connected clients');
    broadcastMessage(this.wsServer, 'reload', { type: '*' });
    callback();
  } else {
    callback(new Error('Server is not started'));
  }
};

module.exports = Server;
<|endoftext|>


<commit_before>/*
Returns and object of the form {err_code, msg}
Where err_code is 0 only if the auth was valid
msg contains the authentificator if it was valid
and an error message if it wasn't
*/
function is_valid_auth(xml)
{
    errcode = xml.getElementsByTagName("error_num");
    if(errcode.length == 0)
    {
        //No errors, return 0 and authenificator
        return {err_code:0, msg:xml.getElementsByTagName("authenticator")[0].childNodes[0].nodeValue}
    }
    else
    {
        //Error occurred, return error code and error message
        return {err_code:xml.getElementsByTagName("error_num")[0].childNodes[0].nodeValue,
                msg:xml.getElementsByTagName("error_msg")[0].childNodes[0].nodeValue}
    }
}

/*
Returns true if the server has given the client work,
returns false otherwise
*/
function has_work(xml)
{
    return (xml.getElementsByTagName("file_info").length > 0)
}

/**
 * Returns the host id if it exists
 * returns null otherwise
 */
function get_host_id_from_scheduler_request(xml)
{
    if(xml.getElementsByTagName("hostid").length == 0)
    {
        return null;
    }
    else
    {
        var e = xml.getElementsByTagName("hostid")[0];
        return e.childNodes[0].nodeValue;
    }
    return
}
<commit_msg>changes to comment format<commit_after>/**
 * Returns and object of the form {err_code, msg}
 * Where err_code is 0 only if the auth was valid
 * msg contains the authentificator if it was valid
 * and an error message if it wasn't
 */
function is_valid_auth(xml)
{
    errcode = xml.getElementsByTagName("error_num");
    if(errcode.length == 0)
    {
        //No errors, return 0 and authenificator
        return {err_code:0, msg:xml.getElementsByTagName("authenticator")[0].childNodes[0].nodeValue}
    }
    else
    {
        //Error occurred, return error code and error message
        return {err_code:xml.getElementsByTagName("error_num")[0].childNodes[0].nodeValue,
                msg:xml.getElementsByTagName("error_msg")[0].childNodes[0].nodeValue}
    }
}

/**
 * Returns true if the server has given the client work,
 * returns false otherwise
 */
function has_work(xml)
{
    return (xml.getElementsByTagName("file_info").length > 0)
}

/**
 * Returns the host id if it exists
 * returns null otherwise
 */
function get_host_id_from_scheduler_request(xml)
{
    if(xml.getElementsByTagName("hostid").length == 0)
    {
        return null;
    }
    else
    {
        var e = xml.getElementsByTagName("hostid")[0];
        return e.childNodes[0].nodeValue;
    }
    return
}
<|endoftext|>


<commit_before>var fs = require('fs');
var path = require('path');
var bodyParser = require('body-parser');
var pjson = require('./package.json');
var app = new (require('express'))()
var port = 3000

var webgpioreact = exports;

const DIST_PATH = path.join(__dirname, "../dist");
const JSON_PATH = path.join(__dirname,"../public","json");
const ENCODING = "UTF-8";

//CORS middleware
var allowCrossDomain = function(req, res, next) {
    res.header('Access-Control-Allow-Origin', '*');
    res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
    res.header('Access-Control-Allow-Headers', 'Content-Type');

    next();
}

webgpioreact.start = function() {

	app.use(allowCrossDomain);

	app.use('/', require('express').static(DIST_PATH));

	app.get("/", function(req, res) {
	  res.sendFile(DIST_PATH + '/index.html') // used for dev. load the index.html from the root folder.
	})

	app.get('/boards', function(req, res) {
		var file = fs.readFileSync(path.join(JSON_PATH,"/boards/boards.json"), ENCODING);
		res.send(JSON.parse(file));
	});

	app.get("/boards/:boardName", function(req, res) {
		var boardName = req.params.boardName;
		var file = fs.readFileSync(path.join(JSON_PATH,"/boards/" + boardName + ".json"), ENCODING);
		res.send(JSON.parse(file));
	});

	app.use(bodyParser.json());
	app.use(bodyParser.urlencoded({extended: true}));

	var version = pjson.version; // does not work on heroku.

	app.listen(port, function(error) {
	  if (error) {
	    console.error(error)
	  } else {
	    console.info("==> 🌎  web-gpio-react server v" + version + " listening on port %s. Open up http://localhost:%s/ in your browser.", port, port)
	  }
	})
}<commit_msg>removed package.json import<commit_after>var fs = require('fs');
var path = require('path');
var bodyParser = require('body-parser');
//var pjson = require('./package.json');
var app = new (require('express'))()
var port = 3000

var webgpioreact = exports;

const DIST_PATH = path.join(__dirname, "../dist");
const JSON_PATH = path.join(__dirname,"../public","json");
const ENCODING = "UTF-8";

//CORS middleware
var allowCrossDomain = function(req, res, next) {
    res.header('Access-Control-Allow-Origin', '*');
    res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
    res.header('Access-Control-Allow-Headers', 'Content-Type');

    next();
}

webgpioreact.start = function() {

	app.use(allowCrossDomain);

	app.use('/', require('express').static(DIST_PATH));

	app.get("/", function(req, res) {
	  res.sendFile(DIST_PATH + '/index.html') // used for dev. load the index.html from the root folder.
	})

	app.get('/boards', function(req, res) {
		var file = fs.readFileSync(path.join(JSON_PATH,"/boards/boards.json"), ENCODING);
		res.send(JSON.parse(file));
	});

	app.get("/boards/:boardName", function(req, res) {
		var boardName = req.params.boardName;
		var file = fs.readFileSync(path.join(JSON_PATH,"/boards/" + boardName + ".json"), ENCODING);
		res.send(JSON.parse(file));
	});

	app.use(bodyParser.json());
	app.use(bodyParser.urlencoded({extended: true}));

	var version = "0.1.0" //pjson.version; // does not work on heroku and dist folder.

	app.listen(port, function(error) {
	  if (error) {
	    console.error(error)
	  } else {
	    console.info("==> 🌎  web-gpio-react server v" + version + " listening on port %s. Open up http://localhost:%s/ in your browser.", port, port)
	  }
	})
}<|endoftext|>