<commit_before>
var noteManager = function (options) {
    this.parameters = options;
    this.defaults = {
        option: 'value'
    };
};

noteManager.prototype = {

    init: function() {
      // merge defaults options and user's ones
      this.options = $.extend({}, this.defaults, this.parameters);
      this.plugEvents();
    },

    plugEvents: function() {

      this.displayNotes();
      var that = this;

      $('button[type="submit"]').on('click', function(e){
        e.preventDefault();

        var note = that.getNote($(this).closest('form'));
        that.saveNote(note);
        that.clearForm();
        that.displaySingleNote(note);
      });

      $('#dropbox').on('click', $.proxy(function(){

        var id = this.createJSONfile($.parseJSON(localStorage.getItem("WebNotes")));
        // FIXME permission denied on univ server
        Dropbox.save("https://etudiant.univ-mlv.fr/~odaire/WebNotes/temp/WebNotes-"+id+".json", "WebNotes");

      }, this));

      $('#delete').on('click', $.proxy(function(){
        this.deleteNotes();
      }, this));

      $(document).on('click', '.note button.delete', function(){
        var id = $(this).parent().attr('id');
        id = id.substr(5, id.length);
        that.deleteSingleNote(id);
      });

      $(document).on('click', '.note button.edit', function(){
        var id = $(this).parent().attr('id');
        id = id.substr(5, id.length);
        that.editNote(id);
      });

      // Only when editing a note
      $(document).on('click', '.note button[type="submit"]', function(e){
        e.preventDefault();
        var note = that.getNote($(this).closest('form'));
        that.saveNote(note);

        var id = $(this).closest('form').parent().attr('id');
        id = id.substr(5, id.length);
        that.deleteSingleNote(id);

        that.displaySingleNote(note);
      });

    },

    /******************
      CORE FUNCTIONS
    ******************/

    /**
     * Get form data and return it as a JSON object
     * @param {HTML Object} form   The form generating this note
     * @return {JSON}   Note as JSON object
     */
    getNote: function(form) {
      var title = form.find('.title').val(),
          content = form.find('textarea').val(),
          url = this.containsURL(content);
          today = this.formatDate(),
          date = today[0],
          time = today[1],
          tags = this.formatTags(form.find('.tags').val());

      var note = this.formatNote(title, content, date, time, tags, url);
      return note;
    },

    /**
     * Format note to JSON with form data
     * @param  {string} title     Note title
     * @param  {string} content   Note text content
     * @param  {string} date      Note date
     * @param  {string} time      Note hour
     * @param  {string} tags      Note tags
     * @param  {string} url       URL contained in note
     * @return {JSON}             Note as JSON object
     */
    formatNote: function(title, content, date, time, tags, url) {
      var note = {
            "title": title,
            "content": content,
            "date": date,
            "time": time,
            "tags": tags,
            "url": url,
          };

      return note;
    },

    /**
     * If notes already exist in local storage, add the new one and save
     * else create the object and save it in local storage.
     * @param  {JSON}
     */
    saveNote: function(note) {
      var notes;
      if (localStorage.getItem("WebNotes") === null) {
        notes = [ note ];
        notes = JSON.stringify(notes);
        localStorage.setItem("WebNotes", notes);
      }else{
        notes = $.parseJSON(localStorage.getItem("WebNotes"));
        notes.push(note);
        notes = JSON.stringify(notes);
        localStorage.setItem("WebNotes", notes);
      }
    },

    /**
     * Display all notes
     */
    displayNotes: function() {
      if (localStorage.getItem("WebNotes") !== null) {

        var notes = $.parseJSON(localStorage.getItem("WebNotes"));
        var tags;

        for (var i = notes.length-1 ; i >= 0; i--) {
          for (var j = 0; j < notes[i].tags.length; j++) {
            if (j === 0 ) {
              tags = '' + notes[i].tags[j] + '';
            }else{
              tags = tags + ' ' + notes[i].tags[j] + '';
            }
          }

          $('#main').append(
            '
'+
              '
'+notes[i].title+'
'+
              '
'+notes[i].content+'
'+
              '
'+ tags +'
'+
              ''+notes[i].date+' - '+notes[i].time+''+
              '<button class="edit">Edit</button>'+
              '<button class="delete">Delete</button>'+
            '
'
          );
        }

      }
    },

    /**
     * Display a single note
     * @param {JSON} note
     */
    displaySingleNote: function(note) {
      var tags;
      var notesLength = $.parseJSON(localStorage.getItem("WebNotes")).length;
      notesLength = notesLength-1; // Number of next note

      for (var j = 0; j < note.tags.length; j++) {
          if (j === 0 ) {
            tags = '' + note.tags[j] + '';
          }else{
            tags = tags + ' ' + note.tags[j] + '';
          }
      }

       $('#main').prepend(
            '
'+
              '
'+note.title+'
'+
              '
'+note.content+'
'+
              '
'+ tags +'
'+
              ''+note.date+' - '+note.time+''+
              '<button class="edit">Edit</button>'+
              '<button class="delete">Delete</button>'+
            '
'
        );
    },

    /**
     * Delete all notes
     */
    deleteNotes: function() {
      localStorage.removeItem("WebNotes");
    },

    /**
     * Delete a single note
     * @param  {int} id  ID of the note to be deleted
     */
    deleteSingleNote: function(id) {
      var notes = $.parseJSON(localStorage.getItem("WebNotes"));
      if (id != -1) {
        notes.splice(id, 1);
        notes = JSON.stringify(notes);
        localStorage.setItem("WebNotes", notes);
        $('#note-'+id+'').remove();
      }
    },

    /**
     * Edit a note
     * @param  {int} id ID of the note to be edited
     */
    editNote: function(id) {
      var notes = $.parseJSON(localStorage.getItem("WebNotes"));
      var note = notes[id];

     $('#note-'+id).html(
        '<form>'+
          '<input type="text" class="title" value="'+note.title+'">'+
          '<textarea>'+note.content+'</textarea>'+
          '<input name="tags" class="tags" value="'+note.tags+'" />'+
          '<button type="submit">Save</button>'+
        '</form>'
      );

     $('.tags').tagsInput();
    },

    /******************
      TOOLS FUNCTIONS
    ******************/

    clearForm: function() {
      $('form input.title, form textarea').val('');
      $('div.tagsinput span').remove();
    },

    /**
     * Get current date and time and format it
     * @return {array}    containing current date and hour
     */
    formatDate: function() {
      var today = new Date();
      var dd = today.getDate();
      var mm = today.getMonth()+1; //January is 0!
      var yyyy = today.getFullYear();

      if(dd<10){
          dd='0'+dd;
      }
      if(mm<10){
          mm='0'+mm;
      }

      var h = today.getHours();
      var m = today.getMinutes();
      var s = today.getSeconds();

      today = dd+'/'+mm+'/'+yyyy;

      var time = h + 'h' + m + 'min' + s + 's';

      return [today, time];
    },

    /**
     * Convert a list of tags into an array
     * @param  {string} tags    list of tags
     * @return {array}          array of tags
     */
    formatTags: function(tags) {
      var tagsArray = tags.split(',');

      return tagsArray;
    },

    /**
     * Ajax request to generate a JSON file through a PHP script
     * @param  {JSON} notes    object containing all notes
     */
    createJSONfile: function(notes) {
      // TODO GET unique ID from php and return it
      $.ajax({
        type : "POST",
        url : "json.php",
        dataType : 'json',
        data : {
            json : JSON.stringify(notes)
        },
        error: function(data){
          console.log('Error generating JSON');
          console.log(data);
        },
        success: function(data){
          return data;
        }
      });
    },

    /**
     * Check for an URL inside a string
     * @param  {string} s
     * @return {string}   Matched URL
     */
    containsURL: function(s) {
      var regexp = /(http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/
      if (regexp.exec(s)) {
        return regexp.exec(s)[0];
      };
    },

    /**
     * Test for compatible websites and return a widget or a picture
     * @param  {string} s URL to be tested
     * @return {string}   HTML tags or picture URL
     */
    matchWebsite: function(s) {
      var regexp = /(youtube\.com|youtu\.be|soundcloud\.com|imdb\.com|allocine\.fr)/

      switch (regexp.exec(s)[0]) {
        case 'youtube.com':
        case 'youtu.be':

        break;
        case 'soundcloud.com':
        // FIXME Find out about the client ID
          SC.initialize({
            client_id: 'YOUR_CLIENT_ID'
          });

          var track_url = s;
          SC.oEmbed(track_url, { auto_play: false }, function(oEmbed) {
            return oEmbed.html;
          });
        break;
        case 'imdb.com':

        break;
        case 'allocine.fr':

        break;
      }

    },

};
<commit_msg>SoundCloud widget working !<commit_after>
var noteManager = function (options) {
    this.parameters = options;
    this.defaults = {
        option: 'value'
    };
};

noteManager.prototype = {

    init: function() {
      // merge defaults options and user's ones
      this.options = $.extend({}, this.defaults, this.parameters);
      this.plugEvents();
    },

    plugEvents: function() {

      this.displayNotes();
      var that = this;

      $('button[type="submit"]').on('click', function(e){
        e.preventDefault();

        var note = that.getNote($(this).closest('form'));
        that.saveNote(note);
        that.clearForm();
        that.displaySingleNote(note);
      });

      $('#dropbox').on('click', $.proxy(function(){

        var id = this.createJSONfile($.parseJSON(localStorage.getItem("WebNotes")));
        // FIXME permission denied on univ server
        Dropbox.save("https://etudiant.univ-mlv.fr/~odaire/WebNotes/temp/WebNotes-"+id+".json", "WebNotes");

      }, this));

      $('#delete').on('click', $.proxy(function(){
        this.deleteNotes();
      }, this));

      $(document).on('click', '.note button.delete', function(){
        var id = $(this).parent().attr('id');
        id = id.substr(5, id.length);
        that.deleteSingleNote(id);
      });

      $(document).on('click', '.note button.edit', function(){
        var id = $(this).parent().attr('id');
        id = id.substr(5, id.length);
        that.editNote(id);
      });

      // Only when editing a note
      $(document).on('click', '.note button[type="submit"]', function(e){
        e.preventDefault();
        var note = that.getNote($(this).closest('form'));
        that.saveNote(note);

        var id = $(this).closest('form').parent().attr('id');
        id = id.substr(5, id.length);
        that.deleteSingleNote(id);

        that.displaySingleNote(note);
      });

    },

    /******************
      CORE FUNCTIONS
    ******************/

    /**
     * Get form data and return it as a JSON object
     * @param {HTML Object} form   The form generating this note
     * @return {JSON}   Note as JSON object
     */
    getNote: function(form) {
      var title = form.find('.title').val(),
          content = form.find('textarea').val(),
          url = this.containsURL(content);
          today = this.formatDate(),
          date = today[0],
          time = today[1],
          tags = this.formatTags(form.find('.tags').val());

      var note = this.formatNote(title, content, date, time, tags, url);
      return note;
    },

    /**
     * Format note to JSON with form data
     * @param  {string} title     Note title
     * @param  {string} content   Note text content
     * @param  {string} date      Note date
     * @param  {string} time      Note hour
     * @param  {string} tags      Note tags
     * @param  {string} url       URL contained in note
     * @return {JSON}             Note as JSON object
     */
    formatNote: function(title, content, date, time, tags, url) {
      var note = {
            "title": title,
            "content": content,
            "date": date,
            "time": time,
            "tags": tags,
            "url": url,
          };

      return note;
    },

    /**
     * If notes already exist in local storage, add the new one and save
     * else create the object and save it in local storage.
     * @param  {JSON}
     */
    saveNote: function(note) {
      var notes;
      if (localStorage.getItem("WebNotes") === null) {
        notes = [ note ];
        notes = JSON.stringify(notes);
        localStorage.setItem("WebNotes", notes);
      }else{
        notes = $.parseJSON(localStorage.getItem("WebNotes"));
        notes.push(note);
        notes = JSON.stringify(notes);
        localStorage.setItem("WebNotes", notes);
      }
    },

    /**
     * Display all notes
     */
    displayNotes: function() {
      if (localStorage.getItem("WebNotes") !== null) {

        var notes = $.parseJSON(localStorage.getItem("WebNotes"));
        var tags;

        for (var i = notes.length-1 ; i >= 0; i--) {
          for (var j = 0; j < notes[i].tags.length; j++) {
            if (j === 0 ) {
              tags = '' + notes[i].tags[j] + '';
            }else{
              tags = tags + ' ' + notes[i].tags[j] + '';
            }
          }

          $('#main').append(
            '
'+
              '
'+notes[i].title+'
'+
              '
'+notes[i].content+'
'+
              '
'+ tags +'
'+
              ''+notes[i].date+' - '+notes[i].time+''+
              '<button class="edit">Edit</button>'+
              '<button class="delete">Delete</button>'+
            '
'
          );

          if (notes[i].url) {
            this.generateWidget(i, notes[i].url);
          }
        }

      }
    },

    /**
     * Display a single note
     * @param {JSON} note
     */
    displaySingleNote: function(note) {
      var tags;
      var notesLength = $.parseJSON(localStorage.getItem("WebNotes")).length;
      notesLength = notesLength-1; // Number of next note

      for (var j = 0; j < note.tags.length; j++) {
          if (j === 0 ) {
            tags = '' + note.tags[j] + '';
          }else{
            tags = tags + ' ' + note.tags[j] + '';
          }
      }

       $('#main').prepend(
            '
'+
              '
'+note.title+'
'+
              '
'+note.content+'
'+
              '
'+ tags +'
'+
              ''+note.date+' - '+note.time+''+
              '<button class="edit">Edit</button>'+
              '<button class="delete">Delete</button>'+
            '
'
        );

      if (note.url) {
        this.generateWidget(notesLength, note.url);
      }
    },

    /**
     * Delete all notes
     */
    deleteNotes: function() {
      localStorage.removeItem("WebNotes");
    },

    /**
     * Delete a single note
     * @param  {int} id  ID of the note to be deleted
     */
    deleteSingleNote: function(id) {
      var notes = $.parseJSON(localStorage.getItem("WebNotes"));
      if (id != -1) {
        notes.splice(id, 1);
        notes = JSON.stringify(notes);
        localStorage.setItem("WebNotes", notes);
        $('#note-'+id+'').remove();
      }
    },

    /**
     * Edit a note
     * @param  {int} id ID of the note to be edited
     */
    editNote: function(id) {
      var notes = $.parseJSON(localStorage.getItem("WebNotes"));
      var note = notes[id];

     $('#note-'+id).html(
        '<form>'+
          '<input type="text" class="title" value="'+note.title+'">'+
          '<textarea>'+note.content+'</textarea>'+
          '<input name="tags" class="tags" value="'+note.tags+'" />'+
          '<button type="submit">Save</button>'+
        '</form>'
      );

     $('.tags').tagsInput();
    },

    /******************
      TOOLS FUNCTIONS
    ******************/

    clearForm: function() {
      $('form input.title, form textarea').val('');
      $('div.tagsinput span').remove();
    },

    /**
     * Get current date and time and format it
     * @return {array}    containing current date and hour
     */
    formatDate: function() {
      var today = new Date();
      var dd = today.getDate();
      var mm = today.getMonth()+1; //January is 0!
      var yyyy = today.getFullYear();

      if(dd<10){
          dd='0'+dd;
      }
      if(mm<10){
          mm='0'+mm;
      }

      var h = today.getHours();
      var m = today.getMinutes();
      var s = today.getSeconds();

      today = dd+'/'+mm+'/'+yyyy;

      var time = h + 'h' + m + 'min' + s + 's';

      return [today, time];
    },

    /**
     * Convert a list of tags into an array
     * @param  {string} tags    list of tags
     * @return {array}          array of tags
     */
    formatTags: function(tags) {
      var tagsArray = tags.split(',');

      return tagsArray;
    },

    /**
     * Ajax request to generate a JSON file through a PHP script
     * @param  {JSON} notes    object containing all notes
     */
    createJSONfile: function(notes) {
      // TODO GET unique ID from php and return it
      $.ajax({
        type : "POST",
        url : "json.php",
        dataType : 'json',
        data : {
            json : JSON.stringify(notes)
        },
        error: function(data){
          console.log('Error generating JSON');
          console.log(data);
        },
        success: function(data){
          return data;
        }
      });
    },

    /**
     * Check for an URL inside a string
     * @param  {string} s
     * @return {string}   Matched URL
     */
    containsURL: function(s) {
      var regexp = /(http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/;
      if (regexp.exec(s)) {
        return regexp.exec(s)[0];
      }
    },

    /**
     * Test for compatible websites and return a widget or a picture
     * @param  {int}    id ID of the note containing the url
     * @param  {string} s  URL to be tested
     * @return {string}    HTML tags or picture URL
     */
    generateWidget: function(id, s) {
      var regexp = /(youtube\.com|youtu\.be|soundcloud\.com|imdb\.com|allocine\.fr)/;

      switch (regexp.exec(s)[0]) {
        case 'youtube.com':
        case 'youtu.be':

        break;
        case 'soundcloud.com':
          // FIXME Fidn out about the client id, mandatory ?
          SC.initialize({
            client_id: 'YOUR_CLIENT_ID'
          });

          var track_url = s;
          SC.oEmbed(track_url, { auto_play: false }, function(oEmbed) {
            $('#note-'+id).prepend(oEmbed.html);
          });
        break;
        case 'imdb.com':

        break;
        case 'allocine.fr':

        break;
      }
    },

};
<|endoftext|>


<commit_before>const puppeteer = require('puppeteer');
const fs = require('fs');
const URL = require('url').URL;
const URLParse = require('url').parse;

const [, , ...args] = process.argv;

/**
 * There are two ways for Browsershot to communicate with puppeteer:
 * - By giving a options JSON dump as an argument
 * - Or by providing a temporary file with the options JSON dump,
 *   the path to this file is then given as an argument with the flag -f
 */
const request = args[0].startsWith('-f ')
    ? JSON.parse(fs.readFileSync(new URL(args[0].substring(3))))
    : JSON.parse(args[0]);

const requestsList = [];

const getOutput = async (page, request) => {
    let output;

    if (request.action == 'requestsList') {
        output = JSON.stringify(requestsList);

        return output;
    }

    if (request.action == 'evaluate') {
        output = await page.evaluate(request.options.pageFunction);

        return output;
    }

    output = await page[request.action](request.options);

    return output.toString('base64');
};

const callChrome = async pup => {
    let browser;
    let page;
    let output;
    let remoteInstance;
	const puppet = (pup || puppeteer);

    try {
        if (request.options.remoteInstanceUrl || request.options.browserWSEndpoint ) {
            // default options
            let options = {
                ignoreHTTPSErrors: request.options.ignoreHttpsErrors
            };

            // choose only one method to connect to the browser instance
            if ( request.options.remoteInstanceUrl ) {
                options.browserURL = request.options.remoteInstanceUrl;
            } else if ( request.options.browserWSEndpoint ) {
                options.browserWSEndpoint = request.options.browserWSEndpoint;
            }

            try {
                browser = await puppet.connect( options );

                remoteInstance = true;
            } catch (exception) { /** does nothing. fallbacks to launching a chromium instance */}
        }

        if (!browser) {
            browser = await puppet.launch({
                ignoreHTTPSErrors: request.options.ignoreHttpsErrors,
                executablePath: request.options.executablePath,
                args: request.options.args || [],
                pipe: request.options.pipe || false,
                env: {
                    ...(request.options.env || {}),
                    ...process.env
                },
            });
        }

        page = await browser.newPage();

        if (request.options && request.options.disableJavascript) {
            await page.setJavaScriptEnabled(false);
        }

        await page.setRequestInterception(true);

        page.on('request', request => {
            requestsList.push({
                url: request.url(),
            });
            request.continue();
        });

        if (request.options && request.options.disableImages) {
            page.on('request', request => {
                if (request.resourceType() === 'image')
                    request.abort();
                else
                    request.continue();
            });
        }

        if (request.options && request.options.blockDomains) {
            var domainsArray = JSON.parse(request.options.blockDomains);
            page.on('request', request => {
                const hostname = URLParse(request.url()).hostname;
                domainsArray.forEach(function(value){
                    if (hostname.indexOf(value) >= 0) request.abort();
                });
                request.continue();
            });
        }

        if (request.options && request.options.blockUrls) {
            var urlsArray = JSON.parse(request.options.blockUrls);
            page.on('request', request => {
                urlsArray.forEach(function(value){
                    if (request.url().indexOf(value) >= 0) request.abort();
                });
                request.continue();
            });
        }

        if (request.options && request.options.dismissDialogs) {
            page.on('dialog', async dialog => {
                await dialog.dismiss();
            });
        }

        if (request.options && request.options.userAgent) {
            await page.setUserAgent(request.options.userAgent);
        }

        if (request.options && request.options.device) {
            const devices = puppeteer.devices;
            const device = devices[request.options.device];
            await page.emulate(device);
        }

        if (request.options && request.options.emulateMedia) {
            await page.emulateMediaType(request.options.emulateMedia);
        }

        if (request.options && request.options.viewport) {
            await page.setViewport(request.options.viewport);
        }

        if (request.options && request.options.extraHTTPHeaders) {
            await page.setExtraHTTPHeaders(request.options.extraHTTPHeaders);
        }

        if (request.options && request.options.authentication) {
            await page.authenticate(request.options.authentication);
        }

        if (request.options && request.options.cookies) {
            await page.setCookie(...request.options.cookies);
        }

        if (request.options && request.options.timeout) {
            await page.setDefaultNavigationTimeout(request.options.timeout);
        }

        const requestOptions = {};

        if (request.options && request.options.networkIdleTimeout) {
            requestOptions.waitUntil = 'networkidle';
            requestOptions.networkIdleTimeout = request.options.networkIdleTimeout;
        } else if (request.options && request.options.waitUntil) {
            requestOptions.waitUntil = request.options.waitUntil;
        }

        await page.goto(request.url, requestOptions);

        if (request.options && request.options.disableImages) {
            await page.evaluate(() => {
                let images = document.getElementsByTagName('img');
                while (images.length > 0) {
                    images[0].parentNode.removeChild(images[0]);
                }
            });
        }

        if (request.options && request.options.types) {
            for (let i = 0, len = request.options.types.length; i < len; i++) {
                let typeOptions = request.options.types[i];
                await page.type(typeOptions.selector, typeOptions.text, {
                    'delay': typeOptions.delay,
                });
            }
        }

        if (request.options && request.options.selects) {
            for (let i = 0, len = request.options.selects.length; i < len; i++) {
                let selectOptions = request.options.selects[i];
                await page.select(selectOptions.selector, selectOptions.value);
            }
        }

        if (request.options && request.options.clicks) {
            for (let i = 0, len = request.options.clicks.length; i < len; i++) {
                let clickOptions = request.options.clicks[i];
                await page.click(clickOptions.selector, {
                    'button': clickOptions.button,
                    'clickCount': clickOptions.clickCount,
                    'delay': clickOptions.delay,
                });
            }
        }

        if (request.options && request.options.addStyleTag) {
            await page.addStyleTag(JSON.parse(request.options.addStyleTag));
        }

        if (request.options && request.options.addScriptTag) {
            await page.addScriptTag(JSON.parse(request.options.addScriptTag));
        }

        if (request.options.delay) {
            await page.waitFor(request.options.delay);
        }

        if (request.options.selector) {
            const element = await page.$(request.options.selector);
            if (element === null) {
                throw {type: 'ElementNotFound'};
            }

            request.options.clip = await element.boundingBox();
        }

        if (request.options.function) {
            let functionOptions = {
                polling: request.options.functionPolling,
                timeout: request.options.functionTimeout || request.options.timeout
            };
            await page.waitForFunction(request.options.function, functionOptions);
        }

        output = await getOutput(page, request);

        if (!request.options.path) {
            console.log(output);
        }

        if (remoteInstance && page) {
            await page.close();
        }

        await remoteInstance ? browser.disconnect() : browser.close();
    } catch (exception) {
        if (browser) {

            if (remoteInstance && page) {
                await page.close();
            }

            await remoteInstance ? browser.disconnect() : browser.close();
        }

        console.error(exception);

        if (exception.type === 'ElementNotFound') {
            process.exit(2);
        }

        process.exit(1);
    }
};

if (require.main === module) {
	callChrome();
}

exports.callChrome = callChrome;
<commit_msg>replace waitFor with waitForTimeout as its deprecated (#452)<commit_after>const puppeteer = require('puppeteer');
const fs = require('fs');
const URL = require('url').URL;
const URLParse = require('url').parse;

const [, , ...args] = process.argv;

/**
 * There are two ways for Browsershot to communicate with puppeteer:
 * - By giving a options JSON dump as an argument
 * - Or by providing a temporary file with the options JSON dump,
 *   the path to this file is then given as an argument with the flag -f
 */
const request = args[0].startsWith('-f ')
    ? JSON.parse(fs.readFileSync(new URL(args[0].substring(3))))
    : JSON.parse(args[0]);

const requestsList = [];

const getOutput = async (page, request) => {
    let output;

    if (request.action == 'requestsList') {
        output = JSON.stringify(requestsList);

        return output;
    }

    if (request.action == 'evaluate') {
        output = await page.evaluate(request.options.pageFunction);

        return output;
    }

    output = await page[request.action](request.options);

    return output.toString('base64');
};

const callChrome = async pup => {
    let browser;
    let page;
    let output;
    let remoteInstance;
	const puppet = (pup || puppeteer);

    try {
        if (request.options.remoteInstanceUrl || request.options.browserWSEndpoint ) {
            // default options
            let options = {
                ignoreHTTPSErrors: request.options.ignoreHttpsErrors
            };

            // choose only one method to connect to the browser instance
            if ( request.options.remoteInstanceUrl ) {
                options.browserURL = request.options.remoteInstanceUrl;
            } else if ( request.options.browserWSEndpoint ) {
                options.browserWSEndpoint = request.options.browserWSEndpoint;
            }

            try {
                browser = await puppet.connect( options );

                remoteInstance = true;
            } catch (exception) { /** does nothing. fallbacks to launching a chromium instance */}
        }

        if (!browser) {
            browser = await puppet.launch({
                ignoreHTTPSErrors: request.options.ignoreHttpsErrors,
                executablePath: request.options.executablePath,
                args: request.options.args || [],
                pipe: request.options.pipe || false,
                env: {
                    ...(request.options.env || {}),
                    ...process.env
                },
            });
        }

        page = await browser.newPage();

        if (request.options && request.options.disableJavascript) {
            await page.setJavaScriptEnabled(false);
        }

        await page.setRequestInterception(true);

        page.on('request', request => {
            requestsList.push({
                url: request.url(),
            });
            request.continue();
        });

        if (request.options && request.options.disableImages) {
            page.on('request', request => {
                if (request.resourceType() === 'image')
                    request.abort();
                else
                    request.continue();
            });
        }

        if (request.options && request.options.blockDomains) {
            var domainsArray = JSON.parse(request.options.blockDomains);
            page.on('request', request => {
                const hostname = URLParse(request.url()).hostname;
                domainsArray.forEach(function(value){
                    if (hostname.indexOf(value) >= 0) request.abort();
                });
                request.continue();
            });
        }

        if (request.options && request.options.blockUrls) {
            var urlsArray = JSON.parse(request.options.blockUrls);
            page.on('request', request => {
                urlsArray.forEach(function(value){
                    if (request.url().indexOf(value) >= 0) request.abort();
                });
                request.continue();
            });
        }

        if (request.options && request.options.dismissDialogs) {
            page.on('dialog', async dialog => {
                await dialog.dismiss();
            });
        }

        if (request.options && request.options.userAgent) {
            await page.setUserAgent(request.options.userAgent);
        }

        if (request.options && request.options.device) {
            const devices = puppeteer.devices;
            const device = devices[request.options.device];
            await page.emulate(device);
        }

        if (request.options && request.options.emulateMedia) {
            await page.emulateMediaType(request.options.emulateMedia);
        }

        if (request.options && request.options.viewport) {
            await page.setViewport(request.options.viewport);
        }

        if (request.options && request.options.extraHTTPHeaders) {
            await page.setExtraHTTPHeaders(request.options.extraHTTPHeaders);
        }

        if (request.options && request.options.authentication) {
            await page.authenticate(request.options.authentication);
        }

        if (request.options && request.options.cookies) {
            await page.setCookie(...request.options.cookies);
        }

        if (request.options && request.options.timeout) {
            await page.setDefaultNavigationTimeout(request.options.timeout);
        }

        const requestOptions = {};

        if (request.options && request.options.networkIdleTimeout) {
            requestOptions.waitUntil = 'networkidle';
            requestOptions.networkIdleTimeout = request.options.networkIdleTimeout;
        } else if (request.options && request.options.waitUntil) {
            requestOptions.waitUntil = request.options.waitUntil;
        }

        await page.goto(request.url, requestOptions);

        if (request.options && request.options.disableImages) {
            await page.evaluate(() => {
                let images = document.getElementsByTagName('img');
                while (images.length > 0) {
                    images[0].parentNode.removeChild(images[0]);
                }
            });
        }

        if (request.options && request.options.types) {
            for (let i = 0, len = request.options.types.length; i < len; i++) {
                let typeOptions = request.options.types[i];
                await page.type(typeOptions.selector, typeOptions.text, {
                    'delay': typeOptions.delay,
                });
            }
        }

        if (request.options && request.options.selects) {
            for (let i = 0, len = request.options.selects.length; i < len; i++) {
                let selectOptions = request.options.selects[i];
                await page.select(selectOptions.selector, selectOptions.value);
            }
        }

        if (request.options && request.options.clicks) {
            for (let i = 0, len = request.options.clicks.length; i < len; i++) {
                let clickOptions = request.options.clicks[i];
                await page.click(clickOptions.selector, {
                    'button': clickOptions.button,
                    'clickCount': clickOptions.clickCount,
                    'delay': clickOptions.delay,
                });
            }
        }

        if (request.options && request.options.addStyleTag) {
            await page.addStyleTag(JSON.parse(request.options.addStyleTag));
        }

        if (request.options && request.options.addScriptTag) {
            await page.addScriptTag(JSON.parse(request.options.addScriptTag));
        }

        if (request.options.delay) {
            await page.waitForTimeout(request.options.delay);
        }

        if (request.options.selector) {
            const element = await page.$(request.options.selector);
            if (element === null) {
                throw {type: 'ElementNotFound'};
            }

            request.options.clip = await element.boundingBox();
        }

        if (request.options.function) {
            let functionOptions = {
                polling: request.options.functionPolling,
                timeout: request.options.functionTimeout || request.options.timeout
            };
            await page.waitForFunction(request.options.function, functionOptions);
        }

        output = await getOutput(page, request);

        if (!request.options.path) {
            console.log(output);
        }

        if (remoteInstance && page) {
            await page.close();
        }

        await remoteInstance ? browser.disconnect() : browser.close();
    } catch (exception) {
        if (browser) {

            if (remoteInstance && page) {
                await page.close();
            }

            await remoteInstance ? browser.disconnect() : browser.close();
        }

        console.error(exception);

        if (exception.type === 'ElementNotFound') {
            process.exit(2);
        }

        process.exit(1);
    }
};

if (require.main === module) {
	callChrome();
}

exports.callChrome = callChrome;
<|endoftext|>


<commit_before>/**
Author: Alex Ball
screeps-scripts

scripts for the JavaScript-based MMO Screeps.
*/

require('tower').runTowerLogic();

const spawnFunctions = require('spawn');
const roomFunctions = require('room');

const roleHarvester = require('role.harvester');
const roleUpgrader = require('role.upgrader');
const roleBuilder = require('role.builder');
const roleMiner = require('role.miner');
const roleCourier = require('role.courier');

const roles = {
  harvester: roleHarvester,
  upgrader: roleUpgrader,
  builder: roleBuilder,
  miner: roleMiner,
  courier: roleCourier,
};

/**Diagnostic and utility functions*/
const FUNCTIONS = require('functions');

//Begin main loop.
module.exports.loop = function() {
  FUNCTIONS.respawn();
  FUNCTIONS.clearDeadCreepMemory();

  let creepsOfRole = {};

  for (let roleName in roles) {
    creepsOfRole[roleName] = {};
  }

  for (let name in Game.creeps) {
    let creep = Game.creeps[name];
    if (roles[creep.memory.role]) {
      creepsOfRole[creep.memory.role][name] = creep.id;
      roles[creep.memory.role].run(creep);
    }
  }

  let spawn = Game.spawns.Spawn1;
  for (let roomName in Game.rooms) {
    let room = Game.rooms[roomName];

    FUNCTIONS.checkForLevelUp(room);

    let spawns = room.find(FIND_MY_STRUCTURES, {
      filter: {
        structureType: STRUCTURE_SPAWN
      }
    });

    let spawn = spawns[0];

    roomFunctions.checkForSources(room);
    let sourceIdMissingMiner = roomFunctions.findSourceIdMissingMiner(room);

    if (_.size(Game.creeps) < 2) {
      spawnFunctions.createCreepWithRole(spawn, 'harvester');
    } else if (_.size(creepsOfRole.courier) < 1) {
      spawn.createCreep([CARRY, CARRY, CARRY, CARRY, CARRY, MOVE], undefined, {
        role: "courier"
      });
    } else if (sourceIdMissingMiner) {
      roomFunctions.buildMiner(room, sourceIdMissingMiner, spawn);
    } else if (_.size(creepsOfRole.courier) < 3) {
      spawn.createCreep([CARRY, CARRY, CARRY, CARRY, CARRY, MOVE], undefined, {
        role: "courier"
      });
    } else if (_.size(creepsOfRole.builder) < 2) {
      spawnFunctions.createCreepWithRole(spawn, 'builder');
    } else if (_.size(creepsOfRole.upgrader) < 1) {
      spawnFunctions.createCreepWithRole(spawn, 'upgrader');
    }

    spawnFunctions.displayCreateCreepVisual(spawn);

    if (!Memory.flags[room.name + " upContainer"]) {
      roomFunctions.placeUpgraderContainer(room, spawn.pos);
    }

    roomFunctions.addExtensionsToRoom(room, spawn.pos);
  }
};
<commit_msg>Changed courier body to include more move parts for faster movement on plains.<commit_after>/**
Author: Alex Ball
screeps-scripts

scripts for the JavaScript-based MMO Screeps.
*/

require('tower').runTowerLogic();

const spawnFunctions = require('spawn');
const roomFunctions = require('room');

const roleHarvester = require('role.harvester');
const roleUpgrader = require('role.upgrader');
const roleBuilder = require('role.builder');
const roleMiner = require('role.miner');
const roleCourier = require('role.courier');

const roles = {
  harvester: roleHarvester,
  upgrader: roleUpgrader,
  builder: roleBuilder,
  miner: roleMiner,
  courier: roleCourier,
};

/**Diagnostic and utility functions*/
const FUNCTIONS = require('functions');

//Begin main loop.
module.exports.loop = function() {
  FUNCTIONS.respawn();
  FUNCTIONS.clearDeadCreepMemory();

  let creepsOfRole = {};

  for (let roleName in roles) {
    creepsOfRole[roleName] = {};
  }

  for (let name in Game.creeps) {
    let creep = Game.creeps[name];
    if (roles[creep.memory.role]) {
      creepsOfRole[creep.memory.role][name] = creep.id;
      roles[creep.memory.role].run(creep);
    }
  }

  let spawn = Game.spawns.Spawn1;
  for (let roomName in Game.rooms) {
    let room = Game.rooms[roomName];

    FUNCTIONS.checkForLevelUp(room);

    let spawns = room.find(FIND_MY_STRUCTURES, {
      filter: {
        structureType: STRUCTURE_SPAWN
      }
    });

    let spawn = spawns[0];

    roomFunctions.checkForSources(room);
    let sourceIdMissingMiner = roomFunctions.findSourceIdMissingMiner(room);

    if (_.size(Game.creeps) < 2) {
      spawnFunctions.createCreepWithRole(spawn, 'harvester');
    } else if (_.size(creepsOfRole.courier) < 1) {
      spawn.createCreep([CARRY, CARRY, CARRY, MOVE, MOVE, MOVE], undefined, {
        role: "courier"
      });
    } else if (sourceIdMissingMiner) {
      roomFunctions.buildMiner(room, sourceIdMissingMiner, spawn);
    } else if (_.size(creepsOfRole.courier) < 3) {
      spawn.createCreep([CARRY, CARRY, CARRY, MOVE, MOVE, MOVE], undefined, {
        role: "courier"
      });
    } else if (_.size(creepsOfRole.builder) < 2) {
      spawnFunctions.createCreepWithRole(spawn, 'builder');
    } else if (_.size(creepsOfRole.upgrader) < 1) {
      spawnFunctions.createCreepWithRole(spawn, 'upgrader');
    }

    spawnFunctions.displayCreateCreepVisual(spawn);

    if (!Memory.flags[room.name + " upContainer"]) {
      roomFunctions.placeUpgraderContainer(room, spawn.pos);
    }

    roomFunctions.addExtensionsToRoom(room, spawn.pos);
  }
};
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2013 Vanderbilt University, All rights reserved.
 *
 * Author: Tamas Kecskes
 */

var requirejs = require("requirejs"),
    express = require('express'),
    passport = require('passport'),
    stratGugli = require('passport-google').Strategy,
    path = require('path'),
    https = require('https'),
    http = require('http');

requirejs.config({
    nodeRequire: require,
    baseUrl: __dirname + "/..",
    paths: {
        "core":"core",
        "logManager": "common/LogManager",
        "util": "util",
        "storage": "storage",
        "user": "user",
        "config": 'config',
        "cli": 'cli',
        "bin": 'bin',
        "auth": 'auth',
        "coreclient": 'coreclient'

    }
});

requirejs(['logManager',
    'bin/getconfig',
    'storage/serverstorage',
    'storage/server',
    'storage/cache',
    'storage/mongo',
    'storage/log',
    'auth/sessionstore',
    'auth/vehicleforgeauth',
    'auth/gmeauth',
    'util/newrest',
    'util/cJson'],function(
    logManager,
    CONFIG,
    Storage,
    Server,
    Cache,
    Mongo,
    Log,
    SStore,
    VFAUTH,
    GMEAUTH,
    REST,
    CANON){
    var parameters = CONFIG;
    var logLevel = parameters.loglevel || logManager.logLevels.WARNING;
    var logFile = parameters.logfile || 'server.log';
    logManager.setLogLevel(logLevel);
    logManager.useColors(true);
    logManager.setFileLogPath(logFile);
    var logger = logManager.create("enhancedServer");
    var iologger = logManager.create("socket.io");
    var sitekey = null;
    var sitecertificate = null;
    var _REST = null;
    var canCheckToken = true;
    if(parameters.httpsecure){
        sitekey = require('fs').readFileSync("proba-key.pem");
        sitecertificate = require('fs').readFileSync("proba-cert.pem");
    }
    var app = express();

    var __sessionStore = new SStore();

    var forge = new VFAUTH({session:__sessionStore});
    var gme = new GMEAUTH({session:__sessionStore,host:parameters.mongoip,port:parameters.mongoport,database:parameters.mongodatabase,guest:parameters.guest});

    var globalAuthorization = function(sessionId,projectName,type,callback){
        __sessionStore.get(sessionId,function(err,data){
            if(!err && data){
                switch (data.userType){
                    case 'GME':
                        gme.authorize(sessionId,projectName,type,callback);
                        break;
                    case 'vehicleForge':
                        forge.authorize(sessionId,projectName,type,callback);
                        break;
                    default:
                        callback('unknown user type',false);
                }
            } else {
                err = err || 'session not found';
                callback(err,false);
            }
        });
    };

    //for session handling we save the user data to the memory and reuse them in case of need
    var _users = {};
    passport.serializeUser(function(user, done) {
        _users[user.id] = user;
        done(null, user.id);
    });
    passport.deserializeUser(function(id, done) {
        done(null,_users[id]);
    });
    function storeQueryString(req,res,next){
        if(req.session.originalQuery === undefined){
            var index = req.url.indexOf('?');
            req.session.originalQuery = index === -1 ? "" : req.url.substring(index);
        }
        console.log("kecso",req.session.originalQuery);
        next();
    }
    var googleAuthenticaitonSet = false;
    function checkGoogleAuthentication(req,res,next){
        if(googleAuthenticaitonSet === true){
            return next();
        } else {
            var protocolPrefix = parameters.httpsecure === true ? 'https://' : 'http://';
            passport.use(new stratGugli({
                    returnURL: protocolPrefix+req.headers.host +'/login/google/return',
                    realm: protocolPrefix+req.headers.host
                },
                function(identifier, profile, done) {
                    return done(null,{id:profile.emails[0].value});
                }
            ));
            googleAuthenticaitonSet = true;
            return next();
        }
    }

    function checkREST(req,res,next){
        var baseUrl = parameters.httpsecure === true ? 'https://' : 'http://'+req.headers.host+'/rest';
        if(_REST === null){
            var restAuthorization;
            if(parameters.secureREST === true){
                restAuthorization = gme.tokenAuthorization;
                baseUrl += '/token';
            }
            _REST = new REST({host:parameters.mongoip,port:parameters.mongoport,database:parameters.mongodatabase,baseUrl:baseUrl,authorization:restAuthorization});
        } else {
            _REST.setBaseUrl(baseUrl);
        }
        return next();
    }

    function ensureAuthenticated(req, res, next) {
        if(true === parameters.authentication){
            if(req.isAuthenticated() || (req.session && true === req.session.authenticated)){
                return next();
            }

            res.redirect('/login');
        } else {
            return next();
        }
    }
    function checkVF(req,res,next){
        console.log('check Vehicle Forge framework');
        if(req.isAuthenticated() || (req.session && true === req.session.authenticated)){
            return next();
        } else {
            if(req.cookies['isisforge']){
                res.redirect('/login/forge');
            } else {
                return next();
            }
        }
    }

    function prepClientLogin(req,res,next){
        req.__gmeAuthFailUrl__ = '/login/client/fail';
        next();
    }

    var staticclientdirpath = path.resolve(__dirname+'./../client');
    var staticdirpath = path.resolve(__dirname+'./..');

    app.configure(function(){
        app.use(express.logger());
        app.use(express.cookieParser());
        app.use(express.bodyParser());
        app.use(express.methodOverride());
        app.use(express.session({store: __sessionStore, secret: parameters.sessioncookiesecret, key: parameters.sessioncookieid}));
        app.use(passport.initialize());
        app.use(passport.session());
        app.use(app.router);
    });
    //GET

    //starting point
    app.get('/',storeQueryString,checkVF,ensureAuthenticated,function(req,res){
        res.sendfile(staticclientdirpath+'/index.html',{user:req.user},function(err){
            res.send(404);
        });
    });

    //authentication related routing
    app.get('/logout', function(req, res){
        res.clearCookie('webgme');
        res.clearCookie('isisforge'); //todo is this really needed
        req.logout();
        req.session.authenticated = false;
        req.session.userType = 'unknown';
        res.redirect('/');
    });
    app.get('/login',storeQueryString,function(req,res){
        res.location('/login');
        res.sendfile(staticclientdirpath+'/login.html',{},function(err){
            res.send(404);
        });
    });
    app.post('/login',storeQueryString,gme.authenticate,function(req,res){
        res.cookie('webgme',req.session.udmId);
        res.redirect('/'+req.session.originalQuery || "");
    });
    app.post('/login/client',prepClientLogin,gme.authenticate,function(req,res){
        res.cookie('webgme',req.session.udmId);
        res.send(200);
    });
    app.get('/login/client/fail',function(req,res){
        res.clearCookie('webgme');
        res.send(401);
    });
    app.get('/login/google',storeQueryString,checkGoogleAuthentication,passport.authenticate('google'));
    app.get('/login/google/return',storeQueryString,gme.authenticate,function(req,res){
        res.cookie('webgme',req.session.udmId);
        res.redirect('/'+req.session.originalQuery || "");
    });
    app.get('/login/forge',storeQueryString,forge.authenticate,function(req,res){
        res.cookie('webgme',req.session.udmId);
        res.redirect('/');
    });

    //static contents
    //javascripts - core and transportation related files
    app.get(/^\/(common|util|storage|core|config|auth|bin|coreclient)\/.*\.js$/,ensureAuthenticated,function(req,res){
        res.sendfile(path.join(staticdirpath,req.path),function(err){
            res.send(404);
        });
    });
    //client contents - js/html/css
    //css classified as not secure content
    app.get(/^\/.*\.(css|ico)$/,function(req,res){
        res.sendfile(staticclientdirpath+req.path,function(err){
            res.send(404);
        });
    });
    app.get(/^\/.*\.(js|html|gif|png|bmp|svg|json)$/,ensureAuthenticated,function(req,res){
        //package.json
        if(req.path === '/package.json') {
            res.sendfile(staticdirpath+req.path,function(err){
                res.send(404);
            });
        } else {
            res.sendfile(staticclientdirpath+req.path,function(err){
                res.send(404);
            });
        }
    });
    //rest functionality
    //rest token generation
    app.get('/gettoken',ensureAuthenticated,function(req,res){
        if(parameters.secureREST == true){
            gme.getToken(req.session.id,function(err,token){
                if(err){
                    res.send(err);
                } else {
                    res.send(token);
                }
            });
        } else {
            res.send(410); //special error for the interpreters to know there is no need for token
        }
    });
    app.get('/checktoken/*',function(req,res){
        if(parameters.secureREST == true){
            if(canCheckToken == true){
                var token = req.url.split('/');
                if(token.length === 3){
                    token = token[2];
                    setTimeout(function(){canCheckToken = true;},10000);
                    canCheckToken = false;
                    gme.checkToken(token,function(isValid){
                        if(isValid === true){
                            res.send(200);
                        } else {
                            res.send(403);
                        }
                    });
                } else {
                    res.send(400);
                }
            } else {
                res.send(403);
            }
        } else {
            res.send(410); //special error for the interpreters to know there is no need for token
        }
    });
    //rest requests
    app.get('/rest/*',checkREST,function(req,res){

        var commandpos = CONFIG.secureREST === true ? 3 : 2,
            minlength = CONFIG.secureREST === true ? 3 : 2,
            urlArray = req.url.split('/');
        if(urlArray.length > minlength){
            var command = urlArray[commandpos],
                token = CONFIG.secureREST === true ? urlArray[2] : "",
                parameters = urlArray.slice(commandpos+1);
            _REST.initialize(function(err){
                if(err){
                    res.send(500);
                } else {
                    _REST.doRESTCommand(_REST.request.GET,command,token,parameters,function(httpStatus,object){
                        if(command === _REST.command.etf){
                            var filename = 'exportedNode.json';
                            if(parameters[3]){
                                filename = parameters[3];
                            }
                            if(filename.indexOf('.') === -1){
                                filename += '.json';
                            }
                            res.header("Content-Type", "application/json");
                            res.header("Content-Disposition", "attachment;filename=\""+filename+"\"");
                            res.status(httpStatus);
                            //res.end(JSON.stringify(object,null,2));
                            res.end(CANON(object));
                        } else {
                            res.json(httpStatus, object || null);
                        }
                    });
                }
            });
        } else {
            res.send(400);
        }
    });
    //worker functionalities
    app.get('/worker/simpleResult/*',function(req,res){
        var urlArray = req.url.split('/');
        if(urlArray.length > 3){
            storage.getWorkerResult(urlArray[3],function(err,result){
                if(err){
                    res.send(500);
                } else {
                    var filename = 'exportedNodes.json';
                    if(urlArray[4]){
                        filename = urlArray[4];
                    }
                    if(filename.indexOf('.') === -1){
                        filename += '.json';
                    }
                    res.header("Content-Type", "application/json");
                    res.header("Content-Disposition", "attachment;filename=\""+filename+"\"");
                    res.status(200);
                    res.end(JSON.stringify(result,null,2));
                }
            });
        } else {
            res.send(404);
        }
    });
    //other get
    app.get('*',function(req,res){
        res.send(400);
    });

    var httpServer = null;
    if(parameters.httpsecure){
        httpServer = https.createServer({key:sitekey,cert:sitecertificate}, app).listen(parameters.port);
    } else {
        httpServer = http.createServer(app).listen(parameters.port);
    }

    var storage = null;
    var __storageOptions = {combined:httpServer,logger:iologger,session:false,cookieID:parameters.sessioncookieid};
    if(true === parameters.authentication){
        __storageOptions.session = true;
        __storageOptions.sessioncheck = __sessionStore.check;
        __storageOptions.secret = parameters.sessioncookiesecret;
        __storageOptions.authorization = globalAuthorization;
        __storageOptions.authInfo = gme.getAuthorizationInfo;
    }

    __storageOptions.host = parameters.mongoip;
    __storageOptions.port = parameters.mongoport;
    __storageOptions.database = parameters.mongodatabase;
    __storageOptions.log = logManager.create('combined-server-storage');
    __storageOptions.getToken = gme.getToken;

    __storageOptions.basedir =  __dirname + "/..";

    storage = Storage(__storageOptions);

    storage.open();

    //debug information
    if(parameters.debug === true){
        console.log('parameters of webgme server:');
        console.log(parameters);
    }
    var networkIfs = require('os').networkInterfaces();
    for(var dev in networkIfs){
        networkIfs[dev].forEach(function(netIf){
            if(netIf.family === 'IPv4'){
                var address = parameters.httpsecure ? 'https' : 'http' + '://' + netIf.address + ':' + parameters.port;
                logger.info(address);
                if(parameters.debug === true){
                    console.log('valid address of webgme server: '+address);
                }
            }
        });
    }
});<commit_msg>now additional command line configuration file can be merged to the existing CONFIG<commit_after>/*
 * Copyright (C) 2013 Vanderbilt University, All rights reserved.
 *
 * Author: Tamas Kecskes
 */

var requirejs = require("requirejs"),
    express = require('express'),
    passport = require('passport'),
    stratGugli = require('passport-google').Strategy,
    path = require('path'),
    https = require('https'),
    http = require('http');

requirejs.config({
    nodeRequire: require,
    baseUrl: __dirname + "/..",
    paths: {
        "core":"core",
        "logManager": "common/LogManager",
        "util": "util",
        "storage": "storage",
        "user": "user",
        "config": 'config',
        "cli": 'cli',
        "bin": 'bin',
        "auth": 'auth',
        "coreclient": 'coreclient'

    }
});

requirejs(['logManager',
    'bin/getconfig',
    'storage/serverstorage',
    'storage/server',
    'storage/cache',
    'storage/mongo',
    'storage/log',
    'auth/sessionstore',
    'auth/vehicleforgeauth',
    'auth/gmeauth',
    'util/newrest',
    'util/cJson'],function(
    logManager,
    CONFIG,
    Storage,
    Server,
    Cache,
    Mongo,
    Log,
    SStore,
    VFAUTH,
    GMEAUTH,
    REST,
    CANON){
    var parameters = CONFIG;
    var logLevel = parameters.loglevel || logManager.logLevels.WARNING;
    var logFile = parameters.logfile || 'server.log';
    logManager.setLogLevel(logLevel);
    logManager.useColors(true);
    logManager.setFileLogPath(logFile);
    var logger = logManager.create("enhancedServer");
    var iologger = logManager.create("socket.io");
    var sitekey = null;
    var sitecertificate = null;
    var _REST = null;
    var canCheckToken = true;
    if(parameters.httpsecure){
        sitekey = require('fs').readFileSync("proba-key.pem");
        sitecertificate = require('fs').readFileSync("proba-cert.pem");
    }
    var app = express();

    var __sessionStore = new SStore();

    var forge = new VFAUTH({session:__sessionStore});
    var gme = new GMEAUTH({session:__sessionStore,host:parameters.mongoip,port:parameters.mongoport,database:parameters.mongodatabase,guest:parameters.guest});

    //optional config file from command line arguments
    if(process.argv.length === 3){
        var cmdConfig = require('fs').readFileSync(process.argv[2]);
        try{
            cmdConfig = JSON.parse(cmdConfig);
            for(var i in cmdConfig){
                CONFIG[i] = cmdConfig[i];
            }
        } catch (e){
            //TODO
            logger.error("extra config file read failure: "+e);
        }
    }

    var globalAuthorization = function(sessionId,projectName,type,callback){
        __sessionStore.get(sessionId,function(err,data){
            if(!err && data){
                switch (data.userType){
                    case 'GME':
                        gme.authorize(sessionId,projectName,type,callback);
                        break;
                    case 'vehicleForge':
                        forge.authorize(sessionId,projectName,type,callback);
                        break;
                    default:
                        callback('unknown user type',false);
                }
            } else {
                err = err || 'session not found';
                callback(err,false);
            }
        });
    };

    //for session handling we save the user data to the memory and reuse them in case of need
    var _users = {};
    passport.serializeUser(function(user, done) {
        _users[user.id] = user;
        done(null, user.id);
    });
    passport.deserializeUser(function(id, done) {
        done(null,_users[id]);
    });
    function storeQueryString(req,res,next){
        if(req.session.originalQuery === undefined){
            var index = req.url.indexOf('?');
            req.session.originalQuery = index === -1 ? "" : req.url.substring(index);
        }
        console.log("kecso",req.session.originalQuery);
        next();
    }
    var googleAuthenticaitonSet = false;
    function checkGoogleAuthentication(req,res,next){
        if(googleAuthenticaitonSet === true){
            return next();
        } else {
            var protocolPrefix = parameters.httpsecure === true ? 'https://' : 'http://';
            passport.use(new stratGugli({
                    returnURL: protocolPrefix+req.headers.host +'/login/google/return',
                    realm: protocolPrefix+req.headers.host
                },
                function(identifier, profile, done) {
                    return done(null,{id:profile.emails[0].value});
                }
            ));
            googleAuthenticaitonSet = true;
            return next();
        }
    }

    function checkREST(req,res,next){
        var baseUrl = parameters.httpsecure === true ? 'https://' : 'http://'+req.headers.host+'/rest';
        if(_REST === null){
            var restAuthorization;
            if(parameters.secureREST === true){
                restAuthorization = gme.tokenAuthorization;
                baseUrl += '/token';
            }
            _REST = new REST({host:parameters.mongoip,port:parameters.mongoport,database:parameters.mongodatabase,baseUrl:baseUrl,authorization:restAuthorization});
        } else {
            _REST.setBaseUrl(baseUrl);
        }
        return next();
    }

    function ensureAuthenticated(req, res, next) {
        if(true === parameters.authentication){
            if(req.isAuthenticated() || (req.session && true === req.session.authenticated)){
                return next();
            }

            res.redirect('/login');
        } else {
            return next();
        }
    }
    function checkVF(req,res,next){
        console.log('check Vehicle Forge framework');
        if(req.isAuthenticated() || (req.session && true === req.session.authenticated)){
            return next();
        } else {
            if(req.cookies['isisforge']){
                res.redirect('/login/forge');
            } else {
                return next();
            }
        }
    }

    function prepClientLogin(req,res,next){
        req.__gmeAuthFailUrl__ = '/login/client/fail';
        next();
    }

    var staticclientdirpath = path.resolve(__dirname+'./../client');
    var staticdirpath = path.resolve(__dirname+'./..');

    app.configure(function(){
        app.use(express.logger());
        app.use(express.cookieParser());
        app.use(express.bodyParser());
        app.use(express.methodOverride());
        app.use(express.session({store: __sessionStore, secret: parameters.sessioncookiesecret, key: parameters.sessioncookieid}));
        app.use(passport.initialize());
        app.use(passport.session());
        app.use(app.router);
    });
    //GET

    //starting point
    app.get('/',storeQueryString,checkVF,ensureAuthenticated,function(req,res){
        res.sendfile(staticclientdirpath+'/index.html',{user:req.user},function(err){
            res.send(404);
        });
    });

    //authentication related routing
    app.get('/logout', function(req, res){
        res.clearCookie('webgme');
        res.clearCookie('isisforge'); //todo is this really needed
        req.logout();
        req.session.authenticated = false;
        req.session.userType = 'unknown';
        res.redirect('/');
    });
    app.get('/login',storeQueryString,function(req,res){
        res.location('/login');
        res.sendfile(staticclientdirpath+'/login.html',{},function(err){
            res.send(404);
        });
    });
    app.post('/login',storeQueryString,gme.authenticate,function(req,res){
        res.cookie('webgme',req.session.udmId);
        res.redirect('/'+req.session.originalQuery || "");
    });
    app.post('/login/client',prepClientLogin,gme.authenticate,function(req,res){
        res.cookie('webgme',req.session.udmId);
        res.send(200);
    });
    app.get('/login/client/fail',function(req,res){
        res.clearCookie('webgme');
        res.send(401);
    });
    app.get('/login/google',storeQueryString,checkGoogleAuthentication,passport.authenticate('google'));
    app.get('/login/google/return',storeQueryString,gme.authenticate,function(req,res){
        res.cookie('webgme',req.session.udmId);
        res.redirect('/'+req.session.originalQuery || "");
    });
    app.get('/login/forge',storeQueryString,forge.authenticate,function(req,res){
        res.cookie('webgme',req.session.udmId);
        res.redirect('/');
    });

    //static contents
    //javascripts - core and transportation related files
    app.get(/^\/(common|util|storage|core|config|auth|bin|coreclient)\/.*\.js$/,ensureAuthenticated,function(req,res){
        res.sendfile(path.join(staticdirpath,req.path),function(err){
            res.send(404);
        });
    });
    //client contents - js/html/css
    //css classified as not secure content
    app.get(/^\/.*\.(css|ico)$/,function(req,res){
        res.sendfile(staticclientdirpath+req.path,function(err){
            res.send(404);
        });
    });
    app.get(/^\/.*\.(js|html|gif|png|bmp|svg|json)$/,ensureAuthenticated,function(req,res){
        //package.json
        if(req.path === '/package.json') {
            res.sendfile(staticdirpath+req.path,function(err){
                res.send(404);
            });
        } else {
            res.sendfile(staticclientdirpath+req.path,function(err){
                res.send(404);
            });
        }
    });
    //rest functionality
    //rest token generation
    app.get('/gettoken',ensureAuthenticated,function(req,res){
        if(parameters.secureREST == true){
            gme.getToken(req.session.id,function(err,token){
                if(err){
                    res.send(err);
                } else {
                    res.send(token);
                }
            });
        } else {
            res.send(410); //special error for the interpreters to know there is no need for token
        }
    });
    app.get('/checktoken/*',function(req,res){
        if(parameters.secureREST == true){
            if(canCheckToken == true){
                var token = req.url.split('/');
                if(token.length === 3){
                    token = token[2];
                    setTimeout(function(){canCheckToken = true;},10000);
                    canCheckToken = false;
                    gme.checkToken(token,function(isValid){
                        if(isValid === true){
                            res.send(200);
                        } else {
                            res.send(403);
                        }
                    });
                } else {
                    res.send(400);
                }
            } else {
                res.send(403);
            }
        } else {
            res.send(410); //special error for the interpreters to know there is no need for token
        }
    });
    //rest requests
    app.get('/rest/*',checkREST,function(req,res){

        var commandpos = CONFIG.secureREST === true ? 3 : 2,
            minlength = CONFIG.secureREST === true ? 3 : 2,
            urlArray = req.url.split('/');
        if(urlArray.length > minlength){
            var command = urlArray[commandpos],
                token = CONFIG.secureREST === true ? urlArray[2] : "",
                parameters = urlArray.slice(commandpos+1);
            _REST.initialize(function(err){
                if(err){
                    res.send(500);
                } else {
                    _REST.doRESTCommand(_REST.request.GET,command,token,parameters,function(httpStatus,object){
                        if(command === _REST.command.etf){
                            var filename = 'exportedNode.json';
                            if(parameters[3]){
                                filename = parameters[3];
                            }
                            if(filename.indexOf('.') === -1){
                                filename += '.json';
                            }
                            res.header("Content-Type", "application/json");
                            res.header("Content-Disposition", "attachment;filename=\""+filename+"\"");
                            res.status(httpStatus);
                            //res.end(JSON.stringify(object,null,2));
                            res.end(CANON(object));
                        } else {
                            res.json(httpStatus, object || null);
                        }
                    });
                }
            });
        } else {
            res.send(400);
        }
    });
    //worker functionalities
    app.get('/worker/simpleResult/*',function(req,res){
        var urlArray = req.url.split('/');
        if(urlArray.length > 3){
            storage.getWorkerResult(urlArray[3],function(err,result){
                if(err){
                    res.send(500);
                } else {
                    var filename = 'exportedNodes.json';
                    if(urlArray[4]){
                        filename = urlArray[4];
                    }
                    if(filename.indexOf('.') === -1){
                        filename += '.json';
                    }
                    res.header("Content-Type", "application/json");
                    res.header("Content-Disposition", "attachment;filename=\""+filename+"\"");
                    res.status(200);
                    res.end(JSON.stringify(result,null,2));
                }
            });
        } else {
            res.send(404);
        }
    });
    //other get
    app.get('*',function(req,res){
        res.send(400);
    });

    var httpServer = null;
    if(parameters.httpsecure){
        httpServer = https.createServer({key:sitekey,cert:sitecertificate}, app).listen(parameters.port);
    } else {
        httpServer = http.createServer(app).listen(parameters.port);
    }

    var storage = null;
    var __storageOptions = {combined:httpServer,logger:iologger,session:false,cookieID:parameters.sessioncookieid};
    if(true === parameters.authentication){
        __storageOptions.session = true;
        __storageOptions.sessioncheck = __sessionStore.check;
        __storageOptions.secret = parameters.sessioncookiesecret;
        __storageOptions.authorization = globalAuthorization;
        __storageOptions.authInfo = gme.getAuthorizationInfo;
    }

    __storageOptions.host = parameters.mongoip;
    __storageOptions.port = parameters.mongoport;
    __storageOptions.database = parameters.mongodatabase;
    __storageOptions.log = logManager.create('combined-server-storage');
    __storageOptions.getToken = gme.getToken;

    __storageOptions.basedir =  __dirname + "/..";

    storage = Storage(__storageOptions);

    storage.open();

    //debug information
    if(parameters.debug === true){
        console.log('parameters of webgme server:');
        console.log(parameters);
    }
    var networkIfs = require('os').networkInterfaces();
    for(var dev in networkIfs){
        networkIfs[dev].forEach(function(netIf){
            if(netIf.family === 'IPv4'){
                var address = parameters.httpsecure ? 'https' : 'http' + '://' + netIf.address + ':' + parameters.port;
                logger.info(address);
                if(parameters.debug === true){
                    console.log('valid address of webgme server: '+address);
                }
            }
        });
    }
});<|endoftext|>


<commit_before>var copyAttrs = function() {
  var to = arguments[0];
  var from = [].splice.call(arguments, 1);

  from.forEach(function(other) {
    Object.keys(other).forEach(function(k) {
      to[k] = other[k];
    });
  });
};

var values = function(dic) {
  return Object.keys(dic).map(function(k) {return dic[k]});
};

var flatten = function(arr) {
  return arr.reduce(function(a, b) {return a.concat(b)}, []);
};

var evaluateCondition = function(cond, a, b) {
  if (cond === '=') {
    return a === b;
  }
  if (cond === '<>') {
    return a !== b;
  }
  throw 'Condition not found ' + cond;
};

var triggerEvent = function(name) {
  window.dispatchEvent(new Event(name));
};

var builder = (function() {

  var createQuestion = function(data, id) {
    id = '' + id;
    var question = createGenericTag('div', {className: 'question'});
    question.appendChild(createGenericTag('label',
                                          {textContent: data.label,
                                            htmlFor: id,
                                            className: 'q-title'}));
    data.id = id;
    if (!data.className) {
      data.className = '';
    }
    data.className +=' q-answer'
    if (data.tag in actions) {
      question.appendChild(actions[data.tag](data));
    }
    return question;
  };

  var createGenericTag = function(tag, attrs, defaultAttrs) {
    defaultAttrs = defaultAttrs || {};
    var elem = document.createElement(tag);
    copyAttrs(elem, defaultAttrs, attrs);
    return elem;
  };

  var createInput = function(attrs) {
    return createGenericTag('input', attrs, {type: 'text'});
  };

  var createTextArea = function(attrs) {
    return createGenericTag('textarea', attrs);
  };

  var createSimpleDiv = function(attr) {
    attr = attr || {};
    return createGenericTag('div', attr);
  };

  var createOptions = function(attrs) {
    var parentDiv = createSimpleDiv();
    attrs.data.forEach(function(e, idx) {
      parentDiv.appendChild(createOption(e, attrs.id + '' + idx,
                                         attrs.id, attrs.tag));
    });

    return parentDiv;
  };

  var createOption = function(data, id, name, type) {
    var parentDiv = createSimpleDiv({className: 'elem-radio-check'});

    parentDiv.appendChild(createGenericTag('input', data,
                                           {type: type, name: name, id: id}));
    parentDiv.appendChild(createGenericTag('label',
                                           {textContent: data.label,
                                            htmlFor: id}));
    return parentDiv;
  };

  var createButton = function(attrs) {
    attrs = attrs || {};
    attrs.textContent = attrs.label || 'addname';
    return createGenericTag('button', attrs);
  };

  var createLabel = function(attrs) {
    return createGenericTag('label', attrs);
  };

  var actions = {
    'button': createButton,
    'input': createInput,
    'textarea': createTextArea,
    'label': createLabel,
    'radio': createOptions,
    'checkbox': createOptions
  };

  var createTitle = function(attrs) {
    var tag = attrs.tag || 'div';
    attrs.textContent = attrs.label;
    return createGenericTag(tag, attrs);
  };

  var createElement = function(type, data) {
    if (type in actions) {
      return actions[type](data);
    }
    return createGenericTag(type, data);
  };

  return {
    createElement: createElement,
    createQuestion: createQuestion,
    createTitle: createTitle
  };

})();

var isOptionType = function(type) {
  return type === 'radio' || type === 'checkbox';
};

var triggerUpdate = function() {
  triggerEvent('updateElementsValue');
};

var FakeElement = function(question, data) {
  this.question = question;
  this.tag = data.tag;
  this.req;

  this.skip = data.skip;
  this.valuefields = question.childNodes[1];

  if (isOptionType(this.tag)) {
    this.valuefields.addEventListener('click', triggerUpdate);

    this.valuefields =  [].map
      .call(this.valuefields.childNodes,
            function(c) {
              return c.childNodes[0];
            });

  } else {
    this.valuefields.addEventListener('keyup', triggerUpdate);
  }

  if (data.req === undefined || data.req === null) {
    this.setReq(true);
  } else {
    this.setReq(data.req);
  }
  this.inititalRequired = this.req;
};

FakeElement.prototype = {

  val: function() {
    if (Array.isArray(this.valuefields)) {

      return this.valuefields
        .filter(function(e) {return e.checked})
        .map(function(e) {return e.value});
    }
    return this.valuefields.value;
  },

  hasValue: function() {
    return this.val().length > 0;
  },

  questionsToSkip: function() {

    if (this.question.classList.contains('error')) {

      this.question.classList.remove('error');
      if (this.req && !this.hasValue()) {
        this.question.classList.add('error');
      }
    }

    if (this.skip) {
      var skips = [].concat(this.skip);
      var valuesFromFields = [].concat(this.val());

      var groupsQuestionsToSkip = skips
        .filter(function(skip) {
          return valuesFromFields.filter(function(val) {
            return evaluateCondition(skip.cond, skip.val, val);
          }).length > 0;
        }).map(function(m) {return m.questions});

      return flatten(groupsQuestionsToSkip);
    }
    return [];
  },

  resetReq: function() {
    this.setReq(this.inititalRequired);
  },

  setReq: function(required) {
    if (!required) {
      this.question.classList.remove('error');
      this.question.classList.add('l-not-req');
    } else {
      this.question.classList.remove('l-not-req');
    }

    this.req = required;
  },

  getError: function() {
    this.question.classList.remove('error');
    if (!this.req || this.hasValue()) return false;
    this.question.classList.add('error');
    return true;
  }
};

var createBody = function(domElements, questions, actionButtons) {
  var form = builder.createElement('form', {});
  var id = 0;

  questions.forEach(function(el) {
    var newElement = builder.createQuestion(el, id);
    domElements[id++] = new FakeElement(newElement, el);
    form.appendChild(newElement);
  })

  actionButtons.forEach(function(btnAttr) {
    form.appendChild(builder.createElement('button', btnAttr));
  });

  return form;
};

var evaluateFakeElements = function(fakeElements) {

  values(fakeElements).forEach(function(elem) {
    elem.resetReq();
  })

  values(fakeElements).forEach(function(elem) {

    elem.questionsToSkip()
      .forEach(function(idx) {
        if (idx in fakeElements) {
          fakeElements[idx].setReq(false);
        }
      });

  });
};

var sheet = (function() {
  var style = document.createElement("style");
  style.appendChild(document.createTextNode(""));
  document.head.appendChild(style);
  return style.sheet;
})();

var init = function(mainElement, schema) {
  var domElements = {};
  var options = schema.options || {};
  var onSubmit = schema.onSubmit || function() {};

  if (options.hideNotReq) {
    sheet.insertRule('.l-not-req { display: none; }', sheet.cssRules.length);
  }

  //submitButton array, maybe in the future it can be many buttons
  mainElement.appendChild(builder.createTitle(schema.title));

  var formElement = createBody(domElements, schema.body, [schema.submitButton]);
  mainElement.appendChild(formElement);

  formElement.addEventListener('submit', function(e) {
    e.preventDefault();
    var elemValues = values(domElements).map(function(k) {return k.val();});
    var errors = values(domElements).map(function(k) {return k.getError();});

    onSubmit(errors, elemValues);
  });

  window.addEventListener('updateElementsValue', function() {
    evaluateFakeElements(domElements);
  });
};

<commit_msg>wrapper function<commit_after>var survey = function() {
  var copyAttrs = function() {
    var to = arguments[0];
    var from = [].splice.call(arguments, 1);

    from.forEach(function(other) {
      Object.keys(other).forEach(function(k) {
        to[k] = other[k];
      });
    });
  };

  var values = function(dic) {
    return Object.keys(dic).map(function(k) {return dic[k];});
  };

  var flatten = function(arr) {
    return arr.reduce(function(a, b) {return a.concat(b);}, []);
  };

  var evaluateCondition = function(cond, a, b) {
    if (cond === '=') {
      return a === b;
    }
    if (cond === '<>') {
      return a !== b;
    }
    throw 'Condition not found ' + cond;
  };

  var triggerEvent = function(name) {
    window.dispatchEvent(new Event(name));
  };

  var builder = (function() {

    var createQuestion = function(data, id) {
      id = '' + id;
      var question = createGenericTag('div', {className: 'question'});
      question.appendChild(createGenericTag('label',
                                            {textContent: data.label,
                                              htmlFor: id,
                                              className: 'q-title'}));
      data.id = id;
      if (!data.className) {
        data.className = '';
      }
      data.className +=' q-answer';
      if (data.tag in actions) {
        question.appendChild(actions[data.tag](data));
      }
      return question;
    };

    var createGenericTag = function(tag, attrs, defaultAttrs) {
      defaultAttrs = defaultAttrs || {};
      var elem = document.createElement(tag);
      copyAttrs(elem, defaultAttrs, attrs);
      return elem;
    };

    var createInput = function(attrs) {
      return createGenericTag('input', attrs, {type: 'text'});
    };

    var createTextArea = function(attrs) {
      return createGenericTag('textarea', attrs);
    };

    var createSimpleDiv = function(attr) {
      attr = attr || {};
      return createGenericTag('div', attr);
    };

    var createOptions = function(attrs) {
      var parentDiv = createSimpleDiv();
      attrs.data.forEach(function(e, idx) {
        parentDiv.appendChild(createOption(e, attrs.id + '' + idx,
                                           attrs.id, attrs.tag));
      });

      return parentDiv;
    };

    var createOption = function(data, id, name, type) {
      var parentDiv = createSimpleDiv({className: 'elem-radio-check'});

      parentDiv.appendChild(createGenericTag('input', data,
                                             {type: type, name: name, id: id}));
      parentDiv.appendChild(createGenericTag('label',
                                             {textContent: data.label,
                                              htmlFor: id}));
      return parentDiv;
    };

    var createButton = function(attrs) {
      attrs = attrs || {};
      attrs.textContent = attrs.label || 'addname';
      return createGenericTag('button', attrs);
    };

    var createLabel = function(attrs) {
      return createGenericTag('label', attrs);
    };

    var actions = {
      'button': createButton,
      'input': createInput,
      'textarea': createTextArea,
      'label': createLabel,
      'radio': createOptions,
      'checkbox': createOptions
    };

    var createTitle = function(attrs) {
      var tag = attrs.tag || 'div';
      attrs.textContent = attrs.label;
      return createGenericTag(tag, attrs);
    };

    var createElement = function(type, data) {
      if (type in actions) {
        return actions[type](data);
      }
      return createGenericTag(type, data);
    };

    return {
      createElement: createElement,
      createQuestion: createQuestion,
      createTitle: createTitle
    };

  })();

  var isOptionType = function(type) {
    return type === 'radio' || type === 'checkbox';
  };

  var triggerUpdate = function() {
    triggerEvent('updateElementsValue');
  };

  var FakeElement = function(question, data) {
    this.question = question;
    this.tag = data.tag;
    this.skip = data.skip;
    this.valuefields = question.childNodes[1];
    this.req;
    if (isOptionType(this.tag)) {
      this.valuefields.addEventListener('click', triggerUpdate);

      this.valuefields =  [].map
        .call(this.valuefields.childNodes,
              function(c) {
                return c.childNodes[0];
              });

    } else {
      this.valuefields.addEventListener('keyup', triggerUpdate);
    }

    if (data.req === undefined || data.req === null) {
      this.setReq(true);
    } else {
      this.setReq(data.req);
    }
    this.inititalRequired = this.req;
  };

  FakeElement.prototype = {

    val: function() {
      if (Array.isArray(this.valuefields)) {

        return this.valuefields
          .filter(function(e) {return e.checked;})
          .map(function(e) {return e.value;});
      }
      return this.valuefields.value;
    },

    hasValue: function() {
      return this.val().length > 0;
    },

    questionsToSkip: function() {

      if (this.question.classList.contains('error')) {

        this.question.classList.remove('error');
        if (this.req && !this.hasValue()) {
          this.question.classList.add('error');
        }
      }

      if (this.skip) {
        var skips = [].concat(this.skip);
        var valuesFromFields = [].concat(this.val());

        var groupsQuestionsToSkip = skips
          .filter(function(skip) {
            return valuesFromFields.filter(function(val) {
              return evaluateCondition(skip.cond, skip.val, val);
            }).length > 0;
          }).map(function(m) {return m.questions;});

        return flatten(groupsQuestionsToSkip);
      }
      return [];
    },

    resetReq: function() {
      this.setReq(this.inititalRequired);
    },

    setReq: function(required) {
      if (!required) {
        this.question.classList.remove('error');
        this.question.classList.add('l-not-req');
      } else {
        this.question.classList.remove('l-not-req');
      }

      this.req = required;
    },

    getError: function() {
      this.question.classList.remove('error');
      if (!this.req || this.hasValue()) return false;
      this.question.classList.add('error');
      return true;
    }
  };

  var createBody = function(domElements, questions, actionButtons) {
    var form = builder.createElement('form', {});
    var id = 0;

    questions.forEach(function(el) {
      var newElement = builder.createQuestion(el, id);
      domElements[id++] = new FakeElement(newElement, el);
      form.appendChild(newElement);
    });

    actionButtons.forEach(function(btnAttr) {
      form.appendChild(builder.createElement('button', btnAttr));
    });

    return form;
  };

  var evaluateFakeElements = function(fakeElements) {

    values(fakeElements).forEach(function(elem) {
      elem.resetReq();
    });

    values(fakeElements).forEach(function(elem) {

      elem.questionsToSkip()
        .forEach(function(idx) {
          if (idx in fakeElements) {
            fakeElements[idx].setReq(false);
          }
        });

    });
  };

  var sheet = (function() {
    var style = document.createElement("style");
    style.appendChild(document.createTextNode(""));
    document.head.appendChild(style);
    return style.sheet;
  })();

  var init = function(mainElement, schema) {
    var domElements = {};
    var options = schema.options || {};
    var onSubmit = schema.onSubmit || function() {};

    if (options.hideNotReq) {
      sheet.insertRule('.l-not-req { display: none; }', sheet.cssRules.length);
    }

    //submitButton array, maybe in the future it can be many buttons
    mainElement.appendChild(builder.createTitle(schema.title));

    var formElement = createBody(domElements, schema.body,
                                 [schema.submitButton]);
    mainElement.appendChild(formElement);

    formElement.addEventListener('submit', function(e) {
      e.preventDefault();
      var elemValues = values(domElements).map(function(k) {return k.val();});
      var errors = values(domElements).map(function(k) {return k.getError();});

      onSubmit(errors, elemValues);
    });

    window.addEventListener('updateElementsValue', function() {
      evaluateFakeElements(domElements);
    });
  };

  return {
    create: init
  }

};<|endoftext|>