<commit_before>var logging = require("./logging");
var request = require("request");
var config = require("./config");
var fs = require("fs");

var session_url = "https://sessionserver.mojang.com/session/minecraft/profile/";
var skins_url = "https://skins.minecraft.net/MinecraftSkins/";
var capes_url = "https://skins.minecraft.net/MinecraftCloaks/";
var mojang_urls = [skins_url, capes_url];

var exp = {};

function extract_url(profile, property) {
  var url = null;
  if (profile && profile.properties) {
    profile.properties.forEach(function(prop) {
      if (prop.name === "textures") {
        var json = new Buffer(prop.value, "base64").toString();
        var props = JSON.parse(json);
        url = props && props.textures && props.textures[property] && props.textures[property].url || null;
      }
    });
  }
  return url;
}

// exracts the skin url of a +profile+ object
// returns null when no url found (user has no skin)
exp.extract_skin_url = function(profile) {
  return extract_url(profile, 'SKIN');
};

// exracts the cape url of a +profile+ object
// returns null when no url found (user has no cape)
exp.extract_cape_url = function(profile) {
  return extract_url(profile, 'CAPE');
};

// makes a GET request to the +url+
// +options+ hash includes various options for
// encoding and timeouts, defaults are already
// specified. +callback+ contains the body, response,
// and error buffer. get_from helper method is available
exp.get_from_options = function(rid, url, options, callback) {
  request.get({
    url: url,
    headers: {
      "User-Agent": "https://crafatar.com"
    },
    timeout: (options.timeout || config.http_timeout),
    encoding: (options.encoding || null),
    followRedirect: (options.folow_redirect || false),
    maxAttempts: (options.max_attempts || 2)
  }, function(error, response, body) {
    // 200 or 301 depending on content type
    if (!error && (response.statusCode === 200 || response.statusCode === 301)) {
      // response received successfully
      logging.log(rid + url + " url received");
      callback(body, response, null);
    } else if (error) {
      callback(body || null, response, error);
    } else if (response.statusCode === 404 || response.statusCode === 204) {
      // page does not exist
      logging.log(rid + url + " url does not exist");
      callback(null, response, null);
    } else if (response.statusCode === 429) {
      // Too Many Requests exception - code 429
      logging.warn(rid + url + " Too many requests");
      callback(body || null, response, error);
    } else {
      logging.error(rid + url + " Unknown error:");
      logging.error(rid + JSON.stringify(response));
      callback(body || null, response, error);
    }
  });
};

// helper method for get_from_options, no options required
exp.get_from = function(rid, url, callback) {
  exp.get_from_options(rid, url, {}, function(body, response, err) {
    callback(body, response, err);
  });
};

// make a request to skins.miencraft.net
// the skin url is taken from the HTTP redirect
// type reference is above
exp.get_username_url = function(rid, name, type, callback) {
  exp.get_from(rid, mojang_urls[type] + name + ".png", function(body, response, err) {
    if (!err) {
      callback(err, response ? (response.statusCode === 404 ? null : response.headers.location) : null);
    } else {
      callback(err, null);
    }
  });
};

// gets the URL for a skin/cape from the profile
// +type+ specifies which to retrieve
exp.get_uuid_url = function(profile, type, callback) {
  var url = null;
  if (type === 1) {
    url = exp.extract_skin_url(profile);
  } else if (type === 2) {
    url = exp.extract_cape_url(profile);
  }
  callback(url || null);
};

// make a request to sessionserver
// profile is returned as json
exp.get_profile = function(rid, uuid, callback) {
  if (!uuid) {
    callback(null, null);
  } else {
    exp.get_from_options(rid, session_url + uuid, { encoding: "utf8" }, function(body, response, err) {
      callback(err || null, (body !== null ? JSON.parse(body) : null));
    });
  }
};

// +userId+ is likely a username and if so
// +userId+ is used to get the url, otherwise
// +profile+ will be used to get the url
exp.get_skin_url = function(rid, userId, profile, callback) {
  get_url(rid, userId, profile, 0, function(url) {
    callback(url);
  });
};

// +userId+ is likely a username and if so
// +userId+ is used to get the url, otherwise
// +profile+ will be used to get the url
exp.get_cape_url = function(rid, userId, profile, callback) {
  get_url(rid, userId, profile, 1, function(url) {
    callback(url);
  });
};

function get_url(rid, userId, profile, type, callback) {
  if (userId.length <= 16) {
    //username
    exp.get_username_url(rid, userId, type, function(err, url) {
      callback(url || null);
    });
  } else {
    exp.get_uuid_url(profile, type, function(url) {
      callback(url || null);
    });
  }
}

exp.save_texture = function(rid, hash, outpath, callback) {
  if (hash) {
    var textureurl = "http://textures.minecraft.net/texture/" + hash;
    exp.get_from(rid, textureurl, function(img, response, err) {
      if (err) {
        logging.error(rid + "error while downloading texture");
        callback(err, response, null);
      } else {
        fs.writeFile(outpath, img, "binary", function(err) {
          if (err) {
            logging.log(rid + "error: " + err.stack);
          }
          callback(err, response, img);
        });
      }
    });
  } else {
    callback(null, null, null);
  }
};

module.exports = exp;<commit_msg>Resolve mismatched URL #s, closes #85, gg @jomo<commit_after>var logging = require("./logging");
var request = require("request");
var config = require("./config");
var fs = require("fs");

var session_url = "https://sessionserver.mojang.com/session/minecraft/profile/";
var skins_url = "https://skins.minecraft.net/MinecraftSkins/";
var capes_url = "https://skins.minecraft.net/MinecraftCloaks/";
var mojang_urls = [skins_url, capes_url];

var exp = {};

function extract_url(profile, property) {
  var url = null;
  if (profile && profile.properties) {
    profile.properties.forEach(function(prop) {
      if (prop.name === "textures") {
        var json = new Buffer(prop.value, "base64").toString();
        var props = JSON.parse(json);
        url = props && props.textures && props.textures[property] && props.textures[property].url || null;
      }
    });
  }
  return url;
}

// exracts the skin url of a +profile+ object
// returns null when no url found (user has no skin)
exp.extract_skin_url = function(profile) {
  return extract_url(profile, 'SKIN');
};

// exracts the cape url of a +profile+ object
// returns null when no url found (user has no cape)
exp.extract_cape_url = function(profile) {
  return extract_url(profile, 'CAPE');
};

// makes a GET request to the +url+
// +options+ hash includes various options for
// encoding and timeouts, defaults are already
// specified. +callback+ contains the body, response,
// and error buffer. get_from helper method is available
exp.get_from_options = function(rid, url, options, callback) {
  request.get({
    url: url,
    headers: {
      "User-Agent": "https://crafatar.com"
    },
    timeout: (options.timeout || config.http_timeout),
    encoding: (options.encoding || null),
    followRedirect: (options.folow_redirect || false),
    maxAttempts: (options.max_attempts || 2)
  }, function(error, response, body) {
    // 200 or 301 depending on content type
    if (!error && (response.statusCode === 200 || response.statusCode === 301)) {
      // response received successfully
      logging.log(rid + url + " url received");
      callback(body, response, null);
    } else if (error) {
      callback(body || null, response, error);
    } else if (response.statusCode === 404 || response.statusCode === 204) {
      // page does not exist
      logging.log(rid + url + " url does not exist");
      callback(null, response, null);
    } else if (response.statusCode === 429) {
      // Too Many Requests exception - code 429
      logging.warn(rid + url + " Too many requests");
      callback(body || null, response, error);
    } else {
      logging.error(rid + url + " Unknown error:");
      logging.error(rid + JSON.stringify(response));
      callback(body || null, response, error);
    }
  });
};

// helper method for get_from_options, no options required
exp.get_from = function(rid, url, callback) {
  exp.get_from_options(rid, url, {}, function(body, response, err) {
    callback(body, response, err);
  });
};

// make a request to skins.miencraft.net
// the skin url is taken from the HTTP redirect
// type reference is above
exp.get_username_url = function(rid, name, type, callback) {
  console.log(mojang_urls[type])
  exp.get_from(rid, mojang_urls[type] + name + ".png", function(body, response, err) {
    if (!err) {
      callback(err, response ? (response.statusCode === 404 ? null : response.headers.location) : null);
    } else {
      callback(err, null);
    }
  });
};

// gets the URL for a skin/cape from the profile
// +type+ specifies which to retrieve
exp.get_uuid_url = function(profile, type, callback) {
  var url = null;
  if (type === 0) {
    url = exp.extract_skin_url(profile);
  } else if (type === 1) {
    url = exp.extract_cape_url(profile);
  }
  callback(url || null);
};

// make a request to sessionserver
// profile is returned as json
exp.get_profile = function(rid, uuid, callback) {
  if (!uuid) {
    callback(null, null);
  } else {
    exp.get_from_options(rid, session_url + uuid, { encoding: "utf8" }, function(body, response, err) {
      callback(err || null, (body !== null ? JSON.parse(body) : null));
    });
  }
};

// +userId+ is likely a username and if so
// +userId+ is used to get the url, otherwise
// +profile+ will be used to get the url
exp.get_skin_url = function(rid, userId, profile, callback) {
  get_url(rid, userId, profile, 0, function(url) {
    callback(url);
  });
};

// +userId+ is likely a username and if so
// +userId+ is used to get the url, otherwise
// +profile+ will be used to get the url
exp.get_cape_url = function(rid, userId, profile, callback) {
  get_url(rid, userId, profile, 1, function(url) {
    callback(url);
  });
};

function get_url(rid, userId, profile, type, callback) {
  if (userId.length <= 16) {
    //username
    exp.get_username_url(rid, userId, type, function(err, url) {
      callback(url || null);
    });
  } else {
    exp.get_uuid_url(profile, type, function(url) {
      callback(url || null);
    });
  }
}

exp.save_texture = function(rid, hash, outpath, callback) {
  if (hash) {
    var textureurl = "http://textures.minecraft.net/texture/" + hash;
    exp.get_from(rid, textureurl, function(img, response, err) {
      if (err) {
        logging.error(rid + "error while downloading texture");
        callback(err, response, null);
      } else {
        fs.writeFile(outpath, img, "binary", function(err) {
          if (err) {
            logging.log(rid + "error: " + err.stack);
          }
          callback(err, response, img);
        });
      }
    });
  } else {
    callback(null, null, null);
  }
};

module.exports = exp;<|endoftext|>


<commit_before>const parser = require('ua-parser-js');
const { uniqueNamesGenerator, animals, colors } = require('unique-names-generator');

class SnapdropServer {

    constructor(port) {
        const WebSocket = require('ws');
        this._wss = new WebSocket.Server({ port: port });
        this._wss.on('connection', (socket, request) => this._onConnection(new Peer(socket, request)));
        this._wss.on('headers', (headers, response) => this._onHeaders(headers, response));

        this._rooms = {};

        console.log('Snapdrop is running on port', port);
    }

    _onConnection(peer) {
        this._joinRoom(peer);
        peer.socket.on('message', message => this._onMessage(peer, message));
        this._keepAlive(peer);

        // send displayName
        this._send(peer, { type: 'displayName', message: peer.name.displayName });
    }

    _onHeaders(headers, response) {
        if (response.headers.cookie && response.headers.cookie.indexOf('peerid=') > -1) return;
        response.peerId = Peer.uuid();
        headers.push('Set-Cookie: peerid=' + response.peerId + "; SameSite=Strict; Secure");
    }

    _onMessage(sender, message) {
        // Try to parse message
        try {
            message = JSON.parse(message);
        } catch (e) {
            return; // TODO: handle malformed JSON
        }

        switch (message.type) {
            case 'disconnect':
                this._leaveRoom(sender);
                break;
            case 'pong':
                sender.lastBeat = Date.now();
                break;
        }

        // relay message to recipient
        if (message.to && this._rooms[sender.ip]) {
            const recipientId = message.to; // TODO: sanitize
            const recipient = this._rooms[sender.ip][recipientId];
            delete message.to;
            // add sender id
            message.sender = sender.id;
            this._send(recipient, message);
            return;
        }
    }

    _joinRoom(peer) {
        // if room doesn't exist, create it
        if (!this._rooms[peer.ip]) {
            this._rooms[peer.ip] = {};
        }

        // notify all other peers
        for (const otherPeerId in this._rooms[peer.ip]) {
            const otherPeer = this._rooms[peer.ip][otherPeerId];
            this._send(otherPeer, {
                type: 'peer-joined',
                peer: peer.getInfo()
            });
        }

        // notify peer about the other peers
        const otherPeers = [];
        for (const otherPeerId in this._rooms[peer.ip]) {
            otherPeers.push(this._rooms[peer.ip][otherPeerId].getInfo());
        }

        this._send(peer, {
            type: 'peers',
            peers: otherPeers
        });

        // add peer to room
        this._rooms[peer.ip][peer.id] = peer;
    }

    _leaveRoom(peer) {
        if (!this._rooms[peer.ip] || !this._rooms[peer.ip][peer.id]) return;
        this._cancelKeepAlive(this._rooms[peer.ip][peer.id]);

        // delete the peer
        delete this._rooms[peer.ip][peer.id];

        peer.socket.terminate();
        //if room is empty, delete the room
        if (!Object.keys(this._rooms[peer.ip]).length) {
            delete this._rooms[peer.ip];
        } else {
            // notify all other peers
            for (const otherPeerId in this._rooms[peer.ip]) {
                const otherPeer = this._rooms[peer.ip][otherPeerId];
                this._send(otherPeer, { type: 'peer-left', peerId: peer.id });
            }
        }
    }

    _send(peer, message) {
        if (!peer) return;
        if (this._wss.readyState !== this._wss.OPEN) return;
        message = JSON.stringify(message);
        peer.socket.send(message, error => '');
    }

    _keepAlive(peer) {
        this._cancelKeepAlive(peer);
        var timeout = 30000;
        if (!peer.lastBeat) {
            peer.lastBeat = Date.now();
        }
        if (Date.now() - peer.lastBeat > 2 * timeout) {
            this._leaveRoom(peer);
            return;
        }

        this._send(peer, { type: 'ping' });

        peer.timerId = setTimeout(() => this._keepAlive(peer), timeout);
    }

    _cancelKeepAlive(peer) {
        if (peer && peer.timerId) {
            clearTimeout(peer.timerId);
        }
    }
}

class Peer {

    constructor(socket, request) {
        // set socket
        this.socket = socket;

        // set remote ip
        this._setIP(request);

        // set peer id
        this._setPeerId(request)
        // is WebRTC supported ?
        this.rtcSupported = request.url.indexOf('webrtc') > -1;
        // set name
        this._setName(request);
        // for keepalive
        this.timerId = 0;
        this.lastBeat = Date.now();
    }

    _setIP(request) {
        if (request.headers['x-forwarded-for']) {
            this.ip = request.headers['x-forwarded-for'].split(/\s*,\s*/)[0];
        } else {
            this.ip = request.connection.remoteAddress;
        }
        // IPv4 and IPv6 use different values to refer to localhost
        if (this.ip == '::1' || this.ip == '::ffff:127.0.0.1') {
            this.ip = '127.0.0.1';
        }
    }

    _setPeerId(request) {
        if (request.peerId) {
            this.id = request.peerId;
        } else {
            this.id = request.headers.cookie.replace('peerid=', '');
        }
    }

    toString() {
        return `<Peer id=${this.id} ip=${this.ip} rtcSupported=${this.rtcSupported}>`
    }

    _setName(req) {
        var ua = parser(req.headers['user-agent']);
        this.name = {
            model: ua.device.model,
            os: ua.os.name,
            browser: ua.browser.name,
            type: ua.device.type,
            displayName: uniqueNamesGenerator({ length: 2, separator: ' ', dictionaries: [colors, animals], style: 'capital' })
        };
    }

    getInfo() {
        return {
            id: this.id,
            name: this.name,
            rtcSupported: this.rtcSupported
        }
    }

    // return uuid of form xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
    static uuid() {
        let uuid = '',
            ii;
        for (ii = 0; ii < 32; ii += 1) {
            switch (ii) {
                case 8:
                case 20:
                    uuid += '-';
                    uuid += (Math.random() * 16 | 0).toString(16);
                    break;
                case 12:
                    uuid += '-';
                    uuid += '4';
                    break;
                case 16:
                    uuid += '-';
                    uuid += (Math.random() * 4 | 8).toString(16);
                    break;
                default:
                    uuid += (Math.random() * 16 | 0).toString(16);
            }
        }
        return uuid;
    };
}

const server = new SnapdropServer(process.env.PORT || 3000);
<commit_msg>Use device type as display name<commit_after>const parser = require('ua-parser-js');

class SnapdropServer {

    constructor(port) {
        const WebSocket = require('ws');
        this._wss = new WebSocket.Server({ port: port });
        this._wss.on('connection', (socket, request) => this._onConnection(new Peer(socket, request)));
        this._wss.on('headers', (headers, response) => this._onHeaders(headers, response));

        this._rooms = {};

        console.log('Snapdrop is running on port', port);
    }

    _onConnection(peer) {
        this._joinRoom(peer);
        peer.socket.on('message', message => this._onMessage(peer, message));
        this._keepAlive(peer);

        // send displayName
        this._send(peer, { type: 'displayName', message: peer.name.displayName });
    }

    _onHeaders(headers, response) {
        if (response.headers.cookie && response.headers.cookie.indexOf('peerid=') > -1) return;
        response.peerId = Peer.uuid();
        headers.push('Set-Cookie: peerid=' + response.peerId + "; SameSite=Strict; Secure");
    }

    _onMessage(sender, message) {
        // Try to parse message
        try {
            message = JSON.parse(message);
        } catch (e) {
            return; // TODO: handle malformed JSON
        }

        switch (message.type) {
            case 'disconnect':
                this._leaveRoom(sender);
                break;
            case 'pong':
                sender.lastBeat = Date.now();
                break;
        }

        // relay message to recipient
        if (message.to && this._rooms[sender.ip]) {
            const recipientId = message.to; // TODO: sanitize
            const recipient = this._rooms[sender.ip][recipientId];
            delete message.to;
            // add sender id
            message.sender = sender.id;
            this._send(recipient, message);
            return;
        }
    }

    _joinRoom(peer) {
        // if room doesn't exist, create it
        if (!this._rooms[peer.ip]) {
            this._rooms[peer.ip] = {};
        }

        // notify all other peers
        for (const otherPeerId in this._rooms[peer.ip]) {
            const otherPeer = this._rooms[peer.ip][otherPeerId];
            this._send(otherPeer, {
                type: 'peer-joined',
                peer: peer.getInfo()
            });
        }

        // notify peer about the other peers
        const otherPeers = [];
        for (const otherPeerId in this._rooms[peer.ip]) {
            otherPeers.push(this._rooms[peer.ip][otherPeerId].getInfo());
        }

        this._send(peer, {
            type: 'peers',
            peers: otherPeers
        });

        // add peer to room
        this._rooms[peer.ip][peer.id] = peer;
    }

    _leaveRoom(peer) {
        if (!this._rooms[peer.ip] || !this._rooms[peer.ip][peer.id]) return;
        this._cancelKeepAlive(this._rooms[peer.ip][peer.id]);

        // delete the peer
        delete this._rooms[peer.ip][peer.id];

        peer.socket.terminate();
        //if room is empty, delete the room
        if (!Object.keys(this._rooms[peer.ip]).length) {
            delete this._rooms[peer.ip];
        } else {
            // notify all other peers
            for (const otherPeerId in this._rooms[peer.ip]) {
                const otherPeer = this._rooms[peer.ip][otherPeerId];
                this._send(otherPeer, { type: 'peer-left', peerId: peer.id });
            }
        }
    }

    _send(peer, message) {
        if (!peer) return;
        if (this._wss.readyState !== this._wss.OPEN) return;
        message = JSON.stringify(message);
        peer.socket.send(message, error => '');
    }

    _keepAlive(peer) {
        this._cancelKeepAlive(peer);
        var timeout = 30000;
        if (!peer.lastBeat) {
            peer.lastBeat = Date.now();
        }
        if (Date.now() - peer.lastBeat > 2 * timeout) {
            this._leaveRoom(peer);
            return;
        }

        this._send(peer, { type: 'ping' });

        peer.timerId = setTimeout(() => this._keepAlive(peer), timeout);
    }

    _cancelKeepAlive(peer) {
        if (peer && peer.timerId) {
            clearTimeout(peer.timerId);
        }
    }
}

class Peer {

    constructor(socket, request) {
        // set socket
        this.socket = socket;

        // set remote ip
        this._setIP(request);

        // set peer id
        this._setPeerId(request)
        // is WebRTC supported ?
        this.rtcSupported = request.url.indexOf('webrtc') > -1;
        // set name
        this._setName(request);
        // for keepalive
        this.timerId = 0;
        this.lastBeat = Date.now();
    }

    _setIP(request) {
        if (request.headers['x-forwarded-for']) {
            this.ip = request.headers['x-forwarded-for'].split(/\s*,\s*/)[0];
        } else {
            this.ip = request.connection.remoteAddress;
        }
        // IPv4 and IPv6 use different values to refer to localhost
        if (this.ip == '::1' || this.ip == '::ffff:127.0.0.1') {
            this.ip = '127.0.0.1';
        }
    }

    _setPeerId(request) {
        if (request.peerId) {
            this.id = request.peerId;
        } else {
            this.id = request.headers.cookie.replace('peerid=', '');
        }
    }

    toString() {
        return `<Peer id=${this.id} ip=${this.ip} rtcSupported=${this.rtcSupported}>`
    }

    _setName(req) {
        let ua = parser(req.headers['user-agent']);

        let displayName = ua.os.name.replace('Mac OS', 'Mac') + ' ';
        if (ua.device.model) {
            displayName += ua.device.model;
        } else {
            displayName += ua.browser.name;
        }

        this.name = {
            model: ua.device.model,
            os: ua.os.name,
            browser: ua.browser.name,
            type: ua.device.type,
            displayName: displayName
        };
    }

    getInfo() {
        return {
            id: this.id,
            name: this.name,
            rtcSupported: this.rtcSupported
        }
    }

    // return uuid of form xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
    static uuid() {
        let uuid = '',
            ii;
        for (ii = 0; ii < 32; ii += 1) {
            switch (ii) {
                case 8:
                case 20:
                    uuid += '-';
                    uuid += (Math.random() * 16 | 0).toString(16);
                    break;
                case 12:
                    uuid += '-';
                    uuid += '4';
                    break;
                case 16:
                    uuid += '-';
                    uuid += (Math.random() * 4 | 8).toString(16);
                    break;
                default:
                    uuid += (Math.random() * 16 | 0).toString(16);
            }
        }
        return uuid;
    };
}

const server = new SnapdropServer(process.env.PORT || 3000);<|endoftext|>


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

/**
 * Checks if the provided object is an instance of WP_Error class.
 *
 * @since n.e.x.t
 *
 * @param {Object} obj The object to check.
 * @return {boolean} TRUE if the object has "code", "data" and "message" properties, otherwise FALSE.
 */
export function isWPError( obj ) {
	return typeof obj === 'object' &&
		obj.hasOwnProperty( 'code' ) && ( typeof obj.code === 'string' || typeof obj.code === 'number' ) &&
		obj.hasOwnProperty( 'message' ) && typeof obj.message === 'string' &&
		obj.hasOwnProperty( 'data' ); // We don't check "obj.data" type because it can be anything.
}
<commit_msg>Update isWPError function to use isPlainObject.<commit_after>/**
 * WP Error Utilities.
 *
 * Site Kit by Google, Copyright 2020 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * External dependencies
 */
import isPlainObject from 'lodash/isPlainObject';

/**
 * Checks if the provided object is an instance of WP_Error class.
 *
 * @since n.e.x.t
 *
 * @param {Object} obj The object to check.
 * @return {boolean} TRUE if the object has "code", "data" and "message" properties, otherwise FALSE.
 */
export function isWPError( obj ) {
	return isPlainObject( obj ) &&
		obj.hasOwnProperty( 'code' ) && ( typeof obj.code === 'string' || typeof obj.code === 'number' ) &&
		obj.hasOwnProperty( 'message' ) && typeof obj.message === 'string' &&
		obj.hasOwnProperty( 'data' ); // We don't check "obj.data" type because it can be anything.
}
<|endoftext|>


<commit_before>/*
eslint-disable no-console
*/
var path = require('path');
var express = require('express');
var session = require('express-session');
var TingoStore = require('connect-tingo')({session});
var bodyParser = require('body-parser');
var cookieParser = require('cookie-parser');
var passport = require('passport');

var appPort = 8080;

var cron = require('../service/cron');
cron();

var app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));

require('./authentication').init(app);
var settings = {
  cookieSecret: require('crypto').randomBytes(64).toString('hex'),
  folderLocation:  path.resolve(__dirname, '../service/database/data')
};
app.use(cookieParser());
app.use(session({
    secret: settings.cookieSecret,
    store: new TingoStore({
      db: settings.folderLocation
    }),
    resave: false,
    saveUninitialized: false
}));

app.use(passport.initialize());
app.use(passport.session());

require('./routes')(app, passport);

app.use('/', express.static(
  path.resolve(__dirname, '../client'),
  {
        setHeaders: (res) => {
            res.setHeader('x-powered-by', 'Foo')
        },
        redirect: false
    }
));

app.listen(appPort, function () {
  console.log('New server on port ' + appPort + '!');
});
<commit_msg>add etag to server responses<commit_after>/*
eslint-disable no-console
*/
var path = require('path');
var express = require('express');
var session = require('express-session');
var TingoStore = require('connect-tingo')({session});
var bodyParser = require('body-parser');
var cookieParser = require('cookie-parser');
var passport = require('passport');

var appPort = 8080;

var cron = require('../service/cron');
cron();

var app = express();
app.enable('etag', 'strong');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));

require('./authentication').init(app);
var settings = {
  cookieSecret: require('crypto').randomBytes(64).toString('hex'),
  folderLocation:  path.resolve(__dirname, '../service/database/data')
};
app.use(cookieParser());
app.use(session({
    secret: settings.cookieSecret,
    store: new TingoStore({
      db: settings.folderLocation
    }),
    resave: false,
    saveUninitialized: false
}));

app.use(passport.initialize());
app.use(passport.session());

require('./routes')(app, passport);

app.use('/', express.static(
  path.resolve(__dirname, '../client'),
  {
        setHeaders: (res) => {
            res.setHeader('x-powered-by', 'Foo')
        },
        redirect: false
    }
));

app.listen(appPort, function () {
  console.log('New server on port ' + appPort + '!');
});
<|endoftext|>


<commit_before>let JudgeState = syzoj.model('judge_state');
let FormattedCode = syzoj.model('formatted_code');
let User = syzoj.model('user');
let Contest = syzoj.model('contest');
let Problem = syzoj.model('problem');

const jwt = require('jsonwebtoken');
const { getSubmissionInfo, getRoughResult, processOverallResult } = require('../libs/submissions_process');

const displayConfig = {
  showScore: true,
  showUsage: true,
  showCode: true,
  showResult: true,
  showOthers: true,
  showTestdata: true,
  showDetailResult: true,
  inContest: false,
  showRejudge: false
};

// s is JudgeState
app.get('/submissions', async (req, res) => {
  try {
    const curUser = res.locals.user;
    let user = await User.fromName(req.query.submitter || '');
    let where = {};
    let inContest = false;
    if (user) where.user_id = user.id;
    else if (req.query.submitter) where.user_id = -1;

    if (!req.query.contest) {
      where.type = { $eq: 0 };
    } else {
      const contestId = Number(req.query.contest);
      const contest = await Contest.fromID(contestId);
      contest.ended = contest.isEnded();
      if ((contest.ended && contest.is_public) || // If the contest is ended and is not hidden
        (curUser && await contest.isSupervisior(curUser)) // Or if the user have the permission to check
      ) {
        where.type = { $eq: 1 };
        where.type_info = { $eq: contestId };
        inContest = true;
      } else {
        throw new Error("您暂时无权查看此比赛的详细评测信息。");
      }
    }

    let minScore = parseInt(req.query.min_score);
    let maxScore = parseInt(req.query.max_score);

    if (!isNaN(minScore) || !isNaN(maxScore)) {
      if (isNaN(minScore)) minScore = 0;
      if (isNaN(maxScore)) maxScore = 100;
      if (!(minScore === 0 && maxScore === 100)) {
        where.score = {
          $and: {
            $gte: parseInt(minScore),
            $lte: parseInt(maxScore)
          }
        };
      }
    }

    if (req.query.language) {
      if (req.query.language === 'submit-answer') where.language = { $or: [{ $eq: '',  }, { $eq: null }] };
      else if (req.query.language === 'non-submit-answer') where.language = { $not: '' };
      else where.language = req.query.language;
    }
    if (req.query.status) where.status = { $like: req.query.status + '%' };

    if (!inContest && (!curUser || !await curUser.hasPrivilege('manage_problem'))) {
      if (req.query.problem_id) {
        let problem_id = parseInt(req.query.problem_id);
        let problem = await Problem.fromID(problem_id);
        if (!problem)
          throw new ErrorMessage("无此题目。");
        if (await problem.isAllowedUseBy(res.locals.user)) {
          where.problem_id = {
            $and: [
              { $eq: where.problem_id = problem_id }
            ]
          };
        } else {
          throw new ErrorMessage("您没有权限进行此操作。");
        }
      } else {
        where.is_public = {
          $eq: true,
        };
      }
    } else {
      if (req.query.problem_id) where.problem_id = parseInt(req.query.problem_id) || -1;
    }

    let isFiltered = !!(where.problem_id || where.user_id || where.score || where.language || where.status);

    let paginate = syzoj.utils.paginate(await JudgeState.count(where), req.query.page, syzoj.config.page.judge_state);
    let judge_state = await JudgeState.query(paginate, where, [['id', 'desc']], true);

    await judge_state.forEachAsync(async obj => {
      await obj.loadRelationships();
      obj.code_length = obj.code.length;
    })

    res.render('submissions', {
      // judge_state: judge_state,
      items: judge_state.map(x => ({
        info: getSubmissionInfo(x, displayConfig),
        token: (x.pending && x.task_id != null) ? jwt.sign({
          taskId: x.task_id,
          type: 'rough',
          displayConfig: displayConfig
        }, syzoj.config.session_secret) : null,
        result: getRoughResult(x, displayConfig, true),
        running: false,
      })),
      paginate: paginate,
      pushType: 'rough',
      form: req.query,
      displayConfig: displayConfig,
      isFiltered: isFiltered
    });
  } catch (e) {
    syzoj.log(e);
    res.render('error', {
      err: e
    });
  }
});

app.get('/submission/:id', async (req, res) => {
  try {
    const id = parseInt(req.params.id);
    const judge = await JudgeState.fromID(id);
    if (!judge) throw new ErrorMessage("提交记录 ID 不正确。");
    const curUser = res.locals.user;
    if (!await judge.isAllowedVisitBy(curUser)) throw new ErrorMessage('您没有权限进行此操作。');

    let contest;
    if (judge.type === 1) {
      contest = await Contest.fromID(judge.type_info);
      contest.ended = contest.isEnded();

      if ((!contest.ended || !contest.is_public) &&
        !(await judge.problem.isAllowedEditBy(res.locals.user) || await contest.isSupervisior(curUser))) {
        throw new Error("比赛没有结束或者没有公开哦");
      }
    }

    await judge.loadRelationships();

    if (judge.problem.type !== 'submit-answer') {
      judge.code_length = judge.code.length;

      let key = syzoj.utils.getFormattedCodeKey(judge.code, judge.language);
      if (key) {
        let formattedCode = await FormattedCode.findOne({
          where: {
            key: key
          }
        });

        if (formattedCode) {
          judge.formattedCode = await syzoj.utils.highlight(formattedCode.code, syzoj.languages[judge.language].highlight);
        }
      }
      judge.code = await syzoj.utils.highlight(judge.code, syzoj.languages[judge.language].highlight);
    }

    displayConfig.showRejudge = await judge.problem.isAllowedEditBy(res.locals.user);
    res.render('submission', {
      info: getSubmissionInfo(judge, displayConfig),
      roughResult: getRoughResult(judge, displayConfig, false),
      code: (judge.problem.type !== 'submit-answer') ? judge.code.toString("utf8") : '',
      formattedCode: judge.formattedCode ? judge.formattedCode.toString("utf8") : null,
      preferFormattedCode: res.locals.user ? res.locals.user.prefer_formatted_code : false,
      detailResult: processOverallResult(judge.result, displayConfig),
      socketToken: (judge.pending && judge.task_id != null) ? jwt.sign({
        taskId: judge.task_id,
        type: 'detail',
        displayConfig: displayConfig
      }, syzoj.config.session_secret) : null,
      displayConfig: displayConfig,
    });
  } catch (e) {
    syzoj.log(e);
    res.render('error', {
      err: e
    });
  }
});

app.post('/submission/:id/rejudge', async (req, res) => {
  try {
    let id = parseInt(req.params.id);
    let judge = await JudgeState.fromID(id);

    if (judge.pending && !(res.locals.user && await res.locals.user.hasPrivilege('manage_problem'))) throw new ErrorMessage('无法重新评测一个评测中的提交。');

    await judge.loadRelationships();

    let allowedRejudge = await judge.problem.isAllowedEditBy(res.locals.user);
    if (!allowedRejudge) throw new ErrorMessage('您没有权限进行此操作。');

    await judge.rejudge();

    res.redirect(syzoj.utils.makeUrl(['submission', id]));
  } catch (e) {
    syzoj.log(e);
    res.render('error', {
      err: e
    });
  }
});
<commit_msg>Fix wrong answer size for submit answer problem's submissions<commit_after>let JudgeState = syzoj.model('judge_state');
let FormattedCode = syzoj.model('formatted_code');
let User = syzoj.model('user');
let Contest = syzoj.model('contest');
let Problem = syzoj.model('problem');

const jwt = require('jsonwebtoken');
const { getSubmissionInfo, getRoughResult, processOverallResult } = require('../libs/submissions_process');

const displayConfig = {
  showScore: true,
  showUsage: true,
  showCode: true,
  showResult: true,
  showOthers: true,
  showTestdata: true,
  showDetailResult: true,
  inContest: false,
  showRejudge: false
};

// s is JudgeState
app.get('/submissions', async (req, res) => {
  try {
    const curUser = res.locals.user;
    let user = await User.fromName(req.query.submitter || '');
    let where = {};
    let inContest = false;
    if (user) where.user_id = user.id;
    else if (req.query.submitter) where.user_id = -1;

    if (!req.query.contest) {
      where.type = { $eq: 0 };
    } else {
      const contestId = Number(req.query.contest);
      const contest = await Contest.fromID(contestId);
      contest.ended = contest.isEnded();
      if ((contest.ended && contest.is_public) || // If the contest is ended and is not hidden
        (curUser && await contest.isSupervisior(curUser)) // Or if the user have the permission to check
      ) {
        where.type = { $eq: 1 };
        where.type_info = { $eq: contestId };
        inContest = true;
      } else {
        throw new Error("您暂时无权查看此比赛的详细评测信息。");
      }
    }

    let minScore = parseInt(req.query.min_score);
    let maxScore = parseInt(req.query.max_score);

    if (!isNaN(minScore) || !isNaN(maxScore)) {
      if (isNaN(minScore)) minScore = 0;
      if (isNaN(maxScore)) maxScore = 100;
      if (!(minScore === 0 && maxScore === 100)) {
        where.score = {
          $and: {
            $gte: parseInt(minScore),
            $lte: parseInt(maxScore)
          }
        };
      }
    }

    if (req.query.language) {
      if (req.query.language === 'submit-answer') where.language = { $or: [{ $eq: '',  }, { $eq: null }] };
      else if (req.query.language === 'non-submit-answer') where.language = { $not: '' };
      else where.language = req.query.language;
    }
    if (req.query.status) where.status = { $like: req.query.status + '%' };

    if (!inContest && (!curUser || !await curUser.hasPrivilege('manage_problem'))) {
      if (req.query.problem_id) {
        let problem_id = parseInt(req.query.problem_id);
        let problem = await Problem.fromID(problem_id);
        if (!problem)
          throw new ErrorMessage("无此题目。");
        if (await problem.isAllowedUseBy(res.locals.user)) {
          where.problem_id = {
            $and: [
              { $eq: where.problem_id = problem_id }
            ]
          };
        } else {
          throw new ErrorMessage("您没有权限进行此操作。");
        }
      } else {
        where.is_public = {
          $eq: true,
        };
      }
    } else {
      if (req.query.problem_id) where.problem_id = parseInt(req.query.problem_id) || -1;
    }

    let isFiltered = !!(where.problem_id || where.user_id || where.score || where.language || where.status);

    let paginate = syzoj.utils.paginate(await JudgeState.count(where), req.query.page, syzoj.config.page.judge_state);
    let judge_state = await JudgeState.query(paginate, where, [['id', 'desc']], true);

    await judge_state.forEachAsync(async obj => {
      await obj.loadRelationships();
      if (obj.problem.type !== 'submit-answer') obj.code_length = obj.code.length;
    })

    res.render('submissions', {
      // judge_state: judge_state,
      items: judge_state.map(x => ({
        info: getSubmissionInfo(x, displayConfig),
        token: (x.pending && x.task_id != null) ? jwt.sign({
          taskId: x.task_id,
          type: 'rough',
          displayConfig: displayConfig
        }, syzoj.config.session_secret) : null,
        result: getRoughResult(x, displayConfig, true),
        running: false,
      })),
      paginate: paginate,
      pushType: 'rough',
      form: req.query,
      displayConfig: displayConfig,
      isFiltered: isFiltered
    });
  } catch (e) {
    syzoj.log(e);
    res.render('error', {
      err: e
    });
  }
});

app.get('/submission/:id', async (req, res) => {
  try {
    const id = parseInt(req.params.id);
    const judge = await JudgeState.fromID(id);
    if (!judge) throw new ErrorMessage("提交记录 ID 不正确。");
    const curUser = res.locals.user;
    if (!await judge.isAllowedVisitBy(curUser)) throw new ErrorMessage('您没有权限进行此操作。');

    let contest;
    if (judge.type === 1) {
      contest = await Contest.fromID(judge.type_info);
      contest.ended = contest.isEnded();

      if ((!contest.ended || !contest.is_public) &&
        !(await judge.problem.isAllowedEditBy(res.locals.user) || await contest.isSupervisior(curUser))) {
        throw new Error("比赛没有结束或者没有公开哦");
      }
    }

    await judge.loadRelationships();

    if (judge.problem.type !== 'submit-answer') {
      judge.code_length = judge.code.length;

      let key = syzoj.utils.getFormattedCodeKey(judge.code, judge.language);
      if (key) {
        let formattedCode = await FormattedCode.findOne({
          where: {
            key: key
          }
        });

        if (formattedCode) {
          judge.formattedCode = await syzoj.utils.highlight(formattedCode.code, syzoj.languages[judge.language].highlight);
        }
      }
      judge.code = await syzoj.utils.highlight(judge.code, syzoj.languages[judge.language].highlight);
    }

    displayConfig.showRejudge = await judge.problem.isAllowedEditBy(res.locals.user);
    res.render('submission', {
      info: getSubmissionInfo(judge, displayConfig),
      roughResult: getRoughResult(judge, displayConfig, false),
      code: (judge.problem.type !== 'submit-answer') ? judge.code.toString("utf8") : '',
      formattedCode: judge.formattedCode ? judge.formattedCode.toString("utf8") : null,
      preferFormattedCode: res.locals.user ? res.locals.user.prefer_formatted_code : false,
      detailResult: processOverallResult(judge.result, displayConfig),
      socketToken: (judge.pending && judge.task_id != null) ? jwt.sign({
        taskId: judge.task_id,
        type: 'detail',
        displayConfig: displayConfig
      }, syzoj.config.session_secret) : null,
      displayConfig: displayConfig,
    });
  } catch (e) {
    syzoj.log(e);
    res.render('error', {
      err: e
    });
  }
});

app.post('/submission/:id/rejudge', async (req, res) => {
  try {
    let id = parseInt(req.params.id);
    let judge = await JudgeState.fromID(id);

    if (judge.pending && !(res.locals.user && await res.locals.user.hasPrivilege('manage_problem'))) throw new ErrorMessage('无法重新评测一个评测中的提交。');

    await judge.loadRelationships();

    let allowedRejudge = await judge.problem.isAllowedEditBy(res.locals.user);
    if (!allowedRejudge) throw new ErrorMessage('您没有权限进行此操作。');

    await judge.rejudge();

    res.redirect(syzoj.utils.makeUrl(['submission', id]));
  } catch (e) {
    syzoj.log(e);
    res.render('error', {
      err: e
    });
  }
});
<|endoftext|>


<commit_before>Meteor.publish('notes', function (text) {
    return Notes.find({});
});

Notes.allow({
    insert: function(userId, doc){
        return true;
    },
    update:  function(userId, doc, fieldNames, modifier){
        return false;
    },
    remove:  function(userId, doc){
        return true;
    }
});

Notes.deny({
});<commit_msg>Remove unused parameter<commit_after>Meteor.publish('notes', function () {
    return Notes.find({});
});

Notes.allow({
    insert: function(userId, doc){
        return true;
    },
    update:  function(userId, doc, fieldNames, modifier){
        return false;
    },
    remove:  function(userId, doc){
        return true;
    }
});

Notes.deny({
});<|endoftext|>


<commit_before>$(function () {
    var server = io.connect(window.location.href);

    var $table = $('table');
    $table.tablesort();
    $("thead th:contains('Date')").data('sortBy', function (th, td, tablesort) {
        var dateString = td.find('span.data').text();
        var date = new Date(dateString);
        if (date == 'Invalid Date') {
            date = new Date(0);
        }
        return date;
    });

    $('#table').click(function (e) {
        e.stopPropagation();
    });
    var updateCell = function (e) {
        e.preventDefault();
        var $td = $('td.active');
        var existingVal = $td.find('span.data').text();
        var val = $('#cell-edit').find('input').val();
        if (val !== existingVal) {
            var key = $td.parent().attr('data-key');
            var col = $td.closest('table').find('th').eq($td.index()).html();
            var data = {key: key, col: col, val: val};
            var dataJSON = JSON.stringify(data);
            console.log("sending 'update table cell' " + dataJSON);
            server.emit('update table cell', dataJSON);
        }
    };
    $('#cell-form').submit(updateCell);
    $('#cell-edit').find('input')[0].oninput = updateCell;
    $('body').click(function (e) {
        $('td').removeClass('active');
        $('#cell-edit').addClass('disabled').find('input').val('');
        $('#cell-ok').addClass('disabled');
    });
    $('#new-row').click(function (e) {
        var row = {};
        $('th').each(function () {
            var thText = $(this).html();
            if (thText.length > 0) {
                row[thText] = "";
            }
        });
        var rowJSON = JSON.stringify(row);
        console.log("sending 'new table row' " + rowJSON);
        server.emit('new table row', rowJSON);
    });

    var tdOnClick = function (e) {
        $('td').removeClass('active');
        $(this).addClass('active');
        $('#cell-edit').removeClass('disabled').find('input').focus().val($(this).find('span.data').html()).select();
        $('#cell-ok').removeClass('disabled');
    };

    var trashOnClick = function (e) {
        var key = $(this).parent().attr('data-key');
        var dataJSON = JSON.stringify({key: key});
        console.log("sending 'delete row' " + dataJSON);
        server.emit('delete row', dataJSON);
    };
    var sortTable = function () {
        var $th = $table.find('th.sorted');
        if ($th.hasClass('descending')) {
            $table.data('tablesort').sort($th, 'desc');
        } else if ($th.hasClass('ascending')) {
            $table.data('tablesort').sort($th, 'asc');
        }
    };

    server.on('connect', function () {
        console.log('established new connection to server, clearing local table');
        $('tbody').html('');
        console.log("sending 'request all' to server");
        server.emit("request all");
    });
    server.on('title', function (dataJSON) {
        $('.title').html(JSON.parse(dataJSON).title);
    });
    server.on('update table cell', function (dataJSON) {
        console.log("received 'update table cell' " + dataJSON);
        var data = JSON.parse(dataJSON);
        var index = $('th:contains(' + data.col + ')').index();
        $('tr[data-key="' + data.key + '"]').find('td').eq(index).find('span.data').html(data.val);
        sortTable();
    });
    server.on('delete row', function (dataJSON) {
        console.log("received 'delete row' " + dataJSON);
        var data = JSON.parse(dataJSON);
        $('tr[data-key="' + data.key + '"]').remove();
    });
    server.on('new table row', function (rowJSON) {
        console.log("received 'new table row' " + rowJSON);
        var row = JSON.parse(rowJSON);
        var $tr = $('

');
        var $smallTrashIcon = $('');
        var $largeTrashIcon = $('');
        $trashTd = $('	');
        $trashTd.append($smallTrashIcon).append($largeTrashIcon);
        $trashTd.click(trashOnClick);
        $tr.append($trashTd);
        $('th').each(function () {
            var thText = $(this).html();
            if (thText.length > 0) {
                var $td = $('');
                var $span1 = $('' + thText + ': ');
                var $span2 = $('' + row.data[thText] + '');
                $td.click(tdOnClick);
                $td.append($span1).append($span2);
                $tr.append($td);
            }
        });
        $('table').append($tr);
        sortTable();
    });
});
<commit_msg>don't resort table if the only change is in a non-sorted column<commit_after>$(function () {
    var server = io.connect(window.location.href);

    var $table = $('table');
    $table.tablesort();
    $("thead th:contains('Date')").data('sortBy', function (th, td, tablesort) {
        var dateString = td.find('span.data').text();
        var date = new Date(dateString);
        if (date == 'Invalid Date') {
            date = new Date(0);
        }
        return date;
    });
    $table.on('tablesort:start', function(event, tablesort) {
        console.log("Starting the sort...");
    });

    $('#table').click(function (e) {
        e.stopPropagation();
    });
    var updateCell = function (e) {
        e.preventDefault();
        var $td = $('td.active');
        var existingVal = $td.find('span.data').text();
        var val = $('#cell-edit').find('input').val();
        if (val !== existingVal) {
            var key = $td.parent().attr('data-key');
            var col = $td.closest('table').find('th').eq($td.index()).html();
            var data = {key: key, col: col, val: val};
            var dataJSON = JSON.stringify(data);
            console.log("sending 'update table cell' " + dataJSON);
            server.emit('update table cell', dataJSON);
        }
    };
    $('#cell-form').submit(updateCell);
    $('#cell-edit').find('input')[0].oninput = updateCell;
    $('body').click(function (e) {
        $('td').removeClass('active');
        $('#cell-edit').addClass('disabled').find('input').val('');
        $('#cell-ok').addClass('disabled');
    });
    $('#new-row').click(function (e) {
        var row = {};
        $('th').each(function () {
            var thText = $(this).html();
            if (thText.length > 0) {
                row[thText] = "";
            }
        });
        var rowJSON = JSON.stringify(row);
        console.log("sending 'new table row' " + rowJSON);
        server.emit('new table row', rowJSON);
    });

    var tdOnClick = function (e) {
        $('td').removeClass('active');
        $(this).addClass('active');
        $('#cell-edit').removeClass('disabled').find('input').focus().val($(this).find('span.data').html()).select();
        $('#cell-ok').removeClass('disabled');
    };

    var trashOnClick = function (e) {
        var key = $(this).parent().attr('data-key');
        var dataJSON = JSON.stringify({key: key});
        console.log("sending 'delete row' " + dataJSON);
        server.emit('delete row', dataJSON);
    };
    var sortTable = function () {
        var $th = $table.find('th.sorted');
        if ($th.hasClass('descending')) {
            $table.data('tablesort').sort($th, 'desc');
        } else if ($th.hasClass('ascending')) {
            $table.data('tablesort').sort($th, 'asc');
        }
    };

    server.on('connect', function () {
        console.log('established new connection to server, clearing local table');
        $('tbody').html('');
        console.log("sending 'request all' to server");
        server.emit("request all");
    });
    server.on('title', function (dataJSON) {
        $('.title').html(JSON.parse(dataJSON).title);
    });
    server.on('update table cell', function (dataJSON) {
        console.log("received 'update table cell' " + dataJSON);
        var data = JSON.parse(dataJSON);
        var $th = $('th:contains(' + data.col + ')');
        var columnIndex = $th.index();
        $('tr[data-key="' + data.key + '"]').find('td').eq(columnIndex).find('span.data').html(data.val);
        if ($th.hasClass('sorted')) {
            sortTable();
        }
    });
    server.on('delete row', function (dataJSON) {
        console.log("received 'delete row' " + dataJSON);
        var data = JSON.parse(dataJSON);
        $('tr[data-key="' + data.key + '"]').remove();
    });
    server.on('new table row', function (rowJSON) {
        console.log("received 'new table row' " + rowJSON);
        var row = JSON.parse(rowJSON);
        var $tr = $('

');
        var $smallTrashIcon = $('');
        var $largeTrashIcon = $('');
        $trashTd = $('	');
        $trashTd.append($smallTrashIcon).append($largeTrashIcon);
        $trashTd.click(trashOnClick);
        $tr.append($trashTd);
        $('th').each(function () {
            var thText = $(this).html();
            if (thText.length > 0) {
                var $td = $('');
                var $span1 = $('' + thText + ': ');
                var $span2 = $('' + row.data[thText] + '');
                $td.click(tdOnClick);
                $td.append($span1).append($span2);
                $tr.append($td);
            }
        });
        $('table').append($tr);
        sortTable();
    });
});
<|endoftext|>


<commit_before>var Coffee = {
  api: 'http://draug.online.ntnu.no/coffee_dev.txt',
  msgNoPots: 'Ingen kanner i dag',
  msgNoCoffee: 'Kaffen har ikke blitt satt på',
  msgFormatError: 'Feil i kaffeformat',
  msgConnectionError: 'Frakoblet fra kaffeknappen',
  msgComforting: 'Det er sikkert kaffe!',

  debugCoffee: 0,
  debugCoffeeString: "200\n1. March 14:28:371",

  get: function(callback) {
    if (callback == undefined) {
      console.log('ERROR: Callback is required. In the callback you should insert the results into the DOM.');
      return;
    }

    // Receives the status for the coffee pot
    var self = this;
    $.ajax({
      url: self.api,
      success: function(data) {

        // If coffee debugging is enabled
        if (self.debugCoffee) {
          data = self.debugCoffeeString;
        }

        try {
          // Split into pot number and age of last pot
          var pieces = data.split("\n");
          var pots = pieces[0];
          var ageString = pieces[1];

          // Get now
          var now = new Date();

          // Figure out which date the coffee was made
          var dateObject = ageString.match(/\d+\. [a-zA-Z]+/); // Operas JS-engine makes an object instead of a string
          var dateString = String(dateObject);
          dateString = dateString.replace('.', ''); // Remove period
          dateString = dateString + ', ' + now.getFullYear();
          var coffeeDate = new Date(dateString);

          // Check if the coffee pots were made today
          if (coffeeDate.getDate() == now.getDate()) {

            // Calulate the age of the last pot better
            var coffeeTime = String(ageString.match(/\d+:\d+:\d+/)).split(':');
            var then = new Date(now.getFullYear(), now.getMonth(), now.getDate(), coffeeTime[0], coffeeTime[1]);
            var one_minute = 1000 * 60;

            // Calculate difference between the two dates, and convert to minutes
            var diff = Math.floor(( now.getTime() - then.getTime() ) / one_minute);

            // Create a proper time string from all the minutes
            var age;
            if (-1 <= diff && diff <= 9) {
              age = 'Kaffen ble nettopp laget';
            }
            else if (10 <= diff && diff <= 59) {
              age = 'Kaffen ble laget for '+diff+' min siden';
            }
            else if (60 <= diff) {
              age = 'Kaffen ble laget kl '+coffeeTime[0]+':'+coffeeTime[1];
            }
            else {
              age = 'WAT? Lager noen kaffe i fremtiden nå?!'
            }

            // Make pots-string
            pots = (pots=='0'?'Ingen kanner':pots=='1'?'1 kanne':pots+' kanner') + ' i dag';

            // Call it back
            callback(pots, age);
          }
          else {
            // Coffee was not made today
            var coffee = '';
            callback(self.msgNoPots, self.msgNoCoffee);
          }
        } catch (err) {
          if (DEBUG) console.log('ERROR: Coffee format is wrong.');
          callback(self.msgFormatError, self.msgComforting);
        }
      },
      error: function(jqXHR, text, err) {
        if (DEBUG) console.log('ERROR: Failed to get coffee pot status.');
        callback(self.msgConnectionError, self.msgComforting);
      },
    });
  },

  // getPots: function(callback) {
  //   // Function used by background process to determine when a new coffee pot is cooking
  //   if (callback == undefined) {
  //     console.log('ERROR: Callback is required. In the callback you should insert the results into the DOM.');
  //     return;
  //   }
  //   var self = this;
  //   $.ajax({
  //     url: self.api,
  //     success: function(data) {
  //       try {
  //         // Split into pot number and age of last pot
  //         var pieces = data.split("\n");
  //         var pots = pieces[0];
  //         var ageString = pieces[1];

  //         // Get now
  //         var now = new Date();

  //         // Check if the coffee pots were made today
  //         var coffeeDate = new Date(ageString.match(/\d+\. [a-zA-Z]+/));
  //         if (coffeeDate.getDate() == now.getDate()) {
  //           callback(pots);
  //         }
  //         else {
  //           callback(0);
  //         }
  //       } catch (err) {
  //         if (DEBUG) console.log('ERROR: Failed to parse coffee status.');
  //         callback(0);
  //       }
  //     },
  //     error: function(jqXHR, text, err) {
  //       if (DEBUG) console.log('ERROR: Failed to get coffee pot status.');
  //       callback(0);
  //     },
  //   });
  // },

  showNotification: function(pots) {
    // Amount of pots currently not used
    Browser.createNotification('subscription.html');
  },

}
<commit_msg>coffee: trashing old function, too much overlap<commit_after>var Coffee = {
  api: 'http://draug.online.ntnu.no/coffee_dev.txt',
  msgNoPots: 'Ingen kanner i dag',
  msgNoCoffee: 'Kaffen har ikke blitt satt på',
  msgFormatError: 'Feil i kaffeformat',
  msgConnectionError: 'Frakoblet fra kaffeknappen',
  msgComforting: 'Det er sikkert kaffe!',

  debugCoffee: 0,
  debugCoffeeString: "200\n1. March 14:28:371",

  get: function(rawData, callback) {
    if (callback == undefined) {
      console.log('ERROR: Callback is required. In the callback you should insert the results into the DOM.');
      return;
    }

    // Receives the status for the coffee pot
    var self = this;
    $.ajax({
      url: self.api,
      success: function(data) {

        // If coffee debugging is enabled
        if (self.debugCoffee) {
          data = self.debugCoffeeString;
        }

        try {
          // Split into pot number and age of last pot
          var pieces = data.split("\n");
          var pots = pieces[0];
          var ageString = pieces[1];

          // Get now
          var now = new Date();

          // Figure out which date the coffee was made
          var dateObject = ageString.match(/\d+\. [a-zA-Z]+/); // Operas JS-engine makes an object instead of a string
          var dateString = String(dateObject);
          dateString = dateString.replace('.', ''); // Remove period
          dateString = dateString + ', ' + now.getFullYear();
          var coffeeDate = new Date(dateString);

          // Check if the coffee pots were made today
          var madeToday = coffeeDate.getDate() == now.getDate();

          // Raw data data requested?
          if (madeToday && rawData) {
            pots = Number(pots);
            var age = coffeeTime[0] + ':' + coffeeTime[1];
            callback(pots, age);
          }
          // Regular data requsted (pretty strings)
          else if (madeToday) {

            // Calulate the age of the last pot better
            var coffeeTime = String(ageString.match(/\d+:\d+:\d+/)).split(':');
            var then = new Date(now.getFullYear(), now.getMonth(), now.getDate(), coffeeTime[0], coffeeTime[1]);
            var one_minute = 1000 * 60;

            // Calculate difference between the two dates, and convert to minutes
            var diff = Math.floor(( now.getTime() - then.getTime() ) / one_minute);

            // Create a proper time string from all the minutes
            var age;
            if (-1 <= diff && diff <= 9) {
              age = 'Kaffen ble nettopp laget';
            }
            else if (10 <= diff && diff <= 59) {
              age = 'Kaffen ble laget for '+diff+' min siden';
            }
            else if (60 <= diff) {
              age = 'Kaffen ble laget kl '+coffeeTime[0]+':'+coffeeTime[1];
            }
            else {
              age = 'WAT? Lager noen kaffe i fremtiden nå?!'
            }

            // Make pots-string
            pots = (pots=='0'?'Ingen kanner':pots=='1'?'1 kanne':pots+' kanner') + ' i dag';

            // Call it back
            callback(pots, age);
          }
          else {
            // Coffee was not made today
            callback(self.msgNoPots, self.msgNoCoffee);
          }
        } catch (err) {
          if (DEBUG) console.log('ERROR: Coffee format is wrong.');
          callback(self.msgFormatError, self.msgComforting);
        }
      },
      error: function(jqXHR, text, err) {
        if (DEBUG) console.log('ERROR: Failed to get coffee pot status.');
        callback(self.msgConnectionError, self.msgComforting);
      },
    });
  },

  showNotification: function(pots) {
    // Amount of pots currently not used
    Browser.createNotification('subscription.html');
  },

}
<|endoftext|>


<commit_before>"use strict";

var Coffee = {
  debug: 0,
  debugString: 0,
  debugThisString: "200\n30. October 14:28:371",

  msgNoPots: 'Ingen kanner i dag',
  msgNoCoffee: 'Kaffen har ikke blitt satt på',
  msgFormatError: 'Feil i kaffeformat',
  msgConnectionError: 'Frakoblet fra kaffekanna',
  msgComforting: 'Så så, det er sikkert kaffe :)',
  msgNotification: 'Kaffen er satt på, straks klar :)',

  get: function(pretty, callback) {
    if (callback == undefined) {
      console.error('Callback is required. In the callback you should insert the results into the DOM.');
      return;
    }

    var api = Affiliation.org[localStorage.affiliationKey1].hw.apis.coffee;

    // Receives the status for the coffee pot
    var self = this;
    Ajaxer.getPlainText({
      url: api,
      success: function(data) {

        // If coffee debugging is enabled
        if (self.debug && self.debugString) {
          data = self.debugThisString;
        }

        try {
          // Split into pot number and age of last pot
          var pieces = data.split("\n");
          var pots = Number(pieces[0]);
          var ageString = pieces[1];

          // Coffee made today?
          if (self.isMadeToday(ageString)) {

            // Calculate minute difference from right now
            var now = new Date();
            var coffeeTime = String(ageString.match(/\d+:\d+:\d+/)).split(':');
            var then = new Date(now.getFullYear(), now.getMonth(), now.getDate(), coffeeTime[0], coffeeTime[1]);
            var age = self.minuteDiff(then);

            // If pretty strings are requested
            if (pretty) {
              age = self.prettyAgeString(age, coffeeTime);
              pots = self.prettyPotsString(pots);
            }

            // Call it back
            callback(pots, age);
          }
          else {
            // Coffee was not made today
            if (pretty) {
              callback(self.msgNoPots, self.msgNoCoffee);
            }
            else {
              callback(0, 0);
            }
          }
        } catch (err) {
          if (self.debug) console.error('Coffee format is wrong:', err);
          callback(self.msgFormatError, self.msgComforting);
        }
      },
      error: function(jqXHR, text, err) {
        if (self.debug) console.error('Failed to get coffee pot status.');
        callback(self.msgConnectionError, self.msgComforting);
      },
    });
  },

  isMadeToday: function(ageString) {
    // Get now
    var now = new Date();
    // Figure out which date the coffee was made
    var dateObject = ageString.match(/\d+\. [a-zA-Z]+/);
    var dateString = String(dateObject);
    dateString = dateString.replace('.', ''); // Remove period
    dateString = dateString + ', ' + now.getFullYear();
    var coffeeDate = new Date(dateString);
    // Check if the coffee pots were made today
    return coffeeDate.getDate() == now.getDate();
  },

  minuteDiff: function(then) {
    // Get now
    var now = new Date();
    var one_minute = 1000 * 60;
    // Calculate difference between the two dates, and convert to minutes
    return Math.floor(( now.getTime() - then.getTime() ) / one_minute);
  },

  prettyAgeString: function(diff, coffeeTime) {
    // Create a proper time string from all the minutes
    if (0 <= diff && diff <= 9)
      return 'Kaffen ble nettopp laget';
    else if (10 <= diff && diff <= 59)
      return 'Kaffen ble laget for '+diff+' min siden';
    else if (60 <= diff)
      return 'Kaffen ble laget kl '+coffeeTime[0]+':'+coffeeTime[1];
    else
      // time is negative, computer is likely in a timezone between GMT -12 and +1
      return 'God reise! Håper de har kaffe! :)';
  },

  prettyPotsString: function(pots) {
    return (pots=='0'?'Ingen kanner':pots=='1'?'1 kanne':pots+' kanner') + ' i dag';
  },

  showNotification: function(pots, age) { // Parameters 'pots' and 'age' not in use yet.
    var demo = (typeof pots == 'undefined' && typeof age == 'undefined');
    // If the computer has slept for a while and there are
    // suddenly four new coffeepots then they will all be
    // lined up for notifications, giving the user four
    // notifications at once. This is prevented here by not
    // allowing two consecutive notifications within 4 minutes
    // of each other.
    var showIt = true;
    if (typeof localStorage.lastSubscriptionTime !== 'undefined') {
      try {
        var then = JSON.parse(localStorage.lastSubscriptionTime);
        if (this.minuteDiff(then) < 5) {
          showIt = false;
        }
      }
      catch (err) {
        if (this.debug) console.error('failed to calculate coffee subscription time difference');
      }
    }

    if (showIt || demo) {

      // Save timestamp if this was a real coffee notification
      if (!demo)
        localStorage.lastSubscriptionTime = JSON.stringify(new Date());

      var key = localStorage.affiliationKey1;
      var memes = [];

      // Add regular memes
      var amount = MEME_AMOUNT; // Number of memes, in regular human numbers, not zero-indexed
      for (var i = 1; i <= amount; i++) {
        memes.push('./meme/'+i+'.png');
      }

      // Add affiliation memes
      if (Affiliation.org[key].hw.memePath) {
        var amount = Affiliation.getMemeCount(key);
        var path = Affiliation.org[key].hw.memePath;
        for (var i = 1; i <= amount; i++) {
          memes.push(path+i+'.png');
        }
      }

      // Randomize image
      var random = 1 + (Math.floor(Math.random() * memes.length));
      if (this.debug) console.log('memes['+(random-1)+'] of '+0+'-'+(memes.length-1)+' is "'+memes[random-1]+'"');
      var image = memes[random - 1]; // the list is zero-indexed

      // Create the notification
      var item = {
        title: Affiliation.org[key].name + ' Notifier',
        description: this.msgNotification,
        image: image,
        link: 'options.html',
        feedKey: key,
      }
      if (!demo) {
        Browser.createNotification(item);
      }
      else {
        // Need to run it by the background process because the event listeners are there
        Browser.getBackgroundProcess().Browser.createNotification(item);
      }
    }
    else {
      if (this.debug) console.error('coffee notification displayed less than four minutes ago');
    }
  },

}
<commit_msg>coffee: added some logging<commit_after>"use strict";

var Coffee = {
  debug: 0,
  debugString: 0,
  debugThisString: "200\n30. October 14:28:371",

  msgNoPots: 'Ingen kanner i dag',
  msgNoCoffee: 'Kaffen har ikke blitt satt på',
  msgFormatError: 'Feil i kaffeformat',
  msgConnectionError: 'Frakoblet fra kaffekanna',
  msgComforting: 'Så så, det er sikkert kaffe :)',
  msgNotification: 'Kaffen er satt på, straks klar :)',

  get: function(pretty, callback) {
    if (callback == undefined) {
      console.error('Callback is required. In the callback you should insert the results into the DOM.');
      return;
    }

    var api = Affiliation.org[localStorage.affiliationKey1].hw.apis.coffee;

    // Receives the status for the coffee pot
    var self = this;
    Ajaxer.getPlainText({
      url: api,
      success: function(data) {

        // If coffee debugging is enabled
        if (self.debug && self.debugString) {
          data = self.debugThisString;
        }

        try {
          // Split into pot number and age of last pot
          var pieces = data.split("\n");
          var pots = Number(pieces[0]);
          var ageString = pieces[1];

          // Coffee made today?
          if (self.isMadeToday(ageString)) {

            // Calculate minute difference from right now
            var now = new Date();
            var coffeeTime = String(ageString.match(/\d+:\d+:\d+/)).split(':');
            var then = new Date(now.getFullYear(), now.getMonth(), now.getDate(), coffeeTime[0], coffeeTime[1]);
            var age = self.minuteDiff(then);

            // If pretty strings are requested
            if (pretty) {
              age = self.prettyAgeString(age, coffeeTime);
              pots = self.prettyPotsString(pots);
            }

            // Call it back
            callback(pots, age);
          }
          else {
            // Coffee was not made today
            if (pretty) {
              callback(self.msgNoPots, self.msgNoCoffee);
            }
            else {
              callback(0, 0);
            }
          }
        } catch (err) {
          if (self.debug) console.error('Coffee format is wrong:', err);
          callback(self.msgFormatError, self.msgComforting);
        }
      },
      error: function(jqXHR, text, err) {
        if (self.debug) console.error('Failed to get coffee pot status.');
        callback(self.msgConnectionError, self.msgComforting);
      },
    });
  },

  isMadeToday: function(ageString) {
    // Get now
    var now = new Date();
    // Figure out which date the coffee was made
    var dateObject = ageString.match(/\d+\. [a-zA-Z]+/);
    var dateString = String(dateObject);
    dateString = dateString.replace('.', ''); // Remove period
    dateString = dateString + ', ' + now.getFullYear();
    var coffeeDate = new Date(dateString);
    // Check if the coffee pots were made today
    return coffeeDate.getDate() == now.getDate();
  },

  minuteDiff: function(then) {
    // Get now
    var now = new Date();
    var one_minute = 1000 * 60;
    // Calculate difference between the two dates, and convert to minutes
    return Math.floor(( now.getTime() - then.getTime() ) / one_minute);
  },

  prettyAgeString: function(diff, coffeeTime) {
    // Create a proper time string from all the minutes
    if (0 <= diff && diff <= 9)
      return 'Kaffen ble nettopp laget';
    else if (10 <= diff && diff <= 59)
      return 'Kaffen ble laget for '+diff+' min siden';
    else if (60 <= diff)
      return 'Kaffen ble laget kl '+coffeeTime[0]+':'+coffeeTime[1];
    else
      // time is negative, computer is likely in a timezone between GMT -12 and +1
      return 'God reise! Håper de har kaffe! :)';
  },

  prettyPotsString: function(pots) {
    return (pots=='0'?'Ingen kanner':pots=='1'?'1 kanne':pots+' kanner') + ' i dag';
  },

  showNotification: function(pots, age) { // Parameters 'pots' and 'age' not in use yet.
    var demo = (typeof pots == 'undefined' && typeof age == 'undefined');
    // If the computer has slept for a while and there are
    // suddenly four new coffeepots then they will all be
    // lined up for notifications, giving the user four
    // notifications at once. This is prevented here by not
    // allowing two consecutive notifications within 4 minutes
    // of each other.
    var showIt = true;
    if (typeof localStorage.lastSubscriptionTime !== 'undefined') {
      try {
        var then = JSON.parse(localStorage.lastSubscriptionTime);
        if (this.minuteDiff(then) < 5) {
          showIt = false;
        }
      }
      catch (err) {
        if (this.debug) console.error('failed to calculate coffee subscription time difference');
      }
    }

    if (showIt || demo) {

      // Save timestamp if this was a real coffee notification
      if (!demo)
        localStorage.lastSubscriptionTime = JSON.stringify(new Date());

      var key = localStorage.affiliationKey1;
      var memes = [];

      // Add regular memes
      var amount = MEME_AMOUNT; // Number of memes, in regular human numbers, not zero-indexed
      for (var i = 1; i <= amount; i++) {
        memes.push('./meme/'+i+'.png');
      }

      // Add affiliation memes
      if (Affiliation.org[key].hw.memePath) {
        var amount = Affiliation.getMemeCount(key);
        var path = Affiliation.org[key].hw.memePath;
        for (var i = 1; i <= amount; i++) {
          memes.push(path+i+'.png');
        }
      }

      // Randomize image
      var random = 1 + (Math.floor(Math.random() * memes.length));
      if (this.debug) console.log('memes['+(random-1)+'] of '+0+'-'+(memes.length-1)+' is "'+memes[random-1]+'"');
      var image = memes[random - 1]; // the list is zero-indexed

      if (this.debug) console.log('memes', random - 1, '/', memes.length, image);

      // Create the notification
      var item = {
        title: Affiliation.org[key].name + ' Notifier',
        description: this.msgNotification,
        image: image,
        link: 'options.html',
        feedKey: key,
      }
      if (!demo) {
        Browser.createNotification(item);
      }
      else {
        // Need to run it by the background process because the event listeners are there
        Browser.getBackgroundProcess().Browser.createNotification(item);
      }
    }
    else {
      if (this.debug) console.error('coffee notification displayed less than four minutes ago');
    }
  },

}
<|endoftext|>


<commit_before>(function(scene) {

  var Lyria = scene.modules.Lyria;

  scene.on('achievement', function() {
    Lyria.AchievementManager.show('switchScene');
  });

  scene.bindEvent({
    '#btnSwitch': {
      'click': function(event) {
        scene.trigger('achievement');
        scene.parent.show('scene2');
      }
    }
  });

  scene.expose({
    test: "Hallo",
    title: scene.t('title', {
      name: scene.name
    })
  });

  console.log(scene);
  console.log(scene.game);
  scene.log('yeeha!');

})(this);
<commit_msg>Updated API call to bind events<commit_after>(function(scene) {

  var Lyria = scene.modules.Lyria;

  scene.on('achievement', function() {
    Lyria.AchievementManager.show('switchScene');
  });

  scene.bindEvents({
    '#btnSwitch': {
      'click': function(event) {
        scene.trigger('achievement');
        scene.parent.show('scene2');
      }
    }
  });

  scene.expose({
    test: "Hallo",
    title: scene.t('title', {
      name: scene.name
    })
  });

  console.log(scene);
  console.log(scene.game);
  scene.log('yeeha!');

})(this);
<|endoftext|>


<commit_before>$(function() {
	$.each($(".album-wrapper a"), function(index, val) {
		$(this).attr("href", $(this).attr("href").replace(".html", ".jpg"));
		$(this).attr("data-caption", $(this).parent().find(".thumbnail-caption").text());
	});
	baguetteBox.run('.album-wrapper', {
	});
});
<commit_msg>album headline #13<commit_after>$(function() {
    $('.album-title').wrapInner('

');
	$.each($(".album-wrapper a"), function(index, val) {
		$(this).attr("href", $(this).attr("href").replace(".html", ".jpg"));
		$(this).attr("data-caption", $(this).parent().find(".thumbnail-caption").text());
	});
	baguetteBox.run('.album-wrapper', {
	});
});
<|endoftext|>


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

   $('.reloadDiv').click(function()
   {
      var link_name = $(this).attr('id');
      $("#mainSection").load(link_name+".php");
    });

   // when the textboxes change value run this function
	$(".addToBasket").change(function()
	{

  	// keep track of number of item
  	var itemCount = itemCounter();

  	// store the values we need for later purposes
  	var nameOfItem = $(this).attr("name");

  	// get variables for updating the stock tags
  	var stockTag = getStock(nameOfItem);
  	var quantity = $(this).val();
  	var stock = $(this).attr('max') - quantity;

  	if(itemCount > 0)
  	{
  		$("#noItems").hide();
  		$("#storeBasket").show();

  		// replace the -'s with spaces throughout the name
  		nameOfItem = nameOfItem.replace(/-/g, ' ');

  		var itemID = $(this).attr('id');

			var money = itemID.substr(itemID.indexOf("-") + 1);
  		var total =  (parseFloat(money) * parseFloat(quantity)).toFixed(2);
  		var found = false;

  		// if the item we just changed was set to zero
  		if(quantity === "0")
  		{

  			// update the stock pile
 				updateStockTags(stock, stockTag);

  			// cycle through all the item in the shopping cart to find the correct item to remove
  			$('#storeBasket .removable').each(function()
				{
					if($(this).children(":first-child").html() === nameOfItem)
					{
						$(this).remove();
					}
				});
  		}
			else //otherwise we want to add the item to the shopping cart
			{
				// check to see wheather the item is already in the shopping cart
				// if so then increment quantity and total otherwise add whole row
				$('#storeBasket .itemname').each(function()
				{
				 	if(($(this).html()) === nameOfItem)
				 	{
				 		$(this).next().next().html(quantity);
				 		$(this).next().next().next().html("$" + total);
				 		found = true;
				 	}
				});

				if(found != true)
				{
					var htmltoadd = "
" + nameOfItem + "	$" + money +
					 "	" + quantity + "	$" + total + "
";

	  			$("#storeBasket tbody").prepend(htmltoadd);
				}
			}

  		// update the total
  		var subtotal = calctotal();
 			$("#totalPrice").html("$" + subtotal);

 			// update the stock pile
 			updateStockTags(stock, stockTag);

 		}
		else // no items in cart
  	{
  		// update the stock pile
 			updateStockTags(stock, stockTag);

			$("#noItems").show();

			$('#storeBasket .removable').each(function()
			{
				$(this).remove();
			});

  		$("#storeBasket").hide();
  	}

	});

	$('#purchase').click(function(){

				$.ajax({
					url: '../assets/scripts/getQuantities.php',
	        data: $(this).serialize(),
	        type: 'post',
	        dataType: 'json',
	        success: function(data) {
	            if(data.success)
	            {
	            	parseTable(data['tables']);
	            }
	        },
	        error: function(){
	        	console.log("Error! Could not connect to database.");
	        }
			});
	});

});

// functoin for parsing bedding table that's returned from ajax call to php
function parseTable(allTables)
{

	// get each key=>value pair and print to appropriate tag
	$.each(allTables, function(key, value){

    // prep key for use later
    key = key.replace(/\s/g,'-');

    // new variable for more manipulating
    var manipulatedKey = key;
    manipulatedKey = manipulatedKey.toLowerCase();
    manipulatedKey = manipulatedKey + "-stock";

    if(value == 0)
    {
    	$('#'+manipulatedKey).attr('class', 'outOfStock');
			$('#'+manipulatedKey).html('Out of Stock!');

			// search through all items with class 'addToBasket' and find the input box thathas matching name and hide
			disableQuantityBox(key);
    }
    else
    {
    	setMaxForQuantityBox(key, value);
    	$('#'+manipulatedKey).html(value + ' in stock');
    }

	});

}

// function for updating Stock tags
function updateStockTags(stock, stockTag)
{
	// update the stock pile
 			if(stock == 0)
 			{
				stockTag.attr('class', 'outOfStock');
				stockTag.html('Out of Stock!');
 			}
 			else
 			{
 				stockTag.html(stock + " in stock");
 			}
}

// function for cycling through stock labels and getting the result
function getStock(nameToFind)
{
	// append -stock for easier searching
	nameToFind = nameToFind.toLowerCase() + '-stock';
	nameToFind = nameToFind.replace('/', '-');
	var result;

	$('.updateStockPile').each(function()
	{
	  if($(this).attr('id') == nameToFind)
	  {

	  	result = $(this);
	  	// break out of loop to return the correct element
	  	return false;
	  }
	});

	return result;
};

// function for cycling through quantitiy boxes to hide the appropriate one
function disableQuantityBox(nameToFind)
{
	$('.addToBasket').each(function()
	{
	  if($(this).attr('name') == nameToFind)
	  {
	  	$(this).hide();
	  }
	});

};

// function for cycling through quantitiy boxes to set max value
function setMaxForQuantityBox(nameToFind, value)
{
	$('.addToBasket').each(function()
	{
	  if($(this).attr('name') == nameToFind)
	  {
	  	$(this).attr('max', value);
	  }
	});

};

// function for getting number of item in quantity boxes
function itemCounter()
{
	var count = 0;
	$('.addToBasket').each(function()
	{
	  count = count + parseInt($(this).val(), 10);
	});

	return count;
};

// function for getting the cumulative total of all item in cart
function calctotal()
{
	var total = 0;
	$('.itemincart').each(function()
	{
	  total = total + parseFloat($(this).html().substring(1));
	});

	total = total.toFixed(2);
	return total;
};

function goToStore()
{
	$("#mainSection").load("purchase.php");
};
<commit_msg>fixed out of stock error<commit_after>$(document).ready(function() {

   $('.reloadDiv').click(function()
   {
      var link_name = $(this).attr('id');
      $("#mainSection").load(link_name+".php");
    });

   // when the textboxes change value run this function
	$(".addToBasket").change(function()
	{
  	//
  	// keep track of number of item
  	var itemCount = itemCounter();

  	// store the values we need for later purposes
  	var nameOfItem = $(this).attr("name");

  	// get variables for updating the stock tags
  	var stockTag = getStock(nameOfItem);
  	var quantity = $(this).val();
  	var stock = $(this).attr('max') - quantity;

  	if(itemCount > 0)
  	{
  		$("#noItems").hide();
  		$("#storeBasket").show();

  		// replace the -'s with spaces throughout the name
  		nameOfItem = nameOfItem.replace(/-/g, ' ');

  		var itemID = $(this).attr('id');

		var money = itemID.substr(itemID.indexOf("-") + 1);
  		var total =  (parseFloat(money) * parseFloat(quantity)).toFixed(2);
  		var found = false;

  		// if the item we just changed was set to zero
  		if(quantity === "0")
  		{
  			// update the stock pile
 				updateStockTags(stock, stockTag);

  			// cycle through all the item in the shopping cart to find the correct item to remove
  			$('#storeBasket .removable').each(function()
				{
					if($(this).children(":first-child").html() === nameOfItem)
					{
						$(this).remove();
					}
				});
  		}

			else if (stock >= 0) //otherwise we want to add the item to the shopping cart
			{
				// check to see wheather the item is already in the shopping cart
				// if so then increment quantity and total otherwise add whole row
				$('#storeBasket .itemname').each(function()
				{
				 	if(($(this).html()) === nameOfItem)
				 	{
				 		$(this).next().next().html(quantity);
				 		$(this).next().next().next().html("$" + total);
				 		found = true;
				 	}
				});

				if(found != true)
				{
					var htmltoadd = "
" + nameOfItem + "	$" + money +
					 "	" + quantity + "	$" + total + "
";

	  			$("#storeBasket tbody").prepend(htmltoadd);
				}

  		// update the total
  		var subtotal = calctotal();
 			$("#totalPrice").html("$" + subtotal);

 			// update the stock pile
 			updateStockTags(stock, stockTag);
 		}
 		}
		else // no items in cart
  	{
  		// update the stock pile
 			updateStockTags(stock, stockTag);

			$("#noItems").show();

			$('#storeBasket .removable').each(function()
			{
				$(this).remove();
			});

  		$("#storeBasket").hide();
  	}

	});

	$('#purchase').click(function(){

				$.ajax({
					url: '../assets/scripts/getQuantities.php',
	        data: $(this).serialize(),
	        type: 'post',
	        dataType: 'json',
	        success: function(data) {
	            if(data.success)
	            {
	            	parseTable(data['tables']);
	            }
	        },
	        error: function(){
	        	console.log("Error! Could not connect to database.");
	        }
			});
	});

});

// functoin for parsing bedding table that's returned from ajax call to php
function parseTable(allTables)
{

	// get each key=>value pair and print to appropriate tag
	$.each(allTables, function(key, value){

    // prep key for use later
    key = key.replace(/\s/g,'-');

    // new variable for more manipulating
    var manipulatedKey = key;
    manipulatedKey = manipulatedKey.toLowerCase();
    manipulatedKey = manipulatedKey + "-stock";

    if(value <= 0)
    {
    	$('#'+manipulatedKey).attr('class', 'outOfStock');
			$('#'+manipulatedKey).html('Out of Stock!');

			// search through all items with class 'addToBasket' and find the input box that's matching name and hide
			disableQuantityBox(key);
    }
    else
    {
    	setMaxForQuantityBox(key, value);
    	$('#'+manipulatedKey).html(value + ' in stock');
    }

	});

}

// function for updating Stock tags
function updateStockTags(stock, stockTag)
{
	// update the stock pile
 			if(stock <= 0)
 			{
				stockTag.attr('class', 'outOfStock');
				stockTag.html('Out of Stock!');
 			}
 			else
 			{
 				stockTag.html(stock + " in stock");
 			}
}

// function for cycling through stock labels and getting the result
function getStock(nameToFind)
{
	// append -stock for easier searching
	nameToFind = nameToFind.toLowerCase() + '-stock';
	nameToFind = nameToFind.replace('/', '-');
	var result;

	$('.updateStockPile').each(function()
	{
	  if($(this).attr('id') == nameToFind)
	  {

	  	result = $(this);
	  	// break out of loop to return the correct element
	  	return false;
	  }
	});

	return result;
};

// function for cycling through quantitiy boxes to hide the appropriate one
function disableQuantityBox(nameToFind)
{
	$('.addToBasket').each(function()
	{
	  if($(this).attr('name') == nameToFind)
	  {
	  	$(this).hide();
	  }
	});

};

// function for cycling through quantitiy boxes to set max value
function setMaxForQuantityBox(nameToFind, value)
{
	$('.addToBasket').each(function()
	{
	  if($(this).attr('name') == nameToFind)
	  {
	  	$(this).attr('max', value);
	  }
	});

};

// function for getting number of item in quantity boxes
function itemCounter()
{
	var count = 0;
	$('.addToBasket').each(function()
	{
	  count = count + parseInt($(this).val(), 10);
	});

	return count;
};

// function for getting the cumulative total of all item in cart
function calctotal()
{
	var total = 0;
	$('.itemincart').each(function()
	{
	  total = total + parseFloat($(this).html().substring(1));
	});

	total = total.toFixed(2);
	return total;
};

function goToStore()
{
	$("#mainSection").load("purchase.php");
};
<|endoftext|>


<commit_before>var DeepstreamServer = require( 'deepstream.io' );
var tutorialServer = new DeepstreamServer();

tutorialServer.set( 'host', 'localhost' );
tutorialServer.set( 'port', 6020 );

tutorialServer.set( 'permissionHandler', {
	isValidUser: function( connectionData, authData, callback ) {
		// We don't care what the username is, as long as one is specified
		if( !authData.username ) {
			callback( 'No username specified' );
		}

		// Let's keep things simple and expect the same password
		// from all users
		else if( authData.password !== 'sesame' ) {
			callback( 'Wrong password' );
		}

		// all good, let's log the user in
		else {
			callback( null, authData.username );
		}
	},

	canPerformAction: function( username, message, callback ) {
		 // allow everything as long as the client is logged in
		callback( null, true );
	}
});

tutorialServer.start();<commit_msg>Getting server 2.0 friendly<commit_after>var DeepstreamServer = require( 'deepstream.io' );
var tutorialServer = new DeepstreamServer();

tutorialServer.set( 'host', 'localhost' );
tutorialServer.set( 'port', 6020 );

tutorialServer.set( 'permissionHandler', {
	isReady: true,
	isValidUser: function( connectionData, authData, callback ) {
		// We don't care what the username is, as long as one is specified
		if( !authData.username ) {
			callback( 'No username specified' );
		}

		// Let's keep things simple and expect the same password
		// from all users
		else if( authData.password !== 'sesame' ) {
			callback( 'Wrong password' );
		}

		// all good, let's log the user in
		else {
			callback( null, authData.username );
		}
	},

	canPerformAction: function( username, message, callback ) {
		 // allow everything as long as the client is logged in
		callback( null, true );
	}
});

tutorialServer.start();<|endoftext|>