<commit_before>/* vim: set expandtab sw=4 ts=4: */
/**
 * Common functions.
 *
 * Copyright (C) 2014-2015 Dieter Adriaenssens <ruleant@users.sourceforge.net>
 *
 * This file is part of buildtimetrend/dashboard
 * <https://github.com/buildtimetrend/dashboard/>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * Checks if a variable is defined and not null.
 */
function isEmpty(varName) {
   return (varName === undefined || varName === null || varName === "");
}

/**
 * Escape html characters
 * inspired by http://css-tricks.com/snippets/javascript/htmlentities-for-javascript/
 */
function htmlEntities(str) {
    return String(str).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"').replace(/'/g, ''');
}

/**
 * Get URL parameter
 * Inspired by http://stackoverflow.com/a/21903119
 */
function getUrlParameter(sParam) {
    var sPageURL = decodeURIComponent(window.location.search.substring(1)),
        sURLVariables = sPageURL.split('&'),
        sParameterName,
        i;

    for (i = 0; i < sURLVariables.length; i++) {
        sParameterName = sURLVariables[i].split('=');

        if (sParameterName[0] === sParam) {
            return sParameterName[1];
        }
    }
}

/**
 * Capitalize first character of a string
 */
function firstCharUpperCase(str) {
    return str.substring(0,1).toUpperCase() + str.substring(1);
}

// add project name to title
function updateTitle() {
    var title = 'Buildtime Trend as a Service';

    // check if config.projectName is set
    if (!isEmpty(config.projectName) && config.projectName !== 'project_name') {
        title = htmlEntities(config.projectName);
    } else if (!isEmpty(config.repoName) && config.repoName !== 'repo_name') {
        title = htmlEntities(config.repoName);
    }

    document.getElementById("title").innerHTML = title;
    document.getElementsByTagName("title")[0].innerHTML = "Buildtime Trend - " + title;
}

// Initialize link urls
function initLinks() {
    // check if config.serviceUrl is set by something else than the default value
    if (!isEmpty(config.websiteUrl) && config.websiteUrl !== 'website_url') {
        $("#title").attr('href', htmlEntities(config.websiteUrl));
    }

    // link to project repo and display icon
    if (!isEmpty(config.repoName) && config.repoName !== 'repo_name') {
        var repoUrl = "https://github.com/" + config.repoName;
        $("#repo-url").attr('href', htmlEntities(repoUrl));
        $("#repo-url").show();
    } else {
        // hide repo icon
        $("#repo-url").hide();
    }
}

// Display message
function initMessage() {
    // add message and display it
    if (!isEmpty(config.message)) {
        $("#message").append(htmlEntities(config.message));
        $("#message").show();
    } else {
        // hide message
        $("#message").hide();
    }
}

// Populate project menu
function populateProjects() {
  // check if config.projectList is defined
  if (!isEmpty(config.projectList) &&
    $.isArray(config.projectList) && config.projectList.length > 0) {
        var i;
        var projectRepo, projectUrl, badgeUrl, projectLinkDropdown, projectLinkOverview;

        for (i = 0; i < config.projectList.length; i++) {
            projectRepo = htmlEntities(config.projectList[i]);
            projectUrl = "/dashboard/" + projectRepo;
            badgeUrl = getBadgeUrl() + projectRepo;

            // add project link to dropdown menu
            projectLinkDropdown = '
' +
              projectRepo + '
';
            $("#projects.dropdown ul").append(projectLinkDropdown);

            // add project link to project overview
            projectLinkOverview = '
' +
              '
' + projectRepo + '
' +
              'Dashboard' +
              ' ' +
              ' ' +
              ' ' +
              '
';
            $("#project-overview").append(projectLinkOverview);
        }

        // show projects dropdown menu
        $("#projects.dropdown").show();
    } else {
        // hide projects dropdown menu
        $("#projects.dropdown").hide();
    }
}

// Get badge url
function getBadgeUrl() {
    // check if config.serviceUrl is set by something else than the default value
    if (isEmpty(config.serviceUrl) || config.serviceUrl === 'service_url') {
        config.serviceUrl = 'https://buildtimetrend.herokuapp.com/';
    }
    return config.serviceUrl + '/badge/';
}
<commit_msg>add function to assign default value<commit_after>/* vim: set expandtab sw=4 ts=4: */
/**
 * Common functions.
 *
 * Copyright (C) 2014-2015 Dieter Adriaenssens <ruleant@users.sourceforge.net>
 *
 * This file is part of buildtimetrend/dashboard
 * <https://github.com/buildtimetrend/dashboard/>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * Checks if a variable is defined and not null.
 */
function isEmpty(varName) {
   return (varName === undefined || varName === null || varName === "");
}

/**
 * Assigns default value if argument is not defined.
 */
function defaultValue(arg, val) {
    return typeof arg !== 'undefined' ? arg : val;
}

/**
 * Escape html characters
 * inspired by http://css-tricks.com/snippets/javascript/htmlentities-for-javascript/
 */
function htmlEntities(str) {
    return String(str).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"').replace(/'/g, ''');
}

/**
 * Get URL parameter
 * Inspired by http://stackoverflow.com/a/21903119
 */
function getUrlParameter(sParam) {
    var sPageURL = decodeURIComponent(window.location.search.substring(1)),
        sURLVariables = sPageURL.split('&'),
        sParameterName,
        i;

    for (i = 0; i < sURLVariables.length; i++) {
        sParameterName = sURLVariables[i].split('=');

        if (sParameterName[0] === sParam) {
            return sParameterName[1];
        }
    }
}

/**
 * Capitalize first character of a string
 */
function firstCharUpperCase(str) {
    return str.substring(0,1).toUpperCase() + str.substring(1);
}

// add project name to title
function updateTitle() {
    var title = 'Buildtime Trend as a Service';

    // check if config.projectName is set
    if (!isEmpty(config.projectName) && config.projectName !== 'project_name') {
        title = htmlEntities(config.projectName);
    } else if (!isEmpty(config.repoName) && config.repoName !== 'repo_name') {
        title = htmlEntities(config.repoName);
    }

    document.getElementById("title").innerHTML = title;
    document.getElementsByTagName("title")[0].innerHTML = "Buildtime Trend - " + title;
}

// Initialize link urls
function initLinks() {
    // check if config.serviceUrl is set by something else than the default value
    if (!isEmpty(config.websiteUrl) && config.websiteUrl !== 'website_url') {
        $("#title").attr('href', htmlEntities(config.websiteUrl));
    }

    // link to project repo and display icon
    if (!isEmpty(config.repoName) && config.repoName !== 'repo_name') {
        var repoUrl = "https://github.com/" + config.repoName;
        $("#repo-url").attr('href', htmlEntities(repoUrl));
        $("#repo-url").show();
    } else {
        // hide repo icon
        $("#repo-url").hide();
    }
}

// Display message
function initMessage() {
    // add message and display it
    if (!isEmpty(config.message)) {
        $("#message").append(htmlEntities(config.message));
        $("#message").show();
    } else {
        // hide message
        $("#message").hide();
    }
}

// Populate project menu
function populateProjects() {
  // check if config.projectList is defined
  if (!isEmpty(config.projectList) &&
    $.isArray(config.projectList) && config.projectList.length > 0) {
        var i;
        var projectRepo, projectUrl, badgeUrl, projectLinkDropdown, projectLinkOverview;

        for (i = 0; i < config.projectList.length; i++) {
            projectRepo = htmlEntities(config.projectList[i]);
            projectUrl = "/dashboard/" + projectRepo;
            badgeUrl = getBadgeUrl() + projectRepo;

            // add project link to dropdown menu
            projectLinkDropdown = '
' +
              projectRepo + '
';
            $("#projects.dropdown ul").append(projectLinkDropdown);

            // add project link to project overview
            projectLinkOverview = '
' +
              '
' + projectRepo + '
' +
              'Dashboard' +
              ' ' +
              ' ' +
              ' ' +
              '
';
            $("#project-overview").append(projectLinkOverview);
        }

        // show projects dropdown menu
        $("#projects.dropdown").show();
    } else {
        // hide projects dropdown menu
        $("#projects.dropdown").hide();
    }
}

// Get badge url
function getBadgeUrl() {
    // check if config.serviceUrl is set by something else than the default value
    if (isEmpty(config.serviceUrl) || config.serviceUrl === 'service_url') {
        config.serviceUrl = 'https://buildtimetrend.herokuapp.com/';
    }
    return config.serviceUrl + '/badge/';
}
<|endoftext|>


<commit_before>Number.prototype.clamp = function(min, max) {
  return Math.min(Math.max(this, min), max);
};

(function() {

    var width, height, largeHeader, canvas, ctx, lines, target, size, animateHeader = true;

    // Main
    initHeader();
    addListeners();
    initAnimation();

    function initHeader() {
        width = window.innerWidth;
        height = window.innerHeight;
        size = width > height ? height : width;
        target = {x: 0, y: height};

        largeHeader = document.getElementById('large-header');
        largeHeader.style.height = height+'px';

        canvas = document.getElementById('demo-canvas');
        canvas.width = width;
        canvas.height = height;
        ctx = canvas.getContext('2d');

        // create particles
        lines = [];
        for(var i = 0; i < 90; i++) {
            var l = new Line(Math.random()*360);
            lines.push(l);
        }
    }

    function initAnimation() {
        animate();
    }

    // Event handling
    function addListeners() {
        window.addEventListener('scroll', scrollCheck);
        window.addEventListener('resize', resize);
    }

    function scrollCheck() {
        if(document.body.scrollTop > height) animateHeader = false;
        else animateHeader = true;
    }

    function resize() {
        width = window.innerWidth;
        height = window.innerHeight;
        size = width > height ? height : width;
        largeHeader.style.height = height+'px';
        canvas.width = width;
        canvas.height = height;
    }

    function animate() {
        if(animateHeader) {
            ctx.clearRect(0,0,width,height);
            for(var i in lines) {
                lines[i].draw();
            }
        }
        requestAnimationFrame(animate);
    }

    // Canvas manipulation
    function Line(angle) {
        var _this = this;
        // globals
        var ROTATIONAL_VELOCITY = 0.1;
        var VELOCITY_FACTOR = 0.01;
        var FLIP_TIME = 100;
        var ACCELERATION_FACTOR = 0.025;

        // constructor
        (function() {
            // console.log(Math.random());
            _this._flag = true;
            _this.angle = angle;
            _this._rotvel = ROTATIONAL_VELOCITY + 0.1 * (2*Math.random() - 1);
            _this._r1 = 25 + Math.random()*(size < 400 ? 400 : size);
            _this._r2 = 25 + Math.random()*(size < 400 ? 400 : size);
            _this._r1_vel = 0*(size < 400 ? 400 : size)*VELOCITY_FACTOR;
            _this._r2_vel = 0*(size < 400 ? 400 : size)*VELOCITY_FACTOR;
            _this._r1_accel = 1;
            _this._r2_accel = 1;
            _this._timestep = 0;
            _this.TIMEFRAME = Math.floor((Math.floor(Math.random()*FLIP_TIME + FLIP_TIME)/4))*2;
            console.log(_this.TIMEFRAME);
        })();

        this.draw = function() {

            var r1 = this._r1;
            var r2 = this._r2;
            var x1 = r1*Math.cos(_this.angle*(Math.PI/180)) + width*0.5;
            var y1 = r1*Math.sin(_this.angle*(Math.PI/180)) + height*0.48;
            var x2 = r2*Math.cos(_this.angle*(Math.PI/180)) + width*0.5;
            var y2 = r2*Math.sin(_this.angle*(Math.PI/180)) + height*0.48;
            ctx.beginPath();
            ctx.moveTo(x1, y1);
            ctx.lineTo(x2, y2);
            ctx.strokeStyle = 'rgba(255, 255, 255,'+(0.5+Math.random()*0.5)+')';

            ctx.stroke();

            ctx.beginPath();
            ctx.arc(x1, y1, 2, 0, 2 * Math.PI, false);
            ctx.fillStyle = 'rgba(255,255,255,'+(0.5+Math.random()*0.5)+')';
            ctx.fill();

            _this.angle += _this._rotvel;
            _this._timestep += 1;

            if (_this._timestep % _this.TIMEFRAME == _this.TIMEFRAME/2) {
                _this._r1_accel *= -1;
                _this._r2_accel *= -1;
                // console.log("FLIPPING");
            }

            _this._r1_vel += _this._r1_accel * ACCELERATION_FACTOR;
            _this._r2_vel += _this._r2_accel * ACCELERATION_FACTOR;

            _this._r1 = (_this._r1 + _this._r1_vel).clamp(0, (size < 400 ? 400 : size));
            _this._r2 = (_this._r2 + _this._r2_vel).clamp(0, (size < 400 ? 400 : size));

            // if (_this._flag) {
            //     console.log(_this);
            //     console.log(ACCELERATION_FACTOR);
            //     _this._flag = false;
            // }
            // console.log(this._r1);
            // console.log(this._r2);
        };
    }

})();<commit_msg>Changed the style a little<commit_after>Number.prototype.clamp = function(min, max) {
  return Math.min(Math.max(this, min), max);
};

(function() {

    var width, height, largeHeader, canvas, ctx, lines, target, size, animateHeader = true;

    // Main
    initHeader();
    addListeners();
    initAnimation();

    function initHeader() {
        width = window.innerWidth;
        height = window.innerHeight;
        size = width > height ? height : width;
        target = {x: 0, y: height};

        largeHeader = document.getElementById('large-header');
        largeHeader.style.height = height+'px';

        canvas = document.getElementById('demo-canvas');
        canvas.width = width;
        canvas.height = height;
        ctx = canvas.getContext('2d');

        // create particles
        lines = [];
        for(var i = 0; i < 90; i++) {
            var l = new Line(Math.random()*360);
            lines.push(l);
        }
    }

    function initAnimation() {
        animate();
    }

    // Event handling
    function addListeners() {
        window.addEventListener('scroll', scrollCheck);
        window.addEventListener('resize', resize);
    }

    function scrollCheck() {
        if(document.body.scrollTop > height) animateHeader = false;
        else animateHeader = true;
    }

    function resize() {
        width = window.innerWidth;
        height = window.innerHeight;
        size = width > height ? height : width;
        largeHeader.style.height = height+'px';
        canvas.width = width;
        canvas.height = height;
    }

    function animate() {
        if(animateHeader) {
            ctx.clearRect(0,0,width,height);
            for(var i in lines) {
                lines[i].draw();
            }
        }
        requestAnimationFrame(animate);
    }

    // Canvas manipulation
    function Line(angle) {
        var _this = this;
        // globals
        var ROTATIONAL_VELOCITY = 0.1;
        var VELOCITY_FACTOR = 0.01;
        var FLIP_TIME = 100;
        var ACCELERATION_FACTOR = 0.025;

        // constructor
        (function() {
            // console.log(Math.random());
            _this._flag = true;
            _this.angle = angle;
            _this._rotvel = ROTATIONAL_VELOCITY + 0.1 * (2*Math.random() - 1);
            _this._r1 = 100 + Math.random()*(size < 400 ? 400 : size)/2;
            _this._r2 = 100 + Math.random()*(size < 400 ? 400 : size)/2;
            _this._r1_vel = 0*(size < 400 ? 400 : size)*VELOCITY_FACTOR;
            _this._r2_vel = 0*(size < 400 ? 400 : size)*VELOCITY_FACTOR;
            _this._r1_accel = 1;
            _this._r2_accel = 1;
            _this._timestep = 0;
            _this.TIMEFRAME = Math.floor((Math.floor(Math.random()*FLIP_TIME + FLIP_TIME)/4))*2;
            console.log(_this.TIMEFRAME);
        })();

        this.draw = function() {

            var r1 = this._r1;
            var r2 = this._r2;
            var x1 = r1*Math.cos(_this.angle*(Math.PI/180)) + width*0.5;
            var y1 = r1*Math.sin(_this.angle*(Math.PI/180)) + height*0.48;
            var x2 = r2*Math.cos(_this.angle*(Math.PI/180)) + width*0.5;
            var y2 = r2*Math.sin(_this.angle*(Math.PI/180)) + height*0.48;
            ctx.beginPath();
            ctx.moveTo(x1, y1);
            ctx.lineTo(x2, y2);
            ctx.strokeStyle = 'rgba(255, 255, 255,'+(0.5+Math.random()*0.2)+')';

            ctx.stroke();

            ctx.beginPath();
            ctx.arc(x1, y1, 2, 0, 2 * Math.PI, false);
            ctx.fillStyle = 'rgba(255,255,255,'+(0.5+Math.random()*0.2)+')';
            ctx.fill();

            _this.angle += _this._rotvel;
            _this._timestep += 1;

            if (_this._timestep % _this.TIMEFRAME == _this.TIMEFRAME/2) {
                _this._r1_accel *= -1;
                _this._r2_accel *= -1;
                // console.log("FLIPPING");
            }

            _this._r1_vel += _this._r1_accel * ACCELERATION_FACTOR;
            _this._r2_vel += _this._r2_accel * ACCELERATION_FACTOR;

            _this._r1 = (_this._r1 + _this._r1_vel).clamp(0, (size < 400 ? 400 : size));
            _this._r2 = (_this._r2 + _this._r2_vel).clamp(0, (size < 400 ? 400 : size));

            // if (_this._flag) {
            //     console.log(_this);
            //     console.log(ACCELERATION_FACTOR);
            //     _this._flag = false;
            // }
            // console.log(this._r1);
            // console.log(this._r2);
        };
    }

})();<|endoftext|>


<commit_before>// @flow
import React from "react";

type Props = {
  task: {
    name?: string,
    currentProgress?: number,
    totalPomodoros?: number,
    stopped?: number,
    active?: boolean
  },
  completeTask: (name: string) => void,
  removeTask: (name: string) => void,
  activateTask: (name: string) => void,
  deactivateTask: (name: string) => void
};

const Task = ({
  task,
  completeTask,
  removeTask,
  activateTask,
  deactivateTask
}: Props) => {
  const { name, stopped } = task.active
    ? {
        name: "task-active-name",
        stopped: "task-active-stopped u-pull-right"
      }
    : {
        name: "task-name",
        stopped: "task-stopped u-pull-right"
      };

  return (

        {task.name}

        {task.currentProgress}/{task.totalPomodoros}

      {task.stopped
        ?
            Stopped {task.stopped} times

        : ""}

  );
};

export default Task;
<commit_msg>Even more stuff!<commit_after>// @flow
import React from "react";

type Props = {
  task: {
    name?: string,
    currentProgress?: number,
    totalPomodoros?: number,
    stopped?: number,
    active?: boolean
  },
  completeTask: (name: string) => void,
  removeTask: (name: string) => void,
  activateTask: (name: string) => void,
  deactivateTask: (name: string) => void
};

const Task = ({
  task,
  completeTask,
  removeTask,
  activateTask,
  deactivateTask
}: Props) => {
  const { name, stopped, buttons } = task.active
    ? {
        name: "task-active-name",
        stopped: "task-active-stopped pad-task u-pull-right",
        buttons: "pad-task u-pull-right"
      }
    : {
        name: "task-name",
        stopped: "task-stopped pad-task u-pull-right",
        buttons: "pad-task u-pull-right"
      };

  return (

        {task.name}

        {task.currentProgress}/{task.totalPomodoros}

      {task.stopped
        ?
            Stopped {task.stopped} times

        : ""}

      {task.active
        ?
             completeTask(task.name)}
              role="button"
              tabIndex="-1"
              className="fa fa-check success"
            />
             deactivateTask(task.name)}
              role="button"
              tabIndex="0"
              className="fa fa-stop danger"
            />

        :
             activateTask(task.name)}
              role="button"
              tabIndex="-1"
              className="fa fa-chevron-up success"
            />
             removeTask(task.name)}
              role="button"
              tabIndex="-0"
              className="fa fa-times danger"
            />
          }

  );
};

export default Task;
<|endoftext|>


<commit_before>var emptyList = '

No results found

';

var $roomsList = $('.rooms-list');
var $groupsList = $('.groups-list');
var $rooms = $('#rooms');

// If rooms list exists, let's populate it.
if ($roomsList.length > 0) {
    $.getJSON('/rooms', function (data) {
        var items = [];
        $rooms.html('');
        data.rooms.forEach(function (room, i, all) {
            items.push('
'+room.name+'
');
            if ($rooms.length > 0) {
                var html = '
 '+room.clientcount+
                           ' users connected
'+room.name+'

'+
                           room.description+'
Jump in!'+
                           '

 '+
                           'Created '+moment(room.createdAt).fromNow()+'

';
                if (room.groups && room.groups.length > 0) {
                    room.groups.forEach(function (group, j, allgroups) {
                        html += '
'+group.name+'
';
                    });
                    html += '
';
                } else {
                    html += '
Public
';
                }
                html += '

';
                $rooms.append(html);
            }
            if (items.length > 0) {
                $roomsList.html(items);
            } else {
                $roomsList.html(emptyList);
            }
        });
    }).fail(function (err) {
        $roomsList.html(emptyList);
        $rooms.html('

Failed to load rooms!

');
    });
}

// If groups list exists, let's populate it.
if ($groupsList.length > 0) {
    $.getJSON('/groups', function (data) {
        var items = [];
        $.each(data.groups, function(index, group) {
            items.push('
'+group.name+'
');
        });
        if (items.length > 0) {
            $groupsList.html(items);
        } else {
            $groupsList.html(emptyList);
        }
    }).fail(function (err) {
        $groupsList.html(emptyList);
    });
}

// Highlight the current nav item
$('.nav-stacked a[href="'+window.location.pathname+'"]').parent('li').addClass('active');
<commit_msg>Only clear #rooms if we actually fetched some.<commit_after>var emptyList = '

No results found

';

var $roomsList = $('.rooms-list');
var $groupsList = $('.groups-list');
var $rooms = $('#rooms');

// If rooms list exists, let's populate it.
if ($roomsList.length > 0) {
    $.getJSON('/rooms', function (data) {
        var items = [];
        if (data.rooms.length > 0) $rooms.html('');
        data.rooms.forEach(function (room, i, all) {
            items.push('
'+room.name+'
');
            if ($rooms.length > 0) {
                var html = '
 '+room.clientcount+
                           ' users connected
'+room.name+'

'+
                           room.description+'
Jump in!'+
                           '

 '+
                           'Created '+moment(room.createdAt).fromNow()+'

';
                if (room.groups && room.groups.length > 0) {
                    room.groups.forEach(function (group, j, allgroups) {
                        html += '
'+group.name+'
';
                    });
                    html += '
';
                } else {
                    html += '
Public
';
                }
                html += '

';
                $rooms.append(html);
            }
            if (items.length > 0) {
                $roomsList.html(items);
            } else {
                $roomsList.html(emptyList);
            }
        });
    }).fail(function (err) {
        $roomsList.html(emptyList);
        $rooms.html('

Failed to load rooms!

');
    });
}

// If groups list exists, let's populate it.
if ($groupsList.length > 0) {
    $.getJSON('/groups', function (data) {
        var items = [];
        $.each(data.groups, function(index, group) {
            items.push('
'+group.name+'
');
        });
        if (items.length > 0) {
            $groupsList.html(items);
        } else {
            $groupsList.html(emptyList);
        }
    }).fail(function (err) {
        $groupsList.html(emptyList);
    });
}

// Highlight the current nav item
$('.nav-stacked a[href="'+window.location.pathname+'"]').parent('li').addClass('active');
<|endoftext|>


<commit_before>import React from "react";
import moment from "moment";

import {Card, CardHeader} from "material-ui/Card";
import {List} from "material-ui/List";
import Divider from "material-ui/Divider";
import IconButton from "material-ui/IconButton";
import RefreshIcon from "material-ui/svg-icons/action/update";

import FeedItem from "./feedItem";

import YQL from "../yql";
import intersperse from "../intersperse";

const styles = {
    cardToolbar: {
        position: "absolute",
        right: 0,
        top: 0
    }
}

class Feed extends React.Component {
    constructor(props) {
        super(props);
        this.state = {items:[]};
    }

    render() {
        let divIndex = 0;
        const listItems = this.state.items.map((item) =>
            <FeedItem key={item.link}
                      item={item}
                      showDescription={this.props.showDescription}
                      showCommentsButton={this.props.showCommentsButton} />);

        return (
            <Card>
                <CardHeader title={this.props.title} subtitle={"Refreshed at " + this.state.timestamp}>

                        <IconButton tooltip="Refresh" onClick={() => this.refreshFeed()}>
                            <RefreshIcon color="#999" />
                        </IconButton>

                </CardHeader>
                <List>
                    {intersperse(listItems, () => <Divider key={`divider${divIndex++}`} />)}
                </List>
            </Card>
        );
    }

    componentWillMount() {
        this.refreshFeed();
    }

    refreshFeed() {
        YQL(`select * from rss where url="${this.props.url}"`, (data) => {
            this.setState({
                timestamp: moment().format("HH:mm"),
                items: data.query.results.item
            });
        });
    }
}

export default Feed;<commit_msg>Refresh feeds every 5 minutes<commit_after>import React from "react";
import moment from "moment";

import {Card, CardHeader} from "material-ui/Card";
import {List} from "material-ui/List";
import Divider from "material-ui/Divider";
import IconButton from "material-ui/IconButton";
import RefreshIcon from "material-ui/svg-icons/action/update";

import FeedItem from "./feedItem";

import YQL from "../yql";
import intersperse from "../intersperse";

const styles = {
    cardToolbar: {
        position: "absolute",
        right: 0,
        top: 0
    }
}

class Feed extends React.Component {
    constructor(props) {
        super(props);
        this.state = {items:[]};
    }

    render() {
        let divIndex = 0;
        const listItems = this.state.items.map((item) =>
            <FeedItem key={item.link}
                      item={item}
                      showDescription={this.props.showDescription}
                      showCommentsButton={this.props.showCommentsButton} />);

        return (
            <Card>
                <CardHeader title={this.props.title} subtitle={"Refreshed at " + this.state.timestamp}>

                        <IconButton tooltip="Refresh" onClick={() => this.refreshFeed()}>
                            <RefreshIcon color="#999" />
                        </IconButton>

                </CardHeader>
                <List>
                    {intersperse(listItems, () => <Divider key={`divider${divIndex++}`} />)}
                </List>
            </Card>
        );
    }

    componentWillMount() {
        this.refreshFeed();
        this.refreshInterval = window.setInterval(() => this.refreshFeed(), 5*60*1000); // Refresh feed every 5 minutes
    }

    componentWillUnmount() {
        window.clearInterval(this.refreshInterval);
    }

    refreshFeed() {
        YQL(`select * from rss where url="${this.props.url}"`, (data) => {
            this.setState({
                timestamp: moment().format("HH:mm"),
                items: data.query.results.item
            });
        });
    }
}

export default Feed;<|endoftext|>


<commit_before>(function (enyo, scope) {
	/**
	* A light-weight panels implementation that has basic support for CSS transitions between child
	* components.
	*
	* @class enyo.LightPanels
	* @extends enyo.Control
	* @ui
	* @public
	*/
	enyo.kind(
		/** @lends enyo.LightPanels.prototype */ {

		/**
		* @private
		*/
		name: 'enyo.LightPanels',

		/**
		* @private
		*/
		kind: 'enyo.Control',

		/**
		* @private
		*/
		classes: 'enyo-light-panels',

		/**
		* @private
		* @lends enyo.LightPanels.prototype
		*/
		published: {

			/**
			* The index of the active panel.
			*
			* @type {Number}
			* @default 0
			* @public
			*/
			index: 0,

			/**
			* Indicates whether the panels animate when transitioning.
			*
			* @type {Boolean}
			* @default true
			* @public
			*/
			animate: true,

			/**
			* Indicates whether panels "wrap around" when moving past the end.
			* The actual effect depends upon the arranger in use.
			*
			* @type {Boolean}
			* @default false
			* @public
			*/
			wrap: false,

			/**
			* When `true`, panels are automatically popped when the user moves back.
			*
			* @type {Boolean}
			* @default true
			* @public
			*/
			popOnBack: true,

			/**
			* The amount of time, in milliseconds, to run the transition animation between panels.
			*
			* @type {Number}
			* @default 250
			* @public
			*/
			duration: 250,

			/**
			* The timing function to be applied to the transition animation between panels.
			*
			* @type {String}
			* @default 'ease-out'
			* @public
			*/
			timingFunction: 'ease-out',

			/**
			* The orientation of the panels. Possible values are 'vertical' and 'horizontal'.
			*
			* @type {String}
			* @default 'horizontal'
			* @public
			*/
			orientation: 'horizontal',

			/**
			* The direction of the panel movement. Possible values are 'forwards' and 'backwards'.
			*
			* @type {String}
			* @default 'forwards'
			* @public
			*/
			direction: 'forwards',

			cachePanels: true
		},

		/**
		* @private
		*/
		handlers: {
			ontransitionend: 'transitionFinished'
		},

		/**
		* @method
		* @private
		*/
		create: enyo.inherit(function (sup) {
			return function () {
				sup.apply(this, arguments);
				this.init();
				this.indexChanged();
			};
		}),

		/**
		* @private
		*/
		init: function () {
			this.addClass(this.orientation);
			this.addClass(this.direction);

			if (this.cachePanels) {
				this.createChrome([
					{name: 'panelCache', kind: 'enyo.Control', canGenerate: false}
				]);
				this.removeChild(this.$.panelCache);
				this.cachedPanels = {};
				this.queuedPanels = [];
			}
		},

		/**
		* @private
		*/
		indexChanged: function (previousIndex) {
			var panels = this.getPanels(),
				nextPanel = panels[this.index],
				trans, wTrans, axis, direction;

			this._indexDirection = (this.index - previousIndex < 0 ? -1 : 1);

			if (nextPanel) {
				// only animate transition if there is more than one panel and/or we're animating
				if (!this.shouldAnimate()) {
					nextPanel.applyStyle('-webkit-transition-duration', '0s');
					nextPanel.applyStyle('transition-duration', '0s');
				} else {
					trans = enyo.format('transform %.ms %.', this.duration, this.timingFunction);
					wTrans = '-webkit-' + trans;
					nextPanel.applyStyle('-webkit-transition', wTrans);
					nextPanel.applyStyle('transition', trans);
					nextPanel.addClass('transitioning');
					if (this._currentPanel) {
						this._currentPanel.applyStyle('-webkit-transition', wTrans);
						this._currentPanel.applyStyle('transition', trans);
						this._currentPanel.addClass('transitioning');
					}
				}

				axis = this.orientation == 'horizontal' ? 'X' : 'Y';
				direction = this.direction == 'forwards' ? 1 : -1;
				setTimeout(this.bindSafely(function () {
					var nextTransition = {};
					nextTransition['translate' + axis] = -100 * direction + '%';
					enyo.dom.transform(nextPanel, nextTransition);
					if (this._currentPanel) {
						var currentTransition = {};
						currentTransition['translate' + axis] = this._indexDirection > 0 ? -200 * direction + '%' : '0%';
						enyo.dom.transform(this._currentPanel, currentTransition);
					}

					this._previousPanel = this._currentPanel;
					this._currentPanel = nextPanel;
					if (!this.shouldAnimate()) {
						this.transitionFinished(this._currentPanel, {originator: this._currentPanel});
					}

				}), this.shouldAnimate() ? 16 : 0);
			}
		},

		/**
		* Determines whether or not we should animate the panel transition.
		*
		* @return {Boolean} If `true`, the panels should animate.
		* @public
		*/
		shouldAnimate: function () {
			return this.getPanels().length > 1 && this.animate;
		},

		/**
		* Retrieves the currently displayed panel.
		*
		* @return {Object} The currently displayed panel.
		* @public
		*/
		getActivePanel: function () {
			return this._currentPanel;
		},

		/**
		* Transitions to the previous panel--i.e., the panel whose index value is one
		* less than that of the current active panel.
		*
		* @public
		*/
		previous: function () {
			var prevIndex = this.index - 1;
			if (this.wrap && prevIndex < 0) {
				prevIndex = this.getPanels().length - 1;
			}
			if (prevIndex >= 0) {
				this.set('index', prevIndex);
			}
		},

		/**
		* Transitions to the next panel--i.e., the panel whose index value is one
		* greater than that of the current active panel.
		*
		* @public
		*/
		next: function () {
			var nextIndex = this.index + 1;
			if (this.wrap && nextIndex >= this.getPanels().length) {
				nextIndex = 0;
			}
			if (nextIndex < this.getPanels().length) {
				this.set('index', nextIndex);
			}
		},

		/**
		* Creates a panel on top of the stack and increments index to select that component.
		*
		* @param {Object} info - The declarative {@glossary kind} definition.
		* @param {Object} moreInfo - Additional properties to be applied (defaults).
		* @param {Object} opts - Additional options to be used during panel pushing.
		* @return {Object} The instance of the panel that was created on top of the stack.
		* @public
		*/
		pushPanel: function (info, moreInfo, opts) {
			if (opts && opts.purge) {
				this.purge();
			}

			var lastIndex = this.getPanels().length - 1,
				nextPanel = (this.cachePanels && this.restorePanel(info.kind)) || this.createComponent(info, moreInfo);
			nextPanel.render();
			this.set('index', lastIndex + 1, true);

			// TODO: When pushing panels after we have gone back (but have not popped), we need to
			// adjust the position of the panels after the previous index before our push.
			return nextPanel;
		},

		/**
		* Creates multiple panels on top of the stack and updates index to select the last one
		* created. Supports an optional `options` object as the third parameter.
		*
		* @param {Object[]} info - The declarative {@glossary kind} definitions.
		* @param {Object} commonInfo - Additional properties to be applied (defaults).
		* @param {Object} options - Additional options for pushPanels.
		* @return {null|Object[]} Array of the panels that were created on top of the stack, or
		*	`null` if panels could not be created.
		* @public
		*/
		pushPanels: function (info, commonInfo, options) {
			var lastIndex = this.getPanels().length,
				newPanels = this.createComponents(info, commonInfo),
				idx;

			for (idx = 0; idx < newPanels.length; ++idx) {
				newPanels[idx].render();
			}

			this.set('index', lastIndex, true);

			return newPanels;
		},

		/**
		* @private
		*/
		getPanels: function () {
			/*jshint -W093 */
			return (this._panels = this._panels || (this.controlParent || this).children);
		},

		/**
		* Destroys panels whose index is greater than or equal to a specified value.
		*
		* @param {Number} index - Index at which to start destroying panels.
		* @public
		*/
		popPanels: function (index) {
			var panels = this.getPanels(),
				panel;

			index = index || panels.length - 1;

			while (panels.length > index && index >= 0) {
				panel = panels[panels.length - 1];
				if (this.cachePanels) {
					this.cachePanel(panel);
				}
				else {
					panel.destroy();
				}
			}
		},

		/**
		* Destroys all panels. These will be queued for destruction after the next panel has loaded.
		*
		* @private
		*/
		purge: function () {
			var panels = this.getPanels();
			this._garbagePanels = panels.slice();
			panels.length = 0;
		},

		/**
		* Clean-up any panels queued for destruction.
		*
		* @private
		*/
		finalizePurge: function () {
			var panels = this._garbagePanels,
				panel;
			while (panels.length) {
				panel = panels.pop();
				if (this.cachePanels) {
					this.cachePanel(panel);
				}
				else {
					panel.destroy();
				}
			}
		},

		/**
		* Caches a given panel so that it can be quickly instantiated and utilized at a later point.
		* This is typically performed on a panel which has already been rendered and which no longer
		* needs to remain in view, but may be revisited at a later time.
		*
		* @param {Object} panel - The panel to cache for later use.
		* @public
		*/
		cachePanel: function (panel) {
			// TODO: This works for Settings use case,
			// but we need to support an alternative
			// identifier for panel-caching purposes
			var pid = panel.kind;

			this.log('caching ' + pid);

			panel.node.remove();
			panel.teardownRender();

			this.removeControl(panel);
			this.$.panelCache.addControl(panel);

			this.cachedPanels[pid] = panel;
		},

		/**
		* Restores the specified panel that was previously cached.
		*
		* @param {String} pid - The unique identifier for the cached panel that is being restored.
		* @return {Object} The restored panel.
		* @public
		*/
		restorePanel: function (pid) {
			var cp = this.cachedPanels,
				panel = cp[pid];

			if (panel) {
				this.log('restored!');
				this.$.panelCache.removeControl(panel);
				this.addControl(panel);

				this.cachedPanels[pid] = null;
			}

			return panel;
		},

		/**
		* Pre-caches a set of panels by creating and caching them, even if they have not yet been
		* rendered into view. This is helpful for reducing the instantiation time for panels which
		* have yet to be shown, but can and eventually will be shown to the user.
		*
		* @param {Object} info - The declarative {@glossary kind} definition.
		* @param {Object} commonInfo - Additional properties to be applied (defaults).
		* @param {Boolean} runPostTransition - If `true`, the {@link enyo.LightPanel#postTransition}
		*	method will be run.
		* @public
		*/
		preCachePanels: function(info, commonInfo, runPostTransition) {
			var pc, panels, i, panel;
			var now = enyo.perfNow();
			if (this.cachePanels) {
				pc = this.$.panelCache;
				commonInfo = commonInfo || {};
				commonInfo.owner = this;
				panels = pc.createComponents(info, commonInfo);
				for (i = 0; i < panels.length; i++) {
					panel = panels[i];
					this.cachedPanels[panel.kind] = panel;
					if (runPostTransition) {
						panel.postTransition();
					}
				}
			}
			this.log(enyo.perfNow() - now);
		},

		/**
		* @private
		*/
		preCacheQueuedPanels: function () {
			this.preCachePanels(this.queuedPanels, {}, true);
			this.queuedPanels.length = 0;
		},

		/**
		* Enqueues a view that will eventually be pre-cached at an opportunistic time.
		*
		* @param {String} viewName - The name of the view to be enqueued.
		* @public
		*/
		enqueueView: function (viewProps) {
			this.queuedPanels.push(viewProps);
		},

		/**
		* Enqueues a set of views that will eventually be pre-cached at an opportunistic time.
		*
		* @param {Array} viewNames - A set of views to be enqueued.
		* @public
		*/
		enqueueViews: function (viewPropsArray) {
			this.queuedPanels = this.queuedPanels.concat(viewPropsArray);
		},

		/**
		* @private
		*/
		transitionFinished: function (sender, ev) {
			if (ev.originator === this._currentPanel) {
				this._currentPanel.removeClass('transitioning');
				if (this._previousPanel) {
					this._previousPanel.removeClass('transitioning');
				}
				if (this.popOnBack && this._indexDirection < 0 && this.index < this.getPanels().length - 1) {
					this.popPanels(this.index + 1);
				}
				if (this._currentPanel.shouldSkipPostTransition && !this._currentPanel.shouldSkipPostTransition()) {
					enyo.asyncMethod(this, function () {
						this._currentPanel.postTransition();
					});
				}
				if (this._garbagePanels && this._garbagePanels.length) {
					this.finalizePurge();
				}
				if (this.cachePanels && this.queuedPanels.length) {
					this.startJob('preCacheQueuedPanels', function() {
						this.preCacheQueuedPanels();
					}, 750);
				}
			}
		}

	});

})(enyo, this);
<commit_msg>Removing logging.<commit_after>(function (enyo, scope) {
	/**
	* A light-weight panels implementation that has basic support for CSS transitions between child
	* components.
	*
	* @class enyo.LightPanels
	* @extends enyo.Control
	* @ui
	* @public
	*/
	enyo.kind(
		/** @lends enyo.LightPanels.prototype */ {

		/**
		* @private
		*/
		name: 'enyo.LightPanels',

		/**
		* @private
		*/
		kind: 'enyo.Control',

		/**
		* @private
		*/
		classes: 'enyo-light-panels',

		/**
		* @private
		* @lends enyo.LightPanels.prototype
		*/
		published: {

			/**
			* The index of the active panel.
			*
			* @type {Number}
			* @default 0
			* @public
			*/
			index: 0,

			/**
			* Indicates whether the panels animate when transitioning.
			*
			* @type {Boolean}
			* @default true
			* @public
			*/
			animate: true,

			/**
			* Indicates whether panels "wrap around" when moving past the end.
			* The actual effect depends upon the arranger in use.
			*
			* @type {Boolean}
			* @default false
			* @public
			*/
			wrap: false,

			/**
			* When `true`, panels are automatically popped when the user moves back.
			*
			* @type {Boolean}
			* @default true
			* @public
			*/
			popOnBack: true,

			/**
			* The amount of time, in milliseconds, to run the transition animation between panels.
			*
			* @type {Number}
			* @default 250
			* @public
			*/
			duration: 250,

			/**
			* The timing function to be applied to the transition animation between panels.
			*
			* @type {String}
			* @default 'ease-out'
			* @public
			*/
			timingFunction: 'ease-out',

			/**
			* The orientation of the panels. Possible values are 'vertical' and 'horizontal'.
			*
			* @type {String}
			* @default 'horizontal'
			* @public
			*/
			orientation: 'horizontal',

			/**
			* The direction of the panel movement. Possible values are 'forwards' and 'backwards'.
			*
			* @type {String}
			* @default 'forwards'
			* @public
			*/
			direction: 'forwards',

			cachePanels: true
		},

		/**
		* @private
		*/
		handlers: {
			ontransitionend: 'transitionFinished'
		},

		/**
		* @method
		* @private
		*/
		create: enyo.inherit(function (sup) {
			return function () {
				sup.apply(this, arguments);
				this.init();
				this.indexChanged();
			};
		}),

		/**
		* @private
		*/
		init: function () {
			this.addClass(this.orientation);
			this.addClass(this.direction);

			if (this.cachePanels) {
				this.createChrome([
					{name: 'panelCache', kind: 'enyo.Control', canGenerate: false}
				]);
				this.removeChild(this.$.panelCache);
				this.cachedPanels = {};
				this.queuedPanels = [];
			}
		},

		/**
		* @private
		*/
		indexChanged: function (previousIndex) {
			var panels = this.getPanels(),
				nextPanel = panels[this.index],
				trans, wTrans, axis, direction;

			this._indexDirection = (this.index - previousIndex < 0 ? -1 : 1);

			if (nextPanel) {
				// only animate transition if there is more than one panel and/or we're animating
				if (!this.shouldAnimate()) {
					nextPanel.applyStyle('-webkit-transition-duration', '0s');
					nextPanel.applyStyle('transition-duration', '0s');
				} else {
					trans = enyo.format('transform %.ms %.', this.duration, this.timingFunction);
					wTrans = '-webkit-' + trans;
					nextPanel.applyStyle('-webkit-transition', wTrans);
					nextPanel.applyStyle('transition', trans);
					nextPanel.addClass('transitioning');
					if (this._currentPanel) {
						this._currentPanel.applyStyle('-webkit-transition', wTrans);
						this._currentPanel.applyStyle('transition', trans);
						this._currentPanel.addClass('transitioning');
					}
				}

				axis = this.orientation == 'horizontal' ? 'X' : 'Y';
				direction = this.direction == 'forwards' ? 1 : -1;
				setTimeout(this.bindSafely(function () {
					var nextTransition = {};
					nextTransition['translate' + axis] = -100 * direction + '%';
					enyo.dom.transform(nextPanel, nextTransition);
					if (this._currentPanel) {
						var currentTransition = {};
						currentTransition['translate' + axis] = this._indexDirection > 0 ? -200 * direction + '%' : '0%';
						enyo.dom.transform(this._currentPanel, currentTransition);
					}

					this._previousPanel = this._currentPanel;
					this._currentPanel = nextPanel;
					if (!this.shouldAnimate()) {
						this.transitionFinished(this._currentPanel, {originator: this._currentPanel});
					}

				}), this.shouldAnimate() ? 16 : 0);
			}
		},

		/**
		* Determines whether or not we should animate the panel transition.
		*
		* @return {Boolean} If `true`, the panels should animate.
		* @public
		*/
		shouldAnimate: function () {
			return this.getPanels().length > 1 && this.animate;
		},

		/**
		* Retrieves the currently displayed panel.
		*
		* @return {Object} The currently displayed panel.
		* @public
		*/
		getActivePanel: function () {
			return this._currentPanel;
		},

		/**
		* Transitions to the previous panel--i.e., the panel whose index value is one
		* less than that of the current active panel.
		*
		* @public
		*/
		previous: function () {
			var prevIndex = this.index - 1;
			if (this.wrap && prevIndex < 0) {
				prevIndex = this.getPanels().length - 1;
			}
			if (prevIndex >= 0) {
				this.set('index', prevIndex);
			}
		},

		/**
		* Transitions to the next panel--i.e., the panel whose index value is one
		* greater than that of the current active panel.
		*
		* @public
		*/
		next: function () {
			var nextIndex = this.index + 1;
			if (this.wrap && nextIndex >= this.getPanels().length) {
				nextIndex = 0;
			}
			if (nextIndex < this.getPanels().length) {
				this.set('index', nextIndex);
			}
		},

		/**
		* Creates a panel on top of the stack and increments index to select that component.
		*
		* @param {Object} info - The declarative {@glossary kind} definition.
		* @param {Object} moreInfo - Additional properties to be applied (defaults).
		* @param {Object} opts - Additional options to be used during panel pushing.
		* @return {Object} The instance of the panel that was created on top of the stack.
		* @public
		*/
		pushPanel: function (info, moreInfo, opts) {
			if (opts && opts.purge) {
				this.purge();
			}

			var lastIndex = this.getPanels().length - 1,
				nextPanel = (this.cachePanels && this.restorePanel(info.kind)) || this.createComponent(info, moreInfo);
			nextPanel.render();
			this.set('index', lastIndex + 1, true);

			// TODO: When pushing panels after we have gone back (but have not popped), we need to
			// adjust the position of the panels after the previous index before our push.
			return nextPanel;
		},

		/**
		* Creates multiple panels on top of the stack and updates index to select the last one
		* created. Supports an optional `options` object as the third parameter.
		*
		* @param {Object[]} info - The declarative {@glossary kind} definitions.
		* @param {Object} commonInfo - Additional properties to be applied (defaults).
		* @param {Object} options - Additional options for pushPanels.
		* @return {null|Object[]} Array of the panels that were created on top of the stack, or
		*	`null` if panels could not be created.
		* @public
		*/
		pushPanels: function (info, commonInfo, options) {
			var lastIndex = this.getPanels().length,
				newPanels = this.createComponents(info, commonInfo),
				idx;

			for (idx = 0; idx < newPanels.length; ++idx) {
				newPanels[idx].render();
			}

			this.set('index', lastIndex, true);

			return newPanels;
		},

		/**
		* @private
		*/
		getPanels: function () {
			/*jshint -W093 */
			return (this._panels = this._panels || (this.controlParent || this).children);
		},

		/**
		* Destroys panels whose index is greater than or equal to a specified value.
		*
		* @param {Number} index - Index at which to start destroying panels.
		* @public
		*/
		popPanels: function (index) {
			var panels = this.getPanels(),
				panel;

			index = index || panels.length - 1;

			while (panels.length > index && index >= 0) {
				panel = panels[panels.length - 1];
				if (this.cachePanels) {
					this.cachePanel(panel);
				}
				else {
					panel.destroy();
				}
			}
		},

		/**
		* Destroys all panels. These will be queued for destruction after the next panel has loaded.
		*
		* @private
		*/
		purge: function () {
			var panels = this.getPanels();
			this._garbagePanels = panels.slice();
			panels.length = 0;
		},

		/**
		* Clean-up any panels queued for destruction.
		*
		* @private
		*/
		finalizePurge: function () {
			var panels = this._garbagePanels,
				panel;
			while (panels.length) {
				panel = panels.pop();
				if (this.cachePanels) {
					this.cachePanel(panel);
				}
				else {
					panel.destroy();
				}
			}
		},

		/**
		* Caches a given panel so that it can be quickly instantiated and utilized at a later point.
		* This is typically performed on a panel which has already been rendered and which no longer
		* needs to remain in view, but may be revisited at a later time.
		*
		* @param {Object} panel - The panel to cache for later use.
		* @public
		*/
		cachePanel: function (panel) {
			// TODO: This works for Settings use case,
			// but we need to support an alternative
			// identifier for panel-caching purposes
			var pid = panel.kind;

			panel.node.remove();
			panel.teardownRender();

			this.removeControl(panel);
			this.$.panelCache.addControl(panel);

			this.cachedPanels[pid] = panel;
		},

		/**
		* Restores the specified panel that was previously cached.
		*
		* @param {String} pid - The unique identifier for the cached panel that is being restored.
		* @return {Object} The restored panel.
		* @public
		*/
		restorePanel: function (pid) {
			var cp = this.cachedPanels,
				panel = cp[pid];

			if (panel) {
				this.$.panelCache.removeControl(panel);
				this.addControl(panel);

				this.cachedPanels[pid] = null;
			}

			return panel;
		},

		/**
		* Pre-caches a set of panels by creating and caching them, even if they have not yet been
		* rendered into view. This is helpful for reducing the instantiation time for panels which
		* have yet to be shown, but can and eventually will be shown to the user.
		*
		* @param {Object} info - The declarative {@glossary kind} definition.
		* @param {Object} commonInfo - Additional properties to be applied (defaults).
		* @param {Boolean} runPostTransition - If `true`, the {@link enyo.LightPanel#postTransition}
		*	method will be run.
		* @public
		*/
		preCachePanels: function(info, commonInfo, runPostTransition) {
			var pc, panels, i, panel;

			if (this.cachePanels) {
				pc = this.$.panelCache;
				commonInfo = commonInfo || {};
				commonInfo.owner = this;
				panels = pc.createComponents(info, commonInfo);
				for (i = 0; i < panels.length; i++) {
					panel = panels[i];
					this.cachedPanels[panel.kind] = panel;
					if (runPostTransition) {
						panel.postTransition();
					}
				}
			}
		},

		/**
		* @private
		*/
		preCacheQueuedPanels: function () {
			this.preCachePanels(this.queuedPanels, {}, true);
			this.queuedPanels.length = 0;
		},

		/**
		* Enqueues a view that will eventually be pre-cached at an opportunistic time.
		*
		* @param {String} viewName - The name of the view to be enqueued.
		* @public
		*/
		enqueueView: function (viewProps) {
			this.queuedPanels.push(viewProps);
		},

		/**
		* Enqueues a set of views that will eventually be pre-cached at an opportunistic time.
		*
		* @param {Array} viewNames - A set of views to be enqueued.
		* @public
		*/
		enqueueViews: function (viewPropsArray) {
			this.queuedPanels = this.queuedPanels.concat(viewPropsArray);
		},

		/**
		* @private
		*/
		transitionFinished: function (sender, ev) {
			if (ev.originator === this._currentPanel) {
				this._currentPanel.removeClass('transitioning');
				if (this._previousPanel) {
					this._previousPanel.removeClass('transitioning');
				}
				if (this.popOnBack && this._indexDirection < 0 && this.index < this.getPanels().length - 1) {
					this.popPanels(this.index + 1);
				}
				if (this._currentPanel.shouldSkipPostTransition && !this._currentPanel.shouldSkipPostTransition()) {
					enyo.asyncMethod(this, function () {
						this._currentPanel.postTransition();
					});
				}
				if (this._garbagePanels && this._garbagePanels.length) {
					this.finalizePurge();
				}
				if (this.cachePanels && this.queuedPanels.length) {
					this.startJob('preCacheQueuedPanels', function() {
						this.preCacheQueuedPanels();
					}, 750);
				}
			}
		}

	});

})(enyo, this);
<|endoftext|>


<commit_before>// n-back.js

var stimuliPool = ['B', 'C', 'D', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'V', 'W', 'X', 'Y', 'Z'];

function getStimuli(step, totalNum, targetNum) {
    if (!(_.isNumber(step) && _.isNumber(totalNum) && _.isNumber(targetNum) && step >= 0)) {
        return;
    };
    var stimuli = [];
    if (step === 0) {
        for (var i = 0; i < totalNum; i++) {
            stimuli.push(_.sample(stimuliPool));
        };
    } else {
        for (var i = 0; i < totalNum; i++) {
            if (i < step) {
                stimuli.push(_.sample(stimuliPool));
            } else {
                var target = _.nth(stimuli, -step);
                if (_.random(1, totalNum - i) <= targetNum) {
                    targetNum--;
                    stimuli.push(target);
                } else {
                    stimuli.push(_.sample(_.difference(stimuliPool, [target])));
                };
            };
        };
    };
    return stimuli;
};<commit_msg>Update<commit_after>// n-back.js

var stimuliPool = ['B', 'C', 'D', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'V', 'W', 'X', 'Y', 'Z'];

function getStimuli(step, totalNum, targetNum) {
    if (!(_.isNumber(step) && _.isNumber(totalNum) && _.isNumber(targetNum) && step >= 0)) {
        return;
    };
    var stimuli = [];
    if (step === 0) {
        for (var i = 0; i < totalNum; i++) {
            stimuli.push({
                'stimulus': _.sample(stimuliPool),
                'is_target': true
            });
        };
    } else {
        for (var i = 0; i < totalNum; i++) {
            if (i < step) {
                stimuli.push({
                    'stimulus': _.sample(stimuliPool),
                    'is_target': false
                });
            } else {
                var target = _.nth(stimuli, -step);
                if (_.random(1, totalNum - i) <= targetNum) {
                    targetNum--;
                    stimuli.push({
                        'stimulus': target.stimulus,
                        'is_target': true
                    });
                } else {
                    stimuli.push({
                        'stimulus': _.sample(_.difference(stimuliPool, [target.stimulus])),
                        'is_target': false
                    });
                };
            };
        };
    };
    return stimuli;
};<|endoftext|>


<commit_before>$(document).ready(function()
{
    $('#navbar_replacement').replaceWith('\

\

\

\
            <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">\
                \
                \
                \
            </button>\
            \

\

\

\

Follow @nocass_official
\

Home
\

About
\

Programme
\

Venue
\

#
\

Sponsorship
\

\

\

\

\
    ');
})
<commit_msg>Update navbar.js<commit_after>$(document).ready(function()
{
    $('#navbar_replacement').replaceWith('\

\

\

\
            <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">\
                \
                \
                \
            </button>\
            \

\

\

\

Follow @nocass_official
\

Home
\

About
\

Programme
\

Venue
\

Registration
\

Sponsorship
\

\

\

\

\
    ');
})
<|endoftext|>


<commit_before>transporter.module.create('projects/projects', function(requires) {}, function(thisModule) {

thisModule.addSlots(avocado, function(add) {

  add.creator('project', {}, {category: ['projects']});

});

thisModule.addSlots(avocado.project, function(add) {

  add.method('current', function () {
    return this._current || (this._current = this.create({ name: "This project" }));
  }, {category: ['current one']});

  add.method('setCurrent', function (p) {
    this._current = p;
  }, {category: ['current one']});

  add.method('create', function (info) {
    return Object.newChildOf(this, info);
  }, {category: ['creating']});

  add.method('initialize', function (info) {
    this.setName(info.name);
    this.setIsPrivate(info.isPrivate);
    if (info._id) {
      this.setID(info._id);
    } else {
      transporter.idTracker.createTemporaryIDFor(this);
    }
    this.markAsUnchanged();
  }, {category: ['creating']});

  add.method('name', function () { return this._name; }, {category: ['accessing']});

  add.method('setName', function (n) { this._name = n; this.markAsChanged(); }, {category: ['accessing']});

  add.method('id', function () { return this._projectID; }, {category: ['accessing']});

  add.method('setID', function (id) { this._projectID = id; }, {category: ['accessing']});

  add.method('isPrivate', function () { return this._isPrivate; }, {category: ['accessing']});

  add.method('setIsPrivate', function (b) { this._isPrivate = b; this.markAsChanged(); }, {category: ['accessing']});

  add.method('isInTrashCan', function () { return this._isInTrashCan; }, {category: ['accessing']});

  add.method('putInTrashCan', function () { this._isInTrashCan = true; this.markAsChanged(); }, {category: ['accessing']});

  add.method('module', function () { return modules.thisProject; }, {category: ['accessing']});

  add.method('inspect', function () { return this.name(); }, {category: ['printing']});

  add.method('toString', function () { return this.name(); }, {category: ['printing']});

  add.method('hasChangedSinceLastFileOut', function () {
    return this._hasChanged || this.module().haveIOrAnyOfMyRequirementsChangedSinceLastFileOut();
  }, {category: ['noticing changes']});

  add.method('markAsChanged', function () {
    this._hasChanged = true;
  }, {category: ['noticing changes']});

  add.method('markAsUnchanged', function () {
    this._hasChanged = false;
  }, {category: ['noticing changes']});

  add.method('togglePrivacy', function (evt) {
    this.setIsPrivate(! this.isPrivate());
  }, {category: ['commands']});

  add.method('grabRootModule', function (evt) {
    avocado.ui.grab(this.module(), evt);
  }, {category: ['commands']});

  add.method('rename', function (evt) {
    avocado.ui.prompt("New name?", function(n) { if (n) { this.setName(n); }}.bind(this), this.name(), evt);
  }, {category: ['commands']});

  add.method('save', function (evt) {
    var rootModule = this.module();
    var versionsToSave = {};
    var modulesNotToSave = {};
    var modulesLeftToLookAt = [this.module()];
    while (modulesLeftToLookAt.length > 0) {
      var m = modulesLeftToLookAt.pop();
      if (!modulesNotToSave[m.name()] && !versionsToSave[m.name()]) {
        // aaa - Could make this algorithm faster if each module knew who required him - just check
        // if m itself has changed, and if so then walk up the requirements chain making sure that
        // they're included.
        if (m === rootModule || m.haveIOrAnyOfMyRequirementsChangedSinceLastFileOut()) { // always save the root, just makes things simpler
          versionsToSave[m.name()] = m.createNewVersion();
          m.requirements().each(function(requiredModuleName) { modulesLeftToLookAt.push(modules[requiredModuleName])});
        } else {
          modulesNotToSave[m.name()] = m;
        }
      }
    }

    var moduleGraph = avocado.graphs.directed.create([this.module()], function(m) { return m.requiredModules(); });
    var sortedModules = moduleGraph.topologicalSort();
    var sortedVersionsToSave = [];
    sortedModules.each(function(m) {
      var v = versionsToSave[m.name()];
      if (v) { sortedVersionsToSave.push(v); }
    });

    var mockRepo = avocado.project.repository.create(this);
    mockRepo.setRoot(versionsToSave[this.module().name()]);
    var errors = transporter.fileOutPlural(sortedVersionsToSave.map(function(v) { return { moduleVersion: v }; }), evt, mockRepo, transporter.module.justBodyFilerOuter);
    if (errors.length === 0) {
      mockRepo.save(function() {
        this.markAsUnchanged();
        for (var moduleName in versionsToSave) {
          modules[moduleName].markAsUnchanged();
        }
      }.bind(this), function(failureReason) {
        console.log("Error saving " + this + ": " + failureReason);
      });
    } else {
      console.log("Not saving because there were transporter errors.");
    }
  }, {category: ['saving']});

  add.creator('repository', {}, {category: ['saving']});

  add.method('buttonCommands', function () {
    return avocado.command.list.create(this, [
      avocado.command.create('Save', this.save)
    ]);
  }, {category: ['user interface', 'commands']});

  add.method('commands', function () {
    return avocado.command.list.create(this, [
      avocado.command.create('save', this.save),
      avocado.command.create('rename', this.rename),
      avocado.command.create('get root module', this.grabRootModule),
      avocado.command.create(this.isPrivate() ? 'be public' : 'be private', this.togglePrivacy)
    ]);
  }, {category: ['user interface', 'commands']});

});

thisModule.addSlots(avocado.project.repository, function(add) {

  add.method('create', function (project) {
    return Object.newChildOf(this, project);
  }, {category: ['creating']});

  add.method('initialize', function (project) {
    this._project = project;
    this._projectData = {
      _id: project.id(),
      name: project.name(),
      isPrivate: project.isPrivate(),
      isInTrashCan: project.isInTrashCan(),
      modules: []
    };
  }, {category: ['creating']});

  add.method('setRoot', function (rootModuleVersion) {
    this._projectData.root = rootModuleVersion.versionID();
  }, {category: ['saving']});

  add.method('fileOutModuleVersion', function (moduleVersion, codeToFileOut, successBlock, failBlock) {
    this._projectData.modules.push({
      module: moduleVersion.module().name(),
      version: moduleVersion.versionID(),
      parents: moduleVersion.parentVersions().map(function(pv) { return pv.versionID(); }),
      reqs: moduleVersion.requiredModuleVersions().map(function(v) { return v.versionID(); }),
      code: codeToFileOut
    });
  }, {category: ['saving']});

  add.method('save', function (successBlock, failBlock) {
    var json = Object.toJSON(this._projectData);
    // aaa - I imagine it's possible to send the JSON without encoding it as a POST parameter, but let's not worry about it yet.
    var postBody = "projectDataJSON=" + encodeURIComponent(json);
    var url = "http://" + window.location.host + "/project/save";
    console.log("About to save the project to URL " + url + ", sending JSON:\n" + json);
    var req = new Ajax.Request(url, {
      method: 'post',
      //postBody: postBody,
      //contentType: 'application/x-www-form-urlencoded',
      postBody: json,
      contentType: 'application/json',

      asynchronous: true,
      onSuccess:   function(transport) { this.onSuccessfulPost(JSON.parse(transport.responseText), successBlock, failBlock); }.bind(this),
      onFailure:   function(t        ) { failBlock("Failed to file out project " + this._project + " to repository " + this + "; HTTP status code was " + req.getStatus()); }.bind(this),
      onException: function(r,      e) { failBlock("Failed to file out project " + this._project + " to repository " + this + "; exception was " + e); }.bind(this)
    });
  }, {category: ['saving']});

  add.method('onSuccessfulPost', function (responseJSON, successBlock, failBlock) {
    if (responseJSON.error) {
      failBlock("Server responded with error: " + responseJSON.error);
    } else {
      var realIDsByTempID = responseJSON;
      for (var tempID in realIDsByTempID) {
        transporter.idTracker.recordRealID(tempID, realIDsByTempID[tempID]);
      }
      successBlock();
    }
  }, {category: ['saving']});

});

});
<commit_msg>Added a hook so that the code to load a project can also set the project's name in the meta-info UI.<commit_after>transporter.module.create('projects/projects', function(requires) {}, function(thisModule) {

thisModule.addSlots(avocado, function(add) {

  add.creator('project', {}, {category: ['projects']});

});

thisModule.addSlots(avocado.project, function(add) {

  add.method('current', function () {
    return this._current || (this._current = this.create({ name: "This project" }));
  }, {category: ['current one']});

  add.method('setCurrent', function (p) {
    this._current = p;

    if (typeof(avocado.justSetCurrentProject) === 'function') {
      avocado.justSetCurrentProject(p);
    }
  }, {category: ['current one']});

  add.method('create', function (info) {
    return Object.newChildOf(this, info);
  }, {category: ['creating']});

  add.method('initialize', function (info) {
    this.setName(info.name);
    this.setIsPrivate(info.isPrivate);
    if (info._id) {
      this.setID(info._id);
    } else {
      transporter.idTracker.createTemporaryIDFor(this);
    }
    this.markAsUnchanged();
  }, {category: ['creating']});

  add.method('name', function () { return this._name; }, {category: ['accessing']});

  add.method('setName', function (n) { this._name = n; this.markAsChanged(); }, {category: ['accessing']});

  add.method('id', function () { return this._projectID; }, {category: ['accessing']});

  add.method('setID', function (id) { this._projectID = id; }, {category: ['accessing']});

  add.method('isPrivate', function () { return this._isPrivate; }, {category: ['accessing']});

  add.method('setIsPrivate', function (b) { this._isPrivate = b; this.markAsChanged(); }, {category: ['accessing']});

  add.method('isInTrashCan', function () { return this._isInTrashCan; }, {category: ['accessing']});

  add.method('putInTrashCan', function () { this._isInTrashCan = true; this.markAsChanged(); }, {category: ['accessing']});

  add.method('module', function () { return modules.thisProject; }, {category: ['accessing']});

  add.method('inspect', function () { return this.name(); }, {category: ['printing']});

  add.method('toString', function () { return this.name(); }, {category: ['printing']});

  add.method('hasChangedSinceLastFileOut', function () {
    return this._hasChanged || this.module().haveIOrAnyOfMyRequirementsChangedSinceLastFileOut();
  }, {category: ['noticing changes']});

  add.method('markAsChanged', function () {
    this._hasChanged = true;
  }, {category: ['noticing changes']});

  add.method('markAsUnchanged', function () {
    this._hasChanged = false;
  }, {category: ['noticing changes']});

  add.method('togglePrivacy', function (evt) {
    this.setIsPrivate(! this.isPrivate());
  }, {category: ['commands']});

  add.method('grabRootModule', function (evt) {
    avocado.ui.grab(this.module(), evt);
  }, {category: ['commands']});

  add.method('rename', function (evt) {
    avocado.ui.prompt("New name?", function(n) { if (n) { this.setName(n); }}.bind(this), this.name(), evt);
  }, {category: ['commands']});

  add.method('save', function (evt) {
    var rootModule = this.module();
    var versionsToSave = {};
    var modulesNotToSave = {};
    var modulesLeftToLookAt = [this.module()];
    while (modulesLeftToLookAt.length > 0) {
      var m = modulesLeftToLookAt.pop();
      if (!modulesNotToSave[m.name()] && !versionsToSave[m.name()]) {
        // aaa - Could make this algorithm faster if each module knew who required him - just check
        // if m itself has changed, and if so then walk up the requirements chain making sure that
        // they're included.
        if (m === rootModule || m.haveIOrAnyOfMyRequirementsChangedSinceLastFileOut()) { // always save the root, just makes things simpler
          versionsToSave[m.name()] = m.createNewVersion();
          m.requirements().each(function(requiredModuleName) { modulesLeftToLookAt.push(modules[requiredModuleName])});
        } else {
          modulesNotToSave[m.name()] = m;
        }
      }
    }

    var moduleGraph = avocado.graphs.directed.create([this.module()], function(m) { return m.requiredModules(); });
    var sortedModules = moduleGraph.topologicalSort();
    var sortedVersionsToSave = [];
    sortedModules.each(function(m) {
      var v = versionsToSave[m.name()];
      if (v) { sortedVersionsToSave.push(v); }
    });

    var mockRepo = avocado.project.repository.create(this);
    mockRepo.setRoot(versionsToSave[this.module().name()]);
    var errors = transporter.fileOutPlural(sortedVersionsToSave.map(function(v) { return { moduleVersion: v }; }), evt, mockRepo, transporter.module.justBodyFilerOuter);
    if (errors.length === 0) {
      mockRepo.save(function() {
        this.markAsUnchanged();
        for (var moduleName in versionsToSave) {
          modules[moduleName].markAsUnchanged();
        }
      }.bind(this), function(failureReason) {
        console.log("Error saving " + this + ": " + failureReason);
      });
    } else {
      console.log("Not saving because there were transporter errors.");
    }
  }, {category: ['saving']});

  add.creator('repository', {}, {category: ['saving']});

  add.method('buttonCommands', function () {
    return avocado.command.list.create(this, [
      avocado.command.create('Save', this.save)
    ]);
  }, {category: ['user interface', 'commands']});

  add.method('commands', function () {
    return avocado.command.list.create(this, [
      avocado.command.create('save', this.save),
      avocado.command.create('rename', this.rename),
      avocado.command.create('get root module', this.grabRootModule),
      avocado.command.create(this.isPrivate() ? 'be public' : 'be private', this.togglePrivacy)
    ]);
  }, {category: ['user interface', 'commands']});

});

thisModule.addSlots(avocado.project.repository, function(add) {

  add.method('create', function (project) {
    return Object.newChildOf(this, project);
  }, {category: ['creating']});

  add.method('initialize', function (project) {
    this._project = project;
    this._projectData = {
      _id: project.id(),
      name: project.name(),
      isPrivate: project.isPrivate(),
      isInTrashCan: project.isInTrashCan(),
      modules: []
    };
  }, {category: ['creating']});

  add.method('setRoot', function (rootModuleVersion) {
    this._projectData.root = rootModuleVersion.versionID();
  }, {category: ['saving']});

  add.method('fileOutModuleVersion', function (moduleVersion, codeToFileOut, successBlock, failBlock) {
    this._projectData.modules.push({
      module: moduleVersion.module().name(),
      version: moduleVersion.versionID(),
      parents: moduleVersion.parentVersions().map(function(pv) { return pv.versionID(); }),
      reqs: moduleVersion.requiredModuleVersions().map(function(v) { return v.versionID(); }),
      code: codeToFileOut
    });
  }, {category: ['saving']});

  add.method('save', function (successBlock, failBlock) {
    var json = Object.toJSON(this._projectData);
    // aaa - I imagine it's possible to send the JSON without encoding it as a POST parameter, but let's not worry about it yet.
    var postBody = "projectDataJSON=" + encodeURIComponent(json);
    var url = "http://" + window.location.host + "/project/save";
    console.log("About to save the project to URL " + url + ", sending JSON:\n" + json);
    var req = new Ajax.Request(url, {
      method: 'post',
      //postBody: postBody,
      //contentType: 'application/x-www-form-urlencoded',
      postBody: json,
      contentType: 'application/json',

      asynchronous: true,
      onSuccess:   function(transport) { this.onSuccessfulPost(JSON.parse(transport.responseText), successBlock, failBlock); }.bind(this),
      onFailure:   function(t        ) { failBlock("Failed to file out project " + this._project + " to repository " + this + "; HTTP status code was " + req.getStatus()); }.bind(this),
      onException: function(r,      e) { failBlock("Failed to file out project " + this._project + " to repository " + this + "; exception was " + e); }.bind(this)
    });
  }, {category: ['saving']});

  add.method('onSuccessfulPost', function (responseJSON, successBlock, failBlock) {
    if (responseJSON.error) {
      failBlock("Server responded with error: " + responseJSON.error);
    } else {
      var realIDsByTempID = responseJSON;
      for (var tempID in realIDsByTempID) {
        transporter.idTracker.recordRealID(tempID, realIDsByTempID[tempID]);
      }
      successBlock();
    }
  }, {category: ['saving']});

});

});
<|endoftext|>


<commit_before>$(document).ready(function() {

    /*========= HEADER HIDE-ON-SCROLL =========*/

    $(function() {
        $(window).scroll(function() {
            var winTop = $(window).scrollTop();
            if (winTop >= 30) {
                $("body").addClass("sticky-header");
            } else {
                $("body").removeClass("sticky-header");
            }
        });
    });

    /*=============== NAV SMOOTH SCROLL ===============*/

    $('a[href^="#"]').on('click', function(event) {

        var target = $($(this).attr('href'));

        if (target.length) {

            event.preventDefault();

            $('html, body').animate({
                scrollTop: target.offset().top
            }, 1000);
        }
    });

    /*========== PROJECT HOVER EFFECT ==========*/

    $(".hover").mouseleave(
        function() {
            $(this).removeClass("hover");
        }
    );

    /*========= PROJECT PAGE REDIRECTS =========*/

    $(".left-box").click(function() {
        window.location = "https://mike-crane.github.io/TIY-Chessboard";
    });

    $(".center-box").click(function() {
        window.location = "https://www.foodstre.am";
    });

    $(".right-box").click(function() {
        window.location = "https://mike-crane.github.io/responsive-icon-grid/";
    });

    $(".work-box.cxd1").click(function() {
        window.location = "https://www.carchexdeals.com/";
    });

    $(".work-box.3sv").click(function() {
        window.location = "http://3s.ventures";
    });

    $(".work-box.gd").click(function() {
        window.location = "https://glassdoctor.com/content/repair-broken-glass-window";
    });

    $(".work-box.cxd2").click(function() {
        window.location = "https://www.carchexdeals.com/FB-AD/protection_plan_quiz-g/index.html";
    });

    $(".work-box.cx").click(function() {
        window.location = "https://www.carchex.com/content/used-car-extended-warranty";
    });

    $(".work-box.cxd3").click(function() {
        window.location = "https://www.carchexdeals.com/branded-lp/index.html";
    });

});
<commit_msg>link fix<commit_after>$(document).ready(function() {

    /*========= HEADER HIDE-ON-SCROLL =========*/

    $(function() {
        $(window).scroll(function() {
            var winTop = $(window).scrollTop();
            if (winTop >= 30) {
                $("body").addClass("sticky-header");
            } else {
                $("body").removeClass("sticky-header");
            }
        });
    });

    /*=============== NAV SMOOTH SCROLL ===============*/

    $('a[href^="#"]').on('click', function(event) {

        var target = $($(this).attr('href'));

        if (target.length) {

            event.preventDefault();

            $('html, body').animate({
                scrollTop: target.offset().top
            }, 1000);
        }
    });

    /*========== PROJECT HOVER EFFECT ==========*/

    $(".hover").mouseleave(
        function() {
            $(this).removeClass("hover");
        }
    );

    /*========= PROJECT PAGE REDIRECTS =========*/

    $(".left-box").click(function() {
        window.location = "https://mike-crane.github.io/TIY-Chessboard";
    });

    $(".center-box").click(function() {
        window.location = "https://github.com/foodstream";
    });

    $(".right-box").click(function() {
        window.location = "https://mike-crane.github.io/responsive-icon-grid/";
    });

    $(".work-box.cxd1").click(function() {
        window.location = "https://www.carchexdeals.com/";
    });

    $(".work-box.3sv").click(function() {
        window.location = "http://3s.ventures";
    });

    $(".work-box.gd").click(function() {
        window.location = "https://glassdoctor.com/content/repair-broken-glass-window";
    });

    $(".work-box.cxd2").click(function() {
        window.location = "https://www.carchexdeals.com/FB-AD/protection_plan_quiz-g/index.html";
    });

    $(".work-box.cx").click(function() {
        window.location = "https://www.carchex.com/content/used-car-extended-warranty";
    });

    $(".work-box.cxd3").click(function() {
        window.location = "https://www.carchexdeals.com/branded-lp/index.html";
    });

});
<|endoftext|>