<commit_before>'use strict';

/**
 * Locals
 */

var has = Object.prototype.hasOwnProperty;

/**
 * .env file parser.
 *
 * @constructor
 */

function Parser(options) {
  options = options || {};

  // env storage
  this._env = options.env || Object.create(null);

  // enable/disable booleans
  this._allowBool = has.call(options, 'booleans')
    ? options.booleans
    : false;

  // enable/disable numbers
  this._allowNum = has.call(options, 'numbers')
    ? options.numbers
    : false;
}

/**
 * Parse a single line.
 *
 * - export (optional)
 * - key
 *   - separator
 * - single quote or double quote or no quote
 *   - value
 * - end
 * - optional comment
 */

Parser.LINE = /^(?:export\s+)?([\w\.]+)(?:\s*=\s*|:\s+?)('(?:\'|[^'])*'|"(?:\"|[^"])*"|[^#\n]+)?(?:\s*\#.*)?$/;

/**
 * Ignore whitespaces and comments.
 */

Parser.IGNORE = /^\s*(?:#.*)?$/;

/**
 * Strip quotes.
 */

Parser.QUOTES = /^(['"])(.*)(['"])$/;

/**
 * Check if bool.
 */

Parser.BOOLEAN = /^(true|false)$/i;

/**
 * Detect variables.
 */

Parser.VARIABLE = /(\\)?(\$)(\{?([A-Z0-9_]+)\}?)/ig;

/**
 * Unescape.
 */

Parser.UNESCAPE = /\\([^$])/g;

/**
 * Parse `str`.
 *
 * @public
 */

Parser.prototype.parse = function(str) {
  var lines = str.split("\n");
  var line = null;
  var node = null;

  while (line = lines.shift()) {
    if (node = this._parsePair(line)) {
      this._env[node.key] = node.val;
    }
  }

  return this._env;
};

/**
 * Parse pair.
 *
 * @param {String} `str`
 * @public
 */

Parser.prototype._parsePair = function(str) {
  var match = null;

  if (Parser.IGNORE.test(str)) {
    return;
  }

  match = str.match(Parser.LINE);

  if (!match) {
    throw new Error("envc: Invalid line: " + line);
  }

  return this._parseVal({ key: match[1], str: match[2] });
};

/**
 * Parse value.
 *
 * @param {Object} node
 * @returns {Object}
 * @private
 */

Parser.prototype._parseVal = function(node) {
  node.val = node.str.replace(Parser.QUOTES, '$2');

  return this._parseBool(node)
    || this._parseNum(node)
    || this._parseStr(node);
};

/**
 * Parse boolean value.
 *
 * @param {Object} node
 * @returns {Object}
 * @private
 */

Parser.prototype._parseBool = function(node) {
  if (this._allowBool && Parser.BOOLEAN.test(node.val)) {
    node.val = node.val.toLowerCase() === 'true';
    return node;
  }
};

/**
 * Parse numeric value.
 *
 * @param {Object} node
 * @returns {Object}
 * @private
 */

Parser.prototype._parseNum = function(node) {
  var num = parseFloat(node.val);

  if (this._allowNum && !Number.isNaN(num)) {
    node.val = num;
    return node;
  }
};

/**
 * Parse string value.
 *
 * @param {Object} node
 * @returns {Object}
 * @private
 */

Parser.prototype._parseStr = function(node) {
  if (node.str[0] === "'") {
    return node;
  }

  if (node.str[0] === '"') {
    node.val = node.val.replace(Parser.UNESCAPE, '$1');
  }

  scan(node.str, Parser.VARIABLE).forEach(function(parts) {
    var replace = parts[1] === '\\'
      ? parts[2] + parts[3]
      : this._env[parts[4]] || '';

    node.val = node.val.replace(parts[0], replace);
  }, this);

  return node;
};

/**
 * Scan `str` with `re`.
 *
 * @param {String} str
 * @param {RegExp} re
 * @returns {Array}
 * @private
 */

function scan(str, re) {
  var match = null;
  var ret = [];

  while (match = re.exec(str)) {
    ret.push(match);
  }

  return ret;
}

/**
 * Primary export
 */

module.exports = Parser;
<commit_msg>Respect the current environment on interpolation<commit_after>'use strict';

/**
 * Locals
 */

var has = Object.prototype.hasOwnProperty;

/**
 * .env file parser.
 *
 * @constructor
 */

function Parser(options) {
  options = options || {};

  // env storage
  this._env = Object.create(null);

  // current env
  this._currEnv = options.currEnv || process.env;

  // enable/disable booleans
  this._allowBool = has.call(options, 'booleans')
    ? options.booleans
    : false;

  // enable/disable numbers
  this._allowNum = has.call(options, 'numbers')
    ? options.numbers
    : false;
}

/**
 * Parse a single line.
 *
 * - export (optional)
 * - key
 *   - separator
 * - single quote or double quote or no quote
 *   - value
 * - end
 * - optional comment
 */

Parser.LINE = /^(?:export\s+)?([\w\.]+)(?:\s*=\s*|:\s+?)('(?:\'|[^'])*'|"(?:\"|[^"])*"|[^#\n]+)?(?:\s*\#.*)?$/;

/**
 * Ignore whitespaces and comments.
 */

Parser.IGNORE = /^\s*(?:#.*)?$/;

/**
 * Strip quotes.
 */

Parser.QUOTES = /^(['"])(.*)(['"])$/;

/**
 * Check if bool.
 */

Parser.BOOLEAN = /^(true|false)$/i;

/**
 * Detect variables.
 */

Parser.VARIABLE = /(\\)?(\$)(\{?([A-Z0-9_]+)\}?)/ig;

/**
 * Unescape.
 */

Parser.UNESCAPE = /\\([^$])/g;

/**
 * Parse `str`.
 *
 * @public
 */

Parser.prototype.parse = function(str) {
  var lines = str.split("\n");
  var line = null;
  var node = null;

  while (line = lines.shift()) {
    if (node = this._parsePair(line)) {
      this._env[node.key] = node.val;
    }
  }

  return this._env;
};

/**
 * Parse pair.
 *
 * @param {String} `str`
 * @public
 */

Parser.prototype._parsePair = function(str) {
  var match = null;

  if (Parser.IGNORE.test(str)) {
    return;
  }

  match = str.match(Parser.LINE);

  if (!match) {
    throw new Error("envc: Invalid line: " + line);
  }

  return this._parseVal({ key: match[1], str: match[2] });
};

/**
 * Parse value.
 *
 * @param {Object} node
 * @returns {Object}
 * @private
 */

Parser.prototype._parseVal = function(node) {
  node.val = node.str.replace(Parser.QUOTES, '$2');

  return this._parseBool(node)
    || this._parseNum(node)
    || this._parseStr(node);
};

/**
 * Parse boolean value.
 *
 * @param {Object} node
 * @returns {Object}
 * @private
 */

Parser.prototype._parseBool = function(node) {
  if (this._allowBool && Parser.BOOLEAN.test(node.val)) {
    node.val = node.val.toLowerCase() === 'true';
    return node;
  }
};

/**
 * Parse numeric value.
 *
 * @param {Object} node
 * @returns {Object}
 * @private
 */

Parser.prototype._parseNum = function(node) {
  var num = parseFloat(node.val);

  if (this._allowNum && !Number.isNaN(num)) {
    node.val = num;
    return node;
  }
};

/**
 * Parse string value.
 *
 * @param {Object} node
 * @returns {Object}
 * @private
 */

Parser.prototype._parseStr = function(node) {
  if (node.str[0] === "'") {
    return node;
  }

  if (node.str[0] === '"') {
    node.val = node.val.replace(Parser.UNESCAPE, '$1');
  }

  scan(node.str, Parser.VARIABLE).forEach(function(parts) {
    var replace = null;

    if (parts[1] === '\\') {
      replace = parts[2] + parts[3];
    } else if (this._env[parts[4]]) {
      replace = this._env[parts[4]];
    } else {
      replace = this._currEnv[parts[4]] || '';
    }

    node.val = node.val.replace(parts[0], replace);
  }, this);

  return node;
};

/**
 * Scan `str` with `re`.
 *
 * @param {String} str
 * @param {RegExp} re
 * @returns {Array}
 * @private
 */

function scan(str, re) {
  var match = null;
  var ret = [];

  while (match = re.exec(str)) {
    ret.push(match);
  }

  return ret;
}

/**
 * Primary export
 */

module.exports = Parser;
<|endoftext|>


<commit_before>module.exports = function (){
    var SantaClaus = {},
        found = false;
    SantaClaus.traverse = function(object, query){
        var type = typeof object;
        if(type == "object") {
            for (var key in object) {
                if (!found){
                    this.traverse(object[key], query);
                }
                else {
                    if (object.type === query) {
                        console.log(object);
                    }
                    break;
                }
            }
        }
        else {
            if(object === query) {
                found = true;
            }
        }
        return found;
    }
    SantaClaus.nice = function(object, query){
        var found = this.traverse(object, query);
        if(found){
            console.log("Good job!");
        }
        else {
            console.log("This program should include a " + query);
        }
    }
    SantaClaus.naughty = function(object, query){
        var found = this.traverse(object, query);
        if (found) {
            console.log("This program should not have a " + query);
        }
        else {
            console.log("Good job!");
        }
    }
    // SantaClaus.chimneyTraverse = function(object, query, found) {
    //     var type = typeof object;

    //     if(type == "object") {
    //         for (var key in object) {
    //                 subtree = object[key];
    //             if(!found) {
    //                 this.chimneyTraverse(subtree, query, found);
    //             }
    //         }
    //     }
    //     else {
    //         if(object === query) {
    //             found = true;
    //         }
    //     }

    //     return subtree;
    // }
    SantaClaus.chimney = function(object, queryObject){
        var foundArray = [],
            subtree = object,
            i;

        //initialize found array
        for (i = 0; i < 1; i++) {
            foundArray[i] = false;
            // subtree = this.chimneyTraverse(subtree, queryObject[i], foundArray[i]);
            foundArray[i] = this.traverse(subtree, queryObject[i]);
        }

        console.log(foundArray);
        console.log(subtree);
    }
    // SantaClaus.present = function() {

    // }
    return SantaClaus;
};

<commit_msg>chimney works for one item<commit_after>module.exports = function (){
    var SantaClaus = {},
        found = false,
        subtree = {};
    SantaClaus.traverse = function(object, query){
        var type = typeof object;
        if(type == "object") {
            for (var key in object) {
                if (!found){
                    this.traverse(object[key], query);
                }
                else {
                    if (object.type === query) {
                        subtree = object;
                    }
                    break;
                }
            }
        }
        else {
            if(object === query) {
                found = true;
            }
        }
        return [found, subtree];
    }
    SantaClaus.nice = function(object, query){
        var found = this.traverse(object, query)[0];
        if(found){
            console.log("Good job!");
        }
        else {
            console.log("This program should include a " + query);
        }
    }
    SantaClaus.naughty = function(object, query){
        var found = this.traverse(object, query)[0];
        if (found) {
            console.log("This program should not have a " + query);
        }
        else {
            console.log("Good job!");
        }
    }
    SantaClaus.chimney = function(object, queryObject){
        var foundArray = [],
            subtree = object,
            i;

        for (i = 0; i < queryObject.length; i++) {
            foundArray[i] = false;
            returnArray = this.traverse(subtree, queryObject[i]);
            foundArray[i] = returnArray[0];
            subtree = returnArray[1];
        }

        console.log(foundArray);
        console.log(subtree);
    }
    // SantaClaus.present = function() {

    // }
    return SantaClaus;
};

<|endoftext|>


<commit_before>export default Ember.Component.extend({

  showPreview: true,
  showCode   : false,

  hasValue: function () {
    return Object.keys(this.get('control.value')).length;
  }.property('control.value'),

  dataString: function () {
    return JSON.stringify(this.get('control.value'), null, 2);
  }.property('control.value'),

  isVisual: function () {
    return ['video', 'rich', 'photo'].indexOf(this.get('control.value.type')) >= 0;
  }.property('control.value.type'),

  previewValue: function () {

    var preview = '';

    switch (this.get('control.value.type')) {
    case 'video':
    case 'rich':
      preview = this.get('control.value.html');
      break;
    case 'photo':
      preview = '';
      break;
    default:
      if (this.get('control.value.title')) {
        preview = this.get('control.value.title') + ' (' + this.get('control.value.original_url') + ')';
      }
      break;
    }

    return preview;

  }.property('control.value'),

  actions: {
    getEmbed: function () {
      if (!this.get('url') || this.get('isFetching')) {
        return;
      }

      this.set('isFetching', true);
      this.set('control.value', {});

      var embedlyControl = this;

      $.embedly.oembed(this.get('url'), {
        key: window.ENV.embedlyKey,
        query: this.get('control.meta.data.options')
      }).progress(function (data) {
        embedlyControl.set('isFetching', false);
        embedlyControl.set('control.value', data);
      });
    },

    togglePreview: function () {
      this.toggleProperty('showCode');
      this.toggleProperty('showPreview');
    },

    clearValue: function () {
      this.set('control.value', {});
    }
  }
});
<commit_msg>default for Object.keys<commit_after>export default Ember.Component.extend({

  showPreview: true,
  showCode   : false,

  hasValue: function () {
    return Object.keys(this.get('control.value') || {}).length;
  }.property('control.value'),

  dataString: function () {
    return JSON.stringify(this.get('control.value'), null, 2);
  }.property('control.value'),

  isVisual: function () {
    return ['video', 'rich', 'photo'].indexOf(this.get('control.value.type')) >= 0;
  }.property('control.value.type'),

  previewValue: function () {

    var preview = '';

    switch (this.get('control.value.type')) {
    case 'video':
    case 'rich':
      preview = this.get('control.value.html');
      break;
    case 'photo':
      preview = '';
      break;
    default:
      if (this.get('control.value.title')) {
        preview = this.get('control.value.title') + ' (' + this.get('control.value.original_url') + ')';
      }
      break;
    }

    return preview;

  }.property('control.value'),

  actions: {
    getEmbed: function () {
      if (!this.get('url') || this.get('isFetching')) {
        return;
      }

      this.set('isFetching', true);
      this.set('control.value', {});

      var embedlyControl = this;

      $.embedly.oembed(this.get('url'), {
        key: window.ENV.embedlyKey,
        query: this.get('control.meta.data.options')
      }).progress(function (data) {
        embedlyControl.set('isFetching', false);
        embedlyControl.set('control.value', data);
      });
    },

    togglePreview: function () {
      this.toggleProperty('showCode');
      this.toggleProperty('showPreview');
    },

    clearValue: function () {
      this.set('control.value', {});
    }
  }
});
<|endoftext|>


<commit_before>// Copyright 2009, 2010, 2011 Chris Forno
//
// This file is part of Vocabulink.
//
// Vocabulink is free software: you can redistribute it and/or modify it under
// the terms of the GNU Affero General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option) any
// later version.
//
// Vocabulink is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
// A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
// details.
//
// You should have received a copy of the GNU Affero General Public License
// along with Vocabulink. If not, see <http://www.gnu.org/licenses/>.

if (!window.console) {
  window.console = {
    log: function () {}
  };
}

(function ($) {

// Crockford's prototypal inheritance operator
V.object = function (o) {
  function F() {}
  F.prototype = o;
  return new F();
};

// This returns a component of the user's authtoken cookie or null if the
// cookie does not exist or the component is not found.
function authTokenPart(key) {
  var authToken = $.cookie('auth');
  if (authToken) {
    var match = authToken.match(new RegExp(key + '=([^&]+)'));
    if (match) {
      return match[1];
    } else {
      return null;
    }
  } else {
    return null;
  }
}

V.loggedIn = function () {
  return V.memberName !== null;
};

V.memberGravatar = function () {
  if (V.gravatarHash) {
    return 'http://www.gravatar.com/avatar.php?gravatar_id=' + V.gravatarHash + '&size=60&default=wavatar';
  } else {
    return null;
  }
};

V.verified = V.memberGravatar;

// http://stackoverflow.com/questions/647259/javascript-query-string
function queryString() {
  var result = {},
      queryString = location.search.substring(1),
      re = /([^&=]+)(=([^&]*))?/g,
      m;
  while (m = re.exec(queryString)) {
    result[decodeURIComponent(m[1])] = m[3] ? decodeURIComponent(m[3]) : true;
  }
  return result;
};
V.query = queryString();

V.incrLinksToReview = function (by) {
  var num = parseInt($('#head .review-box strong').text(), 10) + by;
  if (num == 1) {
    $('#head .review-box').empty().append('1 link to review');
  } else {
    $('#head .review-box').empty().append('' + num + ' links to review');
  }
}

V.toastMessage = function (type, msg, sticky) {
  return $().toastmessage('showToast', {'text': msg
                                       ,'type': type
                                       ,'sticky': sticky
                                       ,'position': 'top-center'
                                       });
}

V.toastNotice = function (msg, sticky) {
  return V.toastMessage('notice', msg, sticky);
}

V.toastSuccess = function (msg, sticky) {
  return V.toastMessage('success', msg, sticky);
}

V.toastError = function (msg, sticky) {
  return V.toastMessage('error', msg, sticky);
}

V.toastWarning = function (msg, sticky) {
  return V.toastMessage('warning', msg, sticky);
}

function lostPasswordPopup() {
  var content = $('

Lost Password
'
          + '<form id="lost-password-form" action="/member/password/reset" method="post">'
            + '
Enter the email address you signed up with, and we\'ll send you a link to reset your password with.
'
            + '
'
              + '
Email:	<input type="email" name="email" required autofocus style="width: 295px">
'
              + '
<input class="light" type="submit" value="Send Password Recovery" style="margin-bottom: 1em">
'
            + '
'
          + '</form>'
        + '
').css('width', '370px');
  $.modal(content);
  var form = $('#lost-password-form');
  var modal = $('#simplemodal-container');
  form.minform()
      .submit(function (e) {
        modal.mask('Sending...');
        e.preventDefault();
        $.post($(this).attr('action'), $(this).serialize())
          .done(function () {$.modal.close(); V.toastSuccess('Password recovery instructions sent.');})
          .fail(function (xhr) {modal.unmask(); V.toastError(xhr.responseText, true);});
        return false;
      });
}

// TODO: Factor out common code between login and signup popups.
V.loginPopup = function () {
  var headBar = $('#head-bar');
  var popup = $(
    '<form id="login-popup" action="https://www.vocabulink.com/member/login" method="post">'
    + '
'
      + '
Username:	<input id="login-username" name="username" required autofocus>
'
      + '
Password:	<input id="login-password" type="password" name="password" required>
'
    + '
'
    + '<input type="submit" value="Login" class="dark">'
    + 'lost password?'
  + '</form>').appendTo(headBar);
  popup.css('top', headBar.offset().top + headBar.outerHeight())
       .css('left', headBar.offset().left + headBar.outerWidth() - $('#login-popup').outerWidth() - 3)
       .find('.cancel').click(function () {
         $(this).parent().remove();
         lostPasswordPopup();
         return false;
       });
  popup.minform();
};

V.signupPopup = function() {
  var headBar = $('#head-bar');
  var usernameOK = false;
  var emailOK = false;
  var popup = $(
    '<form id="signup-popup" action="https://www.vocabulink.com/member/signup" method="post">'
    + '
Sign Up for Free
'
    + '
'
      + '
Username:	<input id="signup-username" name="username" required autofocus minlength="3" maxlength="32">
'
      + '
Email:	<input id="signup-email" type="email" name="email" required>
'
      + '
Password:	<input id="signup-password" type="password" name="password" required>
'
      + '
I agree to the Terms of Use.<input id="signup-terms" name="terms" type="checkbox" required>
'
      + '
	<input type="submit" value="Signup" class="dark">
'
    + '
'
  + '</form>').appendTo(headBar);
  popup.css('top', headBar.offset().top + headBar.outerHeight())
       .css('left', headBar.offset().left + headBar.outerWidth() - $('#signup-popup').outerWidth() - 3)
       .find('.cancel').click(function () {
         $(this).parent().remove();
       });
  popup.minform();
  popup.submit(function () {
    if (!usernameOK) {
      V.toastError("Your chosen username is unavailable or invalid.");
      return false;
    }
    if (!emailOK) {
      V.toastError("Your chosen email address is unavailable or invalid.");
      return false;
    }
  });
  $('#signup-username').change(function () {
    var username = $(this).val();
    $.get('http://www.vocabulink.com/user/' + username + '/available')
     .done(function (available) {
       if (available) {
         $('#signup-username').parent().parent().find('td:last-child').empty().append('');
         usernameOK = true;
       } else {
         $('#signup-username').parent().parent().find('td:last-child').empty().append('');
       }
     });
  });
  $('#signup-email').change(function () {
    var email = $(this).val();
    $.get('http://www.vocabulink.com/email/' + email + '/available')
     .done(function (available) {
       if (available) {
         $('#signup-email').parent().parent().find('td:last-child').empty().append('');
         emailOK = true;
       } else {
         $('#signup-email').parent().parent().find('td:last-child').empty().append('');
       }
     });
  });
}

V.contactPopup = function () {
  var content = $('

Contact Us
'
          + '<form id="contact-form" action="/contact" method="post">'
            + '<input type="hidden" name="url" value="' + window.location + '">'
            + '
'
              + '
Email:	<input type="email" name="email" required autofocus style="width: 295px">
'
              + '
Message:	<textarea name="message" required style="width: 300px"></textarea>
'
              + '
<input class="light" type="submit" value="Send" style="margin-bottom: 1em">
'
            + '
'
          + '</form>'
        + '
');
  if (V.memberGravatar()) {
    content.find('tr:first-child').remove();
  }
  $.modal(content);
  var form = $('#contact-form');
  var modal = $('#simplemodal-container');
  form.minform()
      .submit(function (e) {
        modal.mask('Sending...');
        e.preventDefault();
        $.post($(this).attr('action'), $(this).serialize())
          .done(function () {$.modal.close(); V.toastSuccess('Message sent.');})
          .fail(function (xhr) {modal.unmask(); V.toastError(xhr.responseText, true);});
        return false;
      });
};

V.verificationPopup = function () {
  var content = $(
    '

Email Verification Required
'
    + '
In order to interact with Vocabulink, you need to confirm your email address.
'
    + '<form method="post" action="/member/confirmation" style="margin-bottom: 2.6em;">If you haven\'t received a confirmation email: <input class="button light" type="submit" value="Resend Confirmation Email"></form>'
  + '
'
  );
  $.modal(content);
};

// initialization for every page
$(function () {
  try {
    var pageTracker = _gat._getTracker("UA-73938-2");
    pageTracker._trackPageview();
  } catch(err) {}
  $('#login-button').click(function () {
    if ($('#login-popup').length) {
      $('#login-popup').remove();
    } else {
      $('#signup-popup').remove();
      V.loginPopup();
    }
    return false;
  });

  // Check for signals in the query string.
  if (V.query['badlogin'] && !V.loggedIn()) {
    V.toastError("Username and password do not match (or don't exist).");
    V.loginPopup();
  }
  if (V.query['signedup']) {
    V.toastSuccess("Welcome! Please check your email to confirm your account.", true);
  }
  if (V.query['emailconfirmed']) {
    V.toastSuccess("Congratulations! You've confirmed your account.", true);
  }

  $('#signup-button').click(function () {
    if ($('#signup-popup').length) {
      $('#signup-popup').remove();
    } else {
      $('#login-popup').remove();
      V.signupPopup();
    }
    return false;
  });

  // Hook up any buttons that require login to popup the login box.
  if (!V.loggedIn()) {
    $('.login-required').live('click', function () {
      if (!$('#login-popup').length) {
        V.loginPopup();
      }
      return false;
    });
  } else {
    // Similarly, if there are any buttons that require verification, hook those up.
    if (!V.verified()) {
      $('.verified').live('click', function () {
        V.verificationPopup();
        return false;
      });
    }
  }

  $('.contact-us').live('click', function () {V.contactPopup(); return false;});
});

})(jQuery);
<commit_msg>Switching to new gravatar URL format.<commit_after>// Copyright 2009, 2010, 2011, 2012 Chris Forno
//
// This file is part of Vocabulink.
//
// Vocabulink is free software: you can redistribute it and/or modify it under
// the terms of the GNU Affero General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option) any
// later version.
//
// Vocabulink is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
// A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
// details.
//
// You should have received a copy of the GNU Affero General Public License
// along with Vocabulink. If not, see <http://www.gnu.org/licenses/>.

if (!window.console) {
  window.console = {
    log: function () {}
  };
}

(function ($) {

// Crockford's prototypal inheritance operator
V.object = function (o) {
  function F() {}
  F.prototype = o;
  return new F();
};

// This returns a component of the user's authtoken cookie or null if the
// cookie does not exist or the component is not found.
function authTokenPart(key) {
  var authToken = $.cookie('auth');
  if (authToken) {
    var match = authToken.match(new RegExp(key + '=([^&]+)'));
    if (match) {
      return match[1];
    } else {
      return null;
    }
  } else {
    return null;
  }
}

V.loggedIn = function () {
  return V.memberName !== null;
};

V.memberGravatar = function () {
  if (V.gravatarHash) {
    return 'http://www.gravatar.com/avatar/' + V.gravatarHash + '?s=60&d=wavatar&r=x';
  } else {
    return null;
  }
};

V.verified = V.memberGravatar;

// http://stackoverflow.com/questions/647259/javascript-query-string
function queryString() {
  var result = {},
      queryString = location.search.substring(1),
      re = /([^&=]+)(=([^&]*))?/g,
      m;
  while (m = re.exec(queryString)) {
    result[decodeURIComponent(m[1])] = m[3] ? decodeURIComponent(m[3]) : true;
  }
  return result;
};
V.query = queryString();

V.incrLinksToReview = function (by) {
  var num = parseInt($('#head .review-box strong').text(), 10) + by;
  if (num == 1) {
    $('#head .review-box').empty().append('1 link to review');
  } else {
    $('#head .review-box').empty().append('' + num + ' links to review');
  }
}

V.toastMessage = function (type, msg, sticky) {
  return $().toastmessage('showToast', {'text': msg
                                       ,'type': type
                                       ,'sticky': sticky
                                       ,'position': 'top-center'
                                       });
}

V.toastNotice = function (msg, sticky) {
  return V.toastMessage('notice', msg, sticky);
}

V.toastSuccess = function (msg, sticky) {
  return V.toastMessage('success', msg, sticky);
}

V.toastError = function (msg, sticky) {
  return V.toastMessage('error', msg, sticky);
}

V.toastWarning = function (msg, sticky) {
  return V.toastMessage('warning', msg, sticky);
}

function lostPasswordPopup() {
  var content = $('

Lost Password
'
          + '<form id="lost-password-form" action="/member/password/reset" method="post">'
            + '
Enter the email address you signed up with, and we\'ll send you a link to reset your password with.
'
            + '
'
              + '
Email:	<input type="email" name="email" required autofocus style="width: 295px">
'
              + '
<input class="light" type="submit" value="Send Password Recovery" style="margin-bottom: 1em">
'
            + '
'
          + '</form>'
        + '
').css('width', '370px');
  $.modal(content);
  var form = $('#lost-password-form');
  var modal = $('#simplemodal-container');
  form.minform()
      .submit(function (e) {
        modal.mask('Sending...');
        e.preventDefault();
        $.post($(this).attr('action'), $(this).serialize())
          .done(function () {$.modal.close(); V.toastSuccess('Password recovery instructions sent.');})
          .fail(function (xhr) {modal.unmask(); V.toastError(xhr.responseText, true);});
        return false;
      });
}

// TODO: Factor out common code between login and signup popups.
V.loginPopup = function () {
  var headBar = $('#head-bar');
  var popup = $(
    '<form id="login-popup" action="https://www.vocabulink.com/member/login" method="post">'
    + '
'
      + '
Username:	<input id="login-username" name="username" required autofocus>
'
      + '
Password:	<input id="login-password" type="password" name="password" required>
'
    + '
'
    + '<input type="submit" value="Login" class="dark">'
    + 'lost password?'
  + '</form>').appendTo(headBar);
  popup.css('top', headBar.offset().top + headBar.outerHeight())
       .css('left', headBar.offset().left + headBar.outerWidth() - $('#login-popup').outerWidth() - 3)
       .find('.cancel').click(function () {
         $(this).parent().remove();
         lostPasswordPopup();
         return false;
       });
  popup.minform();
};

V.signupPopup = function() {
  var headBar = $('#head-bar');
  var usernameOK = false;
  var emailOK = false;
  var popup = $(
    '<form id="signup-popup" action="https://www.vocabulink.com/member/signup" method="post">'
    + '
Sign Up for Free
'
    + '
'
      + '
Username:	<input id="signup-username" name="username" required autofocus minlength="3" maxlength="32">
'
      + '
Email:	<input id="signup-email" type="email" name="email" required>
'
      + '
Password:	<input id="signup-password" type="password" name="password" required>
'
      + '
I agree to the Terms of Use.<input id="signup-terms" name="terms" type="checkbox" required>
'
      + '
	<input type="submit" value="Signup" class="dark">
'
    + '
'
  + '</form>').appendTo(headBar);
  popup.css('top', headBar.offset().top + headBar.outerHeight())
       .css('left', headBar.offset().left + headBar.outerWidth() - $('#signup-popup').outerWidth() - 3)
       .find('.cancel').click(function () {
         $(this).parent().remove();
       });
  popup.minform();
  popup.submit(function () {
    if (!usernameOK) {
      V.toastError("Your chosen username is unavailable or invalid.");
      return false;
    }
    if (!emailOK) {
      V.toastError("Your chosen email address is unavailable or invalid.");
      return false;
    }
  });
  $('#signup-username').change(function () {
    var username = $(this).val();
    $.get('http://www.vocabulink.com/user/' + username + '/available')
     .done(function (available) {
       if (available) {
         $('#signup-username').parent().parent().find('td:last-child').empty().append('');
         usernameOK = true;
       } else {
         $('#signup-username').parent().parent().find('td:last-child').empty().append('');
       }
     });
  });
  $('#signup-email').change(function () {
    var email = $(this).val();
    $.get('http://www.vocabulink.com/email/' + email + '/available')
     .done(function (available) {
       if (available) {
         $('#signup-email').parent().parent().find('td:last-child').empty().append('');
         emailOK = true;
       } else {
         $('#signup-email').parent().parent().find('td:last-child').empty().append('');
       }
     });
  });
}

V.contactPopup = function () {
  var content = $('

Contact Us
'
          + '<form id="contact-form" action="/contact" method="post">'
            + '<input type="hidden" name="url" value="' + window.location + '">'
            + '
'
              + '
Email:	<input type="email" name="email" required autofocus style="width: 295px">
'
              + '
Message:	<textarea name="message" required style="width: 300px"></textarea>
'
              + '
<input class="light" type="submit" value="Send" style="margin-bottom: 1em">
'
            + '
'
          + '</form>'
        + '
');
  if (V.memberGravatar()) {
    content.find('tr:first-child').remove();
  }
  $.modal(content);
  var form = $('#contact-form');
  var modal = $('#simplemodal-container');
  form.minform()
      .submit(function (e) {
        modal.mask('Sending...');
        e.preventDefault();
        $.post($(this).attr('action'), $(this).serialize())
          .done(function () {$.modal.close(); V.toastSuccess('Message sent.');})
          .fail(function (xhr) {modal.unmask(); V.toastError(xhr.responseText, true);});
        return false;
      });
};

V.verificationPopup = function () {
  var content = $(
    '

Email Verification Required
'
    + '
In order to interact with Vocabulink, you need to confirm your email address.
'
    + '<form method="post" action="/member/confirmation" style="margin-bottom: 2.6em;">If you haven\'t received a confirmation email: <input class="button light" type="submit" value="Resend Confirmation Email"></form>'
  + '
'
  );
  $.modal(content);
};

// initialization for every page
$(function () {
  try {
    var pageTracker = _gat._getTracker("UA-73938-2");
    pageTracker._trackPageview();
  } catch(err) {}
  $('#login-button').click(function () {
    if ($('#login-popup').length) {
      $('#login-popup').remove();
    } else {
      $('#signup-popup').remove();
      V.loginPopup();
    }
    return false;
  });

  // Check for signals in the query string.
  if (V.query['badlogin'] && !V.loggedIn()) {
    V.toastError("Username and password do not match (or don't exist).");
    V.loginPopup();
  }
  if (V.query['signedup']) {
    V.toastSuccess("Welcome! Please check your email to confirm your account.", true);
  }
  if (V.query['emailconfirmed']) {
    V.toastSuccess("Congratulations! You've confirmed your account.", true);
  }

  $('#signup-button').click(function () {
    if ($('#signup-popup').length) {
      $('#signup-popup').remove();
    } else {
      $('#login-popup').remove();
      V.signupPopup();
    }
    return false;
  });

  // Hook up any buttons that require login to popup the login box.
  if (!V.loggedIn()) {
    $('.login-required').live('click', function () {
      if (!$('#login-popup').length) {
        V.loginPopup();
      }
      return false;
    });
  } else {
    // Similarly, if there are any buttons that require verification, hook those up.
    if (!V.verified()) {
      $('.verified').live('click', function () {
        V.verificationPopup();
        return false;
      });
    }
  }

  $('.contact-us').live('click', function () {V.contactPopup(); return false;});
});

})(jQuery);
<|endoftext|>


<commit_before>'use strict';

var cheerio = require('cheerio')
  , tools = require('./tools')
  , entryObject = require('./entry')
  , getParadigm = require('./paradigme')
  ;

function findEntry($, selector) {
  var word = "";
  var words = $(selector).find('a');
  $(words).each(function (index, element) {
    if (index < words.length - 1) {
      word += $(element).text() + ", ";
    }
    else {
      word += $(element).text();
    }
  });
  return word;
}

function findInterpretation($, tr, article){
  var interpretation = [];
  $(article).find("span").remove(".oppsgramordklassevindu");
  if($(".artikkelinnhold > span.utvidet", tr).children().length > 0){

    // TODO: Check if the div.tydig exists if not there should be another way to handle the definition

    $(".artikkelinnhold > span.utvidet > div.tyding.utvidet", tr).each(function(){

      $(this).find(".kompakt").each(function(){
        $(this).remove();
      });

      var test = $(this).text();
      $(this).children(".tyding").each(function(){
        $(this).find(".kompakt").each(function(){
          $(this).remove();
        });

        test += $(this).text();
      });

      if(test !== null) {
        interpretation.push({definition: test});
      }
    });

  }

  if(interpretation.length === 0) {
    var short = $(article).find(".utvidet").clone().children().remove().end().text();
    interpretation.push({definition: short});
  }

  return interpretation;
}

function findOrigin($, article){
  // Removing the classes kompakt and tydingC failes if the classes are missing.
  // TODO: check if the classes exists
//        if($(".artikkelinnhold > span.utvidet", tr).children().length > 0){
//          // Since there is more levels
//          $(article).find(".tydingC").each(function(){
//            $(this).remove();
//          });
//          $(article).find(".kompakt").each(function(){
//            $(this).remove();
//          });
//        }

  // ORIGIN OF THE WORD
  // CLEAN UP SOME
  $(article).find("span").remove(".utvidet");

  article = article.html().toString();
  article = article.replace(/


<commit_before>'use strict';

const head = document['head'] || document.getElementsByTagName("head")[0] || root;
const header = $('#header');
const $body = $('body');
const initialHeadHeight = header.innerHeight();
const tocNav = $('#toc');
const headerFixPosition = $('.nav-hero-container').innerHeight();
const topDocNavHeight = $('.top-doc-nav-container').innerHeight();
const stickyElement = $('.sticky-element');
const stickyElementPosition = headerFixPosition; // Sticky element top-offset (154px)
const goTopBtn = $('#go-top-btn');
const copyrightEl = $('.copyright');
const $pre = $('pre');
const isFaqPage = $body.is('.faq');
const isDocsPage = $body.is('.docs');
const isPromoPage = $body.is('.promo-page');
const topOffset = 12; // Offset from the `header` navigation
const scrollToOffset = initialHeadHeight + topOffset;

/** Code color variables */
const $colorSelector = $('.color-selector');
const $colorSelectorLinks = $('.color-selector .color-link');
const $selectorDark = $('.color-link.dark');
const $selectorLight = $('.color-link.light');
const colorDark = 'dark';
const colorLight = 'light';
const cookieColorName = 'themeColor';
const baseStylesUrl = '/libs/prettify/skins/';
const darkStylesUrl = baseStylesUrl + 'dark-theme-prettify.css';
const lightStylesUrl = baseStylesUrl + 'light-theme-prettify.css';

/** Grid breakpoints */
const windowHeightMobile = 520;
const phoneMedium = 480;
const phoneXLarge = 640;

$(function() {
    changeCodeColor();
    initPrettyprint();
    openHeaderMenuOnMobile();
    addExternalClass();
    initTocTocify();
    showScrollTopBtn();
    fixStickyElement();
    showCodeColorSelector();
    initBootstrapTooltips();

    if (isFaqPage) {
        expandItemOnHashChange();
        preventDefaultScroll();
    }
});

jQuery(window).on('load', function() {
    ifCookiesExist();
    setStickyElMaxHeight();
    scrollToAnchor();
});

window.onhashchange = function() {
    if (isFaqPage) {
        expandItemOnHashChange();
        scrollToAnchor();
    }
};

window.onscroll = function() {
    fixStickyElement();
    fixHead();
    setStickyElMaxHeight();
    showScrollTopBtn();

    if (isPromoPage) {
        showCodeColorSelectorOnPromoPage();
    }
};

$(window).resize(function() {
    resizeStickyElHeightWithWindow();
    ifCookiesExist();
    fixHead();
    setColorSelectorTopPosition();

    if (isPromoPage) {
        showCodeColorSelectorOnPromoPage();
    }
});

/**
 * Changes code color theme by clicking on the `color-selector` icons.
 *
 *
On page load, the color will be set from the cookie value. If the cookie value is `null`
 * will be set default cookie value.
 */
function changeCodeColor() {
    const cookieValue = Cookies.get(cookieColorName);

    if (cookieValue == null) {
        setDefaultCookieValue();
    } else {
        colorDark === cookieValue && setDarkTheme();
        colorLight === cookieValue && setLightTheme();
    }

    $selectorDark.click(function() {
        setDarkTheme();
    });

    $selectorLight.click(function() {
        setLightTheme();
    })
}

/**
 * Sets default cookie value for the `code` color as `dark`.
 */
function setDefaultCookieValue() {
    Cookies.set(cookieColorName, colorDark);
    setDarkTheme();
}

/**
 * Sets dark theme color.
 */
function setDarkTheme() {
    loadPrettifyStyles(darkStylesUrl);
    $pre.css('opacity', '1');
    makeSelectorActive($selectorDark, colorDark);
}

/**
 * Sets light theme color.
 */
function setLightTheme() {
    loadPrettifyStyles(lightStylesUrl);
    $pre.css('opacity', '1');
    makeSelectorActive($selectorLight, colorLight);
}

/**
 * Loads `prettify` theme style sheets.
 *
 *
`<style>` tag with the `#prettify-styles` ID will be created in the `head` of the
 * document. If the tag is already exist it will be updated depending on the selected theme color.
 * Style files are located in the `/libs/prettify/skins/` folder.
 *
 * @param {string} stylesHref `href` to the `css` file
 */
function loadPrettifyStyles(stylesHref) {
    const $prettifyStyleSheets = $('#prettify-styles');

    if ($prettifyStyleSheets.length) {
        $prettifyStyleSheets.attr('href', stylesHref);
    } else {
        const link = document.createElement('link');
        link.rel = 'stylesheet';
        link.id = 'prettify-styles';
        link.type = 'text/css';
        link.href = stylesHref;
        head.appendChild(link);
    }
}

/**
 * Makes color selector active and sets the value to the `cookie`.
 *
 * @param {Object} selector color selector DOM element
 * @param {string} color color value
 */
function makeSelectorActive(selector, color) {
    $colorSelectorLinks.removeClass('active');
    selector.addClass('active');
    Cookies.set(cookieColorName, color);
}

/**
 * Inits pretty-print scripts.
 *
 * @see {@link https://github.com/google/code-prettify/blob/master/docs/getting_started.md code-prettify}
 */
function initPrettyprint() {
    $('pre').addClass('prettyprint');
    $.getScript("/libs/prettify/run_prettify.js", function(){});
    $.getScript("/libs/prettify/lang-css.js", function(){});
    $.getScript("/libs/prettify/lang-go.js", function(){});
    $.getScript("/libs/prettify/lang-proto.js", function(){});
    $.getScript("/libs/prettify/lang-swift.js", function(){});
    $.getScript("/libs/prettify/lang-yaml.js", function(){});
}

/**
 * Shows the code color selector if there is a `pre` tag on the page and the scroll position
 * under the header.
 */
function showCodeColorSelector() {
    const isPreElementExist = $('.prettyprint').length;

    setColorSelectorTopPosition();

    if (isPreElementExist) {
        if (isPromoPage) {
            showCodeColorSelectorOnPromoPage();
        } else {
            $colorSelector.addClass('show');
        }
    } else {
        $colorSelector.removeClass('show');
    }
}

/**
 * Sets the top position of the `color-selector` depending on the screen size.
 */
function setColorSelectorTopPosition() {
    const inMiddleOnMobile = 42 + '%';
    const topOffset = 24;
    // The value should be equal to the CSS `$color-selector-top-position`
    const docsTopPosition = headerFixPosition + topDocNavHeight + topOffset;
    const isWindowHeightMobile = $(window).height() < windowHeightMobile;

    if (isDocsPage && !isWindowHeightMobile) {
        $colorSelector.css('top', docsTopPosition);
    } else {
        $colorSelector.css('top', inMiddleOnMobile);
    }
}

/**
 * Shows `color-selector` on promo page only if it doesn't overlap the `hero` section.
 *
 *
If it overlaps `hero` section it will be shown when scroll position below the `hero`.
 * It also works for the screens with small height.
 */
function showCodeColorSelectorOnPromoPage() {
    const phoneScreenWidth = phoneMedium;
    const phoneScreenHeight = windowHeightMobile;
    const isPhone = $(window).width() <= phoneScreenWidth;
    const isPhoneHorizontal = $(window).height() <= phoneScreenHeight;
    const scrollPositionUnderHero = window.pageYOffset > headerFixPosition;
    const isPhoneAndUnderHero = isPhone && scrollPositionUnderHero;
    const isPhoneHorizontalAndUnderHero = isPhoneHorizontal && scrollPositionUnderHero;

    if (isPromoPage) {
        if (isPhoneAndUnderHero || isPhoneHorizontalAndUnderHero || !isPhone && !isPhoneHorizontal) {
            $colorSelector.addClass('show');
        } else {
            $colorSelector.removeClass('show');
        }
    }
}

/**
 * Opens header menu on mobile device.
 */
function openHeaderMenuOnMobile() {
    $('#nav-icon-menu').click(function(){
        $(this).toggleClass('open');
        $('body').toggleClass('navigation-opened');
    });
}

/**
 * Adds the `external` class to every outbound link on the site.
 *
 *
The css will add a small right arrow after the link.
 */
function addExternalClass() {
    $('a').filter(function() {
        return this.hostname && this.hostname !== location.hostname;
    }).addClass('external');
}

/**
 * Inits `toc` navigation if a page has more than 2 headers.
 *
 * @see {@link http://gregfranko.com/jquery.tocify.js/ Toc Tocify}
 */
function initTocTocify() {
    const docsContainer = $('.docs-content-text');
    const headersQuantity = docsContainer.find('h2, h3, h4');

    if (headersQuantity.length >= 3) {
        tocNav.tocify({
            context: docsContainer,
            selectors: 'h2, h3, h4',
            showAndHide: false,
            scrollTo: scrollToOffset,
            extendPage: false,
            hashGenerator: 'pretty',
            smoothScroll: false
        });
    }
}

/**
 * Fix sticky element on page while scrolling.
 */
function fixStickyElement() {
    if (stickyElement.length) {
        if (window.pageYOffset > stickyElementPosition) {
            stickyElement.addClass('sticky');
        }
        else {
            stickyElement.removeClass('sticky');
        }
    }
}

/**
 * Makes header navigation sticky on scroll.
 *
 *
The header will not be sticky if the `header` has `hide-sticky-header` class. But it
 * still working on mobile devices. Used for all `docs` pages.
 */
function fixHead() {
    const stickyHeaderHidden = header.hasClass('hide-sticky-header');
    const mobileSize = phoneXLarge;
    const mobileWindow = $(window).width() <= mobileSize;
    const desktopWindow = $(window).width() > mobileSize;
    const headerExistAndNotHidden = header.length && !stickyHeaderHidden;
    const headerOnMobile = header.length && mobileWindow;
    const headerHiddedAndNotMobile = header.length && stickyHeaderHidden && desktopWindow;

    if (headerExistAndNotHidden || headerOnMobile) {
        if (window.pageYOffset > headerFixPosition) {
            header.addClass('not-top'); // When the navigation below offset
            header.addClass('pinned'); // When the navigation below hero section
            header.removeClass('unpinned');
        } else {
            header.removeClass('pinned');
            header.addClass('unpinned');
        }
        /** Determines the header at the top of the page. */
        if (window.pageYOffset < initialHeadHeight) {
            returnToInitialState();
        }
    }

    if (headerHiddedAndNotMobile) {
        returnToInitialState();
    }
}

/**
 * Returns header classes to the initial state.
 */
function returnToInitialState() {
    header.removeClass('not-top');
    header.removeClass('unpinned');
}

/**
 * Sets max-height for the sticky element depends on the scroll position.
 */
function setStickyElMaxHeight() {
    if (stickyElement.length) {
        const elHeights = calcStickyElHeight();

        /**
         * Determines that the max-height value is less than browser window when the scroll
         * position at the top of the page.
         */
        if (elHeights.maxHeight < elHeights.initialHeight) {
            $(stickyElement).css('max-height', elHeights.maxHeight);
        } else {
            $(stickyElement).css('max-height', elHeights.initialHeight);
        }
    }
}

/**
 * Calculates a sticky element heights to make sure that it always fits on the page.
 *
 * @return {Object} an object with initial and calculated heights.
 * {number} initialHeight initial element max-height when the scroll at the top
 *          or at the middle of the page
 * {number} maxHeight max height that dynamically changes on scroll at the bottom of the page
 */
function calcStickyElHeight() {
    const windowHeight = $(window).height();
    const scrollPosition = $(window).scrollTop();
    const footerTopPoint = $('.footer').position().top;
    const cookieContainerHeight = $('#cookieChoiceInfo').innerHeight();
    /**
     * The distance from the element to the footer top point.
     * The value is the same as `docs-content-text` has.
     */
    const contentMarginBottom = 32;

    const initialHeight = windowHeight - stickyElementPosition + contentMarginBottom - cookieContainerHeight;
    const maxHeight = footerTopPoint - scrollPosition - stickyElementPosition + contentMarginBottom;

    return {initialHeight, maxHeight};
}

/**
 * Changes the height of the `.sticky-element` when changing the height of the window.
 */
function resizeStickyElHeightWithWindow() {
    if ($(window).height() > 600) {
        setStickyElMaxHeight();
    }
}

/**
 * Expands FAQ item on hash change.
 */
function expandItemOnHashChange() {
    if ('onhashchange' in window) {
        $(location.hash).collapse('show');
    }
}

/**
 * Prevents default scroll behavior and prevents double click on the same hash for the FAQ page.
 */
function preventDefaultScroll() {
    $('.anchor-link').click(function(event) {
        const anchor = $(this).attr('href');
        const x = window.pageXOffset;
        const y = window.pageYOffset;
        event.preventDefault();
        window.location.hash = anchor;
        window.scrollTo(x, y);
    });
}

/**
 * Scrolls to the anchor.
 */
function scrollToAnchor() {
    const anchor = location.hash;
    let offset = -scrollToOffset;

    if (isFaqPage) {
        offset = -150; // Top offset for the FAQ page target element
    }

    if ($(anchor).length) {
        $(window).scrollTo($(anchor), 500, {offset: offset});
    }
}

/**
 * Adds additional padding values if the `cookieChoiceInfo` exist on the page.
 */
function ifCookiesExist() {
    const cookieInfo = $('#cookieChoiceInfo');
    const cookieAgreeBtn = $('#cookieChoiceDismiss');
    const cookieContainerHeight = cookieInfo.innerHeight();
    const marginBottom = 10; // A bottom margin for the `Go to Top` button
    const copyrightPaddingBottom = 24; // A bottom padding for the `Copyright` div element

    if(cookieInfo.length){
        $(goTopBtn).css('bottom', cookieContainerHeight + marginBottom);
        $(copyrightEl).css('padding-bottom', cookieContainerHeight + copyrightPaddingBottom);

        /**
         * Removes additional padding values on the `Agree` button click.
         */
        $(cookieAgreeBtn).click(function(){
            $(goTopBtn).css('bottom', marginBottom);
            $(copyrightEl).css('padding-bottom', copyrightPaddingBottom);
        });
    } else {
        $(goTopBtn).css('bottom', marginBottom);
        $(copyrightEl).css('padding-bottom', copyrightPaddingBottom);
    }
}

/**
 * Shows `Go to Top` button when the scroll position is 1500px.
 */
function showScrollTopBtn() {
    if ($(this).scrollTop() > 1500 ) {
        $(goTopBtn).show();

    } else {
        $(goTopBtn).hide();
    }
}

/**
 * Scrolls to the top of the page.
 */
function topFunction() {
    $('html, body').stop().animate({scrollTop: 0}, 500, 'swing');
    return false;
}

/**
 * Inits Bootstrap tooltips.
 *
 *
Don't init tooltips if it is a touch device.
 */
function initBootstrapTooltips() {
    const options = {
        delay: { "show": 750, "hide": 100 },
        trigger: 'hover'
    };

    if(isTouchDevice() === false) {
        $('[data-toggle = "tooltip"]').tooltip(options);
    }
}

/**
 * Determines if it is a touch device.
 *
 * @return {boolean} true if it is a touch device, false otherwise
 */
function isTouchDevice() {
    return true === ('ontouchstart' in window || window.DocumentTouch && document instanceof DocumentTouch);
}
<commit_msg>Use variable for the `pre`<commit_after>'use strict';

const head = document['head'] || document.getElementsByTagName("head")[0] || root;
const header = $('#header');
const $body = $('body');
const initialHeadHeight = header.innerHeight();
const tocNav = $('#toc');
const headerFixPosition = $('.nav-hero-container').innerHeight();
const topDocNavHeight = $('.top-doc-nav-container').innerHeight();
const stickyElement = $('.sticky-element');
const stickyElementPosition = headerFixPosition; // Sticky element top-offset (154px)
const goTopBtn = $('#go-top-btn');
const copyrightEl = $('.copyright');
const $pre = $('pre');
const isFaqPage = $body.is('.faq');
const isDocsPage = $body.is('.docs');
const isPromoPage = $body.is('.promo-page');
const topOffset = 12; // Offset from the `header` navigation
const scrollToOffset = initialHeadHeight + topOffset;

/** Code color variables */
const $colorSelector = $('.color-selector');
const $colorSelectorLinks = $('.color-selector .color-link');
const $selectorDark = $('.color-link.dark');
const $selectorLight = $('.color-link.light');
const colorDark = 'dark';
const colorLight = 'light';
const cookieColorName = 'themeColor';
const baseStylesUrl = '/libs/prettify/skins/';
const darkStylesUrl = baseStylesUrl + 'dark-theme-prettify.css';
const lightStylesUrl = baseStylesUrl + 'light-theme-prettify.css';

/** Grid breakpoints */
const windowHeightMobile = 520;
const phoneMedium = 480;
const phoneXLarge = 640;

$(function() {
    changeCodeColor();
    initPrettyprint();
    openHeaderMenuOnMobile();
    addExternalClass();
    initTocTocify();
    showScrollTopBtn();
    fixStickyElement();
    showCodeColorSelector();
    initBootstrapTooltips();

    if (isFaqPage) {
        expandItemOnHashChange();
        preventDefaultScroll();
    }
});

jQuery(window).on('load', function() {
    ifCookiesExist();
    setStickyElMaxHeight();
    scrollToAnchor();
});

window.onhashchange = function() {
    if (isFaqPage) {
        expandItemOnHashChange();
        scrollToAnchor();
    }
};

window.onscroll = function() {
    fixStickyElement();
    fixHead();
    setStickyElMaxHeight();
    showScrollTopBtn();

    if (isPromoPage) {
        showCodeColorSelectorOnPromoPage();
    }
};

$(window).resize(function() {
    resizeStickyElHeightWithWindow();
    ifCookiesExist();
    fixHead();
    setColorSelectorTopPosition();

    if (isPromoPage) {
        showCodeColorSelectorOnPromoPage();
    }
});

/**
 * Changes code color theme by clicking on the `color-selector` icons.
 *
 *
On page load, the color will be set from the cookie value. If the cookie value is `null`
 * will be set default cookie value.
 */
function changeCodeColor() {
    const cookieValue = Cookies.get(cookieColorName);

    if (cookieValue == null) {
        setDefaultCookieValue();
    } else {
        colorDark === cookieValue && setDarkTheme();
        colorLight === cookieValue && setLightTheme();
    }

    $selectorDark.click(function() {
        setDarkTheme();
    });

    $selectorLight.click(function() {
        setLightTheme();
    })
}

/**
 * Sets default cookie value for the `code` color as `dark`.
 */
function setDefaultCookieValue() {
    Cookies.set(cookieColorName, colorDark);
    setDarkTheme();
}

/**
 * Sets dark theme color.
 */
function setDarkTheme() {
    loadPrettifyStyles(darkStylesUrl);
    $pre.css('opacity', '1');
    makeSelectorActive($selectorDark, colorDark);
}

/**
 * Sets light theme color.
 */
function setLightTheme() {
    loadPrettifyStyles(lightStylesUrl);
    $pre.css('opacity', '1');
    makeSelectorActive($selectorLight, colorLight);
}

/**
 * Loads `prettify` theme style sheets.
 *
 *
`<style>` tag with the `#prettify-styles` ID will be created in the `head` of the
 * document. If the tag is already exist it will be updated depending on the selected theme color.
 * Style files are located in the `/libs/prettify/skins/` folder.
 *
 * @param {string} stylesHref `href` to the `css` file
 */
function loadPrettifyStyles(stylesHref) {
    const $prettifyStyleSheets = $('#prettify-styles');

    if ($prettifyStyleSheets.length) {
        $prettifyStyleSheets.attr('href', stylesHref);
    } else {
        const link = document.createElement('link');
        link.rel = 'stylesheet';
        link.id = 'prettify-styles';
        link.type = 'text/css';
        link.href = stylesHref;
        head.appendChild(link);
    }
}

/**
 * Makes color selector active and sets the value to the `cookie`.
 *
 * @param {Object} selector color selector DOM element
 * @param {string} color color value
 */
function makeSelectorActive(selector, color) {
    $colorSelectorLinks.removeClass('active');
    selector.addClass('active');
    Cookies.set(cookieColorName, color);
}

/**
 * Inits pretty-print scripts.
 *
 * @see {@link https://github.com/google/code-prettify/blob/master/docs/getting_started.md code-prettify}
 */
function initPrettyprint() {
    $pre.addClass('prettyprint');
    $.getScript("/libs/prettify/run_prettify.js", function(){});
    $.getScript("/libs/prettify/lang-css.js", function(){});
    $.getScript("/libs/prettify/lang-go.js", function(){});
    $.getScript("/libs/prettify/lang-proto.js", function(){});
    $.getScript("/libs/prettify/lang-swift.js", function(){});
    $.getScript("/libs/prettify/lang-yaml.js", function(){});
}

/**
 * Shows the code color selector if there is a `pre` tag on the page and the scroll position
 * under the header.
 */
function showCodeColorSelector() {
    const isPreElementExist = $('.prettyprint').length;

    setColorSelectorTopPosition();

    if (isPreElementExist) {
        if (isPromoPage) {
            showCodeColorSelectorOnPromoPage();
        } else {
            $colorSelector.addClass('show');
        }
    } else {
        $colorSelector.removeClass('show');
    }
}

/**
 * Sets the top position of the `color-selector` depending on the screen size.
 */
function setColorSelectorTopPosition() {
    const inMiddleOnMobile = 42 + '%';
    const topOffset = 24;
    // The value should be equal to the CSS `$color-selector-top-position`
    const docsTopPosition = headerFixPosition + topDocNavHeight + topOffset;
    const isWindowHeightMobile = $(window).height() < windowHeightMobile;

    if (isDocsPage && !isWindowHeightMobile) {
        $colorSelector.css('top', docsTopPosition);
    } else {
        $colorSelector.css('top', inMiddleOnMobile);
    }
}

/**
 * Shows `color-selector` on promo page only if it doesn't overlap the `hero` section.
 *
 *
If it overlaps `hero` section it will be shown when scroll position below the `hero`.
 * It also works for the screens with small height.
 */
function showCodeColorSelectorOnPromoPage() {
    const phoneScreenWidth = phoneMedium;
    const phoneScreenHeight = windowHeightMobile;
    const isPhone = $(window).width() <= phoneScreenWidth;
    const isPhoneHorizontal = $(window).height() <= phoneScreenHeight;
    const scrollPositionUnderHero = window.pageYOffset > headerFixPosition;
    const isPhoneAndUnderHero = isPhone && scrollPositionUnderHero;
    const isPhoneHorizontalAndUnderHero = isPhoneHorizontal && scrollPositionUnderHero;

    if (isPromoPage) {
        if (isPhoneAndUnderHero || isPhoneHorizontalAndUnderHero || !isPhone && !isPhoneHorizontal) {
            $colorSelector.addClass('show');
        } else {
            $colorSelector.removeClass('show');
        }
    }
}

/**
 * Opens header menu on mobile device.
 */
function openHeaderMenuOnMobile() {
    $('#nav-icon-menu').click(function(){
        $(this).toggleClass('open');
        $('body').toggleClass('navigation-opened');
    });
}

/**
 * Adds the `external` class to every outbound link on the site.
 *
 *
The css will add a small right arrow after the link.
 */
function addExternalClass() {
    $('a').filter(function() {
        return this.hostname && this.hostname !== location.hostname;
    }).addClass('external');
}

/**
 * Inits `toc` navigation if a page has more than 2 headers.
 *
 * @see {@link http://gregfranko.com/jquery.tocify.js/ Toc Tocify}
 */
function initTocTocify() {
    const docsContainer = $('.docs-content-text');
    const headersQuantity = docsContainer.find('h2, h3, h4');

    if (headersQuantity.length >= 3) {
        tocNav.tocify({
            context: docsContainer,
            selectors: 'h2, h3, h4',
            showAndHide: false,
            scrollTo: scrollToOffset,
            extendPage: false,
            hashGenerator: 'pretty',
            smoothScroll: false
        });
    }
}

/**
 * Fix sticky element on page while scrolling.
 */
function fixStickyElement() {
    if (stickyElement.length) {
        if (window.pageYOffset > stickyElementPosition) {
            stickyElement.addClass('sticky');
        }
        else {
            stickyElement.removeClass('sticky');
        }
    }
}

/**
 * Makes header navigation sticky on scroll.
 *
 *
The header will not be sticky if the `header` has `hide-sticky-header` class. But it
 * still working on mobile devices. Used for all `docs` pages.
 */
function fixHead() {
    const stickyHeaderHidden = header.hasClass('hide-sticky-header');
    const mobileSize = phoneXLarge;
    const mobileWindow = $(window).width() <= mobileSize;
    const desktopWindow = $(window).width() > mobileSize;
    const headerExistAndNotHidden = header.length && !stickyHeaderHidden;
    const headerOnMobile = header.length && mobileWindow;
    const headerHiddedAndNotMobile = header.length && stickyHeaderHidden && desktopWindow;

    if (headerExistAndNotHidden || headerOnMobile) {
        if (window.pageYOffset > headerFixPosition) {
            header.addClass('not-top'); // When the navigation below offset
            header.addClass('pinned'); // When the navigation below hero section
            header.removeClass('unpinned');
        } else {
            header.removeClass('pinned');
            header.addClass('unpinned');
        }
        /** Determines the header at the top of the page. */
        if (window.pageYOffset < initialHeadHeight) {
            returnToInitialState();
        }
    }

    if (headerHiddedAndNotMobile) {
        returnToInitialState();
    }
}

/**
 * Returns header classes to the initial state.
 */
function returnToInitialState() {
    header.removeClass('not-top');
    header.removeClass('unpinned');
}

/**
 * Sets max-height for the sticky element depends on the scroll position.
 */
function setStickyElMaxHeight() {
    if (stickyElement.length) {
        const elHeights = calcStickyElHeight();

        /**
         * Determines that the max-height value is less than browser window when the scroll
         * position at the top of the page.
         */
        if (elHeights.maxHeight < elHeights.initialHeight) {
            $(stickyElement).css('max-height', elHeights.maxHeight);
        } else {
            $(stickyElement).css('max-height', elHeights.initialHeight);
        }
    }
}

/**
 * Calculates a sticky element heights to make sure that it always fits on the page.
 *
 * @return {Object} an object with initial and calculated heights.
 * {number} initialHeight initial element max-height when the scroll at the top
 *          or at the middle of the page
 * {number} maxHeight max height that dynamically changes on scroll at the bottom of the page
 */
function calcStickyElHeight() {
    const windowHeight = $(window).height();
    const scrollPosition = $(window).scrollTop();
    const footerTopPoint = $('.footer').position().top;
    const cookieContainerHeight = $('#cookieChoiceInfo').innerHeight();
    /**
     * The distance from the element to the footer top point.
     * The value is the same as `docs-content-text` has.
     */
    const contentMarginBottom = 32;

    const initialHeight = windowHeight - stickyElementPosition + contentMarginBottom - cookieContainerHeight;
    const maxHeight = footerTopPoint - scrollPosition - stickyElementPosition + contentMarginBottom;

    return {initialHeight, maxHeight};
}

/**
 * Changes the height of the `.sticky-element` when changing the height of the window.
 */
function resizeStickyElHeightWithWindow() {
    if ($(window).height() > 600) {
        setStickyElMaxHeight();
    }
}

/**
 * Expands FAQ item on hash change.
 */
function expandItemOnHashChange() {
    if ('onhashchange' in window) {
        $(location.hash).collapse('show');
    }
}

/**
 * Prevents default scroll behavior and prevents double click on the same hash for the FAQ page.
 */
function preventDefaultScroll() {
    $('.anchor-link').click(function(event) {
        const anchor = $(this).attr('href');
        const x = window.pageXOffset;
        const y = window.pageYOffset;
        event.preventDefault();
        window.location.hash = anchor;
        window.scrollTo(x, y);
    });
}

/**
 * Scrolls to the anchor.
 */
function scrollToAnchor() {
    const anchor = location.hash;
    let offset = -scrollToOffset;

    if (isFaqPage) {
        offset = -150; // Top offset for the FAQ page target element
    }

    if ($(anchor).length) {
        $(window).scrollTo($(anchor), 500, {offset: offset});
    }
}

/**
 * Adds additional padding values if the `cookieChoiceInfo` exist on the page.
 */
function ifCookiesExist() {
    const cookieInfo = $('#cookieChoiceInfo');
    const cookieAgreeBtn = $('#cookieChoiceDismiss');
    const cookieContainerHeight = cookieInfo.innerHeight();
    const marginBottom = 10; // A bottom margin for the `Go to Top` button
    const copyrightPaddingBottom = 24; // A bottom padding for the `Copyright` div element

    if(cookieInfo.length){
        $(goTopBtn).css('bottom', cookieContainerHeight + marginBottom);
        $(copyrightEl).css('padding-bottom', cookieContainerHeight + copyrightPaddingBottom);

        /**
         * Removes additional padding values on the `Agree` button click.
         */
        $(cookieAgreeBtn).click(function(){
            $(goTopBtn).css('bottom', marginBottom);
            $(copyrightEl).css('padding-bottom', copyrightPaddingBottom);
        });
    } else {
        $(goTopBtn).css('bottom', marginBottom);
        $(copyrightEl).css('padding-bottom', copyrightPaddingBottom);
    }
}

/**
 * Shows `Go to Top` button when the scroll position is 1500px.
 */
function showScrollTopBtn() {
    if ($(this).scrollTop() > 1500 ) {
        $(goTopBtn).show();

    } else {
        $(goTopBtn).hide();
    }
}

/**
 * Scrolls to the top of the page.
 */
function topFunction() {
    $('html, body').stop().animate({scrollTop: 0}, 500, 'swing');
    return false;
}

/**
 * Inits Bootstrap tooltips.
 *
 *
Don't init tooltips if it is a touch device.
 */
function initBootstrapTooltips() {
    const options = {
        delay: { "show": 750, "hide": 100 },
        trigger: 'hover'
    };

    if(isTouchDevice() === false) {
        $('[data-toggle = "tooltip"]').tooltip(options);
    }
}

/**
 * Determines if it is a touch device.
 *
 * @return {boolean} true if it is a touch device, false otherwise
 */
function isTouchDevice() {
    return true === ('ontouchstart' in window || window.DocumentTouch && document instanceof DocumentTouch);
}
<|endoftext|>


<commit_before>(function () {
	/* verify vote */
	setInterval(() => {

		let lastVote = JSON.parse( localStorage.getItem('Buddy-Last-Vote') );

		if ( lastVote == null ) {
			lastVote = 0;
		}

		let date = moment().format('DD/MM/YYYY');
		let day = moment().format('dddd');
		let month = moment().format('MMM');

		let hourActual = moment().format('HH:MM');

		/* verify is valid day of week */
		if( day != 'Saturday' && day != 'Sunday' && date != lastVote.day ) {
			localStorage.removeItem('Buddy-Vote');
			/* localStorage.removeItem('Buddy-Last-Vote'); */
			let login = '';
			let vote = '';
			login = JSON.parse( localStorage.getItem('Buddy-Login') );
			vote = JSON.parse( localStorage.getItem('Buddy-Vote') );
			/* validate hour to show notification */
			if ( hourActual > '09:00' && hourActual < '18:00' ) {
				resetVote(login, vote);
			}
		} else {
			if ( hourActual > '09:00' && hourActual < '18:00' ) {
				resetVote(login, vote);
			}
		}

	}, 3600000);

/*
3600000 1hour
86400000 24hours
*/

function resetVote(login, vote) {
	let options = {
		icon: '../images/buddy-20x20.png'
	}

	if ( login === '' || login === null || login === undefined ) {
		/* set angry icon */
		chrome.browserAction.setIcon({path: '../images/vote-me-20x20.png'});

		if (!('Notification' in window)) {
			alert('This browser does not support desktop notification');
		}
		else if (Notification.permission === 'granted') {
			let notification = new Notification('Olá, faça login por favor!', options);
			// voteAgain();
			setTimeout(() => {
				notification.close();
			}, 10000);
			notification.onclick = () => {
				chrome.tabs.create({
					url: chrome.extension.getURL('pages/popup.html'),
					active: true
				}, function(tab) {
					chrome.windows.create({
						tabId: tab.id,
						type: 'popup',
						height: 420,
						width: 500,
						focused: true
					});
				});
			}
		}
		else if (Notification.permission !== 'denied') {
			Notification.requestPermission(function (permission) {
				if (permission === 'granted') {
					let notification = new Notification('Olá, faça login por favor!', options);
					// voteAgain();
					setTimeout(() => {
						notification.close();
					}, 10000);
					notification.onclick = () => {
						chrome.tabs.create({
							url: chrome.extension.getURL('pages/popup.html'),
							active: true
						}, function(tab) {
							chrome.windows.create({
								tabId: tab.id,
								type: 'popup',
								height: 420,
								width: 500,
								focused: true
							});
						});
					}
				}
			});
		}

	} else if ( vote === '' || vote === null || vote === undefined ) {
		/* set angry icon */
		chrome.browserAction.setIcon({path: '../images/vote-me-20x20.png'});

		if (!('Notification' in window)) {
			alert('This browser does not support desktop notification');
		}
		else if (Notification.permission === 'granted') {
			let notification = new Notification('Olá, como está seu dia?', options);
			// voteAgain();
			setTimeout(() => {
				notification.close();
			}, 10000);
			notification.onclick = () => {
				chrome.tabs.create({
					url: chrome.extension.getURL('pages/popup.html'),
					active: true
				}, function(tab) {
					chrome.windows.create({
						tabId: tab.id,
						type: 'popup',
						height: 120,
						width: 500,
						focused: true
					});
				});
			}
		}
		else if (Notification.permission !== 'denied') {
			Notification.requestPermission(function (permission) {
				if (permission === 'granted') {
					let notification = new Notification('Olá, como está seu dia?', options);
					// voteAgain();
					setTimeout(() => {
						notification.close();
					}, 10000);
					notification.onclick = () => {
						chrome.tabs.create({
							url: chrome.extension.getURL('pages/popup.html'),
							active: true
						}, function(tab) {
							chrome.windows.create({
								tabId: tab.id,
								type: 'popup',
								height: 120,
								width: 500,
								focused: true
							});
						});
					}
				}
			});
		}

	} else {
		/* set good icon */
		chrome.browserAction.setIcon({path: '../images/buddy-20x20.png'});
	}
}

// function voteAgain() {
// 	let lastNotify = JSON.parse( localStorage.getItem('Buddy-Notify') );

// 	if (  lastNotify === '' || lastNotify === null || lastNotify === undefined ) {

// 		chrome.tabs.create({
// 			url: chrome.extension.getURL('pages/popup.html'),
// 			active: true
// 		}, function(tab) {
// 			chrome.windows.create({
// 				tabId: tab.id,
// 				type: 'popup',
// 				focused: false
// 			});
// 			/* set localstorage value true */
// 			let info = {
// 				'notify': true
// 			};
// 			localStorage.setItem('Buddy-Notify', JSON.stringify(info) );
// 		});

// 	}

// }

setInterval(() => {
	/* reset localstorage value */
	localStorage.removeItem('Buddy-Notify');
}, 72000000);
/*
3600000 1hour
72000000 20hours
*/

/*end js*/
})();<commit_msg>fix: time when notification si visible 15seconds<commit_after>(function () {
	/* verify vote */
	setInterval(() => {

		let lastVote = JSON.parse( localStorage.getItem('Buddy-Last-Vote') );

		if ( lastVote == null ) {
			lastVote = 0;
		}

		let date = moment().format('DD/MM/YYYY');
		let day = moment().format('dddd');
		let month = moment().format('MMM');

		let hourActual = moment().format('HH:MM');

		/* verify is valid day of week */
		if( day != 'Saturday' && day != 'Sunday' && date != lastVote.day ) {
			localStorage.removeItem('Buddy-Vote');
			/* localStorage.removeItem('Buddy-Last-Vote'); */
			let login = '';
			let vote = '';
			login = JSON.parse( localStorage.getItem('Buddy-Login') );
			vote = JSON.parse( localStorage.getItem('Buddy-Vote') );
			/* validate hour to show notification */
			if ( hourActual > '09:00' && hourActual < '18:00' ) {
				resetVote(login, vote);
			}
		} else {
			if ( hourActual > '09:00' && hourActual < '18:00' ) {
				resetVote(login, vote);
			}
		}

	}, 3600000);

/*
3600000 1hour
86400000 24hours
*/

function resetVote(login, vote) {
	let options = {
		icon: '../images/buddy-20x20.png'
	}

	if ( login === '' || login === null || login === undefined ) {
		/* set angry icon */
		chrome.browserAction.setIcon({path: '../images/vote-me-20x20.png'});

		if (!('Notification' in window)) {
			alert('This browser does not support desktop notification');
		}
		else if (Notification.permission === 'granted') {
			let notification = new Notification('Olá, faça login por favor!', options);
			// voteAgain();
			setTimeout(() => {
				notification.close();
			}, 15000);
			notification.onclick = () => {
				chrome.tabs.create({
					url: chrome.extension.getURL('pages/popup.html'),
					active: true
				}, function(tab) {
					chrome.windows.create({
						tabId: tab.id,
						type: 'popup',
						height: 420,
						width: 500,
						focused: true
					});
				});
			}
		}
		else if (Notification.permission !== 'denied') {
			Notification.requestPermission(function (permission) {
				if (permission === 'granted') {
					let notification = new Notification('Olá, faça login por favor!', options);
					// voteAgain();
					setTimeout(() => {
						notification.close();
					}, 15000);
					notification.onclick = () => {
						chrome.tabs.create({
							url: chrome.extension.getURL('pages/popup.html'),
							active: true
						}, function(tab) {
							chrome.windows.create({
								tabId: tab.id,
								type: 'popup',
								height: 420,
								width: 500,
								focused: true
							});
						});
					}
				}
			});
		}

	} else if ( vote === '' || vote === null || vote === undefined ) {
		/* set angry icon */
		chrome.browserAction.setIcon({path: '../images/vote-me-20x20.png'});

		if (!('Notification' in window)) {
			alert('This browser does not support desktop notification');
		}
		else if (Notification.permission === 'granted') {
			let notification = new Notification('Olá, como está seu dia?', options);
			// voteAgain();
			setTimeout(() => {
				notification.close();
			}, 15000);
			notification.onclick = () => {
				chrome.tabs.create({
					url: chrome.extension.getURL('pages/popup.html'),
					active: true
				}, function(tab) {
					chrome.windows.create({
						tabId: tab.id,
						type: 'popup',
						height: 120,
						width: 500,
						focused: true
					});
				});
			}
		}
		else if (Notification.permission !== 'denied') {
			Notification.requestPermission(function (permission) {
				if (permission === 'granted') {
					let notification = new Notification('Olá, como está seu dia?', options);
					// voteAgain();
					setTimeout(() => {
						notification.close();
					}, 15000);
					notification.onclick = () => {
						chrome.tabs.create({
							url: chrome.extension.getURL('pages/popup.html'),
							active: true
						}, function(tab) {
							chrome.windows.create({
								tabId: tab.id,
								type: 'popup',
								height: 120,
								width: 500,
								focused: true
							});
						});
					}
				}
			});
		}

	} else {
		/* set good icon */
		chrome.browserAction.setIcon({path: '../images/buddy-20x20.png'});
	}
}

// function voteAgain() {
// 	let lastNotify = JSON.parse( localStorage.getItem('Buddy-Notify') );

// 	if (  lastNotify === '' || lastNotify === null || lastNotify === undefined ) {

// 		chrome.tabs.create({
// 			url: chrome.extension.getURL('pages/popup.html'),
// 			active: true
// 		}, function(tab) {
// 			chrome.windows.create({
// 				tabId: tab.id,
// 				type: 'popup',
// 				focused: false
// 			});
// 			/* set localstorage value true */
// 			let info = {
// 				'notify': true
// 			};
// 			localStorage.setItem('Buddy-Notify', JSON.stringify(info) );
// 		});

// 	}

// }

setInterval(() => {
	/* reset localstorage value */
	localStorage.removeItem('Buddy-Notify');
}, 72000000);
/*
3600000 1hour
72000000 20hours
*/

/*end js*/
})();<|endoftext|>


<commit_before>/*!
* mingy
* Copyright(c) 2011 Mike Cantelon
* MIT Licensed
*/

var util = require('util')
  , url = require('url')
  , Command = require('./command').Command

exports.Parser = function Parser(commands) {

  this.loadCommands(commands)
  this.validators = {}
  this.env = {}
}

exports.Parser.prototype = {

  setEnv: function(property, value) {
    this.env[property] = value
  },

  loadCommands: function(commands) {

    if (commands) {

      if(commands.constructor.name == 'Array') {

        this.commands = commands
      }
      else if(commands.constructor.name == 'Object') {

        this.commands = {}

        for (var name in commands) {
          this.addCommand(name)
          .set('syntax', commands[name].syntax)
          .set('logic', commands[name].logic)
        }
      }
      else {

        throw "Commands given to parser must be an array or hash (object)."
      }
    }
    else {

      this.commands = {}
    }
  },

  addCommand: function(name) {

    // throw error if name already taken
    var command = new Command('name')
    this.commands[name] = command
    return command
  },

  addValidator: function(name, logic) {
    this.validators[name] = logic
  },

  parse: function(input, callback, system) {

    input = this.cleanInput(input)
    var lexemes = input.split(' ')
    return this.parseLexemes(lexemes, callback, system)
  },

  cleanInput: function(input) {

    // server shell sends extra junk
    input = input.replace("\r\n", "\n")

    // remove trailing newline
    if (input.slice(-1) == "\n") {
      input = input.slice(0, input.length - 1)
    }

    // remove redundant spaces
    while (input.indexOf('  ') != -1) {
      input = input.replace('  ', ' ')
    }

    return input
  },

  parseLexemes: function(lexemes, callback, system) {

    var output = ''

    // cycle through commands looking for syntax match
    for (var index in this.commands) {

      var command = this.commands[index]

      // we clone lexemes because if the last syntax lexeme has a wildcard the
      // submitted lexeme corresponding to the last syntax lexeme ends up
      // getting subsequent submitted lexemes added to it
      if (command.try(this.validators, this.env, this.clone(lexemes), true)) {

        // command condition jazz goes here
        if (1) {

          system = system || {}
          system.callback = callback
          result = command.try(this.validators, this.env, lexemes, false, system)

          if (result) {
            return output + result
          }
        }
        else if(output) {
          return output
        }
      }
    }
  },

  clone: function(obj) {
    var newObj = (obj instanceof Array) ? [] : {};
    for (i in obj) {
      if (i == 'clone') continue;
      if (obj[i] && typeof obj[i] == "object") {
        newObj[i] = this.clone(obj[i]);
      } else newObj[i] = obj[i]
    } return newObj;
  }
}
<commit_msg>Minor refactor.<commit_after>/*!
* mingy
* Copyright(c) 2011 Mike Cantelon
* MIT Licensed
*/

var util = require('util')
  , url = require('url')
  , Command = require('./command').Command

exports.Parser = function Parser(commands) {

  this.loadCommands(commands)
  this.validators = {}
  this.env = {}
}

exports.Parser.prototype = {

  setEnv: function(property, value) {
    this.env[property] = value
  },

  loadCommands: function(commands) {

    if (commands) {

      if(commands.constructor.name == 'Array') {

        this.commands = commands
      }
      else if(commands.constructor.name == 'Object') {

        this.commands = {}

        for (var name in commands) {
          this.addCommand(name)
          .set('syntax', commands[name].syntax)
          .set('logic', commands[name].logic)
        }
      }
      else {

        throw "Commands given to parser must be an array or hash (object)."
      }
    }
    else {

      this.commands = {}
    }
  },

  addCommand: function(name) {

    // throw error if name already taken
    var command = new Command('name')
    this.commands[name] = command
    return command
  },

  addValidator: function(name, logic) {
    this.validators[name] = logic
  },

  parse: function(input, callback, system) {

    input = this.cleanInput(input)
    var lexemes = input.split(' ')
    return this.parseLexemes(lexemes, callback, system)
  },

  cleanInput: function(input) {

    // server shell sends extra junk
    input = input.replace("\r\n", "\n")

    // remove trailing newline
    if (input.slice(-1) == "\n") {
      input = input.slice(0, input.length - 1)
    }

    // remove redundant spaces
    while (input.indexOf('  ') != -1) {
      input = input.replace('  ', ' ')
    }

    return input
  },

  validCommands: function(lexemes) {

    var commands = []

    // cycle through commands looking for syntax match
    for (var index in this.commands) {

      var command = this.commands[index]

      // we clone lexemes because if the last syntax lexeme has a wildcard the
      // submitted lexeme corresponding to the last syntax lexeme ends up
      // getting subsequent submitted lexemes added to it
      if (command.try(this.validators, this.env, this.clone(lexemes), true)) {
        commands.push(command)
      }
    }

    return commands
  },

  parseLexemes: function(lexemes, callback, system) {

    var output = ''

    // cycle through commands looking for syntax match
    var validCommands = this.validCommands(lexemes)
    for (var index in validCommands) {

      var command = validCommands[index]

      // command condition jazz goes here
      if (1) {

        system = system || {}
        system.callback = callback
        result = command.try(this.validators, this.env, lexemes, false, system)

        if (result) {
          return output + result
        }
      }
      else if(output) {
        return output
      }
    }
  },

  clone: function(obj) {
    var newObj = (obj instanceof Array) ? [] : {};
    for (i in obj) {
      if (i == 'clone') continue;
      if (obj[i] && typeof obj[i] == "object") {
        newObj[i] = this.clone(obj[i]);
      } else newObj[i] = obj[i]
    } return newObj;
  }
}
<|endoftext|>


<commit_before>var app = app || {};

app.config = (function() {

	'use strict';

	var config = {
		debug: false,
		primaryDisplayCurrencies: ['BTC', 'CZK', 'EUR', 'GBP', 'LTC', 'USD'],
		supportEmail: 'cryptoterminal.eu@gmail.com',
		cache: {
			onAppStartClearOlderThan: 86400000,// milliseconds
		},
		ctApi: _.extend({
			primusPath: '/primus',
			exchangeRates: {
				timeout: 10000,
			},
		}, app.config.ctApi),
		primus: {
			reconnect: {
				max: 5000, // Number: The max delay before we try to reconnect.
				min: 500, // Number: The minimum delay before we try reconnect.
				retries: Infinity, // Number: How many times we should try to reconnect.
			},
		},
		sqlite: {
			name: 'crypto-terminal.db',
			location: 'default',
			uniqueId: {
				length: 20,
				charset: 'abcdefghijklmnopqrstuvqxyzABCDEFGHIJKLMNOPQRSTUVQXYZ1234567890-_',
			},
		},
		qrCodes: {
			errorCorrectionLevel: 'M',
			margin: 0,
		},
		defaultLocale: 'en',
		numberFormats: {
			default: {
				BigNumber: {
					FORMAT: {
						decimalSeparator: '.',
						groupSeparator: ',',
						groupSize: 3,
					},
				},
				decimals: 2,
			},
			'CZK': {
				BigNumber: {
					FORMAT: {
						decimalSeparator: ',',
						groupSeparator: ' ',
						groupSize: 3,
					},
				},
				decimals: 2,
			},
		},
		numberPad: {
			keysMaxLength: 12,
		},
		screenSaver: {
			idleTime: 3 * 60 * 1000,
		},
		touch: {
			quick: {
				// Maximum time between touchstart and touchend; milliseconds.
				maxTime: 300,
				// Maximum percent of screen traveled for emitting "click" event.
				maxMovement: 2.5,
			},
			long: {
				// Delay before emitting "longtouchstart" event; milliseconds.
				delay: 450,
			},
			swipe: {
				minSpeed: 0.0025,// % of screen width / millisecond
				minMovementX: 12,// % screen width
				tolerance: 4,// % screen width
			},
		},
		// Preset amounts are displayed on the #pay screen as buttons.
		presets: {
			// Example:
			// 'CZK': ['150', '200']
		},
		numberOfSampleAddressesToShow: 5,
		settingsPin: {
			minLength: 1,
			unlockTime: 5 * 60 * 1000,
		},
		paymentRequests: {
			timeout: 5 * 60 * 1000,
			saveDelay: 5000,
		},
		paymentHistory: {
			list: {
				limit: 999,
			},
			export: {
				storagePath: 'file:///storage/emulated/0/',
				storageDirectory: 'download',
				extension: '.csv',
				dateFormat: 'DD-MM-YYYY_HHmmss'
			}
		},
		settings: [
			{
				name: 'debug',
				visible: false,
				default: false,
			},
			{
				name: 'developer',
				visible: false,
				default: false,
			},
			{
				name: 'getting-started-complete',
				visible: false,
				default: false,
			},
			{
				name: 'configurableCryptoCurrencies',
				visible: false,
				default: [],
			},
			{
				name: 'displayCurrency',
				label: function() {
					return app.i18n.t('settings.display-currency.label');
				},
				type: 'select',
				default: 'BTC',
				required: true,
				options: function() {
					var supportedDisplayCurrencies = app.util.getSupportedDisplayCurrencies();
					var sticky = config.primaryDisplayCurrencies;
					var rest = _.difference(supportedDisplayCurrencies, sticky);
					return _.map([].concat(sticky, [''], rest), function(code) {
						return {
							key: code,
							label: code,
							disabled: !code,
						};
					});
				},
			},
			{
				name: 'dateFormat',
				label: function() {
					return app.i18n.t('settings.date-format.label');
				},
				type: 'select',
				required: true,
				options: function() {
					return [
						{
							key: 'DD/MM/YYYY HH:mm:ss',
							label: moment().format('DD/MM/YYYY HH:mm:ss')
						},
						{
							key: 'MMMM Do YYYY, H:mm:ss A',
							label: moment().format('MMMM Do YYYY, H:mm:ss A')
						},
						{
							key: 'lll',
							label: moment().format('lll')
						},
						{
							key: 'LLLL',
							label: moment().format('LLLL')
						},
					];
				},
			},
			{
				name: 'theme',
				label: function() {
					return app.i18n.t('settings.theme.label');
				},
				type: 'select',
				default: 'default',
				required: true,
				options: function() {
					return [
						{
							key: 'default',
							label: function() {
								return app.i18n.t('settings.theme.option.default.label');
							},
						},
						{
							key: 'dark',
							label: function() {
								return app.i18n.t('settings.theme.option.dark.label');
							},
						},
					];
				},
			},
			{
				name: 'inAppAudio',
				label: function() {
					return app.i18n.t('settings.in-app-audio.label');
				},
				description: function() {
					return app.i18n.t('settings.in-app-audio.description');
				},
				type: 'checkbox',
				default: true,
			},
			{
				name: 'screenSaver',
				label: function() {
					return app.i18n.t('settings.screen-saver.label');
				},
				description: function() {
					return app.i18n.t('settings.screen-saver.description');
				},
				type: 'checkbox',
				default: true,
			},
		],
		recommendations: {
			hardwareWallets: [
				{
					name: 'Trezor',
					url: 'https://shop.trezor.io?a=cryptoterminal.eu',
					image: 'images/trezor.svg',
				},
				{
					name: 'Ledger Wallet',
					url: 'https://www.ledgerwallet.com/r/285ab5ed6cb2',
					image: 'images/ledger.svg',
				},
			],
			mobileWallets: {
				android: [
					{
						name: 'Coinomi',
						paymentMethods: ['bitcoinTestnet', 'litecoin'],
						url: 'https://play.google.com/store/apps/details?id=com.coinomi.wallet',
					},
					{
						name: 'Eclair Wallet',
						paymentMethods: ['bitcoinLightning'],
						url: 'https://play.google.com/store/apps/details?id=fr.acinq.eclair.wallet.mainnet2',
					},
					{
						name: 'Samourai Wallet',
						paymentMethods: ['bitcoin'],
						url: 'https://play.google.com/store/apps/details?id=com.samourai.wallet',
					},
				],
				ios: [
					{
						name: 'BRD (formerly "BreadWallet")',
						paymentMethods: ['bitcoin'],
						url: 'https://play.google.com/store/apps/details?id=com.breadwallet',
					},
					{
						name: 'Coinomi',
						paymentMethods: ['bitcoinTestnet'],
						url: 'https://itunes.apple.com/us/app/coinomi-wallet/id1333588809?mt=8',
					},
					{
						name: 'LoafWallet',
						paymentMethods: ['litecoin'],
						url: 'https://itunes.apple.com/us/app/loafwallet/id1119332592?ls=1&mt=8',
					},
				],
			},
		},
	};

	config.settings = _.map(config.settings, function(setting) {
		return _.extend({}, setting, {
			visible: setting.visible !== false,
		});
	});

	_.each(app.paymentMethods, function(paymentMethod) {
		if (paymentMethod.numberFormat) {
			config.numberFormats[paymentMethod.code] = paymentMethod.numberFormat;
		}
	});

	return config;

})();
<commit_msg>Removed sqlite config - no longer used<commit_after>var app = app || {};

app.config = (function() {

	'use strict';

	var config = {
		debug: false,
		primaryDisplayCurrencies: ['BTC', 'CZK', 'EUR', 'GBP', 'LTC', 'USD'],
		supportEmail: 'cryptoterminal.eu@gmail.com',
		cache: {
			onAppStartClearOlderThan: 86400000,// milliseconds
		},
		ctApi: _.extend({
			primusPath: '/primus',
			exchangeRates: {
				timeout: 10000,
			},
		}, app.config.ctApi),
		primus: {
			reconnect: {
				max: 5000, // Number: The max delay before we try to reconnect.
				min: 500, // Number: The minimum delay before we try reconnect.
				retries: Infinity, // Number: How many times we should try to reconnect.
			},
		},
		qrCodes: {
			errorCorrectionLevel: 'M',
			margin: 0,
		},
		defaultLocale: 'en',
		numberFormats: {
			default: {
				BigNumber: {
					FORMAT: {
						decimalSeparator: '.',
						groupSeparator: ',',
						groupSize: 3,
					},
				},
				decimals: 2,
			},
			'CZK': {
				BigNumber: {
					FORMAT: {
						decimalSeparator: ',',
						groupSeparator: ' ',
						groupSize: 3,
					},
				},
				decimals: 2,
			},
		},
		numberPad: {
			keysMaxLength: 12,
		},
		screenSaver: {
			idleTime: 3 * 60 * 1000,
		},
		touch: {
			quick: {
				// Maximum time between touchstart and touchend; milliseconds.
				maxTime: 300,
				// Maximum percent of screen traveled for emitting "click" event.
				maxMovement: 2.5,
			},
			long: {
				// Delay before emitting "longtouchstart" event; milliseconds.
				delay: 450,
			},
			swipe: {
				minSpeed: 0.0025,// % of screen width / millisecond
				minMovementX: 12,// % screen width
				tolerance: 4,// % screen width
			},
		},
		// Preset amounts are displayed on the #pay screen as buttons.
		presets: {
			// Example:
			// 'CZK': ['150', '200']
		},
		numberOfSampleAddressesToShow: 5,
		settingsPin: {
			minLength: 1,
			unlockTime: 5 * 60 * 1000,
		},
		paymentRequests: {
			timeout: 5 * 60 * 1000,
			saveDelay: 5000,
		},
		paymentHistory: {
			list: {
				limit: 999,
			},
			export: {
				storagePath: 'file:///storage/emulated/0/',
				storageDirectory: 'download',
				extension: '.csv',
				dateFormat: 'DD-MM-YYYY_HHmmss'
			}
		},
		settings: [
			{
				name: 'debug',
				visible: false,
				default: false,
			},
			{
				name: 'developer',
				visible: false,
				default: false,
			},
			{
				name: 'getting-started-complete',
				visible: false,
				default: false,
			},
			{
				name: 'configurableCryptoCurrencies',
				visible: false,
				default: [],
			},
			{
				name: 'displayCurrency',
				label: function() {
					return app.i18n.t('settings.display-currency.label');
				},
				type: 'select',
				default: 'BTC',
				required: true,
				options: function() {
					var supportedDisplayCurrencies = app.util.getSupportedDisplayCurrencies();
					var sticky = config.primaryDisplayCurrencies;
					var rest = _.difference(supportedDisplayCurrencies, sticky);
					return _.map([].concat(sticky, [''], rest), function(code) {
						return {
							key: code,
							label: code,
							disabled: !code,
						};
					});
				},
			},
			{
				name: 'dateFormat',
				label: function() {
					return app.i18n.t('settings.date-format.label');
				},
				type: 'select',
				required: true,
				options: function() {
					return [
						{
							key: 'DD/MM/YYYY HH:mm:ss',
							label: moment().format('DD/MM/YYYY HH:mm:ss')
						},
						{
							key: 'MMMM Do YYYY, H:mm:ss A',
							label: moment().format('MMMM Do YYYY, H:mm:ss A')
						},
						{
							key: 'lll',
							label: moment().format('lll')
						},
						{
							key: 'LLLL',
							label: moment().format('LLLL')
						},
					];
				},
			},
			{
				name: 'theme',
				label: function() {
					return app.i18n.t('settings.theme.label');
				},
				type: 'select',
				default: 'default',
				required: true,
				options: function() {
					return [
						{
							key: 'default',
							label: function() {
								return app.i18n.t('settings.theme.option.default.label');
							},
						},
						{
							key: 'dark',
							label: function() {
								return app.i18n.t('settings.theme.option.dark.label');
							},
						},
					];
				},
			},
			{
				name: 'inAppAudio',
				label: function() {
					return app.i18n.t('settings.in-app-audio.label');
				},
				description: function() {
					return app.i18n.t('settings.in-app-audio.description');
				},
				type: 'checkbox',
				default: true,
			},
			{
				name: 'screenSaver',
				label: function() {
					return app.i18n.t('settings.screen-saver.label');
				},
				description: function() {
					return app.i18n.t('settings.screen-saver.description');
				},
				type: 'checkbox',
				default: true,
			},
		],
		recommendations: {
			hardwareWallets: [
				{
					name: 'Trezor',
					url: 'https://shop.trezor.io?a=cryptoterminal.eu',
					image: 'images/trezor.svg',
				},
				{
					name: 'Ledger Wallet',
					url: 'https://www.ledgerwallet.com/r/285ab5ed6cb2',
					image: 'images/ledger.svg',
				},
			],
			mobileWallets: {
				android: [
					{
						name: 'Coinomi',
						paymentMethods: ['bitcoinTestnet', 'litecoin'],
						url: 'https://play.google.com/store/apps/details?id=com.coinomi.wallet',
					},
					{
						name: 'Eclair Wallet',
						paymentMethods: ['bitcoinLightning'],
						url: 'https://play.google.com/store/apps/details?id=fr.acinq.eclair.wallet.mainnet2',
					},
					{
						name: 'Samourai Wallet',
						paymentMethods: ['bitcoin'],
						url: 'https://play.google.com/store/apps/details?id=com.samourai.wallet',
					},
				],
				ios: [
					{
						name: 'BRD (formerly "BreadWallet")',
						paymentMethods: ['bitcoin'],
						url: 'https://play.google.com/store/apps/details?id=com.breadwallet',
					},
					{
						name: 'Coinomi',
						paymentMethods: ['bitcoinTestnet'],
						url: 'https://itunes.apple.com/us/app/coinomi-wallet/id1333588809?mt=8',
					},
					{
						name: 'LoafWallet',
						paymentMethods: ['litecoin'],
						url: 'https://itunes.apple.com/us/app/loafwallet/id1119332592?ls=1&mt=8',
					},
				],
			},
		},
	};

	config.settings = _.map(config.settings, function(setting) {
		return _.extend({}, setting, {
			visible: setting.visible !== false,
		});
	});

	_.each(app.paymentMethods, function(paymentMethod) {
		if (paymentMethod.numberFormat) {
			config.numberFormats[paymentMethod.code] = paymentMethod.numberFormat;
		}
	});

	return config;

})();
<|endoftext|>