<commit_before>const { createBooruFetcher } = require('./booru');
const { mention } = require('../../util');
const { requirePrefix, requirePermission, splitCommands } = require('../../handler');
const Promise = require('bluebird');
const { MAX_SAVE_CODE, BOORU_MODIFY_BLOCKED_TAGS, BOORU_SAVE_PICTURE, BOORU_LOOKUP } = require('./constants');

const RATING_TAGS = [
  'rating:explicit',
  'rating:questionable',
  'rating:safe',
  '-rating:explicit',
  '-rating:questionable',
  '-rating:safe'
];

const tagComplement = tag => tag.startsWith('-') ? tag.substr(1) :`-${tag}`;

const pushSaveCode = function(bot, channelID, url) {
  const { redis } = bot;

  return Promise.all([
    bot.resolveSetting({channelID}, MAX_SAVE_CODE),
    redis.hincrbyAsync(`shinobu_booru_next_save_codes`, channelID, 1)
  ]).then(([ maxSaveCode, nextSaveCode ]) => {
      const resetPromise = nextSaveCode === maxSaveCode
        ? redis.hsetAsync(`shinobu_booru_next_save_codes`, channelID, 0)
        : Promise.resolve();

      const setPromise = redis.hsetAsync(`shinobu_booru_save_codes:${channelID}`, nextSaveCode, url);

      return Promise.all([setPromise, resetPromise]).then(() => nextSaveCode);
  });
};

const createLookupHandler = function(sfw, options={}) {
  const defaultRatingTags = sfw ? 'rating:safe' : '-rating:safe';

  const fetcher = createBooruFetcher(options);

  const addRatingTags = tags => tags.some(tag => RATING_TAGS.indexOf(tag) > -1)
      ? tags
      : tags.concat([defaultRatingTags]);

  const resolveTags = (tags, blockedTags) =>
    addRatingTags(tags.filter(Boolean).map(tag => tag.toLowerCase()))
      .concat(blockedTags.map(tagComplement));

  return function(bot, messageInfo) {
    const userTags = messageInfo.tokens;
    const serverID = bot.serverFromChannelID(messageInfo.channelID);

    const tagPromise = bot.redis.smembersAsync(
      `shinobu_blocked_booru_tags:${serverID}`
    )
    .then(blockedTags => {
      if (userTags.some(tag => blockedTags.indexOf(tag) > -1)) {
        return Promise.reject('Blocked tag detected');
      }

      return resolveTags(userTags, blockedTags);
    });

    const messagePromise = tagPromise.then(tags =>
      bot.sendMessage({
        to: messageInfo.channelID,
        message: `**Search for tags:** ${tags.join(', ')}.`
      }));

    const urlPromise = tagPromise.then(fetcher).then(results => {
      if (results.length === 0) {
        return Promise.reject('No results found');
      }

      return 'https:' + results[Math.floor(Math.random() * results.length)];
    });

    const saveCodePromise = urlPromise.then(url => pushSaveCode(bot, messageInfo.channelID, url));

    return Promise.all([
      urlPromise,
      messagePromise,
      tagPromise,
      saveCodePromise
    ])
    .then(([url, message, tags, saveCode]) => {
      const deletePromise = bot.deleteMessage({
        channelID: messageInfo.channelID,
        messageID: message.id
      });

      const sendPromise = bot.sendMessage({
        to: messageInfo.channelID,
        message: mention(messageInfo.userID),
        embed: {
          title: `**Result found for tags:** ${tags.join(', ')}.`,
          description: `Send \`!qt save ${saveCode}\` to save this picture.`,
          color: 0x6DEB60,
          url,
          image: {
            url
          },
          provider: {
            name: 'Gelbooru',
            url: 'http://gelbooru.com/'
          }
        }
      });

      return Promise.all([deletePromise, sendPromise]);
    })

    .catch(reason => {
      if (reason === 'Blocked tag detected') {
        return bot.sendMessage({
          to: messageInfo.channelID,
          message: `${mention(messageInfo.userID)} Blocked tag detected`
        });
      } else if (reason === 'No results found') {
        if (!messagePromise.isRejected() && !tagPromise.isRejected()) {
          return Promise.all([messagePromise, tagPromise])
          .then(([, tags]) =>
            bot.sendMessage({
              to: messageInfo.channelID,
              message: `**No results found for tags:** ${tags.join(', ')}.`
            })
          );
        }
      } else {
        return Promise.reject(reason);
      }
    });
  };
};

const handleSave = function(bot, messageInfo) {
  const { tokens, channelID } = messageInfo;

  if (tokens.length != 1) {
    return Promise.resolve(false);
  }

  const id = Number(tokens[0]);

  if (isNaN(id)) {
    return Promise.resolve(false);
  }

  const { redis } = bot;
  const serverID = bot.serverFromChannelID(channelID);

  const urlPromise = redis.hgetAsync(`shinobu_booru_save_codes:${channelID}`, id);

  urlPromise.then(() => redis.hdelAsync(`shinobu_booru_save_codes:${channelID}`, id));

  const savePromise = urlPromise.then(url => redis.saddAsync(`shinobu_booru_saved_images:${serverID}`, url))

  return Promise.all([
    urlPromise,
    savePromise
  ]).then(() => bot.sendMessage({
    to: channelID,
    message: 'Image url saved'
  }));
};

const handleSaved = function(bot, messageInfo) {
  const { redis } = bot;
  const { channelID } = messageInfo;
  const serverID = bot.serverFromChannelID(channelID);

  return redis.srandmemberAsync(`shinobu_booru_saved_images:${serverID}`)
    .then(url => bot.sendMessage({
      to: channelID,
      message: mention(messageInfo.userID),
      embed: {
          title: `Saved picture`,
          color: 0x6DEB60,
          url,
          image: {
            url
          },
          provider: {
            name: 'Gelbooru',
            url: 'http://gelbooru.com/'
          }
        }
    }));
};

const handleBlock = function(bot, messageInfo) {
  const tags = messageInfo.tokens.map(encodeURIComponent);

  if (!tags.length) {
    return Promise.resolve('noop');
  }

  const serverID = bot.serverFromChannelID(messageInfo.channelID);

  return bot.redis.saddAsync.apply(
    bot.redis,
    [`shinobu_blocked_booru_tags:${serverID}`].concat(tags)
  ).then(() => bot.sendMessage({
      to: messageInfo.channelID,
      message: `**Blocked tags:** ${tags.join(', ')}.`
    }));
};

const handleAllow = function(bot, messageInfo) {
  const tags = messageInfo.tokens.map(encodeURIComponent);

  if (!tags.length) {
    return Promise.resolve('noop');
  }

  const serverID = bot.serverFromChannelID(messageInfo.channelID);

  return bot.redis.sremAsync.apply(
    bot.redis,
    [`shinobu_blocked_booru_tags:${serverID}`].concat(tags)
  ).then(() => bot.sendMessage({
    to: messageInfo.channelID,
    message: `**Allowed tags:** ${tags.join(', ')}.`
  }));
};

const handleLookup = requirePermission(BOORU_LOOKUP)(createLookupHandler(true));

const handlers = {
  nsfw: requirePermission(BOORU_LOOKUP)(createLookupHandler(false)),
  saved: requirePermission(BOORU_LOOKUP)(handleSaved),
  block: requirePermission(BOORU_MODIFY_BLOCKED_TAGS)(handleBlock),
  allow: requirePermission(BOORU_MODIFY_BLOCKED_TAGS)(handleAllow),
  save: requirePermission(BOORU_SAVE_PICTURE)(handleSave)
};

const booruLookup =
  requirePrefix('!qt')(splitCommands(handlers, handleLookup));

module.exports = booruLookup;
<commit_msg>semicolon goes here<commit_after>const { createBooruFetcher } = require('./booru');
const { mention } = require('../../util');
const { requirePrefix, requirePermission, splitCommands } = require('../../handler');
const Promise = require('bluebird');
const { MAX_SAVE_CODE, BOORU_MODIFY_BLOCKED_TAGS, BOORU_SAVE_PICTURE, BOORU_LOOKUP } = require('./constants');

const RATING_TAGS = [
  'rating:explicit',
  'rating:questionable',
  'rating:safe',
  '-rating:explicit',
  '-rating:questionable',
  '-rating:safe'
];

const tagComplement = tag => tag.startsWith('-') ? tag.substr(1) :`-${tag}`;

const pushSaveCode = function(bot, channelID, url) {
  const { redis } = bot;

  return Promise.all([
    bot.resolveSetting({channelID}, MAX_SAVE_CODE),
    redis.hincrbyAsync(`shinobu_booru_next_save_codes`, channelID, 1)
  ]).then(([ maxSaveCode, nextSaveCode ]) => {
      const resetPromise = nextSaveCode === maxSaveCode
        ? redis.hsetAsync(`shinobu_booru_next_save_codes`, channelID, 0)
        : Promise.resolve();

      const setPromise = redis.hsetAsync(`shinobu_booru_save_codes:${channelID}`, nextSaveCode, url);

      return Promise.all([setPromise, resetPromise]).then(() => nextSaveCode);
  });
};

const createLookupHandler = function(sfw, options={}) {
  const defaultRatingTags = sfw ? 'rating:safe' : '-rating:safe';

  const fetcher = createBooruFetcher(options);

  const addRatingTags = tags => tags.some(tag => RATING_TAGS.indexOf(tag) > -1)
      ? tags
      : tags.concat([defaultRatingTags]);

  const resolveTags = (tags, blockedTags) =>
    addRatingTags(tags.filter(Boolean).map(tag => tag.toLowerCase()))
      .concat(blockedTags.map(tagComplement));

  return function(bot, messageInfo) {
    const userTags = messageInfo.tokens;
    const serverID = bot.serverFromChannelID(messageInfo.channelID);

    const tagPromise = bot.redis.smembersAsync(
      `shinobu_blocked_booru_tags:${serverID}`
    )
    .then(blockedTags => {
      if (userTags.some(tag => blockedTags.indexOf(tag) > -1)) {
        return Promise.reject('Blocked tag detected');
      }

      return resolveTags(userTags, blockedTags);
    });

    const messagePromise = tagPromise.then(tags =>
      bot.sendMessage({
        to: messageInfo.channelID,
        message: `**Search for tags:** ${tags.join(', ')}.`
      }));

    const urlPromise = tagPromise.then(fetcher).then(results => {
      if (results.length === 0) {
        return Promise.reject('No results found');
      }

      return 'https:' + results[Math.floor(Math.random() * results.length)];
    });

    const saveCodePromise = urlPromise.then(url => pushSaveCode(bot, messageInfo.channelID, url));

    return Promise.all([
      urlPromise,
      messagePromise,
      tagPromise,
      saveCodePromise
    ])
    .then(([url, message, tags, saveCode]) => {
      const deletePromise = bot.deleteMessage({
        channelID: messageInfo.channelID,
        messageID: message.id
      });

      const sendPromise = bot.sendMessage({
        to: messageInfo.channelID,
        message: mention(messageInfo.userID),
        embed: {
          title: `**Result found for tags:** ${tags.join(', ')}.`,
          description: `Send \`!qt save ${saveCode}\` to save this picture.`,
          color: 0x6DEB60,
          url,
          image: {
            url
          },
          provider: {
            name: 'Gelbooru',
            url: 'http://gelbooru.com/'
          }
        }
      });

      return Promise.all([deletePromise, sendPromise]);
    })

    .catch(reason => {
      if (reason === 'Blocked tag detected') {
        return bot.sendMessage({
          to: messageInfo.channelID,
          message: `${mention(messageInfo.userID)} Blocked tag detected`
        });
      } else if (reason === 'No results found') {
        if (!messagePromise.isRejected() && !tagPromise.isRejected()) {
          return Promise.all([messagePromise, tagPromise])
          .then(([, tags]) =>
            bot.sendMessage({
              to: messageInfo.channelID,
              message: `**No results found for tags:** ${tags.join(', ')}.`
            })
          );
        }
      } else {
        return Promise.reject(reason);
      }
    });
  };
};

const handleSave = function(bot, messageInfo) {
  const { tokens, channelID } = messageInfo;

  if (tokens.length != 1) {
    return Promise.resolve(false);
  }

  const id = Number(tokens[0]);

  if (isNaN(id)) {
    return Promise.resolve(false);
  }

  const { redis } = bot;
  const serverID = bot.serverFromChannelID(channelID);

  const urlPromise = redis.hgetAsync(`shinobu_booru_save_codes:${channelID}`, id);

  urlPromise.then(() => redis.hdelAsync(`shinobu_booru_save_codes:${channelID}`, id));

  const savePromise = urlPromise.then(url => redis.saddAsync(`shinobu_booru_saved_images:${serverID}`, url))ñ

  return Promise.all([
    urlPromise,
    savePromise
  ]).then(() => bot.sendMessage({
    to: channelID,
    message: 'Image url saved'
  }));
};

const handleSaved = function(bot, messageInfo) {
  const { redis } = bot;
  const { channelID } = messageInfo;
  const serverID = bot.serverFromChannelID(channelID);

  return redis.srandmemberAsync(`shinobu_booru_saved_images:${serverID}`)
    .then(url => bot.sendMessage({
      to: channelID,
      message: mention(messageInfo.userID),
      embed: {
          title: `Saved picture`,
          color: 0x6DEB60,
          url,
          image: {
            url
          },
          provider: {
            name: 'Gelbooru',
            url: 'http://gelbooru.com/'
          }
        }
    }));
};

const handleBlock = function(bot, messageInfo) {
  const tags = messageInfo.tokens.map(encodeURIComponent);

  if (!tags.length) {
    return Promise.resolve('noop');
  }

  const serverID = bot.serverFromChannelID(messageInfo.channelID);

  return bot.redis.saddAsync.apply(
    bot.redis,
    [`shinobu_blocked_booru_tags:${serverID}`].concat(tags)
  ).then(() => bot.sendMessage({
      to: messageInfo.channelID,
      message: `**Blocked tags:** ${tags.join(', ')}.`
    }));
};

const handleAllow = function(bot, messageInfo) {
  const tags = messageInfo.tokens.map(encodeURIComponent);

  if (!tags.length) {
    return Promise.resolve('noop');
  }

  const serverID = bot.serverFromChannelID(messageInfo.channelID);

  return bot.redis.sremAsync.apply(
    bot.redis,
    [`shinobu_blocked_booru_tags:${serverID}`].concat(tags)
  ).then(() => bot.sendMessage({
    to: messageInfo.channelID,
    message: `**Allowed tags:** ${tags.join(', ')}.`
  }));
};

const handleLookup = requirePermission(BOORU_LOOKUP)(createLookupHandler(true));

const handlers = {
  nsfw: requirePermission(BOORU_LOOKUP)(createLookupHandler(false)),
  saved: requirePermission(BOORU_LOOKUP)(handleSaved),
  block: requirePermission(BOORU_MODIFY_BLOCKED_TAGS)(handleBlock),
  allow: requirePermission(BOORU_MODIFY_BLOCKED_TAGS)(handleAllow),
  save: requirePermission(BOORU_SAVE_PICTURE)(handleSave)
};

const booruLookup =
  requirePrefix('!qt')(splitCommands(handlers, handleLookup));

module.exports = booruLookup;
<|endoftext|>


<commit_before>$(function() {

	var width = $('#initial_canvas').width();
	var height = $('#initial_canvas').height();

	$('#input_file').change(function(e) {
		var file = e.target.files[0],
			imageType = /image.*/;

		if (!file.type.match(imageType))
			return;

		var reader = new FileReader();
		reader.onload = fileOnload;
		reader.readAsDataURL(file);
	});

	function fileOnload(e) {
		var $img = $('<img>', { src: e.target.result });
		var canvas = $('#initial_canvas')[0];
		var context = canvas.getContext('2d');

		$img.load(function() {
			context.drawImage(this, 0, 0);
		});
	}

	var invertColors = function() {

		var initial_canvas = $('#initial_canvas')[0].getContext('2d');
		var result_canvas = $('#result_canvas')[0].getContext('2d');

    	var initialImageData = initial_canvas.getImageData(0,0,width,height);
    	var finalImageData = result_canvas.getImageData(0,0,width,height);

		for (var i = 0; i < finalImageData.data.length; i+=4) {
			finalImageData.data[i] = 255 - initialImageData.data[i];
			finalImageData.data[i+1] = 255 - initialImageData.data[i+1];
			finalImageData.data[i+2] = 255 - initialImageData.data[i+2];
			finalImageData.data[i+3] = 255;
		};

		result_canvas.putImageData(finalImageData,0,0);

	}

	var boxFiltering = function(kernel) {

		var initial_canvas = $('#initial_canvas')[0].getContext('2d');
		var result_canvas = $('#result_canvas')[0].getContext('2d');

		var denominator = 0;
		for(var k=0; k<kernel.length; k++) denominator += kernel[k];

    	var initialImageData = initial_canvas.getImageData(0,0,width,height);
    	var finalImageData = result_canvas.getImageData(0,0,width,height);

		for(var l=1; l<height-1; l++) {
			for(var c=1; c<width-1; c++) {

				finalImageData.data[4*(c+(l*width))+3] = 255;

				var red = 0, green = 0, blue = 0;
				for (var k=0; k<kernel.length; k++) {
					var x = c, y = l;

					if(k/3 == 0) y++;
					else if(k/3 == 2) y--;

					if(k%3 == 0) x--;
					else if(k%3 == 2) x++;

					var r = initialImageData.data[4*(x+(y*width))];
					var g = initialImageData.data[4*(x+(y*width))+1];
					var b = initialImageData.data[4*(x+(y*width))+2];

					red += r * kernel[k];
					green += g * kernel[k];
					blue += b * kernel[k];

					if(k == kernel.length-1 && l == height-2 && c == height-2) {
						console.log("Eu entrei aqui.");
						console.log( finalImageData.data.length - (4+4*width) );
						console.log( 4*(c+(l*width)) );
					}
				};

				finalImageData.data[4*(c+(l*width))] = red / denominator;
				finalImageData.data[4*(c+(l*width))+1] = green / denominator;
				finalImageData.data[4*(c+(l*width))+2] = blue / denominator;

			};
		};

		result_canvas.putImageData(finalImageData,0,0);

	}

	var getDynamicMatrix = function(){

		var matrix = [0,0,0,0,0,0,0,0,0];
		for(var k=0; k<9; k++){
			var matrix_pos = "#matrix_"+(k+1);
			var value = $(matrix_pos).val();
			if(value == ""){
				value = "0";
				$(matrix_pos).val("0");
			}
			value = parseInt(value);
			matrix[k] = value;
		}
		return matrix;
	}

	$('#blur_filter').on('click',function(e){
		smothing = [1,1,1,1,2,1,1,1,1];
		boxFiltering(smothing);
	});

	$('#sharpening_filter').on('click',function(e){
		smothing = [-1,-1,-1,-1,9,-1,-1,-1,-1];
		boxFiltering(smothing);
	});

	$('#raised_filter').on('click',function(e){
		smothing = [0,0,-2,0,2,0,1,0,0];
		boxFiltering(smothing);
	});

	$('#motion_blur_filter').on('click',function(e){
		smothing = [0,0,1,0,0,0,1,0,0];
		boxFiltering(smothing);
	});

	$('#edge_detection_filter').on('click',function(e){
		smothing = [-1,-1,-1,-1,8,-1,-1,-1,-1];
		boxFiltering(smothing);
	});

	$('#color_inversion_filter').on('click',function(e){
		invertColors();
	});

	$('#dynamic_matrix_btn').on('click',function(e){
		var dynamic_matrix = getDynamicMatrix();
		boxFiltering(dynamic_matrix);
	});
});
<commit_msg>Added the clear canvas in the code before load a new image.<commit_after>$(function() {

	var width = $('#initial_canvas').width();
	var height = $('#initial_canvas').height();

	$('#input_file').change(function(e) {
		var file = e.target.files[0],
			imageType = /image.*/;

		if (!file.type.match(imageType))
			return;

		var reader = new FileReader();
		reader.onload = fileOnload;
		reader.readAsDataURL(file);
	});

	function fileOnload(e) {
		var $img = $('<img>', { src: e.target.result });
		var canvas = $('#initial_canvas')[0];
		var context = canvas.getContext('2d');
		context.clearRect(0,0,width,height);

		$img.load(function() {
			context.drawImage(this, 0, 0);
		});
	}

	var invertColors = function() {

		var initial_canvas = $('#initial_canvas')[0].getContext('2d');
		var result_canvas = $('#result_canvas')[0].getContext('2d');

    	var initialImageData = initial_canvas.getImageData(0,0,width,height);
    	var finalImageData = result_canvas.getImageData(0,0,width,height);

		for (var i = 0; i < finalImageData.data.length; i+=4) {
			finalImageData.data[i] = 255 - initialImageData.data[i];
			finalImageData.data[i+1] = 255 - initialImageData.data[i+1];
			finalImageData.data[i+2] = 255 - initialImageData.data[i+2];
			finalImageData.data[i+3] = 255;
		};

		result_canvas.putImageData(finalImageData,0,0);

	}

	var boxFiltering = function(kernel) {

		var initial_canvas = $('#initial_canvas')[0].getContext('2d');
		var result_canvas = $('#result_canvas')[0].getContext('2d');

		result_canvas.clearRect(0,0,width,height);

		var denominator = 0;
		for(var k=0; k<kernel.length; k++) denominator += kernel[k];

    	var initialImageData = initial_canvas.getImageData(0,0,width,height);
    	var finalImageData = result_canvas.getImageData(0,0,width,height);

		for(var l=1; l<height-1; l++) {
			for(var c=1; c<width-1; c++) {

				finalImageData.data[4*(c+(l*width))+3] = 255;

				var red = 0, green = 0, blue = 0;
				for (var k=0; k<kernel.length; k++) {
					var x = c, y = l;

					if(k/3 == 0) y++;
					else if(k/3 == 2) y--;

					if(k%3 == 0) x--;
					else if(k%3 == 2) x++;

					var r = initialImageData.data[4*(x+(y*width))];
					var g = initialImageData.data[4*(x+(y*width))+1];
					var b = initialImageData.data[4*(x+(y*width))+2];

					red += r * kernel[k];
					green += g * kernel[k];
					blue += b * kernel[k];

					if(k == kernel.length-1 && l == height-2 && c == height-2) {
						console.log("Eu entrei aqui.");
						console.log( finalImageData.data.length - (4+4*width) );
						console.log( 4*(c+(l*width)) );
					}
				};

				finalImageData.data[4*(c+(l*width))] = red / denominator;
				finalImageData.data[4*(c+(l*width))+1] = green / denominator;
				finalImageData.data[4*(c+(l*width))+2] = blue / denominator;

			};
		};

		result_canvas.putImageData(finalImageData,0,0);

	}

	var getDynamicMatrix = function(){

		var matrix = [0,0,0,0,0,0,0,0,0];
		for(var k=0; k<9; k++){
			var matrix_pos = "#matrix_"+(k+1);
			var value = $(matrix_pos).val();
			if(value == ""){
				value = "0";
				$(matrix_pos).val("0");
			}
			value = parseInt(value);
			matrix[k] = value;
		}
		return matrix;
	}

	$('#blur_filter').on('click',function(e){
		smothing = [1,1,1,1,2,1,1,1,1];
		boxFiltering(smothing);
	});

	$('#sharpening_filter').on('click',function(e){
		smothing = [-1,-1,-1,-1,9,-1,-1,-1,-1];
		boxFiltering(smothing);
	});

	$('#raised_filter').on('click',function(e){
		smothing = [0,0,-2,0,2,0,1,0,0];
		boxFiltering(smothing);
	});

	$('#motion_blur_filter').on('click',function(e){
		smothing = [0,0,1,0,0,0,1,0,0];
		boxFiltering(smothing);
	});

	$('#edge_detection_filter').on('click',function(e){
		smothing = [-1,-1,-1,-1,8,-1,-1,-1,-1];
		boxFiltering(smothing);
	});

	$('#color_inversion_filter').on('click',function(e){
		invertColors();
	});

	$('#dynamic_matrix_btn').on('click',function(e){
		var dynamic_matrix = getDynamicMatrix();
		boxFiltering(dynamic_matrix);
	});
});
<|endoftext|>


<commit_before>
/** Note: This file doesn't contain any unit tests. It has some architecture for
 * performing common test function.*/

const RG = require('../client/src/battles');
const expect = require('chai').expect;

const RGTest = {

};

/* Creates a mock-level for unit tests. */
RGTest.createMockLevel = function(cols, rows) {
    const level = {cols: cols, rows: rows,
        map: {
            getCell: function(x, y) {
                return { x: x, y: y };
            },
            hasXY: function() {
                return true;
            },
            isPassable: function(x, y) {
                return x > -1 && y > -1;
            }
        },
        getMap: function() {return this.map;},

        addActor: function(actor, x, y) {
            actor.setXY(x, y);
            actor.setLevel(this);
        }
    };
    return level;
};

RGTest.createLevel = function(type, cols, rows) {
    return RG.FACT.createLevel('arena', cols, rows);
};

RGTest.equipItem = function(actor, item) {
    const invEq = actor.getInvEq();
    invEq.addItem(item);
    expect(invEq.equipItem(item)).to.equal(true);
};

/* Wraps an object into a cell for later use. Some functions require a map cell
* instead of taking the object directly, so this is useful. */
RGTest.wrapObjWithCell = function(obj) {
    const cell = RG.FACT.createFloorCell();
    cell.setExplored(true); // Otherwise returns darkness
    const propType = obj.getPropType();
    cell.setProp(propType, obj);
    return cell;
};

RGTest.checkActorXY = function(actor, x, y) {
    expect(actor.getX()).to.equal(x);
    expect(actor.getY()).to.equal(y);
};

RGTest.checkChar = function(obj, expChar) {
    const cell = RGTest.wrapObjWithCell(obj);
    expect(RG.getCellChar(cell)).to.equal(expChar);
};

RGTest.checkCSSClassName = function(obj, expClass) {
    const cell = RGTest.wrapObjWithCell(obj);
    expect(RG.getStyleClassForCell(cell)).to.equal(expClass);

};

RGTest.expectEqualHealth = function(o1, o2) {
    expect(o1.get('Health').getHP()).to.equal(o2.get('Health').getHP());
};

// Expect that branches b1 and b2 are connected by number of connections
// given by nConns.
RGTest.expectConnected = function(b1, b2, nConns) {
    let connFound = 0;
    const b1Stairs = b1.getStairsOther();
    const b2Stairs = b2.getStairsOther();
    expect(b1Stairs, 'B1 must have stairs').to.have.length.above(0);
    expect(b2Stairs, 'B2 must have stairs').to.have.length.above(0);

    b1Stairs.forEach( stair1 => {
        const s1TargetID = stair1.getTargetLevel().getID();
        expect(stair1.getTargetStairs()).not.to.be.empty;
        b2Stairs.forEach( stair2 => {
            if (s1TargetID === stair2.getSrcLevel().getID()) {
                ++connFound;
                // stair1 should be the target of stair2
                expect(stair2.getTargetStairs()).not.to.be.empty;
            }
        });
    });
    expect(connFound, `Connections between branches must be ${nConns}`)
        .to.equal(nConns);
};

module.exports = RGTest;
<commit_msg>Fixed expectedConnected to find correct number of connections between levels.<commit_after>
/** Note: This file doesn't contain any unit tests. It has some architecture for
 * performing common test function.*/

const RG = require('../client/src/battles');
const expect = require('chai').expect;

const RGTest = {

};

/* Creates a mock-level for unit tests. */
RGTest.createMockLevel = function(cols, rows) {
    const level = {cols: cols, rows: rows,
        map: {
            getCell: function(x, y) {
                return { x: x, y: y };
            },
            hasXY: function() {
                return true;
            },
            isPassable: function(x, y) {
                return x > -1 && y > -1;
            }
        },
        getMap: function() {return this.map;},

        addActor: function(actor, x, y) {
            actor.setXY(x, y);
            actor.setLevel(this);
        }
    };
    return level;
};

RGTest.createLevel = function(type, cols, rows) {
    return RG.FACT.createLevel('arena', cols, rows);
};

RGTest.equipItem = function(actor, item) {
    const invEq = actor.getInvEq();
    invEq.addItem(item);
    expect(invEq.equipItem(item)).to.equal(true);
};

/* Wraps an object into a cell for later use. Some functions require a map cell
* instead of taking the object directly, so this is useful. */
RGTest.wrapObjWithCell = function(obj) {
    const cell = RG.FACT.createFloorCell();
    cell.setExplored(true); // Otherwise returns darkness
    const propType = obj.getPropType();
    cell.setProp(propType, obj);
    return cell;
};

RGTest.checkActorXY = function(actor, x, y) {
    expect(actor.getX()).to.equal(x);
    expect(actor.getY()).to.equal(y);
};

RGTest.checkChar = function(obj, expChar) {
    const cell = RGTest.wrapObjWithCell(obj);
    expect(RG.getCellChar(cell)).to.equal(expChar);
};

RGTest.checkCSSClassName = function(obj, expClass) {
    const cell = RGTest.wrapObjWithCell(obj);
    expect(RG.getStyleClassForCell(cell)).to.equal(expClass);

};

RGTest.expectEqualHealth = function(o1, o2) {
    expect(o1.get('Health').getHP()).to.equal(o2.get('Health').getHP());
};

// Expect that branches b1 and b2 are connected by number of connections
// given by nConns.
RGTest.expectConnected = function(b1, b2, nConns) {
    let connFound = 0;
    const b1Stairs = b1.getStairsOther();
    const b2Stairs = b2.getStairsOther();
    expect(b1Stairs, 'B1 must have stairs').to.have.length.above(0);
    expect(b2Stairs, 'B2 must have stairs').to.have.length.above(0);

    b1Stairs.forEach(stair1 => {
        const s1TargetID = stair1.getTargetLevel().getID();
        expect(stair1.getTargetStairs()).not.to.be.empty;
        b2Stairs.forEach(stair2 => {
            const s2SourceID = stair2.getSrcLevel().getID();
            if (s1TargetID === s2SourceID) {
                // stair1 should be the target of stair2
                if (stair2.getTargetStairs() === stair1) {
                    ++connFound;
                }
                expect(stair2.getTargetStairs()).not.to.be.empty;
            }
        });
    });
    expect(connFound, `Connections between branches must be ${nConns}`)
        .to.equal(nConns);
};

module.exports = RGTest;
<|endoftext|>


<commit_before>/*
  mustache.js — Logic-less templates in JavaScript

  See http://mustache.github.com/ for more info.
*/

var Mustache = function() {
  var Renderer = function() {};

  Renderer.prototype = {
    otag: "{{",
    ctag: "}}",
    pragmas: {},
    buffer: [],
    pragmas_implemented: {
      "IMPLICIT-ITERATOR": true
    },
    context: {},

    render: function(template, context, partials, in_recursion) {
      // reset buffer & set context
      if(!in_recursion) {
        this.context = context;
        this.buffer = []; // TODO: make this non-lazy
      }

      // fail fast
      if(!this.includes("", template)) {
        if(in_recursion) {
          return template;
        } else {
          this.send(template);
          return;
        }
      }

      template = this.render_pragmas(template);
      var html = this.render_section(template, context, partials);
      if(in_recursion) {
        return this.render_tags(html, context, partials, in_recursion);
      }

      this.render_tags(html, context, partials, in_recursion);
    },

    /*
      Sends parsed lines
    */
    send: function(line) {
      if(line != "") {
        this.buffer.push(line);
      }
    },

    /*
      Looks for %PRAGMAS
    */
    render_pragmas: function(template) {
      // no pragmas
      if(!this.includes("%", template)) {
        return template;
      }

      var that = this;
      var regex = new RegExp(this.otag + "%([\\w_-]+) ?([\\w]+=[\\w]+)?" +
            this.ctag);
      return template.replace(regex, function(match, pragma, options) {
        if(!that.pragmas_implemented[pragma]) {
          throw({message:
            "This implementation of mustache doesn't understand the '" +
            pragma + "' pragma"});
        }
        that.pragmas[pragma] = {};
        if(options) {
          var opts = options.split("=");
          that.pragmas[pragma][opts[0]] = opts[1];
        }
        return "";
        // ignore unknown pragmas silently
      });
    },

    /*
      Tries to find a partial in the curent scope and render it
    */
    render_partial: function(name, context, partials) {
      name = this.trim(name);
      if(!partials || !partials[name]) {
        throw({message: "unknown_partial '" + name + "'"});
      }
      if(typeof(context[name]) != "object") {
        return this.render(partials[name], context, partials, true);
      }
      return this.render(partials[name], context[name], partials, true);
    },

    /*
      Renders inverted (^) and normal (#) sections
    */
    render_section: function(template, context, partials) {
      if(!this.includes("#", template) && !this.includes("^", template)) {
        return template;
      }

      var that = this;
      // CSW - Added "+?" so it finds the tighest bound, not the widest
      var regex = new RegExp(this.otag + "(\\^|\\#)\\s*(.+)\\s*" + this.ctag +
              "\\s*([\\s\\S]+?)" + this.otag + "\\/\\s*\\2\\s*" + this.ctag +
              "\\s*", "mg");

      // for each {{#foo}}{{/foo}} section do...
      return template.replace(regex, function(match, type, name, content) {
        var value = that.find(name, context);
        if(type == "^") { // inverted section
          if(!value || that.is_array(value) && value.length === 0) {
            // false or empty list, render it
            return that.render(content, context, partials, true);
          } else {
            return "";
          }
        } else if(type == "#") { // normal section
          if(that.is_array(value)) { // Enumerable, Let's loop!
            return that.map(value, function(row) {
              return that.render(content, that.create_context(row),
                partials, true);
            }).join("");
          } else if(that.is_object(value)) { // Object, Use it as subcontext!
            return that.render(content, that.create_context(value),
              partials, true);
          } else if(typeof value === "function") {
            // higher order section
            return value.call(context, content, function(text) {
              return that.render(text, context, partials, true);
            });
          } else if(value) { // boolean section
            return that.render(content, context, partials, true);
          } else {
            return "";
          }
        }
      });
    },

    /*
      Replace {{foo}} and friends with values from our view
    */
    render_tags: function(template, context, partials, in_recursion) {
      // tit for tat
      var that = this;

      var new_regex = function() {
        return new RegExp(that.otag + "(=|!|>|\\{|%)?([^\\/#\\^]+?)\\1?" +
          that.ctag + "+", "g");
      };

      var regex = new_regex();
      var tag_replace_callback = function(match, operator, name) {
        switch(operator) {
          case "!": // ignore comments
            return "";
          case "=": // set new delimiters, rebuild the replace regexp
            that.set_delimiters(name);
            regex = new_regex();
            return "";
          case ">": // render partial
            return that.render_partial(name, context, partials);
          case "{": // the triple mustache is unescaped
            return that.find(name, context);
          default: // escape the value
            return that.escape(that.find(name, context));
        }
      };
      var lines = template.split("\n");

       for (var i=0; i < lines.length; i++) {
         lines[i] = lines[i].replace(regex, tag_replace_callback, this);
         if(!in_recursion) {
           this.send(lines[i]);
         }
       }

       if(in_recursion) {
         return lines.join("\n");
       }
    },

    set_delimiters: function(delimiters) {
      var dels = delimiters.split(" ");
      this.otag = this.escape_regex(dels[0]);
      this.ctag = this.escape_regex(dels[1]);
    },

    escape_regex: function(text) {
      // thank you Simon Willison
      if(!arguments.callee.sRE) {
        var specials = [
          '/', '.', '*', '+', '?', '|',
          '(', ')', '[', ']', '{', '}', '\\'
        ];
        arguments.callee.sRE = new RegExp(
          '(\\' + specials.join('|\\') + ')', 'g'
        );
      }
    return text.replace(arguments.callee.sRE, '\\$1');
    },

    /*
      find `name` in current `context`. That is find me a value
      from the view object
    */
    find: function(name, context) {
      name = this.trim(name);

      // Checks whether a value is thruthy or false or 0
      function is_kinda_truthy(bool) {
        return bool === false || bool === 0 || bool;
      }

      var value;
      if(is_kinda_truthy(context[name])) {
        value = context[name];
      } else if(is_kinda_truthy(this.context[name])) {
        value = this.context[name];
      }

      if(typeof value === "function") {
        return value.apply(context);
      }
      if(value !== undefined) {
        return value;
      }
      // silently ignore unkown variables
      return "";
    },

    // Utility methods

    /* includes tag */
    includes: function(needle, haystack) {
      return haystack.indexOf(this.otag + needle) != -1;
    },

    /*
      Does away with nasty characters
    */
    escape: function(s) {
      s = String(s === null ? "" : s);
      return s.replace(/&(?!\w+;)|["<>\\]/g, function(s) {
        switch(s) {
          case "&": return "&";
          case "\\": return "\\\\";
          case '"': return '\"';
          case "<": return "<";
          case ">": return ">";
          default: return s;
        }
      });
    },

    // by @langalex, support for arrays of strings
    create_context: function(_context) {
      if(this.is_object(_context)) {
        return _context;
      } else if(this.pragmas["IMPLICIT-ITERATOR"]) {
        var iterator = this.pragmas["IMPLICIT-ITERATOR"].iterator || ".";
        var ctx = {};
        ctx[iterator] = _context;
        return ctx;
      }
    },

    is_object: function(a) {
      return a && typeof a == "object";
    },

    is_array: function(a) {
      return Object.prototype.toString.call(a) === '[object Array]';
    },

    /*
      Gets rid of leading and trailing whitespace
    */
    trim: function(s) {
      return s.replace(/^\s*|\s*$/g, "");
    },

    /*
      Why, why, why? Because IE. Cry, cry cry.
    */
    map: function(array, fn) {
      if (typeof array.map == "function") {
        return array.map(fn);
      } else {
        var r = [];
        var l = array.length;
        for(var i=0;i<l;i++) {
          r.push(fn(array[i]));
        }
        return r;
      }
    }
  };

  return({
    name: "mustache.js",
    version: "0.3.0-dev",

    /*
      Turns a template and view into HTML
    */
    to_html: function(template, view, partials, send_fun) {
      var renderer = new Renderer();
      if(send_fun) {
        renderer.send = send_fun;
      }
      renderer.render(template, view, partials);
      if(!send_fun) {
        return renderer.buffer.join("\n");
      }
    }
  });
}();
<commit_msg>whitespacin'<commit_after>/*
  mustache.js — Logic-less templates in JavaScript

  See http://mustache.github.com/ for more info.
*/

var Mustache = function() {
  var Renderer = function() {};

  Renderer.prototype = {
    otag: "{{",
    ctag: "}}",
    pragmas: {},
    buffer: [],
    pragmas_implemented: {
      "IMPLICIT-ITERATOR": true
    },
    context: {},

    render: function(template, context, partials, in_recursion) {
      // reset buffer & set context
      if(!in_recursion) {
        this.context = context;
        this.buffer = []; // TODO: make this non-lazy
      }

      // fail fast
      if(!this.includes("", template)) {
        if(in_recursion) {
          return template;
        } else {
          this.send(template);
          return;
        }
      }

      template = this.render_pragmas(template);
      var html = this.render_section(template, context, partials);
      if(in_recursion) {
        return this.render_tags(html, context, partials, in_recursion);
      }

      this.render_tags(html, context, partials, in_recursion);
    },

    /*
      Sends parsed lines
    */
    send: function(line) {
      if(line != "") {
        this.buffer.push(line);
      }
    },

    /*
      Looks for %PRAGMAS
    */
    render_pragmas: function(template) {
      // no pragmas
      if(!this.includes("%", template)) {
        return template;
      }

      var that = this;
      var regex = new RegExp(this.otag + "%([\\w_-]+) ?([\\w]+=[\\w]+)?" +
            this.ctag);
      return template.replace(regex, function(match, pragma, options) {
        if(!that.pragmas_implemented[pragma]) {
          throw({message:
            "This implementation of mustache doesn't understand the '" +
            pragma + "' pragma"});
        }
        that.pragmas[pragma] = {};
        if(options) {
          var opts = options.split("=");
          that.pragmas[pragma][opts[0]] = opts[1];
        }
        return "";
        // ignore unknown pragmas silently
      });
    },

    /*
      Tries to find a partial in the curent scope and render it
    */
    render_partial: function(name, context, partials) {
      name = this.trim(name);
      if(!partials || !partials[name]) {
        throw({message: "unknown_partial '" + name + "'"});
      }
      if(typeof(context[name]) != "object") {
        return this.render(partials[name], context, partials, true);
      }
      return this.render(partials[name], context[name], partials, true);
    },

    /*
      Renders inverted (^) and normal (#) sections
    */
    render_section: function(template, context, partials) {
      if(!this.includes("#", template) && !this.includes("^", template)) {
        return template;
      }

      var that = this;
      // CSW - Added "+?" so it finds the tighest bound, not the widest
      var regex = new RegExp(this.otag + "(\\^|\\#)\\s*(.+)\\s*" + this.ctag +
              "\\s*([\\s\\S]+?)" + this.otag + "\\/\\s*\\2\\s*" + this.ctag +
              "\\s*", "mg");

      // for each {{#foo}}{{/foo}} section do...
      return template.replace(regex, function(match, type, name, content) {
        var value = that.find(name, context);
        if(type == "^") { // inverted section
          if(!value || that.is_array(value) && value.length === 0) {
            // false or empty list, render it
            return that.render(content, context, partials, true);
          } else {
            return "";
          }
        } else if(type == "#") { // normal section
          if(that.is_array(value)) { // Enumerable, Let's loop!
            return that.map(value, function(row) {
              return that.render(content, that.create_context(row),
                partials, true);
            }).join("");
          } else if(that.is_object(value)) { // Object, Use it as subcontext!
            return that.render(content, that.create_context(value),
              partials, true);
          } else if(typeof value === "function") {
            // higher order section
            return value.call(context, content, function(text) {
              return that.render(text, context, partials, true);
            });
          } else if(value) { // boolean section
            return that.render(content, context, partials, true);
          } else {
            return "";
          }
        }
      });
    },

    /*
      Replace {{foo}} and friends with values from our view
    */
    render_tags: function(template, context, partials, in_recursion) {
      // tit for tat
      var that = this;

      var new_regex = function() {
        return new RegExp(that.otag + "(=|!|>|\\{|%)?([^\\/#\\^]+?)\\1?" +
          that.ctag + "+", "g");
      };

      var regex = new_regex();
      var tag_replace_callback = function(match, operator, name) {
        switch(operator) {
        case "!": // ignore comments
          return "";
        case "=": // set new delimiters, rebuild the replace regexp
          that.set_delimiters(name);
          regex = new_regex();
          return "";
        case ">": // render partial
          return that.render_partial(name, context, partials);
        case "{": // the triple mustache is unescaped
          return that.find(name, context);
        default: // escape the value
          return that.escape(that.find(name, context));
        }
      };
      var lines = template.split("\n");
      for(var i = 0; i < lines.length; i++) {
        lines[i] = lines[i].replace(regex, tag_replace_callback, this);
        if(!in_recursion) {
          this.send(lines[i]);
        }
      }

      if(in_recursion) {
        return lines.join("\n");
      }
    },

    set_delimiters: function(delimiters) {
      var dels = delimiters.split(" ");
      this.otag = this.escape_regex(dels[0]);
      this.ctag = this.escape_regex(dels[1]);
    },

    escape_regex: function(text) {
      // thank you Simon Willison
      if(!arguments.callee.sRE) {
        var specials = [
          '/', '.', '*', '+', '?', '|',
          '(', ')', '[', ']', '{', '}', '\\'
        ];
        arguments.callee.sRE = new RegExp(
          '(\\' + specials.join('|\\') + ')', 'g'
        );
      }
      return text.replace(arguments.callee.sRE, '\\$1');
    },

    /*
      find `name` in current `context`. That is find me a value
      from the view object
    */
    find: function(name, context) {
      name = this.trim(name);

      // Checks whether a value is thruthy or false or 0
      function is_kinda_truthy(bool) {
        return bool === false || bool === 0 || bool;
      }

      var value;
      if(is_kinda_truthy(context[name])) {
        value = context[name];
      } else if(is_kinda_truthy(this.context[name])) {
        value = this.context[name];
      }

      if(typeof value === "function") {
        return value.apply(context);
      }
      if(value !== undefined) {
        return value;
      }
      // silently ignore unkown variables
      return "";
    },

    // Utility methods

    /* includes tag */
    includes: function(needle, haystack) {
      return haystack.indexOf(this.otag + needle) != -1;
    },

    /*
      Does away with nasty characters
    */
    escape: function(s) {
      s = String(s === null ? "" : s);
      return s.replace(/&(?!\w+;)|["<>\\]/g, function(s) {
        switch(s) {
        case "&": return "&";
        case "\\": return "\\\\";
        case '"': return '\"';
        case "<": return "<";
        case ">": return ">";
        default: return s;
        }
      });
    },

    // by @langalex, support for arrays of strings
    create_context: function(_context) {
      if(this.is_object(_context)) {
        return _context;
      } else if(this.pragmas["IMPLICIT-ITERATOR"]) {
        var iterator = this.pragmas["IMPLICIT-ITERATOR"].iterator || ".";
        var ctx = {};
        ctx[iterator] = _context;
        return ctx;
      }
    },

    is_object: function(a) {
      return a && typeof a == "object";
    },

    is_array: function(a) {
      return Object.prototype.toString.call(a) === '[object Array]';
    },

    /*
      Gets rid of leading and trailing whitespace
    */
    trim: function(s) {
      return s.replace(/^\s*|\s*$/g, "");
    },

    /*
      Why, why, why? Because IE. Cry, cry cry.
    */
    map: function(array, fn) {
      if (typeof array.map == "function") {
        return array.map(fn);
      } else {
        var r = [];
        var l = array.length;
        for(var i = 0; i < l; i++) {
          r.push(fn(array[i]));
        }
        return r;
      }
    }
  };

  return({
    name: "mustache.js",
    version: "0.3.0-dev",

    /*
      Turns a template and view into HTML
    */
    to_html: function(template, view, partials, send_fun) {
      var renderer = new Renderer();
      if(send_fun) {
        renderer.send = send_fun;
      }
      renderer.render(template, view, partials);
      if(!send_fun) {
        return renderer.buffer.join("\n");
      }
    }
  });
}();
<|endoftext|>


<commit_before>; (function($, undefined) {

    // Plugin Logic
    $.fn.extend({

        myPlugin: function (options) {

            console.log('Plugin has been called');

            // Set our options from the defaults, overriding with the
            // parameter we pass into this function
            options = $.extend({}, $.fn.myPlugin.options, options);

            return this.each(function(index, element) {

                console.log(index);
                console.log($(element));

            });

        }

    });

    // Methods (Private)

    // Defaults
    $.fn.myPlugin.options = {

    };

})(jQuery);

// Initialise when the DOM is ready
$(function () {

  // $('div').myPlugin();

});
<commit_msg>Added jshint comment<commit_after>; // jshint ignore:line
(function($, undefined) {

    // Plugin Logic
    $.fn.extend({

        myPlugin: function (options) {

            console.log('Plugin has been called');

            // Set our options from the defaults, overriding with the
            // parameter we pass into this function
            options = $.extend({}, $.fn.myPlugin.options, options);

            return this.each(function(index, element) {

                console.log(index);
                console.log($(element));

            });

        }

    });

    // Methods (Private)

    // Defaults
    $.fn.myPlugin.options = {

    };

})(jQuery);

// Initialise when the DOM is ready
$(function () {

  // $('div').myPlugin();

});
<|endoftext|>


<commit_before>/**
 * Backbone localStorage Adapter
 * Version 1.1.13
 *
 * https://github.com/jeromegn/Backbone.localStorage
 */
(function (root, factory) {
  if (typeof exports === 'object' && typeof require === 'function') {
    module.exports = factory(require("backbone"));
  } else if (typeof define === "function" && define.amd) {
    // AMD. Register as an anonymous module.
    define(["backbone"], function(Backbone) {
      // Use global variables if the locals are undefined.
      return factory(Backbone || root.Backbone);
    });
  } else {
    factory(Backbone);
  }
}(this, function(Backbone) {
// A simple module to replace `Backbone.sync` with *localStorage*-based
// persistence. Models are given GUIDS, and saved into a JSON object. Simple
// as that.

// Hold reference to Underscore.js and Backbone.js in the closure in order
// to make things work even if they are removed from the global namespace

// Generate four random hex digits.
function S4() {
   return (((1+Math.random())*0x10000)|0).toString(16).substring(1);
};

// Generate a pseudo-GUID by concatenating random hexadecimal.
function guid() {
   return (S4()+S4()+"-"+S4()+"-"+S4()+"-"+S4()+"-"+S4()+S4()+S4());
};

function isObject(item) {
  return item === Object(item);
}

function contains(array, item) {
  var i = array.length;
  while (i--) if (array[i] === item) return true;
  return false;
}

function extend(obj, props) {
  for (var key in props) obj[key] = props[key]
  return obj;
}

function result(object, property) {
    if (object == null) return void 0;
    var value = object[property];
    return (typeof value === 'function') ? object[property]() : value;
}

// Our Store is represented by a single JS object in *localStorage*. Create it
// with a meaningful name, like the name you'd give a table.
// window.Store is deprectated, use Backbone.LocalStorage instead
Backbone.LocalStorage = window.Store = function(name, serializer) {
  if( !this.localStorage ) {
    throw "Backbone.localStorage: Environment does not support localStorage."
  }
  this.name = name;
  this.serializer = serializer || {
    serialize: function(item) {
      return isObject(item) ? JSON.stringify(item) : item;
    },
    // fix for "illegal access" error on Android when JSON.parse is passed null
    deserialize: function (data) {
      return data && JSON.parse(data);
    }
  };
  var store = this.localStorage().getItem(this.name);
  this.records = (store && store.split(",")) || [];
};

extend(Backbone.LocalStorage.prototype, {

  // Save the current state of the **Store** to *localStorage*.
  save: function() {
    this.localStorage().setItem(this.name, this.records.join(","));
  },

  // Add a model, giving it a (hopefully)-unique GUID, if it doesn't already
  // have an id of it's own.
  create: function(model) {
    if (!model.id && model.id !== 0) {
      model.id = guid();
      model.set(model.idAttribute, model.id);
    }
    this.localStorage().setItem(this._itemName(model.id), this.serializer.serialize(model));
    this.records.push(model.id.toString());
    this.save();
    return this.find(model) !== false;
  },

  // Update a model by replacing its copy in `this.data`.
  update: function(model) {
    this.localStorage().setItem(this._itemName(model.id), this.serializer.serialize(model));
    var modelId = model.id.toString();
    if (!contains(this.records, modelId)) {
      this.records.push(modelId);
      this.save();
    }
    return this.find(model) !== false;
  },

  // Retrieve a model from `this.data` by id.
  find: function(model) {
    return this.serializer.deserialize(this.localStorage().getItem(this._itemName(model.id)));
  },

  // Return the array of all models currently in storage.
  findAll: function() {
    var result = [];
    for (var i = 0, id, data; i < this.records.length; i++) {
      id = this.records[i];
      data = this.serializer.deserialize(this.localStorage().getItem(this._itemName(id)));
      if (data != null) result.push(data);
    }
    return result;
  },

  // Delete a model from `this.data`, returning it.
  destroy: function(model) {
    this.localStorage().removeItem(this._itemName(model.id));
    var modelId = model.id.toString();
    for (var i = 0, id; i < this.records.length; i++) {
      if (this.records[i] === modelId) {
        this.records.splice(i, 1);
      }
    }
    this.save();
    return model;
  },

  localStorage: function() {
    return localStorage;
  },

  // Clear localStorage for specific collection.
  _clear: function() {
    var local = this.localStorage(),
      itemRe = new RegExp("^" + this.name + "-");

    // Remove id-tracking item (e.g., "foo").
    local.removeItem(this.name);

    // Match all data items (e.g., "foo-ID") and remove.
    for (var k in local) {
      if (itemRe.test(k)) {
        local.removeItem(k);
      }
    }

    this.records.length = 0;
  },

  // Size of localStorage.
  _storageSize: function() {
    return this.localStorage().length;
  },

  _itemName: function(id) {
    return this.name+"-"+id;
  }

});

// localSync delegate to the model or collection's
// *localStorage* property, which should be an instance of `Store`.
// window.Store.sync and Backbone.localSync is deprecated, use Backbone.LocalStorage.sync instead
Backbone.LocalStorage.sync = window.Store.sync = Backbone.localSync = function(method, model, options) {
  var store = result(model, 'localStorage') || result(model.collection, 'localStorage');

  var resp, errorMessage;
  //If $ is having Deferred - use it.
  var syncDfd = Backbone.$ ?
    (Backbone.$.Deferred && Backbone.$.Deferred()) :
    (Backbone.Deferred && Backbone.Deferred());

  try {

    switch (method) {
      case "read":
        resp = model.id != undefined ? store.find(model) : store.findAll();
        break;
      case "create":
        resp = store.create(model);
        break;
      case "update":
        resp = store.update(model);
        break;
      case "delete":
        resp = store.destroy(model);
        break;
    }

  } catch(error) {
    if (error.code === 22 && store._storageSize() === 0)
      errorMessage = "Private browsing is unsupported";
    else
      errorMessage = error.message;
  }

  if (resp) {
    if (options && options.success) {
      if (Backbone.VERSION === "0.9.10") {
        options.success(model, resp, options);
      } else {
        options.success(resp);
      }
    }
    if (syncDfd) {
      syncDfd.resolve(resp);
    }

  } else {
    errorMessage = errorMessage ? errorMessage
                                : "Record Not Found";

    if (options && options.error)
      if (Backbone.VERSION === "0.9.10") {
        options.error(model, errorMessage, options);
      } else {
        options.error(errorMessage);
      }

    if (syncDfd)
      syncDfd.reject(errorMessage);
  }

  // add compatibility with $.ajax
  // always execute callback for success and error
  if (options && options.complete) options.complete(resp);

  return syncDfd && syncDfd.promise();
};

Backbone.ajaxSync = Backbone.sync;

Backbone.getSyncMethod = function(model) {
  if(model.localStorage || (model.collection && model.collection.localStorage)) {
    return Backbone.localSync;
  }

  return Backbone.ajaxSync;
};

// Override 'Backbone.sync' to default to localSync,
// the original 'Backbone.sync' is still available in 'Backbone.ajaxSync'
Backbone.sync = function(method, model, options) {
  return Backbone.getSyncMethod(model).apply(this, [method, model, options]);
};

return Backbone.LocalStorage;
}));
<commit_msg>Delete outdated comments<commit_after>/**
 * Backbone localStorage Adapter
 * Version 1.1.13
 *
 * https://github.com/jeromegn/Backbone.localStorage
 */
(function (root, factory) {
  if (typeof exports === 'object' && typeof require === 'function') {
    module.exports = factory(require("backbone"));
  } else if (typeof define === "function" && define.amd) {
    // AMD. Register as an anonymous module.
    define(["backbone"], function(Backbone) {
      // Use global variables if the locals are undefined.
      return factory(Backbone || root.Backbone);
    });
  } else {
    factory(Backbone);
  }
}(this, function(Backbone) {
// A simple module to replace `Backbone.sync` with *localStorage*-based
// persistence. Models are given GUIDS, and saved into a JSON object. Simple
// as that.

// Generate four random hex digits.
function S4() {
   return (((1+Math.random())*0x10000)|0).toString(16).substring(1);
};

// Generate a pseudo-GUID by concatenating random hexadecimal.
function guid() {
   return (S4()+S4()+"-"+S4()+"-"+S4()+"-"+S4()+"-"+S4()+S4()+S4());
};

function isObject(item) {
  return item === Object(item);
}

function contains(array, item) {
  var i = array.length;
  while (i--) if (array[i] === item) return true;
  return false;
}

function extend(obj, props) {
  for (var key in props) obj[key] = props[key]
  return obj;
}

function result(object, property) {
    if (object == null) return void 0;
    var value = object[property];
    return (typeof value === 'function') ? object[property]() : value;
}

// Our Store is represented by a single JS object in *localStorage*. Create it
// with a meaningful name, like the name you'd give a table.
// window.Store is deprectated, use Backbone.LocalStorage instead
Backbone.LocalStorage = window.Store = function(name, serializer) {
  if( !this.localStorage ) {
    throw "Backbone.localStorage: Environment does not support localStorage."
  }
  this.name = name;
  this.serializer = serializer || {
    serialize: function(item) {
      return isObject(item) ? JSON.stringify(item) : item;
    },
    // fix for "illegal access" error on Android when JSON.parse is passed null
    deserialize: function (data) {
      return data && JSON.parse(data);
    }
  };
  var store = this.localStorage().getItem(this.name);
  this.records = (store && store.split(",")) || [];
};

extend(Backbone.LocalStorage.prototype, {

  // Save the current state of the **Store** to *localStorage*.
  save: function() {
    this.localStorage().setItem(this.name, this.records.join(","));
  },

  // Add a model, giving it a (hopefully)-unique GUID, if it doesn't already
  // have an id of it's own.
  create: function(model) {
    if (!model.id && model.id !== 0) {
      model.id = guid();
      model.set(model.idAttribute, model.id);
    }
    this.localStorage().setItem(this._itemName(model.id), this.serializer.serialize(model));
    this.records.push(model.id.toString());
    this.save();
    return this.find(model) !== false;
  },

  // Update a model by replacing its copy in `this.data`.
  update: function(model) {
    this.localStorage().setItem(this._itemName(model.id), this.serializer.serialize(model));
    var modelId = model.id.toString();
    if (!contains(this.records, modelId)) {
      this.records.push(modelId);
      this.save();
    }
    return this.find(model) !== false;
  },

  // Retrieve a model from `this.data` by id.
  find: function(model) {
    return this.serializer.deserialize(this.localStorage().getItem(this._itemName(model.id)));
  },

  // Return the array of all models currently in storage.
  findAll: function() {
    var result = [];
    for (var i = 0, id, data; i < this.records.length; i++) {
      id = this.records[i];
      data = this.serializer.deserialize(this.localStorage().getItem(this._itemName(id)));
      if (data != null) result.push(data);
    }
    return result;
  },

  // Delete a model from `this.data`, returning it.
  destroy: function(model) {
    this.localStorage().removeItem(this._itemName(model.id));
    var modelId = model.id.toString();
    for (var i = 0, id; i < this.records.length; i++) {
      if (this.records[i] === modelId) {
        this.records.splice(i, 1);
      }
    }
    this.save();
    return model;
  },

  localStorage: function() {
    return localStorage;
  },

  // Clear localStorage for specific collection.
  _clear: function() {
    var local = this.localStorage(),
      itemRe = new RegExp("^" + this.name + "-");

    // Remove id-tracking item (e.g., "foo").
    local.removeItem(this.name);

    // Match all data items (e.g., "foo-ID") and remove.
    for (var k in local) {
      if (itemRe.test(k)) {
        local.removeItem(k);
      }
    }

    this.records.length = 0;
  },

  // Size of localStorage.
  _storageSize: function() {
    return this.localStorage().length;
  },

  _itemName: function(id) {
    return this.name+"-"+id;
  }

});

// localSync delegate to the model or collection's
// *localStorage* property, which should be an instance of `Store`.
// window.Store.sync and Backbone.localSync is deprecated, use Backbone.LocalStorage.sync instead
Backbone.LocalStorage.sync = window.Store.sync = Backbone.localSync = function(method, model, options) {
  var store = result(model, 'localStorage') || result(model.collection, 'localStorage');

  var resp, errorMessage;
  //If $ is having Deferred - use it.
  var syncDfd = Backbone.$ ?
    (Backbone.$.Deferred && Backbone.$.Deferred()) :
    (Backbone.Deferred && Backbone.Deferred());

  try {

    switch (method) {
      case "read":
        resp = model.id != undefined ? store.find(model) : store.findAll();
        break;
      case "create":
        resp = store.create(model);
        break;
      case "update":
        resp = store.update(model);
        break;
      case "delete":
        resp = store.destroy(model);
        break;
    }

  } catch(error) {
    if (error.code === 22 && store._storageSize() === 0)
      errorMessage = "Private browsing is unsupported";
    else
      errorMessage = error.message;
  }

  if (resp) {
    if (options && options.success) {
      if (Backbone.VERSION === "0.9.10") {
        options.success(model, resp, options);
      } else {
        options.success(resp);
      }
    }
    if (syncDfd) {
      syncDfd.resolve(resp);
    }

  } else {
    errorMessage = errorMessage ? errorMessage
                                : "Record Not Found";

    if (options && options.error)
      if (Backbone.VERSION === "0.9.10") {
        options.error(model, errorMessage, options);
      } else {
        options.error(errorMessage);
      }

    if (syncDfd)
      syncDfd.reject(errorMessage);
  }

  // add compatibility with $.ajax
  // always execute callback for success and error
  if (options && options.complete) options.complete(resp);

  return syncDfd && syncDfd.promise();
};

Backbone.ajaxSync = Backbone.sync;

Backbone.getSyncMethod = function(model) {
  if(model.localStorage || (model.collection && model.collection.localStorage)) {
    return Backbone.localSync;
  }

  return Backbone.ajaxSync;
};

// Override 'Backbone.sync' to default to localSync,
// the original 'Backbone.sync' is still available in 'Backbone.ajaxSync'
Backbone.sync = function(method, model, options) {
  return Backbone.getSyncMethod(model).apply(this, [method, model, options]);
};

return Backbone.LocalStorage;
}));
<|endoftext|>


<commit_before>const coreApp = require('kolibri');
const coreActions = require('kolibri.coreVue.vuex.actions');
const values = require('lodash/values');

const CoreConstants = require('kolibri.coreVue.vuex.constants');
const Constants = require('../../constants');
const ReportConstants = require('../../reportConstants');

const reportGetters = require('../getters/reports');

const RecentReportResourceConstructor = require('../../apiResources/recentReport');
const UserReportResourceConstructor = require('../../apiResources/userReport');
const UserSummaryResourceConstructor = require('../../apiResources/userSummary');
const ContentSummaryResourceConstructor = require('../../apiResources/contentSummary');
const ContentReportResourceConstructor = require('../../apiResources/contentReport');

const RecentReportResource = new RecentReportResourceConstructor(coreApp);
const UserReportResource = new UserReportResourceConstructor(coreApp);
const UserSummaryResource = new UserSummaryResourceConstructor(coreApp);
const ContentSummaryResource = new ContentSummaryResourceConstructor(coreApp);
const ContentReportResource = new ContentReportResourceConstructor(coreApp);

const AttemptLogResource = coreApp.resources.AttemptLog;
const ChannelResource = coreApp.resources.ChannelResource;
const ContentNodeResource = coreApp.resources.ContentNodeResource;

function _showChannelList(store, classId) {
  function channelLastActivePromise(channel) {
    // helper function for _showChannelList
    // @param channel to get recentActivity for
    // @returns promise that resolves channel with lastActive value in object:
    // {
    //   'channelId': dateOfLastActivity,
    // }
    const summaryPayload = {
      channel_id: channel.id,
      collection_kind: ReportConstants.UserScopes.FACILITY,
      collection_id: store.state.core.session.facility_id,
    };

    // workaround for conditionalPromise.then() misbehaving
    return new Promise(
      (resolve, reject) => {
        const getSumm = ContentSummaryResource.getModel(channel.root_id, summaryPayload).fetch();
        getSumm.then(
          channelSummary => {
            const channelLastActive = {};
            channelLastActive[channel.id] = channelSummary.last_active;
            resolve(channelLastActive);
          },
          error => reject(error)
        );
      }
    );
  }

  const channelLastActivePromises = [];
  store.state.core.channels.list.forEach(
    channel => channelLastActivePromises.push(channelLastActivePromise(channel))
  );

  Promise.all(channelLastActivePromises).then(
    allChannelLastActive => {
      const lastActive = {};
      allChannelLastActive.forEach(
        channelLastActive => Object.assign(lastActive, channelLastActive)
      );
      const pageState = {
        lastActive,
        classId,
      };
      store.dispatch('SET_PAGE_STATE', pageState);
      store.dispatch('CORE_SET_PAGE_LOADING', false);
      store.dispatch('CORE_SET_ERROR', null);
    }
  );
}

function _progressState(progressData) {
  // not all of these keys are defined for all requests...
  return {
    // all reports
    totalProgress: progressData.total_progress,
    // content/learner reports
    kind: progressData.kind,
    nodeCount: progressData.node_count,
    // 'recent' reports
    logCountComplete: progressData.log_count_complete,
    logCountTotal: progressData.log_count_total,
  };
}

function _reportState(data) {
  if (!data) { return []; }
  return data.map(row => ({
    contentId: row.content_id,
    kind: row.kind,
    lastActive: row.last_active,
    parent: {
      id: row.parent.pk,
      title: row.parent.title,
    },
    id: row.pk,
    progress: row.progress.map(_progressState),
    title: row.title,
  }));
}

function _contentSummaryState(data) {
  if (!data) { return {}; }
  const kind = !data.ancestors.length ? CoreConstants.ContentNodeKinds.CHANNEL : data.kind;
  return {
    ancestors: data.ancestors.map(item => ({
      id: item.pk,
      title: item.title
    })),
    contentId: data.content_id,
    kind,
    lastActive: data.last_active,
    numUsers: data.num_users,
    id: data.pk,
    progress: data.progress.map(_progressState),
    title: data.title,
  };
}

function _userSummaryState(data) {
  // console.log('uuuuuu', data);
  if (!data) {
    return {};
  }
  return data;
}

function _showReport(store, options) {
  const classId = options.classId;
  const channelId = options.channelId;
  const contentScope = options.contentScope;
  const contentScopeId = options.contentScopeId;
  const userScope = options.userScope;
  const userScopeId = options.userScopeId;

  /* check if params are semi-valid. */
  function _validate(value, constants) {
    if (!values(constants).includes(value)) {
      throw Error(`Invalid report parameters: ${value} not in ${JSON.stringify(constants)}`);
    }
  }
  _validate(contentScope, ReportConstants.ContentScopes);
  _validate(userScope, ReportConstants.UserScopes);

  // REPORT
  const reportPayload = {
    channel_id: channelId,
    content_node_id: contentScopeId,
    collection_kind: ReportConstants.UserScopes.CLASSROOM,
    collection_id: classId,
  };
  let reportPromise;
  if (reportGetters.isTopicPage) {
    reportPromise = ContentReportResource.getCollection(reportPayload).fetch();
  } else if (reportGetters.isLearnerPage) {
    reportPromise = UserReportResource.getCollection(reportPayload).fetch();
  } else if (reportGetters.isRecentPage) {
    throw Error('recent report is not currently handled in this action');
  }

  // CONTENT SUMMARY
  const contentPromise = ContentSummaryResource.getModel(contentScopeId, reportPayload).fetch();

  // USER SUMMARY
  let userPromise;
  if (userScope === ReportConstants.UserScopes.USER) {
    userPromise = UserSummaryResource.getModel(userScopeId, reportPayload).fetch();
  }

  const promises = [];
  promises.push(reportPromise);
  promises.push(contentPromise);
  promises.push(userPromise);

  // API response handlers
  Promise.all(promises).then(
    ([report, contentSummary, userSummary]) => {
      const pageState = {
        classId,
        channelId,
        contentScope,
        contentScopeId,
        userScope,
        userScopeId,
        tableData: _reportState(report),
        contentScopeSummary: _contentSummaryState(contentSummary),
        userScopeSummary: _userSummaryState(userSummary),
      };
      store.dispatch('SET_PAGE_STATE', pageState);
      store.dispatch('CORE_SET_PAGE_LOADING', false);
    },
    error => coreActions.handleError(store, error)
  );
}

function _showChannelRoot(store, classId, channelId) {
  const channelPromise = ChannelResource.getModel(channelId).fetch();

  channelPromise.then(
    (channelData) => {
      _showReport(store, {
        classId,
        channelId,
        contentScope: ReportConstants.ContentScopes.ROOT,
        contentScopeId: channelData.root_pk,
        userScope: ReportConstants.UserScopes.CLASSROOM,
        userScopeId: classId,
        sortColumn: ReportConstants.TableColumns.NAME,
        sortOrder: ReportConstants.SortOrders.NONE,
      });
    },
    error => coreActions.handleError(store, error)
  );
}

function _showTopic(store, classId, channelId, topicId) {
  _showReport(store, {
    classId,
    channelId,
    contentScope: ReportConstants.ContentScopes.TOPIC,
    contentScopeId: topicId,
    userScope: ReportConstants.UserScopes.CLASSROOM,
    userScopeId: classId,
    sortColumn: ReportConstants.TableColumns.NAME,
    sortOrder: ReportConstants.SortOrders.NONE,
  });
}

// needs exercise, attemptlog. Pass answerstate into contentrender to display answer
function showCoachExerciseRenderPage(store, classId, userId, channelId, contentId) {
  // function _daysElapsed(startTime, endTime) {
  //   const ONE_DAY = 86400000;
  //   return (Date.UTC(startTime.getYear(), startTime.getMonth(), startTime.getDate()) -
  //     Date.UTC(endTime.getYear(), endTime.getMonth(), endTime.getDate())) / ONE_DAY;
  // }
  store.dispatch('CORE_SET_PAGE_LOADING', true);
  store.dispatch('SET_PAGE_NAME', Constants.PageNames.EXERCISE_RENDER);

  // const reversedAttemptLogs = [];
  // const today = new Date();

  Promise.all([
    ContentNodeResource.getCollection({ channel_id: channelId }, { content_id: contentId }).fetch(),
    AttemptLogResource.getCollection({ user: userId, content: contentId }).fetch(),
  ]).then(
    ([exercise, attemptLogs]) => {
      attemptLogs.sort(
        (attemptLog1, attemptLog2) =>
          new Date(attemptLog2.end_timestamp) - new Date(attemptLog1.end_timestamp)
      );

      console.log('attemptLogs', attemptLogs);
      console.log('exercise', exercise[0]);
      const pageState = {
        // because this is info returned from a collection
        exercise: exercise[0],
        attemptLogs,
        channelId,
      };
      store.dispatch('SET_PAGE_STATE', pageState);
      store.dispatch('CORE_SET_PAGE_LOADING', false);
      store.dispatch('CORE_SET_TITLE', 'Exercise Detail View');
    },
      error => { coreActions.handleApiError(store, error); }
    );
}

function showRecentChannels(store, classId) {
  store.dispatch('SET_PAGE_NAME', Constants.PageNames.RECENT_CHANNELS);
  store.dispatch('CORE_SET_TITLE', 'Recent - All channels');
  store.dispatch('CORE_SET_PAGE_LOADING', true);
  // console.log('showRecentChannels');
  _showChannelList(store, classId);
}

function showRecentItemsForChannel(store, classId, channelId) {
  store.dispatch('SET_PAGE_NAME', Constants.PageNames.RECENT_ITEMS_FOR_CHANNEL);
  store.dispatch('CORE_SET_TITLE', 'Recent - Items');
  store.dispatch('CORE_SET_PAGE_LOADING', true);
  // console.log('showRecentItemsForChannel');
  const channelPromise = ChannelResource.getModel(channelId).fetch();

  channelPromise.then(
    channelData => {
      const sevenDaysAgo = new Date();
      // this is being set by default in the backend
      // backend date data might be unreliable, though
      sevenDaysAgo.setDate(sevenDaysAgo.getDate() - 7);

      const reportPayload = {
        channel_id: channelId,
        content_node_id: channelData.root_pk,
        collection_kind: ReportConstants.UserScopes.CLASSROOM,
        collection_id: classId,
        last_active_time: sevenDaysAgo,
      };
      const recentReportsPromise = RecentReportResource.getCollection(reportPayload).fetch();

      recentReportsPromise.then(
        reports => {
          const pageState = {
            reports: _reportState(reports),
            classId,
            channelId,
          };
          store.dispatch('SET_PAGE_STATE', pageState);
          store.dispatch('CORE_SET_PAGE_LOADING', false);
          store.dispatch('CORE_SET_ERROR', null);
          store.dispatch('CORE_SET_TITLE', 'Recents');
        },
        error => coreActions.handleApiError(store, error)
      );
    },
    error => coreActions.handleApiError(store, error)
  );
}

function showRecentLearnersForItem(store, classId, channelId, contentId) {
  store.dispatch('SET_PAGE_NAME', Constants.PageNames.RECENT_LEARNERS_FOR_ITEM);
  store.dispatch('CORE_SET_TITLE', 'Recent - Learners');
  store.dispatch('CORE_SET_PAGE_LOADING', true);
  // console.log('showRecentLearnersForItem');
}

function showRecentLearnerItemDetails(store, classId, channelId, contentId, userId) {
  store.dispatch('SET_PAGE_NAME', Constants.PageNames.RECENT_LEARNER_ITEM_DETAILS);
  store.dispatch('CORE_SET_TITLE', 'Recent - Learner Details');
  store.dispatch('CORE_SET_PAGE_LOADING', true);
  // console.log('showRecentLearnerItemDetails');
}

function showTopicChannels(store, classId) {
  store.dispatch('SET_PAGE_NAME', Constants.PageNames.TOPIC_CHANNELS);
  store.dispatch('CORE_SET_TITLE', 'Topics - All channels');
  store.dispatch('CORE_SET_PAGE_LOADING', true);
  // console.log('showTopicChannels');
  _showChannelList(store, classId);
}

function showTopicChannelRoot(store, classId, channelId) {
  store.dispatch('SET_PAGE_NAME', Constants.PageNames.TOPIC_CHANNEL_ROOT);
  store.dispatch('CORE_SET_TITLE', 'Topics - Channel');
  store.dispatch('CORE_SET_PAGE_LOADING', true);
  // console.log('showTopicChannelRoot');
  _showChannelRoot(store, classId, channelId);
}

function showTopicItemList(store, classId, channelId, topicId) {
  store.dispatch('SET_PAGE_NAME', Constants.PageNames.TOPIC_ITEM_LIST);
  store.dispatch('CORE_SET_TITLE', 'Topics - Items');
  store.dispatch('CORE_SET_PAGE_LOADING', true);
  // console.log('showTopicItemList');
  _showTopic(store, classId, channelId, topicId);
}

function showTopicLearnersForItem(store, classId, channelId, contentId) {
  store.dispatch('SET_PAGE_NAME', Constants.PageNames.TOPIC_LEARNERS_FOR_ITEM);
  store.dispatch('CORE_SET_TITLE', 'Topics - Learners');
  store.dispatch('CORE_SET_PAGE_LOADING', true);
  // console.log('showTopicLearnersForItem');
}

function showTopicLearnerItemDetails(store, classId, channelId, contentId, userId) {
  store.dispatch('SET_PAGE_NAME', Constants.PageNames.TOPIC_LEARNER_ITEM_DETAILS);
  store.dispatch('CORE_SET_TITLE', 'Topics - Learner Details');
  store.dispatch('CORE_SET_PAGE_LOADING', true);
  // console.log('showTopicLearnerItemDetails');
}

function showLearnerList(store, classId) {
  store.dispatch('SET_PAGE_NAME', Constants.PageNames.LEARNER_LIST);
  store.dispatch('CORE_SET_TITLE', 'Learners');
  store.dispatch('CORE_SET_PAGE_LOADING', true);
  // console.log('showLearnerList');
}

function showLearnerChannels(store, classId, userId) {
  store.dispatch('SET_PAGE_NAME', Constants.PageNames.LEARNER_CHANNELS);
  store.dispatch('CORE_SET_TITLE', 'Learners - All channels');
  store.dispatch('CORE_SET_PAGE_LOADING', true);
  // console.log('showLearnerChannels');
  _showChannelList(store, classId);
}

function showLearnerChannelRoot(store, classId, userId, channelId) {
  store.dispatch('SET_PAGE_NAME', Constants.PageNames.LEARNER_CHANNEL_ROOT);
  store.dispatch('CORE_SET_TITLE', 'Learners - Channel');
  store.dispatch('CORE_SET_PAGE_LOADING', true);
  // console.log('showLearnerChannelRoot');
}

function showLearnerItemList(store, classId, userId, channelId, topicId) {
  store.dispatch('SET_PAGE_NAME', Constants.PageNames.LEARNER_ITEM_LIST);
  store.dispatch('CORE_SET_TITLE', 'Learners - Items');
  store.dispatch('CORE_SET_PAGE_LOADING', true);
  // console.log('showLearnerItemList');
}

function showLearnerItemDetails(store, classId, userId, channelId, contentId) {
  store.dispatch('SET_PAGE_NAME', Constants.PageNames.LEARNER_ITEM_DETAILS);
  store.dispatch('CORE_SET_TITLE', 'Learners - Item Details');
  store.dispatch('CORE_SET_PAGE_LOADING', true);
  // console.log('showLearnerItemDetails');
}

module.exports = {
  showCoachExerciseRenderPage, // remove this after making it a helper
  showRecentChannels,
  showRecentItemsForChannel,
  showRecentLearnersForItem,
  showRecentLearnerItemDetails,
  showTopicChannels,
  showTopicChannelRoot,
  showTopicItemList,
  showTopicLearnersForItem,
  showTopicLearnerItemDetails,
  showLearnerList,
  showLearnerChannels,
  showLearnerChannelRoot,
  showLearnerItemList,
  showLearnerItemDetails,
};
<commit_msg>Clearing out unused logic<commit_after>const coreApp = require('kolibri');
const coreActions = require('kolibri.coreVue.vuex.actions');
const values = require('lodash/values');

const CoreConstants = require('kolibri.coreVue.vuex.constants');
const Constants = require('../../constants');
const ReportConstants = require('../../reportConstants');

const reportGetters = require('../getters/reports');

const RecentReportResourceConstructor = require('../../apiResources/recentReport');
const UserReportResourceConstructor = require('../../apiResources/userReport');
const UserSummaryResourceConstructor = require('../../apiResources/userSummary');
const ContentSummaryResourceConstructor = require('../../apiResources/contentSummary');
const ContentReportResourceConstructor = require('../../apiResources/contentReport');

const RecentReportResource = new RecentReportResourceConstructor(coreApp);
const UserReportResource = new UserReportResourceConstructor(coreApp);
const UserSummaryResource = new UserSummaryResourceConstructor(coreApp);
const ContentSummaryResource = new ContentSummaryResourceConstructor(coreApp);
const ContentReportResource = new ContentReportResourceConstructor(coreApp);

const AttemptLogResource = coreApp.resources.AttemptLog;
const ChannelResource = coreApp.resources.ChannelResource;
const ContentNodeResource = coreApp.resources.ContentNodeResource;

function _showChannelList(store, classId) {
  function channelLastActivePromise(channel) {
    // helper function for _showChannelList
    // @param channel to get recentActivity for
    // @returns promise that resolves channel with lastActive value in object:
    // {
    //   'channelId': dateOfLastActivity,
    // }
    const summaryPayload = {
      channel_id: channel.id,
      collection_kind: ReportConstants.UserScopes.FACILITY,
      collection_id: store.state.core.session.facility_id,
    };

    // workaround for conditionalPromise.then() misbehaving
    return new Promise(
      (resolve, reject) => {
        const getSumm = ContentSummaryResource.getModel(channel.root_id, summaryPayload).fetch();
        getSumm.then(
          channelSummary => {
            const channelLastActive = {};
            channelLastActive[channel.id] = channelSummary.last_active;
            resolve(channelLastActive);
          },
          error => reject(error)
        );
      }
    );
  }

  const channelLastActivePromises = [];
  store.state.core.channels.list.forEach(
    channel => channelLastActivePromises.push(channelLastActivePromise(channel))
  );

  Promise.all(channelLastActivePromises).then(
    allChannelLastActive => {
      const lastActive = {};
      allChannelLastActive.forEach(
        channelLastActive => Object.assign(lastActive, channelLastActive)
      );
      const pageState = {
        lastActive,
        classId,
      };
      store.dispatch('SET_PAGE_STATE', pageState);
      store.dispatch('CORE_SET_PAGE_LOADING', false);
      store.dispatch('CORE_SET_ERROR', null);
    }
  );
}

function _progressState(progressData) {
  // not all of these keys are defined for all requests...
  return {
    // all reports
    totalProgress: progressData.total_progress,
    // content/learner reports
    kind: progressData.kind,
    nodeCount: progressData.node_count,
    // 'recent' reports
    logCountComplete: progressData.log_count_complete,
    logCountTotal: progressData.log_count_total,
  };
}

function _reportState(data) {
  if (!data) { return []; }
  return data.map(row => ({
    contentId: row.content_id,
    kind: row.kind,
    lastActive: row.last_active,
    parent: {
      id: row.parent.pk,
      title: row.parent.title,
    },
    id: row.pk,
    progress: row.progress.map(_progressState),
    title: row.title,
  }));
}

function _contentSummaryState(data) {
  if (!data) { return {}; }
  const kind = !data.ancestors.length ? CoreConstants.ContentNodeKinds.CHANNEL : data.kind;
  return {
    ancestors: data.ancestors.map(item => ({
      id: item.pk,
      title: item.title
    })),
    contentId: data.content_id,
    kind,
    lastActive: data.last_active,
    numUsers: data.num_users,
    id: data.pk,
    progress: data.progress.map(_progressState),
    title: data.title,
  };
}

function _userSummaryState(data) {
  // console.log('uuuuuu', data);
  if (!data) {
    return {};
  }
  return data;
}

function _showReport(store, options) {
  const classId = options.classId;
  const channelId = options.channelId;
  const contentScope = options.contentScope;
  const contentScopeId = options.contentScopeId;
  const userScope = options.userScope;
  const userScopeId = options.userScopeId;

  /* check if params are semi-valid. */
  function _validate(value, constants) {
    if (!values(constants).includes(value)) {
      throw Error(`Invalid report parameters: ${value} not in ${JSON.stringify(constants)}`);
    }
  }
  _validate(contentScope, ReportConstants.ContentScopes);
  _validate(userScope, ReportConstants.UserScopes);

  // REPORT
  const reportPayload = {
    channel_id: channelId,
    content_node_id: contentScopeId,
    collection_kind: ReportConstants.UserScopes.CLASSROOM,
    collection_id: classId,
  };
  let reportPromise;
  if (reportGetters.isTopicPage) {
    reportPromise = ContentReportResource.getCollection(reportPayload).fetch();
  } else if (reportGetters.isLearnerPage) {
    reportPromise = UserReportResource.getCollection(reportPayload).fetch();
  } else if (reportGetters.isRecentPage) {
    throw Error('recent report is not currently handled in this action');
  }

  // CONTENT SUMMARY
  const contentPromise = ContentSummaryResource.getModel(contentScopeId, reportPayload).fetch();

  // USER SUMMARY
  let userPromise;
  if (userScope === ReportConstants.UserScopes.USER) {
    userPromise = UserSummaryResource.getModel(userScopeId, reportPayload).fetch();
  }

  const promises = [];
  promises.push(reportPromise);
  promises.push(contentPromise);
  promises.push(userPromise);

  // API response handlers
  Promise.all(promises).then(
    ([report, contentSummary, userSummary]) => {
      const pageState = {
        classId,
        channelId,
        contentScope,
        contentScopeId,
        userScope,
        userScopeId,
        tableData: _reportState(report),
        contentScopeSummary: _contentSummaryState(contentSummary),
        userScopeSummary: _userSummaryState(userSummary),
      };
      store.dispatch('SET_PAGE_STATE', pageState);
      store.dispatch('CORE_SET_PAGE_LOADING', false);
    },
    error => coreActions.handleError(store, error)
  );
}

function _showChannelRoot(store, classId, channelId) {
  const channelPromise = ChannelResource.getModel(channelId).fetch();

  channelPromise.then(
    (channelData) => {
      _showReport(store, {
        classId,
        channelId,
        contentScope: ReportConstants.ContentScopes.ROOT,
        contentScopeId: channelData.root_pk,
        userScope: ReportConstants.UserScopes.CLASSROOM,
        userScopeId: classId,
        sortColumn: ReportConstants.TableColumns.NAME,
        sortOrder: ReportConstants.SortOrders.NONE,
      });
    },
    error => coreActions.handleError(store, error)
  );
}

function _showTopic(store, classId, channelId, topicId) {
  _showReport(store, {
    classId,
    channelId,
    contentScope: ReportConstants.ContentScopes.TOPIC,
    contentScopeId: topicId,
    userScope: ReportConstants.UserScopes.CLASSROOM,
    userScopeId: classId,
    sortColumn: ReportConstants.TableColumns.NAME,
    sortOrder: ReportConstants.SortOrders.NONE,
  });
}

// needs exercise, attemptlog. Pass answerstate into contentrender to display answer
function showCoachExerciseRenderPage(store, classId, userId, channelId, contentId) {
  store.dispatch('CORE_SET_PAGE_LOADING', true);
  store.dispatch('SET_PAGE_NAME', Constants.PageNames.EXERCISE_RENDER);

  Promise.all([
    ContentNodeResource.getCollection({ channel_id: channelId }, { content_id: contentId }).fetch(),
    AttemptLogResource.getCollection({ user: userId, content: contentId }).fetch(),
  ]).then(
    ([exercise, attemptLogs]) => {
      attemptLogs.sort(
        (attemptLog1, attemptLog2) =>
          new Date(attemptLog2.end_timestamp) - new Date(attemptLog1.end_timestamp)
      );

      console.log('attemptLogs', attemptLogs);
      console.log('exercise', exercise[0]);
      const pageState = {
        // because this is info returned from a collection
        exercise: exercise[0],
        attemptLogs,
        channelId,
      };
      store.dispatch('SET_PAGE_STATE', pageState);
      store.dispatch('CORE_SET_PAGE_LOADING', false);
      store.dispatch('CORE_SET_TITLE', 'Exercise Detail View');
    },
      error => { coreActions.handleApiError(store, error); }
    );
}

function showRecentChannels(store, classId) {
  store.dispatch('SET_PAGE_NAME', Constants.PageNames.RECENT_CHANNELS);
  store.dispatch('CORE_SET_TITLE', 'Recent - All channels');
  store.dispatch('CORE_SET_PAGE_LOADING', true);
  // console.log('showRecentChannels');
  _showChannelList(store, classId);
}

function showRecentItemsForChannel(store, classId, channelId) {
  store.dispatch('SET_PAGE_NAME', Constants.PageNames.RECENT_ITEMS_FOR_CHANNEL);
  store.dispatch('CORE_SET_TITLE', 'Recent - Items');
  store.dispatch('CORE_SET_PAGE_LOADING', true);
  // console.log('showRecentItemsForChannel');
  const channelPromise = ChannelResource.getModel(channelId).fetch();

  channelPromise.then(
    channelData => {
      const sevenDaysAgo = new Date();
      // this is being set by default in the backend
      // backend date data might be unreliable, though
      sevenDaysAgo.setDate(sevenDaysAgo.getDate() - 7);

      const reportPayload = {
        channel_id: channelId,
        content_node_id: channelData.root_pk,
        collection_kind: ReportConstants.UserScopes.CLASSROOM,
        collection_id: classId,
        last_active_time: sevenDaysAgo,
      };
      const recentReportsPromise = RecentReportResource.getCollection(reportPayload).fetch();

      recentReportsPromise.then(
        reports => {
          const pageState = {
            reports: _reportState(reports),
            classId,
            channelId,
          };
          store.dispatch('SET_PAGE_STATE', pageState);
          store.dispatch('CORE_SET_PAGE_LOADING', false);
          store.dispatch('CORE_SET_ERROR', null);
          store.dispatch('CORE_SET_TITLE', 'Recents');
        },
        error => coreActions.handleApiError(store, error)
      );
    },
    error => coreActions.handleApiError(store, error)
  );
}

function showRecentLearnersForItem(store, classId, channelId, contentId) {
  store.dispatch('SET_PAGE_NAME', Constants.PageNames.RECENT_LEARNERS_FOR_ITEM);
  store.dispatch('CORE_SET_TITLE', 'Recent - Learners');
  store.dispatch('CORE_SET_PAGE_LOADING', true);
  // console.log('showRecentLearnersForItem');
}

function showRecentLearnerItemDetails(store, classId, channelId, contentId, userId) {
  store.dispatch('SET_PAGE_NAME', Constants.PageNames.RECENT_LEARNER_ITEM_DETAILS);
  store.dispatch('CORE_SET_TITLE', 'Recent - Learner Details');
  store.dispatch('CORE_SET_PAGE_LOADING', true);
  // console.log('showRecentLearnerItemDetails');
}

function showTopicChannels(store, classId) {
  store.dispatch('SET_PAGE_NAME', Constants.PageNames.TOPIC_CHANNELS);
  store.dispatch('CORE_SET_TITLE', 'Topics - All channels');
  store.dispatch('CORE_SET_PAGE_LOADING', true);
  // console.log('showTopicChannels');
  _showChannelList(store, classId);
}

function showTopicChannelRoot(store, classId, channelId) {
  store.dispatch('SET_PAGE_NAME', Constants.PageNames.TOPIC_CHANNEL_ROOT);
  store.dispatch('CORE_SET_TITLE', 'Topics - Channel');
  store.dispatch('CORE_SET_PAGE_LOADING', true);
  // console.log('showTopicChannelRoot');
  _showChannelRoot(store, classId, channelId);
}

function showTopicItemList(store, classId, channelId, topicId) {
  store.dispatch('SET_PAGE_NAME', Constants.PageNames.TOPIC_ITEM_LIST);
  store.dispatch('CORE_SET_TITLE', 'Topics - Items');
  store.dispatch('CORE_SET_PAGE_LOADING', true);
  // console.log('showTopicItemList');
  _showTopic(store, classId, channelId, topicId);
}

function showTopicLearnersForItem(store, classId, channelId, contentId) {
  store.dispatch('SET_PAGE_NAME', Constants.PageNames.TOPIC_LEARNERS_FOR_ITEM);
  store.dispatch('CORE_SET_TITLE', 'Topics - Learners');
  store.dispatch('CORE_SET_PAGE_LOADING', true);
  // console.log('showTopicLearnersForItem');
}

function showTopicLearnerItemDetails(store, classId, channelId, contentId, userId) {
  store.dispatch('SET_PAGE_NAME', Constants.PageNames.TOPIC_LEARNER_ITEM_DETAILS);
  store.dispatch('CORE_SET_TITLE', 'Topics - Learner Details');
  store.dispatch('CORE_SET_PAGE_LOADING', true);
  // console.log('showTopicLearnerItemDetails');
}

function showLearnerList(store, classId) {
  store.dispatch('SET_PAGE_NAME', Constants.PageNames.LEARNER_LIST);
  store.dispatch('CORE_SET_TITLE', 'Learners');
  store.dispatch('CORE_SET_PAGE_LOADING', true);
  // console.log('showLearnerList');
}

function showLearnerChannels(store, classId, userId) {
  store.dispatch('SET_PAGE_NAME', Constants.PageNames.LEARNER_CHANNELS);
  store.dispatch('CORE_SET_TITLE', 'Learners - All channels');
  store.dispatch('CORE_SET_PAGE_LOADING', true);
  // console.log('showLearnerChannels');
  _showChannelList(store, classId);
}

function showLearnerChannelRoot(store, classId, userId, channelId) {
  store.dispatch('SET_PAGE_NAME', Constants.PageNames.LEARNER_CHANNEL_ROOT);
  store.dispatch('CORE_SET_TITLE', 'Learners - Channel');
  store.dispatch('CORE_SET_PAGE_LOADING', true);
  // console.log('showLearnerChannelRoot');
}

function showLearnerItemList(store, classId, userId, channelId, topicId) {
  store.dispatch('SET_PAGE_NAME', Constants.PageNames.LEARNER_ITEM_LIST);
  store.dispatch('CORE_SET_TITLE', 'Learners - Items');
  store.dispatch('CORE_SET_PAGE_LOADING', true);
  // console.log('showLearnerItemList');
}

function showLearnerItemDetails(store, classId, userId, channelId, contentId) {
  store.dispatch('SET_PAGE_NAME', Constants.PageNames.LEARNER_ITEM_DETAILS);
  store.dispatch('CORE_SET_TITLE', 'Learners - Item Details');
  store.dispatch('CORE_SET_PAGE_LOADING', true);
  // console.log('showLearnerItemDetails');
}

module.exports = {
  showCoachExerciseRenderPage, // remove this after making it a helper
  showRecentChannels,
  showRecentItemsForChannel,
  showRecentLearnersForItem,
  showRecentLearnerItemDetails,
  showTopicChannels,
  showTopicChannelRoot,
  showTopicItemList,
  showTopicLearnersForItem,
  showTopicLearnerItemDetails,
  showLearnerList,
  showLearnerChannels,
  showLearnerChannelRoot,
  showLearnerItemList,
  showLearnerItemDetails,
};
<|endoftext|>