<commit_before>/*global
    window, document, alert, XMLHttpRequest
 */

(function () {
    "use strict";

    var console = window.console,
        log = (console)
            ? console.log.bind(console)
            : function () {
                return;
            };

    /*
    function extend(target, source) {
        Object.keys(source).forEach(function (key) {
            if (target[key] === undefined) {
                target[key] = source[key];
            }
        });
    }

    function asyncGet(url, onSuccess, onFailure) {
        var xhr = new XMLHttpRequest();
        xhr.open('GET', encodeURI(url), true);  // asynchronous
        xhr.onreadystatechange = function () {
            if (xhr.readyState === 4) {  // response received and loaded
                if (xhr.status === 200) {
                    onSuccess(xhr.responseText, xhr.statusText);
                } else {
                    onFailure(xhr.statusText);
                }
            }
        };
        xhr.send(null);
    }
    */

    function parseUrl(url) {
        var a = document.createElement('a');
        a.href = url;
        return a;
    }

    function parseQueryParams(location) {
        var query = location.search.substr(1),
            pairs = query.split("&"),
            params = {};
        pairs.forEach(function (e) {
            var pair = e.split("="),
                name = decodeURIComponent(pair[0]),
                value = decodeURIComponent(pair[1] || "");
            params[name] = value;
        });
        return params;
    }

    /* Spy "class" */
    function createSpy() {
        // There's also:
        // - http://www.nainwak.com/accueil/resume.php?IDS=...&errmsg=
        var IDS = parseQueryParams(window.location).IDS,
            infoFrame = window.info.frameElement,
            enabled = false,
            infoLoaded = function () {
                var infoDoc = window.info.document,
                    url = infoDoc.location;
                //html = infoDoc.documentElement.innerHTML;
                log("info frame loaded: " + url);
            },
            gameUrl = function (name) {
                return 'http://www.nainwak.com/jeu/' + name + '.php?IDS=' + IDS;
            },
            gameUrls = {
                menu: gameUrl('menu'),  // Menu principal
                pager: gameUrl('pager'),  // Pager : PV/PA, compteur des messages
                pub: gameUrl('pub'),  // Publicités
                map: gameUrl('map'),  // Carte de la détection
                detect: gameUrl('detect'),  // Détection
                deplac: gameUrl('deplac'),  // Action
                invent: gameUrl('invent'),  // Inventaire
                perso: gameUrl('perso'),  // Fiche de perso
                even: gameUrl('even') + "&duree=240&type=ALL",  // événements : tous types d'evts sur 10 jours
                chat: gameUrl('chat'),  // Messagerie
                guilde: gameUrl('guilde'),  // Guilde
                encyclo: gameUrl('encyclo')  // Encyclopédie
            },
            sendUpdate = function () {
                Object.keys(gameUrls).forEach(function (name) {
                    var url = gameUrls[name];
                    log(name + ": " + url);
                });
                //asyncGet(gameUrls.detect, log, log);
            },
            createUI = function () {
                var button = document.createElement("button");
                button.setAttribute("class", "spy");
                button.setAttribute("type", "button");
                button.innerHTML = "Lancer MAJ";
                button.onclick = sendUpdate;
                return button;
            },
            isEnabled = function () {
                return enabled;
            },
            enable = function () {
                if (isEnabled()) {
                    return false;
                }

                infoFrame.addEventListener('load', infoLoaded, false);
                enabled = true;
                return true;
            },
            disable = function () {
                if (!isEnabled()) {
                    return false;
                }

                infoFrame.removeEventListener('load', infoLoaded, false);
                enabled = false;
                return true;
            };

        // TODO: we should implement a getter/setter for the enabled flag
        return Object.freeze({
            isEnabled: isEnabled,
            enable: enable,
            disable: disable,
            createUI: createUI  // TODO: we should not expose that directly
        });
    }

    /* Application "class" */
    function createApplication(container, hubUrl, cssUrl) {
        var spy = createSpy(),  // Spy instance
            containerContent = null,  // initial content of the container
            createHubFrame = function () {
                var iframe = document.createElement("iframe");
                iframe.setAttribute("class", "hub");
                iframe.setAttribute("src", hubUrl);
                return iframe;
            },
            createCssLink = function () {
                var link = document.createElement('link');
                link.setAttribute('rel', 'stylesheet');
                link.setAttribute('type', 'text/css');
                link.setAttribute('href', cssUrl);
                return link;
            },
            createUI = function () {
                var root = document.createElement("div"),
                    spyUI = spy.createUI(),
                    hubFrame;

                root.setAttribute("class", "nainwaklet");

                if (spyUI) {
                    root.appendChild(spyUI);
                }

                hubFrame = createHubFrame();
                root.appendChild(hubFrame);

                return root;
            },
            ui = createUI(),  // application UI
            cssLink = createCssLink(), // application CSS link
            isEnabled = function () {
                return containerContent !== null;
            },
            enable = function () {
                /* This method installs the application UI in the container
                 * element if the application is not already enabled.
                 */
                if (isEnabled()) {
                    return false;
                }

                var doc = container.ownerDocument,
                    head = doc.getElementsByTagName('head')[0];

                // add the CSS element to the head
                head.appendChild(cssLink);

                // backup the initial content
                containerContent = container.innerHTML;

                // replace by our UI
                container.innerHTML = "";
                container.appendChild(ui);

                // enable the spy agent
                spy.enable();

                return true;
            },
            disable = function () {
                /* This method removes the application UI from the container
                 * element and restores its content if the application is enabled.
                 */
                if (!isEnabled()) {
                    return false;
                }

                // disable the spy agent
                spy.disable();

                // restore the initial content
                container.innerHTML = containerContent;
                containerContent = null;

                // remove the CSS element
                cssLink.parentNode.removeChild(cssLink);

                return true;
            };

        // TODO: we should implement a getter/setter for the enabled flag
        return Object.freeze({
            isEnabled: isEnabled,
            enable: enable,
            disable: disable,
            spy: spy
        });
    }

    function isNainwakGamePage() {
        var path = window.location.origin + window.location.pathname;
        return path === "http://www.nainwak.com/jeu/index.php";
    }

    function toggleApp() {
        var currentScript = document.scripts[document.scripts.length - 1],
            scriptLocation = parseUrl(currentScript.src),
            scriptUrl = scriptLocation.origin + scriptLocation.pathname,
            scriptParams = parseQueryParams(scriptLocation),
            cssUrl = scriptUrl.replace('.js', '.css'),
            hubUrl = scriptParams.hub,
            container = window.pub.document.body,
            app = window.nainwakletApp;

        if (!app) {  // app not initialized => create & enable
            app = createApplication(container, hubUrl, cssUrl);
            app.enable();
            window.nainwakletApp = app;
        } else {  // app already initialized => disable & delete
            app.disable();
            delete window.nainwakletApp;
        }
    }

    if (isNainwakGamePage()) {
        toggleApp();
    } else {
        alert("Erreur : ce bouton fonctionne uniquement sur la page jeu de Nainwak");
    }
}());<commit_msg>Minor improvement, reuse the infoFrame variable in infoLoaded<commit_after>/*global
    window, document, alert, XMLHttpRequest
 */

(function () {
    "use strict";

    var console = window.console,
        log = (console)
            ? console.log.bind(console)
            : function () {
                return;
            };

    /*
    function extend(target, source) {
        Object.keys(source).forEach(function (key) {
            if (target[key] === undefined) {
                target[key] = source[key];
            }
        });
    }

    function asyncGet(url, onSuccess, onFailure) {
        var xhr = new XMLHttpRequest();
        xhr.open('GET', encodeURI(url), true);  // asynchronous
        xhr.onreadystatechange = function () {
            if (xhr.readyState === 4) {  // response received and loaded
                if (xhr.status === 200) {
                    onSuccess(xhr.responseText, xhr.statusText);
                } else {
                    onFailure(xhr.statusText);
                }
            }
        };
        xhr.send(null);
    }
    */

    function parseUrl(url) {
        var a = document.createElement('a');
        a.href = url;
        return a;
    }

    function parseQueryParams(location) {
        var query = location.search.substr(1),
            pairs = query.split("&"),
            params = {};
        pairs.forEach(function (e) {
            var pair = e.split("="),
                name = decodeURIComponent(pair[0]),
                value = decodeURIComponent(pair[1] || "");
            params[name] = value;
        });
        return params;
    }

    /* Spy "class" */
    function createSpy() {
        // There's also:
        // - http://www.nainwak.com/accueil/resume.php?IDS=...&errmsg=
        var IDS = parseQueryParams(window.location).IDS,
            infoFrame = window.info.frameElement,
            enabled = false,
            infoLoaded = function () {
                var infoDoc = infoFrame.contentDocument,
                    url = infoDoc.location;
                //html = infoDoc.documentElement.innerHTML;
                log("info frame loaded: " + url);
            },
            gameUrl = function (name) {
                return 'http://www.nainwak.com/jeu/' + name + '.php?IDS=' + IDS;
            },
            gameUrls = {
                menu: gameUrl('menu'),  // Menu principal
                pager: gameUrl('pager'),  // Pager : PV/PA, compteur des messages
                pub: gameUrl('pub'),  // Publicités
                map: gameUrl('map'),  // Carte de la détection
                detect: gameUrl('detect'),  // Détection
                deplac: gameUrl('deplac'),  // Action
                invent: gameUrl('invent'),  // Inventaire
                perso: gameUrl('perso'),  // Fiche de perso
                even: gameUrl('even') + "&duree=240&type=ALL",  // événements : tous types d'evts sur 10 jours
                chat: gameUrl('chat'),  // Messagerie
                guilde: gameUrl('guilde'),  // Guilde
                encyclo: gameUrl('encyclo')  // Encyclopédie
            },
            sendUpdate = function () {
                Object.keys(gameUrls).forEach(function (name) {
                    var url = gameUrls[name];
                    log(name + ": " + url);
                });
                //asyncGet(gameUrls.detect, log, log);
            },
            createUI = function () {
                var button = document.createElement("button");
                button.setAttribute("class", "spy");
                button.setAttribute("type", "button");
                button.innerHTML = "Lancer MAJ";
                button.onclick = sendUpdate;
                return button;
            },
            isEnabled = function () {
                return enabled;
            },
            enable = function () {
                if (isEnabled()) {
                    return false;
                }

                infoFrame.addEventListener('load', infoLoaded, false);
                enabled = true;
                return true;
            },
            disable = function () {
                if (!isEnabled()) {
                    return false;
                }

                infoFrame.removeEventListener('load', infoLoaded, false);
                enabled = false;
                return true;
            };

        // TODO: we should implement a getter/setter for the enabled flag
        return Object.freeze({
            isEnabled: isEnabled,
            enable: enable,
            disable: disable,
            createUI: createUI  // TODO: we should not expose that directly
        });
    }

    /* Application "class" */
    function createApplication(container, hubUrl, cssUrl) {
        var spy = createSpy(),  // Spy instance
            containerContent = null,  // initial content of the container
            createHubFrame = function () {
                var iframe = document.createElement("iframe");
                iframe.setAttribute("class", "hub");
                iframe.setAttribute("src", hubUrl);
                return iframe;
            },
            createCssLink = function () {
                var link = document.createElement('link');
                link.setAttribute('rel', 'stylesheet');
                link.setAttribute('type', 'text/css');
                link.setAttribute('href', cssUrl);
                return link;
            },
            createUI = function () {
                var root = document.createElement("div"),
                    spyUI = spy.createUI(),
                    hubFrame;

                root.setAttribute("class", "nainwaklet");

                if (spyUI) {
                    root.appendChild(spyUI);
                }

                hubFrame = createHubFrame();
                root.appendChild(hubFrame);

                return root;
            },
            ui = createUI(),  // application UI
            cssLink = createCssLink(), // application CSS link
            isEnabled = function () {
                return containerContent !== null;
            },
            enable = function () {
                /* This method installs the application UI in the container
                 * element if the application is not already enabled.
                 */
                if (isEnabled()) {
                    return false;
                }

                var doc = container.ownerDocument,
                    head = doc.getElementsByTagName('head')[0];

                // add the CSS element to the head
                head.appendChild(cssLink);

                // backup the initial content
                containerContent = container.innerHTML;

                // replace by our UI
                container.innerHTML = "";
                container.appendChild(ui);

                // enable the spy agent
                spy.enable();

                return true;
            },
            disable = function () {
                /* This method removes the application UI from the container
                 * element and restores its content if the application is enabled.
                 */
                if (!isEnabled()) {
                    return false;
                }

                // disable the spy agent
                spy.disable();

                // restore the initial content
                container.innerHTML = containerContent;
                containerContent = null;

                // remove the CSS element
                cssLink.parentNode.removeChild(cssLink);

                return true;
            };

        // TODO: we should implement a getter/setter for the enabled flag
        return Object.freeze({
            isEnabled: isEnabled,
            enable: enable,
            disable: disable,
            spy: spy
        });
    }

    function isNainwakGamePage() {
        var path = window.location.origin + window.location.pathname;
        return path === "http://www.nainwak.com/jeu/index.php";
    }

    function toggleApp() {
        var currentScript = document.scripts[document.scripts.length - 1],
            scriptLocation = parseUrl(currentScript.src),
            scriptUrl = scriptLocation.origin + scriptLocation.pathname,
            scriptParams = parseQueryParams(scriptLocation),
            cssUrl = scriptUrl.replace('.js', '.css'),
            hubUrl = scriptParams.hub,
            container = window.pub.document.body,
            app = window.nainwakletApp;

        if (!app) {  // app not initialized => create & enable
            app = createApplication(container, hubUrl, cssUrl);
            app.enable();
            window.nainwakletApp = app;
        } else {  // app already initialized => disable & delete
            app.disable();
            delete window.nainwakletApp;
        }
    }

    if (isNainwakGamePage()) {
        toggleApp();
    } else {
        alert("Erreur : ce bouton fonctionne uniquement sur la page jeu de Nainwak");
    }
}());<|endoftext|>


<commit_before>// credits for the creation of this game goes to Dragotic.
'use strict';

let color = require('../config/color');

let diceOne = function (dice) {
	dice = Math.floor(Math.random() * 6) + 1;
	return dice;
};

let diceTwo = function (dice) {
	dice = Math.floor(Math.random() * 6) + 1;
	return dice;
};

let rng = function (n) {
	n = Math.floor(Math.random() * 100);
	return n;
};

function isEven(n) {
	return n % 2 === 0;
}

function isOdd(n) {
	return Math.abs(n % 2) === 1;
}

exports.commands = {
	bet: function (target, room, user) {
		let firstDice = diceOne();
		let secondDice = diceTwo();
		let totalDice = firstDice + secondDice;
		let house = rng();

		let choice = target.toUpperCase();

		let amount = Db('money').get(user.userid, 0);
		if (room.id !== 'casino' && !~developers.indexOf(this.userid)) return this.errorReply('betting games can only be used in Casino');

		if (amount < 2) return this.errorReply("You don't have enough bucks for the bet.");

		if (!target) return this.parse('/help bet');

		switch (choice) {
		case 'ODD':
			Db('money').set(user.userid, amount - 2).get(user.userid);
			if (isOdd(totalDice) && house < 87) {
				this.sendReply('|raw|

' + user.name + ' betted on "' + choice + '".
' + user.name + '\'s both dices rolled a
total of ' + totalDice + '.

You Win!!

');
				Db('money').set(user.userid, amount + 2).get(user.userid);
			} else {
				this.sendReply('|raw|

' + user.name + ' betted on "' + choice + '".
' + user.name + '
You lose... better luck next time!

');
			}
			break;
		case 'EVEN':
			Db('money').set(user.userid, amount - 2).get(user.userid);
			if (isEven(totalDice) && house < 87) {
				this.sendReply('|raw|

' + user.name + ' betted on "' + choice + '".
' + user.name + '\'s both dices rolled a
total of ' + totalDice + '.

You Win!!

');
				Db('money').set(user.userid, amount + 2).get(user.userid);
			} else {
				this.sendReply('|raw|

' + user.name + ' betted on "' + choice + '".
' + user.name + '
You lose... better luck next time!

');
			}
			break;
		case '7': case 'SEVEN':
			Db('money').set(user.userid, amount - 2).get(user.userid);
			if (totalDice === 7 && house < 70) {
				this.sendReply('|raw|

' + user.name + ' betted on "' + choice + '".
' + user.name + '\'s both dices rolled a
total of ' + totalDice + '.

You Win!!

');
				Db('money').set(user.userid, amount + 14).get(user.userid);
			} else {
				this.sendReply('|raw|

' + user.name + ' betted on "' + choice + '".
' + user.name + '
You lose... better luck next time!

');
			}
			break;
		default:
			this.errorReply("Not a valid bet.");
		}
	},
	bethelp: ["/bet [type] - rolls two dices and adds the two to make a final number. Choose between odd, even or seven. If you guess correctly you win bucks (betting for seven and winning awards more bucks)."],
};
<commit_msg>Update betting-game.js<commit_after>// credits for the creation of this game goes to Dragotic.
'use strict';

let color = require('../config/color');

let diceOne = function (dice) {
	dice = Math.floor(Math.random() * 6) + 1;
	return dice;
};

let diceTwo = function (dice) {
	dice = Math.floor(Math.random() * 6) + 1;
	return dice;
};

let rng = function (n) {
	n = Math.floor(Math.random() * 100);
	return n;
};

function isEven(n) {
	return n % 2 === 0;
}

function isOdd(n) {
	return Math.abs(n % 2) === 1;
}

exports.commands = {
	betting: function (target, room, user) {
		let firstDice = diceOne();
		let secondDice = diceTwo();
		let totalDice = firstDice + secondDice;
		let house = rng();

		let choice = target.toUpperCase();

		let amount = Db('money').get(user.userid, 0);
		if (room.id !== 'casino') return this.errorReply('betting games can only be used in Casino');

		if (amount < 2) return this.errorReply("You don't have enough bucks for the bet.");

		if (!target) return this.parse('/help betting');

		switch (choice) {
		case 'ODD':
			Db('money').set(user.userid, amount - 2).get(user.userid);
			if (isOdd(totalDice) && house < 87) {
				this.sendReply('|raw|

' + user.name + ' betted on "' + choice + '".
' + user.name + '\'s both dices rolled a
total of ' + totalDice + '.

You Win!!

');
				Db('money').set(user.userid, amount + 2).get(user.userid);
			} else {
				this.sendReply('|raw|

' + user.name + ' betted on "' + choice + '".
' + user.name + '
You lose... better luck next time!

');
			}
			break;
		case 'EVEN':
			Db('money').set(user.userid, amount - 2).get(user.userid);
			if (isEven(totalDice) && house < 87) {
				this.sendReply('|raw|

' + user.name + ' betted on "' + choice + '".
' + user.name + '\'s both dices rolled a
total of ' + totalDice + '.

You Win!!

');
				Db('money').set(user.userid, amount + 2).get(user.userid);
			} else {
				this.sendReply('|raw|

' + user.name + ' betted on "' + choice + '".
' + user.name + '
You lose... better luck next time!

');
			}
			break;
		case '7': case 'SEVEN':
			Db('money').set(user.userid, amount - 2).get(user.userid);
			if (totalDice === 7 && house < 70) {
				this.sendReply('|raw|

' + user.name + ' betted on "' + choice + '".
' + user.name + '\'s both dices rolled a
total of ' + totalDice + '.

You Win!!

');
				Db('money').set(user.userid, amount + 14).get(user.userid);
			} else {
				this.sendReply('|raw|

' + user.name + ' betted on "' + choice + '".
' + user.name + '
You lose... better luck next time!

');
			}
			break;
		default:
			this.errorReply("Not a valid bet.");
		}
	},
	bethelp: ["/bet [type] - rolls two dices and adds the two to make a final number. Choose between odd, even or seven. If you guess correctly you win bucks (betting for seven and winning awards more bucks)."],
};
<|endoftext|>


<commit_before>'use strict';

const cloudinary = require('cloudinary').v2;
// const schema = require('../config/schema');
// const crypto = require('crypto');
// const Photo = schema.models.Photo;
// const multipart = require('connect-multiparty');
// const multipartMiddleware = multipart();
const Photo = require('../../db/models/EventPhoto');

const uploadOptions = (evt) => ({
  public_id: (evtName => encodeURIComponent(evtName))(evt.name),
  folder: ((uuid) => `React-Timeline/${uuid}/`)(evt.uuid),
  use_filename: true,
  unique_filename: true,
  resource_type: 'auto',
  type: 'upload',
  access_mode: 'public',
  discard_original_filename: false,
  overwrite: true,
  async: true,
  return_delete_token: true,
  allowed_formats: ['mp4', 'ogv', 'jpg', 'png', 'pdf'],
  tags: ((tags) => ['React-Timeline', 'Cloudinary Upload', 'Event Photo', 'Unsigned'].concat(tags))(evt.type)
});

//
const addNewPhoto = (req, res, next) => {
  const { title, url, dateTaken, locationTaken, isCoverPhoto } = req.body;
  const photoData = { title, url, dateTaken, locationTaken, isCoverPhoto };
  new Photo(photoData)
    .save()
    .then(() => Photo.findOne({ url }))
    .then(photo => res.json(photo))
    .catch(() => {
      res.status(400).send('Failed to create new photo!');
      next();
    });
};

//
function create_through_server(req, res, next) {
  // In through-the-server mode, the image is first uploaded to the server
  // and from there to Cloudinary servers.
  // The upload metadata (e.g. image size) is then added to the photo  model (photo.image)
  // and then saved to the database.

  cloudinary.config({
    cloud_name: process.env.CLOUD_NAME,
    api_key: process.env.API_KEY,
    api_secret: process.env.API_SECRET
  });

  // file was not uploaded redirecting to upload
    // if (req.files.image.ws.bytesWritten == 0) {
    //   res.redirect('/photos/add');
    //   return;
    // }

  console.log('\n\nREQ BODY:', req.body);
  const { evt, url, title } = req.body;
  var photo = new Photo({ title, url });

  // Upload file to Cloudinary
  cloudinary.uploader
    .upload(url, uploadOptions(evt))
    .then(photo => res.send(photo))
    .catch(err => {
      console.log('Error uploading photo to Cloudinary:\t', err);
      next();
    });
}

module.exports = {
  addNewPhoto,
  create_through_server
};
<commit_msg>feat (Controller): Make concurrent GET requests on /photos endpoint<commit_after>'use strict';
const Cloudinary = require('cloudinary').v2;
// const schema = require('../config/schema');
// const crypto = require('crypto');
// const Photo = schema.models.Photo;
// const multipart = require('connect-multiparty');
// const multipartMiddleware = multipart();
const Photo = require('../../db/models/EventPhoto');
const Axios = require('axios');

const uploadOptions = (evt) => ({
  public_id: (evt => evt.name)(evt),
  folder: ((uuid) => `React-Timeline/${uuid}/`)(evt.uuid),
  use_filename: true,
  unique_filename: true,
  resource_type: 'auto',
  type: 'upload',
  access_mode: 'public',
  discard_original_filename: false,
  overwrite: true,
  async: true,
  return_delete_token: true,
  allowed_formats: ['bmp', 'gif', 'jpg', 'mp4', 'ogv', 'pdf', 'png', 'svg', 'tiff', 'raw'],
  tags: ((tags) => ['React-Timeline', 'Cloudinary Upload', 'Event Photo', 'Unsigned'].concat(tags))(evt.type)
});

//
const addNewPhoto = (req, res, next) => {
  const { title, url, dateTaken, locationTaken, isCoverPhoto } = req.body;
  const photoData = { title, url, dateTaken, locationTaken, isCoverPhoto };
  new Photo(photoData)
    .save()
    .then(() => Photo.findOne({ url }))
    .then(photo => res.json(photo))
    .catch(() => {
      res.status(400).send('Failed to create new photo!');
      next();
    });
};

// In through-the-server mode, the image is first uploaded to the server
//  and from there to Cloudinary servers. The upload metadata (e.g., image
//  size) is then added to the photo  model (photo.image) and then saved
//  to the database.
const serverSideCloudinaryUpload = (req, res, next) => {
  console.log('\n\nREQ BODY:', req.body);
  const { evt, url, title } = req.body;
  var photo = new Photo({ title, url });

  Cloudinary.uploader
    .upload(url, uploadOptions(evt))
    .then(photo => res.send(photo))
    .catch(err => {
      console.log(`Error uploading photo to Cloudinary:\t${err}`);
      next();
    });
};

//
const fetchSubfolderNames = () => {
  const extractSubfolderName = (path) => path.replace(/^.+\/(.+)\/.+$/, '$1');

  return Axios
    .get(`${process.env.ADMIN_URL}/folders/React-Timeline`);
    // .then(resp => {
    //   console.log(resp.data);
    //   res.json(resp.data.folders);
    // })
    // .catch(err => {
    //   console.log(err);
    //   next();
    // });
};

const fetchAll = () => {
  /**
   * Other Endpoints:
   *   > /folders/React-Timeline
   *   > /resources/image/upload
   */
  console.log('\n\n\nSTARTING CALL\n\n');
  return Axios
    .get(`${process.env.ADMIN_URL}/resources/image`)
    // .then(resp => {
    //   const tlImages = resp.data.resources.filter(img => /^React-Timeline\//.test(img.public_id))
    //   // console.log(tlImages);
    //   // res.json(tlImages);
    //   return tlImages;
    // });
    // .catch(err => {
    //   console.log('ERROR:', err);
    //   next();
    // });
};

//
const fetchCloudinaryImageData = (req, res, next) => {
  return Axios
    .all([fetchSubfolderNames(), fetchAll()])
    .then(Axios.spread(function(subfolders, images) {
      const [subfolderNames, tlImages] = [
        subfolders.data.folders,
        images.data.resources.filter(img => /^React-Timeline\//.test(img.public_id))
      ];
      res.json({ subfolderNames, tlImages });
    }))
    .catch(err => {
      console.log('Error:', err);
      next();
    });
};

module.exports = {
  addNewPhoto,
  serverSideCloudinaryUpload,
  fetchSubfolderNames,
  fetchAll,
  fetchCloudinaryImageData
};
<|endoftext|>


<commit_before>/* eslint-disable no-restricted-syntax, no-invalid-this */
'use strict';

// MODULES //

var setReadOnly = require( '@stdlib/utils/define-read-only-property' );
var isPositive = require( '@stdlib/assert/is-positive-number').isPrimitive;
var entropy = require( '@stdlib/math/base/dist/levy/entropy' );
var mean = require( '@stdlib/math/base/dist/levy/mean' );
var median = require( '@stdlib/math/base/dist/levy/median' );
var mode = require( '@stdlib/math/base/dist/levy/mode' );
var variance = require( '@stdlib/math/base/dist/levy/variance' );
var cdf = require( '@stdlib/math/base/dist/levy/cdf' );
var logpdf = require( '@stdlib/math/base/dist/levy/logpdf' );
var pdf = require( '@stdlib/math/base/dist/levy/pdf' );
var quantile = require( '@stdlib/math/base/dist/levy/quantile' );

// FUNCTIONS //

/**
* Evaluates the cumulative distribution function (CDF).
*
* @private
* @param {number} x - input value
* @returns {Probability} evaluated CDF
*/
function levyCDF( x ) {
	return cdf( x, this.mu, this.c );
} // end FUNCTION levyCDF()

/**
* Evaluates the natural logarithm of the probability density function (logPDF).
*
* @private
* @param {number} x - input value
* @returns {number} evaluated logPDF
*/
function levyLogPDF( x ) {
	return logpdf( x, this.mu, this.c );
} // end FUNCTION levyLogPDF()

/**
* Evaluates the probability density function (PDF).
*
* @private
* @param {number} x - input value
* @returns {number} evaluated PDF
*/
function levyPDF( x ) {
	return pdf( x, this.mu, this.c );
} // end FUNCTION levyPDF()

/**
* Evaluates the quantile function.
*
* @private
* @param {Probability} p - input probability
* @returns {number} evaluated quantile function
*/
function levyQuantile( p ) {
	return quantile( p, this.mu, this.c );
} // end FUNCTION levyQuantile()

// MAIN //

/**
* Lévy distribution constructor.
*
* @constructor
* @param {number} [mu=0.0] - location parameter
* @param {PositiveNumber} [c=1.0] - scale parameter
* @throws {TypeError} `c` must be a positive number
* @returns {Levy} distribution instance
*
* @example
* var levy = new Levy( 1.0, 1.0 );
*
* var y = levy.cdf( 0.8 );
* // returns 0.8
*
* var mu = levy.mean;
* // returns 0.5
*/
function Levy() {
	var mu;
	var c;
	if ( !(this instanceof Levy) ) {
		if ( arguments.length === 0 ) {
			return new Levy();
		}
		return new Levy( arguments[ 0 ], arguments[ 1 ] );
	}
	if ( arguments.length ) {
		mu = arguments[ 0 ];
		c = arguments[ 1 ];
		if ( !isPositive( c ) ) {
			throw new TypeError( 'invalid input argument. Scale parameter `c` must be a positive number. Value: `' + c + '`' );
		}
	} else {
		mu = 0.0;
		c = 1.0;
	}
	Object.defineProperty( this, 'mu', {
		'configurable': false,
		'enumerable': true,
		'get': function get() {
			return mu;
		},
		'set': function set( value ) {
			mu = value;
		}
	});
	Object.defineProperty( this, 'c', {
		'configurable': false,
		'enumerable': true,
		'get': function get() {
			return c;
		},
		'set': function set( value ) {
			if ( !isPositive( value ) ) {
				throw new TypeError( 'invalid value. Must be a positive number. Value: `' + value + '`' );
			}
			c = value;
		}
	});
	return this;
} // end FUNCTION Levy()

/**
* Lévy distribution differential entropy.
*
* @memberof Levy.prototype
* @name entropy
* @type {number}
* @see [differential entropy]{@link https://en.wikipedia.org/wiki/Entropy_%28information_theory%29}
*
* @example
* var levy = new Levy( 4.0, 12.0 );
*
* var v = levy.entropy;
* // returns ~-0.869
*/
Object.defineProperty( Levy.prototype, 'entropy', {
	'configurable': false,
	'enumerable': true,
	'get': function get() {
		return entropy( this.mu, this.c );
	}
});

/**
* Lévy distribution expected value.
*
* @memberof Levy.prototype
* @name mean
* @type {number}
* @see [expected value]{@link https://en.wikipedia.org/wiki/Expected_value}
*
* @example
* var levy = new Levy( 4.0, 12.0 );
*
* var v = levy.mean;
* // returns 0.25
*/
Object.defineProperty( Levy.prototype, 'mean', {
	'configurable': false,
	'enumerable': true,
	'get': function get() {
		return mean( this.mu, this.c );
	}
});

/**
* Lévy distribution median.
*
* @memberof Levy.prototype
* @name median
* @type {number}
* @see [median]{@link https://en.wikipedia.org/wiki/Median}
*
* @example
* var levy = new Levy( 4.0, 12.0 );
*
* var v = levy.median;
* // returns ~0.239
*/
Object.defineProperty( Levy.prototype, 'median', {
	'configurable': false,
	'enumerable': true,
	'get': function get() {
		return median( this.mu, this.c );
	}
});

/**
* Lévy distribution mode.
*
* @memberof Levy.prototype
* @name mode
* @type {number}
* @see [mode]{@link https://en.wikipedia.org/wiki/Mode_%28statistics%29}
*
* @example
* var levy = new Levy( 4.0, 12.0 );
*
* var v = levy.mode;
* // returns 0.25
*/
Object.defineProperty( Levy.prototype, 'mode', {
	'configurable': false,
	'enumerable': true,
	'get': function get() {
		return mode( this.mu, this.c );
	}
});

/**
* Lévy distribution variance.
*
* @memberof Levy.prototype
* @name variance
* @type {number}
* @see [variance]{@link https://en.wikipedia.org/wiki/Variance}
*
* @example
* var levy = new Levy( 4.0, 12.0 );
*
* var v = levy.variance;
* // returns ~0.011
*/
Object.defineProperty( Levy.prototype, 'variance', {
	'configurable': false,
	'enumerable': true,
	'get': function get() {
		return variance( this.mu, this.c );
	}
});

/**
* Evaluates the cumulative distribution function (CDF).
*
* @memberof Levy.prototype
* @name cdf
* @type {Function}
* @param {number} x - input value
* @returns {number} evaluated CDF
* @see [cdf]{@link https://en.wikipedia.org/wiki/Cumulative_distribution_function}
*
* @example
* var levy = new Levy( 2.0, 4.0 );
*
* var v = levy.cdf( 0.5 );
* // returns ~0.813
*/
setReadOnly( Levy.prototype, 'cdf', levyCDF );

/**
* Evaluates the natural logarithm of the probability density function (logPDF).
*
* @memberof Levy.prototype
* @name logpdf
* @type {Function}
* @param {number} x - input value
* @returns {number} evaluated logPDF
* @see [pdf]{@link https://en.wikipedia.org/wiki/Probability_density_function}
*
* @example
* var levy = new Levy( 2.0, 4.0 );
*
* var v = levy.logpdf( 0.8 );
* // returns ~-2.0557
*/
setReadOnly( Levy.prototype, 'logpdf', levyLogPDF );

/**
* Evaluates the probability density function (PDF).
*
* @memberof Levy.prototype
* @name pdf
* @type {Function}
* @param {number} x - input value
* @returns {number} evaluated PDF
* @see [pdf]{@link https://en.wikipedia.org/wiki/Probability_density_function}
*
* @example
* var levy = new Levy( 2.0, 4.0 );
*
* var v = levy.pdf( 0.8 );
* // returns ~0.013
*/
setReadOnly( Levy.prototype, 'pdf', levyPDF );

/**
* Evaluates the quantile function.
*
* @memberof Levy.prototype
* @name quantile
* @type {Function}
* @param {Probability} p - input probability
* @returns {number} evaluated quantile function
* @see [quantile function]{@link https://en.wikipedia.org/wiki/Quantile_function}
*
* @example
* var levy = new Levy( 2.0, 4.0 );
*
* var v = levy.quantile( 0.5 );
* // returns ~0.314
*/
setReadOnly( Levy.prototype, 'quantile', levyQuantile );

// EXPORTS //

module.exports = Levy;
<commit_msg>Fix return annotations<commit_after>/* eslint-disable no-restricted-syntax, no-invalid-this */
'use strict';

// MODULES //

var setReadOnly = require( '@stdlib/utils/define-read-only-property' );
var isPositive = require( '@stdlib/assert/is-positive-number').isPrimitive;
var entropy = require( '@stdlib/math/base/dist/levy/entropy' );
var mean = require( '@stdlib/math/base/dist/levy/mean' );
var median = require( '@stdlib/math/base/dist/levy/median' );
var mode = require( '@stdlib/math/base/dist/levy/mode' );
var variance = require( '@stdlib/math/base/dist/levy/variance' );
var cdf = require( '@stdlib/math/base/dist/levy/cdf' );
var logpdf = require( '@stdlib/math/base/dist/levy/logpdf' );
var pdf = require( '@stdlib/math/base/dist/levy/pdf' );
var quantile = require( '@stdlib/math/base/dist/levy/quantile' );

// FUNCTIONS //

/**
* Evaluates the cumulative distribution function (CDF).
*
* @private
* @param {number} x - input value
* @returns {Probability} evaluated CDF
*/
function levyCDF( x ) {
	return cdf( x, this.mu, this.c );
} // end FUNCTION levyCDF()

/**
* Evaluates the natural logarithm of the probability density function (logPDF).
*
* @private
* @param {number} x - input value
* @returns {number} evaluated logPDF
*/
function levyLogPDF( x ) {
	return logpdf( x, this.mu, this.c );
} // end FUNCTION levyLogPDF()

/**
* Evaluates the probability density function (PDF).
*
* @private
* @param {number} x - input value
* @returns {number} evaluated PDF
*/
function levyPDF( x ) {
	return pdf( x, this.mu, this.c );
} // end FUNCTION levyPDF()

/**
* Evaluates the quantile function.
*
* @private
* @param {Probability} p - input probability
* @returns {number} evaluated quantile function
*/
function levyQuantile( p ) {
	return quantile( p, this.mu, this.c );
} // end FUNCTION levyQuantile()

// MAIN //

/**
* Lévy distribution constructor.
*
* @constructor
* @param {number} [mu=0.0] - location parameter
* @param {PositiveNumber} [c=1.0] - scale parameter
* @throws {TypeError} `c` must be a positive number
* @returns {Levy} distribution instance
*
* @example
* var levy = new Levy( 1.0, 1.0 );
*
* var y = levy.cdf( 3.0 );
* // returns ~0.48
*
* var mode = levy.mode;
* // returns ~1.333
*/
function Levy() {
	var mu;
	var c;
	if ( !(this instanceof Levy) ) {
		if ( arguments.length === 0 ) {
			return new Levy();
		}
		return new Levy( arguments[ 0 ], arguments[ 1 ] );
	}
	if ( arguments.length ) {
		mu = arguments[ 0 ];
		c = arguments[ 1 ];
		if ( !isPositive( c ) ) {
			throw new TypeError( 'invalid input argument. Scale parameter `c` must be a positive number. Value: `' + c + '`' );
		}
	} else {
		mu = 0.0;
		c = 1.0;
	}
	Object.defineProperty( this, 'mu', {
		'configurable': false,
		'enumerable': true,
		'get': function get() {
			return mu;
		},
		'set': function set( value ) {
			mu = value;
		}
	});
	Object.defineProperty( this, 'c', {
		'configurable': false,
		'enumerable': true,
		'get': function get() {
			return c;
		},
		'set': function set( value ) {
			if ( !isPositive( value ) ) {
				throw new TypeError( 'invalid value. Must be a positive number. Value: `' + value + '`' );
			}
			c = value;
		}
	});
	return this;
} // end FUNCTION Levy()

/**
* Lévy distribution differential entropy.
*
* @memberof Levy.prototype
* @name entropy
* @type {number}
* @see [differential entropy]{@link https://en.wikipedia.org/wiki/Entropy_%28information_theory%29}
*
* @example
* var levy = new Levy( 4.0, 12.0 );
*
* var v = levy.entropy;
* // returns ~5.809
*/
Object.defineProperty( Levy.prototype, 'entropy', {
	'configurable': false,
	'enumerable': true,
	'get': function get() {
		return entropy( this.mu, this.c );
	}
});

/**
* Lévy distribution expected value.
*
* @memberof Levy.prototype
* @name mean
* @type {number}
* @see [expected value]{@link https://en.wikipedia.org/wiki/Expected_value}
*
* @example
* var levy = new Levy( 4.0, 12.0 );
*
* var v = levy.mean;
* // returns Number.POSITIVE_INFINITY
*/
Object.defineProperty( Levy.prototype, 'mean', {
	'configurable': false,
	'enumerable': true,
	'get': function get() {
		return mean( this.mu, this.c );
	}
});

/**
* Lévy distribution median.
*
* @memberof Levy.prototype
* @name median
* @type {number}
* @see [median]{@link https://en.wikipedia.org/wiki/Median}
*
* @example
* var levy = new Levy( 4.0, 12.0 );
*
* var v = levy.median;
* // returns ~30.377
*/
Object.defineProperty( Levy.prototype, 'median', {
	'configurable': false,
	'enumerable': true,
	'get': function get() {
		return median( this.mu, this.c );
	}
});

/**
* Lévy distribution mode.
*
* @memberof Levy.prototype
* @name mode
* @type {number}
* @see [mode]{@link https://en.wikipedia.org/wiki/Mode_%28statistics%29}
*
* @example
* var levy = new Levy( 4.0, 12.0 );
*
* var v = levy.mode;
* // returns 8.0
*/
Object.defineProperty( Levy.prototype, 'mode', {
	'configurable': false,
	'enumerable': true,
	'get': function get() {
		return mode( this.mu, this.c );
	}
});

/**
* Lévy distribution variance.
*
* @memberof Levy.prototype
* @name variance
* @type {number}
* @see [variance]{@link https://en.wikipedia.org/wiki/Variance}
*
* @example
* var levy = new Levy( 4.0, 12.0 );
*
* var v = levy.variance;
* // returns Number.POSITIVE_INFINITY
*/
Object.defineProperty( Levy.prototype, 'variance', {
	'configurable': false,
	'enumerable': true,
	'get': function get() {
		return variance( this.mu, this.c );
	}
});

/**
* Evaluates the cumulative distribution function (CDF).
*
* @memberof Levy.prototype
* @name cdf
* @type {Function}
* @param {number} x - input value
* @returns {number} evaluated CDF
* @see [cdf]{@link https://en.wikipedia.org/wiki/Cumulative_distribution_function}
*
* @example
* var levy = new Levy( 2.0, 4.0 );
*
* var v = levy.cdf( 2.5 );
* // returns ~0.005
*/
setReadOnly( Levy.prototype, 'cdf', levyCDF );

/**
* Evaluates the natural logarithm of the probability density function (logPDF).
*
* @memberof Levy.prototype
* @name logpdf
* @type {Function}
* @param {number} x - input value
* @returns {number} evaluated logPDF
* @see [pdf]{@link https://en.wikipedia.org/wiki/Probability_density_function}
*
* @example
* var levy = new Levy( 2.0, 4.0 );
*
* var v = levy.logpdf( 2.5 );
* // returns ~-3.186
*/
setReadOnly( Levy.prototype, 'logpdf', levyLogPDF );

/**
* Evaluates the probability density function (PDF).
*
* @memberof Levy.prototype
* @name pdf
* @type {Function}
* @param {number} x - input value
* @returns {number} evaluated PDF
* @see [pdf]{@link https://en.wikipedia.org/wiki/Probability_density_function}
*
* @example
* var levy = new Levy( 2.0, 4.0 );
*
* var v = levy.pdf( 2.5 );
* // returns ~0.041
*/
setReadOnly( Levy.prototype, 'pdf', levyPDF );

/**
* Evaluates the quantile function.
*
* @memberof Levy.prototype
* @name quantile
* @type {Function}
* @param {Probability} p - input probability
* @returns {number} evaluated quantile function
* @see [quantile function]{@link https://en.wikipedia.org/wiki/Quantile_function}
*
* @example
* var levy = new Levy( 2.0, 4.0 );
*
* var v = levy.quantile( 0.5 );
* // returns ~10.792
*/
setReadOnly( Levy.prototype, 'quantile', levyQuantile );

// EXPORTS //

module.exports = Levy;
<|endoftext|>


<commit_before>/* Biblia League plugin
 * A fun script that holds all
 * of the league ranks in a JSON
 * file to be accessed at our leisure
 * By: panpawn
 */

var fs = require('fs');
var serialize = require('node-serialize');
var leagueRanks = {};
var leagueName = "Biblia";
var leagueRanksToHave = ["e4", "champ", "gl", "purgatory"];

function loadLeague() {
	try {
		leagueRanks = serialize.unserialize(fs.readFileSync('config/biblia-league-ranks.json', 'utf8'));
		Object.merge(Core.biblia, leagueRanks);
	} catch (e) {};
}
setTimeout(function(){loadLeague();},1000);

function saveLeague() {
	try {
		fs.writeFileSync('config/biblia-league-ranks.json',serialize.serialize(leagueRanks));
		Object.merge(Core.biblia, leagueRanks);
	} catch (e) {};
}

exports.commands = {
	biblia: function (target, room, user) {
		if (!target) target = 'help';
		if (room.id !== 'thebiblialeague') return false;
		var parts = target.split(',');
		for (var u in parts) parts[u] = parts[u].trim();
		try {
			switch (toId(parts[0])) {
				case 'give':
				case 'giverank':
					if (!parts[1] || !parts[2]) return this.sendReply("ERROR!  Usage: /biblia give, [user], [rank] - Gives a user a league rank.");
					if (!this.can('roommod')) return this.sendReply("Only room owners and up can give a " + leagueName + " rank!");
					var targetUser = toId(parts[1]);
					if (Core.biblia[targetUser]) return this.sendReply("ERROR! The user " + targetUser + " already has a league rank!");
					if (toId(parts[2]).indexOf(leagueRanksToHave) > -1) return this.sendReply("Ahhhh!  You didn't enter a valid league rank! (" + leagueRanksToHave + ")");
					leagueRanks[targetUser] = Core.biblia[targetUser] = toId(parts[2]); //shouldn't have to take the id here, this is for safety precautions
					saveLeague();
					this.sendReply(targetUser + " was given the league rank of " + parts[2]);
					this.logModCommand(targetUser + " was given the league rank of " + parts[2]);
					room.add(targetUser + " was given the league rank of " + parts[2] + " by " + user.name);
					break;
				case 'take':
				case 'takerank':
					if (!this.can('roommod')) return this.sendReply("Only room owners and up can take a " + leagueName + " rank!");
					if (!parts[1]) return this.sendReply("Usage: /biblia take, [user] - Removes a users rank.");
					var targetUser = toId(parts[1]);
					if (!Core.biblia[targetUser]) return this.sendReply("ERROR!  The user " + targetUser + " does not have an existing rank to remove!");
					delete Core.biblia[targetUser];
					delete leagueRanks[targetUser];
					saveEmotes();
					this.sendReply(targetUser + "'s league rank was removed.");
					this.logModCommand(targetUser + "'s league rank was removed by " + user.name);
					room.add(targetUser + "'s league rank was removed by " + user.name);
					break;
				case 'view':
				case 'show':
					if (!this.canBroadcast()) return;
					var rank = Core.biblia[toId(parts[1])];
					if (!rank) return this.sendReply("User " + parts[1] + " does not have a " + leagueName + " rank.");
					var img = "";
					switch (rank) {
						case 'e4':
							img = '';
							braek;
						case 'champ':
							img = '';
							break;
						case 'gl':
							img = '';
							break;
						case 'purgatory':
							img = '';
							break;
						default:
							img = '';
					}
					return this.sendReplyBox("Rank: " + rank.substring(0,1).toUpperCase() + rank.substring(1,rank.length) + "
" + img);
					break;
				case 'help':
				default:
					if (!this.canBroadcast()) return;
					return this.sendReplyBox(
						"Biblia commands:
" +
						"/biblia give, [user], [rank] - Gives someone a league rank. Requires # and up.
" +
						"/biblia remove, [user] - Removes that user's league rank.  Requires # and up.
" +
						"/biblia show, [user] - Shows that user's league rank according to the biblia script."
					);
			}
		} catch (e) {
			console.log("AH!  THE BIBLIA SCRIPT HAS SELF DESTRUCTED!");
		}
	}
};
<commit_msg>add /biblia object<commit_after>/* Biblia League plugin
 * A fun script that holds all
 * of the league ranks in a JSON
 * file to be accessed at our leisure
 * By: panpawn
 */

var fs = require('fs');
var serialize = require('node-serialize');
var leagueRanks = {};
var leagueName = "Biblia";
var leagueRanksToHave = ["e4", "champ", "gl", "purgatory"];

function loadLeague() {
	try {
		leagueRanks = serialize.unserialize(fs.readFileSync('config/biblia-league-ranks.json', 'utf8'));
		Object.merge(Core.biblia, leagueRanks);
	} catch (e) {};
}
setTimeout(function(){loadLeague();},1000);

function saveLeague() {
	try {
		fs.writeFileSync('config/biblia-league-ranks.json',serialize.serialize(leagueRanks));
		Object.merge(Core.biblia, leagueRanks);
	} catch (e) {};
}

exports.commands = {
	biblia: function (target, room, user) {
		if (!target) target = 'help';
		if (room.id !== 'thebiblialeague') return false;
		var parts = target.split(',');
		for (var u in parts) parts[u] = parts[u].trim();
		try {
			switch (toId(parts[0])) {
				case 'give':
				case 'giverank':
					if (!parts[1] || !parts[2]) return this.sendReply("ERROR!  Usage: /biblia give, [user], [rank] - Gives a user a league rank.");
					if (!this.can('roommod')) return this.sendReply("Only room owners and up can give a " + leagueName + " rank!");
					var targetUser = toId(parts[1]);
					if (Core.biblia[targetUser]) return this.sendReply("ERROR! The user " + targetUser + " already has a league rank!");
					if (toId(parts[2]).indexOf(leagueRanksToHave) > -1) return this.sendReply("Ahhhh!  You didn't enter a valid league rank! (" + leagueRanksToHave + ")");
					leagueRanks[targetUser] = Core.biblia[targetUser] = toId(parts[2]); //shouldn't have to take the id here, this is for safety precautions
					saveLeague();
					this.sendReply(targetUser + " was given the league rank of " + parts[2]);
					this.logModCommand(targetUser + " was given the league rank of " + parts[2]);
					room.add(targetUser + " was given the league rank of " + parts[2] + " by " + user.name);
					break;
				case 'take':
				case 'takerank':
					if (!this.can('roommod')) return this.sendReply("Only room owners and up can take a " + leagueName + " rank!");
					if (!parts[1]) return this.sendReply("Usage: /biblia take, [user] - Removes a users rank.");
					var targetUser = toId(parts[1]);
					if (!Core.biblia[targetUser]) return this.sendReply("ERROR!  The user " + targetUser + " does not have an existing rank to remove!");
					delete Core.biblia[targetUser];
					delete leagueRanks[targetUser];
					saveEmotes();
					this.sendReply(targetUser + "'s league rank was removed.");
					this.logModCommand(targetUser + "'s league rank was removed by " + user.name);
					room.add(targetUser + "'s league rank was removed by " + user.name);
					break;
				case 'view':
				case 'show':
					if (!this.canBroadcast()) return;
					var rank = Core.biblia[toId(parts[1])];
					if (!rank) return this.sendReply("User " + parts[1] + " does not have a " + leagueName + " rank.");
					var img = "";
					switch (rank) {
						case 'e4':
							img = '';
							braek;
						case 'champ':
							img = '';
							break;
						case 'gl':
							img = '';
							break;
						case 'purgatory':
							img = '';
							break;
						default:
							img = '';
					}
					return this.sendReplyBox("Rank: " + rank.substring(0,1).toUpperCase() + rank.substring(1,rank.length) + "
" + img);
					break;
				case 'object':
					//development command
					if (!this.canBroadcast()) return;
					if (this.broadcasting) return this.sendReply("ERROR: this command is too spammy to broadcast.  Use / instead of ! to see it for yourself.");
					return this.sendReplyBox("Core.biblia = " + fs.readFileSync('config/biblia-league-ranks.json', 'utf8'));
					break;
				case 'help':
				default:
					if (!this.canBroadcast()) return;
					return this.sendReplyBox(
						"Biblia commands:
" +
						"/biblia give, [user], [rank] - Gives someone a league rank. Requires # and up.
" +
						"/biblia remove, [user] - Removes that user's league rank.  Requires # and up.
" +
						"/biblia show, [user] - Shows that user's league rank according to the biblia script."
					);
			}
		} catch (e) {
			console.log("AH!  THE BIBLIA SCRIPT HAS SELF DESTRUCTED!");
		}
	}
};
<|endoftext|>


<commit_before>window.ModuleList = [
  ['Top Five','25.1.2017','v1.0'],
  ['Newest Member Today','25.1.2017','v1.0'],
  ['Topic Preview','25.1.2017','v1.0']
];
<commit_msg>Update release.js<commit_after>window.ModuleList = [
  ['Top Five','25.1.2017','v1.0'],
  ['Newest Member Today','25.1.2017','v1.0'],
  ['Topic Preview','25.1.2017','v1.0']
];

window.Avaible = [
  ['Top Five','/admin/index.forum?part=extensions&sub=modules&mode=ext_edit&id=1&extended_admin=1&tid=',''],
  ['Newest Member Today','/admin/index.forum?part=extensions&sub=modules&mode=ext_edit&id=1&extended_admin=1&tid=',''],
  ['Topic Preview','/admin/index.forum?part=extensions&sub=modules&mode=ext_edit&id=1&extended_admin=1&tid=','']
];
<|endoftext|>


<commit_before>'use strict';

console.log(mySlot.getAdUnitPath());
<commit_msg>Added license header to custom script<commit_after>/**
 * @file An example for custom script injection.
 * @author Peter Goldsborough <peter@goldsborough.me>
 * @license Apache
 * Copyright 2016 Google Inc.
 *
 * 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
 *
 *     http://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.
*/

'use strict';

console.log(mySlot.getAdUnitPath());
<|endoftext|>


<commit_before>/**
 * @package info.ajaxplorer.plugins
 *
 * Copyright 2007-2009 Charles du Jeu
 * This file is part of AjaXplorer.
 * The latest code can be found at http://www.ajaxplorer.info/
 *
 * This program is published under the LGPL Gnu Lesser General Public License.
 * You should have received a copy of the license along with AjaXplorer.
 *
 * The main conditions are as follow :
 * You must conspicuously and appropriately publish on each copy distributed
 * an appropriate copyright notice and disclaimer of warranty and keep intact
 * all the notices that refer to this License and to the absence of any warranty;
 * and give any other recipients of the Program a copy of the GNU Lesser General
 * Public License along with the Program.
 *
 * If you modify your copy or copies of the library or any portion of it, you may
 * distribute the resulting library provided you do so under the GNU Lesser
 * General Public License. However, programs that link to the library may be
 * licensed under terms of your choice, so long as the library itself can be changed.
 * Any translation of the GNU Lesser General Public License must be accompanied by the
 * GNU Lesser General Public License.
 *
 * If you copy or distribute the program, you must accompany it with the complete
 * corresponding machine-readable source code or with a written offer, valid for at
 * least three years, to furnish the complete corresponding machine-readable source code.
 *
 * Any of the above conditions can be waived if you get permission from the copyright holder.
 * AjaXplorer is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 *
 * Description : Static class for renderers
 */
Class.create("ExifCellRenderer", {
	initialize: function(){
	},

	infoPanelModifier : function(htmlElement){
		var latiCell = htmlElement.down('#ip_COMPUTED_GPS-GPS_Latitude');
		var longiCell = htmlElement.down('#ip_COMPUTED_GPS-GPS_Longitude');
		if(latiCell && longiCell && latiCell.innerHTML && longiCell.innerHTML){
			var object = new ExifCellRenderer();
			object.transformGeoCells(latiCell, longiCell);
		}
	},

	transformGeoCells : function(latiCell, longiCell){
		var split = latiCell.innerHTML.split('--');
		latiCell.update(split[0]);
		latiCell.setAttribute("latiDegree", split[1]);
		split = longiCell.innerHTML.split('--');
		longiCell.update(split[0]);
		longiCell.setAttribute("longiDegree", split[1]);
		var button = new Element('div', {
			className:'fakeUploadButton',
			style:'padding-top:3px;width:50px;margin-bottom:0px;padding-bottom:3px;'
		}).update('
'+MessageHash['meta.exif.2']);
		var buttonCell = new Element('td', {
			rowspan:2,
			align:'center',
			valign:'center',
			style:'padding:2px;width:60px;'
		}).update(button);
		latiCell.insert({after:buttonCell});
		// Set all other cells colspan to 2.
		latiCell.up().nextSiblings().each(function(tr){
			tr.down('td.infoPanelValue').setAttribute('colspan', 2);
		});
		button.observe("click", function(){
			this.openLocator(latiCell.getAttribute('latiDegree'), longiCell.getAttribute("longiDegree"));
		}.bind(this) );
	},

	openLocator : function(latitude, longitude){
		// console.log(latitude, longitude);
		// Call openLayer editor!
		// TEST : WestHausen : longitude=10.2;latitude = 48.9;
		var editors = ajaxplorer.findEditorsForMime("ol_layer");
		if(editors.length){
			editorData = editors[0];
		}
		if(editorData){
			// Update ajxpNode with Google Layer!
			var ajxpNode = ajaxplorer.getUserSelection().getUniqueNode();
			var metadata = ajxpNode.getMetadata();
			ajxpNode.setMetadata(metadata.merge({
				'ol_layers' : [{type:'Google', google_type:'hybrid'}, {type:'Google', google_type:'streets'}, {type:'OSM'}],
				'ol_center' : {latitude:parseFloat(latitude),longitude:parseFloat(longitude)}
			}));
			ajaxplorer.loadEditorResources(editorData.resourcesManager);
			modal.openEditorDialog(editorData);
		}

	}
});<commit_msg>"Colspan bug in longitude cell."<commit_after>/**
 * @package info.ajaxplorer.plugins
 *
 * Copyright 2007-2009 Charles du Jeu
 * This file is part of AjaXplorer.
 * The latest code can be found at http://www.ajaxplorer.info/
 *
 * This program is published under the LGPL Gnu Lesser General Public License.
 * You should have received a copy of the license along with AjaXplorer.
 *
 * The main conditions are as follow :
 * You must conspicuously and appropriately publish on each copy distributed
 * an appropriate copyright notice and disclaimer of warranty and keep intact
 * all the notices that refer to this License and to the absence of any warranty;
 * and give any other recipients of the Program a copy of the GNU Lesser General
 * Public License along with the Program.
 *
 * If you modify your copy or copies of the library or any portion of it, you may
 * distribute the resulting library provided you do so under the GNU Lesser
 * General Public License. However, programs that link to the library may be
 * licensed under terms of your choice, so long as the library itself can be changed.
 * Any translation of the GNU Lesser General Public License must be accompanied by the
 * GNU Lesser General Public License.
 *
 * If you copy or distribute the program, you must accompany it with the complete
 * corresponding machine-readable source code or with a written offer, valid for at
 * least three years, to furnish the complete corresponding machine-readable source code.
 *
 * Any of the above conditions can be waived if you get permission from the copyright holder.
 * AjaXplorer is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 *
 * Description : Static class for renderers
 */
Class.create("ExifCellRenderer", {
	initialize: function(){
	},

	infoPanelModifier : function(htmlElement){
		var latiCell = htmlElement.down('#ip_COMPUTED_GPS-GPS_Latitude');
		var longiCell = htmlElement.down('#ip_COMPUTED_GPS-GPS_Longitude');
		if(latiCell && longiCell && latiCell.innerHTML && longiCell.innerHTML){
			var object = new ExifCellRenderer();
			object.transformGeoCells(latiCell, longiCell);
		}
	},

	transformGeoCells : function(latiCell, longiCell){
		var split = latiCell.innerHTML.split('--');
		latiCell.update(split[0]);
		latiCell.setAttribute("latiDegree", split[1]);
		split = longiCell.innerHTML.split('--');
		longiCell.update(split[0]);
		longiCell.setAttribute("longiDegree", split[1]);
		var button = new Element('div', {
			className:'fakeUploadButton',
			style:'padding-top:3px;width:50px;margin-bottom:0px;padding-bottom:3px;'
		}).update('
'+MessageHash['meta.exif.2']);
		var buttonCell = new Element('td', {
			rowspan:2,
			align:'center',
			valign:'center',
			style:'padding:2px;width:60px;'
		}).update(button);
		latiCell.insert({after:buttonCell});
		// Set all other cells colspan to 2.
		latiCell.up().nextSiblings().each(function(tr){
			tr.down('td.infoPanelValue').setAttribute('colspan', 2);
		});
		longiCell.setAttribute("colspan", "1");
		button.observe("click", function(){
			this.openLocator(latiCell.getAttribute('latiDegree'), longiCell.getAttribute("longiDegree"));
		}.bind(this) );
	},

	openLocator : function(latitude, longitude){
		// console.log(latitude, longitude);
		// Call openLayer editor!
		// TEST : WestHausen : longitude=10.2;latitude = 48.9;
		var editors = ajaxplorer.findEditorsForMime("ol_layer");
		if(editors.length){
			editorData = editors[0];
		}
		if(editorData){
			// Update ajxpNode with Google Layer!
			var ajxpNode = ajaxplorer.getUserSelection().getUniqueNode();
			var metadata = ajxpNode.getMetadata();
			ajxpNode.setMetadata(metadata.merge({
				'ol_layers' : [{type:'Google', google_type:'hybrid'}, {type:'Google', google_type:'streets'}, {type:'OSM'}],
				'ol_center' : {latitude:parseFloat(latitude),longitude:parseFloat(longitude)}
			}));
			ajaxplorer.loadEditorResources(editorData.resourcesManager);
			modal.openEditorDialog(editorData);
		}

	}
});<|endoftext|>


<commit_before>const QueryParser = require('querystring')
const Constants = require('../../frontend/constants/Constants')
const Defaults = require('./queryConstants')

function escape (query) {
  return query.replace(/\//g, '\\/')
}

function initCommonQuery (workQuery, publicationQuery, allFilters, workFilters, publicationFilters, excludeUnavailable, page, pageSize = 20, options) {
  options = Object.assign({
    explain: false,
    ageGain: 0.6,
    ageScale: 100,
    itemsGain: 0.3,
    itemsScale: 100,
    itemsCountLimit: 200,
    childBoost: 1
  }, options)

  const publicationAggregations = {}
  const workAggregations = {}
  Object.keys(Constants.filterableFields).forEach(key => {
    let field
    let fieldName
    if (key === 'branch') {
      fieldName = 'branches'
      field = 'homeBranches'
      if (excludeUnavailable) {
        field = 'availableBranches'
      }
    } else {
      field = Constants.filterableFields[ key ].name
      fieldName = field
    }
    if (fieldName === 'fictionNonfiction' || fieldName === 'audiences') {
      // aggregations on work properties
      workAggregations[ fieldName ] = {
        terms: {
          field: field,
          size: 1000
        }
      }
    } else {
      // aggregations on publication properties
      publicationAggregations[ fieldName ] = {
        terms: {
          field: field,
          size: 1000
        },
        aggregations: {
          parents: {
            cardinality: {
              field: '_parent'
            }
          }
        }
      }
    }
  })

  function publicationBoost (query) {
    return {
      function_score: {
        boost: options.childBoost, // general child boost
        boost_mode: 'multiply',
        query: query,
        script_score: {
          script: {
            inline: `
                      def score = _score;

                      def mtScores = [
                        "Film": 0.3,
                        "Språkkurs": 0.2
                      ];

                      if (doc['_type'] === 'publication') {
                        def mtScore = mtScores.get(doc.mt.value);
                        if (mtScore !== null) {
                          score = score * mtScore;
                        }
                      }

                      def langscores = [
                        "nob": 1.5,
                        "nno": 1.5,
                        "nor": 1.5,
                        "eng": 1.4,
                        "swe": 1.3,
                        "dan": 1.3,
                        "ger": 1.2,
                        "fre": 1.2,
                        "spa": 1.1,
                        "ita": 1.1
                      ];

                      def langscore = langscores.get(doc.language.value);
                      if (langscore == null) {
                        langscore = 1;
                      }

                      if (doc['_type'] === 'publication' && doc.mt === 'Bok') {
                        score = _score * langscore;
                      }

                      return score;`.replace('\n', ''),
            lang: 'painless'
          }
        }
      }
    }
  }

  function workBoost (query) {
    return {
      function_score: {
        boost: options.childBoost, // general child boost
        boost_mode: 'multiply',
        query: query,
        script_score: {
          script: {
            inline: `
                      def score = _score;

                      def items_gain=params.itemsGain;
                      def items_scale=params.itemsScale;
                      if (doc.totalNumItems.value != null) {
                        score *= (1 + (items_gain*(Math.min(doc.totalNumItems.value, params.itemsCountLimit)/items_scale)));
                      }

                      def age_gain=params.ageGain;
                      def age_scale=params.ageScale;
                      if (!doc['created'].empty) {
                        score *= (1 + (age_gain*age_scale)/(age_scale+(params.now - doc.created.date.getMillis())/86400000));
                      }

                      return score;`.replace('\n', ''),
            lang: 'painless',
            params: {
              now: Date.now() - options.timeTravel ? Number(options.timeTravel) * 86400000 : 0,
              itemsGain: Number(options.itemsGain),
              itemsScale: Number(options.itemsScale),
              itemsCountLimit: Number(options.itemsCountLimit),
              ageGain: Number(options.ageGain),
              ageScale: Number(options.ageScale)
            }
          }
        }
      }
    }
  }

  const boostableQuery = {
    bool: {
      must: [
        publicationQuery
      ]
    }
  }
  return {
    size: pageSize,
    from: pageSize * (page - 1 || 0),
    aggs: Object.assign({
      facets: {
        children: {
          type: 'publication'
        },
        aggs: publicationAggregations
      }}, workAggregations),
    highlight: {
      fields: {
        '*': {}
      },
      require_field_match: false
    },
    query: {
      bool: {
        must: {
          dis_max: {
            queries: [
              {
                // query work by publication properties
                has_child: {
                  score_mode: 'max',
                  type: 'publication',
                  query: !options.skipScript ? publicationBoost(boostableQuery) : boostableQuery,
                  inner_hits: {
                    size: 100,
                    name: 'publications',
                    explain: options.explain === 'true'
                  }
                }
              },
              {
                // query by work properties
                bool: {
                  must: {
                    has_child: {
                      type: 'publication',
                      query: {
                        match_all: {}
                      },
                      inner_hits: {
                        size: 100,
                        name: 'publications'
                      }
                    }
                  },
                  should: [
                    workQuery,
                    workBoost(workQuery)
                  ]
                }
              }
            ]
          }
        },
        filter: allFilters.concat(workFilters).concat([
          {
            bool: {
              must: [
                {
                  has_child: {
                    type: 'publication',
                    query: {
                      bool: {
                        should: {
                          match_all: {}
                        },
                        filter: publicationFilters.concat(
                          excludeUnavailable
                          ? [{
                            exists: {
                              field: 'availableBranches'
                            }
                          }]
                          : []
                          )
                      }
                    }
                  }
                }
              ]
            }
          }
        ])
      }
    },
    explain: options.explain === 'true'
  }
}

function simpleQuery (query, fields, options) {
  options = options || {}
  const terms = query.split(/\s+/)
  let phrases = [query]
  for (let i = 0; i < terms.length; i++) {
    const firstPart = terms.slice(0, i + 1)
    if (firstPart.length > 1) {
      phrases.push(firstPart.join(' '))
    }
    const secondPart = terms.slice(i)
    if (secondPart.length > 1) {
      phrases.push(secondPart.join(' '))
    }
  }

  phrases = [ ...new Set(phrases) ]

  const fieldsAndPhrases = []
  fields.forEach(field => {
    if (field.phrase && !options.noPhrasePerm || field.tokenize) {
      phrases.forEach(phrase => {
        fieldsAndPhrases.push({
          field, query: phrase, boost: (field.boost || 1)
        })
      })
    } else {
      fieldsAndPhrases.push({
        field, query, boost: field.boost
      })
    }
  })

  return {
    dis_max: {
      queries: fieldsAndPhrases.map(field => {
        return {
          constant_score: {
            filter: field.field.phrase ? {
              match_phrase: {
                [field.field.field]: {
                  query: field.query,
                  slop: 3
                }
              }
            } : {
              match: {
                [field.field.field]: {
                  query: field.query,
                  minimum_should_match: field.minimumMatch || '70%'
                }
              }
            },
            boost: field.boost || 1
          }
        }
      })
    }
  }
}

function initAdvancedQuery (query) {
  return {
    query_string: {
      query: translateFieldTerms(query, Constants.queryFieldTranslations),
      default_operator: 'and'
    }
  }
}

function translateFieldTerms (query, translations) {
  const chars = [ ...query ]
  let result = ''
  let inQuote = false
  let startField = 0
  let startValue = 0
  for (let i = 0; i < chars.length; i++) {
    const c = chars[ i ]
    if (c === ' ') {
      if (i + 1 === chars.length) {
        break
      }
      startField = i + 1
    }
    if (c === '"') {
      inQuote = !inQuote
    }
    if (!inQuote && c === ':') {
      result += chars.slice(startValue, startField).join('')
      let field = chars.slice(startField, i).join('')
      if (translations[ field ]) {
        field = translations[ field ]
        if (field instanceof Object) {
          field = field.translation
        }
      }
      result += field
      result += ':'
      startValue = i + 1
    }
  }
  return result += chars.slice(startValue, chars.length).join('')
}

// parse query string to decide what kind of query we think this is
function queryStringToQuery (queryString, workFilters, publicationFilters, excludeUnavailable, page, pageSize, options) {
  const escapedQueryString = escape(queryString)
  const isbn10 = new RegExp('^[0-9Xx-]{10,13}$')
  const isbn13 = new RegExp('^[0-9-]{13,17}$')
  const advTriggers = new RegExp('[:+/\\-()*^]|AND|OR|NOT|TO')

  if (isbn10.test(escapedQueryString) || isbn13.test(escapedQueryString)) {
    return initCommonQuery({}, initAdvancedQuery(`isbn:${escapedQueryString}`), [initAdvancedQuery(`isbn:${escapedQueryString}`)], workFilters, publicationFilters, excludeUnavailable, page, pageSize, options)
  } else if (advTriggers.test(escapedQueryString)) {
    return initCommonQuery(initAdvancedQuery(escapedQueryString), initAdvancedQuery(escapedQueryString), [initAdvancedQuery(escapedQueryString)], workFilters, publicationFilters, excludeUnavailable, page, pageSize, options)
  } else {
    const _allFilter = options.noAllFilter ? [] : [ {
      match: {
        _all: {
          query: options.query,
          operator: 'and'
        }
      }
    } ]
    return initCommonQuery(
      simpleQuery(escapedQueryString, Defaults.defaultWorkFields, options),
      simpleQuery(escapedQueryString, Defaults.defaultPublicationFields, options),
      _allFilter,
      workFilters,
      publicationFilters,
      excludeUnavailable, page, pageSize, options)
  }
}

function parseFilters (filtersFromLocationQuery, domain, excludeUnavailable) {
  const filterableFields = Constants.filterableFields
  const terms = {}
  if (!Array.isArray(filtersFromLocationQuery)) {
    filtersFromLocationQuery = [ filtersFromLocationQuery ]
  }
  filtersFromLocationQuery.forEach(filterParamValue => { // ex filterParamValue: 'audience_juvenile'
    const split = filterParamValue.split('_')
    const filterableField = filterableFields[ split[ 0 ] ]
    if (filterableField.domain === domain) {
      let aggregation = filterableField.name
      if (aggregation === 'branches') {
        aggregation = 'homeBranches'
        if (excludeUnavailable) {
          aggregation = 'availableBranches'
        }
      }
      if (!terms[ aggregation ]) {
        terms[ aggregation ] = []
      }
      const val = filterableField.prefix + filterParamValue.substring(`${split[ 0 ]}_`.length)
      terms[ aggregation ].push(val)
    }
  })

  const filters = []
  Object.keys(terms).forEach(aggregation => {
    filters.push({ terms: { [aggregation]: terms[ aggregation ] } })
  })

  return filters
}

function yearRangeFilter (yearFrom, yearTo) {
  const start = yearFrom || 0
  const end = yearTo || new Date().getFullYear()
  return {
    range: {
      publicationYear: {
        gte: parseInt(start),
        lte: parseInt(end)
      }
    }
  }
}

function createPublicationFilters (params, excludeUnavailable) {
  const publicationFilters = parseFilters(params.filter || [], 'publication', excludeUnavailable)

  let yearRange
  if (params.yearFrom || params.yearTo) {
    yearRange = yearRangeFilter(params.yearFrom, params.yearTo)
  }
  if (yearRange) {
    publicationFilters.push(yearRange)
  }

  return publicationFilters
}

module.exports.buildQuery = function (urlQueryString) {
  const params = QueryParser.parse(urlQueryString)
  const excludeUnavailable = Object.hasOwnProperty.call(params, 'excludeUnavailable')
  const workFilters = parseFilters(params.filter || [], 'work')
  const publicationFilters = createPublicationFilters(params, excludeUnavailable)
  const query = queryStringToQuery(params.query, workFilters, publicationFilters, excludeUnavailable, params.page, params.pageSize, params)
//  console.log(JSON.stringify(query, null, 2))
  return query
}

module.exports.buildUnfilteredAggregatedQuery = function (urlQueryString) {
  const params = QueryParser.parse(urlQueryString)
  return queryStringToQuery(params.query, [], [], false, 0, 0, params)
}

// function exported only to be testable. TODO is there another way?
module.exports.translateFieldTerms = translateFieldTerms

<commit_msg>patron-client: query string must match work OR publication<commit_after>const QueryParser = require('querystring')
const Constants = require('../../frontend/constants/Constants')
const Defaults = require('./queryConstants')

function escape (query) {
  return query.replace(/\//g, '\\/')
}

function initCommonQuery (workQuery, publicationQuery, allFilters, workFilters, publicationFilters, excludeUnavailable, page, pageSize = 20, options) {
  options = Object.assign({
    explain: false,
    ageGain: 0.6,
    ageScale: 100,
    itemsGain: 0.3,
    itemsScale: 100,
    itemsCountLimit: 200,
    childBoost: 1
  }, options)

  const publicationAggregations = {}
  const workAggregations = {}
  Object.keys(Constants.filterableFields).forEach(key => {
    let field
    let fieldName
    if (key === 'branch') {
      fieldName = 'branches'
      field = 'homeBranches'
      if (excludeUnavailable) {
        field = 'availableBranches'
      }
    } else {
      field = Constants.filterableFields[ key ].name
      fieldName = field
    }
    if (fieldName === 'fictionNonfiction' || fieldName === 'audiences') {
      // aggregations on work properties
      workAggregations[ fieldName ] = {
        terms: {
          field: field,
          size: 1000
        }
      }
    } else {
      // aggregations on publication properties
      publicationAggregations[ fieldName ] = {
        terms: {
          field: field,
          size: 1000
        },
        aggregations: {
          parents: {
            cardinality: {
              field: '_parent'
            }
          }
        }
      }
    }
  })

  function publicationBoost (query) {
    return {
      function_score: {
        boost: options.childBoost, // general child boost
        boost_mode: 'multiply',
        query: query,
        script_score: {
          script: {
            inline: `
                      def score = _score;

                      def mtScores = [
                        "Film": 0.3,
                        "Språkkurs": 0.2
                      ];

                      if (doc['_type'] === 'publication') {
                        def mtScore = mtScores.get(doc.mt.value);
                        if (mtScore !== null) {
                          score = score * mtScore;
                        }
                      }

                      def langscores = [
                        "nob": 1.5,
                        "nno": 1.5,
                        "nor": 1.5,
                        "eng": 1.4,
                        "swe": 1.3,
                        "dan": 1.3,
                        "ger": 1.2,
                        "fre": 1.2,
                        "spa": 1.1,
                        "ita": 1.1
                      ];

                      def langscore = langscores.get(doc.language.value);
                      if (langscore == null) {
                        langscore = 1;
                      }

                      if (doc['_type'] === 'publication' && doc.mt === 'Bok') {
                        score = _score * langscore;
                      }

                      return score;`.replace('\n', ''),
            lang: 'painless'
          }
        }
      }
    }
  }

  function workBoost (query) {
    return {
      function_score: {
        boost: options.childBoost, // general child boost
        boost_mode: 'multiply',
        query: query,
        script_score: {
          script: {
            inline: `
                      def score = _score;

                      def items_gain=params.itemsGain;
                      def items_scale=params.itemsScale;
                      if (doc.totalNumItems.value != null) {
                        score *= (1 + (items_gain*(Math.min(doc.totalNumItems.value, params.itemsCountLimit)/items_scale)));
                      }

                      def age_gain=params.ageGain;
                      def age_scale=params.ageScale;
                      if (!doc['created'].empty) {
                        score *= (1 + (age_gain*age_scale)/(age_scale+(params.now - doc.created.date.getMillis())/86400000));
                      }

                      return score;`.replace('\n', ''),
            lang: 'painless',
            params: {
              now: Date.now() - options.timeTravel ? Number(options.timeTravel) * 86400000 : 0,
              itemsGain: Number(options.itemsGain),
              itemsScale: Number(options.itemsScale),
              itemsCountLimit: Number(options.itemsCountLimit),
              ageGain: Number(options.ageGain),
              ageScale: Number(options.ageScale)
            }
          }
        }
      }
    }
  }

  const boostableQuery = {
    bool: {
      must: [
        publicationQuery
      ]
    }
  }
  return {
    size: pageSize,
    from: pageSize * (page - 1 || 0),
    aggs: Object.assign({
      facets: {
        children: {
          type: 'publication'
        },
        aggs: publicationAggregations
      }}, workAggregations),
    query: {
      bool: {
        must: {
          dis_max: {
            queries: [
              {
                // query work by publication properties
                has_child: {
                  score_mode: 'max',
                  type: 'publication',
                  query: !options.skipScript ? publicationBoost(boostableQuery) : boostableQuery,
                  inner_hits: {
                    size: 100,
                    name: 'publications',
                    explain: options.explain === 'true'
                  }
                }
              },
              {
                // query by work properties
                bool: {
                  must: {
                    has_child: {
                      type: 'publication',
                      query: {
                        match_all: {}
                      },
                      inner_hits: {
                        size: 100,
                        name: 'publications'
                      }
                    }
                  },
                  should: [
                    workQuery,
                    workBoost(workQuery)
                  ]
                }
              }
            ]
          }
        },
        filter: [
          {
            bool: {
              minimum_should_match: 1,
              should: [
                allFilters[0],
                {
                  has_child: {
                    type: 'publication',
                    query: allFilters[0]
                  }
                }
              ]
            }
          }
        ].concat(workFilters).concat([
          {
            bool: {
              must: [
                {
                  has_child: {
                    type: 'publication',
                    query: {
                      bool: {
                        should: {
                          match_all: {}
                        },
                        filter: publicationFilters.concat(
                          excludeUnavailable
                          ? [{
                            exists: {
                              field: 'availableBranches'
                            }
                          }]
                          : []
                          )
                      }
                    }
                  }
                }
              ]
            }
          }
        ])
      }
    },
    explain: options.explain === 'true'
  }
}

function simpleQuery (query, fields, options) {
  options = options || {}
  const terms = query.split(/\s+/)
  let phrases = [query]
  for (let i = 0; i < terms.length; i++) {
    const firstPart = terms.slice(0, i + 1)
    if (firstPart.length > 1) {
      phrases.push(firstPart.join(' '))
    }
    const secondPart = terms.slice(i)
    if (secondPart.length > 1) {
      phrases.push(secondPart.join(' '))
    }
  }

  phrases = [ ...new Set(phrases) ]

  const fieldsAndPhrases = []
  fields.forEach(field => {
    if (field.phrase && !options.noPhrasePerm || field.tokenize) {
      phrases.forEach(phrase => {
        fieldsAndPhrases.push({
          field, query: phrase, boost: (field.boost || 1)
        })
      })
    } else {
      fieldsAndPhrases.push({
        field, query, boost: field.boost
      })
    }
  })

  return {
    dis_max: {
      queries: fieldsAndPhrases.map(field => {
        return {
          constant_score: {
            filter: field.field.phrase ? {
              match_phrase: {
                [field.field.field]: {
                  query: field.query,
                  slop: 3
                }
              }
            } : {
              match: {
                [field.field.field]: {
                  query: field.query,
                  minimum_should_match: field.minimumMatch || '70%'
                }
              }
            },
            boost: field.boost || 1
          }
        }
      })
    }
  }
}

function initAdvancedQuery (query) {
  return {
    query_string: {
      query: translateFieldTerms(query, Constants.queryFieldTranslations),
      default_operator: 'and'
    }
  }
}

function translateFieldTerms (query, translations) {
  const chars = [ ...query ]
  let result = ''
  let inQuote = false
  let startField = 0
  let startValue = 0
  for (let i = 0; i < chars.length; i++) {
    const c = chars[ i ]
    if (c === ' ') {
      if (i + 1 === chars.length) {
        break
      }
      startField = i + 1
    }
    if (c === '"') {
      inQuote = !inQuote
    }
    if (!inQuote && c === ':') {
      result += chars.slice(startValue, startField).join('')
      let field = chars.slice(startField, i).join('')
      if (translations[ field ]) {
        field = translations[ field ]
        if (field instanceof Object) {
          field = field.translation
        }
      }
      result += field
      result += ':'
      startValue = i + 1
    }
  }
  return result += chars.slice(startValue, chars.length).join('')
}

// parse query string to decide what kind of query we think this is
function queryStringToQuery (queryString, workFilters, publicationFilters, excludeUnavailable, page, pageSize, options) {
  const escapedQueryString = escape(queryString)
  const isbn10 = new RegExp('^[0-9Xx-]{10,13}$')
  const isbn13 = new RegExp('^[0-9-]{13,17}$')
  const advTriggers = new RegExp('[:+/\\-()*^]|AND|OR|NOT|TO')

  if (isbn10.test(escapedQueryString) || isbn13.test(escapedQueryString)) {
    return initCommonQuery({}, initAdvancedQuery(`isbn:${escapedQueryString}`), [initAdvancedQuery(`isbn:${escapedQueryString}`)], workFilters, publicationFilters, excludeUnavailable, page, pageSize, options)
  } else if (advTriggers.test(escapedQueryString)) {
    return initCommonQuery(initAdvancedQuery(escapedQueryString), initAdvancedQuery(escapedQueryString), [initAdvancedQuery(escapedQueryString)], workFilters, publicationFilters, excludeUnavailable, page, pageSize, options)
  } else {
    const _allFilter = options.noAllFilter ? [] : [ {
      match: {
        _all: {
          query: options.query,
          operator: 'and'
        }
      }
    } ]
    return initCommonQuery(
      simpleQuery(escapedQueryString, Defaults.defaultWorkFields, options),
      simpleQuery(escapedQueryString, Defaults.defaultPublicationFields, options),
      _allFilter,
      workFilters,
      publicationFilters,
      excludeUnavailable, page, pageSize, options)
  }
}

function parseFilters (filtersFromLocationQuery, domain, excludeUnavailable) {
  const filterableFields = Constants.filterableFields
  const terms = {}
  if (!Array.isArray(filtersFromLocationQuery)) {
    filtersFromLocationQuery = [ filtersFromLocationQuery ]
  }
  filtersFromLocationQuery.forEach(filterParamValue => { // ex filterParamValue: 'audience_juvenile'
    const split = filterParamValue.split('_')
    const filterableField = filterableFields[ split[ 0 ] ]
    if (filterableField.domain === domain) {
      let aggregation = filterableField.name
      if (aggregation === 'branches') {
        aggregation = 'homeBranches'
        if (excludeUnavailable) {
          aggregation = 'availableBranches'
        }
      }
      if (!terms[ aggregation ]) {
        terms[ aggregation ] = []
      }
      const val = filterableField.prefix + filterParamValue.substring(`${split[ 0 ]}_`.length)
      terms[ aggregation ].push(val)
    }
  })

  const filters = []
  Object.keys(terms).forEach(aggregation => {
    filters.push({ terms: { [aggregation]: terms[ aggregation ] } })
  })

  return filters
}

function yearRangeFilter (yearFrom, yearTo) {
  const start = yearFrom || 0
  const end = yearTo || new Date().getFullYear()
  return {
    range: {
      publicationYear: {
        gte: parseInt(start),
        lte: parseInt(end)
      }
    }
  }
}

function createPublicationFilters (params, excludeUnavailable) {
  const publicationFilters = parseFilters(params.filter || [], 'publication', excludeUnavailable)

  let yearRange
  if (params.yearFrom || params.yearTo) {
    yearRange = yearRangeFilter(params.yearFrom, params.yearTo)
  }
  if (yearRange) {
    publicationFilters.push(yearRange)
  }

  return publicationFilters
}

module.exports.buildQuery = function (urlQueryString) {
  const params = QueryParser.parse(urlQueryString)
  const excludeUnavailable = Object.hasOwnProperty.call(params, 'excludeUnavailable')
  const workFilters = parseFilters(params.filter || [], 'work')
  const publicationFilters = createPublicationFilters(params, excludeUnavailable)
  const query = queryStringToQuery(params.query, workFilters, publicationFilters, excludeUnavailable, params.page, params.pageSize, params)
//  console.log(JSON.stringify(query, null, 2))
  return query
}

module.exports.buildUnfilteredAggregatedQuery = function (urlQueryString) {
  const params = QueryParser.parse(urlQueryString)
  return queryStringToQuery(params.query, [], [], false, 0, 0, params)
}

// function exported only to be testable. TODO is there another way?
module.exports.translateFieldTerms = translateFieldTerms

<|endoftext|>