<commit_before>'use strict';
// #1 define constants and requirements
const express = require('express');
const pg = require('pg');
const tmi = require('tmi.js');
const app = express();
const PORT = process.env.PORT || 31337;

const conString = process.env.DATABASE_URL;
const client = new pg.Client(conString);
client.connect();
client.on('error', err => console.error(err));

app.use(express.static('./public'));
// #2 set up the http requests
app.get('/', function(request, response){
	response.sendFile('public/index.html', {root: '.'});
});

app.listen(PORT, function() {
	console.log(`My server is running on port: ${PORT}`);
});

// #3 create Database
loadDB();

function loadDB() {
	client.query(`
		CREATE TABLE IF NOT EXISTS
		users (
			user_id SERIAL PRIMARY KEY,
			username VARCHAR(255) UNIQUE NOT NULL,
			widget_text VARCHAR(1000) NOT NULL,
			text_color VARCHAR(255) NOT NULL,
			fill_color VARCHAR(255) NOT NULL,
			goal INTEGER NOT NULL
		);`
	)
	.catch(console.error);

  client.query(`
    CREATE TABLE IF NOT EXISTS
    choices (
      choice_id SERIAL PRIMARY KEY,
      user_id INTEGER NOT NULL REFERENCES users(user_id),
      choice_text VARCHAR(255) NOT NULL,
			choice_color VARCHAR(255) NOT NULL,
			value INTEGER
    );`
  )
  .catch(console.error);
}

// #4 populate Database
app.post('/choices', (request, response) => {
	console.log(request);
	console.log(request.body);
  client.query(
    'INSERT INTO users(username, widget_text, text_color, fill_color, goal) VALUES($1, $2, $3, $4, $5) ON CONFLICT DO NOTHING',
    [request.body.username, request.body.widgetText, request.body.textColor, request.body.fillColor, request.body.goal]
  )
  .then(() => {
    client.query(`
      INSERT INTO
      choices(user_id, choice_text, choice_color, value)
      SELECT author_id, $1, $2, $3
      FROM users
      WHERE username=$4;
      `,
      [
        request.body.choiceText,
        request.body.choiceColor,
        request.body.value,
        request.body.username,
      ]
    )
  })
  .then(() => response.send('Insert complete'))
  .catch(console.error);
});

app.delete('/choices/:username', (request, response) => {
  client.query(`
    DELETE FROM choices
    INNER JOIN users
			ON choices.user_id=users.user_id
		WHERE username = $1;`,
    [request.params.username]
  )
  .then(() => response.send('Delete complete'))
  .catch(console.error);
});

// #5 retrieve info from database
app.get('/choices/:username', (request, response) => {
  client.query(`
    SELECT * FROM choices
    INNER JOIN users
      ON choices.user_id=users.user_id
		WHERE username = $1;`,
		[request.params.username]
  )
  .then(result => {
		console.log(result.rows);
		response.send(result.rows);
	})
  .catch(console.error);
});
<commit_msg>Added body parser<commit_after>'use strict';
// #1 define constants and requirements
const express = require('express');
const bodyParser = require('body-parser');
const pg = require('pg');
const tmi = require('tmi.js');
const app = express();
const PORT = process.env.PORT || 31337;

const conString = process.env.DATABASE_URL;
const client = new pg.Client(conString);
client.connect();
client.on('error', err => console.error(err));

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
app.use(express.static('./public'));

// #2 set up the http requests
app.get('/', function(request, response){
	response.sendFile('public/index.html', {root: '.'});
});

app.listen(PORT, function() {
	console.log(`My server is running on port: ${PORT}`);
});

// #3 create Database
loadDB();

function loadDB() {
	client.query(`
		CREATE TABLE IF NOT EXISTS
		users (
			user_id SERIAL PRIMARY KEY,
			username VARCHAR(255) UNIQUE NOT NULL,
			widget_text VARCHAR(1000) NOT NULL,
			text_color VARCHAR(255) NOT NULL,
			fill_color VARCHAR(255) NOT NULL,
			goal INTEGER NOT NULL
		);`
	)
	.catch(console.error);

  client.query(`
    CREATE TABLE IF NOT EXISTS
    choices (
      choice_id SERIAL PRIMARY KEY,
      user_id INTEGER NOT NULL REFERENCES users(user_id),
      choice_text VARCHAR(255) NOT NULL,
			choice_color VARCHAR(255) NOT NULL,
			value INTEGER
    );`
  )
  .catch(console.error);
}

// #4 populate Database
app.post('/choices', (request, response) => {
	console.log(request);
	console.log(request.body);
  client.query(
    'INSERT INTO users(username, widget_text, text_color, fill_color, goal) VALUES($1, $2, $3, $4, $5) ON CONFLICT DO NOTHING',
    [request.body.username, request.body.widgetText, request.body.textColor, request.body.fillColor, request.body.goal]
  )
  .then(() => {
    client.query(`
      INSERT INTO
      choices(user_id, choice_text, choice_color, value)
      SELECT author_id, $1, $2, $3
      FROM users
      WHERE username=$4;
      `,
      [
        request.body.choiceText,
        request.body.choiceColor,
        request.body.value,
        request.body.username,
      ]
    )
  })
  .then(() => response.send('Insert complete'))
  .catch(console.error);
});

app.delete('/choices/:username', (request, response) => {
  client.query(`
    DELETE FROM choices
    INNER JOIN users
			ON choices.user_id=users.user_id
		WHERE username = $1;`,
    [request.params.username]
  )
  .then(() => response.send('Delete complete'))
  .catch(console.error);
});

// #5 retrieve info from database
app.get('/choices/:username', (request, response) => {
  client.query(`
    SELECT * FROM choices
    INNER JOIN users
      ON choices.user_id=users.user_id
		WHERE username = $1;`,
		[request.params.username]
  )
  .then(result => {
		console.log(result.rows);
		response.send(result.rows);
	})
  .catch(console.error);
});
<|endoftext|>


<commit_before>import { addFurniture, ADD_FURNITURE } from '../actions/add.furniture.action';

function addFurniture(state = [], action) {
  switch (action.type) {
    case ADD_FURNITURE:
      return [
        ...state,
        {
          color: action.color,
          name: action.name
        }
      ];
    default:
      return state;
  }
}
<commit_msg>chore (frontend): Delete deprecated furniture.reducer file<commit_after><|endoftext|>


<commit_before>
(function($) {
	function GridManager() {
		var gridElementPrefix = "#grid_",
		gridElementSuffix = " .grid",
		pagerElementSuffix = " .pager",
		filterTriggerElementSuffix = " .grid-header .filter_toggle",
		deleteElementSuffix = ' .grid-header .delete_button',
		createElementSuffix = ' .grid-header .create_button',
		updateElementSuffix = ' .grid-header .batch_update_button'

		grids = [],
		operatedIds = [],
		defaultOptions = {
			editable: true,
			enableAddRow: false,
			enableCellNavigation: true,
			asyncEditorLoading: false,
			autoEdit: false,
			cellFlashingCssClass: "master_flashing",
			rowHeight: 25
		};

		function init() {
		}

		function getEditorForType(type){
			switch(type.toLowerCase()){
				case "string":
				return TextCellEditor;
				case "text":
				return LongTextCellEditor;
				case "datetime":
				return DateTimeCellEditor;
				case "date":
				return StandardDateCellEditor;
				case "integer":
				return IntegerCellEditor;
				case "boolean":
				return YesNoCheckboxCellEditor;
				case "belongs_to":
				return BelongsToEditor;
				case "has_and_belongs_to_many":
				return BelongsToEditor;
				case "has_many":
				return HasManyEditor;
				default:
				return TextCellEditor;
			}
		}

		function appendEditor(columns){
		  var i, type_str;
		  for(i in columns){
		    type_str = columns[i].type.toLowerCase();
				if(columns[i].editable == true) {
				  if (columns[i].editor) {
				    columns[i].editor = eval(columns[i].editor);
  				} else {
  					columns[i].editor = getEditorForType(columns[i].type);
  				}
  				if (columns[i].formatter) {
  					columns[i].formatter = eval(columns[i].formatter);
  				}
					if(type_str == "date") {
						columns[i].formatter = StandardDateCellFormatter;
						columns[i].DateShowFormat = "yy-mm-dd";
					} else if (type_str == "boolean") {
						columns[i].formatter = BoolCellFormatter;
					}
				}
				if(type_str == "belongs_to" || type_str == "has_and_belongs_to_many") {
					columns[i].formatter = BelongsToFormatter;
				}
				if (type_str == "has_many") {
					columns[i].formatter = HasManyFormatter;
				}
				if(type_str == 'has_one' ) {
					columns[i].formatter = HasOneFormatter;
				}
				if(type_str == "boolean") {
					columns[i].cssClass = 'cell-effort-driven';
				}
			}
		}

		function createNewGrid(name, screen, path, columns, states, actions, behaviors, extend_options) {
		  var gridElement, loader, grid, pagerElement, pager, filterTriggerElement, filterPanel,
		  gridAttrs, deleteElement, createButtonElement;
		  options = $.extend(defaultOptions, extend_options);

			gridElement = $(gridElementPrefix + name + gridElementSuffix);

			// Append editor attribute to columns
			appendEditor(columns);

      // Apply current filters
      path = GridStatesManager.applayFilters(path, states["filter"]);

      // Set Loader
			loader = new Slick.Data.RemoteModel(path, columns);

			// restore the order states to columns
      columns = GridStatesManager.restoreOrderStates(columns, states["order"]);
			// restore the visibility states to columns
		  GridStatesManager.restoreVisibilityStates(columns, states["visibility"]);
		  // restore the width states to columns
      GridStatesManager.restoreWidthStates(columns, states["width"]);

      // Set options along with actions
		  if (actions.indexOf('edit') == -1) {
		    options['editable'] = false;
		  } else {
		    options['editable'] = true;
		  }
			// ------------------------- Create Grid ------------------------------------
			grid = new Slick.Grid(gridElement, loader.data, columns, options);
			grid.setSelectionModel(new Slick.RowSelectionModel());

			loader.setGrid(grid);

			// create loading indicator on the activity panel
			loader.setLoadingIndicator(createLoadingIndicator(gridElement));

			// restore the sorting states to grid
      GridStatesManager.restoreSortingStates(grid, loader, states["sort"]);

			// Set Pager
			pagerElement = $(gridElementPrefix + name + pagerElementSuffix);
			pager = new Slick.Controls.Pager(loader, grid, pagerElement);

      // Set Filter
			filterTriggerElement = $(gridElementPrefix + name + filterTriggerElementSuffix);
      filterPanel = new Slick.FilterPanel(grid, loader, filterTriggerElement, states["filter"]);

			// Set ColumnPicker
			var columnpicker = new Slick.Controls.ColumnPicker(columns, grid, options);

			// Set grid body height after rendering
			setGridBodyHeight(gridElement);
			grid.resizeCanvas();

			// Load the first page
			grid.onViewportChanged.notify();

			pathWithoutQuery = path.split(".json")[0];
			query = path.split(".json")[1];
			// Append necessary attributes to the grid
			gridAttrs = {name: name, screen: screen, loader: loader, path: pathWithoutQuery, query: query, pager: pager, filterPanel: filterPanel, actions: actions, extend_options: extend_options};
      for(var attr in gridAttrs) {
        grid[attr] = gridAttrs[attr];
      }

      // dispatch behaviors
			WulinMaster.BehaviorManager.dispatchBehaviors(grid, behaviors);

      // delete old grid if exsisting, then add grid
			for(var i in grids){
				if(grid.name == grids[i].name){
					grids.splice(i, 1);
				}
			}
			grids.push(grid);

			// ------------------------------- register events on the grid ----------------------------------------
			// cell update events
			grid.onCellChange.subscribe(function(e, args){
			  Requests.updateByAjax(this, args.item);
			});

			// when editor validate return false
			grid.onValidationError.subscribe(function(e,args){
			  var rs = args.validationResults;
			  if (rs.msg) {
			    displayErrorMessage(rs.msg);
			  }
			});

			// handle multiple grids: select one,release previou one
      grid.onClick.subscribe(function(e, args){
        $.each(grids, function(){
          if (this.name != grid.name)
            this.setSelectedRows([]);
        });
      });

      // push selected IDs to operatedIds when selected row changed
      grid.onSelectedRowsChanged.subscribe(function(e, args) {
        gridManager.operatedIds = grid.getSelectedIds();
      });

      // highlight the selected rows then empty operatedIds when grid re-rendered
      grid.loader.onDataLoaded.subscribe(function(e, args){
        var data = grid.getData(), selectedIndexes = [];
        for (var i in data) {
          if (data[i] && gridManager.operatedIds.indexOf(data[i].id) != -1) {
            selectedIndexes.push(data[i].slick_index);
          }
        }
        grid.setSelectedRows(selectedIndexes);
        //Empty operatedIds when grid re-rendered
        gridManager.operatedIds = [];
      });

      // Empty the operatedIds when switch grid
      grid.onViewportChanged.subscribe(function(e, args){
        gridManager.operatedIds = [];
      });

			// ------------------------------ register callbacks for handling grid states ------------------------
      if(states)
        GridStatesManager.onStateEvents(grid);

			// ------------------------------ button events -----------------------------------------

			// Delete along delete button
			deleteElement = $(gridElementPrefix + name + deleteElementSuffix);
			deleteElement.on('click', function() {
				var ids = Ui.selectIds(grid);
				if (ids) {
				  Ui.deleteGrids(ids);
  			  return false;
				} else {
				  displayErrorMessage("Please select a record.");
				}
			});

			// Create action
			createButtonElement = $(gridElementPrefix + name + createElementSuffix);
			createButtonElement.on('click', function() {
				Ui.openDialog(name, grid.extend_options);
			});
			// Click 'Create' button
			$('#' + name + '_submit').on('click', function() {
				Requests.createByAjax(grid, false);
			  return false;
			});
			// Click 'Create and Continue' button
			$('#' + name + '_submit_continue').on('click', function() {
				Requests.createByAjax(grid, true);
			  return false;
			});

			// Batch update action
			updateButtonElement = $(gridElementPrefix + name + updateElementSuffix);
			updateButtonElement.on('click', function(){
			  Requests.batchUpdateByAjax(grid, true);
			  return false;
			});

		} // createNewGrid

		function createLoadingIndicator(gridElement) {
			var truncateThreshold = 35,
			parent = gridElement.parent(".grid_container"),
			id = parent.attr("id"),
			title = $.trim(parent.find(".grid-header h2").text()),

			indicators = $("#activity #indicators"),
			indicator;

			if (title.length > truncateThreshold) {
				title = title.substring(0, truncateThreshold-2) + "..."
			}

			// Remove init indicator if it exists.
			indicators.find("#init_menu_indicator").remove();
			indicator = indicators.find(".loading_indicator#" + id);

			if (indicator.length == 0) {
				indicator = $(buildIndicatorHtml(id, title, "")).appendTo(indicators);
				// Init counter
				indicator.data("requestCount", 0);
			}

			return indicator;
		}

		function buildIndicatorHtml(id, title){
			return "

"+ title +"

"
		}

		function getGrid(name) {
			var theGrid = null;

			$.each(grids, function() {
				if (this.name == name)
				theGrid = this;
			});

			return theGrid;
		}

		function setGridBodyHeight(gridElement) {
		  var container = gridElement.parent(".grid_container"),
		  ch = container.height(),
		  hh = container.find(".grid-header").height(),
		  ph = container.find(".pager").height(),
	    gh = ch - hh - ph;

	    gridElement.css("height", gh - 1);
		}

		function resizeGrids() {
		  var gridElement;
			$.each(grids, function() {
			  gridElement = $(gridElementPrefix + this.name + gridElementSuffix);
			  setGridBodyHeight(gridElement);
				this.resizeCanvas();
			});
		}

		init();

		return {
			// properties
			"grids": grids,
			'operatedIds': operatedIds,

			// methods
			"createNewGrid": createNewGrid,
			"getGrid": getGrid,
			"resizeGrids": resizeGrids,
			"buildIndicatorHtml": buildIndicatorHtml
		};
	}

	$.extend(true, window, { GridManager: GridManager});
	})(jQuery);

	var gridManager = new GridManager();

	$(window).resize(function() { gridManager.resizeGrids(); });
	<commit_msg>BUG - fixed the row selection highlight bug again<commit_after>
(function($) {
	function GridManager() {
		var gridElementPrefix = "#grid_",
		gridElementSuffix = " .grid",
		pagerElementSuffix = " .pager",
		filterTriggerElementSuffix = " .grid-header .filter_toggle",
		deleteElementSuffix = ' .grid-header .delete_button',
		createElementSuffix = ' .grid-header .create_button',
		updateElementSuffix = ' .grid-header .batch_update_button'

		grids = [],
		operatedIds = [],
		defaultOptions = {
			editable: true,
			enableAddRow: false,
			enableCellNavigation: true,
			asyncEditorLoading: false,
			autoEdit: false,
			cellFlashingCssClass: "master_flashing",
			rowHeight: 25
		};

		function init() {
		}

		function getEditorForType(type){
			switch(type.toLowerCase()){
				case "string":
				return TextCellEditor;
				case "text":
				return LongTextCellEditor;
				case "datetime":
				return DateTimeCellEditor;
				case "date":
				return StandardDateCellEditor;
				case "integer":
				return IntegerCellEditor;
				case "boolean":
				return YesNoCheckboxCellEditor;
				case "belongs_to":
				return BelongsToEditor;
				case "has_and_belongs_to_many":
				return BelongsToEditor;
				case "has_many":
				return HasManyEditor;
				default:
				return TextCellEditor;
			}
		}

		function appendEditor(columns){
		  var i, type_str;
		  for(i in columns){
		    type_str = columns[i].type.toLowerCase();
				if(columns[i].editable == true) {
				  if (columns[i].editor) {
				    columns[i].editor = eval(columns[i].editor);
  				} else {
  					columns[i].editor = getEditorForType(columns[i].type);
  				}
  				if (columns[i].formatter) {
  					columns[i].formatter = eval(columns[i].formatter);
  				}
					if(type_str == "date") {
						columns[i].formatter = StandardDateCellFormatter;
						columns[i].DateShowFormat = "yy-mm-dd";
					} else if (type_str == "boolean") {
						columns[i].formatter = BoolCellFormatter;
					}
				}
				if(type_str == "belongs_to" || type_str == "has_and_belongs_to_many") {
					columns[i].formatter = BelongsToFormatter;
				}
				if (type_str == "has_many") {
					columns[i].formatter = HasManyFormatter;
				}
				if(type_str == 'has_one' ) {
					columns[i].formatter = HasOneFormatter;
				}
				if(type_str == "boolean") {
					columns[i].cssClass = 'cell-effort-driven';
				}
			}
		}

		function createNewGrid(name, screen, path, columns, states, actions, behaviors, extend_options) {
		  var gridElement, loader, grid, pagerElement, pager, filterTriggerElement, filterPanel,
		  gridAttrs, deleteElement, createButtonElement;
		  options = $.extend(defaultOptions, extend_options);

			gridElement = $(gridElementPrefix + name + gridElementSuffix);

			// Append editor attribute to columns
			appendEditor(columns);

      // Apply current filters
      path = GridStatesManager.applayFilters(path, states["filter"]);

      // Set Loader
			loader = new Slick.Data.RemoteModel(path, columns);

			// restore the order states to columns
      columns = GridStatesManager.restoreOrderStates(columns, states["order"]);
			// restore the visibility states to columns
		  GridStatesManager.restoreVisibilityStates(columns, states["visibility"]);
		  // restore the width states to columns
      GridStatesManager.restoreWidthStates(columns, states["width"]);

      // Set options along with actions
		  if (actions.indexOf('edit') == -1) {
		    options['editable'] = false;
		  } else {
		    options['editable'] = true;
		  }
			// ------------------------- Create Grid ------------------------------------
			grid = new Slick.Grid(gridElement, loader.data, columns, options);
			grid.setSelectionModel(new Slick.RowSelectionModel());

			loader.setGrid(grid);

			// create loading indicator on the activity panel
			loader.setLoadingIndicator(createLoadingIndicator(gridElement));

			// restore the sorting states to grid
      GridStatesManager.restoreSortingStates(grid, loader, states["sort"]);

			// Set Pager
			pagerElement = $(gridElementPrefix + name + pagerElementSuffix);
			pager = new Slick.Controls.Pager(loader, grid, pagerElement);

      // Set Filter
			filterTriggerElement = $(gridElementPrefix + name + filterTriggerElementSuffix);
      filterPanel = new Slick.FilterPanel(grid, loader, filterTriggerElement, states["filter"]);

			// Set ColumnPicker
			var columnpicker = new Slick.Controls.ColumnPicker(columns, grid, options);

			// Set grid body height after rendering
			setGridBodyHeight(gridElement);
			grid.resizeCanvas();

			// Load the first page
			grid.onViewportChanged.notify();

			pathWithoutQuery = path.split(".json")[0];
			query = path.split(".json")[1];
			// Append necessary attributes to the grid
			gridAttrs = {name: name, screen: screen, loader: loader, path: pathWithoutQuery, query: query, pager: pager, filterPanel: filterPanel, actions: actions, extend_options: extend_options};
      for(var attr in gridAttrs) {
        grid[attr] = gridAttrs[attr];
      }

      // dispatch behaviors
			WulinMaster.BehaviorManager.dispatchBehaviors(grid, behaviors);

      // delete old grid if exsisting, then add grid
			for(var i in grids){
				if(grid.name == grids[i].name){
					grids.splice(i, 1);
				}
			}
			grids.push(grid);

			// ------------------------------- register events on the grid ----------------------------------------
			// cell update events
			grid.onCellChange.subscribe(function(e, args){
			  Requests.updateByAjax(this, args.item);
			});

			// when editor validate return false
			grid.onValidationError.subscribe(function(e,args){
			  var rs = args.validationResults;
			  if (rs.msg) {
			    displayErrorMessage(rs.msg);
			  }
			});

			// handle multiple grids: select one,release previou one
      grid.onClick.subscribe(function(e, args){
        $.each(grids, function(){
          if (this.name != grid.name)
            this.setSelectedRows([]);
        });
      });

      // push selected IDs to operatedIds when selected row changed
      grid.onSelectedRowsChanged.subscribe(function(e, args) {
        gridManager.operatedIds = grid.getSelectedIds();
      });

      // highlight the selected rows
      grid.loader.onDataLoaded.subscribe(function(e, args){
        var data = grid.getData(), selectedIndexes = [];
        for (var i in data) {
          if (data[i] && gridManager.operatedIds.indexOf(data[i].id) != -1) {
            selectedIndexes.push(data[i].slick_index);
          }
        }
        // highlight selected rows, at this moment, the onSelectedRowsChanged event will be triggered so don't need to handly assign gridManager.operatedIds
        grid.setSelectedRows(selectedIndexes);
      });

      // Empty the operatedIds when switch grid
      grid.onViewportChanged.subscribe(function(e, args){
        gridManager.operatedIds = [];
      });

			// ------------------------------ register callbacks for handling grid states ------------------------
      if(states)
        GridStatesManager.onStateEvents(grid);

			// ------------------------------ button events -----------------------------------------

			// Delete along delete button
			deleteElement = $(gridElementPrefix + name + deleteElementSuffix);
			deleteElement.on('click', function() {
				var ids = Ui.selectIds(grid);
				if (ids) {
				  Ui.deleteGrids(ids);
  			  return false;
				} else {
				  displayErrorMessage("Please select a record.");
				}
			});

			// Create action
			createButtonElement = $(gridElementPrefix + name + createElementSuffix);
			createButtonElement.on('click', function() {
				Ui.openDialog(name, grid.extend_options);
			});
			// Click 'Create' button
			$('#' + name + '_submit').on('click', function() {
				Requests.createByAjax(grid, false);
			  return false;
			});
			// Click 'Create and Continue' button
			$('#' + name + '_submit_continue').on('click', function() {
				Requests.createByAjax(grid, true);
			  return false;
			});

			// Batch update action
			updateButtonElement = $(gridElementPrefix + name + updateElementSuffix);
			updateButtonElement.on('click', function(){
			  Requests.batchUpdateByAjax(grid, true);
			  return false;
			});

		} // createNewGrid

		function createLoadingIndicator(gridElement) {
			var truncateThreshold = 35,
			parent = gridElement.parent(".grid_container"),
			id = parent.attr("id"),
			title = $.trim(parent.find(".grid-header h2").text()),

			indicators = $("#activity #indicators"),
			indicator;

			if (title.length > truncateThreshold) {
				title = title.substring(0, truncateThreshold-2) + "..."
			}

			// Remove init indicator if it exists.
			indicators.find("#init_menu_indicator").remove();
			indicator = indicators.find(".loading_indicator#" + id);

			if (indicator.length == 0) {
				indicator = $(buildIndicatorHtml(id, title, "")).appendTo(indicators);
				// Init counter
				indicator.data("requestCount", 0);
			}

			return indicator;
		}

		function buildIndicatorHtml(id, title){
			return "

"+ title +"

"
		}

		function getGrid(name) {
			var theGrid = null;

			$.each(grids, function() {
				if (this.name == name)
				theGrid = this;
			});

			return theGrid;
		}

		function setGridBodyHeight(gridElement) {
		  var container = gridElement.parent(".grid_container"),
		  ch = container.height(),
		  hh = container.find(".grid-header").height(),
		  ph = container.find(".pager").height(),
	    gh = ch - hh - ph;

	    gridElement.css("height", gh - 1);
		}

		function resizeGrids() {
		  var gridElement;
			$.each(grids, function() {
			  gridElement = $(gridElementPrefix + this.name + gridElementSuffix);
			  setGridBodyHeight(gridElement);
				this.resizeCanvas();
			});
		}

		init();

		return {
			// properties
			"grids": grids,
			'operatedIds': operatedIds,

			// methods
			"createNewGrid": createNewGrid,
			"getGrid": getGrid,
			"resizeGrids": resizeGrids,
			"buildIndicatorHtml": buildIndicatorHtml
		};
	}

	$.extend(true, window, { GridManager: GridManager});
	})(jQuery);

	var gridManager = new GridManager();

	$(window).resize(function() { gridManager.resizeGrids(); });
	<|endoftext|>


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

foam.CLASS({
  package: 'foam.u2.stack',
  name: 'Stack',
  properties: [
    {
      name: 'stack_',
      hidden: true,
      factory: function() { return []; }
    },
    {
      class: 'Int',
      name: 'depth',
      value: 0
    },
    {
      class: 'Int',
      name: 'pos',
      value: -1,
      preSet: function(_, p) {
        if ( isNaN(p) || p > this.depth ) return this.depth - 1;
        if ( p < 0 ) return 0;
        return p;
      }
    },
    {
      class: 'foam.u2.ViewSpec',
      name: 'top',
      hidden: true,
      expression: function(pos) {
        return this.stack_[pos];
      }
    }
  ],
  methods: [
    function slotAt(i) {
      return this.StackSlot.create({
        pos: i,
        stack: this
      });
    },
    function at(i) {
      return i < 0 ? this.stack_[this.pos + i + 1] : this.stack_[i];
    },
    function push(v) {
      var pos = this.pos + 1;

      this.depth = pos + 1;
      this.stack_.length = this.depth;
      this.stack_[pos] = v;
      this.pos = pos;
    }
  ],
  actions: [
    {
      name: 'back',
      isEnabled: function(pos) { return pos > 0; },
      code: function() {
        this.pos--;
      }
    },
    {
      name: 'forward',
      isEnabled: function(pos, depth) { return pos < depth - 1; },
      code: function() {
        this.pos++;
      }
    }
  ],
  classes: [
    {
      name: 'StackSlot',
      implements: [ 'foam.core.Slot' ],
      properties: [
        {
          name: 'stack'
        },
        {
          class: 'Int',
          name: 'pos'
        }
      ],
      methods: [
        function init() {
          this.onDestroy(this.stack.pos$.sub(this.onStackChange));
        },
        function get() {
          return this.stack.at(this.pos);
        },
        function set() {
          // unimplemnted.
        },
        function sub(l) {
          return this.SUPER('update', l);
        },
        function unsub(l) {
          return this.SUPER('update', l);
        },
        function toString() {
          return 'StackSlot(' + this.pos + ')';
        }
      ],
      listeners: [
        function onStackChange(s) {
          if ( this.pos < 0 ||
              this.pos === this.stack.pos ) {
            this.pub('update');
          }
        }
      ]
    }
  ]
});
<commit_msg>Remove StackSlot.unsub() method.<commit_after>/**
 * @license
 * Copyright 2016 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

foam.CLASS({
  package: 'foam.u2.stack',
  name: 'Stack',
  properties: [
    {
      name: 'stack_',
      hidden: true,
      factory: function() { return []; }
    },
    {
      class: 'Int',
      name: 'depth',
      value: 0
    },
    {
      class: 'Int',
      name: 'pos',
      value: -1,
      preSet: function(_, p) {
        if ( isNaN(p) || p > this.depth ) return this.depth - 1;
        if ( p < 0 ) return 0;
        return p;
      }
    },
    {
      class: 'foam.u2.ViewSpec',
      name: 'top',
      hidden: true,
      expression: function(pos) {
        return this.stack_[pos];
      }
    }
  ],
  methods: [
    function slotAt(i) {
      return this.StackSlot.create({
        pos: i,
        stack: this
      });
    },
    function at(i) {
      return i < 0 ? this.stack_[this.pos + i + 1] : this.stack_[i];
    },
    function push(v) {
      var pos = this.pos + 1;

      this.depth = pos + 1;
      this.stack_.length = this.depth;
      this.stack_[pos] = v;
      this.pos = pos;
    }
  ],
  actions: [
    {
      name: 'back',
      isEnabled: function(pos) { return pos > 0; },
      code: function() {
        this.pos--;
      }
    },
    {
      name: 'forward',
      isEnabled: function(pos, depth) { return pos < depth - 1; },
      code: function() {
        this.pos++;
      }
    }
  ],
  classes: [
    {
      name: 'StackSlot',
      implements: [ 'foam.core.Slot' ],
      properties: [
        {
          name: 'stack'
        },
        {
          class: 'Int',
          name: 'pos'
        }
      ],
      methods: [
        function init() {
          this.onDestroy(this.stack.pos$.sub(this.onStackChange));
        },
        function get() {
          return this.stack.at(this.pos);
        },
        function set() {
          // unimplemnted.
        },
        function sub(l) {
          return this.SUPER('update', l);
        },
        function toString() {
          return 'StackSlot(' + this.pos + ')';
        }
      ],
      listeners: [
        function onStackChange(s) {
          if ( this.pos < 0 ||
              this.pos === this.stack.pos ) {
            this.pub('update');
          }
        }
      ]
    }
  ]
});
<|endoftext|>


<commit_before>import {assert} from 'chai';

import {jsdom} from 'jsdom';

import {Transformime} from '../src/transformime';
import {DefaultRenderer} from '../src/defaultrenderer';

/**
 * Dummy Renderer for spying on
 */
class DummyRenderer{
    constructor(mimetype) {
        this._mimetype = mimetype;
    }

    get mimetype() {
        return this._mimetype;
    }

    set mimetype(mimetype) {
       this._mimetype = mimetype;
    }

    transform(data, doc) {
        let pre = doc.createElement('pre');

        this.lastData = data;
        this.lastDoc = doc;
        pre.textContent = data;
        return pre;
    }
}

describe('Transformime defaults', function() {
    before(function() {
        this.document = jsdom();
    });
    describe('default constructor', function() {
        before(function(){
            this.t = new Transformime();
        });
        it('should have default renderers', function() {
            assert(Array.isArray(this.t.renderers));
        });
        it('should have the DefaultRenderer as the fallbackRenderer', function() {
            assert(this.t.fallbackRenderer instanceof DefaultRenderer);
        });
    });
});

describe('Transformime', function() {
    beforeEach(function() {
        this.dummyRenderer1 = new DummyRenderer("transformime/dummy1");
        this.dummyRenderer2 = new DummyRenderer("transformime/dummy2");
        this.dummyRenderer3 = new DummyRenderer("transformime/dummy3");
        this.renderers = [
            this.dummyRenderer1,
            this.dummyRenderer2,
            this.dummyRenderer3
        ];
        this.t = new Transformime(this.renderers);
        this.document = jsdom();
    });
    describe('transform', function() {
        it('should have called our DummyRender', function() {
            var elPromise = this.t.transform("dummy-data", "transformime/dummy1", this.document);

            return elPromise.then((el) => {
                assert.equal(this.dummyRenderer1.lastData, "dummy-data");
                assert.equal(this.dummyRenderer1.lastDoc, this.document);

                // el should be an HTMLElement, which only exists in jsdom or on a
                // real document.
                assert(el instanceof this.document.defaultView.HTMLElement);
            });

        });
        it('should fail when the mimetype is not known', function() {
            let elPromise = this.t.transform("my-data", "transformime/unknown", this.doc);

            return elPromise.catch((err) => {
                assert.equal(err, 'Renderer for mimetype transformime/unknown not found.');
            });
        });
    });
    describe('getRenderer', function() {
        it('should get the right renderer for a given mimetype', function() {
            let renderer = this.t.getRenderer('transformime/dummy1');
            assert.equal(this.dummyRenderer1, renderer);
        });
        it('should return null with an unknown mimetype', function() {
            assert.isNull(this.t.getRenderer('cats/calico'), 'found a renderer when I shouldn\'t have');
        });
    });
    describe('transformRichest', function() {
        describe('should only render the "richest" of the renderers', function() {
            it('when called with all mimetypes in the mimebundle, only return lastmost', function() {
                let mimeBundle = {
                    'transformime/dummy1': 'dummy data 1',
                    'transformime/dummy2': 'dummy data 2',
                    'transformime/dummy3': 'dummy data 3'
                };

                var elPromise = this.t.transformRichest(mimeBundle, this.document);
                return elPromise.then( () => {
                    assert.isUndefined(this.dummyRenderer1.lastData);
                    assert.isUndefined(this.dummyRenderer2.lastData);
                    assert.equal(this.dummyRenderer3.lastData, "dummy data 3");
                });

            });
            it('when called with a lesser mimebundle, choose most rich', function() {
                let mimeBundle = {
                    'transformime/dummy1': 'dummy data 1',
                    'transformime/dummy2': 'dummy data 2'
                };

                let elPromise = this.t.transformRichest(mimeBundle, this.document);
                return elPromise.then( () => {
                    assert.isUndefined(this.dummyRenderer1.lastData);
                    assert.equal(this.dummyRenderer2.lastData, "dummy data 2");
                    assert.isUndefined(this.dummyRenderer3.lastData);
                });
            });
            it('when called with mimetypes it doesn\'t know, it uses supported mimetypes', function() {
                let mimeBundle = {
                    'video/quicktime': 'cat vid',
                    'transformime/dummy1': 'dummy data 1',
                    'application/x-shockwave-flash': 'flashy',
                    'application/msword': 'DOC',
                    'application/zip': 'zippy'
                };

                let elPromise = this.t.transformRichest(mimeBundle, this.document);
                return elPromise.then( () => {
                    assert.equal(this.dummyRenderer1.lastData, "dummy data 1");
                    assert.isUndefined(this.dummyRenderer2.lastData);
                    assert.isUndefined(this.dummyRenderer3.lastData);
                });
            });
            it('when called with no supported mimetypes, it uses the fallbackRenderer', function(){
                let mimeBundle = {
                    'video/quicktime': 'cat vid',
                    'application/zip': 'zippy'
                };

                this.t.fallbackRenderer = new DummyRenderer("fallback/test");
                let elPromise = this.t.transformRichest(mimeBundle, this.document);

                return elPromise.then( () => {
                    assert.equal(this.t.fallbackRenderer.lastData, 'omg this is going to fail');
                });
            });
        });
    });
});
<commit_msg>Skip the fallback rendering case.<commit_after>import {assert} from 'chai';

import {jsdom} from 'jsdom';

import {Transformime} from '../src/transformime';
import {DefaultRenderer} from '../src/defaultrenderer';

/**
 * Dummy Renderer for spying on
 */
class DummyRenderer{
    constructor(mimetype) {
        this._mimetype = mimetype;
    }

    get mimetype() {
        return this._mimetype;
    }

    set mimetype(mimetype) {
       this._mimetype = mimetype;
    }

    transform(data, doc) {
        let pre = doc.createElement('pre');

        this.lastData = data;
        this.lastDoc = doc;
        pre.textContent = data;
        return pre;
    }
}

describe('Transformime defaults', function() {
    before(function() {
        this.document = jsdom();
    });
    describe('default constructor', function() {
        before(function(){
            this.t = new Transformime();
        });
        it('should have default renderers', function() {
            assert(Array.isArray(this.t.renderers));
        });
        it('should have the DefaultRenderer as the fallbackRenderer', function() {
            assert(this.t.fallbackRenderer instanceof DefaultRenderer);
        });
    });
});

describe('Transformime', function() {
    beforeEach(function() {
        this.dummyRenderer1 = new DummyRenderer("transformime/dummy1");
        this.dummyRenderer2 = new DummyRenderer("transformime/dummy2");
        this.dummyRenderer3 = new DummyRenderer("transformime/dummy3");
        this.renderers = [
            this.dummyRenderer1,
            this.dummyRenderer2,
            this.dummyRenderer3
        ];
        this.t = new Transformime(this.renderers);
        this.document = jsdom();
    });
    describe('transform', function() {
        it('should have called our DummyRender', function() {
            var elPromise = this.t.transform("dummy-data", "transformime/dummy1", this.document);

            return elPromise.then((el) => {
                assert.equal(this.dummyRenderer1.lastData, "dummy-data");
                assert.equal(this.dummyRenderer1.lastDoc, this.document);

                // el should be an HTMLElement, which only exists in jsdom or on a
                // real document.
                assert(el instanceof this.document.defaultView.HTMLElement);
            });

        });
        it('should fail when the mimetype is not known', function() {
            let elPromise = this.t.transform("my-data", "transformime/unknown", this.doc);

            return elPromise.catch((err) => {
                assert.equal(err.message, 'Renderer for mimetype transformime/unknown not found.');
            });
        });
    });
    describe('getRenderer', function() {
        it('should get the right renderer for a given mimetype', function() {
            let renderer = this.t.getRenderer('transformime/dummy1');
            assert.equal(this.dummyRenderer1, renderer);
        });
        it('should return null with an unknown mimetype', function() {
            assert.isNull(this.t.getRenderer('cats/calico'), 'found a renderer when I shouldn\'t have');
        });
    });
    describe('transformRichest', function() {
        describe('should only render the "richest" of the renderers', function() {
            it('when called with all mimetypes in the mimebundle, only return lastmost', function() {
                let mimeBundle = {
                    'transformime/dummy1': 'dummy data 1',
                    'transformime/dummy2': 'dummy data 2',
                    'transformime/dummy3': 'dummy data 3'
                };

                var elPromise = this.t.transformRichest(mimeBundle, this.document);
                return elPromise.then( () => {
                    assert.isUndefined(this.dummyRenderer1.lastData);
                    assert.isUndefined(this.dummyRenderer2.lastData);
                    assert.equal(this.dummyRenderer3.lastData, "dummy data 3");
                });

            });
            it('when called with a lesser mimebundle, choose most rich', function() {
                let mimeBundle = {
                    'transformime/dummy1': 'dummy data 1',
                    'transformime/dummy2': 'dummy data 2'
                };

                let elPromise = this.t.transformRichest(mimeBundle, this.document);
                return elPromise.then( () => {
                    assert.isUndefined(this.dummyRenderer1.lastData);
                    assert.equal(this.dummyRenderer2.lastData, "dummy data 2");
                    assert.isUndefined(this.dummyRenderer3.lastData);
                });
            });
            it('when called with mimetypes it doesn\'t know, it uses supported mimetypes', function() {
                let mimeBundle = {
                    'video/quicktime': 'cat vid',
                    'transformime/dummy1': 'dummy data 1',
                    'application/x-shockwave-flash': 'flashy',
                    'application/msword': 'DOC',
                    'application/zip': 'zippy'
                };

                let elPromise = this.t.transformRichest(mimeBundle, this.document);
                return elPromise.then( () => {
                    assert.equal(this.dummyRenderer1.lastData, "dummy data 1");
                    assert.isUndefined(this.dummyRenderer2.lastData);
                    assert.isUndefined(this.dummyRenderer3.lastData);
                });
            });
            it.skip('when called with no supported mimetypes, it uses the fallbackRenderer', function(){
                let mimeBundle = {
                    'video/quicktime': 'cat vid',
                    'application/zip': 'zippy'
                };

                this.t.fallbackRenderer = new DummyRenderer("fallback/test");
                //TODO: Fix/determine the fallbackRenderer case

                let elPromise = this.t.transformRichest(mimeBundle, this.document);
                return elPromise.then( () => {
                    assert.equal(this.t.fallbackRenderer.lastData, '');
                });
            });
        });
    });
});
<|endoftext|>


<commit_before>var child_process = require('child_process')
var fs = require('fs');
var max_sleep = 300
var step = 10
//Added a comment that achieves no real goal.
//Non-blocking loop
//Adjustable step
//Status line
//Add a rough time indicator
//First cut at libfaketime support

var commit_messages = [
  "Fixing an important issue with the universe.",
  "Someone poisoned the waterhole!",
  "You feeling lucky punk?",
  "Five bullets or six?",
  "Fixed memory parsing error #1337",
  "Cleaned out the intertubes",
  "AAAAAAAAAAARGH!",
  "Fixed a typo",
  "Updated the readme",
  "Fixing a typo added in the last readme update",
  "GET A HAIRCUT!",
  "Updated the readme again",
  "Found an issue with the letter 'a', so I fixed it.",
  "Incompatible dimensions found, Cthuhlu Error 666",
  "Who you calling a fool?",
  "How many more of these can I make?",
  "Fixing an error introduced in the last commit",
  "Re-updating the readme.",
  "Work in Progress",
  "WIP",
  "Quick fix",
  "Grammar fix",
  "Fixing punctuation",
  "Correcting style",
  "Logic error",
  "Almost there",
  "Nearly got it",
  "Not quite working",
  "Ooops!",
  "Did I do that?",
  "Commit all the required changes",
  "Really commit all the required changes",
  "Should work now",
  "Back out the last commit",
  "Reverting changes",
  "One more time...",
  "Re-commiting last",
  "One more User Story done",
  "Can work my way through the Kanban",
  "Sprint complete",
  "Well that seemed pretty easy",
  "What do you mean you can't pack up the commit?",
  "Merge in master",
  "Fast-forwarding changes"
]

if ( process.argv[ 2 ] && process.argv[ 3 ] ) {
  var inFile = process.argv[ 2 ]
  var outFile = process.argv[ 3 ]
  if (inFile == outFile) {
    console.error("Aborted: infile and outfile must be different")
    return(-1);
  }
  if (process.argv [ 4 ]) max_sleep = process.argv [ 4 ]
  if (process.argv [ 5 ]) step = parseInt(process.argv [ 5 ])
  console.info("Writing from %s to %s, with up to %s seconds between commits of %s bytes", inFile, outFile, max_sleep, step)
  var outFD = fs.openSync(outFile, 'w')
  fs.readFile(inFile, function(err,data) {
    var length = data.length
    var commit_count = Math.ceil(length / step)
    var commit_time = commit_count * max_sleep / 2
    var commit_time_hour = Math.floor(commit_time / 3600)
    var commit_time_rem = commit_time - (commit_time_hour * 3600)
    var commit_time_min = Math.floor(commit_time_rem / 60)
    var commit_time_sec = commit_time_rem - (commit_time_min * 60)
    console.info("Input file is %s Bytes, this will generate %s commits and take approximately %s hours %s minutes %s seconds", length, commit_count, commit_time_hour, commit_time_min, commit_time_sec)
    var t_offset = 0
    if (process.env.FAKETIME) {
      // 20% buffer, to reduce the likelihood of going in to the future
      t_offset = commit_time * -1.2;
      faketime(t_offset);
    }
    try {
      child_process.execFileSync('git', ['add', outFile])
    } catch (e) {
      console.error("Couldn't add %s to git: %s", outFile, e)
    }
    var counter = 0
    process.stdout.write("Queueing up the first commit...\r");
    var timeout;
    if (p<commit_msg>Should work now<commit_after>var child_process = require('child_process')
var fs = require('fs');
var max_sleep = 300
var step = 10
//Added a comment that achieves no real goal.
//Non-blocking loop
//Adjustable step
//Status line
//Add a rough time indicator
//First cut at libfaketime support

var commit_messages = [
  "Fixing an important issue with the universe.",
  "Someone poisoned the waterhole!",
  "You feeling lucky punk?",
  "Five bullets or six?",
  "Fixed memory parsing error #1337",
  "Cleaned out the intertubes",
  "AAAAAAAAAAARGH!",
  "Fixed a typo",
  "Updated the readme",
  "Fixing a typo added in the last readme update",
  "GET A HAIRCUT!",
  "Updated the readme again",
  "Found an issue with the letter 'a', so I fixed it.",
  "Incompatible dimensions found, Cthuhlu Error 666",
  "Who you calling a fool?",
  "How many more of these can I make?",
  "Fixing an error introduced in the last commit",
  "Re-updating the readme.",
  "Work in Progress",
  "WIP",
  "Quick fix",
  "Grammar fix",
  "Fixing punctuation",
  "Correcting style",
  "Logic error",
  "Almost there",
  "Nearly got it",
  "Not quite working",
  "Ooops!",
  "Did I do that?",
  "Commit all the required changes",
  "Really commit all the required changes",
  "Should work now",
  "Back out the last commit",
  "Reverting changes",
  "One more time...",
  "Re-commiting last",
  "One more User Story done",
  "Can work my way through the Kanban",
  "Sprint complete",
  "Well that seemed pretty easy",
  "What do you mean you can't pack up the commit?",
  "Merge in master",
  "Fast-forwarding changes"
]

if ( process.argv[ 2 ] && process.argv[ 3 ] ) {
  var inFile = process.argv[ 2 ]
  var outFile = process.argv[ 3 ]
  if (inFile == outFile) {
    console.error("Aborted: infile and outfile must be different")
    return(-1);
  }
  if (process.argv [ 4 ]) max_sleep = process.argv [ 4 ]
  if (process.argv [ 5 ]) step = parseInt(process.argv [ 5 ])
  console.info("Writing from %s to %s, with up to %s seconds between commits of %s bytes", inFile, outFile, max_sleep, step)
  var outFD = fs.openSync(outFile, 'w')
  fs.readFile(inFile, function(err,data) {
    var length = data.length
    var commit_count = Math.ceil(length / step)
    var commit_time = commit_count * max_sleep / 2
    var commit_time_hour = Math.floor(commit_time / 3600)
    var commit_time_rem = commit_time - (commit_time_hour * 3600)
    var commit_time_min = Math.floor(commit_time_rem / 60)
    var commit_time_sec = commit_time_rem - (commit_time_min * 60)
    console.info("Input file is %s Bytes, this will generate %s commits and take approximately %s hours %s minutes %s seconds", length, commit_count, commit_time_hour, commit_time_min, commit_time_sec)
    var t_offset = 0
    if (process.env.FAKETIME) {
      // 20% buffer, to reduce the likelihood of going in to the future
      t_offset = commit_time * -1.2;
      faketime(t_offset);
    }
    try {
      child_process.execFileSync('git', ['add', outFile])
    } catch (e) {
      console.error("Couldn't add %s to git: %s", outFile, e)
    }
    var counter = 0
    process.stdout.write("Queueing up the first commit...\r");
    var timeout;
    if (pr<|endoftext|>


<commit_before>import React, { Component, Fragment } from 'react'
import PropTypes from 'prop-types'
import LoadMoreButton from 'components/Buttons/LoadMoreButton'
import Loading from 'components/Loading'
import VideoThumbImage from 'components/VideoThumbImage'
import { Color } from 'constants/css'
import { cleanString, queryStringForArray } from 'helpers/stringHelpers'
import { Link } from 'react-router-dom'
import request from 'axios'
import { URL } from 'constants/URL'
import NotFound from 'components/NotFound'

const API_URL = `${URL}/playlist`

export default class Playlist extends Component {
  static propTypes = {
    onLoad: PropTypes.func,
    playlistId: PropTypes.number.isRequired
  }

  state = {
    videos: [],
    loadMoreButtonShown: false,
    loading: false,
    loaded: false
  }

  async componentDidMount() {
    const { playlistId, onLoad } = this.props
    try {
      const {
        data: { videos, title }
      } = await request.get(`${API_URL}/playlist?playlistId=${playlistId}`)
      let loadMoreButtonShown = false
      if (videos.length > 20) {
        videos.pop()
        loadMoreButtonShown = true
      }
      if (typeof onLoad === 'function') {
        onLoad({ exists: videos.length > 0, title })
      }
      this.setState({
        videos,
        loaded: true,
        loadMoreButtonShown
      })
    } catch (error) {
      console.error(error.response || error)
    }
  }

  render() {
    const { playlistId } = this.props
    const { videos, loaded, loading, loadMoreButtonShown } = this.state
    return (
      <Fragment>
        {videos.length === 0 ? (
          loaded ? (
            <NotFound
              title="Playlist does not exist"
              text="It is either removed or never existed in the first place"
            />
          ) : (
            <Loading text="Loading..." />
          )
        ) : null}
        {videos.map((video, index) => (

              <Link to={`/videos/${video.id}?playlist=${playlistId}`}>
                <VideoThumbImage
                  isStarred={!!video.isStarred}
                  videoId={video.id}
                  src={`https://img.youtube.com/vi/${
                    video.content
                  }/mqdefault.jpg`}
                />
              </Link>

              <Link
                style={{
                  fontSize: '2rem',
                  fontWeight: 'bold',
                  lineHeight: 1.5
                }}
                to={`/videos/${video.id}?playlist=${playlistId}`}
              >
                {cleanString(video.title)}
              </Link>

                Uploaded by {video.uploaderName}

        ))}
        {loadMoreButtonShown && (
          <LoadMoreButton
            style={{ marginTop: '1.5em' }}
            loading={loading}
            filled
            info
            onClick={this.onLoadMoreVideos}
          />
        )}
      </Fragment>
    )
  }

  onLoadMoreVideos = async() => {
    const { playlistId } = this.props
    const { videos } = this.state
    this.setState({ loading: true })
    try {
      const {
        data: { videos: loadedVideos }
      } = await request.get(
        `${API_URL}/playlist?playlistId=${playlistId}&${queryStringForArray(
          videos,
          'id',
          'shownVideos'
        )}`
      )
      let loadMoreButtonShown = false
      if (loadedVideos.length > 10) {
        loadedVideos.pop()
        loadMoreButtonShown = true
      }
      this.setState({
        videos: videos.concat(loadedVideos),
        loadMoreButtonShown,
        loading: false
      })
    } catch (error) {
      console.error(error.response || error)
    }
  }
}
<commit_msg>playlist load 20 at a time<commit_after>import React, { Component, Fragment } from 'react'
import PropTypes from 'prop-types'
import LoadMoreButton from 'components/Buttons/LoadMoreButton'
import Loading from 'components/Loading'
import VideoThumbImage from 'components/VideoThumbImage'
import { Color } from 'constants/css'
import { cleanString, queryStringForArray } from 'helpers/stringHelpers'
import { Link } from 'react-router-dom'
import request from 'axios'
import { URL } from 'constants/URL'
import NotFound from 'components/NotFound'

const API_URL = `${URL}/playlist`

export default class Playlist extends Component {
  static propTypes = {
    onLoad: PropTypes.func,
    playlistId: PropTypes.number.isRequired
  }

  state = {
    videos: [],
    loadMoreButtonShown: false,
    loading: false,
    loaded: false
  }

  async componentDidMount() {
    const { playlistId, onLoad } = this.props
    try {
      const {
        data: { videos, title }
      } = await request.get(`${API_URL}/playlist?playlistId=${playlistId}`)
      let loadMoreButtonShown = false
      if (videos.length > 20) {
        videos.pop()
        loadMoreButtonShown = true
      }
      if (typeof onLoad === 'function') {
        onLoad({ exists: videos.length > 0, title })
      }
      this.setState({
        videos,
        loaded: true,
        loadMoreButtonShown
      })
    } catch (error) {
      console.error(error.response || error)
    }
  }

  render() {
    const { playlistId } = this.props
    const { videos, loaded, loading, loadMoreButtonShown } = this.state
    return (
      <Fragment>
        {videos.length === 0 ? (
          loaded ? (
            <NotFound
              title="Playlist does not exist"
              text="It is either removed or never existed in the first place"
            />
          ) : (
            <Loading text="Loading..." />
          )
        ) : null}
        {videos.map((video, index) => (

              <Link to={`/videos/${video.id}?playlist=${playlistId}`}>
                <VideoThumbImage
                  isStarred={!!video.isStarred}
                  videoId={video.id}
                  src={`https://img.youtube.com/vi/${
                    video.content
                  }/mqdefault.jpg`}
                />
              </Link>

              <Link
                style={{
                  fontSize: '2rem',
                  fontWeight: 'bold',
                  lineHeight: 1.5
                }}
                to={`/videos/${video.id}?playlist=${playlistId}`}
              >
                {cleanString(video.title)}
              </Link>

                Uploaded by {video.uploaderName}

        ))}
        {loadMoreButtonShown && (
          <LoadMoreButton
            style={{ marginTop: '1.5em' }}
            loading={loading}
            filled
            info
            onClick={this.onLoadMoreVideos}
          />
        )}
      </Fragment>
    )
  }

  onLoadMoreVideos = async() => {
    const { playlistId } = this.props
    const { videos } = this.state
    this.setState({ loading: true })
    try {
      const {
        data: { videos: loadedVideos }
      } = await request.get(
        `${API_URL}/playlist?playlistId=${playlistId}&${queryStringForArray(
          videos,
          'id',
          'shownVideos'
        )}`
      )
      let loadMoreButtonShown = false
      if (loadedVideos.length > 20) {
        loadedVideos.pop()
        loadMoreButtonShown = true
      }
      this.setState({
        videos: videos.concat(loadedVideos),
        loadMoreButtonShown,
        loading: false
      })
    } catch (error) {
      console.error(error.response || error)
    }
  }
}
<|endoftext|>


<commit_before>(function(exports){
    exports.features = [];
    var featureRunner = {
        enqueue : function(feature){
            exports.features.push(feature);
        }
    };

    function Feature(featureDescription){
        function Scenario(scenarioDescription, options){
            var self = this;
            options = options || {};
            this.description = scenarioDescription;
            this.steps = [];
			this.addStep = function(){
			  var args = Array.prototype.splice.call(arguments, 2);
              this.steps.push({
                description : arguments[1],
				fullDescription : arguments[0] + '  ' + arguments[1] + ' ' + (args && args.length > 0 ? JSON.stringify(args, null, 2) : ''),
				/* replace with :
					fullDescription : exports.featureStepStringify(arguments[0], arguments[1], args), */
                arguments : args
              });
            };

            this.given = function(){
                this.addStep.apply(this, ['Given'].concat(Array.prototype.slice.call(arguments, 0)));

                self.and = function(){
                  this.addStep.apply(this, ['And'].concat(Array.prototype.slice.call(arguments, 0)));
                  return self;
                };

                return self;
            };
            this.when = function(){
                self.addStep.apply(this, ['When'].concat(Array.prototype.slice.call(arguments, 0)));

                self.and = function(){
                  self.addStep.apply(this, ['And'].concat(Array.prototype.slice.call(arguments, 0)));
                  return self;
                };

                return self;
            };
            this.then = function(){
                self.addStep.apply(this, ['Then'].concat(Array.prototype.slice.call(arguments, 0)));

                self.and = function(){
                  self.addStep.apply(this, ['And'].concat(Array.prototype.slice.call(arguments, 0)));
                  return self;
                };

                return self;
            };

            // could add this.and as a default - but at least this way you don't get and until you use given, when or then
            this.isOnly = options.only === true ? true : false;
            this.never = options.not === true ? true : false;
        }
        Scenario.prototype = this;
        var self = this;

        self.not = {
            scenario : function(){
                return self.scenario.apply(self, Array.prototype.slice.call(arguments, 0).concat({ not : true}));
            }
        };

        self.only = {
            scenario : function(){
                return self.scenario.apply(self, Array.prototype.slice.call(arguments, 0).concat({ only : true}));
            }
        };

        this.description = featureDescription;
        this.scenarios = [];
        exports.scenario = this.scenario = function(scenarioDescription, callback){
            var scenario = new Scenario(scenarioDescription, callback);
            self.scenarios.push(scenario);
            return scenario;
        };
    }
    function feature(featureDescription, callback){
        var f = new Feature(featureDescription, callback);
        featureRunner.enqueue(f);
        return f;
    }

    exports.steps = [];

    function FeatureSteps(featurePattern, callback){
        this.pattern = new RegExp(featurePattern);
        this.beforeSteps = [];
        this.afterSteps = [];
        this.steps = [];
        this.given = this.when = this.then = function(pattern, definition){
            this.steps.push({pattern : new RegExp('^' + pattern + '$'), definition : definition});
            return this;
        };
        this.before = function(definition){
            this.beforeSteps.push(definition);
            return this;
        };

        this.after = function(definition){
            this.afterSteps.push(definition);
            return this;
        };

        if (callback){
            callback.call(this);
        }
    }

    exports.feature = feature;
    exports.featureSteps = function(featurePattern, callback){
        var featureSteps = new FeatureSteps(featurePattern, callback);
        exports.steps.push(featureSteps);
        return featureSteps;
    };
}(typeof window !== 'undefined' ? window : module.exports));<commit_msg>Nice display of Table arguments steps<commit_after>(function(exports){
    exports.features = [];
    var featureRunner = {
        enqueue : function(feature){
            exports.features.push(feature);
        }
    };

    function Feature(featureDescription){
        function Scenario(scenarioDescription, options){
            var self = this;
            options = options || {};
            this.description = scenarioDescription;
            this.steps = [];
			this.addStep = function(){
			  var args = Array.prototype.splice.call(arguments, 2);
              this.steps.push({
                description : arguments[1],
				fullDescription : exports.featureStepStringify(arguments[0], arguments[1], args),
                arguments : args
              });
            };

            this.given = function(){
                this.addStep.apply(this, ['Given'].concat(Array.prototype.slice.call(arguments, 0)));

                self.and = function(){
                  this.addStep.apply(this, ['And'].concat(Array.prototype.slice.call(arguments, 0)));
                  return self;
                };

                return self;
            };
            this.when = function(){
                self.addStep.apply(this, ['When'].concat(Array.prototype.slice.call(arguments, 0)));

                self.and = function(){
                  self.addStep.apply(this, ['And'].concat(Array.prototype.slice.call(arguments, 0)));
                  return self;
                };

                return self;
            };
            this.then = function(){
                self.addStep.apply(this, ['Then'].concat(Array.prototype.slice.call(arguments, 0)));

                self.and = function(){
                  self.addStep.apply(this, ['And'].concat(Array.prototype.slice.call(arguments, 0)));
                  return self;
                };

                return self;
            };

            // could add this.and as a default - but at least this way you don't get and until you use given, when or then
            this.isOnly = options.only === true ? true : false;
            this.never = options.not === true ? true : false;
        }
        Scenario.prototype = this;
        var self = this;

        self.not = {
            scenario : function(){
                return self.scenario.apply(self, Array.prototype.slice.call(arguments, 0).concat({ not : true}));
            }
        };

        self.only = {
            scenario : function(){
                return self.scenario.apply(self, Array.prototype.slice.call(arguments, 0).concat({ only : true}));
            }
        };

        this.description = featureDescription;
        this.scenarios = [];
        exports.scenario = this.scenario = function(scenarioDescription, callback){
            var scenario = new Scenario(scenarioDescription, callback);
            self.scenarios.push(scenario);
            return scenario;
        };
    }
    function feature(featureDescription, callback){
        var f = new Feature(featureDescription, callback);
        featureRunner.enqueue(f);
        return f;
    }

    exports.steps = [];

    function FeatureSteps(featurePattern, callback){
        this.pattern = new RegExp(featurePattern);
        this.beforeSteps = [];
        this.afterSteps = [];
        this.steps = [];
        this.given = this.when = this.then = function(pattern, definition){
            this.steps.push({pattern : new RegExp('^' + pattern + '$'), definition : definition});
            return this;
        };
        this.before = function(definition){
            this.beforeSteps.push(definition);
            return this;
        };

        this.after = function(definition){
            this.afterSteps.push(definition);
            return this;
        };

        if (callback){
            callback.call(this);
        }
    }

    exports.feature = feature;
    exports.featureSteps = function(featurePattern, callback){
        var featureSteps = new FeatureSteps(featurePattern, callback);
        exports.steps.push(featureSteps);
        return featureSteps;
    };
}(typeof window !== 'undefined' ? window : module.exports));<|endoftext|>


<commit_before>module.controller('ExcerptsPanel', [
	'$scope',
	'pageService',
	function ($scope, page) {
		$scope.bootPanel = function () {
			if (angular.isArray($scope.volume.excerpts) && $scope.volume.excerpts.length > 0) {
				$scope.current = $scope.volume.excerpts[0] || undefined;
			}
		};

		$scope.refreshPanel = function () {
			$scope.enabled = angular.isArray($scope.volume.excerpts) && $scope.volume.excerpts.length > 0;
		};

		//

		$scope.setCurrent = function (asset) {
			$scope.current = asset;
		};

		$scope.getMimeGroup = function (asset) {
			var mimetype = page.types.assetFormat(asset).mimetype,
				type = mimetype.split('/')[0];

			return type == 'text' ? mimetype[1] : type;
		};

		$scope.hasThumbnail = function (asset) {
			return $scope.getMimeGroup(asset) == 'image' || $scope.getMimeGroup(asset) == 'video';
		};

		$scope.listClass = function (excerpt) {
			var cls = [];

			if (angular.isArray(excerpt.segment)) {
				cls.push('video');
			}

			return cls;
		};

		$scope.supported = function () {
			return page.$window.navigator.userAgent.toLowerCase().indexOf('firefox') == -1 || page.$window.navigator.platform.toLowerCase().indexOf('mac') == -1;
		};

		$scope.jump = function (asset) {
			var found;

			for (var i = 0, l = page.browser.groups.session.length; i < l; i++) {
				if (page.browser.groups.session[i].object.id == asset.container.id) {
					found = page.browser.groups.session[i];
					break;
				}
			}

			if (!found) {
				return expandTo(page.browser.data.items[0].volume.sessions[asset.container.id], asset);
			}

			var $item = $('#' + found.id);

			if ($item.length == 0) {
				return addTo(found, asset);
			}

			page.display.scrollTo($item);
			page.browser.setItemExpand(found, true);
		};

		var expandTo = function (session, asset) {
			var dirty;

			angular.forEach(page.browser.groups, function (objects, group) {
				if (!$.isNumeric(group)) {
					return;
				}

				var recordIDs = session.categories[group];

				if (recordIDs) {
					recordIDs = recordIDs.map(function (obj) {
						return obj.id;
					});
				}
				else {
					recordIDs = [0];
				}

				angular.forEach(objects, function (data) {
					if (recordIDs.indexOf(data.object.id) > -1) {
						page.browser.setItemExpand(data, true);
						dirty = true;
					}
				});
			});

			if (dirty) {
				page.$timeout(function () {
					$scope.jump(asset);
				}, 1);
			}
		};

		var addTo = function (session, asset) {
			var data = session.parent, index;

			for (var i = 0, l = data.items.length; i < l; i++) {
				if (data.items[i] == session) {
					index = i;
					break;
				}
			}

			if (index) {
				data.items.splice(9, 0, data.items.splice(index, 1)[0]);

				page.$timeout(function () {
					$scope.jump(asset);
				}, 1);
			}
		};
	}
]);
<commit_msg>Show excerpts play icon on all videos rather than slotted assets<commit_after>module.controller('ExcerptsPanel', [
	'$scope',
	'pageService',
	function ($scope, page) {
		$scope.bootPanel = function () {
			if (angular.isArray($scope.volume.excerpts) && $scope.volume.excerpts.length > 0) {
				$scope.current = $scope.volume.excerpts[0] || undefined;
			}
		};

		$scope.refreshPanel = function () {
			$scope.enabled = angular.isArray($scope.volume.excerpts) && $scope.volume.excerpts.length > 0;
		};

		//

		$scope.setCurrent = function (asset) {
			$scope.current = asset;
		};

		$scope.getMimeGroup = function (asset) {
			var mimetype = page.types.assetFormat(asset).mimetype,
				type = mimetype.split('/')[0];

			return type == 'text' ? mimetype[1] : type;
		};

		$scope.hasThumbnail = function (asset) {
			return $scope.getMimeGroup(asset) == 'image' || $scope.getMimeGroup(asset) == 'video';
		};

		$scope.listClass = function (excerpt) {
			var cls = [];

			if ($scope.getMimeGroup(excerpt) == 'video') {
				cls.push('video');
			}

			return cls;
		};

		$scope.supported = function () {
			return page.$window.navigator.userAgent.toLowerCase().indexOf('firefox') == -1 || page.$window.navigator.platform.toLowerCase().indexOf('mac') == -1;
		};

		$scope.jump = function (asset) {
			var found;

			for (var i = 0, l = page.browser.groups.session.length; i < l; i++) {
				if (page.browser.groups.session[i].object.id == asset.container.id) {
					found = page.browser.groups.session[i];
					break;
				}
			}

			if (!found) {
				return expandTo(page.browser.data.items[0].volume.sessions[asset.container.id], asset);
			}

			var $item = $('#' + found.id);

			if ($item.length == 0) {
				return addTo(found, asset);
			}

			page.display.scrollTo($item);
			page.browser.setItemExpand(found, true);
		};

		var expandTo = function (session, asset) {
			var dirty;

			angular.forEach(page.browser.groups, function (objects, group) {
				if (!$.isNumeric(group)) {
					return;
				}

				var recordIDs = session.categories[group];

				if (recordIDs) {
					recordIDs = recordIDs.map(function (obj) {
						return obj.id;
					});
				}
				else {
					recordIDs = [0];
				}

				angular.forEach(objects, function (data) {
					if (recordIDs.indexOf(data.object.id) > -1) {
						page.browser.setItemExpand(data, true);
						dirty = true;
					}
				});
			});

			if (dirty) {
				page.$timeout(function () {
					$scope.jump(asset);
				}, 1);
			}
		};

		var addTo = function (session, asset) {
			var data = session.parent, index;

			for (var i = 0, l = data.items.length; i < l; i++) {
				if (data.items[i] == session) {
					index = i;
					break;
				}
			}

			if (index) {
				data.items.splice(9, 0, data.items.splice(index, 1)[0]);

				page.$timeout(function () {
					$scope.jump(asset);
				}, 1);
			}
		};
	}
]);
<|endoftext|>


<commit_before>/*
 * CodePress - Real Time Syntax Highlighting Editor written in JavaScript - http://codepress.org/
 *
 * Copyright (C) 2006 Fernando M.A.d.S. <fermads@gmail.com>
 *
 * This program is free software; you can redistribute it and/or modify it under the terms of the
 * GNU Lesser General Public License as published by the Free Software Foundation.
 *
 * Read the full licence: http://www.opensource.org/licenses/lgpl-license.php
 */

// MOD: All local modifications marked with this comment prefix.

// Copied from http://www.google.com/ig/modules/codepress/codepress.js.
// Further modifications to decouple the domain of the script and the
// editor iframe.

CodePress = function(obj) {
  var self = document.getElementById('codepress-iframe');
  self.textarea = obj;
  self.textarea.disabled = true;
  self.textarea.style.overflow = 'hidden';

  // MOD(daniellee): Set height to match existing textarea element
  self.style.height = self.textarea.offsetHeight + 'px';

  // MOD(wwen): change width to 100%
  //self.style.width = self.textarea.clientWidth+'px';
  self.style.width = "100%";

  self.textarea.style.overflow = 'auto';
  // MOD(daniellee): Remove default border. Stylize editor in gge.xml
  //self.style.border = '1px solid gray';
  self.frameBorder = 0; // remove IE internal iframe border
  self.style.visibility = 'hidden';
  self.style.position = 'absolute';
  self.options = self.textarea.className;

  self.initialize = function() {
    self.editor = self.contentWindow.CodePress;
    self.editor.body = self.contentWindow.document.getElementsByTagName('body')[0];
    self.editor.setCode(self.textarea.value);
    self.setOptions();
    self.editor.syntaxHighlight('init');
    self.textarea.style.display = 'none';
    self.style.position = 'static';
    self.style.visibility = 'visible';
    self.style.display = 'inline';
    // MOD(burdon): Call Wrapper.
    if (CodePress.postInitialize) {
      CodePress.postInitialize();
    }
    // MOD(burdon): Spell check off.
    if (self.editor.body.spellcheck) {
      self.editor.body.spellcheck = false;
    }
  }

  self.edit = function(id,language) {
    console.log('edit()');
    if(id) self.textarea.value = document.getElementById(id).value;
    if(!self.textarea.disabled) return;
    self.language = language ? language : self.options.replace(/ ?codepress ?| ?readonly-on ?| ?autocomplete-off ?| ?linenumbers-off ?/g,'');
    if(!CodePress.languages[self.language]) self.language = 'generic';

    var contentDoc = self.document || self.contentDocument || self.contentWindow.documnt;
    contentDoc.open();
    contentDoc.write(codePressEmptyIframeContent);
    contentDoc.close();
    contentDoc.location.reload();
    console.log('codePressEmptyIframeContent:');
    console.log(codePressEmptyIframeContent);
    console.log('contentDoc.innerHTML:');
    console.log(contentDoc.innerHTML);

    contentDoc.open();
    contentDoc.write(codePressEmptyIframeContent);
    contentDoc.close();
    contentDoc.location.reload();
    console.log('contentDoc.innerHTML2:');
    console.log(contentDoc.innerHTML);

    if(self.attachEvent) self.attachEvent('onload',self.initialize);
    else self.addEventListener('load',self.initialize,false);
  }

  self.setOptions = function() {
    if(self.options.match('autocomplete-off')) self.toggleAutoComplete();
    if(self.options.match('readonly-on')) self.toggleReadOnly();
    if(self.options.match('linenumbers-off')) self.toggleLineNumbers();
  }

  self.getCode = function() {
    return self.textarea.disabled ? self.editor.getCode() : self.textarea.value;
  }

  self.setCode = function(code) {
    self.textarea.disabled ? self.editor.setCode(code) : self.textarea.value = code;
  }

  self.toggleAutoComplete = function() {
    self.editor.autocomplete = (self.editor.autocomplete) ? false : true;
  }

  self.toggleReadOnly = function() {
    self.textarea.readOnly = (self.textarea.readOnly) ? false : true;
    if(self.style.display != 'none') // prevent exception on FF + iframe with display:none
      self.editor.readOnly(self.textarea.readOnly ? true : false);
  }

  self.toggleLineNumbers = function() {
    var cn = self.editor.body.className;
    self.editor.body.className = (cn==''||cn=='show-line-numbers') ? 'hide-line-numbers' : 'show-line-numbers';
  }

  self.toggleEditor = function() {
    if(self.textarea.disabled) {
      self.textarea.value = self.getCode();
      self.textarea.disabled = false;
      self.style.display = 'none';
      self.textarea.style.display = 'inline';
    }
    else {
      self.textarea.disabled = true;
      self.setCode(self.textarea.value);
      self.editor.syntaxHighlight('init');
      self.style.display = 'inline';
      self.textarea.style.display = 'none';
    }
  }

  self.edit();
  return self;
}

CodePress.languages = {
  css : 'CSS',
  generic : 'Generic',
  html : 'HTML',
  java : 'Java',
  javascript : 'JavaScript',
  perl : 'Perl',
  ruby : 'Ruby',
  php : 'PHP',
  text : 'Text',
  sql : 'SQL',
  gadget : 'Gadget'
}

// MOD(burdon):
CodePress.getEngine = function() {
  var engine = 'older';
  var ua = navigator.userAgent;
  if(ua.match('MSIE')) engine = 'msie';
  else if(ua.match('KHTML')) engine = 'khtml';
  else if(ua.match('Opera')) engine = 'opera';
  else if(ua.match('Gecko')) engine = 'gecko';
  return engine;
}

CodePress.run = function() {
  console.log('run()');
  CodePress.engine = CodePress.getEngine();
  var s = document.getElementsByTagName('script');
//  for(var i=0,n=s.length;i<n;i++) {
//    if(s[i].src.match(/codepress_wrapper\.js.*/)) {
//      CodePress.path = s[i].src.replace(/codepress_wrapper\.js.*/,'');
//    }
//  }
  var t = document.getElementsByTagName('textarea');
  for(var i=0,n=t.length;i<n;i++) {
    if(t[i].className.match('codepress')) {
      var id = t[i].id;
      t[i].id = id+'_cp';
      window[id] = new CodePress(t[i]);
      t[i].parentNode.insertBefore(window[id], t[i]);
    }
  }
}

// MOD(burdon): Add our language.
CodePress.languages["gm"] = 'GM';

/*
// MOD(burdon): Now triggered by CodePressEditor:init
if(window.attachEvent) window.attachEvent('onload',CodePress.run);
else window.addEventListener('DOMContentLoaded',CodePress.run,false);
*/

var language = "gm";
var engine = "older";
var ua = navigator.userAgent;
var ts = (new Date).getTime(); // timestamp to avoid cache
var lh = location.href;

if(ua.match("MSIE")) engine = "msie";
else if(ua.match("KHTML")) engine = "khtml";
else if(ua.match("Opera")) engine = "opera";
else if(ua.match("Gecko")) engine = "gecko";

if(lh.match("language=")) language = lh.replace(/.*language=(.*?)(&.*)?$/,"$1");

// XSS fix (wwen)
// these are the only languages that GGE supports
if (!language.match(/^(css|gadget|javascript)$/)) {
  language = "gadget";
}

CodePress.path = 'http://www.google.com/ig/modules/codepress/';
var codePressEmptyIframeContent = '\n' +
    '\n' +
    '  <title>CodePress - Real Time Syntax Highlighting Editor written in JavaScript</title>\n' +
    '  <meta name="description" content="CodePress - source code editor window" />\n' +
    '\n' +
    '  <link type="text/css" href="' + CodePress.path + 'codepress.css?ts='+ts+'" rel="stylesheet" />\n' +
    '  <link type="text/css" href="' + CodePress.path + 'languages/'+language+'.css?ts='+ts+'" rel="stylesheet" id="cp-lang-style" />\n' +
    '  \n' +
    '  \n' +
    '\n' +
    '\n' +
    '\n' +
    '';
<commit_msg>removed console logging<commit_after>/*
 * CodePress - Real Time Syntax Highlighting Editor written in JavaScript - http://codepress.org/
 *
 * Copyright (C) 2006 Fernando M.A.d.S. <fermads@gmail.com>
 *
 * This program is free software; you can redistribute it and/or modify it under the terms of the
 * GNU Lesser General Public License as published by the Free Software Foundation.
 *
 * Read the full licence: http://www.opensource.org/licenses/lgpl-license.php
 */

// MOD: All local modifications marked with this comment prefix.

// Copied from http://www.google.com/ig/modules/codepress/codepress.js.
// Further modifications to decouple the domain of the script and the
// editor iframe.

CodePress = function(obj) {
  var self = document.getElementById('codepress-iframe');
  self.textarea = obj;
  self.textarea.disabled = true;
  self.textarea.style.overflow = 'hidden';

  // MOD(daniellee): Set height to match existing textarea element
  self.style.height = self.textarea.offsetHeight + 'px';

  // MOD(wwen): change width to 100%
  //self.style.width = self.textarea.clientWidth+'px';
  self.style.width = "100%";

  self.textarea.style.overflow = 'auto';
  // MOD(daniellee): Remove default border. Stylize editor in gge.xml
  //self.style.border = '1px solid gray';
  self.frameBorder = 0; // remove IE internal iframe border
  self.style.visibility = 'hidden';
  self.style.position = 'absolute';
  self.options = self.textarea.className;

  self.initialize = function() {
    self.editor = self.contentWindow.CodePress;
    self.editor.body = self.contentWindow.document.getElementsByTagName('body')[0];
    self.editor.setCode(self.textarea.value);
    self.setOptions();
    self.editor.syntaxHighlight('init');
    self.textarea.style.display = 'none';
    self.style.position = 'static';
    self.style.visibility = 'visible';
    self.style.display = 'inline';
    // MOD(burdon): Call Wrapper.
    if (CodePress.postInitialize) {
      CodePress.postInitialize();
    }
    // MOD(burdon): Spell check off.
    if (self.editor.body.spellcheck) {
      self.editor.body.spellcheck = false;
    }
  }

  self.edit = function(id,language) {
    if(id) self.textarea.value = document.getElementById(id).value;
    if(!self.textarea.disabled) return;
    self.language = language ? language : self.options.replace(/ ?codepress ?| ?readonly-on ?| ?autocomplete-off ?| ?linenumbers-off ?/g,'');
    if(!CodePress.languages[self.language]) self.language = 'generic';

    var contentDoc = self.document || self.contentDocument || self.contentWindow.documnt;
    contentDoc.open();
    contentDoc.write(codePressEmptyIframeContent);
    contentDoc.close();
    contentDoc.location.reload();

    contentDoc.open();
    contentDoc.write(codePressEmptyIframeContent);
    contentDoc.close();
    contentDoc.location.reload();

    if(self.attachEvent) self.attachEvent('onload',self.initialize);
    else self.addEventListener('load',self.initialize,false);
  }

  self.setOptions = function() {
    if(self.options.match('autocomplete-off')) self.toggleAutoComplete();
    if(self.options.match('readonly-on')) self.toggleReadOnly();
    if(self.options.match('linenumbers-off')) self.toggleLineNumbers();
  }

  self.getCode = function() {
    return self.textarea.disabled ? self.editor.getCode() : self.textarea.value;
  }

  self.setCode = function(code) {
    self.textarea.disabled ? self.editor.setCode(code) : self.textarea.value = code;
  }

  self.toggleAutoComplete = function() {
    self.editor.autocomplete = (self.editor.autocomplete) ? false : true;
  }

  self.toggleReadOnly = function() {
    self.textarea.readOnly = (self.textarea.readOnly) ? false : true;
    if(self.style.display != 'none') // prevent exception on FF + iframe with display:none
      self.editor.readOnly(self.textarea.readOnly ? true : false);
  }

  self.toggleLineNumbers = function() {
    var cn = self.editor.body.className;
    self.editor.body.className = (cn==''||cn=='show-line-numbers') ? 'hide-line-numbers' : 'show-line-numbers';
  }

  self.toggleEditor = function() {
    if(self.textarea.disabled) {
      self.textarea.value = self.getCode();
      self.textarea.disabled = false;
      self.style.display = 'none';
      self.textarea.style.display = 'inline';
    }
    else {
      self.textarea.disabled = true;
      self.setCode(self.textarea.value);
      self.editor.syntaxHighlight('init');
      self.style.display = 'inline';
      self.textarea.style.display = 'none';
    }
  }

  self.edit();
  return self;
}

CodePress.languages = {
  css : 'CSS',
  generic : 'Generic',
  html : 'HTML',
  java : 'Java',
  javascript : 'JavaScript',
  perl : 'Perl',
  ruby : 'Ruby',
  php : 'PHP',
  text : 'Text',
  sql : 'SQL',
  gadget : 'Gadget'
}

// MOD(burdon):
CodePress.getEngine = function() {
  var engine = 'older';
  var ua = navigator.userAgent;
  if(ua.match('MSIE')) engine = 'msie';
  else if(ua.match('KHTML')) engine = 'khtml';
  else if(ua.match('Opera')) engine = 'opera';
  else if(ua.match('Gecko')) engine = 'gecko';
  return engine;
}

CodePress.run = function() {
  CodePress.engine = CodePress.getEngine();
  var s = document.getElementsByTagName('script');
//  for(var i=0,n=s.length;i<n;i++) {
//    if(s[i].src.match(/codepress_wrapper\.js.*/)) {
//      CodePress.path = s[i].src.replace(/codepress_wrapper\.js.*/,'');
//    }
//  }
  var t = document.getElementsByTagName('textarea');
  for(var i=0,n=t.length;i<n;i++) {
    if(t[i].className.match('codepress')) {
      var id = t[i].id;
      t[i].id = id+'_cp';
      window[id] = new CodePress(t[i]);
      t[i].parentNode.insertBefore(window[id], t[i]);
    }
  }
}

// MOD(burdon): Add our language.
CodePress.languages["gm"] = 'GM';

/*
// MOD(burdon): Now triggered by CodePressEditor:init
if(window.attachEvent) window.attachEvent('onload',CodePress.run);
else window.addEventListener('DOMContentLoaded',CodePress.run,false);
*/

var language = "gm";
var engine = "older";
var ua = navigator.userAgent;
var ts = (new Date).getTime(); // timestamp to avoid cache
var lh = location.href;

if(ua.match("MSIE")) engine = "msie";
else if(ua.match("KHTML")) engine = "khtml";
else if(ua.match("Opera")) engine = "opera";
else if(ua.match("Gecko")) engine = "gecko";

if(lh.match("language=")) language = lh.replace(/.*language=(.*?)(&.*)?$/,"$1");

// XSS fix (wwen)
// these are the only languages that GGE supports
if (!language.match(/^(css|gadget|javascript)$/)) {
  language = "gadget";
}

CodePress.path = 'http://www.google.com/ig/modules/codepress/';
var codePressEmptyIframeContent = '\n' +
    '\n' +
    '  <title>CodePress - Real Time Syntax Highlighting Editor written in JavaScript</title>\n' +
    '  <meta name="description" content="CodePress - source code editor window" />\n' +
    '\n' +
    '  <link type="text/css" href="' + CodePress.path + 'codepress.css?ts='+ts+'" rel="stylesheet" />\n' +
    '  <link type="text/css" href="' + CodePress.path + 'languages/'+language+'.css?ts='+ts+'" rel="stylesheet" id="cp-lang-style" />\n' +
    '  \n' +
    '  \n' +
    '\n' +
    '\n' +
    '\n' +
    '';
<|endoftext|>


<commit_before>
// interface for each should be roughly:
/*
  {
    title: 'string',
    prompt: 'string',
    winCondition: computationData => bool
  }
*/
export default [
  {
    title: 'Simple Identifier',
    prompt: "Let's get acquainted with some basic syntax. First, type 'a₁'. Letters followed optionally by numbers represent variables in the lambda calculus.",
    winCondition: ({text}) => {
      return text === 'a₁';
    }
  },
  // okay the first problem I actually care about
  {
    title: 'Application',
    prompt: "You just wrote a lambda expression which containes only the variable 'a₁', which is not currently bound to anything. In the lambda calculus, variables can be bound to functions, and variables can be applied to one another. \n\n To apply the variable b₁ to the variable a₁, type in 'a₁b₁'. This is akin to saying that we're calling the function a₁ with b₁ as an argument.",
    winCondition: ({text}) => {
      return text === 'a₁b₁';
    }
  },
  {
    title: 'Identity',
    prompt: "Nice! Now we'll get into lambda expressions. Lambda expressions represent functions in the lambda calculus. A lambda expression takes the form 'λ [arg] . [body]' where [arg] is the input, and [body] is the output. \n\n Let's write the identity function; a function which takes its argument, does nothing to it, and spits it back out. In the lambda calculus, that looks something like 'λa.a'",
    winCondition: ({ast}) => {
      return (
        // We could put conditions that we might like to use into lib/lambda when we need to.
        ast &&
        ast.type === "function" &&
        ast.body.type === "token" &&
        ast.argument === ast.body.name
      );
    }
  },
  {
    title: "Parentheses",
    prompt: "Schweet! This takes one argument a and outputs that same argument! Now go ahead and wrap the whole thing in parentheses",
    winCondition: ({text, ast}) => {
      return (
        // We could put conditions that we might like to use into lib/lambda when we need to.
        /^\s*\(.*\)\s*$/.test(text) &&
        ast &&
        ast.type === "function" &&
        ast.body.type === "token" &&
        ast.argument === ast.body.name
      );
    }
  },
  {
    title: "Baby's first β-reduction",
    prompt: "Now in the same way that we can apply variables to other variables, we can apply variables to functions. Try applying 'b' to your identity function, by writing '(λa.a)b'.",
    winCondition: ({ast, text}) => {
      // These win conditions need work
      return text === '(λa.a)b';
      /*return (
        // We could put conditions that we might like to use into lib/lambda when we need to.
        ast &&
        ast.type === "function" &&
        ast.body.type === "token" &&
        ast.argument === ast.body.name &&
        false //because i haven't implemented this yet.
      );*/
    }
  },
  {
    title: 'β-reduction function',
    prompt: "Nice! What happened here is your identity function took 'b' as the input and spit it right back out. The result is in what's called 'normal form', which we'll get into a little later. \n\n Just like we can do this for variables, we can also do this for functions! Try typing '(λa.a)λb.b'",
    winCondition: ({text}) => text === '(λa.a)λb.b',
  },
  {
    title: 'Curry',
    prompt: 'As you may have noticed before, lambda expressions can only take one argument.'
  },
  {
    title: "Challenge: Can't stop, won't stop executing."
  },
  /*
    considering following types of problems:
    - illustrating syntactic sugar of multiple arguments, and what that means.
    - illustrating how you can always replace a variable with a function
    - illustrating alpha conversion when a naming collision applies.
    - Challenges...
  */
];
<commit_msg>add in more fake problems<commit_after>
// interface for each should be roughly:
/*
  {
    title: 'string',
    prompt: 'string',
    winCondition: computationData => bool
  }
*/
export default [
  {
    title: 'Simple Identifier',
    prompt: "Let's get acquainted with some basic syntax. First, type 'a₁'. Letters followed optionally by numbers represent variables in the lambda calculus.",
    winCondition: ({text}) => {
      return text === 'a₁';
    }
  },
  // okay the first problem I actually care about
  {
    title: 'Application',
    prompt: "You just wrote a lambda expression which containes only the variable 'a₁', which is not currently bound to anything. In the lambda calculus, variables can be bound to functions, and variables can be applied to one another. \n\n To apply the variable b₁ to the variable a₁, type in 'a₁b₁'. This is akin to saying that we're calling the function a₁ with b₁ as an argument.",
    winCondition: ({text}) => {
      return text === 'a₁b₁';
    }
  },
  {
    title: 'Identity',
    prompt: "Nice! Now we'll get into lambda expressions. Lambda expressions represent functions in the lambda calculus. A lambda expression takes the form 'λ [arg] . [body]' where [arg] is the input, and [body] is the output. \n\n Let's write the identity function; a function which takes its argument, does nothing to it, and spits it back out. In the lambda calculus, that looks something like 'λa.a'",
    winCondition: ({ast}) => {
      return (
        // We could put conditions that we might like to use into lib/lambda when we need to.
        ast &&
        ast.type === "function" &&
        ast.body.type === "token" &&
        ast.argument === ast.body.name
      );
    }
  },
  {
    title: "Parentheses",
    prompt: "Schweet! This takes one argument a and outputs that same argument! Now go ahead and wrap the whole thing in parentheses",
    winCondition: ({text, ast}) => {
      return (
        // We could put conditions that we might like to use into lib/lambda when we need to.
        /^\s*\(.*\)\s*$/.test(text) &&
        ast &&
        ast.type === "function" &&
        ast.body.type === "token" &&
        ast.argument === ast.body.name
      );
    }
  },
  {
    title: "Baby's first β-reduction",
    prompt: "Now in the same way that we can apply variables to other variables, we can apply variables to functions. Try applying 'b' to your identity function, by writing '(λa.a)b'.",
    winCondition: ({ast, text}) => {
      // These win conditions need work
      return text === '(λa.a)b';
      /*return (
        // We could put conditions that we might like to use into lib/lambda when we need to.
        ast &&
        ast.type === "function" &&
        ast.body.type === "token" &&
        ast.argument === ast.body.name &&
        false //because i haven't implemented this yet.
      );*/
    }
  },
  {
    title: 'β-reduction function',
    prompt: "Nice! What happened here is your identity function took 'b' as the input and spit it right back out. The result is in what's called 'normal form', which we'll get into a little later. \n\n Just like we can do this for variables, we can also do this for functions! Try typing '(λa.a)λb.b'",
    winCondition: ({text}) => text === '(λa.a)λb.b',
  },
  {
    title: 'Curry',
    prompt: 'As you may have noticed before, lambda expressions can only take one argument. this puzzle and all further ones are not yet implemented',
    winCondition: () => false,
  },
  {
    title: 'Defining numbers',
  },
  {
    title: 'Defining Booleans',
  },
  {
    title: 'Functions on Numbers',
  },
  {
    title: 'Functions as Numbers',
  },
  {
    title: 'The Y-Combinator'
  },
  {
    title: 'lol these arent finished yet',
  },
  {
    title: "Challenge: Can't stop, won't stop executing."
  },
  /*
    considering following types of problems:
    - illustrating syntactic sugar of multiple arguments, and what that means.
    - illustrating how you can always replace a variable with a function
    - illustrating alpha conversion when a naming collision applies.
    - Challenges...
  */
];
<|endoftext|>