<commit_before>import "../types/patch";

import * as t from "@babel/types";
import traverse, { NodePath, Scope } from "@babel/traverse";
import { MARKO_TYPES, MARKO_ALIAS_TYPES } from "../types/definitions";

MARKO_TYPES.forEach(typeName => {
  const checkKey = `is${typeName}`;
  const assertKey = `assert${typeName}`;
  const checkFn = t[checkKey];
  const assertFn = t[assertKey];
  NodePath.prototype[checkKey] = function (opts) {
    return checkFn(this.node, opts);
  };
  NodePath.prototype[assertKey] = function (opts) {
    assertFn(this.node, opts);
  };
});

MARKO_ALIAS_TYPES.forEach(aliasName => {
  const checkKey = `is${aliasName}`;
  const originalProtoCheck = NodePath.prototype[checkKey];
  NodePath.prototype[checkKey] = function (opts) {
    return (
      t.is(aliasName, this.node, opts) ||
      originalProtoCheck.call(this, this.node, opts)
    );
  };
});

// Adds a one time patch to the scope collector visitors to include
// Marko bindings for params and tag vars.
const originalCrawl = Scope.prototype.crawl;
const patchedVisitors = new WeakSet();

Scope.prototype.crawl = function () {
  const path = this.path;
  const originalTraverse = path.traverse;
  path.traverse = function (visitor, state) {
    path.traverse = originalTraverse;

    if (!patchedVisitors.has(visitor)) {
      patchedVisitors.add(visitor);
      Object.assign(
        traverse.explode(visitor),
        traverse.explode({
          MarkoTagBody(body) {
            for (const param of body.get("params")) {
              body.scope.registerBinding("param", param);
            }
          },
          MarkoTag(tag) {
            const tagVar = tag.get("var");
            if (tagVar.node) {
              tag.scope.registerBinding("local", tagVar, tag);
              for (const name in tagVar.getBindingIdentifiers()) {
                let curScope = tag.scope;
                const binding = curScope.getBinding(name);

                while ((curScope = curScope.parent)) {
                  curScope.hoistableTagVars =
                    curScope.hoistableTagVars ||
                    (curScope.hoistableTagVars = {});
                  const existingBinding = curScope.hoistableTagVars[name];

                  if (existingBinding) {
                    if (existingBinding !== binding) {
                      curScope.hoistableTagVars[name] = true;
                    }
                  } else {
                    curScope.hoistableTagVars[name] = binding;
                  }
                }
              }
            }
          }
        })
      );
    }

    this.traverse(visitor, state);

    if (state.references.length) {
      const movedBindings = new Map();
      for (const ref of state.references) {
        const { name } = ref.node;
        let curScope = ref.scope;
        if (curScope.hasBinding(name)) continue;

        do {
          const hoistableBinding =
            curScope.hoistableTagVars && curScope.hoistableTagVars[name];
          if (hoistableBinding) {
            if (hoistableBinding === true) {
              throw ref.buildCodeFrameError(
                "Ambiguous reference, variable was defined in multiple places and was not shadowed."
              );
            }

            const movedBinding = movedBindings.get(hoistableBinding);
            if (
              !movedBinding ||
              getScopeDepth(movedBinding.scope) < getScopeDepth(curScope)
            ) {
              movedBindings.set(hoistableBinding, curScope);
            }
          }
        } while ((curScope = curScope.parent));
      }

      for (const [binding, scope] of movedBindings) {
        binding.scope.moveBindingTo(binding.identifier.name, scope);
      }
    }
  };

  originalCrawl.call(this);
  path.traverse = originalTraverse;
};

function getScopeDepth(scope) {
  let depth = 0;
  let cur = scope;
  while ((cur = cur.parent)) depth++;
  return depth;
}
<commit_msg>fix: issue with hoisted tag var scopes<commit_after>import "../types/patch";

import * as t from "@babel/types";
import traverse, { NodePath, Scope } from "@babel/traverse";
import { MARKO_TYPES, MARKO_ALIAS_TYPES } from "../types/definitions";

MARKO_TYPES.forEach(typeName => {
  const checkKey = `is${typeName}`;
  const assertKey = `assert${typeName}`;
  const checkFn = t[checkKey];
  const assertFn = t[assertKey];
  NodePath.prototype[checkKey] = function (opts) {
    return checkFn(this.node, opts);
  };
  NodePath.prototype[assertKey] = function (opts) {
    assertFn(this.node, opts);
  };
});

MARKO_ALIAS_TYPES.forEach(aliasName => {
  const checkKey = `is${aliasName}`;
  const originalProtoCheck = NodePath.prototype[checkKey];
  NodePath.prototype[checkKey] = function (opts) {
    return (
      t.is(aliasName, this.node, opts) ||
      originalProtoCheck.call(this, this.node, opts)
    );
  };
});

// Adds a one time patch to the scope collector visitors to include
// Marko bindings for params and tag vars.
const originalCrawl = Scope.prototype.crawl;
const patchedVisitors = new WeakSet();

Scope.prototype.crawl = function () {
  const path = this.path;
  const originalTraverse = path.traverse;
  path.traverse = function (visitor, state) {
    path.traverse = originalTraverse;

    if (!patchedVisitors.has(visitor)) {
      patchedVisitors.add(visitor);
      Object.assign(
        traverse.explode(visitor),
        traverse.explode({
          MarkoTagBody(body) {
            for (const param of body.get("params")) {
              body.scope.registerBinding("param", param);
            }
          },
          MarkoTag(tag) {
            const tagVar = tag.get("var");
            if (tagVar.node) {
              tag.scope.registerBinding("local", tagVar, tag);
              for (const name in tagVar.getBindingIdentifiers()) {
                let curScope = tag.scope;
                const binding = curScope.getBinding(name);

                while ((curScope = curScope.parent)) {
                  curScope.hoistableTagVars =
                    curScope.hoistableTagVars ||
                    (curScope.hoistableTagVars = {});
                  const existingBinding = curScope.hoistableTagVars[name];

                  if (existingBinding) {
                    if (existingBinding !== binding) {
                      curScope.hoistableTagVars[name] = true;
                    }
                  } else {
                    curScope.hoistableTagVars[name] = binding;
                  }
                }
              }
            }
          }
        })
      );
    }

    this.traverse(visitor, state);

    if (state.references.length) {
      const movedBindings = new Map();
      for (const ref of state.references) {
        const { name } = ref.node;
        let curScope = ref.scope;
        if (curScope.hasBinding(name)) continue;

        do {
          const hoistableBinding =
            curScope.hoistableTagVars && curScope.hoistableTagVars[name];
          if (hoistableBinding) {
            if (hoistableBinding === true) {
              throw ref.buildCodeFrameError(
                "Ambiguous reference, variable was defined in multiple places and was not shadowed."
              );
            }

            const movedBinding = movedBindings.get(hoistableBinding);
            if (
              !movedBinding ||
              getScopeDepth(movedBinding) < getScopeDepth(curScope)
            ) {
              movedBindings.set(hoistableBinding, curScope);
            }
          }
        } while ((curScope = curScope.parent));
      }

      for (const [binding, scope] of movedBindings) {
        binding.scope.moveBindingTo(binding.identifier.name, scope);
      }
    }
  };

  originalCrawl.call(this);
  path.traverse = originalTraverse;
};

function getScopeDepth(scope) {
  let depth = 0;
  let cur = scope;
  while ((cur = cur.parent)) depth++;
  return depth;
}
<|endoftext|>


<commit_before>const   express     = require('express'),
        router      = express.Router(),
        jwt         = require('jsonwebtoken'),
        morgan      = require('morgan'),
        bodyParser  = require('body-parser'),
        secretToken = 'superSecret';

module.exports = function(app, options){

    options.debug && router.use(morgan('api'));

    router.use(bodyParser.urlencoded({ extended: true }));
    router.use(bodyParser.json());

    router.post('/authenticate', function(req, res) {
        var token = jwt.sign({
            username: 'test',
            role: 'ADMIN'
        }, secretToken, {
            expiresIn: 1440*60 // expires in 24 hours
        });

        res.json({
            message: 'Enjoy your token!',
            token: token
        });
    });

    router.use(function(req, res, next) {
        (function(token){
            token ? jwt.verify(token, secretToken, function(err, decoded){
                err ? res.status(403).json({
                    message: 'Failed to authenticate token.'
                }) : next();
            }) : res.status(400).json({
                message: 'No token provided.'
            });
        })(req.body.token || req.query.token || req.headers['x-access-token']);
    });

    require('./views/user.js')(router, app.orm);

    router.get('/', function(req, res) {
        res.json({ message: 'hooray! welcome to our api!' });
    });

    return router;
};
<commit_msg>update: no token provided error api 400 to 401<commit_after>const express = require('express'),
    router = express.Router(),
    jwt = require('jsonwebtoken'),
    morgan = require('morgan'),
    bodyParser = require('body-parser'),
    secretToken = 'superSecret';

module.exports = function(app, options) {

    options.debug && router.use(morgan('api'));

    router.use(bodyParser.urlencoded({
        extended: true
    }));
    router.use(bodyParser.json());

    router.post('/authenticate', function(req, res) {
        var token = jwt.sign({
            username: 'test',
            role: 'ADMIN'
        }, secretToken, {
            expiresIn: 1440 * 60 // expires in 24 hours
        });

        res.json({
            message: 'Enjoy your token!',
            token: token
        });
    });

    router.use(function(req, res, next) {
        (function(token) {
            token ? jwt.verify(token, secretToken, function(err, decoded) {
                err ? res.status(403).json({
                    message: 'Failed to authenticate token.'
                }) : next();
            }) : res.status(401).json({
                message: 'No token provided.'
            });
        })(req.body.token || req.query.token || req.headers['x-access-token']);
    });

    require('./views/user.js')(router, app.orm);

    router.get('/', function(req, res) {
        res.json({
            message: 'hooray! welcome to our api!'
        });
    });

    router.use(function(req, res, next) {
        res.status(404);

        if (req.accepts('json')) {
            res.send({
                error: 'Not found'
            });
            return;
        }
        res.type('txt').send('Not found');
    });

    return router;
};
<|endoftext|>


<commit_before>var path = require('path');
var webpack = require('webpack');

module.exports = {
  entry: [
    path.join(__dirname, 'main.js')
  ],

  output: {
    path: path.join(__dirname, 'dist'),
    filename: 'app.js'
  },

  module: {
    loaders: [
      {test: /\.js$/, exclude: /node_modules/, loader: 'babel'},
      {test: /\.less$/, loader: 'style!css!autoprefixer!less'}
    ]
  },

  resolve: {
    alias: {
      'react-mobile-picker': path.join(__dirname, '..', 'src')
    }
  },

  plugins: [
    new webpack.optimize.OccurenceOrderPlugin(),
    new webpack.DefinePlugin({
      'process.env': {
        NODE_ENV: '"production"'
      }
    }),
    new webpack.optimize.UglifyJsPlugin({
      compressor: {
        warnings: false
      }
    })
  ]
};
<commit_msg>add hash to example bundle<commit_after>var path = require('path');
var webpack = require('webpack');

module.exports = {
  entry: [
    path.join(__dirname, 'main.js')
  ],

  output: {
    path: path.join(__dirname, 'dist'),
    filename: '[hash].app.js'
  },

  module: {
    loaders: [
      {test: /\.js$/, exclude: /node_modules/, loader: 'babel'},
      {test: /\.less$/, loader: 'style!css!autoprefixer!less'}
    ]
  },

  resolve: {
    alias: {
      'react-mobile-picker': path.join(__dirname, '..', 'src')
    }
  },

  plugins: [
    new webpack.optimize.OccurenceOrderPlugin(),
    new webpack.DefinePlugin({
      'process.env': {
        NODE_ENV: '"production"'
      }
    }),
    new webpack.optimize.UglifyJsPlugin({
      compressor: {
        warnings: false
      }
    })
  ]
};
<|endoftext|>


<commit_before>'use strict';

const fs = require('fs');
const path = require('path');

const requestsFile = path.resolve(__dirname, '../config/chat-plugins/genrequests.json');

//const permittedGenners = ['desokoro', 'lombres']
//const permittedGennersByNames = ['Desokoro', 'Lombres']

let genRequests = {requests: [], blacklist: [], permittedGenners: [], permittedGennersByNames: []};
try {
	genRequests = require(requestsFile);
} catch (e) {
	if (e.code !== 'MODULE_NOT_FOUND') throw e;
}

if (!(genRequests || typeof genRequests === 'object')) genRequests = {requests: [], blacklist: [], permittedGenners: [], permittedGennersByNames: []};

function writeGenRequests() {
	fs.writeFileSync(requestsFile, JSON.stringify(genRequests));
}

exports.commands = {
	genreq: function (target, room, user) {
		if (genRequests.blacklist.includes(user.userid)) return false;
		if (user.locked || !user.autoconfirmed) return this.errorReply('You do not have adequate permissions to request a gen.');
		if (!target) return this.errorReply("Please specify something for the gen request.");
		if (target.length > 180) return this.errorReply('|html|Please use a link shortener like Pastebin');
		if (target.includes("pornhub" || "xvideos" || "xnxx")) return this.errorReply('You are not permitted to link those things.');
				if (target.includes("http://" || ".com")) {
			target = '' + 'Gen Request' + '';
		}
		genRequests.requests.push({username: user.name, request: target, time: new Date().toUTCString()});
		writeGenRequests();
		this.sendReply("Your gen request was successfully added to the queue.");
	},

	reqview: function (target, room, user) {
                if (user.userid !== 'desokoro') return this.errorReply('You aren\'t permitted to use this command.');
		//if (!this.can('hotpatch')) return false;
		if (!genRequests.requests.length) return this.errorReply('There are no current genning requests.');
		let output = `There are <b>${genRequests.requests.length}</b> users who requested genning:<br />`;
		for (let i = 0; i < genRequests.requests.length; i++) {
			output += `<b>${genRequests.requests[i].username}</b>: ${genRequests.requests[i].request} (${genRequests.requests[i].time}).<br />`;
		}
		this.sendReplyBox(output);
	},

        gbl: 'genblacklist',
	genblacklist: function (target, room, user) {
                if (user.userid !== 'desokoro') return this.errorReply('You aren\'t permitted to use this command.');
		//if (!this.can('hotpatch')) return false;
		if (!target) return this.errorReply('Please specify a target.');
		let blacklisted = toId(target);
		if (genRequests.blacklist.includes(blacklisted)) return this.errorReply(`${target} is already present on the genning blacklist.`);
		genRequests.blacklist.push(blacklisted);
		writeGenRequests();
		this.sendReply(`${target} was added to the genning blacklist.`);
		// Notify the user that they were blacklisted, if they are online.
		if (Users(blacklisted)) Users(blacklisted).popup(`You were added to the genning blacklist by ${user.name}. If you feel this is unfair, please PM an administrator (~) or the user who blacklisted you.`);
	},

        gwl: 'genunblacklist',
        genwhitelist: 'genunblacklist',
	genunblacklist: function (target, room, user) {
                if (user.userid !== 'desokoro') return this.errorReply('You aren\'t permitted to use this command.');
		//if (!this.can('hotpatch')) return false;
		if (!target) return this.errorReply("Please specify a target.");
		let blacklisted = toId(target);
		if (!genRequests.blacklist.includes(blacklisted)) return this.errorReply(`${target} is currently not on the genning blacklist.`);
		genRequests.blacklist.splice(genRequests.blacklist.indexOf(blacklisted), 1);
		writeGenRequests();
		this.sendReply(`${target} was removed from the genning blacklist.`);
		// Notify the user that they were unblacklisted, if they are online.
		if (Users(blacklisted)) Users(blacklisted).popup(`You were removed from the genning blacklist by ${user.name}.`);
	},

        vbl: 'blacklistview',
        blv: 'blacklistview',
	blacklistview: function (target, room, user) {
                if (user.userid !== 'desokoro') return this.errorReply('You aren\'t permitted to use this command.');
		//if (!this.can('hotpatch')) return false;
		if (!genRequests.blacklist.length) return this.errorReply("There are currently no users on the genning blacklist.");
		let output = `There are <b>${genRequests.blacklist.length}</b> users on the genning blacklist:<br />`;
		for (let i = 0; i < genRequests.blacklist.length; i++) {
			output += `<i>${genRequests.blacklist[i]}</i><br />`;
		}
		this.sendReplyBox(output);
	},

        delreq: 'reqclear',
	reqclear: function (target, room, user) {
                if (user.userid !== 'desokoro') return this.errorReply('You aren\'t permitted to use this command.');
		//if (!this.can('hotpatch')) return false;
		if (!(target || target === 'force')) {
			this.errorReply("WARNING: This will reset all genning requests on the server.");
			this.errorReply("If you wish to continue, use /reqclear force.");
			return;
		}
		// Really lazy hack for doing this - just reset everything in genRequests.requests.
		genRequests.requests = [];
		writeGenRequests();
		this.sendReply("All genning requests were erased from the server.");
	},

	genguide: function (target, room, user) {
	this.sendReplyBox('
GENNING GUIDE

genreq (request): Requests a gen for those who can gen and are permitted by Tsunami to do so

viewgenners: View eligible genners

reportgenner: Reports a genner to Desokoro; use only if absolutely needed

More commands available to all users will be listed here in the future
');
	},

	staffgenguide: function (target, room, user) {
	if (!genRequests.permittedGenners.includes(user.userid) || !genRequests.permittedGennersByNames.includes(user.name)) return this.errorReply('You are not permitted to view this.');
	this.sendReplyBox('
GENNING RESPONSE GUIDE

reqclear: Clears all requests

vbl: Views all blacklisted users

gbl: Blacklists a user.

gwl: Un-blacklists a user
');
	},

	genneradd: function (target, room, user) {
	if (user.userid !== 'desokoro') return this.errorReply('You are not permitted to use this command.');
	if (!target) return this.errorReply('Please specify a target.')
	let targetUser = Users(toId(target));
	if (!targetUser) return this.errorReply('The target user ' + target + ' could not be found. Please check your spelling!');
		if (genRequests.permittedGenners.includes(targetUser.userid) || genRequests.permittedGennersByNames.includes(targetUser.name)) return this.errorReply(`${target} is already present on the permitted genners list.`);
		genRequests.permittedGenners.push(targetUser.userid);
		genRequests.permittedGennersByNames.push(targetUser.name);
		writeGenRequests();
	this.sendReply('You have successfully added ' + targetUser.name + ' to the permitted genners list!');
	console.log(targetUser.name + ' was added to the permitted genners list by ' + user.name + '.');
	},

	removegenner: function (target, room, user) {
	if (user.userid !== 'desokoro') return this.errorReply('You are not permitted to use this command.');
	if (!target) return this.errorReply('Please specify a target.');
	let targetUser = Users(toId(target));
	if (!targetUser) return this.errorReply('The target user ' + target + ' was not found. Check your spelling!');
	if (!genRequests.permittedGenners.includes(targetUser.userid) || !genRequests.permittedGennersByNames.includes(targetUser.name)) return this.errorReply('The target ' + target + ' is not on the permitted genners list.');
		genRequests.permittedGenners.splice(genRequests.permittedGenners.indexOf(targetUser.userid), 1);
		genRequests.permittedGennersByNames.splice(genRequests.permittedGennersByNames.indexOf(targetUser.name), 1);
		writeGenRequests();
	this.sendReply(target + ' was successfully removed from the permitted genners list.');
	console.log(target + ' was removed from the genners list by ' + user.name);
	},

	viewgenners: function (target, room, user) {
	for (let i = 0; i <  genRequests.permittedGennersByNames.length; i++) { this.sendReplyBox(genRequests.permittedGennersByNames[i]);   }
	},

	reportgenner: function (target, room, user) {
	//let CaseSensitiveArray = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']
	if (genRequests.blacklist.includes(user.userid)) return this.errorReply('You are not allowed to partake in any genning services.');
	if (user.canTalk) return this.errorReply('You are currently unable to be trusted due to your disciplinary status; your report will not be accepted.');
	if (!user.autoconfirmed) return this.errorReply('You are not autoconfirmed and your report will not be accepted.');
	if (!target) return this.errorReply('Please specify a target.');
	if (!genRequests.permittedGenners.includes(target) && !genRequests.permittedGennersByNames.includes(target)) return this.errorReply('The user you have reported is not a valid genner.');
	if (target === 'desokoro' || target === 'Desokoro') return this.errorReply('Reporting the owner of the server to himself won\'t do you much good...');
	//if (CaseSensitiveArray.includes(target)) this.errorReply('Only lowercase letters and numbers can be used to report a genner.');
	this.parse('/tell Desokoro, TOKEN OF AUTHENTICITY: ' + user.name + '|' + Math.floor(Math.random() * 20) + '|' +  + Math.floor(Math.random() * 20) + '|' + Math.floor(Math.random() * 20) + '. Reporting genner ' + target + ' for misconduct.');
	},

	gensyscredits: function (target, room, user, connection) {
	this.sendReplyBox('Thank ' + '' + Chat.escapeHTML('Mystifi') + '' + ' for essentially building the framework for the genning request system!. The system is maintained by ' + '' + Chat.escapeHTML('Desokoro') + '' + '.');
	},
};

/*'use strict';

let GenReqArray = []

exports.commands = {
genreq: function (target, room, user) {
if (user.isBlacklisted === true) return this.errorReply('You are blacklisted.');
if (user.locked) return this.errorReply('You do not have adequate permissions to request a gen.');
if (!user.autoconfirmed) return this.errorReply('You do not have adequate permissions to request a gen.');
//if (GenReqArray.length === 0) {
GenReqArray.push(user.userid);
//}
},

reqview: function (target, room, user) {
if (user.userid !== 'desokoro') return this.errorReply('Only Desokoro is permitted to use this.');
if (GenReqArray.length === 0) return this.errorReply('Nobody has requested a gen.');
for (let i = 0; i <  GenReqArray.length; i++) { this.sendReplyBox(GenReqArray[i]);   }
},

genblacklist: function (target, room, user) {
if (user.userid !== 'desokoro') return this.errorReply('You lack the permissions to use this.');
if (!target) return this.errorReply('Please specify a target.');
let targetUser = Users(toId(target));
if (!targetUser) return this.errorReply(target + ' could not be found. Check your spelling.');
if (targetUser.isBlacklisted === true) return this.errorReply(targetUser.username + ' is already blacklisted.');
targetUser.isBlacklisted = true;
this.sendReply(targetUser + ' is now blacklisted.');
},

genwhitelist: function (target, room, user) {
if (user.userid !== 'desokoro') return this.errorReply('You lack the permissions to use this.');
if (!target) return this.errorReply('Please specify a target.');
let targetUser = Users(toId(target));
if (!targetUser) return this.errorReply(target + ' could not be found. Check your spelling.');
if (targetUser.isBlacklisted === false) return this.errorReply(targetUser.username + ' is not blacklisted.');
targetUser.isBlacklisted = false;
this.sendReply(targetUser + ' is no longer blacklisted.');
},

blacklistview: function (target, room, user) {
if (user.userid !== 'desokoro') return this.errorReply('You lack the permissions to use this.');
if (!target) return this.errorReply('Please specify a target.');
let targetUser = Users(toId(target));
if (!targetUser) this.errorReply (target + ' could not be found. Check your spelling.');
if (targetUser.isBlacklisted === true) return this.sendReply('This user is blacklisted.');
else return this.sendReply('This user is not blacklisted.');
},

reqclear: function (target, room, user) {
if (user.userid !== 'desokoro') return this.errorReply('You lack the permissions to use this.');
GenReqArray = []
    this.sendReply('All requests have been cleared.');
console.log('Gen requests have been cleared by ' + user.name);
},
    };*/
<commit_msg>Fix syntax<commit_after>'use strict';

const fs = require('fs');
const path = require('path');

const requestsFile = path.resolve(__dirname, '../config/chat-plugins/genrequests.json');

//const permittedGenners = ['desokoro', 'lombres']
//const permittedGennersByNames = ['Desokoro', 'Lombres']

let genRequests = {requests: [], blacklist: [], permittedGenners: [], permittedGennersByNames: []};
try {
	genRequests = require(requestsFile);
} catch (e) {
	if (e.code !== 'MODULE_NOT_FOUND') throw e;
}

if (!(genRequests || typeof genRequests === 'object')) genRequests = {requests: [], blacklist: [], permittedGenners: [], permittedGennersByNames: []};

function writeGenRequests() {
	fs.writeFileSync(requestsFile, JSON.stringify(genRequests));
}

exports.commands = {
	genreq: function (target, room, user) {
		if (genRequests.blacklist.includes(user.userid)) return false;
		if (user.locked || !user.autoconfirmed) return this.errorReply('You do not have adequate permissions to request a gen.');
		if (!target) return this.errorReply("Please specify something for the gen request.");
		if (target.length > 180) return this.errorReply(|html|'Please use a link shortener like Pastebin');
		if (target.includes("pornhub" || "xvideos" || "xnxx")) return this.errorReply('You are not permitted to link those things.');
				if (target.includes("http://" || ".com")) {
			target = '' + 'Gen Request' + '';
		}
		genRequests.requests.push({username: user.name, request: target, time: new Date().toUTCString()});
		writeGenRequests();
		this.sendReply("Your gen request was successfully added to the queue.");
	},

	reqview: function (target, room, user) {
                if (user.userid !== 'desokoro') return this.errorReply('You aren\'t permitted to use this command.');
		//if (!this.can('hotpatch')) return false;
		if (!genRequests.requests.length) return this.errorReply('There are no current genning requests.');
		let output = `There are <b>${genRequests.requests.length}</b> users who requested genning:<br />`;
		for (let i = 0; i < genRequests.requests.length; i++) {
			output += `<b>${genRequests.requests[i].username}</b>: ${genRequests.requests[i].request} (${genRequests.requests[i].time}).<br />`;
		}
		this.sendReplyBox(output);
	},

        gbl: 'genblacklist',
	genblacklist: function (target, room, user) {
                if (user.userid !== 'desokoro') return this.errorReply('You aren\'t permitted to use this command.');
		//if (!this.can('hotpatch')) return false;
		if (!target) return this.errorReply('Please specify a target.');
		let blacklisted = toId(target);
		if (genRequests.blacklist.includes(blacklisted)) return this.errorReply(`${target} is already present on the genning blacklist.`);
		genRequests.blacklist.push(blacklisted);
		writeGenRequests();
		this.sendReply(`${target} was added to the genning blacklist.`);
		// Notify the user that they were blacklisted, if they are online.
		if (Users(blacklisted)) Users(blacklisted).popup(`You were added to the genning blacklist by ${user.name}. If you feel this is unfair, please PM an administrator (~) or the user who blacklisted you.`);
	},

        gwl: 'genunblacklist',
        genwhitelist: 'genunblacklist',
	genunblacklist: function (target, room, user) {
                if (user.userid !== 'desokoro') return this.errorReply('You aren\'t permitted to use this command.');
		//if (!this.can('hotpatch')) return false;
		if (!target) return this.errorReply("Please specify a target.");
		let blacklisted = toId(target);
		if (!genRequests.blacklist.includes(blacklisted)) return this.errorReply(`${target} is currently not on the genning blacklist.`);
		genRequests.blacklist.splice(genRequests.blacklist.indexOf(blacklisted), 1);
		writeGenRequests();
		this.sendReply(`${target} was removed from the genning blacklist.`);
		// Notify the user that they were unblacklisted, if they are online.
		if (Users(blacklisted)) Users(blacklisted).popup(`You were removed from the genning blacklist by ${user.name}.`);
	},

        vbl: 'blacklistview',
        blv: 'blacklistview',
	blacklistview: function (target, room, user) {
                if (user.userid !== 'desokoro') return this.errorReply('You aren\'t permitted to use this command.');
		//if (!this.can('hotpatch')) return false;
		if (!genRequests.blacklist.length) return this.errorReply("There are currently no users on the genning blacklist.");
		let output = `There are <b>${genRequests.blacklist.length}</b> users on the genning blacklist:<br />`;
		for (let i = 0; i < genRequests.blacklist.length; i++) {
			output += `<i>${genRequests.blacklist[i]}</i><br />`;
		}
		this.sendReplyBox(output);
	},

        delreq: 'reqclear',
	reqclear: function (target, room, user) {
                if (user.userid !== 'desokoro') return this.errorReply('You aren\'t permitted to use this command.');
		//if (!this.can('hotpatch')) return false;
		if (!(target || target === 'force')) {
			this.errorReply("WARNING: This will reset all genning requests on the server.");
			this.errorReply("If you wish to continue, use /reqclear force.");
			return;
		}
		// Really lazy hack for doing this - just reset everything in genRequests.requests.
		genRequests.requests = [];
		writeGenRequests();
		this.sendReply("All genning requests were erased from the server.");
	},

	genguide: function (target, room, user) {
	this.sendReplyBox('
GENNING GUIDE

genreq (request): Requests a gen for those who can gen and are permitted by Tsunami to do so

viewgenners: View eligible genners

reportgenner: Reports a genner to Desokoro; use only if absolutely needed

More commands available to all users will be listed here in the future
');
	},

	staffgenguide: function (target, room, user) {
	if (!genRequests.permittedGenners.includes(user.userid) || !genRequests.permittedGennersByNames.includes(user.name)) return this.errorReply('You are not permitted to view this.');
	this.sendReplyBox('
GENNING RESPONSE GUIDE

reqclear: Clears all requests

vbl: Views all blacklisted users

gbl: Blacklists a user.

gwl: Un-blacklists a user
');
	},

	genneradd: function (target, room, user) {
	if (user.userid !== 'desokoro') return this.errorReply('You are not permitted to use this command.');
	if (!target) return this.errorReply('Please specify a target.')
	let targetUser = Users(toId(target));
	if (!targetUser) return this.errorReply('The target user ' + target + ' could not be found. Please check your spelling!');
		if (genRequests.permittedGenners.includes(targetUser.userid) || genRequests.permittedGennersByNames.includes(targetUser.name)) return this.errorReply(`${target} is already present on the permitted genners list.`);
		genRequests.permittedGenners.push(targetUser.userid);
		genRequests.permittedGennersByNames.push(targetUser.name);
		writeGenRequests();
	this.sendReply('You have successfully added ' + targetUser.name + ' to the permitted genners list!');
	console.log(targetUser.name + ' was added to the permitted genners list by ' + user.name + '.');
	},

	removegenner: function (target, room, user) {
	if (user.userid !== 'desokoro') return this.errorReply('You are not permitted to use this command.');
	if (!target) return this.errorReply('Please specify a target.');
	let targetUser = Users(toId(target));
	if (!targetUser) return this.errorReply('The target user ' + target + ' was not found. Check your spelling!');
	if (!genRequests.permittedGenners.includes(targetUser.userid) || !genRequests.permittedGennersByNames.includes(targetUser.name)) return this.errorReply('The target ' + target + ' is not on the permitted genners list.');
		genRequests.permittedGenners.splice(genRequests.permittedGenners.indexOf(targetUser.userid), 1);
		genRequests.permittedGennersByNames.splice(genRequests.permittedGennersByNames.indexOf(targetUser.name), 1);
		writeGenRequests();
	this.sendReply(target + ' was successfully removed from the permitted genners list.');
	console.log(target + ' was removed from the genners list by ' + user.name);
	},

	viewgenners: function (target, room, user) {
	for (let i = 0; i <  genRequests.permittedGennersByNames.length; i++) { this.sendReplyBox(genRequests.permittedGennersByNames[i]);   }
	},

	reportgenner: function (target, room, user) {
	//let CaseSensitiveArray = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']
	if (genRequests.blacklist.includes(user.userid)) return this.errorReply('You are not allowed to partake in any genning services.');
	if (user.canTalk) return this.errorReply('You are currently unable to be trusted due to your disciplinary status; your report will not be accepted.');
	if (!user.autoconfirmed) return this.errorReply('You are not autoconfirmed and your report will not be accepted.');
	if (!target) return this.errorReply('Please specify a target.');
	if (!genRequests.permittedGenners.includes(target) && !genRequests.permittedGennersByNames.includes(target)) return this.errorReply('The user you have reported is not a valid genner.');
	if (target === 'desokoro' || target === 'Desokoro') return this.errorReply('Reporting the owner of the server to himself won\'t do you much good...');
	//if (CaseSensitiveArray.includes(target)) this.errorReply('Only lowercase letters and numbers can be used to report a genner.');
	this.parse('/tell Desokoro, TOKEN OF AUTHENTICITY: ' + user.name + '|' + Math.floor(Math.random() * 20) + '|' +  + Math.floor(Math.random() * 20) + '|' + Math.floor(Math.random() * 20) + '. Reporting genner ' + target + ' for misconduct.');
	},

	gensyscredits: function (target, room, user, connection) {
	this.sendReplyBox('Thank ' + '' + Chat.escapeHTML('Mystifi') + '' + ' for essentially building the framework for the genning request system!. The system is maintained by ' + '' + Chat.escapeHTML('Desokoro') + '' + '.');
	},
};

/*'use strict';

let GenReqArray = []

exports.commands = {
genreq: function (target, room, user) {
if (user.isBlacklisted === true) return this.errorReply('You are blacklisted.');
if (user.locked) return this.errorReply('You do not have adequate permissions to request a gen.');
if (!user.autoconfirmed) return this.errorReply('You do not have adequate permissions to request a gen.');
//if (GenReqArray.length === 0) {
GenReqArray.push(user.userid);
//}
},

reqview: function (target, room, user) {
if (user.userid !== 'desokoro') return this.errorReply('Only Desokoro is permitted to use this.');
if (GenReqArray.length === 0) return this.errorReply('Nobody has requested a gen.');
for (let i = 0; i <  GenReqArray.length; i++) { this.sendReplyBox(GenReqArray[i]);   }
},

genblacklist: function (target, room, user) {
if (user.userid !== 'desokoro') return this.errorReply('You lack the permissions to use this.');
if (!target) return this.errorReply('Please specify a target.');
let targetUser = Users(toId(target));
if (!targetUser) return this.errorReply(target + ' could not be found. Check your spelling.');
if (targetUser.isBlacklisted === true) return this.errorReply(targetUser.username + ' is already blacklisted.');
targetUser.isBlacklisted = true;
this.sendReply(targetUser + ' is now blacklisted.');
},

genwhitelist: function (target, room, user) {
if (user.userid !== 'desokoro') return this.errorReply('You lack the permissions to use this.');
if (!target) return this.errorReply('Please specify a target.');
let targetUser = Users(toId(target));
if (!targetUser) return this.errorReply(target + ' could not be found. Check your spelling.');
if (targetUser.isBlacklisted === false) return this.errorReply(targetUser.username + ' is not blacklisted.');
targetUser.isBlacklisted = false;
this.sendReply(targetUser + ' is no longer blacklisted.');
},

blacklistview: function (target, room, user) {
if (user.userid !== 'desokoro') return this.errorReply('You lack the permissions to use this.');
if (!target) return this.errorReply('Please specify a target.');
let targetUser = Users(toId(target));
if (!targetUser) this.errorReply (target + ' could not be found. Check your spelling.');
if (targetUser.isBlacklisted === true) return this.sendReply('This user is blacklisted.');
else return this.sendReply('This user is not blacklisted.');
},

reqclear: function (target, room, user) {
if (user.userid !== 'desokoro') return this.errorReply('You lack the permissions to use this.');
GenReqArray = []
    this.sendReply('All requests have been cleared.');
console.log('Gen requests have been cleared by ' + user.name);
},
    };*/
<|endoftext|>


<commit_before>module.exports = require('ember-popover').extend({
    template: require('../templates/period-selector'),

    classNames: ['period-selector'],

    value: null,

    currentType: null,

    matchWidth: false,

    types: function() {
        return [
            Em.O({
                key: 'all',
                name: t('period_selector.all'),
                viewClass: null
            }),
            Em.O({
                key: 'month',
                name: t('period_selector.month'),
                viewClass: require('./period-views/month-view')
            }),
            Em.O({
                key: 'quarter',
                name: t('period_selector.quarter'),
                viewClass: require('./period-views/quarter-view')
            }),
            Em.O({
                key: 'year',
                name: t('period_selector.year'),
                viewClass: require('./period-views/year-view')
            }),
            Em.O({
                key: 'fiscalyear',
                name: t('period_selector.fiscalyear'),
                viewClass: require('./period-views/fiscal-year-view')
            }),
            Em.O({
                key: 'dates',
                name: t('period_selector.dates'),
                viewClass: require('./period-views/dates-view')
            })
        ];
    }.property(),

    actions: {
        select: function(value) {
            this.trigger('select', value);
        }
    },

    itemViewClass: require('./item-view')
});<commit_msg>expose periods<commit_after>module.exports = require('ember-popover').extend({
    template: require('../templates/period-selector'),

    classNames: ['period-selector'],

    value: null,

    currentType: null,

    matchWidth: false,

    types: function() {
        return [
            Em.O({
                key: 'all',
                name: t('period_selector.all'),
                viewClass: null
            }),
            Em.O({
                key: 'month',
                name: t('period_selector.month'),
                viewClass: require('./period-views/month-view')
            }),
            Em.O({
                key: 'quarter',
                name: t('period_selector.quarter'),
                viewClass: require('./period-views/quarter-view')
            }),
            Em.O({
                key: 'year',
                name: t('period_selector.year'),
                viewClass: require('./period-views/year-view')
            }),
            Em.O({
                key: 'fiscalyear',
                name: t('period_selector.fiscalyear'),
                viewClass: require('./period-views/fiscal-year-view')
            }),
            Em.O({
                key: 'dates',
                name: t('period_selector.dates'),
                viewClass: require('./period-views/dates-view')
            })
        ];
    }.property(),

    actions: {
        select: function(value) {
            this.trigger('select', value);
        }
    },

    itemViewClass: require('./item-view')
});

module.exports.periods = require('./periods');<|endoftext|>


<commit_before>// ==========================================================================
// YouTube plugin
// ==========================================================================

import ui from '../ui';
import { createElement, replaceElement, toggleClass } from '../utils/elements';
import { triggerEvent } from '../utils/events';
import fetch from '../utils/fetch';
import is from '../utils/is';
import loadImage from '../utils/loadImage';
import loadScript from '../utils/loadScript';
import { extend } from '../utils/objects';
import { format, generateId } from '../utils/strings';
import { setAspectRatio } from '../utils/style';

// Parse YouTube ID from URL
function parseId(url) {
    if (is.empty(url)) {
        return null;
    }

    const regex = /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|&v=)([^#&?]*).*/;
    return url.match(regex) ? RegExp.$2 : url;
}

// Set playback state and trigger change (only on actual change)
function assurePlaybackState(play) {
    if (play && !this.embed.hasPlayed) {
        this.embed.hasPlayed = true;
    }
    if (this.media.paused === play) {
        this.media.paused = !play;
        triggerEvent.call(this, this.media, play ? 'play' : 'pause');
    }
}

function useHttp() {
    return !window.location.href.includes('https://');
}

function getYoutubeHost(config) {
    let host;

    if (config.noCookie) {
        host = 'https://www.youtube-nocookie.com';
    } else {
        host = useHttp() ? 'http://www.youtube.com' : undefined;
    }

    return host;
}

const youtube = {
    setup() {
        // Add embed class for responsive
        toggleClass(this.elements.wrapper, this.config.classNames.embed, true);

        // Set aspect ratio
        setAspectRatio.call(this);

        // Setup API
        if (is.object(window.YT) && is.function(window.YT.Player)) {
            youtube.ready.call(this);
        } else {
            // Load the API
            loadScript(this.config.urls.youtube.sdk).catch(error => {
                this.debug.warn('YouTube API failed to load', error);
            });

            // Setup callback for the API
            // YouTube has it's own system of course...
            window.onYouTubeReadyCallbacks = window.onYouTubeReadyCallbacks || [];

            // Add to queue
            window.onYouTubeReadyCallbacks.push(() => {
                youtube.ready.call(this);
            });

            // Set callback to process queue
            window.onYouTubeIframeAPIReady = () => {
                window.onYouTubeReadyCallbacks.forEach(callback => {
                    callback();
                });
            };
        }
    },

    // Get the media title
    getTitle(videoId) {
        // Try via undocumented API method first
        // This method disappears now and then though...
        // https://github.com/sampotts/plyr/issues/709
        if (is.function(this.embed.getVideoData)) {
            const { title } = this.embed.getVideoData();

            if (is.empty(title)) {
                this.config.title = title;
                ui.setTitle.call(this);
                return;
            }
        }

        // Or via Google API
        const key = this.config.keys.google;
        if (is.string(key) && !is.empty(key)) {
            const url = format(this.config.urls.youtube.api, videoId, key);

            fetch(url)
                .then(result => {
                    if (is.object(result)) {
                        this.config.title = result.items[0].snippet.title;
                        ui.setTitle.call(this);
                    }
                })
                .catch(() => {});
        }
    },

    // API ready
    ready() {
        const player = this;

        // Ignore already setup (race condition)
        const currentId = player.media.getAttribute('id');
        if (!is.empty(currentId) && currentId.startsWith('youtube-')) {
            return;
        }

        // Get the source URL or ID
        let source = player.media.getAttribute('src');

        // Get from <div> if needed
        if (is.empty(source)) {
            source = player.media.getAttribute(this.config.attributes.embed.id);
        }

        // Replace the <iframe> with a <div> due to YouTube API issues
        const videoId = parseId(source);
        const id = generateId(player.provider);

        // Get poster, if already set
        const { poster } = player;

        // Replace media element
        const container = createElement('div', { id, poster });
        player.media = replaceElement(container, player.media);

        // Id to poster wrapper
        const posterSrc = format => `https://i.ytimg.com/vi/${videoId}/${format}default.jpg`;

        // Check thumbnail images in order of quality, but reject fallback thumbnails (120px wide)
        loadImage(posterSrc('maxres'), 121) // Higest quality and unpadded
            .catch(() => loadImage(posterSrc('sd'), 121)) // 480p padded 4:3
            .catch(() => loadImage(posterSrc('hq'))) // 360p padded 4:3. Always exists
            .then(image => ui.setPoster.call(player, image.src))
            .then(posterSrc => {
                // If the image is padded, use background-size "cover" instead (like youtube does too with their posters)
                if (!posterSrc.includes('maxres')) {
                    player.elements.poster.style.backgroundSize = 'cover';
                }
            })
            .catch(() => {});

        const config = player.config.youtube;

        // Setup instance
        // https://developers.google.com/youtube/iframe_api_reference
        player.embed = new window.YT.Player(id, {
            videoId,
            host: getYoutubeHost(config),
            playerVars: extend(
                {},
                {
                    autoplay: player.config.autoplay ? 1 : 0, // Autoplay
                    hl: player.config.hl, // iframe interface language
                    controls: player.supported.ui ? 0 : 1, // Only show controls if not fully supported
                    disablekb: 1, // Disable keyboard as we handle it
                    playsinline: !player.config.fullscreen.iosNative ? 1 : 0, // Allow iOS inline playback
                    // Captions are flaky on YouTube
                    cc_load_policy: player.captions.active ? 1 : 0,
                    cc_lang_pref: player.config.captions.language,
                    // Tracking for stats
                    widget_referrer: window ? window.location.href : null,
                },
                config,
            ),
            events: {
                onError(event) {
                    // YouTube may fire onError twice, so only handle it once
                    if (!player.media.error) {
                        const code = event.data;
                        // Messages copied from https://developers.google.com/youtube/iframe_api_reference#onError
                        const message =
                            {
                                2: 'The request contains an invalid parameter value. For example, this error occurs if you specify a video ID that does not have 11 characters, or if the video ID contains invalid characters, such as exclamation points or asterisks.',
                                5: 'The requested content cannot be played in an HTML5 player or another error related to the HTML5 player has occurred.',
                                100: 'The video requested was not found. This error occurs when a video has been removed (for any reason) or has been marked as private.',
                                101: 'The owner of the requested video does not allow it to be played in embedded players.',
                                150: 'The owner of the requested video does not allow it to be played in embedded players.',
                            }[code] || 'An unknown error occured';

                        player.media.error = { code, message };

                        triggerEvent.call(player, player.media, 'error');
                    }
                },
                onPlaybackRateChange(event) {
                    // Get the instance
                    const instance = event.target;

                    // Get current speed
                    player.media.playbackRate = instance.getPlaybackRate();

                    triggerEvent.call(player, player.media, 'ratechange');
                },
                onReady(event) {
                    // Bail if onReady has already been called. See issue #1108
                    if (is.function(player.media.play)) {
                        return;
                    }
                    // Get the instance
                    const instance = event.target;

                    // Get the title
                    youtube.getTitle.call(player, videoId);

                    // Create a faux HTML5 API using the YouTube API
                    player.media.play = () => {
                        assurePlaybackState.call(player, true);
                        instance.playVideo();
                    };

                    player.media.pause = () => {
                        assurePlaybackState.call(player, false);
                        instance.pauseVideo();
                    };

                    player.media.stop = () => {
                        instance.stopVideo();
                    };

                    player.media.duration = instance.getDuration();
                    player.media.paused = true;

                    // Seeking
                    player.media.currentTime = 0;
                    Object.defineProperty(player.media, 'currentTime', {
                        get() {
                            return Number(instance.getCurrentTime());
                        },
                        set(time) {
                            // If paused and never played, mute audio preventively (YouTube starts playing on seek if the video hasn't been played yet).
                            if (player.paused && !player.embed.hasPlayed) {
                                player.embed.mute();
                            }

                            // Set seeking state and trigger event
                            player.media.seeking = true;
                            triggerEvent.call(player, player.media, 'seeking');

                            // Seek after events sent
                            instance.seekTo(time);
                        },
                    });

                    // Playback speed
                    Object.defineProperty(player.media, 'playbackRate', {
                        get() {
                            return instance.getPlaybackRate();
                        },
                        set(input) {
                            instance.setPlaybackRate(input);
                        },
                    });

                    // Volume
                    let { volume } = player.config;
                    Object.defineProperty(player.media, 'volume', {
                        get() {
                            return volume;
                        },
                        set(input) {
                            volume = input;
                            instance.setVolume(volume * 100);
                            triggerEvent.call(player, player.media, 'volumechange');
                        },
                    });

                    // Muted
                    let { muted } = player.config;
                    Object.defineProperty(player.media, 'muted', {
                        get() {
                            return muted;
                        },
                        set(input) {
                            const toggle = is.boolean(input) ? input : muted;
                            muted = toggle;
                            instance[toggle ? 'mute' : 'unMute']();
                            triggerEvent.call(player, player.media, 'volumechange');
                        },
                    });

                    // Source
                    Object.defineProperty(player.media, 'currentSrc', {
                        get() {
                            return instance.getVideoUrl();
                        },
                    });

                    // Ended
                    Object.defineProperty(player.media, 'ended', {
                        get() {
                            return player.currentTime === player.duration;
                        },
                    });

                    // Get available speeds
                    player.options.speed = instance.getAvailablePlaybackRates();

                    // Set the tabindex to avoid focus entering iframe
                    if (player.supported.ui) {
                        player.media.setAttribute('tabindex', -1);
                    }

                    triggerEvent.call(player, player.media, 'timeupdate');
                    triggerEvent.call(player, player.media, 'durationchange');

                    // Reset timer
                    clearInterval(player.timers.buffering);

                    // Setup buffering
                    player.timers.buffering = setInterval(() => {
                        // Get loaded % from YouTube
                        player.media.buffered = instance.getVideoLoadedFraction();

                        // Trigger progress only when we actually buffer something
                        if (player.media.lastBuffered === null || player.media.lastBuffered < player.media.buffered) {
                            triggerEvent.call(player, player.media, 'progress');
                        }

                        // Set last buffer point
                        player.media.lastBuffered = player.media.buffered;

                        // Bail if we're at 100%
                        if (player.media.buffered === 1) {
                            clearInterval(player.timers.buffering);

                            // Trigger event
                            triggerEvent.call(player, player.media, 'canplaythrough');
                        }
                    }, 200);

                    // Rebuild UI
                    setTimeout(() => ui.build.call(player), 50);
                },
                onStateChange(event) {
                    // Get the instance
                    const instance = event.target;

                    // Reset timer
                    clearInterval(player.timers.playing);

                    const seeked = player.media.seeking && [1, 2].includes(event.data);

                    if (seeked) {
                        // Unset seeking and fire seeked event
                        player.media.seeking = false;
                        triggerEvent.call(player, player.media, 'seeked');
                    }

                    // Handle events
                    // -1   Unstarted
                    // 0    Ended
                    // 1    Playing
                    // 2    Paused
                    // 3    Buffering
                    // 5    Video cued
                    switch (event.data) {
                        case -1:
                            // Update scrubber
                            triggerEvent.call(player, player.media, 'timeupdate');

                            // Get loaded % from YouTube
                            player.media.buffered = instance.getVideoLoadedFraction();
                            triggerEvent.call(player, player.media, 'progress');

                            break;

                        case 0:
                            assurePlaybackState.call(player, false);

                            // YouTube doesn't support loop for a single video, so mimick it.
                            if (player.media.loop) {
                                // YouTube needs a call to `stopVideo` before playing again
                                instance.stopVideo();
                                instance.playVideo();
                            } else {
                                triggerEvent.call(player, player.media, 'ended');
                            }

                            break;

                        case 1:
                            // Restore paused state (YouTube starts playing on seek if the video hasn't been played yet)
                            if (player.media.paused && !player.embed.hasPlayed) {
                                player.media.pause();
                            } else {
                                assurePlaybackState.call(player, true);

                                triggerEvent.call(player, player.media, 'playing');

                                // Poll to get playback progress
                                player.timers.playing = setInterval(() => {
                                    triggerEvent.call(player, player.media, 'timeupdate');
                                }, 50);

                                // Check duration again due to YouTube bug
                                // https://github.com/sampotts/plyr/issues/374
                                // https://code.google.com/p/gdata-issues/issues/detail?id=8690
                                if (player.media.duration !== instance.getDuration()) {
                                    player.media.duration = instance.getDuration();
                                    triggerEvent.call(player, player.media, 'durationchange');
                                }
                            }

                            break;

                        case 2:
                            // Restore audio (YouTube starts playing on seek if the video hasn't been played yet)
                            if (!player.muted) {
                                player.embed.unMute();
                            }
                            assurePlaybackState.call(player, false);

                            break;

                        default:
                            break;
                    }

                    triggerEvent.call(player, player.elements.container, 'statechange', false, {
                        code: event.data,
                    });
                },
            },
        });
    },
};

export default youtube;
<commit_msg>code cleanup<commit_after>// ==========================================================================
// YouTube plugin
// ==========================================================================

import ui from '../ui';
import { createElement, replaceElement, toggleClass } from '../utils/elements';
import { triggerEvent } from '../utils/events';
import fetch from '../utils/fetch';
import is from '../utils/is';
import loadImage from '../utils/loadImage';
import loadScript from '../utils/loadScript';
import { extend } from '../utils/objects';
import { format, generateId } from '../utils/strings';
import { setAspectRatio } from '../utils/style';

// Parse YouTube ID from URL
function parseId(url) {
    if (is.empty(url)) {
        return null;
    }

    const regex = /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|&v=)([^#&?]*).*/;
    return url.match(regex) ? RegExp.$2 : url;
}

// Set playback state and trigger change (only on actual change)
function assurePlaybackState(play) {
    if (play && !this.embed.hasPlayed) {
        this.embed.hasPlayed = true;
    }
    if (this.media.paused === play) {
        this.media.paused = !play;
        triggerEvent.call(this, this.media, play ? 'play' : 'pause');
    }
}

function getYoutubeHost(config) {
    if (config.noCookie) {
        return 'https://www.youtube-nocookie.com';
    }

    return `${window.location.protocol}//www.youtube.com`;
}

const youtube = {
    setup() {
        // Add embed class for responsive
        toggleClass(this.elements.wrapper, this.config.classNames.embed, true);

        // Set aspect ratio
        setAspectRatio.call(this);

        // Setup API
        if (is.object(window.YT) && is.function(window.YT.Player)) {
            youtube.ready.call(this);
        } else {
            // Load the API
            loadScript(this.config.urls.youtube.sdk).catch(error => {
                this.debug.warn('YouTube API failed to load', error);
            });

            // Setup callback for the API
            // YouTube has it's own system of course...
            window.onYouTubeReadyCallbacks = window.onYouTubeReadyCallbacks || [];

            // Add to queue
            window.onYouTubeReadyCallbacks.push(() => {
                youtube.ready.call(this);
            });

            // Set callback to process queue
            window.onYouTubeIframeAPIReady = () => {
                window.onYouTubeReadyCallbacks.forEach(callback => {
                    callback();
                });
            };
        }
    },

    // Get the media title
    getTitle(videoId) {
        // Try via undocumented API method first
        // This method disappears now and then though...
        // https://github.com/sampotts/plyr/issues/709
        if (is.function(this.embed.getVideoData)) {
            const { title } = this.embed.getVideoData();

            if (is.empty(title)) {
                this.config.title = title;
                ui.setTitle.call(this);
                return;
            }
        }

        // Or via Google API
        const key = this.config.keys.google;
        if (is.string(key) && !is.empty(key)) {
            const url = format(this.config.urls.youtube.api, videoId, key);

            fetch(url)
                .then(result => {
                    if (is.object(result)) {
                        this.config.title = result.items[0].snippet.title;
                        ui.setTitle.call(this);
                    }
                })
                .catch(() => {});
        }
    },

    // API ready
    ready() {
        const player = this;

        // Ignore already setup (race condition)
        const currentId = player.media.getAttribute('id');
        if (!is.empty(currentId) && currentId.startsWith('youtube-')) {
            return;
        }

        // Get the source URL or ID
        let source = player.media.getAttribute('src');

        // Get from <div> if needed
        if (is.empty(source)) {
            source = player.media.getAttribute(this.config.attributes.embed.id);
        }

        // Replace the <iframe> with a <div> due to YouTube API issues
        const videoId = parseId(source);
        const id = generateId(player.provider);

        // Get poster, if already set
        const { poster } = player;

        // Replace media element
        const container = createElement('div', { id, poster });
        player.media = replaceElement(container, player.media);

        // Id to poster wrapper
        const posterSrc = format => `https://i.ytimg.com/vi/${videoId}/${format}default.jpg`;

        // Check thumbnail images in order of quality, but reject fallback thumbnails (120px wide)
        loadImage(posterSrc('maxres'), 121) // Higest quality and unpadded
            .catch(() => loadImage(posterSrc('sd'), 121)) // 480p padded 4:3
            .catch(() => loadImage(posterSrc('hq'))) // 360p padded 4:3. Always exists
            .then(image => ui.setPoster.call(player, image.src))
            .then(posterSrc => {
                // If the image is padded, use background-size "cover" instead (like youtube does too with their posters)
                if (!posterSrc.includes('maxres')) {
                    player.elements.poster.style.backgroundSize = 'cover';
                }
            })
            .catch(() => {});

        const config = player.config.youtube;

        // Setup instance
        // https://developers.google.com/youtube/iframe_api_reference
        player.embed = new window.YT.Player(id, {
            videoId,
            host: getYoutubeHost(config),
            playerVars: extend(
                {},
                {
                    autoplay: player.config.autoplay ? 1 : 0, // Autoplay
                    hl: player.config.hl, // iframe interface language
                    controls: player.supported.ui ? 0 : 1, // Only show controls if not fully supported
                    disablekb: 1, // Disable keyboard as we handle it
                    playsinline: !player.config.fullscreen.iosNative ? 1 : 0, // Allow iOS inline playback
                    // Captions are flaky on YouTube
                    cc_load_policy: player.captions.active ? 1 : 0,
                    cc_lang_pref: player.config.captions.language,
                    // Tracking for stats
                    widget_referrer: window ? window.location.href : null,
                },
                config,
            ),
            events: {
                onError(event) {
                    // YouTube may fire onError twice, so only handle it once
                    if (!player.media.error) {
                        const code = event.data;
                        // Messages copied from https://developers.google.com/youtube/iframe_api_reference#onError
                        const message =
                            {
                                2: 'The request contains an invalid parameter value. For example, this error occurs if you specify a video ID that does not have 11 characters, or if the video ID contains invalid characters, such as exclamation points or asterisks.',
                                5: 'The requested content cannot be played in an HTML5 player or another error related to the HTML5 player has occurred.',
                                100: 'The video requested was not found. This error occurs when a video has been removed (for any reason) or has been marked as private.',
                                101: 'The owner of the requested video does not allow it to be played in embedded players.',
                                150: 'The owner of the requested video does not allow it to be played in embedded players.',
                            }[code] || 'An unknown error occured';

                        player.media.error = { code, message };

                        triggerEvent.call(player, player.media, 'error');
                    }
                },
                onPlaybackRateChange(event) {
                    // Get the instance
                    const instance = event.target;

                    // Get current speed
                    player.media.playbackRate = instance.getPlaybackRate();

                    triggerEvent.call(player, player.media, 'ratechange');
                },
                onReady(event) {
                    // Bail if onReady has already been called. See issue #1108
                    if (is.function(player.media.play)) {
                        return;
                    }
                    // Get the instance
                    const instance = event.target;

                    // Get the title
                    youtube.getTitle.call(player, videoId);

                    // Create a faux HTML5 API using the YouTube API
                    player.media.play = () => {
                        assurePlaybackState.call(player, true);
                        instance.playVideo();
                    };

                    player.media.pause = () => {
                        assurePlaybackState.call(player, false);
                        instance.pauseVideo();
                    };

                    player.media.stop = () => {
                        instance.stopVideo();
                    };

                    player.media.duration = instance.getDuration();
                    player.media.paused = true;

                    // Seeking
                    player.media.currentTime = 0;
                    Object.defineProperty(player.media, 'currentTime', {
                        get() {
                            return Number(instance.getCurrentTime());
                        },
                        set(time) {
                            // If paused and never played, mute audio preventively (YouTube starts playing on seek if the video hasn't been played yet).
                            if (player.paused && !player.embed.hasPlayed) {
                                player.embed.mute();
                            }

                            // Set seeking state and trigger event
                            player.media.seeking = true;
                            triggerEvent.call(player, player.media, 'seeking');

                            // Seek after events sent
                            instance.seekTo(time);
                        },
                    });

                    // Playback speed
                    Object.defineProperty(player.media, 'playbackRate', {
                        get() {
                            return instance.getPlaybackRate();
                        },
                        set(input) {
                            instance.setPlaybackRate(input);
                        },
                    });

                    // Volume
                    let { volume } = player.config;
                    Object.defineProperty(player.media, 'volume', {
                        get() {
                            return volume;
                        },
                        set(input) {
                            volume = input;
                            instance.setVolume(volume * 100);
                            triggerEvent.call(player, player.media, 'volumechange');
                        },
                    });

                    // Muted
                    let { muted } = player.config;
                    Object.defineProperty(player.media, 'muted', {
                        get() {
                            return muted;
                        },
                        set(input) {
                            const toggle = is.boolean(input) ? input : muted;
                            muted = toggle;
                            instance[toggle ? 'mute' : 'unMute']();
                            triggerEvent.call(player, player.media, 'volumechange');
                        },
                    });

                    // Source
                    Object.defineProperty(player.media, 'currentSrc', {
                        get() {
                            return instance.getVideoUrl();
                        },
                    });

                    // Ended
                    Object.defineProperty(player.media, 'ended', {
                        get() {
                            return player.currentTime === player.duration;
                        },
                    });

                    // Get available speeds
                    player.options.speed = instance.getAvailablePlaybackRates();

                    // Set the tabindex to avoid focus entering iframe
                    if (player.supported.ui) {
                        player.media.setAttribute('tabindex', -1);
                    }

                    triggerEvent.call(player, player.media, 'timeupdate');
                    triggerEvent.call(player, player.media, 'durationchange');

                    // Reset timer
                    clearInterval(player.timers.buffering);

                    // Setup buffering
                    player.timers.buffering = setInterval(() => {
                        // Get loaded % from YouTube
                        player.media.buffered = instance.getVideoLoadedFraction();

                        // Trigger progress only when we actually buffer something
                        if (player.media.lastBuffered === null || player.media.lastBuffered < player.media.buffered) {
                            triggerEvent.call(player, player.media, 'progress');
                        }

                        // Set last buffer point
                        player.media.lastBuffered = player.media.buffered;

                        // Bail if we're at 100%
                        if (player.media.buffered === 1) {
                            clearInterval(player.timers.buffering);

                            // Trigger event
                            triggerEvent.call(player, player.media, 'canplaythrough');
                        }
                    }, 200);

                    // Rebuild UI
                    setTimeout(() => ui.build.call(player), 50);
                },
                onStateChange(event) {
                    // Get the instance
                    const instance = event.target;

                    // Reset timer
                    clearInterval(player.timers.playing);

                    const seeked = player.media.seeking && [1, 2].includes(event.data);

                    if (seeked) {
                        // Unset seeking and fire seeked event
                        player.media.seeking = false;
                        triggerEvent.call(player, player.media, 'seeked');
                    }

                    // Handle events
                    // -1   Unstarted
                    // 0    Ended
                    // 1    Playing
                    // 2    Paused
                    // 3    Buffering
                    // 5    Video cued
                    switch (event.data) {
                        case -1:
                            // Update scrubber
                            triggerEvent.call(player, player.media, 'timeupdate');

                            // Get loaded % from YouTube
                            player.media.buffered = instance.getVideoLoadedFraction();
                            triggerEvent.call(player, player.media, 'progress');

                            break;

                        case 0:
                            assurePlaybackState.call(player, false);

                            // YouTube doesn't support loop for a single video, so mimick it.
                            if (player.media.loop) {
                                // YouTube needs a call to `stopVideo` before playing again
                                instance.stopVideo();
                                instance.playVideo();
                            } else {
                                triggerEvent.call(player, player.media, 'ended');
                            }

                            break;

                        case 1:
                            // Restore paused state (YouTube starts playing on seek if the video hasn't been played yet)
                            if (player.media.paused && !player.embed.hasPlayed) {
                                player.media.pause();
                            } else {
                                assurePlaybackState.call(player, true);

                                triggerEvent.call(player, player.media, 'playing');

                                // Poll to get playback progress
                                player.timers.playing = setInterval(() => {
                                    triggerEvent.call(player, player.media, 'timeupdate');
                                }, 50);

                                // Check duration again due to YouTube bug
                                // https://github.com/sampotts/plyr/issues/374
                                // https://code.google.com/p/gdata-issues/issues/detail?id=8690
                                if (player.media.duration !== instance.getDuration()) {
                                    player.media.duration = instance.getDuration();
                                    triggerEvent.call(player, player.media, 'durationchange');
                                }
                            }

                            break;

                        case 2:
                            // Restore audio (YouTube starts playing on seek if the video hasn't been played yet)
                            if (!player.muted) {
                                player.embed.unMute();
                            }
                            assurePlaybackState.call(player, false);

                            break;

                        default:
                            break;
                    }

                    triggerEvent.call(player, player.elements.container, 'statechange', false, {
                        code: event.data,
                    });
                },
            },
        });
    },
};

export default youtube;
<|endoftext|>


<commit_before>CESIUM_BASE_URL = '/cesium/Cesium/';

var CesiumSwitcher = function(opt_options) {
  var options = opt_options || {};
  var control = this;

  var enabled = false;
  var ol3d = undefined;

  var element = document.createElement('div');
  element.className = 'CesiumSwitcher ol-unselectable';

  var draw = function() {
    $(element).on('click touchend', $.proxy(onClick, control));
    control.setMode(this.enabled);
  };

  var onClick = function(evt) {
    control.setMode(!this.enabled);
    evt.preventDefault();
  };

  ol.control.Control.call(this, {
    element: element,
    target: options.target
  });

  draw();
};

ol.inherits(CesiumSwitcher, ol.control.Control);

/**
 * Sets the 3d mode.
 * @param {bool} mode - Enabled or not
 */
CesiumSwitcher.prototype.setMode = function(mode) {
  if (mode) {
    this.element.innerHTML = '';
    $(this).triggerHandler('cesium_enable');
    this.loadCesium();
  } else {
    this.element.innerHTML = '';
    if (this.ol3d) {
      $(this).triggerHandler('cesium_disable');
      this.ol3d.setEnabled(false);
      this.getMap().getView().setRotation(0);
    }
  }

  this.enabled = mode;
};

/**
 * Loads cesium.
 */
CesiumSwitcher.prototype.loadCesium = function() {
  var _this = this;

  if (typeof Cesium === 'undefined') {
    var cesium = document.createElement('script');
    cesium.src = '/cesium/Cesium/Cesium.js';
    cesium.onload = function() {
      _this.loadOL3cesium();
    };
    document.body.appendChild(cesium);
  }
};

/**
 * Loads ol3-cesium.
 */
CesiumSwitcher.prototype.loadOL3cesium = function() {
  var _this = this;

  if (typeof olcs === 'undefined') {
    var ol3cesium = document.createElement('script');
    ol3cesium.src = '/cesium/ol3cesium.js';
    ol3cesium.onload = function() {
      _this.enableCesium();
    };
    document.body.appendChild(ol3cesium);
  }
};

/**
 * Enbables ol3-cesium.
 */
CesiumSwitcher.prototype.enableCesium = function() {
  if (!this.ol3d) {
    var map = this.getMap();

    this.ol3d = new olcs.OLCesium({map: map});
    var scene = this.ol3d.getCesiumScene();
    var terrainProvider = new Cesium.CesiumTerrainProvider({
      url: '//assets.agi.com/stk-terrain/world'
    });
    scene.terrainProvider = terrainProvider;
    scene.globe.depthTestAgainstTerrain = true;
  }

  this.ol3d.setEnabled(true);
};

/**
 * Returns the mode of cesium (3d or 2d).
 * @return {bool}
 */
CesiumSwitcher.prototype.getMode = function() {
  return this.enabled;
};

/**
 * @param {slFlight} flight
 * @param {Array} fix_data
 */
CesiumSwitcher.prototype.showPlane = function(flight, fix_data) {
  var lonlat = ol.proj.transform([fix_data['lon'], fix_data['lat']],
                                 'EPSG:3857', 'EPSG:4326');

  var position = Cesium.Cartesian3.fromDegrees(lonlat[0], lonlat[1],
      fix_data['alt-msl'] + flight.getGeoid());
  var modelMatrix = Cesium.Transforms.headingPitchRollToFixedFrame(position,
      fix_data['heading'] - Math.PI / 2, 0, 0);

  if (!flight.getPlane().entity) {
    var scene = this.ol3d.getCesiumScene();
    var entity = Cesium.Model.fromGltf({
      modelMatrix: modelMatrix,
      url: '../../images/Cesium_Air.gltf',
      scale: 1,
      minimumPixelSize: 64,
      allowPicking: false
    });
    scene.primitives.add(entity);
    flight.getPlane().entity = entity;
  } else {
    flight.getPlane().entity.modelMatrix = modelMatrix;
    flight.getPlane().entity.show = true;
  }
};

/**
 * @param {slFlight} flight
 */
CesiumSwitcher.prototype.hidePlane = function(flight) {
  if (flight.getPlane().entity) {
    flight.getPlane().entity.show = false;
  }
};
<commit_msg>ol-CesiumSwitcher: enable AutoRenderLoop<commit_after>CESIUM_BASE_URL = '/cesium/Cesium/';

var CesiumSwitcher = function(opt_options) {
  var options = opt_options || {};
  var control = this;

  var enabled = false;
  var ol3d = undefined;

  var element = document.createElement('div');
  element.className = 'CesiumSwitcher ol-unselectable';

  var draw = function() {
    $(element).on('click touchend', $.proxy(onClick, control));
    control.setMode(this.enabled);
  };

  var onClick = function(evt) {
    control.setMode(!this.enabled);
    evt.preventDefault();
  };

  ol.control.Control.call(this, {
    element: element,
    target: options.target
  });

  draw();
};

ol.inherits(CesiumSwitcher, ol.control.Control);

/**
 * Sets the 3d mode.
 * @param {bool} mode - Enabled or not
 */
CesiumSwitcher.prototype.setMode = function(mode) {
  if (mode) {
    this.element.innerHTML = '';
    $(this).triggerHandler('cesium_enable');
    this.loadCesium();
  } else {
    this.element.innerHTML = '';
    if (this.ol3d) {
      $(this).triggerHandler('cesium_disable');
      this.ol3d.setEnabled(false);
      this.getMap().getView().setRotation(0);
    }
  }

  this.enabled = mode;
};

/**
 * Loads cesium.
 */
CesiumSwitcher.prototype.loadCesium = function() {
  var _this = this;

  if (typeof Cesium === 'undefined') {
    var cesium = document.createElement('script');
    cesium.src = '/cesium/Cesium/Cesium.js';
    cesium.onload = function() {
      _this.loadOL3cesium();
    };
    document.body.appendChild(cesium);
  }
};

/**
 * Loads ol3-cesium.
 */
CesiumSwitcher.prototype.loadOL3cesium = function() {
  var _this = this;

  if (typeof olcs === 'undefined') {
    var ol3cesium = document.createElement('script');
    ol3cesium.src = '/cesium/ol3cesium.js';
    ol3cesium.onload = function() {
      _this.enableCesium();
    };
    document.body.appendChild(ol3cesium);
  }
};

/**
 * Enbables ol3-cesium.
 */
CesiumSwitcher.prototype.enableCesium = function() {
  if (!this.ol3d) {
    var map = this.getMap();

    this.ol3d = new olcs.OLCesium({map: map});
    var scene = this.ol3d.getCesiumScene();
    var terrainProvider = new Cesium.CesiumTerrainProvider({
      url: '//assets.agi.com/stk-terrain/world'
    });
    scene.terrainProvider = terrainProvider;
    scene.globe.depthTestAgainstTerrain = true;
  }

  this.ol3d.setEnabled(true);
  this.ol3d.enableAutoRenderLoop();
};

/**
 * Returns the mode of cesium (3d or 2d).
 * @return {bool}
 */
CesiumSwitcher.prototype.getMode = function() {
  return this.enabled;
};

/**
 * @param {slFlight} flight
 * @param {Array} fix_data
 */
CesiumSwitcher.prototype.showPlane = function(flight, fix_data) {
  var lonlat = ol.proj.transform([fix_data['lon'], fix_data['lat']],
                                 'EPSG:3857', 'EPSG:4326');

  var position = Cesium.Cartesian3.fromDegrees(lonlat[0], lonlat[1],
      fix_data['alt-msl'] + flight.getGeoid());
  var modelMatrix = Cesium.Transforms.headingPitchRollToFixedFrame(position,
      fix_data['heading'] - Math.PI / 2, 0, 0);

  if (!flight.getPlane().entity) {
    var scene = this.ol3d.getCesiumScene();
    var entity = Cesium.Model.fromGltf({
      modelMatrix: modelMatrix,
      url: '../../images/Cesium_Air.gltf',
      scale: 1,
      minimumPixelSize: 64,
      allowPicking: false
    });
    scene.primitives.add(entity);
    flight.getPlane().entity = entity;
  } else {
    flight.getPlane().entity.modelMatrix = modelMatrix;
    flight.getPlane().entity.show = true;
  }
};

/**
 * @param {slFlight} flight
 */
CesiumSwitcher.prototype.hidePlane = function(flight) {
  if (flight.getPlane().entity) {
    flight.getPlane().entity.show = false;
  }
};
<|endoftext|>


<commit_before>$(document).ready(function() {
    update_inventory();
});

function update_inventory() {
    $('#FilterBestiaryForm').submit();
}

$('body')
    .on('submit', '#FilterBestiaryForm', function() {
        ToggleLoading($('#wrap'));

        var $form = $(this);
        $.ajax({
            type: $form.attr('method'),
            url: $form.attr('action'),
            data: $form.serialize()
        }).done(function (data) {
            ToggleLoading($('#wrap'), false);
            $('#bestiary-inventory').replaceWith(data);

            //Reinit everything
            $('[data-toggle="tooltip"]').tooltip({
                container: 'body'
            });
            $('[data-toggle="popover"]').popover({
                html:true,
                viewport: {selector: 'body', padding: 2}
            });

            $('#bestiary_table').tablesorter({
                widgets: ['saveSort', 'columnSelector', 'stickyHeaders'],
                serverSideSorting: true,
                widgetOptions: {
                    filter_reset: '.reset',
                    columnSelector_container : '#column-selectors',
                    columnSelector_saveColumns: true,
                    columnSelector_mediaquery: false,
                    columnSelector_layout: '<input type="checkbox">{name}',
                    stickyHeaders_zIndex : 2,
                    stickyHeaders_offset: 100
                }
            })
            .bind('sortBegin', function(e, table) {
                var sortColumn = e.target.config.sortList[0][0];
                var sortDirection = e.target.config.sortList[0][1] == 0 ? 'asc' : 'desc';
                var sort_header = slugify($(table).find('th')[sortColumn].innerText);

                $('#id_sort').val(sort_header + ';' + sortDirection);
                update_inventory();
                //throw new Error("");    //shitty but only way of preventing sort from actually happening
            });
        });

        return false;  //cancel default on submit action.
    })
    .on('click', '.reset', function() {
        $('#monster_table').trigger('sortReset');
        var form = $('#FilterBestiaryForm');
        form[0].reset();
        form.find('label').toggleClass('active', false);

        update_inventory();
    })
    .on('click', '.pager-btn', function() {
        $('#id_page').val($(this).data('page'));
        update_inventory();
    });<commit_msg>Fixed resetting saved sort on fresh page load since it always returns default sorting first load.<commit_after>$(document).ready(function() {
    update_inventory();
});

function update_inventory() {
    $('#FilterBestiaryForm').submit();
}

$('body')
    .on('submit', '#FilterBestiaryForm', function() {
        ToggleLoading($('#wrap'));

        var $form = $(this);
        $.ajax({
            type: $form.attr('method'),
            url: $form.attr('action'),
            data: $form.serialize()
        }).done(function (data) {
            ToggleLoading($('#wrap'), false);
            $('#bestiary-inventory').replaceWith(data);

            //Reinit everything
            $('[data-toggle="tooltip"]').tooltip({
                container: 'body'
            });
            $('[data-toggle="popover"]').popover({
                html:true,
                viewport: {selector: 'body', padding: 2}
            });
            var bestiary_table = $('#bestiary_table');
            bestiary_table.tablesorter({
                widgets: ['saveSort', 'columnSelector', 'stickyHeaders'],
                serverSideSorting: true,
                widgetOptions: {
                    filter_reset: '.reset',
                    columnSelector_container : '#column-selectors',
                    columnSelector_saveColumns: true,
                    columnSelector_mediaquery: false,
                    columnSelector_layout: '<input type="checkbox">{name}',
                    stickyHeaders_zIndex : 2,
                    stickyHeaders_offset: 100
                }
            })
            .bind('sortBegin', function(e, table) {
                var sortColumn = e.target.config.sortList[0][0];
                var sortDirection = e.target.config.sortList[0][1] == 0 ? 'asc' : 'desc';
                var sort_header = slugify($(table).find('th')[sortColumn].innerText);

                $('#id_sort').val(sort_header + ';' + sortDirection);
                update_inventory();
            });

            // Trigger a sort reset if the sort form field is empty
            if (!$('#id_sort').val()) {
                bestiary_table.trigger('sortReset');
                bestiary_table.trigger('saveSortReset');
            }
        });

        return false;  //cancel default on submit action.
    })
    .on('click', '.reset', function() {
        $('#monster_table').trigger('sortReset');
        var form = $('#FilterBestiaryForm');
        form[0].reset();
        $('#id_sort').val('');
        form.find('label').toggleClass('active', false);

        update_inventory();
    })
    .on('click', '.pager-btn', function() {
        $('#id_page').val($(this).data('page'));
        update_inventory();
    });<|endoftext|>