<commit_before>'use strict';

const utilities = require('../brain/utilities');
const config = require('../config/config');
const request = require('request');
const Q = require('q');

/**
 * Verifies that request actually coming from Slack
 * not currently in use
 *
 * @param req
 * @param res
 */
// function verify() {
//   console.log("Nothing to see here.")
// }

/**
 * Makes array of generic request objects from incoming context
 *
 * @param context
 * @return {genericRequests}
 */
function translateRequestToGenericFormats(context) {
  var text = context.userRequest.text;
  var verifyToken = config.slackVerifyToken;
  var incomingToken = context.userRequest.token;
  var genericRequests = [{
    reqType: 'user-input',
    userInput: '',
    context: context
  }];

  // checking for valid token from Slack
  if (verifyToken !== incomingToken) {
    console.log('Slack access token mismatch! Ignoring incoming request.');
    console.log('Incoming Token: ' + incomingToken);
    console.log('Verify Token: ' + verifyToken);
    return [];
  };
  console.log('Slack access token match! It\'s all good, man.');

  if (text) {
    genericRequests[0].userInput = text;
  };
  if (text.toLowerCase() === 'help') {
    console.log('Detected user input of \"help\"');
    genericRequests[0].reqType = 'help';
  };
  console.log('Slack bot has prepared this generic request: ' + JSON.stringify(genericRequests));
  return genericRequests;
}

/**
 * Takes generic response data and structures payloads for Slack sending
 *
 * @param genericResponse
 * @return {payloads}
 */
function generateResponsePayloads(genericResponse) {
  console.log("About to begin generating payloads from genericResponse.");
  // form basic payload
  var payloads = formBasicPayload(genericResponse);
  var type = genericResponse.type;

  // if a False object passed in, passes down False to next step
  if (!genericResponse) {
    return false;
  };

  // Refactor to switch statement?
  // Case: no user input
  if (type === 'no-input') {
    console.log('No user input flag detected in genericResponse.');
    payloads[0].json.text = 'Tell me the company you would like to contact.';
    return payloads;
  } else if (type === 'help') {
    // Case: Help user
    console.log('Help flag detected in genericResponse.');
    payloads[0].json.text = 'It looks like you need some help. Please tell me the name of the company you want to reach, and I will provide you with a list of the top issues for customers of this company, the company\'s contact info, and a list of other companies you may want to search for.';
    return payloads;
  } else if (type === 'nothing-found') {
    // Case: nothing returned from Companies search / junk input
    console.log('No Company Results flag detected in genericResponse.');
    payloads[0].json.text = 'I couldn\'t tell what you meant by \"' + genericResponse.userInput + '\". Please tell me company you are looking for. (ex: \"/gethuman Verizon Wireless\")';
    return payloads;
  } else if (type === 'standard') {
    // do we need the explicit type check after the first two, or just 'else'?
    // Refactor inner parts of this case to a function?
    console.log('Standard type flag detected in genericResponse.');
    var name = genericResponse.data.name || '';
    var posts = genericResponse.data.posts || [];
    var otherCompanies = genericResponse.data.otherCompanies || [];
    var topContacts = formatContacts(genericResponse.data.contactMethods);
    if (posts && posts.length) {
      payloads = loadPostsAttachments(payloads, posts, name);
      console.log('Posts info pushed into Payloads');
    };
    if (topContacts) {
      payloads = loadContactsAttachments(payloads, topContacts, name);
      console.log('Company Contact Info pushed into Payloads');
    };
    if (otherCompanies && otherCompanies.length) {
      payloads = loadOtherCompaniesAttachments(payloads, otherCompanies, name);
      console.log('Other Companies info pushed into Payloads');
    };
    if (!payloads[0].json.attachments.length) {
        payloads[0].json.text = 'I couldn\'t find anything for \"' + name + '\". Please tell me which company you are looking for. (ex: \"/gethuman Verizon Wireless\")';
        console.log('No card info found for Companies, returning Nothing Found text.');
    }
    return payloads;
  }
}

/**
 * Forms base payload for Slack response
 *
 * @param genericResponse
 * @return {payloads}
 */
function formBasicPayload(genericResponse) {
  var path = config.slackAccessToken;
  var uri = 'https://hooks.slack.com/services/' + path;
  var channel = genericResponse.context.userRequest.channel_id;
  var payloads = [{
    uri: uri,
    method: 'POST',
    json: {
      channel: channel,
      username: 'GetHuman',
      icon_emoji: ':gethuman:',
      text: '',
      attachments: []
    }
  }];
  return payloads;
};

/**
 * Forms payload attachment for Posts information
 *
 * @param payloads
 * @param posts
 * @param name
 * @return {payloads}
 */
function loadPostsAttachments(payloads, posts, name) {
  var colors = utilities.colors;
  payloads[0].json.text = 'Top issues for ' + name + ':';
  for (let i = 0; i < posts.length; i++) {
      let title = posts[i].title || '';
      let urlId = posts[i].urlId || '';
      let color = colors[i];
      let singleAttachment = {
          "fallback": "Issue for " + name,
          "title": title,
          "color": color,
          "fields": [
              {
                  "value": "<https://gethuman.com?company=" + encodeURIComponent(name) + "|Solve for me - $20>",
                  "short": true
              },
              {
                  "value": "<https://answers.gethuman.co/_" + encodeURIComponent(urlId) + "|More info ...>",
                  "short": true
              }
          ]
      };
      payloads[0].json.attachments.push(singleAttachment);
  };
  return payloads;
};

/**
 * Forms payload attachment for Contact information
 *
 * @param payloads
 * @param topContacts
 * @param name
 * @return {payloads}
 */
function loadContactsAttachments(payloads, topContacts, name) {
  payloads[0].json.attachments.push({
      fallback: 'Contact info for ' + name,
      title: 'Best ways to contact ' + name,
      color: '#999999',
      text: topContacts,
  });
  return payloads;
}

/**
 * Forms payload attachment for Other Companies information
 *
 * @param payloads
 * @param otherCompanies
 * @param name
 * @return {payloads}
 */
function loadOtherCompaniesAttachments(payloads, otherCompanies, name) {
  var otherCompaniesList = convertArrayToBoldList(otherCompanies);
  payloads[0].json.attachments.push({
      fallback: 'Other solutions',
      title: 'Were you talking about ' + name + '?',
      color: '#BBBBBB',
      text: 'Or maybe you meant ' + otherCompaniesList + '?',
      mrkdwn_in: ["text"]
  });
  return payloads;
}

/**
 * Takes contact methods, forms a structured string of <= 3 items for display
 *
 * @param contactMethods
 * @return {topContacts}
 */
function formatContacts(contactMethods) {
  var topContacts = '';
  var counter = 1;
  for(var key in contactMethods) {
    if (contactMethods.hasOwnProperty(key) && (counter <= 3) && (contactMethods[key])) {
      switch(key) {
          case 'twitter':
              topContacts = topContacts + '<https://twitter.com/' + contactMethods[key] +'|Twitter> | ';
              break;
          case 'web':
              topContacts = topContacts + '<' + contactMethods[key] +'|Web> | ';
              break;
          case 'chat':
              topContacts = topContacts + '<' + contactMethods[key] +'|Chat> | ';
              break;
          case 'facebook':
              topContacts = topContacts + '<' + contactMethods[key] +'|Facebook> | ';
              break;
          default:
              topContacts = topContacts + contactMethods[key] + ' | ';
      }
      counter += 1;
    }
  }
  if (topContacts) {
    topContacts = topContacts.slice(0, -3);
  }
  console.log("Formatted string for Slack contact methods: " + topContacts);
  return topContacts;
};

/**
 * convert an array of strings to one string separated by commas, with each entry *bolded*
 *
 * @param arrayOfStrings
 * @return {otherCompaniesList}
 */
function convertArrayToBoldList(arrayOfStrings) {
  var otherCompaniesList = '*';
  otherCompaniesList = otherCompaniesList + arrayOfStrings.join('*, *') + "*";
  return otherCompaniesList;
}

/**
 * OAuth stuff
 *
 * @return {promise}
 */
function oauthResponse(req, res) {
  var query = req.query;
  console.log('Query captured from OAuth request: ' + JSON.stringify(query));
  var code = query.code || '';
  var clientId = config.slackClientId || '';
  var clientSecret = config.slackClientSecret || '';
  // var deferred = Q.defer();
  var uri = 'https://slack.com/api/oauth.access';
  var payload = {
    uri: uri,
    method: 'POST',
    // charset: 'utf-8',
    json: {
      client_id: clientId,
      client_secret: clientSecret,
      code: code
    }
  };
  console.log('Payload prepared for OAuth response: ' + JSON.stringify(payload));

  // You will need to exchange the code for an access token using the oauth.access method.
  request(payload, function (error, response, body) {
    if (error) {
      console.log('Ran into error while sending reply to OAuth prompt: ' + error);
    }
    else {
      console.log('Success of reply to OAuth prompt: ' + JSON.stringify(body));
      res.redirect('http://localhost:4200');
    }
  });
};

module.exports = {
  // verify: verify,
  translateRequestToGenericFormats: translateRequestToGenericFormats,
  generateResponsePayloads: generateResponsePayloads,
  formBasicPayload: formBasicPayload,
  loadPostsAttachments: loadPostsAttachments,
  loadContactsAttachments: loadContactsAttachments,
  loadOtherCompaniesAttachments: loadOtherCompaniesAttachments,
  formatContacts: formatContacts,
  convertArrayToBoldList: convertArrayToBoldList,
  oauthResponse: oauthResponse
};
<commit_msg>debug<commit_after>'use strict';

const utilities = require('../brain/utilities');
const config = require('../config/config');
const request = require('request');
const Q = require('q');

/**
 * Verifies that request actually coming from Slack
 * not currently in use
 *
 * @param req
 * @param res
 */
// function verify() {
//   console.log("Nothing to see here.")
// }

/**
 * Makes array of generic request objects from incoming context
 *
 * @param context
 * @return {genericRequests}
 */
function translateRequestToGenericFormats(context) {
  var text = context.userRequest.text;
  var verifyToken = config.slackVerifyToken;
  var incomingToken = context.userRequest.token;
  var genericRequests = [{
    reqType: 'user-input',
    userInput: '',
    context: context
  }];

  // checking for valid token from Slack
  if (verifyToken !== incomingToken) {
    console.log('Slack access token mismatch! Ignoring incoming request.');
    console.log('Incoming Token: ' + incomingToken);
    console.log('Verify Token: ' + verifyToken);
    return [];
  };
  console.log('Slack access token match! It\'s all good, man.');

  if (text) {
    genericRequests[0].userInput = text;
  };
  if (text.toLowerCase() === 'help') {
    console.log('Detected user input of \"help\"');
    genericRequests[0].reqType = 'help';
  };
  console.log('Slack bot has prepared this generic request: ' + JSON.stringify(genericRequests));
  return genericRequests;
}

/**
 * Takes generic response data and structures payloads for Slack sending
 *
 * @param genericResponse
 * @return {payloads}
 */
function generateResponsePayloads(genericResponse) {
  console.log("About to begin generating payloads from genericResponse.");
  // form basic payload
  var payloads = formBasicPayload(genericResponse);
  var type = genericResponse.type;

  // if a False object passed in, passes down False to next step
  if (!genericResponse) {
    return false;
  };

  // Refactor to switch statement?
  // Case: no user input
  if (type === 'no-input') {
    console.log('No user input flag detected in genericResponse.');
    payloads[0].json.text = 'Tell me the company you would like to contact.';
    return payloads;
  } else if (type === 'help') {
    // Case: Help user
    console.log('Help flag detected in genericResponse.');
    payloads[0].json.text = 'It looks like you need some help. Please tell me the name of the company you want to reach, and I will provide you with a list of the top issues for customers of this company, the company\'s contact info, and a list of other companies you may want to search for.';
    return payloads;
  } else if (type === 'nothing-found') {
    // Case: nothing returned from Companies search / junk input
    console.log('No Company Results flag detected in genericResponse.');
    payloads[0].json.text = 'I couldn\'t tell what you meant by \"' + genericResponse.userInput + '\". Please tell me company you are looking for. (ex: \"/gethuman Verizon Wireless\")';
    return payloads;
  } else if (type === 'standard') {
    // do we need the explicit type check after the first two, or just 'else'?
    // Refactor inner parts of this case to a function?
    console.log('Standard type flag detected in genericResponse.');
    var name = genericResponse.data.name || '';
    var posts = genericResponse.data.posts || [];
    var otherCompanies = genericResponse.data.otherCompanies || [];
    var topContacts = formatContacts(genericResponse.data.contactMethods);
    if (posts && posts.length) {
      payloads = loadPostsAttachments(payloads, posts, name);
      console.log('Posts info pushed into Payloads');
    };
    if (topContacts) {
      payloads = loadContactsAttachments(payloads, topContacts, name);
      console.log('Company Contact Info pushed into Payloads');
    };
    if (otherCompanies && otherCompanies.length) {
      payloads = loadOtherCompaniesAttachments(payloads, otherCompanies, name);
      console.log('Other Companies info pushed into Payloads');
    };
    if (!payloads[0].json.attachments.length) {
        payloads[0].json.text = 'I couldn\'t find anything for \"' + name + '\". Please tell me which company you are looking for. (ex: \"/gethuman Verizon Wireless\")';
        console.log('No card info found for Companies, returning Nothing Found text.');
    }
    return payloads;
  }
}

/**
 * Forms base payload for Slack response
 *
 * @param genericResponse
 * @return {payloads}
 */
function formBasicPayload(genericResponse) {
  var path = config.slackAccessToken;
  var uri = 'https://hooks.slack.com/services/' + path;
  var channel = genericResponse.context.userRequest.channel_id;
  var payloads = [{
    uri: uri,
    method: 'POST',
    json: {
      channel: channel,
      username: 'GetHuman',
      icon_emoji: ':gethuman:',
      text: '',
      attachments: []
    }
  }];
  return payloads;
};

/**
 * Forms payload attachment for Posts information
 *
 * @param payloads
 * @param posts
 * @param name
 * @return {payloads}
 */
function loadPostsAttachments(payloads, posts, name) {
  var colors = utilities.colors;
  payloads[0].json.text = 'Top issues for ' + name + ':';
  for (let i = 0; i < posts.length; i++) {
      let title = posts[i].title || '';
      let urlId = posts[i].urlId || '';
      let color = colors[i];
      let singleAttachment = {
          "fallback": "Issue for " + name,
          "title": title,
          "color": color,
          "fields": [
              {
                  "value": "<https://gethuman.com?company=" + encodeURIComponent(name) + "|Solve for me - $20>",
                  "short": true
              },
              {
                  "value": "<https://answers.gethuman.co/_" + encodeURIComponent(urlId) + "|More info ...>",
                  "short": true
              }
          ]
      };
      payloads[0].json.attachments.push(singleAttachment);
  };
  return payloads;
};

/**
 * Forms payload attachment for Contact information
 *
 * @param payloads
 * @param topContacts
 * @param name
 * @return {payloads}
 */
function loadContactsAttachments(payloads, topContacts, name) {
  payloads[0].json.attachments.push({
      fallback: 'Contact info for ' + name,
      title: 'Best ways to contact ' + name,
      color: '#999999',
      text: topContacts,
  });
  return payloads;
}

/**
 * Forms payload attachment for Other Companies information
 *
 * @param payloads
 * @param otherCompanies
 * @param name
 * @return {payloads}
 */
function loadOtherCompaniesAttachments(payloads, otherCompanies, name) {
  var otherCompaniesList = convertArrayToBoldList(otherCompanies);
  payloads[0].json.attachments.push({
      fallback: 'Other solutions',
      title: 'Were you talking about ' + name + '?',
      color: '#BBBBBB',
      text: 'Or maybe you meant ' + otherCompaniesList + '?',
      mrkdwn_in: ["text"]
  });
  return payloads;
}

/**
 * Takes contact methods, forms a structured string of <= 3 items for display
 *
 * @param contactMethods
 * @return {topContacts}
 */
function formatContacts(contactMethods) {
  var topContacts = '';
  var counter = 1;
  for(var key in contactMethods) {
    if (contactMethods.hasOwnProperty(key) && (counter <= 3) && (contactMethods[key])) {
      switch(key) {
          case 'twitter':
              topContacts = topContacts + '<https://twitter.com/' + contactMethods[key] +'|Twitter> | ';
              break;
          case 'web':
              topContacts = topContacts + '<' + contactMethods[key] +'|Web> | ';
              break;
          case 'chat':
              topContacts = topContacts + '<' + contactMethods[key] +'|Chat> | ';
              break;
          case 'facebook':
              topContacts = topContacts + '<' + contactMethods[key] +'|Facebook> | ';
              break;
          default:
              topContacts = topContacts + contactMethods[key] + ' | ';
      }
      counter += 1;
    }
  }
  if (topContacts) {
    topContacts = topContacts.slice(0, -3);
  }
  console.log("Formatted string for Slack contact methods: " + topContacts);
  return topContacts;
};

/**
 * convert an array of strings to one string separated by commas, with each entry *bolded*
 *
 * @param arrayOfStrings
 * @return {otherCompaniesList}
 */
function convertArrayToBoldList(arrayOfStrings) {
  var otherCompaniesList = '*';
  otherCompaniesList = otherCompaniesList + arrayOfStrings.join('*, *') + "*";
  return otherCompaniesList;
}

/**
 * OAuth stuff
 *
 * @return {promise}
 */
function oauthResponse(req, res) {
  var query = req.query;
  console.log('Query captured from OAuth request: ' + JSON.stringify(query));
  var code = query.code || '';
  var clientId = config.slackClientId || '';
  var clientSecret = config.slackClientSecret || '';
  // var deferred = Q.defer();
  var uri = 'https://slack.com/api/oauth.access';
  var payload = {
    uri: uri,
    method: 'POST',
    // charset: 'utf-8',
    json: JSON.parse({
      client_id: clientId,
      client_secret: clientSecret,
      code: code
    })
  };
  console.log('Payload prepared for OAuth response: ' + JSON.stringify(payload));

  // You will need to exchange the code for an access token using the oauth.access method.
  request(payload, function (error, response, body) {
    if (error) {
      console.log('Ran into error while sending reply to OAuth prompt: ' + error);
    }
    else {
      console.log('Success of reply to OAuth prompt: ' + JSON.stringify(body));
      res.redirect('http://localhost:4200');
    }
  });
};

module.exports = {
  // verify: verify,
  translateRequestToGenericFormats: translateRequestToGenericFormats,
  generateResponsePayloads: generateResponsePayloads,
  formBasicPayload: formBasicPayload,
  loadPostsAttachments: loadPostsAttachments,
  loadContactsAttachments: loadContactsAttachments,
  loadOtherCompaniesAttachments: loadOtherCompaniesAttachments,
  formatContacts: formatContacts,
  convertArrayToBoldList: convertArrayToBoldList,
  oauthResponse: oauthResponse
};
<|endoftext|>


<commit_before>"use strict";

if(!window.requestAnimationFrame)
{
    window.requestAnimationFrame =
        window.mozRequestAnimationFrame ||
        window.webkitRequestAnimationFrame;
}

/**
 * Adapter to use visual screen in browsers (in constrast to node)
 * @constructor
 */
function ScreenAdapter()
{
    var
        dom_target = document.body,
        text_screen = document.getElementById("screen"),
        graphic_screen = document.getElementById("vga"),
        graphic_context = graphic_screen.getContext("2d"),
        cursor_element = document.createElement("div"),

        graphic_image_data,
        graphic_buffer,
        graphic_buffer32,

        /** @type {number} */
        cursor_row,

        /** @type {number} */
        cursor_col,

        /** @type {number} */
        scale_x = 1,

        /** @type {number} */
        scale_y = 1,

        graphical_mode_width,

        modified_pixel_min = 0,
        modified_pixel_max = 0,

        screen = this,

        changed_rows,

        did_redraw = true,

        // Index 0: ASCII code
        // Index 1: Background color
        // Index 2: Foreground color
        text_mode_data,

        // number of columns
        text_mode_width,

        // number of rows
        text_mode_height;

    // 0x12345 -> "#012345"
    function number_as_color(n)
    {
        n = n.toString(16);

        return "#" + Array(7 - n.length).join("0") + n;
    }

    /**
     * Charmaps that containt unicode sequences for the default dospage
     * @const
     */
    var charmap_high = new Uint16Array([
        0xC7, 0xFC, 0xE9, 0xE2, 0xE4, 0xE0, 0xE5, 0xE7,
        0xEA, 0xEB, 0xE8, 0xEF, 0xEE, 0xEC, 0xC4, 0xC5,
        0xC9, 0xE6, 0xC6, 0xF4, 0xF6, 0xF2, 0xFB, 0xF9,
        0xFF, 0xD6, 0xDC, 0xA2, 0xA3, 0xA5, 0x20A7, 0x192,
        0xE1, 0xED, 0xF3, 0xFA, 0xF1, 0xD1, 0xAA, 0xBA,
        0xBF, 0x2310, 0xAC, 0xBD, 0xBC, 0xA1, 0xAB, 0xBB,
        0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
        0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
        0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F,
        0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
        0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B,
        0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
        0x3B1, 0xDF, 0x393, 0x3C0, 0x3A3, 0x3C3, 0xB5, 0x3C4,
        0x3A6, 0x398, 0x3A9, 0x3B4, 0x221E, 0x3C6, 0x3B5, 0x2229,
        0x2261, 0xB1, 0x2265, 0x2264, 0x2320, 0x2321, 0xF7,
        0x2248, 0xB0, 0x2219, 0xB7, 0x221A, 0x207F, 0xB2, 0x25A0, 0xA0
    ]);

    /** @const */
    var charmap_low = new Uint16Array([
        0x20,   0x263A, 0x263B, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022,
        0x25D8, 0x25CB, 0x25D9, 0x2642, 0x2640, 0x266A, 0x266B, 0x263C,
        0x25BA, 0x25C4, 0x2195, 0x203C, 0xB6,   0xA7,   0x25AC, 0x21A8,
        0x2191, 0x2193, 0x2192, 0x2190, 0x221F, 0x2194, 0x25B2, 0x25BC
    ]);

    var charmap = [],
        chr;

    for(var i = 0; i < 256; i++)
    {
        if(i > 127)
        {
            chr = charmap_high[i - 0x80];
        }
        else if(i < 32)
        {
            chr = charmap_low[i];
        }
        else
        {
            chr = i;
        }

        charmap[i] = String.fromCharCode(chr);
    }

    graphic_context["imageSmoothingEnabled"] = false;
    graphic_context["mozImageSmoothingEnabled"] = false;
    graphic_context["webkitImageSmoothingEnabled"] = false;

    cursor_element.id = "cursor";
    text_screen.style.display = "block";

    graphic_screen.style.display = "none";

    this.make_screenshot = function()
    {
        try {
            window.open(graphic_screen.toDataURL());
        }
        catch(e) {}
    };

    this.put_char = function(row, col, chr, bg_color, fg_color)
    {
        if(row < text_mode_height && col < text_mode_width)
        {
            var p = 3 * (row * text_mode_width + col);
            dbg_assert(p + 2 <= text_mode_data.length);

            text_mode_data[p] = chr;
            text_mode_data[p + 1] = bg_color;
            text_mode_data[p + 2] = fg_color;

            changed_rows[row] = 1;
        }
    };

    this.timer_text = function()
    {
        if(!did_redraw)
        {
            return;
        }
        did_redraw = false;

        requestAnimationFrame(update_text);
    };

    function update_text()
    {
        did_redraw = true;

        for(var i = 0; i < text_mode_height; i++)
        {
            if(changed_rows[i])
            {
                screen.text_update_row(i);
                changed_rows[i] = 0;
            }
        }
    }

    this.put_pixel = function(x, y, color)
    {
        var index = y * graphical_mode_width + x << 2;

        graphic_buffer[index] = color >> 16;
        graphic_buffer[index + 1] = color >> 8;
        graphic_buffer[index + 2] = color;

        modified_pixel_min = index < modified_pixel_min ? index : modified_pixel_min;
        modified_pixel_max = index > modified_pixel_max ? index : modified_pixel_max;
    };

    // put a single color component
    this.put_pixel_linear = function(index, color)
    {
        dbg_assert((index & 3) !== 3);

        if(index >= graphic_buffer.length)
        {
            return;
        }

        modified_pixel_min = index < modified_pixel_min ? index : modified_pixel_min;
        modified_pixel_max = index > modified_pixel_max ? index : modified_pixel_max;

        // (addr + 1) ^ 3: Change BGR (svga) order to RGB (canvas)
        graphic_buffer[(index + 1) ^ 3] = color;
    };

    // put a single color
    this.put_pixel_linear32 = function(index, color)
    {
        dbg_assert((index & 3) === 0);

        if(index >= graphic_buffer.length)
        {
            dbg_log("Write outside of buffer: " + h(index), LOG_VGA);
            return;
        }

        modified_pixel_min = index < modified_pixel_min ? index : modified_pixel_min;
        modified_pixel_max = index > modified_pixel_max ? index : modified_pixel_max;

        graphic_buffer32[index >> 2] = 0xFF000000 | color >> 16 | (color << 16 | color) & 0xFFFF00;
    };

    this.timer_graphical = function()
    {
        if(!did_redraw)
        {
            return;
        }
        did_redraw = false;

        requestAnimationFrame(function()
        {
            did_redraw = true;

            if(modified_pixel_min < modified_pixel_max)
            {
                var top = modified_pixel_min / graphical_mode_width >> 2;
                var height = ((modified_pixel_max - modified_pixel_min) / graphical_mode_width >> 2) + 1;

                graphic_context.putImageData(
                    graphic_image_data,
                    0, 0,
                    0, top,
                    graphical_mode_width, height
                );

                modified_pixel_min = 1e7;
                modified_pixel_max = 0;
            }
        });
    };

    this.destroy = function()
    {
        //dom_target.removeChild(text_screen);
        //dom_target.removeChild(graphic_screen);
    };

    this.set_mode = function(graphical)
    {
        if(graphical)
        {
            text_screen.style.display = "none";
            graphic_screen.style.display = "block";
        }
        else
        {
            text_screen.style.display = "block";
            graphic_screen.style.display = "none";
        }
    };

    this.clear_screen = function()
    {
        graphic_context.fillStyle = "#000";
        graphic_context.fillRect(0, 0, graphic_screen.width, graphic_screen.height);
    };

    /**
     * @param {number} cols
     * @param {number} rows
     */
    this.set_size_text = function(cols, rows)
    {
        changed_rows = new Int8Array(rows);
        text_mode_data = new Int32Array(cols * rows * 3);

        text_mode_width = cols;
        text_mode_height = rows;

        while(text_screen.firstChild)
        {
            text_screen.removeChild(text_screen.firstChild);
        }

        for(var i = 0; i < rows; i++)
        {
            text_screen.appendChild(document.createElement("div"));
        }

        for(var i = 0; i < rows; i++)
        {
            this.text_update_row(i);
        }
    };

    this.set_size_graphical = function(width, height)
    {
        graphic_screen.style.display = "block";

        graphic_screen.width = width;
        graphic_screen.height = height;

        //graphic_screen.style.width = width * scale_x + "px";
        //graphic_screen.style.height = height * scale_y + "px";

        // Make sure to call this here, because pixels are transparent otherwise
        screen.clear_screen();

        graphic_image_data = graphic_context.getImageData(0, 0, width, height);
        graphic_buffer = new Uint8Array(graphic_image_data.data.buffer);
        graphic_buffer32 = new Int32Array(graphic_image_data.data.buffer);

        graphical_mode_width = width;
    };

    this.set_scale = function(s_x, s_y)
    {
        scale_x = s_x;
        scale_y = s_y;

        elem_set_scale(graphic_screen, scale_x, scale_y);
        elem_set_scale(text_screen, scale_x, scale_y);
    };
    this.set_scale(scale_x, scale_y);

    function elem_set_scale(elem, scale_x, scale_y)
    {
        var scale_str = "";

        scale_str += scale_x === 1 ? "" : " scaleX(" + scale_x + ")";
        scale_str += scale_y === 1 ? "" : " scaleY(" + scale_y + ")";

        elem.style.webkitTransform = elem.style.MozTransform = scale_str;
    }

    this.update_cursor_scanline = function(start, end)
    {
        if(start & 0x20)
        {
            cursor_element.style.display = "none";
        }
        else
        {
            cursor_element.style.display = "inline";

            cursor_element.style.height = Math.min(15, end - start) + "px";
            cursor_element.style.marginTop = Math.min(15, start) + "px";
        }
    };

    this.update_cursor = function(row, col)
    {
        if(row !== cursor_row || col !== cursor_col)
        {
            changed_rows[row] = 1;
            changed_rows[cursor_row] = 1;

            cursor_row = row;
            cursor_col = col;
        }
    };

    this.text_update_row = function(row)
    {
        var offset = 3 * row * text_mode_width,
            row_element,
            color_element,
            fragment;

        var
            bg_color,
            fg_color,
            text;

        row_element = text_screen.childNodes[row];
        fragment = document.createDocumentFragment();

        while(row_element.firstChild)
        {
            row_element.removeChild(row_element.firstChild);
        }

        for(var i = 0; i < text_mode_width; )
        {
            color_element = document.createElement("span");

            bg_color = text_mode_data[offset + 1];
            fg_color = text_mode_data[offset + 2];

            color_element.style.backgroundColor = number_as_color(bg_color);
            color_element.style.color = number_as_color(fg_color);

            text = "";

            // put characters of the same color in one element
            while(i < text_mode_width
                    && text_mode_data[offset + 1] === bg_color
                    && text_mode_data[offset + 2] === fg_color)
            {
                var ascii = text_mode_data[offset];

                text += charmap[ascii];

                i++;
                offset += 3;

                if(row === cursor_row)
                {
                    if(i === cursor_col)
                    {
                        // next row will be cursor
                        // create new element
                        break;
                    }
                    else if(i === cursor_col + 1)
                    {
                        // found the cursor
                        fragment.appendChild(cursor_element);
                        break;
                    }
                }
            }

            color_element.textContent = text;
            fragment.appendChild(color_element);
        }

        row_element.appendChild(fragment);
    };
}
<commit_msg>Correct conversion from RGB to BGR<commit_after>"use strict";

if(!window.requestAnimationFrame)
{
    window.requestAnimationFrame =
        window.mozRequestAnimationFrame ||
        window.webkitRequestAnimationFrame;
}

/**
 * Adapter to use visual screen in browsers (in constrast to node)
 * @constructor
 */
function ScreenAdapter()
{
    var
        dom_target = document.body,
        text_screen = document.getElementById("screen"),
        graphic_screen = document.getElementById("vga"),
        graphic_context = graphic_screen.getContext("2d"),
        cursor_element = document.createElement("div"),

        graphic_image_data,
        graphic_buffer,
        graphic_buffer32,

        /** @type {number} */
        cursor_row,

        /** @type {number} */
        cursor_col,

        /** @type {number} */
        scale_x = 1,

        /** @type {number} */
        scale_y = 1,

        graphical_mode_width,

        modified_pixel_min = 0,
        modified_pixel_max = 0,

        screen = this,

        changed_rows,

        did_redraw = true,

        // Index 0: ASCII code
        // Index 1: Background color
        // Index 2: Foreground color
        text_mode_data,

        // number of columns
        text_mode_width,

        // number of rows
        text_mode_height;

    // 0x12345 -> "#012345"
    function number_as_color(n)
    {
        n = n.toString(16);

        return "#" + Array(7 - n.length).join("0") + n;
    }

    /**
     * Charmaps that containt unicode sequences for the default dospage
     * @const
     */
    var charmap_high = new Uint16Array([
        0xC7, 0xFC, 0xE9, 0xE2, 0xE4, 0xE0, 0xE5, 0xE7,
        0xEA, 0xEB, 0xE8, 0xEF, 0xEE, 0xEC, 0xC4, 0xC5,
        0xC9, 0xE6, 0xC6, 0xF4, 0xF6, 0xF2, 0xFB, 0xF9,
        0xFF, 0xD6, 0xDC, 0xA2, 0xA3, 0xA5, 0x20A7, 0x192,
        0xE1, 0xED, 0xF3, 0xFA, 0xF1, 0xD1, 0xAA, 0xBA,
        0xBF, 0x2310, 0xAC, 0xBD, 0xBC, 0xA1, 0xAB, 0xBB,
        0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
        0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
        0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F,
        0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
        0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B,
        0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
        0x3B1, 0xDF, 0x393, 0x3C0, 0x3A3, 0x3C3, 0xB5, 0x3C4,
        0x3A6, 0x398, 0x3A9, 0x3B4, 0x221E, 0x3C6, 0x3B5, 0x2229,
        0x2261, 0xB1, 0x2265, 0x2264, 0x2320, 0x2321, 0xF7,
        0x2248, 0xB0, 0x2219, 0xB7, 0x221A, 0x207F, 0xB2, 0x25A0, 0xA0
    ]);

    /** @const */
    var charmap_low = new Uint16Array([
        0x20,   0x263A, 0x263B, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022,
        0x25D8, 0x25CB, 0x25D9, 0x2642, 0x2640, 0x266A, 0x266B, 0x263C,
        0x25BA, 0x25C4, 0x2195, 0x203C, 0xB6,   0xA7,   0x25AC, 0x21A8,
        0x2191, 0x2193, 0x2192, 0x2190, 0x221F, 0x2194, 0x25B2, 0x25BC
    ]);

    var charmap = [],
        chr;

    for(var i = 0; i < 256; i++)
    {
        if(i > 127)
        {
            chr = charmap_high[i - 0x80];
        }
        else if(i < 32)
        {
            chr = charmap_low[i];
        }
        else
        {
            chr = i;
        }

        charmap[i] = String.fromCharCode(chr);
    }

    graphic_context["imageSmoothingEnabled"] = false;
    graphic_context["mozImageSmoothingEnabled"] = false;
    graphic_context["webkitImageSmoothingEnabled"] = false;

    cursor_element.id = "cursor";
    text_screen.style.display = "block";

    graphic_screen.style.display = "none";

    this.make_screenshot = function()
    {
        try {
            window.open(graphic_screen.toDataURL());
        }
        catch(e) {}
    };

    this.put_char = function(row, col, chr, bg_color, fg_color)
    {
        if(row < text_mode_height && col < text_mode_width)
        {
            var p = 3 * (row * text_mode_width + col);
            dbg_assert(p + 2 <= text_mode_data.length);

            text_mode_data[p] = chr;
            text_mode_data[p + 1] = bg_color;
            text_mode_data[p + 2] = fg_color;

            changed_rows[row] = 1;
        }
    };

    this.timer_text = function()
    {
        if(!did_redraw)
        {
            return;
        }
        did_redraw = false;

        requestAnimationFrame(update_text);
    };

    function update_text()
    {
        did_redraw = true;

        for(var i = 0; i < text_mode_height; i++)
        {
            if(changed_rows[i])
            {
                screen.text_update_row(i);
                changed_rows[i] = 0;
            }
        }
    }

    this.put_pixel = function(x, y, color)
    {
        var index = y * graphical_mode_width + x << 2;

        graphic_buffer[index] = color >> 16;
        graphic_buffer[index + 1] = color >> 8;
        graphic_buffer[index + 2] = color;

        modified_pixel_min = index < modified_pixel_min ? index : modified_pixel_min;
        modified_pixel_max = index > modified_pixel_max ? index : modified_pixel_max;
    };

    // put a single color component
    this.put_pixel_linear = function(index, color)
    {
        dbg_assert((index & 3) !== 3);

        if(index >= graphic_buffer.length)
        {
            return;
        }

        modified_pixel_min = index < modified_pixel_min ? index : modified_pixel_min;
        modified_pixel_max = index > modified_pixel_max ? index : modified_pixel_max;

        // (addr + 1) ^ 3: Change BGR (svga) order to RGB (canvas)
        graphic_buffer[(index + 1) ^ 3] = color;
    };

    // put a single color
    this.put_pixel_linear32 = function(index, color)
    {
        dbg_assert((index & 3) === 0);

        if(index >= graphic_buffer.length)
        {
            dbg_log("Write outside of buffer: " + h(index), LOG_VGA);
            return;
        }

        modified_pixel_min = index < modified_pixel_min ? index : modified_pixel_min;
        modified_pixel_max = index > modified_pixel_max ? index : modified_pixel_max;

        // change BGR order to RGB
        graphic_buffer32[index >> 2] = 0xFF000000 | color >> 16 & 0xFF | color << 16 | color & 0xFF00;
    };

    this.timer_graphical = function()
    {
        if(!did_redraw)
        {
            return;
        }
        did_redraw = false;

        requestAnimationFrame(function()
        {
            did_redraw = true;

            if(modified_pixel_min < modified_pixel_max)
            {
                var top = modified_pixel_min / graphical_mode_width >> 2;
                var height = ((modified_pixel_max - modified_pixel_min) / graphical_mode_width >> 2) + 1;

                graphic_context.putImageData(
                    graphic_image_data,
                    0, 0,
                    0, top,
                    graphical_mode_width, height
                );

                modified_pixel_min = 1e7;
                modified_pixel_max = 0;
            }
        });
    };

    this.destroy = function()
    {
        //dom_target.removeChild(text_screen);
        //dom_target.removeChild(graphic_screen);
    };

    this.set_mode = function(graphical)
    {
        if(graphical)
        {
            text_screen.style.display = "none";
            graphic_screen.style.display = "block";
        }
        else
        {
            text_screen.style.display = "block";
            graphic_screen.style.display = "none";
        }
    };

    this.clear_screen = function()
    {
        graphic_context.fillStyle = "#000";
        graphic_context.fillRect(0, 0, graphic_screen.width, graphic_screen.height);
    };

    /**
     * @param {number} cols
     * @param {number} rows
     */
    this.set_size_text = function(cols, rows)
    {
        changed_rows = new Int8Array(rows);
        text_mode_data = new Int32Array(cols * rows * 3);

        text_mode_width = cols;
        text_mode_height = rows;

        while(text_screen.firstChild)
        {
            text_screen.removeChild(text_screen.firstChild);
        }

        for(var i = 0; i < rows; i++)
        {
            text_screen.appendChild(document.createElement("div"));
        }

        for(var i = 0; i < rows; i++)
        {
            this.text_update_row(i);
        }
    };

    this.set_size_graphical = function(width, height)
    {
        graphic_screen.style.display = "block";

        graphic_screen.width = width;
        graphic_screen.height = height;

        //graphic_screen.style.width = width * scale_x + "px";
        //graphic_screen.style.height = height * scale_y + "px";

        // Make sure to call this here, because pixels are transparent otherwise
        screen.clear_screen();

        graphic_image_data = graphic_context.getImageData(0, 0, width, height);
        graphic_buffer = new Uint8Array(graphic_image_data.data.buffer);
        graphic_buffer32 = new Int32Array(graphic_image_data.data.buffer);

        graphical_mode_width = width;
    };

    this.set_scale = function(s_x, s_y)
    {
        scale_x = s_x;
        scale_y = s_y;

        elem_set_scale(graphic_screen, scale_x, scale_y);
        elem_set_scale(text_screen, scale_x, scale_y);
    };
    this.set_scale(scale_x, scale_y);

    function elem_set_scale(elem, scale_x, scale_y)
    {
        var scale_str = "";

        scale_str += scale_x === 1 ? "" : " scaleX(" + scale_x + ")";
        scale_str += scale_y === 1 ? "" : " scaleY(" + scale_y + ")";

        elem.style.webkitTransform = elem.style.MozTransform = scale_str;
    }

    this.update_cursor_scanline = function(start, end)
    {
        if(start & 0x20)
        {
            cursor_element.style.display = "none";
        }
        else
        {
            cursor_element.style.display = "inline";

            cursor_element.style.height = Math.min(15, end - start) + "px";
            cursor_element.style.marginTop = Math.min(15, start) + "px";
        }
    };

    this.update_cursor = function(row, col)
    {
        if(row !== cursor_row || col !== cursor_col)
        {
            changed_rows[row] = 1;
            changed_rows[cursor_row] = 1;

            cursor_row = row;
            cursor_col = col;
        }
    };

    this.text_update_row = function(row)
    {
        var offset = 3 * row * text_mode_width,
            row_element,
            color_element,
            fragment;

        var
            bg_color,
            fg_color,
            text;

        row_element = text_screen.childNodes[row];
        fragment = document.createDocumentFragment();

        while(row_element.firstChild)
        {
            row_element.removeChild(row_element.firstChild);
        }

        for(var i = 0; i < text_mode_width; )
        {
            color_element = document.createElement("span");

            bg_color = text_mode_data[offset + 1];
            fg_color = text_mode_data[offset + 2];

            color_element.style.backgroundColor = number_as_color(bg_color);
            color_element.style.color = number_as_color(fg_color);

            text = "";

            // put characters of the same color in one element
            while(i < text_mode_width
                    && text_mode_data[offset + 1] === bg_color
                    && text_mode_data[offset + 2] === fg_color)
            {
                var ascii = text_mode_data[offset];

                text += charmap[ascii];

                i++;
                offset += 3;

                if(row === cursor_row)
                {
                    if(i === cursor_col)
                    {
                        // next row will be cursor
                        // create new element
                        break;
                    }
                    else if(i === cursor_col + 1)
                    {
                        // found the cursor
                        fragment.appendChild(cursor_element);
                        break;
                    }
                }
            }

            color_element.textContent = text;
            fragment.appendChild(color_element);
        }

        row_element.appendChild(fragment);
    };
}
<|endoftext|>


<commit_before>/*
 * Copyright 2015 Google Inc. All Rights Reserved.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var Modes = require('./modes.js');
var Emitter = require('./emitter.js');
var Util = require('./util.js');

/**
 * Everything having to do with the WebVR button.
 * Emits a 'click' event when it's clicked.
 */
function ButtonManager() {
  this.loadIcons_();

  // Make the fullscreen button.
  var fsButton = this.createButton();
  fsButton.src = this.ICONS.fullscreen;
  fsButton.title = 'Fullscreen mode';
  var s = fsButton.style;
  s.bottom = 0;
  s.right = 0;
  fsButton.addEventListener('click', this.createClickHandler_('fs'));
  document.body.appendChild(fsButton);
  this.fsButton = fsButton;

  // Make the VR button.
  var vrButton = this.createButton();
  vrButton.src = this.ICONS.cardboard;
  vrButton.title = 'Virtual reality mode';
  var s = vrButton.style;
  s.bottom = 0;
  s.right = '48px';
  vrButton.addEventListener('click', this.createClickHandler_('vr'));
  document.body.appendChild(vrButton);
  this.vrButton = vrButton;

  // Make the back button.
  var backButton = this.createButton();
  backButton.title = 'Back to previous mode';
  var s = backButton.style;
  s.left = 0;
  s.top = 0;
  backButton.src = this.ICONS.back;
  backButton.addEventListener('click', this.createClickHandler_('back'));
  document.body.appendChild(backButton);
  this.backButton = backButton;

  this.isVisible = true;

}
ButtonManager.prototype = new Emitter();

ButtonManager.prototype.createButton = function() {
  var button = document.createElement('img');
  button.className = 'webvr-button';
  var s = button.style;
  s.position = 'fixed';
  s.width = '24px'
  s.height = '24px';
  s.backgroundSize = 'cover';
  s.backgroundColor = 'transparent';
  s.border = 0;
  s.userSelect = 'none';
  s.webkitUserSelect = 'none';
  s.MozUserSelect = 'none';
  s.cursor = 'pointer';
  s.padding = '12px';
  s.zIndex = 1;
  s.display = 'none';

  // Prevent button from being selected and dragged.
  button.draggable = false;
  button.addEventListener('dragstart', function(e) {
    e.preventDefault();
  });

  // Style it on hover.
  button.addEventListener('mouseenter', function(e) {
    /* -webkit-filter: drop-shadow(0 0 5px rgba(255,255,255,1)); */
    s.webkitFilter = 'drop-shadow(0 0 5px rgba(255,255,255,1))';
  });
  button.addEventListener('mouseleave', function(e) {
    s.webkitFilter = '';
  });
  return button;
};

ButtonManager.prototype.setMode = function(mode, isVRCompatible) {
  if (!this.isVisible) {
    return;
  }
  switch (mode) {
    case Modes.NORMAL:
      this.fsButton.style.display = 'block';
      this.fsButton.src = this.ICONS.fullscreen;
      this.vrButton.style.display = (isVRCompatible ? 'block' : 'none');
      this.backButton.style.display = 'none';
      break;
    case Modes.MAGIC_WINDOW:
      this.fsButton.style.display = 'block';
      this.fsButton.src = this.ICONS.exitFullscreen;
      this.vrButton.style.display = (isVRCompatible ? 'block' : 'none');
      this.backButton.style.display = 'block';
      break;
    case Modes.VR:
      this.fsButton.style.display = 'none';
      this.vrButton.style.display = 'none';
      this.backButton.style.display = 'block';
      break;
  }

  // Hack for Safari Mac/iOS to force relayout (svg-specific issue)
  // http://goo.gl/hjgR6r
  var oldValue = this.fsButton.style.display;
  this.fsButton.style.display = 'inline-block';
  this.fsButton.offsetHeight;
  this.fsButton.style.display = oldValue;
};

ButtonManager.prototype.setVisibility = function(isVisible) {
  this.isVisible = isVisible;
  this.fsButton.style.display = isVisible ? 'block' : 'none';
  this.vrButton.style.display = isVisible ? 'block' : 'none';
  this.backButton.style.display = isVisible ? 'block' : 'none';
};

ButtonManager.prototype.createClickHandler_ = function(eventName) {
  return function(e) {
    e.stopPropagation();
    e.preventDefault();
    this.emit(eventName);
  }.bind(this);
};

ButtonManager.prototype.loadIcons_ = function() {
  // Preload some hard-coded SVG.
  this.ICONS = {};
  this.ICONS.cardboard = Util.base64('image/svg+xml', 'PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNHB4IiBoZWlnaHQ9IjI0cHgiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0iI0ZGRkZGRiI+CiAgICA8cGF0aCBkPSJNMjAuNzQgNkgzLjIxQzIuNTUgNiAyIDYuNTcgMiA3LjI4djEwLjQ0YzAgLjcuNTUgMS4yOCAxLjIzIDEuMjhoNC43OWMuNTIgMCAuOTYtLjMzIDEuMTQtLjc5bDEuNC0zLjQ4Yy4yMy0uNTkuNzktMS4wMSAxLjQ0LTEuMDFzMS4yMS40MiAxLjQ1IDEuMDFsMS4zOSAzLjQ4Yy4xOS40Ni42My43OSAxLjExLjc5aDQuNzljLjcxIDAgMS4yNi0uNTcgMS4yNi0xLjI4VjcuMjhjMC0uNy0uNTUtMS4yOC0xLjI2LTEuMjh6TTcuNSAxNC42MmMtMS4xNyAwLTIuMTMtLjk1LTIuMTMtMi4xMiAwLTEuMTcuOTYtMi4xMyAyLjEzLTIuMTMgMS4xOCAwIDIuMTIuOTYgMi4xMiAyLjEzcy0uOTUgMi4xMi0yLjEyIDIuMTJ6bTkgMGMtMS4xNyAwLTIuMTMtLjk1LTIuMTMtMi4xMiAwLTEuMTcuOTYtMi4xMyAyLjEzLTIuMTNzMi4xMi45NiAyLjEyIDIuMTMtLjk1IDIuMTItMi4xMiAyLjEyeiIvPgogICAgPHBhdGggZmlsbD0ibm9uZSIgZD0iTTAgMGgyNHYyNEgwVjB6Ii8+Cjwvc3ZnPgo=');
  this.ICONS.fullscreen = Util.base64('image/svg+xml', 'PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNHB4IiBoZWlnaHQ9IjI0cHgiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0iI0ZGRkZGRiI+CiAgICA8cGF0aCBkPSJNMCAwaDI0djI0SDB6IiBmaWxsPSJub25lIi8+CiAgICA8cGF0aCBkPSJNNyAxNEg1djVoNXYtMkg3di0zem0tMi00aDJWN2gzVjVINXY1em0xMiA3aC0zdjJoNXYtNWgtMnYzek0xNCA1djJoM3YzaDJWNWgtNXoiLz4KPC9zdmc+Cg==');
  this.ICONS.exitFullscreen = Util.base64('image/svg+xml', 'PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNHB4IiBoZWlnaHQ9IjI0cHgiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0iI0ZGRkZGRiI+CiAgICA8cGF0aCBkPSJNMCAwaDI0djI0SDB6IiBmaWxsPSJub25lIi8+CiAgICA8cGF0aCBkPSJNNSAxNmgzdjNoMnYtNUg1djJ6bTMtOEg1djJoNVY1SDh2M3ptNiAxMWgydi0zaDN2LTJoLTV2NXptMi0xMVY1aC0ydjVoNVY4aC0zeiIvPgo8L3N2Zz4K');
  this.ICONS.back = Util.base64('image/svg+xml', 'PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNHB4IiBoZWlnaHQ9IjI0cHgiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0iI0ZGRkZGRiI+CiAgICA8cGF0aCBkPSJNMCAwaDI0djI0SDB6IiBmaWxsPSJub25lIi8+CiAgICA8cGF0aCBkPSJNMjAgMTFINy44M2w1LjU5LTUuNTlMMTIgNGwtOCA4IDggOCAxLjQxLTEuNDFMNy44MyAxM0gyMHYtMnoiLz4KPC9zdmc+Cg==');
};

module.exports = ButtonManager;
<commit_msg>Add non-prefixed filter style<commit_after>/*
 * Copyright 2015 Google Inc. All Rights Reserved.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var Modes = require('./modes.js');
var Emitter = require('./emitter.js');
var Util = require('./util.js');

/**
 * Everything having to do with the WebVR button.
 * Emits a 'click' event when it's clicked.
 */
function ButtonManager() {
  this.loadIcons_();

  // Make the fullscreen button.
  var fsButton = this.createButton();
  fsButton.src = this.ICONS.fullscreen;
  fsButton.title = 'Fullscreen mode';
  var s = fsButton.style;
  s.bottom = 0;
  s.right = 0;
  fsButton.addEventListener('click', this.createClickHandler_('fs'));
  document.body.appendChild(fsButton);
  this.fsButton = fsButton;

  // Make the VR button.
  var vrButton = this.createButton();
  vrButton.src = this.ICONS.cardboard;
  vrButton.title = 'Virtual reality mode';
  var s = vrButton.style;
  s.bottom = 0;
  s.right = '48px';
  vrButton.addEventListener('click', this.createClickHandler_('vr'));
  document.body.appendChild(vrButton);
  this.vrButton = vrButton;

  // Make the back button.
  var backButton = this.createButton();
  backButton.title = 'Back to previous mode';
  var s = backButton.style;
  s.left = 0;
  s.top = 0;
  backButton.src = this.ICONS.back;
  backButton.addEventListener('click', this.createClickHandler_('back'));
  document.body.appendChild(backButton);
  this.backButton = backButton;

  this.isVisible = true;

}
ButtonManager.prototype = new Emitter();

ButtonManager.prototype.createButton = function() {
  var button = document.createElement('img');
  button.className = 'webvr-button';
  var s = button.style;
  s.position = 'fixed';
  s.width = '24px'
  s.height = '24px';
  s.backgroundSize = 'cover';
  s.backgroundColor = 'transparent';
  s.border = 0;
  s.userSelect = 'none';
  s.webkitUserSelect = 'none';
  s.MozUserSelect = 'none';
  s.cursor = 'pointer';
  s.padding = '12px';
  s.zIndex = 1;
  s.display = 'none';

  // Prevent button from being selected and dragged.
  button.draggable = false;
  button.addEventListener('dragstart', function(e) {
    e.preventDefault();
  });

  // Style it on hover.
  button.addEventListener('mouseenter', function(e) {
    s.filter = s.webkitFilter = 'drop-shadow(0 0 5px rgba(255,255,255,1))';
  });
  button.addEventListener('mouseleave', function(e) {
    s.filter = s.webkitFilter = '';
  });
  return button;
};

ButtonManager.prototype.setMode = function(mode, isVRCompatible) {
  if (!this.isVisible) {
    return;
  }
  switch (mode) {
    case Modes.NORMAL:
      this.fsButton.style.display = 'block';
      this.fsButton.src = this.ICONS.fullscreen;
      this.vrButton.style.display = (isVRCompatible ? 'block' : 'none');
      this.backButton.style.display = 'none';
      break;
    case Modes.MAGIC_WINDOW:
      this.fsButton.style.display = 'block';
      this.fsButton.src = this.ICONS.exitFullscreen;
      this.vrButton.style.display = (isVRCompatible ? 'block' : 'none');
      this.backButton.style.display = 'block';
      break;
    case Modes.VR:
      this.fsButton.style.display = 'none';
      this.vrButton.style.display = 'none';
      this.backButton.style.display = 'block';
      break;
  }

  // Hack for Safari Mac/iOS to force relayout (svg-specific issue)
  // http://goo.gl/hjgR6r
  var oldValue = this.fsButton.style.display;
  this.fsButton.style.display = 'inline-block';
  this.fsButton.offsetHeight;
  this.fsButton.style.display = oldValue;
};

ButtonManager.prototype.setVisibility = function(isVisible) {
  this.isVisible = isVisible;
  this.fsButton.style.display = isVisible ? 'block' : 'none';
  this.vrButton.style.display = isVisible ? 'block' : 'none';
  this.backButton.style.display = isVisible ? 'block' : 'none';
};

ButtonManager.prototype.createClickHandler_ = function(eventName) {
  return function(e) {
    e.stopPropagation();
    e.preventDefault();
    this.emit(eventName);
  }.bind(this);
};

ButtonManager.prototype.loadIcons_ = function() {
  // Preload some hard-coded SVG.
  this.ICONS = {};
  this.ICONS.cardboard = Util.base64('image/svg+xml', 'PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNHB4IiBoZWlnaHQ9IjI0cHgiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0iI0ZGRkZGRiI+CiAgICA8cGF0aCBkPSJNMjAuNzQgNkgzLjIxQzIuNTUgNiAyIDYuNTcgMiA3LjI4djEwLjQ0YzAgLjcuNTUgMS4yOCAxLjIzIDEuMjhoNC43OWMuNTIgMCAuOTYtLjMzIDEuMTQtLjc5bDEuNC0zLjQ4Yy4yMy0uNTkuNzktMS4wMSAxLjQ0LTEuMDFzMS4yMS40MiAxLjQ1IDEuMDFsMS4zOSAzLjQ4Yy4xOS40Ni42My43OSAxLjExLjc5aDQuNzljLjcxIDAgMS4yNi0uNTcgMS4yNi0xLjI4VjcuMjhjMC0uNy0uNTUtMS4yOC0xLjI2LTEuMjh6TTcuNSAxNC42MmMtMS4xNyAwLTIuMTMtLjk1LTIuMTMtMi4xMiAwLTEuMTcuOTYtMi4xMyAyLjEzLTIuMTMgMS4xOCAwIDIuMTIuOTYgMi4xMiAyLjEzcy0uOTUgMi4xMi0yLjEyIDIuMTJ6bTkgMGMtMS4xNyAwLTIuMTMtLjk1LTIuMTMtMi4xMiAwLTEuMTcuOTYtMi4xMyAyLjEzLTIuMTNzMi4xMi45NiAyLjEyIDIuMTMtLjk1IDIuMTItMi4xMiAyLjEyeiIvPgogICAgPHBhdGggZmlsbD0ibm9uZSIgZD0iTTAgMGgyNHYyNEgwVjB6Ii8+Cjwvc3ZnPgo=');
  this.ICONS.fullscreen = Util.base64('image/svg+xml', 'PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNHB4IiBoZWlnaHQ9IjI0cHgiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0iI0ZGRkZGRiI+CiAgICA8cGF0aCBkPSJNMCAwaDI0djI0SDB6IiBmaWxsPSJub25lIi8+CiAgICA8cGF0aCBkPSJNNyAxNEg1djVoNXYtMkg3di0zem0tMi00aDJWN2gzVjVINXY1em0xMiA3aC0zdjJoNXYtNWgtMnYzek0xNCA1djJoM3YzaDJWNWgtNXoiLz4KPC9zdmc+Cg==');
  this.ICONS.exitFullscreen = Util.base64('image/svg+xml', 'PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNHB4IiBoZWlnaHQ9IjI0cHgiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0iI0ZGRkZGRiI+CiAgICA8cGF0aCBkPSJNMCAwaDI0djI0SDB6IiBmaWxsPSJub25lIi8+CiAgICA8cGF0aCBkPSJNNSAxNmgzdjNoMnYtNUg1djJ6bTMtOEg1djJoNVY1SDh2M3ptNiAxMWgydi0zaDN2LTJoLTV2NXptMi0xMVY1aC0ydjVoNVY4aC0zeiIvPgo8L3N2Zz4K');
  this.ICONS.back = Util.base64('image/svg+xml', 'PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNHB4IiBoZWlnaHQ9IjI0cHgiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0iI0ZGRkZGRiI+CiAgICA8cGF0aCBkPSJNMCAwaDI0djI0SDB6IiBmaWxsPSJub25lIi8+CiAgICA8cGF0aCBkPSJNMjAgMTFINy44M2w1LjU5LTUuNTlMMTIgNGwtOCA4IDggOCAxLjQxLTEuNDFMNy44MyAxM0gyMHYtMnoiLz4KPC9zdmc+Cg==');
};

module.exports = ButtonManager;
<|endoftext|>


<commit_before>window.c.ProjectMain = (function(m, c, _, h){
  return {
    controller: function(args) {
      var project = args.project,
          generateRoutes = function() {
            var hash = window.location.hash,
                c_opts = {project: project},
                routes = {
                  '#about': m.component(c.ProjectAbout, c_opts),
                  '#comments': m.component(c.ProjectComments, c_opts)
                };

            h.fbParse();

            if (_.isEmpty(hash)) {
              return routes['#about'];
            }

            return routes[hash];
          };

      window.addEventListener('hashchange', m.redraw, false);

      return {
        project: project,
        generateRoutes: generateRoutes
      };
    },

    view: function(ctrl) {
      return m('section.section[itemtype="http://schema.org/CreativeWork"]', [
        m('.w-container', [
          m('.w-row', ctrl.generateRoutes())
        ])
      ]);
    }
  };
}(window.m, window.c, window._, window.c.h));
<commit_msg>added project-reward-list to render at #rewards hash<commit_after>window.c.ProjectMain = (function(m, c, _, h){
  return {
    controller: function(args) {
      var project = args.project,
          generateRoutes = function() {
            var hash = window.location.hash,
                c_opts = {project: project},
                routes = {
                  '#rewards': m('.w-col.w-col-12', m.component(c.ProjectRewardList, c_opts)),
                  '#about': m.component(c.ProjectAbout, c_opts),
                  '#comments': m.component(c.ProjectComments, c_opts)
                };

            h.fbParse();

            if (_.isEmpty(hash)) {
              return routes['#about'];
            }

            return routes[hash];
          };

      window.addEventListener('hashchange', m.redraw, false);

      return {
        project: project,
        generateRoutes: generateRoutes
      };
    },

    view: function(ctrl) {
      return m('section.section[itemtype="http://schema.org/CreativeWork"]', [
        m('.w-container', [
          m('.w-row', ctrl.generateRoutes())
        ])
      ]);
    }
  };
}(window.m, window.c, window._, window.c.h));
<|endoftext|>


<commit_before>jsface.pointcuts(jsface.util.Events, {
   bind: function(event, fn) {
      console.log("EVENTS: Binding " + event);
   },

   trigger: function() {
      var args = [].concat(Array.prototype.slice.apply(arguments));
      console.log("EVENTS: Trigger " + args.shift() + " with params: " + args);
   }
});

alert(1);<commit_msg>Remove debug code.<commit_after>jsface.pointcuts(jsface.util.Events, {
   bind: function(event, fn) {
      console.log("EVENTS: Binding " + event);
   },

   trigger: function() {
      var args = [].concat(Array.prototype.slice.apply(arguments));
      console.log("EVENTS: Trigger " + args.shift() + " with params: " + args);
   }
});<|endoftext|>


<commit_before>/**
 * This module is a registry of all Redux action types used within the app.
 * Redux actions are shared by all components/reducers so their names must not
 * collide. Having them defined as constants in a single module is a simple
 * measure to prevent such hard to debug cases.
 *
 * The name and value of the constants must be the same.
 * The name should be the name of the component the action relates to and a verb
 * describing what it does, concatenated by double underscore.
 */

export const INTERACTIONS__LOADED = 'INTERACTIONS__LOADED'
export const INTERACTIONS__SET_INTERACTIONS_METADATA =
  'INTERACTIONS__SET_INTERACTIONS_METADATA'
export const INTERACTIONS__METADATA_LOADED = 'INTERACTIONS__METADATA_LOADED'

export const COMPANIES__LOADED = 'COMPANIES__LOADED'
export const COMPANIES__SET_COMPANIES_METADATA =
  'COMPANIES__SET_COMPANIES_METADATA'

export const COMPANY_LISTS__LISTS_LOADED = 'COMPANY_LISTS__LISTS_LOADED'
export const COMPANY_LISTS__SELECT = 'COMPANY_LISTS__SELECT'
export const COMPANY_LISTS__COMPANIES_LOADED = 'COMPANY_LISTS__COMPANIES_LOADED'
export const COMPANY_LISTS__FILTER = 'COMPANY_LISTS__FILTER'
export const COMPANY_LISTS__ORDER = 'COMPANY_LISTS__ORDER'

export const CONTACTS__LOADED = 'CONTACTS__LOADED'
export const CONTACTS__METADATA_LOADED = 'CONTACTS__METADATA_LOADED'

export const DATA_SUMMARY_PICKER__RANGE_SELECTED =
  'DATA_SUMMARY_PICKER__RANGE_SELECTED'
export const DATA_SUMMARY_PICKER__ACCESSIBLE_TOGGLE =
  'DATA_SUMMARY_PICKER__ACCESSIBLE_TOGGLE'

export const REFERRAL_DETAILS = 'REFERRAL_DETAILS'

export const TASK__START = 'TASK__START'
export const TASK__PROGRESS = 'TASK__PROGRESS'
export const TASK__CANCEL = 'TASK__CANCEL'
export const TASK__ERROR = 'TASK__ERROR'
export const TASK__DISMISS_ERROR = 'TASK__DISMISS_ERROR'
export const TASK__CLEAR = 'TASK__CLEAR'

export const EXPORTS_HISTORY__LOADED = 'EXPORTS_HISTORY__LOADED'
export const EXPORTS_HISTORY__SELECT_PAGE = 'EXPORTS_HISTORY__SELECT_PAGE'

export const TAB_NAV__SELECT = 'TAB_NAV__SELECT'
export const TAB_NAV__FOCUS = 'TAB_NAV__FOCUS'

export const SEND_REFERRAL_FORM__SUBMIT = 'SEND_REFERRAL_FORM__SUBMIT'

export const EDIT_ONE_LIST_DETAILS__SUBMIT = 'EDIT_ONE_LIST_DETAILS__SUBMIT'

export const REFERRAL_LIST__LOADED = 'REFERRAL_LIST__LOADED'
export const REFERRAL_LIST__FILTER_CHANGE = 'REFERRAL_LIST__FILTER_CHANGE'

export const EXPORT_WINS__LOADED = 'EXPORT_WINS__LOADED'
export const EXPORT_WINS__SELECT_PAGE = 'EXPORT_WINS__SELECT_PAGE'

export const EXPORT_COUNTRIES_EDIT__SAVE = 'EXPORT_COUNTRIES_EDIT__SAVE'

export const ADD_INTERACTION_FORM__SUBMIT = 'ADD_INTERACTION_FORM__SUBMIT'
export const ADD_INTERACTION_FORM__CONTACT_FORM_OPENED =
  'ADD_INTERACTION_FORM__CONTACT_FORM_OPENED'

export const FORM__LOADED = 'FORM__LOADED'

export const FORM__FIELD_SET_VALUE = 'FORM__FIELD_SET_VALUE'
export const FORM__FIELD_TOUCHED = 'FORM__FIELD_TOUCHED'

export const FORM__FIELD_REGISTER = 'FORM__FIELD_REGISTER'
export const FORM__FIELD_DEREGISTER = 'FORM__FIELD_DEREGISTER'

export const FORM__STEP_REGISTER = 'FORM__STEP_REGISTER'
export const FORM__STEP_DEREGISTER = 'FORM__STEP_DEREGISTER'

export const FORM__FORWARD = 'FORM__FORWARD'
export const FORM__BACK = 'FORM__BACK'

export const FORM__VALIDATE = 'FORM__VALIDATE'

export const ADD_COMPANY__REGION_LOADED = 'ADD_COMPANY__REGION_LOADED'

export const ADD_INTERACTION__GET_ACTIVE_EVENTS =
  'ADD_INTERACTION__GET_ACTIVE_EVENTS'
export const INVESTMENT_PROJECT_ADMIN__UPDATE_STAGE =
  'INVESTMENT_PROJECT_ADMIN__UPDATE_STAGE'

export const PIPELINE__CHECKED_IF_ON_PIPELINE =
  'PIPELINE__CHECKED_IF_ON_PIPELINE'
export const PIPELINE__ADD_ITEM = 'PIPELINE__ADD_ITEM'
export const PIPELINE__LIST_LOADED = 'PIPELINE__LIST_LOADED'
export const PIPELINE__GET_ITEM = 'PIPELINE__GET_ITEM'
export const PIPELINE__EDIT_ITEM = 'PIPELINE__EDIT_ITEM'
export const PIPELINE__ARCHIVE_ITEM = 'PIPELINE__ARCHIVE_ITEM'
export const PIPELINE__UNARCHIVE_ITEM = 'PIPELINE__UNARCHIVE_ITEM'
export const PIPELINE__DELETE_ITEM = 'PIPELINE__DELETE_ITEM'
export const PIPELINE__GET_COMPANY_CONTACTS = 'PIPELINE__GET_COMPANY_CONTACTS'
export const PIPELINE__LIST_FILTER_SORT_CHANGED =
  'PIPELINE__LIST_FILTER_SORT_CHANGED'

export const DROP_DOWN_MENU_TOGGLE = 'DROP_DOWN_MENU_TOGGLE'
export const DROP_DOWN_MENU_OPEN = 'DROP_DOWN_MENU_OPEN'
export const DROP_DOWN_MENU_CLOSED = 'DROP_DOWN_MENU_CLOSED'
export const DROP_DOWN_MENU_UPDATE_INDEX = 'DROP_DOWN_MENU_UPDATE_INDEX'

export const ANALYTICS__PUSH = 'ANALYTICS__PUSH'
export const MANAGE_ADVISER__UPDATE_STAGE = 'MANAGE_ADVISER__UPDATE_STAGE'
export const MANAGE_ADVISER__UPDATE = 'MANAGE_ADVISER__UPDATE'

export const DNB__CHECK_PENDING_REQUEST = 'DNB__CHECK_PENDING_REQUEST'

export const TOGGLE_SECTION__TOGGLE = 'TOGGLE_SECTION__TOGGLE'

export const INVESTMENTS__PROJECTS_LOADED = 'INVESTMENTS__PROJECTS_LOADED'
export const INVESTMENTS__PROJECTS_SELECTED_ADVISERS =
  'INVESTMENTS__PROJECTS_SELECTED_ADVISERS'

export const INVESTMENTS__PROFILES_LOADED = 'INVESTMENTS__PROFILES_LOADED'
export const INVESTMENTS__PROFILES_SELECT_PAGE =
  'INVESTMENTS__PROFILES_SELECT_PAGE'
export const INVESTMENTS__SET_PROJECTS_METADATA =
  'INVESTMENTS__SET_PROJECTS_METADATA'

export const INVESTMENTS_PROFILES__FILTER_OPTIONS_LOADED =
  'INVESTMENTS_PROFILES__FILTER_OPTIONS_LOADED'

export const INVESTMENT_OPPORTUNITY_DETAILS__LOADED =
  'INVESTMENT_OPPORTUNITY_DETAILS__LOADED'
export const INVESTMENTS__OPPORTUNITIES_LOADED =
  'INVESTMENTS__OPPORTUNITIES_LOADED'
export const INVESTMENTS__OPPORTUNITIES_SELECT_PAGE =
  'INVESTMENTS__OPPORTUNITIES_SELECT_PAGE'
export const INVESTMENT_OPPORTUNITY__DETAILS_METADATA_LOADED =
  'INVESTMENT_OPPORTUNITY__DETAILS_METADATA_LOADED'
export const INVESTMENT_OPPORTUNITY__REQUIREMENTS_METADATA_LOADED =
  'INVESTMENT_OPPORTUNITY__REQUIREMENTS_METADATA_LOADED'
export const INVESTMENT_OPPORTUNITY__EDIT_DETAILS =
  'INVESTMENT_OPPORTUNITY__EDIT_DETAILS'
export const INVESTMENT_OPPORTUNITY__EDIT_REQUIREMENTS =
  'INVESTMENT_OPPORTUNITY__EDIT_REQUIREMENTS'
export const INVESTMENT_OPPORTUNITY__CANCEL_EDIT =
  'INVESTMENT_OPPORTUNITY__CANCEL_EDIT'
export const INVESTMENT_OPPORTUNITY__DETAILS_CHANGE =
  'INVESTMENT_OPPORTUNITY__DETAILS_CHANGE'

export const MY_INVESTMENTS__LIST_LOADED = 'MY_INVESTMENTS__LIST_LOADED'
export const MY_INVESTMENTS__CHECK_COMPLETE = 'MY_INVESTMENTS__CHECK_COMPLETE'
export const MY_INVESTMENTS__PAGINATION_CLICK =
  'MY_INVESTMENTS__PAGINATION_CLICK'
export const MY_INVESTMENTS__FILTER_CHANGE = 'MY_INVESTMENTS__FILTER_CHANGE'
export const MY_INVESTMENTS__SORT_CHANGE = 'MY_INVESTMENTS__SORT_CHANGE'
export const MY_INVESTMENTS__SHOW_DETAILS_CHANGE =
  'MY_INVESTMENTS__SHOW_DETAILS_CHANGE'

export const INVESTMENT_SUMMARY_DATA_RANGES__LOADED =
  'INVESTMENT_SUMMARY_DATA_RANGES__LOADED'

export const OUTSTANDING_PROPOSITIONS__LOADED =
  'OUTSTANDING_PROPOSITIONS__LOADED'

export const ROUTED_INPUT__CHANGE = 'ROUTED_INPUT__CHANGE'
export const ROUTED_INPUT__SELECT = 'ROUTED_INPUT__SELECT'
export const ROUTED_INPUT__RESET = 'ROUTED_INPUT__RESET'

export const CREATE_UK_INVESTMENT_OPPORTUNITY__CHANGE =
  'CREATE_UK_INVESTMENT_OPPORTUNITY__CHANGE'
export const CREATE_UK_INVESTMENT_OPPORTUNITY__SUBMIT =
  'CREATE_UK_INVESTMENT_OPPORTUNITY__SUBMIT'
export const CREATE_UK_INVESTMENT_OPPORTUNITY__SUCCESS =
  'CREATE_UK_INVESTMENT_OPPORTUNITY__SUCCESS'

export const HARD_REDIRECT = 'HARD_REDIRECT'
<commit_msg>Remove actions as we don't need them yet<commit_after>/**
 * This module is a registry of all Redux action types used within the app.
 * Redux actions are shared by all components/reducers so their names must not
 * collide. Having them defined as constants in a single module is a simple
 * measure to prevent such hard to debug cases.
 *
 * The name and value of the constants must be the same.
 * The name should be the name of the component the action relates to and a verb
 * describing what it does, concatenated by double underscore.
 */

export const INTERACTIONS__LOADED = 'INTERACTIONS__LOADED'

export const COMPANIES__LOADED = 'COMPANIES__LOADED'
export const COMPANIES__SET_COMPANIES_METADATA =
  'COMPANIES__SET_COMPANIES_METADATA'

export const COMPANY_LISTS__LISTS_LOADED = 'COMPANY_LISTS__LISTS_LOADED'
export const COMPANY_LISTS__SELECT = 'COMPANY_LISTS__SELECT'
export const COMPANY_LISTS__COMPANIES_LOADED = 'COMPANY_LISTS__COMPANIES_LOADED'
export const COMPANY_LISTS__FILTER = 'COMPANY_LISTS__FILTER'
export const COMPANY_LISTS__ORDER = 'COMPANY_LISTS__ORDER'

export const CONTACTS__LOADED = 'CONTACTS__LOADED'
export const CONTACTS__METADATA_LOADED = 'CONTACTS__METADATA_LOADED'

export const DATA_SUMMARY_PICKER__RANGE_SELECTED =
  'DATA_SUMMARY_PICKER__RANGE_SELECTED'
export const DATA_SUMMARY_PICKER__ACCESSIBLE_TOGGLE =
  'DATA_SUMMARY_PICKER__ACCESSIBLE_TOGGLE'

export const REFERRAL_DETAILS = 'REFERRAL_DETAILS'

export const TASK__START = 'TASK__START'
export const TASK__PROGRESS = 'TASK__PROGRESS'
export const TASK__CANCEL = 'TASK__CANCEL'
export const TASK__ERROR = 'TASK__ERROR'
export const TASK__DISMISS_ERROR = 'TASK__DISMISS_ERROR'
export const TASK__CLEAR = 'TASK__CLEAR'

export const EXPORTS_HISTORY__LOADED = 'EXPORTS_HISTORY__LOADED'
export const EXPORTS_HISTORY__SELECT_PAGE = 'EXPORTS_HISTORY__SELECT_PAGE'

export const TAB_NAV__SELECT = 'TAB_NAV__SELECT'
export const TAB_NAV__FOCUS = 'TAB_NAV__FOCUS'

export const SEND_REFERRAL_FORM__SUBMIT = 'SEND_REFERRAL_FORM__SUBMIT'

export const EDIT_ONE_LIST_DETAILS__SUBMIT = 'EDIT_ONE_LIST_DETAILS__SUBMIT'

export const REFERRAL_LIST__LOADED = 'REFERRAL_LIST__LOADED'
export const REFERRAL_LIST__FILTER_CHANGE = 'REFERRAL_LIST__FILTER_CHANGE'

export const EXPORT_WINS__LOADED = 'EXPORT_WINS__LOADED'
export const EXPORT_WINS__SELECT_PAGE = 'EXPORT_WINS__SELECT_PAGE'

export const EXPORT_COUNTRIES_EDIT__SAVE = 'EXPORT_COUNTRIES_EDIT__SAVE'

export const ADD_INTERACTION_FORM__SUBMIT = 'ADD_INTERACTION_FORM__SUBMIT'
export const ADD_INTERACTION_FORM__CONTACT_FORM_OPENED =
  'ADD_INTERACTION_FORM__CONTACT_FORM_OPENED'

export const FORM__LOADED = 'FORM__LOADED'

export const FORM__FIELD_SET_VALUE = 'FORM__FIELD_SET_VALUE'
export const FORM__FIELD_TOUCHED = 'FORM__FIELD_TOUCHED'

export const FORM__FIELD_REGISTER = 'FORM__FIELD_REGISTER'
export const FORM__FIELD_DEREGISTER = 'FORM__FIELD_DEREGISTER'

export const FORM__STEP_REGISTER = 'FORM__STEP_REGISTER'
export const FORM__STEP_DEREGISTER = 'FORM__STEP_DEREGISTER'

export const FORM__FORWARD = 'FORM__FORWARD'
export const FORM__BACK = 'FORM__BACK'

export const FORM__VALIDATE = 'FORM__VALIDATE'

export const ADD_COMPANY__REGION_LOADED = 'ADD_COMPANY__REGION_LOADED'

export const ADD_INTERACTION__GET_ACTIVE_EVENTS =
  'ADD_INTERACTION__GET_ACTIVE_EVENTS'
export const INVESTMENT_PROJECT_ADMIN__UPDATE_STAGE =
  'INVESTMENT_PROJECT_ADMIN__UPDATE_STAGE'

export const PIPELINE__CHECKED_IF_ON_PIPELINE =
  'PIPELINE__CHECKED_IF_ON_PIPELINE'
export const PIPELINE__ADD_ITEM = 'PIPELINE__ADD_ITEM'
export const PIPELINE__LIST_LOADED = 'PIPELINE__LIST_LOADED'
export const PIPELINE__GET_ITEM = 'PIPELINE__GET_ITEM'
export const PIPELINE__EDIT_ITEM = 'PIPELINE__EDIT_ITEM'
export const PIPELINE__ARCHIVE_ITEM = 'PIPELINE__ARCHIVE_ITEM'
export const PIPELINE__UNARCHIVE_ITEM = 'PIPELINE__UNARCHIVE_ITEM'
export const PIPELINE__DELETE_ITEM = 'PIPELINE__DELETE_ITEM'
export const PIPELINE__GET_COMPANY_CONTACTS = 'PIPELINE__GET_COMPANY_CONTACTS'
export const PIPELINE__LIST_FILTER_SORT_CHANGED =
  'PIPELINE__LIST_FILTER_SORT_CHANGED'

export const DROP_DOWN_MENU_TOGGLE = 'DROP_DOWN_MENU_TOGGLE'
export const DROP_DOWN_MENU_OPEN = 'DROP_DOWN_MENU_OPEN'
export const DROP_DOWN_MENU_CLOSED = 'DROP_DOWN_MENU_CLOSED'
export const DROP_DOWN_MENU_UPDATE_INDEX = 'DROP_DOWN_MENU_UPDATE_INDEX'

export const ANALYTICS__PUSH = 'ANALYTICS__PUSH'
export const MANAGE_ADVISER__UPDATE_STAGE = 'MANAGE_ADVISER__UPDATE_STAGE'
export const MANAGE_ADVISER__UPDATE = 'MANAGE_ADVISER__UPDATE'

export const DNB__CHECK_PENDING_REQUEST = 'DNB__CHECK_PENDING_REQUEST'

export const TOGGLE_SECTION__TOGGLE = 'TOGGLE_SECTION__TOGGLE'

export const INVESTMENTS__PROJECTS_LOADED = 'INVESTMENTS__PROJECTS_LOADED'
export const INVESTMENTS__PROJECTS_SELECTED_ADVISERS =
  'INVESTMENTS__PROJECTS_SELECTED_ADVISERS'

export const INVESTMENTS__PROFILES_LOADED = 'INVESTMENTS__PROFILES_LOADED'
export const INVESTMENTS__PROFILES_SELECT_PAGE =
  'INVESTMENTS__PROFILES_SELECT_PAGE'
export const INVESTMENTS__SET_PROJECTS_METADATA =
  'INVESTMENTS__SET_PROJECTS_METADATA'

export const INVESTMENTS_PROFILES__FILTER_OPTIONS_LOADED =
  'INVESTMENTS_PROFILES__FILTER_OPTIONS_LOADED'

export const INVESTMENT_OPPORTUNITY_DETAILS__LOADED =
  'INVESTMENT_OPPORTUNITY_DETAILS__LOADED'
export const INVESTMENTS__OPPORTUNITIES_LOADED =
  'INVESTMENTS__OPPORTUNITIES_LOADED'
export const INVESTMENTS__OPPORTUNITIES_SELECT_PAGE =
  'INVESTMENTS__OPPORTUNITIES_SELECT_PAGE'
export const INVESTMENT_OPPORTUNITY__DETAILS_METADATA_LOADED =
  'INVESTMENT_OPPORTUNITY__DETAILS_METADATA_LOADED'
export const INVESTMENT_OPPORTUNITY__REQUIREMENTS_METADATA_LOADED =
  'INVESTMENT_OPPORTUNITY__REQUIREMENTS_METADATA_LOADED'
export const INVESTMENT_OPPORTUNITY__EDIT_DETAILS =
  'INVESTMENT_OPPORTUNITY__EDIT_DETAILS'
export const INVESTMENT_OPPORTUNITY__EDIT_REQUIREMENTS =
  'INVESTMENT_OPPORTUNITY__EDIT_REQUIREMENTS'
export const INVESTMENT_OPPORTUNITY__CANCEL_EDIT =
  'INVESTMENT_OPPORTUNITY__CANCEL_EDIT'
export const INVESTMENT_OPPORTUNITY__DETAILS_CHANGE =
  'INVESTMENT_OPPORTUNITY__DETAILS_CHANGE'

export const MY_INVESTMENTS__LIST_LOADED = 'MY_INVESTMENTS__LIST_LOADED'
export const MY_INVESTMENTS__CHECK_COMPLETE = 'MY_INVESTMENTS__CHECK_COMPLETE'
export const MY_INVESTMENTS__PAGINATION_CLICK =
  'MY_INVESTMENTS__PAGINATION_CLICK'
export const MY_INVESTMENTS__FILTER_CHANGE = 'MY_INVESTMENTS__FILTER_CHANGE'
export const MY_INVESTMENTS__SORT_CHANGE = 'MY_INVESTMENTS__SORT_CHANGE'
export const MY_INVESTMENTS__SHOW_DETAILS_CHANGE =
  'MY_INVESTMENTS__SHOW_DETAILS_CHANGE'

export const INVESTMENT_SUMMARY_DATA_RANGES__LOADED =
  'INVESTMENT_SUMMARY_DATA_RANGES__LOADED'

export const OUTSTANDING_PROPOSITIONS__LOADED =
  'OUTSTANDING_PROPOSITIONS__LOADED'

export const ROUTED_INPUT__CHANGE = 'ROUTED_INPUT__CHANGE'
export const ROUTED_INPUT__SELECT = 'ROUTED_INPUT__SELECT'
export const ROUTED_INPUT__RESET = 'ROUTED_INPUT__RESET'

export const CREATE_UK_INVESTMENT_OPPORTUNITY__CHANGE =
  'CREATE_UK_INVESTMENT_OPPORTUNITY__CHANGE'
export const CREATE_UK_INVESTMENT_OPPORTUNITY__SUBMIT =
  'CREATE_UK_INVESTMENT_OPPORTUNITY__SUBMIT'
export const CREATE_UK_INVESTMENT_OPPORTUNITY__SUCCESS =
  'CREATE_UK_INVESTMENT_OPPORTUNITY__SUCCESS'

export const HARD_REDIRECT = 'HARD_REDIRECT'
<|endoftext|>


<commit_before>import {
  action,
  observable,
  runInAction,
  autorun as mobxAutorun,
  toJS,
} from 'mobx'
import { app } from '@mindhive/di'

import { LocalContext } from './localContext'

// Based on https://github.com/meteor-space/tracker-mobx-autorun

const readySubscription = {
  ready: () => true,
}

const meteorTracker = global.Tracker

const autorun = (func) => {
  let mobxDisposer = null
  let computation = null
  let isFirstRun = true
  computation = meteorTracker.autorun(() => {
    if (mobxDisposer) {
      mobxDisposer()
      isFirstRun = true
    }
    mobxDisposer = mobxAutorun(() => {
      if (isFirstRun) {
        func()
      } else {
        computation.invalidate()
      }
      isFirstRun = false
    })
  })
  return {
    stop() {
      computation.stop()
      mobxDisposer()
    },
  }
}

// Automatically pump data from a Mongo cursor to a Mobx array or map
// See pumpSubscriptionToMobx for something more high level
const pumpMongoToMobx = ({
  actionPrefix,
  subscription = readySubscription,
  mongoCursor,
  observableArray,
  observableMap,
  endless = false,
}) => {
  if (! meteorTracker.active) {
    if (endless) {
      if (! subscription.ready()) {
        // If we wanted to handle this we could with slightly more complicated code below
        console.error('When using endless pump outside a Tracker.autorun() ' +  // eslint-disable-line no-console
          'the subscription must be ready as we cannot react to it changing')
      }
    } else {
      console.warn('You are setting up a pump outside of a Tracker.autorun().\n' +  // eslint-disable-line no-console
        'Cannot follow subscription.ready() changes, and observe/observeChanges cannot be stopped.\n' +
        'If that is what you intended then specify endless.')
    }
  }
  if (observableArray) {
    if (subscription.ready()) {
      meteorTracker.nonreactive(() => {
        runInAction(`${actionPrefix}: initial fetch`, () => {
          observableArray.replace(mongoCursor.fetch())
        })
      })
      mongoCursor.observe({  // More efficient than observe()
        _suppress_initial: true,  // suppresses addedAt callback for documents initially fetched
        addedAt: action(`${actionPrefix}: document added`, (doc, index) => {
          observableArray.splice(index, 0, doc)
        }),
        removedAt: action(`${actionPrefix}: document removed`, (doc, index) => {
          observableArray.splice(index, 1)
        }),
        changedAt: action(`${actionPrefix}: document changed`, (doc, oldDoc, index) => {
          // REVISIT: if existing value isObservable we could be more efficient here and just assign top level fields
          // Probably using extendObservable but also handling fields disappearing
          // Or use observeChanges instead so we just get fields
          observableArray[index] = doc
        }),
        movedTo: action(`${actionPrefix}: document moved`, (doc, fromIndex, toIndex) => {
          observableArray.splice(fromIndex, 1)
          observableArray.splice(toIndex, 0, doc)
        }),
      })
    } else {
      runInAction(`${actionPrefix}: initialized`, () => {
        observableArray.clear()
      })
    }
  }
  if (observableMap) {
    if (subscription.ready()) {
      meteorTracker.nonreactive(() => {
        runInAction(`${actionPrefix}: initial fetch`, () => {
          observableMap.clear()
          mongoCursor.fetch().forEach((doc) => { observableMap.set(doc._id, doc) })
        })
      })
      mongoCursor.observeChanges({  // More efficient than observe()
        _suppress_initial: true,  // suppresses addedAt callback for documents initially fetched
        added: action(`${actionPrefix}: document added`, (id, doc) => {
          observableMap.set(id, doc)
        }),
        removed: action(`${actionPrefix}: document removed`, (id) => {
          observableMap.remove(id)
        }),
        changed: action(`${actionPrefix}: document changed`, (id, fields) => {
          // REVISIT: if existing value isObservable we could be more efficient here and just assign new fields
          // Probably using extendObservable but also handling fields disappearing (undefined in fields)
          const doc = toJS(observableMap.get(id) || {}, false)  // If was observable, toJS clones
          // Doesn't matter we may be overwriting existing object here, as we know it's not observable
          Object.entries(fields).forEach(([k, v]) => {
            if (v === undefined) {
              delete doc[k]
            } else {
              doc[k] = v
            }
          })
          observableMap.set(id, doc)
        }),
      })
    } else {
      runInAction(`${actionPrefix}: initialized`, () => {
        observableMap.clear()
      })
    }
  }
}

// What it says on the can, returns handle with stop() (from autorun) and observable property loading
const pumpSubscriptionToMobx = ({
  publicationName,
  subscriptionArgs,
  focusedView,
  viewSelector = {},
  observableArray,
  observableMap,
  context = `subscription:${publicationName}`,
}) => {
  const result = observable({
    loading: true,  // Don't call it ready to avoid confusion with Meteor subscription ready method
  })
  const autorunHandle = autorun(() => {
    if (app().viewerDomain.isAuthenticatedLive) {  // Otherwise focusedViews won't have the info they need
      // Also useful to give other subscriptions a head start
      const subscription = Meteor.subscribe(publicationName, subscriptionArgs)
      pumpMongoToMobx({
        actionPrefix: context,
        observableArray,
        observableMap,
        subscription,
        mongoCursor: focusedView.find(new LocalContext(context), viewSelector),
      })
      if (subscription.ready()) {
        runInAction(`${context}: ready`, () => {
          result.loading = false
        })
      }
    }
  })
  result.stop = autorunHandle.stop  // Copy stop across
  return result
}

export const Tracker = {
  autorun,
  pumpSubscriptionToMobx,
  pumpMongoToMobx,
}
<commit_msg>Comment<commit_after>import {
  action,
  observable,
  runInAction,
  autorun as mobxAutorun,
  toJS,
} from 'mobx'
import { app } from '@mindhive/di'

import { LocalContext } from './localContext'

// Based on https://github.com/meteor-space/tracker-mobx-autorun

const readySubscription = {
  ready: () => true,
}

const meteorTracker = global.Tracker

const autorun = (func) => {
  let mobxDisposer = null
  let computation = null
  let isFirstRun = true
  computation = meteorTracker.autorun(() => {
    if (mobxDisposer) {
      mobxDisposer()
      isFirstRun = true
    }
    mobxDisposer = mobxAutorun(() => {
      if (isFirstRun) {
        func()
      } else {
        computation.invalidate()
      }
      isFirstRun = false
    })
  })
  return {
    stop() {
      computation.stop()
      mobxDisposer()
    },
  }
}

// Automatically pump data from a Mongo cursor to a Mobx array or map
// See pumpSubscriptionToMobx for something more high level
const pumpMongoToMobx = ({
  actionPrefix,
  subscription = readySubscription,
  mongoCursor,
  observableArray,
  observableMap,
  endless = false,
}) => {
  if (! meteorTracker.active) {
    if (endless) {
      if (! subscription.ready()) {
        // If we wanted to handle this we could with slightly more complicated code below
        console.error('When using endless pump outside a Tracker.autorun() ' +  // eslint-disable-line no-console
          'the subscription must be ready as we cannot react to it changing')
      }
    } else {
      console.warn('You are setting up a pump outside of a Tracker.autorun().\n' +  // eslint-disable-line no-console
        'Cannot follow subscription.ready() changes, and observe/observeChanges cannot be stopped.\n' +
        'If that is what you intended then specify endless.')
    }
  }
  if (observableArray) {
    if (subscription.ready()) {
      meteorTracker.nonreactive(() => {
        runInAction(`${actionPrefix}: initial fetch`, () => {
          observableArray.replace(mongoCursor.fetch())
        })
      })
      mongoCursor.observe({
        _suppress_initial: true,  // suppresses addedAt callback for documents initially fetched
        addedAt: action(`${actionPrefix}: document added`, (doc, index) => {
          observableArray.splice(index, 0, doc)
        }),
        removedAt: action(`${actionPrefix}: document removed`, (doc, index) => {
          observableArray.splice(index, 1)
        }),
        changedAt: action(`${actionPrefix}: document changed`, (doc, oldDoc, index) => {
          // REVISIT: if existing value isObservable we could be more efficient here and just assign top level fields
          // Probably using extendObservable but also handling fields disappearing
          // Or use observeChanges instead so we just get fields
          observableArray[index] = doc
        }),
        movedTo: action(`${actionPrefix}: document moved`, (doc, fromIndex, toIndex) => {
          observableArray.splice(fromIndex, 1)
          observableArray.splice(toIndex, 0, doc)
        }),
      })
    } else {
      runInAction(`${actionPrefix}: initialized`, () => {
        observableArray.clear()
      })
    }
  }
  if (observableMap) {
    if (subscription.ready()) {
      meteorTracker.nonreactive(() => {
        runInAction(`${actionPrefix}: initial fetch`, () => {
          observableMap.clear()
          mongoCursor.fetch().forEach((doc) => { observableMap.set(doc._id, doc) })
        })
      })
      mongoCursor.observeChanges({  // More efficient than observe()
        _suppress_initial: true,  // suppresses addedAt callback for documents initially fetched
        added: action(`${actionPrefix}: document added`, (id, doc) => {
          observableMap.set(id, doc)
        }),
        removed: action(`${actionPrefix}: document removed`, (id) => {
          observableMap.remove(id)
        }),
        changed: action(`${actionPrefix}: document changed`, (id, fields) => {
          // REVISIT: if existing value isObservable we could be more efficient here and just assign new fields
          // Probably using extendObservable but also handling fields disappearing (undefined in fields)
          const doc = toJS(observableMap.get(id) || {}, false)  // If was observable, toJS clones
          // Doesn't matter we may be overwriting existing object here, as we know it's not observable
          Object.entries(fields).forEach(([k, v]) => {
            if (v === undefined) {
              delete doc[k]
            } else {
              doc[k] = v
            }
          })
          observableMap.set(id, doc)
        }),
      })
    } else {
      runInAction(`${actionPrefix}: initialized`, () => {
        observableMap.clear()
      })
    }
  }
}

// What it says on the can, returns handle with stop() (from autorun) and observable property loading
const pumpSubscriptionToMobx = ({
  publicationName,
  subscriptionArgs,
  focusedView,
  viewSelector = {},
  observableArray,
  observableMap,
  context = `subscription:${publicationName}`,
}) => {
  const result = observable({
    loading: true,  // Don't call it ready to avoid confusion with Meteor subscription ready method
  })
  const autorunHandle = autorun(() => {
    if (app().viewerDomain.isAuthenticatedLive) {  // Otherwise focusedViews won't have the info they need
      // Also useful to give other subscriptions a head start
      const subscription = Meteor.subscribe(publicationName, subscriptionArgs)
      pumpMongoToMobx({
        actionPrefix: context,
        observableArray,
        observableMap,
        subscription,
        mongoCursor: focusedView.find(new LocalContext(context), viewSelector),
      })
      if (subscription.ready()) {
        runInAction(`${context}: ready`, () => {
          result.loading = false
        })
      }
    }
  })
  result.stop = autorunHandle.stop  // Copy stop across
  return result
}

export const Tracker = {
  autorun,
  pumpSubscriptionToMobx,
  pumpMongoToMobx,
}
<|endoftext|>


<commit_before>import Promise from 'bluebird';
import { resolve } from 'dns';
import readHostFile from '../read-host-file';
import writeHostFile from '../write-host-file';
import lineMatchesHost from '../line-matches-host';
import backupHosts from '../backup-hosts';
import { addressRegex } from '../patterns';
import wildcardToRegex from '../wildcard-to-regex';

export default {
  command: 'point <host> to <address>',
  describe: 'Assigns an address to the given hostname',
  handler({ host, address: destName }) {

    let dest = null;
    let lines = null;

    return (
      readHostFile()
    ).then(contents => {
      lines = contents;
      return resolveDest(destName, host, lines);
    }).then(resolved => {
      dest = resolved;
      let updated = false;
      let foundMatch = false;
      let insertionPoint = lines.length;
      const newLines = lines.map((line, i) => {
        if (lineMatchesHost(line, host)) {
          insertionPoint = i + 1;
          if (line.address === dest.address) {
            foundMatch = true;
            if (line.isActive) {
              console.log(`${line.hosts} is already pointing to ${dest.address}`);
            } else {
              updated = true;
              return { ...line, isActive: true, updated: true };
            }
          } else if (line.isActive) {
            updated = true;
            return { ...line, isActive: false, updated: true };
          }
        }

        return line;
      });

      if (!foundMatch) {
        if (host.indexOf('*') >= 0) {
          return void console.log('No matching hosts found.');
        } else {
          updated = true;
          newLines.splice(insertionPoint, 0, {
            type: 'entry',
            isActive: true,
            address: dest.address,
            hosts: [host],
            comment: dest.name && `# ${dest.name}`,
            updated: true
          });
        }
      }

      if (updated) {
        return backupHosts().then(() => writeHostFile(newLines));
      }
    });
  }
};

function resolveDest(destName, host, lines) {
  if (addressRegex.test(destName)) {
    return Promise.resolve({ address: destName });
  }

  if (destName.indexOf('*') >= 0) {
    const regex = wildcardToRegex(destName);
    const matches = lines.filter(line => {
      return (
        lineMatchesHost(line, host)
        && (line.addressAliases || []).some(alias => regex.test(alias))
      );
    });
    if (!matches.length) {
      throw new Error(`Could not resolve ${destName}`);
    } else if (matches.length > 1) {
      const matchDesc = matches.map(m => `${m.address} (${m.addressAliases})`);
      throw new Error(`Ambiguous pattern ${destName} matches ${matchDesc}`);
    } else {
      return { address: matches[0].address };
    }
  }

  return (
    resolve(destName, cb)
  ).then(addresses => {
    const validAddress = addresses.find(address => addressRegex.test(address));
    if (!validAddress) {
      throw new Error(`Could not resolve ${destName}.`);
    }

    return {
      name: destName,
      address: validAddress
    };
  });
}
<commit_msg>local(host) alias<commit_after>import Promise from 'bluebird';
import { resolve } from 'dns';
import readHostFile from '../read-host-file';
import writeHostFile from '../write-host-file';
import lineMatchesHost from '../line-matches-host';
import backupHosts from '../backup-hosts';
import { addressRegex } from '../patterns';
import wildcardToRegex from '../wildcard-to-regex';

export default {
  command: 'point <host> to <address>',
  describe: 'Assigns an address to the given hostname',
  handler({ host, address: destName }) {

    let dest = null;
    let lines = null;

    return (
      readHostFile()
    ).then(contents => {
      lines = contents;
      return resolveDest(destName, host, lines);
    }).then(resolved => {
      dest = resolved;
      let updated = false;
      let foundMatch = false;
      let insertionPoint = lines.length;
      const newLines = lines.map((line, i) => {
        if (lineMatchesHost(line, host)) {
          insertionPoint = i + 1;
          if (line.address === dest.address) {
            foundMatch = true;
            if (line.isActive) {
              console.log(`${line.hosts} is already pointing to ${dest.address}`);
            } else {
              updated = true;
              return { ...line, isActive: true, updated: true };
            }
          } else if (line.isActive) {
            updated = true;
            return { ...line, isActive: false, updated: true };
          }
        }

        return line;
      });

      if (!foundMatch) {
        if (host.indexOf('*') >= 0) {
          return void console.log('No matching hosts found.');
        } else {
          updated = true;
          newLines.splice(insertionPoint, 0, {
            type: 'entry',
            isActive: true,
            address: dest.address,
            hosts: [host],
            comment: dest.name && `# ${dest.name}`,
            updated: true
          });
        }
      }

      if (updated) {
        return backupHosts().then(() => writeHostFile(newLines));
      }
    });
  }
};

function resolveDest(destName, host, lines) {
  if (/^local(host)?$/i.test(destName)) {
    return { address: '127.0.0.1' };
  }

  if (addressRegex.test(destName)) {
    return { address: destName };
  }

  if (destName.indexOf('*') >= 0) {
    const regex = wildcardToRegex(destName);
    const matches = lines.filter(line => {
      return (
        lineMatchesHost(line, host)
        && (line.addressAliases || []).some(alias => regex.test(alias))
      );
    });
    if (!matches.length) {
      throw new Error(`Could not resolve ${destName}`);
    } else if (matches.length > 1) {
      const matchDesc = matches.map(m => `${m.address} (${m.addressAliases})`);
      throw new Error(`Ambiguous pattern ${destName} matches ${matchDesc}`);
    } else {
      return { address: matches[0].address };
    }
  }

  return (
    Promise.fromCallback(cb => resolve(destName, cb))
  ).then(addresses => {
    const validAddress = addresses.find(address => addressRegex.test(address));
    if (!validAddress) {
      throw new Error(`Could not resolve ${destName}.`);
    }

    return {
      name: destName,
      address: validAddress
    };
  });
}
<|endoftext|>


<commit_before>/* jshint node: true */
/**
 * PUSH Notification server
 * (c) Telefonica Digital, 2012 - All rights reserved
 * License: GNU Affero V3 (see LICENSE file)
 * Fernando Rodríguez Sela <frsela@tid.es>
 * Guillermo Lopez Leal <gll@tid.es>
 */

var publicBaseURL = require('../config.js').consts.publicBaseURL,
    uuid = require('node-uuid'),
    crypto = require('../common/cryptography.js'),
    exec = require('child_process').exec;

/**
 * Gets the public notification URL for the given apptoken
 */
function getNotificationURL(apptoken) {
  return publicBaseURL + '/notify/' + apptoken;
}
exports.getNotificationURL = getNotificationURL;

function getAppToken(watoken, pbkbase64) {
  return crypto.hashSHA256(watoken + pbkbase64);
}
exports.getAppToken = getAppToken;

function padNumber(number,len) {
  var str = '' + number;
  while (str.length < len) {
      str = '0' + str;
  }
  return str;
}
exports.padNumber = padNumber;

function checkCallback(callback) {
  if (typeof callback !== 'function') {
    callback = function() {};
  }
  return callback;
}
exports.checkCallback = checkCallback;

function getMaxFileDescriptors(cb) {
  exec('ulimit -n', function(error,stdout,stderr) {
    cb(error, stdout);
  });
}
exports.getMaxFileDescriptors = getMaxFileDescriptors;

/**
 * Check if a version is a valid one for this API (v1)
 * In v1 case:
 *   - should be a number
 *   - should not be NaN
 *   - should be greater or equal than 0
 */
function isVersion(version) {
  var number = parseInt(version, 10);
  if (typeof number !== 'number') {
    return false;
  }

  if (isNaN(number)) {
    return false;
  }

  if (number < 0) {
    return false;
  }

  return true;
}
exports.isVersion = isVersion;

function getCaChannel() {

  var log = require('./logger.js');
  var caDir = require('../config.js').consts.caDir;

  var cas = [];
  if (!caDir) {
    log.error(log.messages.ERROR_CASDIRECTORYUNDEFINED);
    return cas;
  }

  var path = require('path');
  var fs = require('fs');
  try {
    var files = fs.readdirSync(caDir);

    var i;
    var len = files.length;
    if (len === 0) {
      log.error(log.messages.ERROR_NOCADEFINED, {
        "path": caDir
      });
      return cas;
    }

    for (i = 0; i < len; i++) {
      cas.push(fs.readFileSync(caDir + path.sep + files[i]));
    }
  } catch (e) {
    log.error(log.messages.ERROR_NOCADEFINED, {
        "path": caDir
    });
  }

  return cas;
}
exports.getCaChannel = getCaChannel;

<commit_msg>Fix version checking<commit_after>/* jshint node: true */
/**
 * PUSH Notification server
 * (c) Telefonica Digital, 2012 - All rights reserved
 * License: GNU Affero V3 (see LICENSE file)
 * Fernando Rodríguez Sela <frsela@tid.es>
 * Guillermo Lopez Leal <gll@tid.es>
 */

var publicBaseURL = require('../config.js').consts.publicBaseURL,
    uuid = require('node-uuid'),
    crypto = require('../common/cryptography.js'),
    exec = require('child_process').exec;

/**
 * Gets the public notification URL for the given apptoken
 */
function getNotificationURL(apptoken) {
  return publicBaseURL + '/notify/' + apptoken;
}
exports.getNotificationURL = getNotificationURL;

function getAppToken(watoken, pbkbase64) {
  return crypto.hashSHA256(watoken + pbkbase64);
}
exports.getAppToken = getAppToken;

function padNumber(number,len) {
  var str = '' + number;
  while (str.length < len) {
      str = '0' + str;
  }
  return str;
}
exports.padNumber = padNumber;

function checkCallback(callback) {
  if (typeof callback !== 'function') {
    callback = function() {};
  }
  return callback;
}
exports.checkCallback = checkCallback;

function getMaxFileDescriptors(cb) {
  exec('ulimit -n', function(error,stdout,stderr) {
    cb(error, stdout);
  });
}
exports.getMaxFileDescriptors = getMaxFileDescriptors;

function isVersion(n) {
    return !isNaN(parseInt(n)) && isFinite(n) &&
        (n < 9007199254740992) && (n >= 0) && (n % 1 === 0);
}
exports.isVersion = isVersion;

function getCaChannel() {

  var log = require('./logger.js');
  var caDir = require('../config.js').consts.caDir;

  var cas = [];
  if (!caDir) {
    log.error(log.messages.ERROR_CASDIRECTORYUNDEFINED);
    return cas;
  }

  var path = require('path');
  var fs = require('fs');
  try {
    var files = fs.readdirSync(caDir);

    var i;
    var len = files.length;
    if (len === 0) {
      log.error(log.messages.ERROR_NOCADEFINED, {
        "path": caDir
      });
      return cas;
    }

    for (i = 0; i < len; i++) {
      cas.push(fs.readFileSync(caDir + path.sep + files[i]));
    }
  } catch (e) {
    log.error(log.messages.ERROR_NOCADEFINED, {
        "path": caDir
    });
  }

  return cas;
}
exports.getCaChannel = getCaChannel;

<|endoftext|>