<commit_before>var http      = require('http'),
    apns      = require('./notification/apple'),
    gcm       = require('./notification/google'),
    qs        = require('querystring'),
    responder = require('./responder'),
    log       = require('./log').logger;

var config = require('./config.json');

function handlePostData (request, response, handler) {
  var body = '';

  request.on('data', function (data) {
    body += data;
  });

  request.on('end', function (){
    try {
      request.body = JSON.parse(body);
    } catch (err) {
      response.end(responder.err({ error: "Bad JSON Input" }));
      return;
    }

    handleRequest(request, response, handler);
  });
}

function handleRequest(request, response, handler) {
  if (request.body === undefined) {
    response.end(responder.err({ error: "No Data" }));
  } else {
    if (request.body.appId === undefined) {
      response.end(responder.err({ error: "Missing Required Field appId" }));

    } else if (request.body.deviceId === undefined) {
        response.end(responder.err({ error: "Missing Required Field deviceId" }));

    } else if (request.body.mode === undefined) {
      response.end(responder.err({ error: "Missing Required Field mode" }));

    } else if (request.body.notification === undefined) {
      response.end(responder.err({ error: "Missing Required Field notification" }));

    } else {
      // if we do not have a timeout, set the default
      if (request.body.timeout === undefined) {
        request.body.timeout = config.timeout;
      }

      handler.handleMessage(request, response);
    }
  }
}

function handleNotFound(response) {
  response.writeHead(404);
  response.end("not found");
}

var server = http.createServer(function (request, response) {
  if (request.method !== 'POST') {
    handleNotFound(response);
  }

  switch (request.url) {
  case '/message/apn':
    handlePostData(request, response, apns);
    break;
  case '/message/gcm':
    handlePostData(request, response, gcm);
    break;
  default:
    handleNotFound(response);
  }
});

server.listen(config.port ? config.port : 8080);
log.info("Listening on port "+config.port);
<commit_msg>Flattening handleRequest<commit_after>var http      = require('http'),
    apns      = require('./notification/apple'),
    gcm       = require('./notification/google'),
    qs        = require('querystring'),
    responder = require('./responder'),
    log       = require('./log').logger;

var config = require('./config.json');

function handlePostData (request, response, handler) {
  var body = '';

  request.on('data', function (data) {
    body += data;
  });

  request.on('end', function (){
    try {
      request.body = JSON.parse(body);
    } catch (err) {
      response.end(responder.err({ error: "Bad JSON Input" }));
      return;
    }

    handleRequest(request, response, handler);
  });
}

function handleRequest(request, response, handler) {
  if (request.body === undefined) {
    response.end(responder.err({ error: "No Data" }));
  }

  if (request.body.appId === undefined) {
    response.end(responder.err({ error: "Missing Required Field appId" }));
  }

  if (request.body.deviceId === undefined) {
    response.end(responder.err({ error: "Missing Required Field deviceId" }));
  }

  if (request.body.mode === undefined) {
    response.end(responder.err({ error: "Missing Required Field mode" }));
  }

  if (request.body.notification === undefined) {
    response.end(responder.err({ error: "Missing Required Field notification" }));
  }

  // if we do not have a timeout, set the default
  if (request.body.timeout === undefined) {
    request.body.timeout = config.timeout;
  }

  handler.handleMessage(request, response);
}

function handleNotFound(response) {
  response.writeHead(404);
  response.end("not found");
}

var server = http.createServer(function (request, response) {
  if (request.method !== 'POST') {
    handleNotFound(response);
  }

  switch (request.url) {
  case '/message/apn':
    handlePostData(request, response, apns);
    break;
  case '/message/gcm':
    handlePostData(request, response, gcm);
    break;
  default:
    handleNotFound(response);
  }
});

server.listen(config.port ? config.port : 8080);
log.info("Listening on port "+config.port);
<|endoftext|>


<commit_before>var notifications = {};
notifications.total = 0;

notifications.init = function() {
    if ($('[data-notif-total]').size() > 0) {
        notifications.initCounts();
        notifications.showUnread();
        notifications.delegateReadedEvent();
        notifications.listen();
    }
};

notifications.listen = function() {
    function handleData(response) {
        response = JSON.parse(response);
        console.log(response);
        if (response) {
            if (response.t == 'n') {
                notifications.handleNewNotification(response);
            }
        }
    }
    if ((typeof Meteor != 'undefined') && (typeof notificationChannel != 'undefined')) {
        Meteor.registerEventCallback("process", handleData);
        Meteor.joinChannel(notificationChannel);
        Meteor.connect();
        console.log('Escuchando notifications..');
    }
};

notifications.handleNewNotification = function(response) {
    id = response.id; entity = response.p;
    notifications.updateBubbleCount(entity, 1, false);
    ajax.genericAction('user_ajaxnotification', {'id' : id},
    function(response) {
        if (response) {
            entityContent = $('[data-entity]').data('entity');
            if ('total' === entityContent) {
                $('[data-notification]').prepend(notifications.getClassicNotificationTemplate(response));
                $('[data-sidebaralert]:first').effect("bounce", {times:2}, 300);
            } else {
                if (entityContent  === entity) {
                    if ($('[data-sidebaralert]').size() >= 4) $('[data-sidebaralert]:last').fadeOut("slow").remove();
                    $('[data-notification]').prepend(notifications.getClassicNotificationTemplate(response));
                    $('[data-sidebaralert]:first').effect("bounce", {times:2}, 300);
                } else {
                    notice(notifications.getBubbleNotificationTemplate(response));
                }
            }
        }
    });
};

notifications.showCounts = function(entity, value) {
    if (value > 0) {
        if ($('[data-notif-' + entity + ']').children("span").length > 0) {
            $('[data-notif-' + entity + ']').children("span").eq(0).html(value);
        } else {
            $('[data-notif-' + entity + ']').prepend(getBadgeTemplate(value));
        }
    } else {
        if ($('[data-notif-' + entity + ']').children("span").length > 0) $('[data-notif-' + entity + ']').children("span").eq(0).remove();
    }
    if ('total' === entity && $('[data-notif-count]').size()) $('[data-notif-count]').html(value);
    function getBadgeTemplate(number) {
        return '' + number + '';
    }
};

notifications.initCounts = function () {
    ajax.genericAction('user_ajaxgetnotifications_typecounts', {},
        function(response) {
            if (response) {
                for (i in response) {
                    result = response[i];
                    notifications.total += parseInt(result.cnt);
                    $('[data-notif-' + result.parent + ']').data('notif-' + result.parent).count = parseInt(result.cnt);
                    notifications.showCounts(result.parent, result.cnt);
                }
                notifications.showCounts("total", notifications.total);
            }
        }
    );
};

notifications.updateBubbleCount = function(entity, value, parentOfNotification) {
    // newCant = $('[data-notif-' + entity + ']').data('notif-' + entity).count += value;
    actualCant = $('[data-notif-' + entity + ']').data('notif-' + entity).count;
    newCant = parseInt(actualCant) + parseInt(value);
    $('[data-notif-' + entity + ']').data('notif-' + entity).count = newCant;
    notifications.total += value;
    notifications.showCounts(entity, newCant);
    notifications.showCounts("total", notifications.total);
    $('[data-notif-' + entity + '] span').effect("highlight", {color: "#a0c882"}, 2000);
    if ('total' != entity) $('[data-notif-' + entity + ']').effect("bounce", { times: 4 }, 1200);
    if ('total' === entity) {
         newCant = $('[data-notif-' + parentOfNotification + ']').data('notif-' + parentOfNotification).count += value;
         notifications.showCounts(parentOfNotification, newCant);
    }
};

notifications.showUnread = function () {
    if ($('[data-entity]').size() > 0) {
        entity = $('[data-entity]').data('entity');
        ajax.genericAction('notification_getlatest', { 'parentName' : entity},
            function(response) {
                console.log('Notifications unread for ' + entity + ': ' + response);
                nCounts = response.length;
                if (nCounts > 4) nCounts = 4;
                for (j = 0; j < nCounts; j++) {
                    id = response[j];
                    $.ajax({
                        url: 'http://' + location.host + Routing.generate( appLocale + '_user_ajaxnotification' ),
                        data:{
                            'id': id
                        },
                        success: function(response){
                        if (response) {
                            if ($('[data-entity]').size() > 0) {
                                //if ($('[data-sidebaralert]').size() >= 4) $('[data-sidebaralert]:last').fadeOut("slow").remove();
                                $('[data-notification]').prepend(notifications.getClassicNotificationTemplate(response));
                            }
                        }
                    });
                }
            }
        )
    }
};

notifications.readNotification = function(id) {
    ajax.genericAction({route: 'user_ajaxdeletenotification', params: { id: id }, callback: function(response) {
        console.log('ReadNotification: ' + id + ' => ' + response);
        return response;
    }});
};

notifications.acceptFriendship = function(id) {
    ajax.genericAction({route: 'friendship_accept', params: { id: id }, callback: function(response) {
        console.log('acceptFriendship: ' + id + ' => ' + response);
        return response;
    }});
};

notifications.rejectFriendship = function(id) {
    ajax.genericAction({route: 'friendship_reject', params: { id: id }, callback: function(response) {
        console.log('rejectFriendship: ' + id + ' => ' + response);
        return response;
    }});
};

notifications.delegateReadedEvent = function () {
    $('[data-notification]').on( 'mouseenter', '[data-sidebaralert]', function() {
        readed = $(this).data('sidebaralert');
        if (!readed) {
            $(this).data('sidebaralert', true);
            entity = $('[data-entity]').data('entity');
            notificationId = $(this).find('[data-notifid]').data('notifid');
            parentOfNotification = $(this).find('[data-notifid]').data('parent');
            if ($(this).find('[data-friendship-pending]').size() == 0) {
                notifications.readNotification(notificationId);
                notifications.updateBubbleCount(entity, -1, parentOfNotification);
            }
        }
    });

    $('[data-friendship-container]').on("click", '[data-accept-friendship]', function() {
        var response = confirm("Aceptar solicitud?");
        if (response) {
            friendshipId = $(this).data('accept-friendship');
            notifications.acceptFriendship(friendshipId);
            notifications.updateBubbleCount('total', -1, 'fans');
            $(this).parent('[data-friendship-container]').html(' | Solicitud Aceptada');
        }
    });

    $('[data-friendship-container]').on("click", '[data-reject-friendship]', function() {
        var response = confirm("Cancelar solicitud?");
        if (response) {
            friendshipId = $(this).data('reject-friendship');
            notifications.rejectFriendship(friendshipId);
            notifications.updateBubbleCount('total', -1, 'fans');
            $(this).parent('[data-friendship-container]').html(' | Solicitud Denegada');
        }
    });
};

notifications.getBubbleNotificationTemplate = function(htmlResponse) {
    return '
' + htmlResponse + '
';
};

notifications.getClassicNotificationTemplate = function (htmlResponse) {
    btnClose = '<button type="button" class="close" data-dismiss="alert">×</button>';
    return '
'+ btnClose + htmlResponse + '
';
};

notifications.sendToMeteor = function (type) {
    ajax.genericAction('notification_setfake', {'type': type},
        function(response){}
    );
};

notifications.test = function(id, parent) {
    var r = {}; r.id = id; r.p = parent;
    notifications.handleNewNotification(r);
};

$(document).ready(function() {
    notifications.init();
});<commit_msg>fix: 0000597: Error mis videos<commit_after>var notifications = {};
notifications.total = 0;

notifications.init = function() {
    if ($('[data-notif-total]').size() > 0) {
        notifications.initCounts();
        notifications.showUnread();
        notifications.delegateReadedEvent();
        notifications.listen();
    }
};

notifications.listen = function() {
    function handleData(response) {
        response = JSON.parse(response);
        console.log(response);
        if (response) {
            if (response.t == 'n') {
                notifications.handleNewNotification(response);
            }
        }
    }
    if ((typeof Meteor != 'undefined') && (typeof notificationChannel != 'undefined')) {
        Meteor.registerEventCallback("process", handleData);
        Meteor.joinChannel(notificationChannel);
        Meteor.connect();
        console.log('Escuchando notifications..');
    }
};

notifications.handleNewNotification = function(response) {
    id = response.id; entity = response.p;
    notifications.updateBubbleCount(entity, 1, false);
    ajax.genericAction('user_ajaxnotification', {'id' : id},
    function(response) {
        if (response) {
            entityContent = $('[data-entity]').data('entity');
            if ('total' === entityContent) {
                $('[data-notification]').prepend(notifications.getClassicNotificationTemplate(response));
                $('[data-sidebaralert]:first').effect("bounce", {times:2}, 300);
            } else {
                if (entityContent  === entity) {
                    if ($('[data-sidebaralert]').size() >= 4) $('[data-sidebaralert]:last').fadeOut("slow").remove();
                    $('[data-notification]').prepend(notifications.getClassicNotificationTemplate(response));
                    $('[data-sidebaralert]:first').effect("bounce", {times:2}, 300);
                } else {
                    notice(notifications.getBubbleNotificationTemplate(response));
                }
            }
        }
    });
};

notifications.showCounts = function(entity, value) {
    if (value > 0) {
        if ($('[data-notif-' + entity + ']').children("span").length > 0) {
            $('[data-notif-' + entity + ']').children("span").eq(0).html(value);
        } else {
            $('[data-notif-' + entity + ']').prepend(getBadgeTemplate(value));
        }
    } else {
        if ($('[data-notif-' + entity + ']').children("span").length > 0) $('[data-notif-' + entity + ']').children("span").eq(0).remove();
    }
    if ('total' === entity && $('[data-notif-count]').size()) $('[data-notif-count]').html(value);
    function getBadgeTemplate(number) {
        return '' + number + '';
    }
};

notifications.initCounts = function () {
    ajax.genericAction('user_ajaxgetnotifications_typecounts', {},
        function(response) {
            if (response) {
                for (i in response) {
                    result = response[i];
                    notifications.total += parseInt(result.cnt);
                    $('[data-notif-' + result.parent + ']').data('notif-' + result.parent).count = parseInt(result.cnt);
                    notifications.showCounts(result.parent, result.cnt);
                }
                notifications.showCounts("total", notifications.total);
            }
        }
    );
};

notifications.updateBubbleCount = function(entity, value, parentOfNotification) {
    // newCant = $('[data-notif-' + entity + ']').data('notif-' + entity).count += value;
    actualCant = $('[data-notif-' + entity + ']').data('notif-' + entity).count;
    newCant = parseInt(actualCant) + parseInt(value);
    $('[data-notif-' + entity + ']').data('notif-' + entity).count = newCant;
    notifications.total += value;
    notifications.showCounts(entity, newCant);
    notifications.showCounts("total", notifications.total);
    $('[data-notif-' + entity + '] span').effect("highlight", {color: "#a0c882"}, 2000);
    if ('total' != entity) $('[data-notif-' + entity + ']').effect("bounce", { times: 4 }, 1200);
    if ('total' === entity) {
         newCant = $('[data-notif-' + parentOfNotification + ']').data('notif-' + parentOfNotification).count += value;
         notifications.showCounts(parentOfNotification, newCant);
    }
};

notifications.showUnread = function () {
    if ($('[data-entity]').size() > 0) {
        entity = $('[data-entity]').data('entity');
        ajax.genericAction('notification_getlatest', { 'parentName' : entity},
            function(response) {
                console.log('Notifications unread for ' + entity + ': ' + response);
                nCounts = response.length;
                if (nCounts > 4) nCounts = 4;
                for (j = 0; j < nCounts; j++) {
                    id = response[j];
                    $.ajax({
                        url: 'http://' + location.host + Routing.generate( appLocale + '_user_ajaxnotification' ),
                        data:{
                            'id': id
                        },
                        success: function(response){
                            if (response) {
                                if ($('[data-entity]').size() > 0) {
                                    //if ($('[data-sidebaralert]').size() >= 4) $('[data-sidebaralert]:last').fadeOut("slow").remove();
                                    $('[data-notification]').prepend(notifications.getClassicNotificationTemplate(response));
                                }
                            }
                        }
                    });

                    /*ajax.getNotification(id, function(response) {
                        if (response) {
                            if ($('[data-entity]').size() > 0) {
                                //if ($('[data-sidebaralert]').size() >= 4) $('[data-sidebaralert]:last').fadeOut("slow").remove();
                                $('[data-notification]').prepend(notifications.getClassicNotificationTemplate(response));
                            }
                        }
                    });*/
                }
            }
        )
    }
};

notifications.readNotification = function(id) {
    ajax.genericAction({route: 'user_ajaxdeletenotification', params: { id: id }, callback: function(response) {
        console.log('ReadNotification: ' + id + ' => ' + response);
        return response;
    }});
};

notifications.acceptFriendship = function(id) {
    ajax.genericAction({route: 'friendship_accept', params: { id: id }, callback: function(response) {
        console.log('acceptFriendship: ' + id + ' => ' + response);
        return response;
    }});
};

notifications.rejectFriendship = function(id) {
    ajax.genericAction({route: 'friendship_reject', params: { id: id }, callback: function(response) {
        console.log('rejectFriendship: ' + id + ' => ' + response);
        return response;
    }});
};

notifications.delegateReadedEvent = function () {
    $('[data-notification]').on( 'mouseenter', '[data-sidebaralert]', function() {
        readed = $(this).data('sidebaralert');
        if (!readed) {
            $(this).data('sidebaralert', true);
            entity = $('[data-entity]').data('entity');
            notificationId = $(this).find('[data-notifid]').data('notifid');
            parentOfNotification = $(this).find('[data-notifid]').data('parent');
            if ($(this).find('[data-friendship-pending]').size() == 0) {
                notifications.readNotification(notificationId);
                notifications.updateBubbleCount(entity, -1, parentOfNotification);
            }
        }
    });

    $('[data-friendship-container]').on("click", '[data-accept-friendship]', function() {
        var response = confirm("Aceptar solicitud?");
        if (response) {
            friendshipId = $(this).data('accept-friendship');
            notifications.acceptFriendship(friendshipId);
            notifications.updateBubbleCount('total', -1, 'fans');
            $(this).parent('[data-friendship-container]').html(' | Solicitud Aceptada');
        }
    });

    $('[data-friendship-container]').on("click", '[data-reject-friendship]', function() {
        var response = confirm("Cancelar solicitud?");
        if (response) {
            friendshipId = $(this).data('reject-friendship');
            notifications.rejectFriendship(friendshipId);
            notifications.updateBubbleCount('total', -1, 'fans');
            $(this).parent('[data-friendship-container]').html(' | Solicitud Denegada');
        }
    });
};

notifications.getBubbleNotificationTemplate = function(htmlResponse) {
    return '
' + htmlResponse + '
';
};

notifications.getClassicNotificationTemplate = function (htmlResponse) {
    btnClose = '<button type="button" class="close" data-dismiss="alert">×</button>';
    return '
'+ btnClose + htmlResponse + '
';
};

notifications.sendToMeteor = function (type) {
    ajax.genericAction('notification_setfake', {'type': type},
        function(response){}
    );
};

notifications.test = function(id, parent) {
    var r = {}; r.id = id; r.p = parent;
    notifications.handleNewNotification(r);
};

$(document).ready(function() {
    notifications.init();
});<|endoftext|>


<commit_before>import React from 'react'
import PropTypes from 'prop-types'
import { withStyles } from '@material-ui/core/styles'
import Typography from '@material-ui/core/Typography'
import RaisedButton from 'material-ui/RaisedButton'
import Divider from '@material-ui/core/Divider'
import HeartBorderIcon from 'material-ui/svg-icons/action/favorite-border'
import { dividerColor, dashboardIconActiveColor } from 'js/theme/default'
import DashboardPopover from 'js/components/Dashboard/DashboardPopover'
import { goToInviteFriends, goToDonate } from 'js/navigation/navigation'

// TODO: break out to make the component customizable:
// https://material-ui.com/customization/overrides/#3-specific-variation-of-a-component
const styles = {
  typographyRoot: {
    color: 'white',
  },
  dividerRoot: {
    backgroundColor: 'rgba(255, 255, 255, 0.20)',
  },
}

const HeartsDropdownComponent = props => {
  const { anchorElement, app, classes, onClose, open, user } = props
  const sectionStyle = {
    paddingTop: 12,
    paddingBottom: 20,
  }
  const popoverButtonStyle = {
    marginTop: 6,
    marginBottom: 0,
  }
  const popoverButtonLabelStyle = {
    fontSize: 13,
  }

  return (
    <DashboardPopover open={open} anchorEl={anchorElement} onClose={onClose}>

          <Typography
            classes={{
              root: classes.typographyRoot,
            }}
            variant={'h5'}
            color={'primary'}
          >
            Level {user.level}
          </Typography>

            <Typography
              classes={{
                root: classes.typographyRoot,
              }}
              variant={'body2'}
            >
              {user.heartsUntilNextLevel}
            </Typography>
            <HeartBorderIcon
              style={{
                height: 16, // TODO: use body2 font size
              }}
              color={dashboardIconActiveColor}
            />
            <Typography
              classes={{
                root: classes.typographyRoot,
              }}
              variant={'body2'}
            >
              {' '}
              until next level
            </Typography>

        <Divider classes={{ root: classes.dividerRoot }} />

              <Typography
                classes={{
                  root: classes.typographyRoot,
                }}
                variant={'h5'}
              >
                {user.vcDonatedAllTime}
              </Typography>
              <HeartBorderIcon
                style={{
                  marginLeft: 2,
                  height: 24,
                  width: 24,
                  paddingBottom: 1,
                }}
                color={dashboardIconActiveColor}
              />

            <Typography
              classes={{
                root: classes.typographyRoot,
              }}
              variant={'body2'}
            >
              donated
            </Typography>

            <RaisedButton
              label="Donate Hearts"
              style={popoverButtonStyle}
              labelStyle={popoverButtonLabelStyle}
              primary
              onClick={goToDonate}
            />

        <Divider classes={{ root: classes.dividerRoot }} />

            <Typography
              classes={{
                root: classes.typographyRoot,
              }}
              variant={'h5'}
            >
              {user.numUsersRecruited}
            </Typography>
            <Typography
              classes={{
                root: classes.typographyRoot,
              }}
              variant={'body2'}
            >
              Tabbers Recruited
            </Typography>

            <RaisedButton
              label="Invite A Friend"
              labelPosition="before"
              style={popoverButtonStyle}
              labelStyle={popoverButtonLabelStyle}
              primary
              onClick={goToInviteFriends}
            />

        <Divider classes={{ root: classes.dividerRoot }} />

            <Typography
              classes={{
                root: classes.typographyRoot,
              }}
              variant={'body2'}
              style={{
                flex: 6,
              }}
            >
              Open a tab
            </Typography>

              <Typography
                classes={{
                  root: classes.typographyRoot,
                }}
                variant={'body2'}
                style={{ textAlign: 'right' }}
              >
                1
              </Typography>
              <HeartBorderIcon
                style={{
                  height: 16,
                }}
                color={dividerColor}
              />

            <Typography
              classes={{
                root: classes.typographyRoot,
              }}
              variant={'body2'}
              style={{
                flex: 6,
              }}
            >
              Recruit a friend
            </Typography>

              <Typography
                classes={{
                  root: classes.typographyRoot,
                }}
                variant={'body2'}
                style={{ textAlign: 'right' }}
              >
                {app.referralVcReward}
              </Typography>
              <HeartBorderIcon
                style={{
                  height: 16,
                }}
                color={dividerColor}
              />

    </DashboardPopover>
  )
}

HeartsDropdownComponent.displayNamae = 'HeartsDropdownComponent'

HeartsDropdownComponent.propTypes = {
  anchorElement: PropTypes.oneOfType([PropTypes.object, PropTypes.func]),
  app: PropTypes.shape({
    referralVcReward: PropTypes.number.isRequired,
  }),
  classes: PropTypes.object.isRequired,
  user: PropTypes.shape({
    vcCurrent: PropTypes.number.isRequired,
    level: PropTypes.number.isRequired,
    heartsUntilNextLevel: PropTypes.number.isRequired,
    vcDonatedAllTime: PropTypes.number.isRequired,
    numUsersRecruited: PropTypes.number.isRequired,
    tabsToday: PropTypes.number.isRequired,
  }),
  onClose: PropTypes.func.isRequired,
  open: PropTypes.bool.isRequired,
}

HeartsDropdownComponent.defaultProps = {
  open: false,
}

export default withStyles(styles)(HeartsDropdownComponent)
<commit_msg>Use latest MUI button<commit_after>import React from 'react'
import PropTypes from 'prop-types'
import { withStyles } from '@material-ui/core/styles'
import Typography from '@material-ui/core/Typography'
import Button from '@material-ui/core/Button'
import Divider from '@material-ui/core/Divider'
import HeartBorderIcon from 'material-ui/svg-icons/action/favorite-border'
import { dividerColor, dashboardIconActiveColor } from 'js/theme/default'
import DashboardPopover from 'js/components/Dashboard/DashboardPopover'
import { goToInviteFriends, goToDonate } from 'js/navigation/navigation'

// TODO: break out to make the component customizable:
// https://material-ui.com/customization/overrides/#3-specific-variation-of-a-component
const styles = {
  typographyRoot: {
    color: 'white',
  },
  dividerRoot: {
    backgroundColor: 'rgba(255, 255, 255, 0.20)',
  },
}

const HeartsDropdownComponent = props => {
  const { anchorElement, app, classes, onClose, open, user } = props
  const sectionStyle = {
    paddingTop: 12,
    paddingBottom: 20,
  }
  const buttonStyle = {
    marginTop: 8,
    marginBottom: 0,
  }
  return (
    <DashboardPopover open={open} anchorEl={anchorElement} onClose={onClose}>

          <Typography
            classes={{
              root: classes.typographyRoot,
            }}
            variant={'h5'}
            color={'primary'}
          >
            Level {user.level}
          </Typography>

            <Typography
              classes={{
                root: classes.typographyRoot,
              }}
              variant={'body2'}
            >
              {user.heartsUntilNextLevel}
            </Typography>
            <HeartBorderIcon
              style={{
                height: 16, // TODO: use body2 font size
              }}
              color={dashboardIconActiveColor}
            />
            <Typography
              classes={{
                root: classes.typographyRoot,
              }}
              variant={'body2'}
            >
              {' '}
              until next level
            </Typography>

        <Divider classes={{ root: classes.dividerRoot }} />

              <Typography
                classes={{
                  root: classes.typographyRoot,
                }}
                variant={'h5'}
              >
                {user.vcDonatedAllTime}
              </Typography>
              <HeartBorderIcon
                style={{
                  marginLeft: 2,
                  height: 24,
                  width: 24,
                  paddingBottom: 1,
                }}
                color={dashboardIconActiveColor}
              />

            <Typography
              classes={{
                root: classes.typographyRoot,
              }}
              variant={'body2'}
            >
              donated
            </Typography>

            <Button
              variant={'contained'}
              color={'primary'}
              style={buttonStyle}
              onClick={goToDonate}
            >
              Donate Hearts
            </Button>

        <Divider classes={{ root: classes.dividerRoot }} />

            <Typography
              classes={{
                root: classes.typographyRoot,
              }}
              variant={'h5'}
            >
              {user.numUsersRecruited}
            </Typography>
            <Typography
              classes={{
                root: classes.typographyRoot,
              }}
              variant={'body2'}
            >
              Tabbers recruited
            </Typography>

            <Button
              variant={'contained'}
              color={'primary'}
              style={buttonStyle}
              onClick={goToInviteFriends}
            >
              Invite A Friend
            </Button>

        <Divider classes={{ root: classes.dividerRoot }} />

            <Typography
              classes={{
                root: classes.typographyRoot,
              }}
              variant={'body2'}
              style={{
                flex: 6,
              }}
            >
              Open a tab
            </Typography>

              <Typography
                classes={{
                  root: classes.typographyRoot,
                }}
                variant={'body2'}
                style={{ textAlign: 'right' }}
              >
                1
              </Typography>
              <HeartBorderIcon
                style={{
                  height: 16,
                }}
                color={dividerColor}
              />

            <Typography
              classes={{
                root: classes.typographyRoot,
              }}
              variant={'body2'}
              style={{
                flex: 6,
              }}
            >
              Recruit a friend
            </Typography>

              <Typography
                classes={{
                  root: classes.typographyRoot,
                }}
                variant={'body2'}
                style={{ textAlign: 'right' }}
              >
                {app.referralVcReward}
              </Typography>
              <HeartBorderIcon
                style={{
                  height: 16,
                }}
                color={dividerColor}
              />

    </DashboardPopover>
  )
}

HeartsDropdownComponent.displayNamae = 'HeartsDropdownComponent'

HeartsDropdownComponent.propTypes = {
  anchorElement: PropTypes.oneOfType([PropTypes.object, PropTypes.func]),
  app: PropTypes.shape({
    referralVcReward: PropTypes.number.isRequired,
  }),
  classes: PropTypes.object.isRequired,
  user: PropTypes.shape({
    vcCurrent: PropTypes.number.isRequired,
    level: PropTypes.number.isRequired,
    heartsUntilNextLevel: PropTypes.number.isRequired,
    vcDonatedAllTime: PropTypes.number.isRequired,
    numUsersRecruited: PropTypes.number.isRequired,
    tabsToday: PropTypes.number.isRequired,
  }),
  onClose: PropTypes.func.isRequired,
  open: PropTypes.bool.isRequired,
}

HeartsDropdownComponent.defaultProps = {
  open: false,
}

export default withStyles(styles)(HeartsDropdownComponent)
<|endoftext|>


<commit_before>/*global define, requestAnimationFrame*/
define(
	[ 'src/glitch', 'util/canvas', 'lib/raf' ],
	function( glitch, canvas_helper )
	{
		var tmp_canvas = document.createElement( 'canvas' );
		var tmp_ctx = tmp_canvas.getContext( '2d' );

		var canvas = document.getElementById( 'canvas' );
		var ctx = canvas.getContext( '2d' );

		var is_processing = false;
		var values;
		var image;
		var signals;
		var image_data;
		var canvas_size;

		function init( shared )
		{
			signals = shared.signals;

			signals['image-loaded'].add( generate );
			signals['control-updated'].add( controlsUpdated );
			signals['saved'].add( exportData );
		}

		function controlsUpdated( new_values )
		{
			values = getAdjustedValues( new_values );

			update();
		}

		function generate( img )
		{
			if ( ! is_processing )
			{
				image = img;
				processImage( image );
			}
		}

		function requestTick()
		{
			if ( ! is_processing )
			{
				requestAnimationFrame( update );
			}

			is_processing = true;
		}

		function update()
		{
			if ( image )
			{
				processImage( image );
			}

			else
			{
				is_processing = false;
			}
		}

		function processImage( img )
		{
			is_processing = true;

			canvas_helper.clear( tmp_canvas, tmp_ctx );
			canvas_helper.clear( canvas, ctx );
			canvas_helper.resize( tmp_canvas, img );
			canvas_helper.resize( canvas, img );

			tmp_ctx.drawImage( img, 0, 0 );

			image_data = tmp_ctx.getImageData( 0, 0, tmp_canvas.width, tmp_canvas.height );

			glitch( image_data, values, draw );
		}

		function draw( image_data )
		{
			canvas_helper.resize( canvas, image_data );
			ctx.putImageData( image_data, 0, 0 );

			is_processing = false;
			image_data = null;
		}

		function exportData()
		{
			signals['export-png'].dispatch( canvas.toDataURL( 'image/png' ) );
		}

		function getAdjustedValues( new_values )
		{
			var result = { };

			for ( var key in new_values )
			{
				result[key] = parseInt( new_values[key], 10 );
			}

			key = null;

			return result;
		}

		return { init: init };
	}
);<commit_msg>small speed improvements<commit_after>/*global define, requestAnimationFrame*/
define(
	[ 'src/glitch', 'util/canvas', 'lib/raf' ],
	function( glitch, canvas_helper )
	{
		var tmp_canvas = document.createElement( 'canvas' );
		var tmp_ctx = tmp_canvas.getContext( '2d' );

		var canvas = document.getElementById( 'canvas' );
		var ctx = canvas.getContext( '2d' );

		var is_processing = false;
		var values;
		var image;
		var signals;
		var image_data;
		var canvas_size;

		function init( shared )
		{
			signals = shared.signals;

			signals['image-loaded'].add( generate );
			signals['control-updated'].add( controlsUpdated );
			signals['saved'].add( exportData );
		}

		function controlsUpdated( new_values )
		{
			values = getAdjustedValues( new_values );

			update();
		}

		function generate( img )
		{
			if ( ! is_processing )
			{
				image = img;
				resetCanvas( image );
				updateImageData( image );
				processImage( image );
			}
		}

		function requestTick()
		{
			if ( ! is_processing )
			{
				requestAnimationFrame( update );
			}

			is_processing = true;
		}

		function update()
		{
			if ( image )
			{
				processImage( image );
			}

			else
			{
				is_processing = false;
			}
		}

		function updateImageData( img )
		{
			tmp_ctx.drawImage( img, 0, 0 );

			image_data = tmp_ctx.getImageData( 0, 0, tmp_canvas.width, tmp_canvas.height );
		}

		function resetCanvas( img )
		{
			canvas_helper.clear( tmp_canvas, tmp_ctx );
			canvas_helper.resize( tmp_canvas, img );
			canvas_helper.clear( canvas, ctx );
			canvas_helper.resize( canvas, img );
		}

		function processImage( img )
		{
			is_processing = true;

			glitch( image_data, values, draw );
		}

		function draw( glitched_image_data )
		{
			ctx.putImageData( glitched_image_data, 0, 0 );

			is_processing = false;
			glitched_image_data = null;
		}

		function exportData()
		{
			signals['export-png'].dispatch( canvas.toDataURL( 'image/png' ) );
		}

		function getAdjustedValues( new_values )
		{
			var result = { };

			for ( var key in new_values )
			{
				result[key] = parseInt( new_values[key], 10 );
			}

			key = null;

			return result;
		}

		return { init: init };
	}
);<|endoftext|>


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

var config = {};

//set defaults
config.clientId = '2574228432.104777884963';
config.port = 3004;
config.axosoftClientId = '4b62de06-1f39-41f7-ae38-37ec5262478a'

var prefix = process.env.BUILD_LIFECYCLE;

if (prefix == 'production') {
    prefix = '';
}

config.redirectUri = prefix + 'slackbot.axosoft.com:3004';
config.mongoUri = 'mongodb://' + prefix + 'slackbot.axosoft.com:27017/slackData'

// test for process.env
console.log(process.env);

if (process.env.AXO_slackbot_secret && process.env.AXO_slackbot_axosoft_secret) {
console.log('updating config file...')
    config.clientSecret = process.env.AXO_slackbot_secret;
    config.axosoftClientSecret = process.env.AXO_slackbot_axosoft_secret;
}

// write to file
console.log(config);
fs.writeFileSync('./config.json', JSON.stringify(config));<commit_msg>Removing logging of secrets<commit_after>var fs = require('fs')

var config = {};

//set defaults
config.clientId = '2574228432.104777884963';
config.port = 3004;
config.axosoftClientId = '4b62de06-1f39-41f7-ae38-37ec5262478a'

var prefix = process.env.BUILD_LIFECYCLE;

if (prefix == 'production') {
    prefix = '';
}

config.redirectUri = prefix + 'slackbot.axosoft.com:3004';
config.mongoUri = 'mongodb://' + prefix + 'slackbot.axosoft.com:27017/slackData'

if (process.env.AXO_slackbot_secret && process.env.AXO_slackbot_axosoft_secret) {
console.log('updating config file...')
    config.clientSecret = process.env.AXO_slackbot_secret;
    config.axosoftClientSecret = process.env.AXO_slackbot_axosoft_secret;
}

// write to file
// Don't want to write secrets to the log file...
//console.log(config);
fs.writeFileSync('./config.json', JSON.stringify(config));<|endoftext|>


<commit_before>/*
 *  [2015] - [2016] Codenvy, S.A.
 *  All Rights Reserved.
 *
 * NOTICE:  All information contained herein is, and remains
 * the property of Codenvy S.A. and its suppliers,
 * if any.  The intellectual and technical concepts contained
 * herein are proprietary to Codenvy S.A.
 * and its suppliers and may be covered by U.S. and Foreign Patents,
 * patents in process, and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material
 * is strictly forbidden unless prior written permission is obtained
 * from Codenvy S.A..
 */
'use strict';

export class CodenvyNavBarCtrl {

  /**
   * Default constructor
   * @ngInject for Dependency injection
   */
  constructor($mdSidenav, $scope, $location, $route, userDashboardConfig, cheAPI, codenvyAPI, imsArtifactApi, $rootScope, $http, $window, $cookies, $resource) {
    this.mdSidenav = $mdSidenav;
    this.$scope = $scope;
    this.$location = $location;
    this.$route = $route;
    this.cheAPI = cheAPI;
    this.codenvyAPI = codenvyAPI;
    this.imsArtifactApi = imsArtifactApi;
    this.codenvyUser = codenvyAPI.getUser();
    this.codenvyPermissions = codenvyAPI.getPermissions();
    this.links = [{href: '#/create-workspace', name: 'New Workspace'}];
    this.$rootScope = $rootScope;
    this.$window = $window;
    this.$resource = $resource;
    this.$cookies = $cookies;
    this.logoutAPI = this.$resource('/api/auth/logout', {});

    this.userServices = this.codenvyPermissions.getUserServices();
    if(!this.codenvyPermissions.getSystemPermissions()) {
      this.codenvyPermissions.fetchSystemPermissions();
    }

    this.displayLoginItem = userDashboardConfig.developmentMode;
    let promiseService = this.cheAPI.getService().fetchServices();
    promiseService.then(() => {
      this.isFactoryServiceAvailable = cheAPI.getService().isServiceAvailable(codenvyAPI.getFactory().getFactoryServicePath());
    });

    let promiseAdminService = this.cheAPI.getAdminService().fetchServices();
    promiseAdminService.then(() => {
      this.isAdminServiceAvailable = cheAPI.getAdminService().isAdminServiceAvailable();
      this.isAdminPluginServiceAvailable = cheAPI.getAdminService().isServiceAvailable(cheAPI.getAdminPlugins().getPluginsServicePath());
    });

    this.profile = cheAPI.getProfile().getProfile();
    if (this.profile.attributes) {
      this.email = this.profile.attributes.email;
    } else {
      this.profile.$promise.then(() => {
        this.email = this.profile.attributes.email ? this.profile.attributes.email : 'N/A ';
      }, () => {
        this.email = 'N/A ';
      });
    }
    this.onpremAdminExpanded = true;

    this.menuItemUrl = {
      login: '#/login',
      dashboard: '#/',
      projects: '#/projects',
      workspaces: '#/workspaces',
      factories: '#/factories',
      administration: '#/onprem/administration',
      usermanagement: '#/admin/usermanagement',

      // subsection
      plugins: '#/admin/plugins'
    };

    // highlight navbar menu item
    $scope.$on('$locationChangeStart', () => {
      let path = '#' + $location.path();
      $scope.$broadcast('navbar-selected:set', path);
    });

    // update branding
    let assetPrefix = 'assets/branding/';
    $http.get(assetPrefix + 'product.json').then((data) => {
      if (data.data.navbarButton) {
        this.$rootScope.branding.navbarButton = {
          title: data.data.navbarButton.title,
          tooltip: data.data.navbarButton.tooltip,
          link: data.data.navbarButton.link
        };
        this.accountItems.splice(2, 0, {
          name: data.data.navbarButton.title,
          url: data.data.navbarButton.link
        });
      }
    });

    cheAPI.cheWorkspace.fetchWorkspaces();

    // account dropdown items
    this.accountItems = [
      {
        name: 'Profile & Account',
        url: '#/account'
      }, {
        name: 'Administration',
        url: '#/administration'
      }, {
        name: 'Logout',
        onclick: () => {
          this.logout();
        }
      }
    ];
  }

  reload() {
    this.$route.reload();
  }

  /**
   * Toggle the left menu
   */
  toggleLeftMenu() {
    this.mdSidenav('left').toggle();
  }

  getWorkspacesNumber() {
    return this.cheAPI.cheWorkspace.getWorkspaces().length;
  }

  getProjectsNumber() {
    return this.cheAPI.cheWorkspace.getAllProjects().length;
  }

  getFactoriesNumber() {
    return this.codenvyAPI.codenvyFactory.getFactories().length;
  }

  openLinkInNewTab(url) {
    this.$window.open(url, '_blank');
  }

  /**
   * Logout current user
   */
  logout() {
    let data = {token: this.$cookies['session-access-key']};
    let promise = this.logoutAPI.save(data).$promise;
    promise.then(() => {
      this.$rootScope.showIDE = false;
      this.$window.location.href = this.menuItemUrl.login;
    });
  }
}
<commit_msg>Fix redirect to site login page on logout<commit_after>/*
 *  [2015] - [2016] Codenvy, S.A.
 *  All Rights Reserved.
 *
 * NOTICE:  All information contained herein is, and remains
 * the property of Codenvy S.A. and its suppliers,
 * if any.  The intellectual and technical concepts contained
 * herein are proprietary to Codenvy S.A.
 * and its suppliers and may be covered by U.S. and Foreign Patents,
 * patents in process, and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material
 * is strictly forbidden unless prior written permission is obtained
 * from Codenvy S.A..
 */
'use strict';

export class CodenvyNavBarCtrl {

  /**
   * Default constructor
   * @ngInject for Dependency injection
   */
  constructor($mdSidenav, $scope, $location, $route, userDashboardConfig, cheAPI, codenvyAPI, imsArtifactApi, $rootScope, $http, $window, $cookies, $resource) {
    this.mdSidenav = $mdSidenav;
    this.$scope = $scope;
    this.$location = $location;
    this.$route = $route;
    this.cheAPI = cheAPI;
    this.codenvyAPI = codenvyAPI;
    this.imsArtifactApi = imsArtifactApi;
    this.codenvyUser = codenvyAPI.getUser();
    this.codenvyPermissions = codenvyAPI.getPermissions();
    this.links = [{href: '#/create-workspace', name: 'New Workspace'}];
    this.$rootScope = $rootScope;
    this.$window = $window;
    this.$resource = $resource;
    this.$cookies = $cookies;
    this.logoutAPI = this.$resource('/api/auth/logout', {});

    this.userServices = this.codenvyPermissions.getUserServices();
    if(!this.codenvyPermissions.getSystemPermissions()) {
      this.codenvyPermissions.fetchSystemPermissions();
    }

    this.displayLoginItem = userDashboardConfig.developmentMode;
    let promiseService = this.cheAPI.getService().fetchServices();
    promiseService.then(() => {
      this.isFactoryServiceAvailable = cheAPI.getService().isServiceAvailable(codenvyAPI.getFactory().getFactoryServicePath());
    });

    let promiseAdminService = this.cheAPI.getAdminService().fetchServices();
    promiseAdminService.then(() => {
      this.isAdminServiceAvailable = cheAPI.getAdminService().isAdminServiceAvailable();
      this.isAdminPluginServiceAvailable = cheAPI.getAdminService().isServiceAvailable(cheAPI.getAdminPlugins().getPluginsServicePath());
    });

    this.profile = cheAPI.getProfile().getProfile();
    if (this.profile.attributes) {
      this.email = this.profile.attributes.email;
    } else {
      this.profile.$promise.then(() => {
        this.email = this.profile.attributes.email ? this.profile.attributes.email : 'N/A ';
      }, () => {
        this.email = 'N/A ';
      });
    }
    this.onpremAdminExpanded = true;

    this.menuItemUrl = {
      login: '/site/login',
      dashboard: '#/',
      projects: '#/projects',
      workspaces: '#/workspaces',
      factories: '#/factories',
      administration: '#/onprem/administration',
      usermanagement: '#/admin/usermanagement',

      // subsection
      plugins: '#/admin/plugins'
    };

    // highlight navbar menu item
    $scope.$on('$locationChangeStart', () => {
      let path = '#' + $location.path();
      $scope.$broadcast('navbar-selected:set', path);
    });

    // update branding
    let assetPrefix = 'assets/branding/';
    $http.get(assetPrefix + 'product.json').then((data) => {
      if (data.data.navbarButton) {
        this.$rootScope.branding.navbarButton = {
          title: data.data.navbarButton.title,
          tooltip: data.data.navbarButton.tooltip,
          link: data.data.navbarButton.link
        };
        this.accountItems.splice(2, 0, {
          name: data.data.navbarButton.title,
          url: data.data.navbarButton.link
        });
      }
    });

    cheAPI.cheWorkspace.fetchWorkspaces();

    // account dropdown items
    this.accountItems = [
      {
        name: 'Profile & Account',
        url: '#/account'
      }, {
        name: 'Administration',
        url: '#/administration'
      }, {
        name: 'Logout',
        onclick: () => {
          this.logout();
        }
      }
    ];
  }

  reload() {
    this.$route.reload();
  }

  /**
   * Toggle the left menu
   */
  toggleLeftMenu() {
    this.mdSidenav('left').toggle();
  }

  getWorkspacesNumber() {
    return this.cheAPI.cheWorkspace.getWorkspaces().length;
  }

  getProjectsNumber() {
    return this.cheAPI.cheWorkspace.getAllProjects().length;
  }

  getFactoriesNumber() {
    return this.codenvyAPI.codenvyFactory.getFactories().length;
  }

  openLinkInNewTab(url) {
    this.$window.open(url, '_blank');
  }

  /**
   * Logout current user
   */
  logout() {
    let data = {token: this.$cookies['session-access-key']};
    let promise = this.logoutAPI.save(data).$promise;
    promise.then(() => {
      this.$rootScope.showIDE = false;
      this.$window.location.href = this.menuItemUrl.login;
    });
  }
}
<|endoftext|>


<commit_before>window.Class = (function(){
	"use strict";

	var BaseClass = function(){
		var self = {};
		self.__init__ = function(){};
		return self;
	};

	var MRO = function(){
		var classes = [].slice.apply(arguments),
			seqs = [],
			res = [];
		for (var i = 0; i < classes.length; i++) {
			seqs.push(classes[i].isClass?classes[i].__mro__.slice():[]);
		}
		seqs.push(classes);
		while (1) {
			var non_empty = seqs.filter(function(x){return x&&[].slice.apply(x).length});
			if (!non_empty.length)
				return res;
			for (var i = 0; i < non_empty.length; i++) {
				var seq = non_empty[i],
					candidate = seq[0],
					not_head = false;
				// Check to see if the candidate is later in another sequence
				for (var j = 0; j < non_empty.length; j++) {
					if (non_empty[j].slice(1).indexOf(candidate) > -1) {
						not_head = true;
						break;
					}
				}
				if (not_head)  // Invalid candidate
					candidate = null;
				else
					break;
			}
			if (!candidate) {
				throw TypeError('Inconsistent MRO');
			}
			res.push(candidate);
			// Remove candidate from sequences
			for (var i = 0; i < non_empty.length; i++) {
				if (non_empty[i][0] == candidate) {
					non_empty[i].shift();
				}
			}
		}
	};

	var Class = function(){
		var classes = [].slice.apply(arguments),
			constructor = classes.pop(),
			mro = [];
		var init = function(){
			var object = {},
				classList = init.__mro__.slice();
			// Add a helper function to call this class's constructor
			classList.push(function(){
				constructor(object);
			});
			for (var i = 0; i < classList.length; i++) {
				var instance = classList[i].apply(this, arguments);
				for (var k in instance) {
					if (!(k in {})) {
						object[k] = instance[k];
					}
				}
			}
			if ('__init__' in object && 'apply' in object.__init__)
				object.__init__.apply(this, arguments);
			return object;
		};
		init.__mro__ = MRO.apply(this, classes);
		init.isClass = true;
		return init;
	};

	Class.BaseClass = BaseClass;
	Class.MRO = MRO;

	return Class;
})();
<commit_msg>Better initialization error checking<commit_after>window.Class = (function(){
	"use strict";

	var BaseClass = function(){
		var self = {};
		self.__init__ = function(){};
		return self;
	};

	var MRO = function(){
		var classes = [].slice.apply(arguments),
			seqs = [],
			res = [];
		for (var i = 0; i < classes.length; i++) {
			seqs.push(classes[i].isClass?classes[i].__mro__.slice():[]);
		}
		seqs.push(classes);
		while (1) {
			var non_empty = seqs.filter(function(x){return x&&[].slice.apply(x).length});
			if (!non_empty.length)
				return res;
			for (var i = 0; i < non_empty.length; i++) {
				var seq = non_empty[i],
					candidate = seq[0],
					not_head = false;
				// Check to see if the candidate is later in another sequence
				for (var j = 0; j < non_empty.length; j++) {
					if (non_empty[j].slice(1).indexOf(candidate) > -1) {
						not_head = true;
						break;
					}
				}
				if (not_head)  // Invalid candidate
					candidate = null;
				else
					break;
			}
			if (!candidate) {
				throw TypeError('Inconsistent MRO');
			}
			res.push(candidate);
			// Remove candidate from sequences
			for (var i = 0; i < non_empty.length; i++) {
				if (non_empty[i][0] == candidate) {
					non_empty[i].shift();
				}
			}
		}
	};

	var Class = function(){
		var classes = [].slice.apply(arguments),
			constructor = classes.pop(),
			mro = [];
		if (!(!!constructor && 'call' in constructor)) {
			throw TypeError('Invalid constructor.');
		}
		for (var c in classes) {
			var cls = classes[c];
			if (!(c in []) && !(cls && cls.isClass && 'apply' in cls && '__mro__' in cls)) {
				throw TypeError('Parent class is not a valid class.');
			}
		}
		var init = function(){
			var object = {},
				classList = init.__mro__.slice();
			// Add a helper function to call this class's constructor
			classList.push(function(){
				constructor(object);
			});
			for (var i = 0; i < classList.length; i++) {
				var instance = classList[i].apply(this, arguments);
				for (var k in instance) {
					if (!(k in {})) {
						object[k] = instance[k];
					}
				}
			}
			if ('__init__' in object && 'apply' in object.__init__)
				object.__init__.apply(this, arguments);
			return object;
		};
		init.__mro__ = MRO.apply(this, classes);
		init.isClass = true;
		return init;
	};

	Class.BaseClass = BaseClass;
	Class.MRO = MRO;

	return Class;
})();
<|endoftext|>


<commit_before>// for scrolltotop arrow

$(window).scroll(function() {
  if ($(this).scrollTop() >= $("#top-c").height()) {
    $('#return-to-top').fadeIn(200);    // Fade in the arrow
  } else {
    $('#return-to-top').fadeOut(200);   // Else fade out the arrow
  }
});

$('#return-to-top').click(function() {      // When arrow is clicked
    $('body,html').animate({
        scrollTop : $("#top-c").scrollTop() - $(".legalese-nav").height()// Scroll to top of body
    }, 500);
});

// insert copyright date

let currentYear = `2017 \u2014 ${(new Date()).getFullYear()}`
$("#copyright-date").text(currentYear);

// show various bits of players navbar

$(".sidebar-header").each(function() {
    $(this).click(function() {
	var id = ".sub-" + $(this).attr("href").slice(1);
	$(".left-menu-sub").hide();
	$(id).show();
    });
});

// don't know why I can't just add a css class here

$('.left-menu-item').on('click', function() {
  $('.left-menu-item').css({ "font-weight": "300", "text-decoration": "none" });
  $(this).css({ "font-weight": "700", "text-decoration": "none" });
});

$('.left-menu-item').hover(
  function() {
    $(this).css({ "font-weight": "700", "text-decoration": "none", "color": "#333333" });
  }, function() {
    $(this).css({ "font-weight": "300", "text-decoration": "none" });
  }
);

$(window).on('scroll', function() {
  $('.lower-nav-el').each(function() {
    if($(window).scrollTop() > ($(this).offset().top - 10)) {
      var id = $(this).attr('id');
      $('.left-menu-item').css('font-weight','300');
      $('a[href="#'+ id +'"]').css('font-weight','700');
    }
  });
});

// only affix sidebar if not on mobile

if ($(window).width() > 768) {
  $(".player-nav").affix({
    offset: {
      top: function() {
	return (this.top = $("#blurb-nav-id").offset().top + 65)
      }
    }
  })
}

$(window).resize(function() {
  if ($(window).width() > 767) {
    $("#magic-shift-toggle-bottom").hide();
    $("#magic-shift-toggle").show()
  } else {
    $("#magic-shift-toggle").hide();
    $("#magic-shift-toggle-bottom").show()
  }
})

if ($(window).width() > 767) {
  $("#magic-shift-toggle-bottom").hide();
  $("#magic-shift-toggle").show()
} else {
  $("#magic-shift-toggle").hide();
  $("#magic-shift-toggle-bottom").show()
}

// downarrow click

$(".downarrow").click(function() {
  $('html, body').animate({
    scrollTop: $("#top-c").height() - $(".legalese-nav").height()
  }, 500);
});

// fix top button to above bot-container when scrolling

$(window).scroll(function() {
  var bottomHeight = $(".bot-container").height()
  if ($(window).scrollTop() + $(window).height() >= $(".bot-container").offset().top) {
    $("#return-to-top").css({
      "bottom": bottomHeight + 30
    });
    $("#return-to-top-text").css({
      "bottom": bottomHeight + 2
    });
  } else {
    $("#return-to-top").css({
      "bottom": "20px"
    });
    $("#return-to-top-text").css({
      "bottom": "-8px"
    });
  }
})

// fix bar to bottom for large screens

if ($('body').outerHeight() < $(window).height()) {
  $(".bot-container").addClass("bot-container-fixed")
} else {
  $(".bot-container").removeClass("bot-container-fixed")
}

// set pricetags

function monthly(price, which) {
  if (which) {
    return price
  } else {
    return (price / 0.7).toFixed(2)
  }
}

accounting.settings = {
  currency: {
    symbol : "$",   // default currency symbol is '$'
    format: "%v", // controls output: %s = symbol, %v = value/number (can be object: see below)
    decimal : ".",  // decimal point separator
    thousand: ",",  // thousands separator
    precision : 0   // decimal places
  },
  number: {
    precision : 0,  // default precision on numbers is 0
    thousand: ",",
    decimal : "."
  }
}

function headers(price, which) {
  if (which) {
    return price
  } else {
    return accounting.formatMoney(price*0.7)
  }
}

let which = false

const prices = {
  pro: {
    header: 2000,
    substandard: 1.74,
    subcomplex: 2.34,
  },
  plus: {
    header: 25,
    substandard: 1.74,
    subcomplex: 2.34,
  },
  basic: {
    header: 15,
    substandard: 2.32,
    subcomplex: 3.12,
  },
}

$('#price-toggle').change(function() {
  $('#subheader-pro').hide().html(`$${headers(prices.pro.header, which)}`).fadeIn(500)
  $('#subheader-plus').hide().html(`$${headers(prices.plus.header, which)}`).fadeIn(500)
  $('#subheader-basic').hide().html(`$${headers(prices.basic.header, which)}`).fadeIn(500)
  $('#substandard-pro').hide().html(`$${monthly(prices.pro.substandard, which)}`).fadeIn(500)
  $('#substandard-plus').hide().html(`$${monthly(prices.plus.substandard, which)}`).fadeIn(500)
  $('#substandard-basic').hide().html(`$${monthly(prices.basic.substandard, which)}`).fadeIn(500)
  $('#subcomplex-pro').hide().html(`$${monthly(prices.pro.subcomplex, which)}`).fadeIn(500)
  $('#subcomplex-plus').hide().html(`$${monthly(prices.plus.subcomplex, which)}`).fadeIn(500)
  $('#subcomplex-basic').hide().html(`$${monthly(prices.basic.subcomplex, which)}`).fadeIn(500)
  which = !which
})

$(function () {
  $('[data-toggle="popover"]').popover()
})

// show or hide relevant fields based on radio selection

$(function() {
  const emailRadio = $('#comms-email-radio')
  const phoneRadio = $('#comms-phone-radio')
  const eitherRadio = $('#comms-either-radio')

  const emailField = $('#commsEmail')
  const phoneField = $('#commsPhone')

  const weekdayRadio = $('#weekdays-radio')
  const everydayRadio = $('#everyday-radio')

  const weekdayGroup = $('#weekdaysGroup')
  const everydayGroup = $('#everydayGroup')

  emailRadio.change(function() {
    if (emailRadio.prop('checked', true)) {
      emailField.show()
      phoneField.hide()
    } else {
      emailField.hide()
    }
  })

  phoneRadio.change(function() {
    if (phoneRadio.prop('checked', true)) {
      phoneField.show()
      emailField.hide()
    } else {
      phoneField.hide()
    }
  })

  eitherRadio.change(function() {
    if (eitherRadio.prop('checked', true)) {
      emailField.show()
      phoneField.show()
    } else {
      emailField.hide()
      phoneField.hide()
    }
  })

  weekdayRadio.change(function() {
    if (weekdayRadio.prop('checked', true)) {
      weekdayGroup.show()
      everydayGroup.hide()
    } else {
      weekdayGroup.show()
      everydayGroup.hide()
    }
  })

  everydayRadio.change(function() {
    if (everydayRadio.prop('checked', true)) {
      everydayGroup.show()
      weekdayGroup.hide()
    } else {
      everydayGroup.show()
      weekdayGroup.hide()
    }
  })

})

function sendData() {

  $('#formModal').modal('toggle')
  $('#congratsModal').modal('toggle')
  var XHR = new XMLHttpRequest();

  // Bind the FormData object and the form element
  const form = document.getElementById('interestForm')
  var FD = new FormData(form);

  // Define what happens on successful data submission
  XHR.addEventListener("load", function(event) {
    console.log(event.target.responseText);
  });

  // Define what happens in case of error
  XHR.addEventListener("error", function(event) {
    console.log('Oops! Something went wrong.');
  });

  // Set up our request
  XHR.open("POST", "http://localhost/api/email/signup");

  // The data sent is what the user provided in the form
  XHR.send(FD);
}

var c = document.getElementById('celebration-canvas');
var ctx = c.getContext('2d');

var particles = [];

let startingX = c.width / 2
let startingY = c.height / 2

document.getElementById('contrastButtonCelebration').addEventListener('mouseover', function(e){
  startingX = Math.random() * 400
  startingY = Math.random() * 60
  createParticles();
});

setTimeout(function(){
  createParticles();
}, 250);

draw();

function draw(){

  drawBg();
  incParticles();
  drawParticles();
  window.requestAnimationFrame(draw);

}

function drawBg(){
  ctx.rect(0, 0, c.width, c.height);
  ctx.fillStyle = "#fff";
  ctx.fill();
}

function drawParticles(){
  for(let i = 0; i < particles.length; i++){
    ctx.beginPath();
    ctx.arc(particles[i].x,
	    particles[i].y,
	    particles[i].size,
	    0,
	    Math.PI * 2);
    ctx.fillStyle = particles[i].color;
    ctx.closePath();
    ctx.fill();
  }
}

function incParticles(){
  for(let i = 0; i < particles.length; i++){
    particles[i].x += particles[i].velX;
    particles[i].y += particles[i].velY;

    particles[i].size = Math.max(0, (particles[i].size - .05));

    if(particles[i].size === 0){
      particles.splice(i, 1);
    }
  }
}

function createParticles(){
  for(let i = 0; i < 30; i++){
    particles.push({
      x: startingX,
      y: startingY,
      size: parseInt(Math.random() * 10),
      color: 'rgb(' + ranRgb() + ')',
      velX: ranVel(),
      velY: ranVel()
    });
  }
}

function ranRgb(){
  var colors = [
    '255, 122, 206',
    '0, 157, 255',
    '0, 240, 168',
    '0, 240, 120'
  ];

  var i = parseInt(Math.floor(Math.random() * Math.floor(4)));

  return colors[i];
}

function ranVel(){
  var vel = 0;

  if(Math.random() < 0.5){
    vel = Math.abs(Math.random());
  } else {
    vel = -Math.abs(Math.random());
  }

  return vel;
}
<commit_msg>only do confetti on pages with load modals<commit_after>// for scrolltotop arrow

$(window).scroll(function() {
  if ($(this).scrollTop() >= $("#top-c").height()) {
    $('#return-to-top').fadeIn(200);    // Fade in the arrow
  } else {
    $('#return-to-top').fadeOut(200);   // Else fade out the arrow
  }
});

$('#return-to-top').click(function() {      // When arrow is clicked
    $('body,html').animate({
        scrollTop : $("#top-c").scrollTop() - $(".legalese-nav").height()// Scroll to top of body
    }, 500);
});

// insert copyright date

let currentYear = `2017 \u2014 ${(new Date()).getFullYear()}`
$("#copyright-date").text(currentYear);

// show various bits of players navbar

$(".sidebar-header").each(function() {
    $(this).click(function() {
	var id = ".sub-" + $(this).attr("href").slice(1);
	$(".left-menu-sub").hide();
	$(id).show();
    });
});

// don't know why I can't just add a css class here

$('.left-menu-item').on('click', function() {
  $('.left-menu-item').css({ "font-weight": "300", "text-decoration": "none" });
  $(this).css({ "font-weight": "700", "text-decoration": "none" });
});

$('.left-menu-item').hover(
  function() {
    $(this).css({ "font-weight": "700", "text-decoration": "none", "color": "#333333" });
  }, function() {
    $(this).css({ "font-weight": "300", "text-decoration": "none" });
  }
);

$(window).on('scroll', function() {
  $('.lower-nav-el').each(function() {
    if($(window).scrollTop() > ($(this).offset().top - 10)) {
      var id = $(this).attr('id');
      $('.left-menu-item').css('font-weight','300');
      $('a[href="#'+ id +'"]').css('font-weight','700');
    }
  });
});

// only affix sidebar if not on mobile

if ($(window).width() > 768) {
  $(".player-nav").affix({
    offset: {
      top: function() {
	return (this.top = $("#blurb-nav-id").offset().top + 65)
      }
    }
  })
}

$(window).resize(function() {
  if ($(window).width() > 767) {
    $("#magic-shift-toggle-bottom").hide();
    $("#magic-shift-toggle").show()
  } else {
    $("#magic-shift-toggle").hide();
    $("#magic-shift-toggle-bottom").show()
  }
})

if ($(window).width() > 767) {
  $("#magic-shift-toggle-bottom").hide();
  $("#magic-shift-toggle").show()
} else {
  $("#magic-shift-toggle").hide();
  $("#magic-shift-toggle-bottom").show()
}

// downarrow click

$(".downarrow").click(function() {
  $('html, body').animate({
    scrollTop: $("#top-c").height() - $(".legalese-nav").height()
  }, 500);
});

// fix top button to above bot-container when scrolling

$(window).scroll(function() {
  var bottomHeight = $(".bot-container").height()
  if ($(window).scrollTop() + $(window).height() >= $(".bot-container").offset().top) {
    $("#return-to-top").css({
      "bottom": bottomHeight + 30
    });
    $("#return-to-top-text").css({
      "bottom": bottomHeight + 2
    });
  } else {
    $("#return-to-top").css({
      "bottom": "20px"
    });
    $("#return-to-top-text").css({
      "bottom": "-8px"
    });
  }
})

// fix bar to bottom for large screens

if ($('body').outerHeight() < $(window).height()) {
  $(".bot-container").addClass("bot-container-fixed")
} else {
  $(".bot-container").removeClass("bot-container-fixed")
}

// set pricetags

function monthly(price, which) {
  if (which) {
    return price
  } else {
    return (price / 0.7).toFixed(2)
  }
}

accounting.settings = {
  currency: {
    symbol : "$",   // default currency symbol is '$'
    format: "%v", // controls output: %s = symbol, %v = value/number (can be object: see below)
    decimal : ".",  // decimal point separator
    thousand: ",",  // thousands separator
    precision : 0   // decimal places
  },
  number: {
    precision : 0,  // default precision on numbers is 0
    thousand: ",",
    decimal : "."
  }
}

function headers(price, which) {
  if (which) {
    return price
  } else {
    return accounting.formatMoney(price*0.7)
  }
}

let which = false

const prices = {
  pro: {
    header: 2000,
    substandard: 1.74,
    subcomplex: 2.34,
  },
  plus: {
    header: 25,
    substandard: 1.74,
    subcomplex: 2.34,
  },
  basic: {
    header: 15,
    substandard: 2.32,
    subcomplex: 3.12,
  },
}

$('#price-toggle').change(function() {
  $('#subheader-pro').hide().html(`$${headers(prices.pro.header, which)}`).fadeIn(500)
  $('#subheader-plus').hide().html(`$${headers(prices.plus.header, which)}`).fadeIn(500)
  $('#subheader-basic').hide().html(`$${headers(prices.basic.header, which)}`).fadeIn(500)
  $('#substandard-pro').hide().html(`$${monthly(prices.pro.substandard, which)}`).fadeIn(500)
  $('#substandard-plus').hide().html(`$${monthly(prices.plus.substandard, which)}`).fadeIn(500)
  $('#substandard-basic').hide().html(`$${monthly(prices.basic.substandard, which)}`).fadeIn(500)
  $('#subcomplex-pro').hide().html(`$${monthly(prices.pro.subcomplex, which)}`).fadeIn(500)
  $('#subcomplex-plus').hide().html(`$${monthly(prices.plus.subcomplex, which)}`).fadeIn(500)
  $('#subcomplex-basic').hide().html(`$${monthly(prices.basic.subcomplex, which)}`).fadeIn(500)
  which = !which
})

$(function () {
  $('[data-toggle="popover"]').popover()
})

// show or hide relevant fields based on radio selection

$(function() {
  const emailRadio = $('#comms-email-radio')
  const phoneRadio = $('#comms-phone-radio')
  const eitherRadio = $('#comms-either-radio')

  const emailField = $('#commsEmail')
  const phoneField = $('#commsPhone')

  const weekdayRadio = $('#weekdays-radio')
  const everydayRadio = $('#everyday-radio')

  const weekdayGroup = $('#weekdaysGroup')
  const everydayGroup = $('#everydayGroup')

  emailRadio.change(function() {
    if (emailRadio.prop('checked', true)) {
      emailField.show()
      phoneField.hide()
    } else {
      emailField.hide()
    }
  })

  phoneRadio.change(function() {
    if (phoneRadio.prop('checked', true)) {
      phoneField.show()
      emailField.hide()
    } else {
      phoneField.hide()
    }
  })

  eitherRadio.change(function() {
    if (eitherRadio.prop('checked', true)) {
      emailField.show()
      phoneField.show()
    } else {
      emailField.hide()
      phoneField.hide()
    }
  })

  weekdayRadio.change(function() {
    if (weekdayRadio.prop('checked', true)) {
      weekdayGroup.show()
      everydayGroup.hide()
    } else {
      weekdayGroup.show()
      everydayGroup.hide()
    }
  })

  everydayRadio.change(function() {
    if (everydayRadio.prop('checked', true)) {
      everydayGroup.show()
      weekdayGroup.hide()
    } else {
      everydayGroup.show()
      weekdayGroup.hide()
    }
  })

})

function sendData() {

  $('#formModal').modal('toggle')
  $('#congratsModal').modal('toggle')
  var XHR = new XMLHttpRequest();

  // Bind the FormData object and the form element
  const form = document.getElementById('interestForm')
  var FD = new FormData(form);

  // Define what happens on successful data submission
  XHR.addEventListener("load", function(event) {
    console.log(event.target.responseText);
  });

  // Define what happens in case of error
  XHR.addEventListener("error", function(event) {
    console.log('Oops! Something went wrong.');
  });

  // Set up our request
  XHR.open("POST", "http://localhost/api/email/signup");

  // The data sent is what the user provided in the form
  XHR.send(FD);
}

$(document).ready(function() {
  var c = document.getElementById('celebration-canvas')
  if (c) {
    var ctx = c.getContext('2d');

    var particles = [];

    let startingX = c.width / 2
    let startingY = c.height / 2

    document.getElementById('contrastButtonCelebration').addEventListener('mouseover', function(e){
      startingX = Math.random() * 400
      startingY = Math.random() * 60
      createParticles();
    });

    setTimeout(function(){
      createParticles();
    }, 250);

    draw();

    function draw(){

      drawBg();
      incParticles();
      drawParticles();
      window.requestAnimationFrame(draw);

    }

    function drawBg(){
      ctx.rect(0, 0, c.width, c.height);
      ctx.fillStyle = "#fff";
      ctx.fill();
    }

    function drawParticles(){
      for(let i = 0; i < particles.length; i++){
	ctx.beginPath();
	ctx.arc(particles[i].x,
		particles[i].y,
		particles[i].size,
		0,
		Math.PI * 2);
	ctx.fillStyle = particles[i].color;
	ctx.closePath();
	ctx.fill();
      }
    }

    function incParticles(){
      for(let i = 0; i < particles.length; i++){
	particles[i].x += particles[i].velX;
	particles[i].y += particles[i].velY;

	particles[i].size = Math.max(0, (particles[i].size - .05));

	if(particles[i].size === 0){
	  particles.splice(i, 1);
	}
      }
    }

    function createParticles(){
      for(let i = 0; i < 30; i++){
	particles.push({
	  x: startingX,
	  y: startingY,
	  size: parseInt(Math.random() * 10),
	  color: 'rgb(' + ranRgb() + ')',
	  velX: ranVel(),
	  velY: ranVel()
	});
      }
    }

    function ranRgb(){
      var colors = [
	'255, 122, 206',
	'0, 157, 255',
	'0, 240, 168',
	'0, 240, 120'
      ];

      var i = parseInt(Math.floor(Math.random() * Math.floor(4)));

      return colors[i];
    }

    function ranVel(){
      var vel = 0;

      if(Math.random() < 0.5){
	vel = Math.abs(Math.random());
      } else {
	vel = -Math.abs(Math.random());
      }

      return vel;
    }
  }
})
<|endoftext|>


<commit_before>/*
 * Loady module
 * https://github.com/softwarespot/loady
 * Author: softwarespot
 * Licensed under the MIT license
 * Version: 0.1.0
 *
 * Loady module - Load external JavaScript file(s) and append it to the head of the current document
 * Note: This is NOT a replacement for module loaders available on the market
 */
; // jshint ignore:line
((global, name, iLoader, undefined) => {
    // Constants

    // Public API
    const _loadyAPI = (sourceFiles, callback) => {
        // Create an instance of the internal loader class
        const loady = new iLoader();

        // Load the source file(s)
        loady.load(sourceFiles, callback);
    };

    // Store a 'module' reference
    const module = global.module;

    // Store a 'define' reference
    const define = global.define;

    if (module !== undefined && module.exports) {
        // Node.js Module
        module.exports = _loadyAPI;
    } else if (typeof define === 'function' && define.amd) {
        // AMD Module
        global.define(name, [], _loadyAPI);
    }

    // Check if Loady has already been registered beforehand and if so, throw an error
    if (global[name] !== undefined) {
        throw new Error('Loady appears to be already registered with the global object, therefore the module has not be registered.');
    }

    // Append the Loady API to the global object reference
    global[name] = _loadyAPI;

})(window, 'loady', (document) => { // Can't be 'this' with babelJS, as it gets set to 'undefined'
    // Constants

    const _dataAttributes = {
        SOURCE_FILE: 'data-loady-sourcefile'
    };

    // Store the first head node
    const _head = document.head || document.getElementsByTagName('head')[0];

    // Regular expression to strip the JS extension
    const _reJsExtension = /\.js$/;

    // Store previously loaded source file(s)
    const _storageFiles = [];

    // Store the state of the source file(s) i.e. true or false
    const _storageState = [];

    // Return strings of toString() found on the Object prototype
    // Based on the implementation by lodash inc. is* function as well
    const _objectStrings = {
        FUNCTION: '[object Function]',
        STRING: '[object String]'
    };

    // Store the toString method
    const _objectToString = Object.prototype.toString;

    /**
     * Check if a variable is an array datatype
     *
     * @param {mixed} value Value to check
     * @returns {boolean} True the value is an array datatype; otherwise, false
     */
    const isArray = Array.isArray;

    /**
     * Check if a variable is a function datatype
     *
     * @param {mixed} value Value to check
     * @returns {boolean} True the value is a function datatype; otherwise, false
     */
    function isFunction(value) {
        return isObject(value) && _objectToString.call(value) === _objectStrings.FUNCTION;
    }

    /**
     * Check if a variable is an object
     *
     * @param {mixed} value Value to check
     * @returns {boolean} True the value is an object; otherwise, false
     */
    function isObject(value) {
        // Store the typeof value
        const type = typeof value;

        // !!value is basically checking if value is not 'truthy' e.g. null or zero and then inverts that boolean value
        // So, !'Some test' is false and then inverting false is true. There if value contains 'something', continue
        return !!value && (type === 'object' || type === 'function');
    }

    /**
     * Check if a variable is a string datatype
     *
     * @param {mixed} value Value to check
     * @returns {boolean} True the value is a string datatype; otherwise, false
     */
    function isString(value) {
        return typeof value === 'string' || _objectToString.call(value) === _objectStrings.STRING;
    }

    /**
     * ILoader class
     */
    return class ILoader {
        /**
         * Constructor
         *
         * @return {undefined}
         */
        constructor() {
            this.destroy();
        }

        /**
         * Tidy up resources i.e. good housekeeping
         *
         * @return {undefined}
         */
        destroy() {
            // Final callback function
            this._callback = null;

            // Currently loaded total count
            // Note: The loaded count is set to -1, due to this.onCompleted incrementing by 1 and checking against this._length,
            // which right now is set to 0. So utilised before pre-checks
            this._loaded = -1;

            // An array of successfully loaded source file(s)
            this._called = null;

            // An array of source file(s) initially passed in
            this._files = null;

            // Length of the source file(s) initially passed in
            this._length = 0;
        }

        /**
         * Load an array of source file(s)
         *
         * @param {array} sourceFiles An array of source file(s). Note: .js is optional
         * @param {function} callback Callback function to invoke on successful completion.
         * The arguments passed to the callback is an array of loaded scripts and a success parameter of true or false
         * @return {undefined}
         */
        load(sourceFiles, callback) {
            // Destroy the previous contents
            this.destroy();

            // This is the only error thrown, due to a callback being required
            if (!isFunction(callback)) {
                throw new Error('Loady: The callback function argument is not a valid function type.');
            }

            // Coerce as an array if the source file is a string
            if (isString(sourceFiles)) {
                sourceFiles = [sourceFiles];
            }

            // Set the callback function property
            this._callback = callback;

            // Check if the source file(s) argument is not an array
            if (!isArray(sourceFiles)) {
                this.onCompleted(false);
                return;
            }

            // Check if any values exist in the array
            if (sourceFiles.length === 0) {
                this.onCompleted(false);
                return;
            }

            // Set to 0, as now all the important checks have passed, thankfully
            this._loaded = 0;
            this._called = [];
            this._files = sourceFiles;
            this._length = sourceFiles.length;

            for (let i = 0; i < this._length; i++) {
                let sourceFile = sourceFiles[i];
                // Strip and append .js to the source file
                sourceFile = sourceFile.replace(_reJsExtension, '') + '.js';

                const index = _storageFiles.indexOf(sourceFile);
                if (index !== -1) {
                    this.onCompleted(_storageState[index]);
                    continue;
                }

                // Load the script file and append to the current document
                this.loadScript(sourceFile);
            }
        }

        /**
         * Load a script and append to the first HEAD node in the DOM
         *
         * @param {string} sourceFile Script source location that can be absolute or relative
         * @return {undefined}
         */
        loadScript(sourceFile) {
            const node = document.createElement('script');
            node.src = sourceFile;
            // node.text = file;

            // node.type = 'text/javascript';
            // node.charset = 'utf-8';

            node.async = true;

            node.setAttribute(_dataAttributes.SOURCE_FILE, sourceFile);

            // Attach events
            // Note: Bind is used to 'bind' to the context of 'this' i.e. the current object
            node.addEventListener('load', this.onLoad.bind(this), false);
            node.addEventListener('error', this.onLoad.bind(this), false);

            // Append to the HEAD node
            _head.appendChild(node);

            // Push to the internal storage
            _storageFiles.push(sourceFile);
        }

        /**
         * Increment the loaded scripts property and invoke the callback function on completion
         *
         * @param {boolean} isSuccess Whether the request was successful
         * @return {undefined}
         */
        onCompleted(isSuccess) {
            // If not equal to the boolean type and true, then automatically assume as false
            if (isSuccess !== true) {
                isSuccess = false;
            }

            // Increment the loaded total count
            this._loaded++;

            if (this._length === this._loaded) {
                this._callback.apply(this, [this._called, isSuccess]);
                this.destroy();
            }
        }

        /**
         * The 'load' or 'error' callback function for the event listeners
         *
         * @param {event} event Event object passed by the event listener
         * @return {undefined}
         */
        onLoad(event) {
            // Store the type of event and whether it was a 'load' or 'error' type event
            const type = event.type;
            const isLoaded = type === 'load';

            if (isLoaded || type === 'error') {
                const node = event.currentTarget || event.srcElement;
                if (!node) {
                    return;
                }

                // Remove assigned events
                node.removeEventListener('load', this.onLoad, false);
                node.removeEventListener('error', this.onLoad, false);

                // Push the state of the source file. If loaded will be true; otherwise, false
                _storageState.push(isLoaded);

                // Display details about the inserted SCRIPT node and script
                if (isLoaded) {
                    // console.log('Loader.onLoad: Loaded/Error callback invoked, Time: %i', +(new Date()));
                    // console.log('Loader.onLoad: Attribute = ' + node.getAttribute(_dataAttributes.SOURCE_FILE));

                    // Get the source file directly from the data-* attribute
                    const sourceFile = node.getAttribute(_dataAttributes.SOURCE_FILE);

                    // Push to the successfully loaded scripts
                    this._called.push(sourceFile);
                }

                this.onCompleted(true);
            }
        }
    };

}(window.document)); // Can't be 'this.document' with babelJS, as it gets set to 'undefined'
<commit_msg>Add version function<commit_after>/*
 * Loady module
 * https://github.com/softwarespot/loady
 * Author: softwarespot
 * Licensed under the MIT license
 * Version: 0.1.0
 *
 * Loady module - Load external JavaScript file(s) and append it to the head of the current document
 * Note: This is NOT a replacement for module loaders available on the market
 */
; // jshint ignore:line
((global, name, iLoader, undefined) => {
    // Constants

    // Public API
    const _loadyAPI = (sourceFiles, callback) => {
        // Create an instance of the internal loader class
        const loady = new iLoader();

        // Load the source file(s)
        loady.load(sourceFiles, callback);
    };

    // Store a 'module' reference
    const module = global.module;

    // Store a 'define' reference
    const define = global.define;

    if (module !== undefined && module.exports) {
        // Node.js Module
        module.exports = _loadyAPI;
    } else if (typeof define === 'function' && define.amd) {
        // AMD Module
        global.define(name, [], _loadyAPI);
    }

    // Check if Loady has already been registered beforehand and if so, throw an error
    if (global[name] !== undefined) {
        throw new Error('Loady appears to be already registered with the global object, therefore the module has not be registered.');
    }

    // Append the Loady API to the global object reference
    global[name] = _loadyAPI;

})(window, 'loady', (document) => { // Can't be 'this' with babelJS, as it gets set to 'undefined'
    // Constants

    // Version number of the module
    const VERSION = '0.1.0';

    const _dataAttributes = {
        SOURCE_FILE: 'data-loady-sourcefile'
    };

    // Store the first head node
    const _head = document.head || document.getElementsByTagName('head')[0];

    // Regular expression to strip the JS extension
    const _reJsExtension = /\.js$/;

    // Store previously loaded source file(s)
    const _storageFiles = [];

    // Store the state of the source file(s) i.e. true or false
    const _storageState = [];

    // Return strings of toString() found on the Object prototype
    // Based on the implementation by lodash inc. is* function as well
    const _objectStrings = {
        FUNCTION: '[object Function]',
        STRING: '[object String]'
    };

    // Store the toString method
    const _objectToString = Object.prototype.toString;

    /**
     * Check if a variable is an array datatype
     *
     * @param {mixed} value Value to check
     * @returns {boolean} True the value is an array datatype; otherwise, false
     */
    const isArray = Array.isArray;

    /**
     * Check if a variable is a function datatype
     *
     * @param {mixed} value Value to check
     * @returns {boolean} True the value is a function datatype; otherwise, false
     */
    function isFunction(value) {
        return isObject(value) && _objectToString.call(value) === _objectStrings.FUNCTION;
    }

    /**
     * Check if a variable is an object
     *
     * @param {mixed} value Value to check
     * @returns {boolean} True the value is an object; otherwise, false
     */
    function isObject(value) {
        // Store the typeof value
        const type = typeof value;

        // !!value is basically checking if value is not 'truthy' e.g. null or zero and then inverts that boolean value
        // So, !'Some test' is false and then inverting false is true. There if value contains 'something', continue
        return !!value && (type === 'object' || type === 'function');
    }

    /**
     * Check if a variable is a string datatype
     *
     * @param {mixed} value Value to check
     * @returns {boolean} True the value is a string datatype; otherwise, false
     */
    function isString(value) {
        return typeof value === 'string' || _objectToString.call(value) === _objectStrings.STRING;
    }

    /**
     * ILoader class
     */
    return class ILoader {
        /**
         * Constructor
         *
         * @return {undefined}
         */
        constructor() {
            this.destroy();
        }

        /**
         * Tidy up resources i.e. good housekeeping
         *
         * @return {undefined}
         */
        destroy() {
            // Final callback function
            this._callback = null;

            // Currently loaded total count
            // Note: The loaded count is set to -1, due to this.onCompleted incrementing by 1 and checking against this._length,
            // which right now is set to 0. So utilised before pre-checks
            this._loaded = -1;

            // An array of successfully loaded source file(s)
            this._called = null;

            // An array of source file(s) initially passed in
            this._files = null;

            // Length of the source file(s) initially passed in
            this._length = 0;
        }

        /**
         * Load an array of source file(s)
         *
         * @param {array} sourceFiles An array of source file(s). Note: .js is optional
         * @param {function} callback Callback function to invoke on successful completion.
         * The arguments passed to the callback is an array of loaded scripts and a success parameter of true or false
         * @return {undefined}
         */
        load(sourceFiles, callback) {
            // Destroy the previous contents
            this.destroy();

            // This is the only error thrown, due to a callback being required
            if (!isFunction(callback)) {
                throw new Error('Loady: The callback function argument is not a valid function type.');
            }

            // Coerce as an array if the source file is a string
            if (isString(sourceFiles)) {
                sourceFiles = [sourceFiles];
            }

            // Set the callback function property
            this._callback = callback;

            // Check if the source file(s) argument is not an array
            if (!isArray(sourceFiles)) {
                this.onCompleted(false);
                return;
            }

            // Check if any values exist in the array
            if (sourceFiles.length === 0) {
                this.onCompleted(false);
                return;
            }

            // Set to 0, as now all the important checks have passed, thankfully
            this._loaded = 0;
            this._called = [];
            this._files = sourceFiles;
            this._length = sourceFiles.length;

            for (let i = 0; i < this._length; i++) {
                let sourceFile = sourceFiles[i];
                // Strip and append .js to the source file
                sourceFile = sourceFile.replace(_reJsExtension, '') + '.js';

                const index = _storageFiles.indexOf(sourceFile);
                if (index !== -1) {
                    this.onCompleted(_storageState[index]);
                    continue;
                }

                // Load the script file and append to the current document
                this.loadScript(sourceFile);
            }
        }

        /**
         * Load a script and append to the first HEAD node in the DOM
         *
         * @param {string} sourceFile Script source location that can be absolute or relative
         * @return {undefined}
         */
        loadScript(sourceFile) {
            const node = document.createElement('script');
            node.src = sourceFile;
            // node.text = file;

            // node.type = 'text/javascript';
            // node.charset = 'utf-8';

            node.async = true;

            node.setAttribute(_dataAttributes.SOURCE_FILE, sourceFile);

            // Attach events
            // Note: Bind is used to 'bind' to the context of 'this' i.e. the current object
            node.addEventListener('load', this.onLoad.bind(this), false);
            node.addEventListener('error', this.onLoad.bind(this), false);

            // Append to the HEAD node
            _head.appendChild(node);

            // Push to the internal storage
            _storageFiles.push(sourceFile);
        }

        /**
         * Increment the loaded scripts property and invoke the callback function on completion
         *
         * @param {boolean} isSuccess Whether the request was successful
         * @return {undefined}
         */
        onCompleted(isSuccess) {
            // If not equal to the boolean type and true, then automatically assume as false
            if (isSuccess !== true) {
                isSuccess = false;
            }

            // Increment the loaded total count
            this._loaded++;

            if (this._length === this._loaded) {
                this._callback.apply(this, [this._called, isSuccess]);
                this.destroy();
            }
        }

        /**
         * The 'load' or 'error' callback function for the event listeners
         *
         * @param {event} event Event object passed by the event listener
         * @return {undefined}
         */
        onLoad(event) {
            // Store the type of event and whether it was a 'load' or 'error' type event
            const type = event.type;
            const isLoaded = type === 'load';

            if (isLoaded || type === 'error') {
                const node = event.currentTarget || event.srcElement;
                if (!node) {
                    return;
                }

                // Remove assigned events
                node.removeEventListener('load', this.onLoad, false);
                node.removeEventListener('error', this.onLoad, false);

                // Push the state of the source file. If loaded will be true; otherwise, false
                _storageState.push(isLoaded);

                // Display details about the inserted SCRIPT node and script
                if (isLoaded) {
                    // console.log('Loader.onLoad: Loaded/Error callback invoked, Time: %i', +(new Date()));
                    // console.log('Loader.onLoad: Attribute = ' + node.getAttribute(_dataAttributes.SOURCE_FILE));

                    // Get the source file directly from the data-* attribute
                    const sourceFile = node.getAttribute(_dataAttributes.SOURCE_FILE);

                    // Push to the successfully loaded scripts
                    this._called.push(sourceFile);
                }

                this.onCompleted(true);
            }
        }

        // Get the version number of the module
        getVersion() {
            return VERSION;
        }
    };

}(window.document)); // Can't be 'this.document' with babelJS, as it gets set to 'undefined'
<|endoftext|>