<commit_before>import React, {Component} from 'react';
import PropTypes from 'prop-types';
import {connect} from 'react-redux';
import AutoBind from 'auto-bind-es5';

import {toggleModal, sendCart} from '../store/actions/cart';
import CartList from '../components/CartList';

class CartContainer extends Component {
    constructor(props) {
        super(props);
        AutoBind(this);
    }
    render() {
        if (!this.props.visible) return null;
        return (

Saved items

                        <button className="modal-close" onClick={toggleModal} />

                        <CartList />

                                <textarea
                                    className="textarea"
                                    placeholder="Additionnal informations..."
                                    ref={el => this.message = el}
                                />

                         sendCart(this.message.value)}>Send this order
                         console.log('reset')}>Empty cart

        );
    }
}

CartContainer.propTypes = {
    visible: PropTypes.bool
};

export default connect(state => ({
    visible: state.cart.isVisible
}))(CartContainer);
<commit_msg>wording<commit_after>import React, {Component} from 'react';
import PropTypes from 'prop-types';
import {connect} from 'react-redux';
import AutoBind from 'auto-bind-es5';

import {toggleModal, sendCart} from '../store/actions/cart';
import CartList from '../components/CartList';

class CartContainer extends Component {
    constructor(props) {
        super(props);
        AutoBind(this);
    }
    render() {
        if (!this.props.visible) return null;
        return (

Saved items

                        <button className="modal-close" onClick={toggleModal} />

                        <CartList />

                                <textarea
                                    className="textarea"
                                    placeholder="Additionnal information..."
                                    ref={el => this.message = el}
                                />

                         sendCart(this.message.value)}>Send this order
                         console.log('reset')}>Empty cart

        );
    }
}

CartContainer.propTypes = {
    visible: PropTypes.bool
};

export default connect(state => ({
    visible: state.cart.isVisible
}))(CartContainer);
<|endoftext|>


<commit_before>import setting from '../utilities/Setting';
import ApiClient from '../utilities/ApiClient';
import { sortCampaignsByRelevance } from '../campaign/helpers';

class CampaignController {
  constructor() {
    this.campaignsToExclude = setting('dsUser.activity.signups', []);
    this.campaignsApiPage = 1;
    this.apiClient = new ApiClient('v1');
    this.retrievedCampaigns = [];
  }

  filter(campaigns, comparison) {
    return campaigns.filter(campaign => comparison.indexOf(parseInt(campaign.id)) == -1);
  }

  /**
   * Grab campaigns & alter based on given args.
   * @param {Object} args containing the following optional parameters
   *   - {boolean} isStaffPick - Defaults to false.
   *   - {int} page - Defaults to 1.
   *   - {boolean} removeDuplicateResults
   *   - {boolean} sortByRelevance
   *   - {boolean} removeSignups
   * @return {Promise}
   */
  getCampaigns(args) {
    const query = {
      staff_pick: args['isStaffPick'] ? +args['isStaffPick'] : 0, // API requires 1/0 instead of true/false
      page: args['page'] || 1,
    };

    return this.apiClient.get('campaigns', query).then(response => {
      let campaigns = response.data;

      // Remove any campaigns we've already fetched for this gallery.
      if (args['removeDuplicateResults']) {
        campaigns = this.filter(campaigns, this.retrievedCampaigns);
      }
      // Keep track of the campaigns we've recieved.
      this.retrievedCampaigns.concat(campaigns.map(campaign => parseInt(campaign.id)));

      // Use our secret sauce to sort them in order.
      if (args['sortByRelevance']) {
        campaigns = sortCampaignsByRelevance(campaigns);
      }

      if (args['removeSignups']) {
        const signups = setting('dsUser.activity.signups', []);
        campaigns = this.filter(campaigns, signups);
      }

      return campaigns;
    });
  }

  /**
   * Sign the current user up for the specified campaign.
   *
   * @param {int} campaignId
   * @param {string} source
   * @return {Promise}
   */
  signup(campaignId, source) {
    const url = `campaigns/${campaignId}/signup`;
    const data = {source: source};

    return this.apiClient.post(url, data).then(response => {
      return true;
    });
  }

}

export default CampaignController;
<commit_msg>Removes unneeded return<commit_after>import setting from '../utilities/Setting';
import ApiClient from '../utilities/ApiClient';
import { sortCampaignsByRelevance } from '../campaign/helpers';

class CampaignController {
  constructor() {
    this.campaignsToExclude = setting('dsUser.activity.signups', []);
    this.campaignsApiPage = 1;
    this.apiClient = new ApiClient('v1');
    this.retrievedCampaigns = [];
  }

  filter(campaigns, comparison) {
    return campaigns.filter(campaign => comparison.indexOf(parseInt(campaign.id)) == -1);
  }

  /**
   * Grab campaigns & alter based on given args.
   * @param {Object} args containing the following optional parameters
   *   - {boolean} isStaffPick - Defaults to false.
   *   - {int} page - Defaults to 1.
   *   - {boolean} removeDuplicateResults
   *   - {boolean} sortByRelevance
   *   - {boolean} removeSignups
   * @return {Promise}
   */
  getCampaigns(args) {
    const query = {
      staff_pick: args['isStaffPick'] ? Number(args['isStaffPick']) : 0, //TODO: Move this back to true/false. See https://github.com/DoSomething/phoenix/issues/7049
      page: args['page'] || 1,
    };

    this.apiClient.get('campaigns', query).then(response => {
      let campaigns = response.data;

      // Remove any campaigns we've already fetched for this gallery.
      if (args['removeDuplicateResults']) {
        campaigns = this.filter(campaigns, this.retrievedCampaigns);
      }
      // Keep track of the campaigns we've recieved.
      this.retrievedCampaigns.concat(campaigns.map(campaign => parseInt(campaign.id)));

      // Use our secret sauce to sort them in order.
      if (args['sortByRelevance']) {
        campaigns = sortCampaignsByRelevance(campaigns);
      }

      if (args['removeSignups']) {
        const signups = setting('dsUser.activity.signups', []);
        campaigns = this.filter(campaigns, signups);
      }

      return campaigns;
    });
  }

  /**
   * Sign the current user up for the specified campaign.
   *
   * @param {int} campaignId
   * @param {string} source
   * @return {Promise}
   */
  signup(campaignId, source) {
    const url = `campaigns/${campaignId}/signup`;
    const data = {source: source};

    this.apiClient.post(url, data).then(response => {
      return true;
    });
  }

}

export default CampaignController;
<|endoftext|>


<commit_before>/* eslint-env mocha */
/* global proclaim */

it('returns a next-able object', function () {
	var str = 'ab';
	var iterator = str[Symbol.iterator]();

	proclaim.isInstanceOf(iterator.next, Function);
	proclaim.deepEqual(iterator.next(), {
		value: 'a',
		done: false
	});
});

it('finally returns a done object', function () {
	var str = 'ab';
	var iterator = str[Symbol.iterator]();
	iterator.next();
	iterator.next();
	proclaim.deepEqual(iterator.next(), {
		value: undefined,
		done: true
	});
});

<commit_msg>improve tests for string.prototype.@@iterator (#1667)<commit_after>/* eslint-env mocha */
/* globals proclaim, Symbol */

it('is a function', function () {
	proclaim.isFunction(String.prototype[Symbol.iterator]);
});

it('has correct arity', function () {
	proclaim.arity(String.prototype[Symbol.iterator], 0);
});

// TODO: Look into this
// it('has correct name', function () {
// 	proclaim.hasName(String.prototype[Symbol.iterator], '[Symbol.iterator]');
// });

it('is not enumerable', function () {
	proclaim.nonEnumerable(String.prototype, Symbol.iterator);
});

it('returns a next-able object', function () {
	var str = 'ab';
	var iterator = str[Symbol.iterator]();

	proclaim.isInstanceOf(iterator.next, Function);
	proclaim.deepEqual(iterator.next(), {
		value: 'a',
		done: false
	});
});

it('finally returns a done object', function () {
	var str = 'ab';
	var iterator = str[Symbol.iterator]();
	iterator.next();
	iterator.next();
	proclaim.deepEqual(iterator.next(), {
		value: undefined,
		done: true
	});
});

<|endoftext|>


<commit_before>/**
 * jQuery AutoLink
 *
 * @link      https://github.com/MarQuisKnox/jQuery.AutoLink
 * @license   MIT
 *
 * @copyright	2013 - 2015 Andreas Savvides et al
 * @copyright	2014 - 2017 MarQuis Knox
*/
!function(a){"use strict";function b(b,c){var m,d={local:{baseUrl:"//"+window.location.host+"/",hashtagSearchUrl:"search/",target:"_self",scheme:"//"},twitter:{baseUrl:"https://twitter.com/",hashtagSearchUrl:"search?q=",target:"_blank",scheme:"https://"},instagram:{baseUrl:"http://instagram.com/",hashtagSearchUrl:"explore/tags/",target:"_blank",scheme:"http://"},github:{baseUrl:"https://github.com/",hashtagSearchUrl:null,target:"_blank",scheme:"https://"}},g={mentions:!0,hashtags:!1,urls:!0,linkTo:"local",target:"_self",scheme:"//"},j=a.extend(g,c),k=b.html(),l=/(?:(?:http|https):\/\/)?([-a-zA-Z0-9.]{2,256}\.[a-z]{2,4})\b(?:\/[-a-zA-Z0-9@:%_\+.~#?&\/\/=]*)?((\?|\/)(.*))?/gi;return j.urls&&(m=k.match(l),m&&(k=e(m,b,j))),j.mentions&&f(k)&&(k=h(k,d[j.linkTo].baseUrl,b,j)),j.hashtags&&(k=i(k,d[j.linkTo],b)),k}function c(a){var b=/ed2k|ftp|http|https|news|nntp/;return!!a.match(b)}function d(a){var b=a.match(/dailymotion\.com\/embed/gi);if(b=null!==b)return!0;var c=a.match(/w\.soundcloud\.com\/player|api\.soundcloud\.com/gi);if(c=null!==c)return!0;var d=a.match(/player\.vimeo\.com\/video/gi);if(d=null!==d)return!0;var e=a.match(/cache\.vevo\.com/gi);if(e)return!0;var f=a.match(/youtube\.com\/embed|youtube\-nocookie\.com\/embed/gi);return f=null!==f,!!f}function e(b,e,f){var g=e.html();return a.each(b,function(a,b){var h=d(b),i=c(b)?"":f.scheme;h||0!==e.find('a[href="'+i+this+'"]').length||(g=g.replace(this,''+this+""))}),g}function f(a){var b=/@(\w+)/gi,c=a.match(b);return!!c}function g(a){var b=/@(\w+)/gi,c=a.match(b);return c?c:null}function h(b,c,d,e){if(!d.hasClass("parsed")&&!d.hasClass("autoLinked")){var f=g(b);f&&a.each(f,function(a,b){var f=b.replace("@",""),g=''+b+"",h=str_replace(b,g,d.html());d.html(h)})}}function i(a,b,c){if("undefined"!=typeof a)return null===b.hashtagSearchUrl?a:0===c.find('a[href="'+this+'"]').length?a.replace(/(^|\s|\(|>)#((\w|[\u00A1-\uFFFF])+)/g,"$1#$2"):void 0}a.fn.autolink=function(c){return this.each(function(){var d=a(this),e=b(d,c);d.html(e)})}}(jQuery);
<commit_msg>FIXED:  URL Linking<commit_after>/**
 * jQuery AutoLink
 *
 * @link      https://github.com/MarQuisKnox/jQuery.AutoLink
 * @license   MIT
 *
 * @copyright	2013 - 2015 Andreas Savvides et al
 * @copyright	2014 - 2017 MarQuis Knox
*/!function($){"use strict";function _linkify(e,a){var r,n={local:{baseUrl:"//"+window.location.host+"/",hashtagSearchUrl:"search/",target:"_self",scheme:"//"},twitter:{baseUrl:"https://twitter.com/",hashtagSearchUrl:"search?q=",target:"_blank",scheme:"https://"},instagram:{baseUrl:"http://instagram.com/",hashtagSearchUrl:"explore/tags/",target:"_blank",scheme:"http://"},github:{baseUrl:"https://github.com/",hashtagSearchUrl:null,target:"_blank",scheme:"https://"}},t={mentions:!0,hashtags:!1,urls:!0,linkTo:"local",target:"_self",scheme:"//"},i=$.extend(t,a),s=e.html(),l=URL_REGEX;return i.hashtags&&(s=_linkifyHashtags(s,n[i.linkTo],e)),i.urls&&(r=s.match(l))&&(s=_linkifyUrls(r,e,i)),i.mentions&&_isMention(s)&&(s=_linkifyMentions(s,n[i.linkTo].baseUrl,e,i)),s}function _hasScheme(e){var a=/ed2k|ftp|http|https|news|nntp/;return!!e.match(a)}function _isEmbed(e){var a=e.match(/dailymotion\.com\/embed/gi);if(a=null!==a)return!0;var r=e.match(/w\.soundcloud\.com\/player|api\.soundcloud\.com/gi);if(r=null!==r)return!0;var n=e.match(/player\.vimeo\.com\/video/gi);if(n=null!==n)return!0;if(e.match(/cache\.vevo\.com/gi))return!0;var t=e.match(/youtube\.com\/embed|youtube\-nocookie\.com\/embed/gi);return!!(t=null!==t)}function _linkifyUrls(e,a,r){var n=a.html();return e=array_unique(e),$.each(e,function(e,a){var t=_isEmbed(a),i=_hasScheme(a)?"":r.scheme,s=a.trim();s=s.replace("
",""),!t&&a.length>0&&(n=n.split(new RegExp(a)).join(''+a+""))}),n}function _isMention(e){var a=/(?:(^|[ ]|\n|
))\B@([a-zA-Z0-9-.]+)/gi;return!!e.match(a)}function _getMentions(e){var a=/(?:(^|[ ]|\n|
))\B@([a-zA-Z0-9-.]+)/gi,r=e.match(a);return r||null}function _linkifyMentions(e,a,r,n){var t=e;if(!r.hasClass("parsed")&&!r.hasClass("autoLinked")&&!r.hasClass("linkified")){var i=_getMentions(e);i&&$.each(i,function(e,i){var s=i.trim().replace("@","");s=s.replace("
","");var l=''+i+"";t=t.replaceAllByRegex(/(?:(^|[ ]|\n|
))\B@([a-zA-Z0-9-.]+)/,l,r.html())})}return t}function _linkifyHashtags(e,a,r){if(void 0!==e)return null===a.hashtagSearchUrl?e:e.replace(/(^|\s|\(|>)#([a-zA-Z0-9-.]+)/g,"$1#$2")}function array_unique(e){var a="",r={},n="";for(a in e)e.hasOwnProperty(a)&&!1===function(e,a){var r="";for(r in a)if(a.hasOwnProperty(r)&&a[r]+""==e+"")return r;return!1}(n=e[a],r)&&(r[a]=n);return r}function array_walk(array,funcname,userdata){var key,value,ini;if(!array||"object"!=typeof array)return!1;if("object"==typeof array&&array.change_key_case)return arguments.length>2?array.walk(funcname,userdata):array.walk(funcname);try{if("function"==typeof funcname)for(key in array)arguments.length>2?funcname(array[key],key,userdata):funcname(array[key],key);else if("string"==typeof funcname)if(this.php_js=this.php_js||{},this.php_js.ini=this.php_js.ini||{},!(ini=this.php_js.ini["phpjs.no-eval"])||0===parseInt(ini.local_value,10)||ini.local_value.toLowerCase&&"off"===ini.local_value.toLowerCase())if(arguments.length>2)for(key in array)eval(funcname+"(array[key], key, userdata)");else for(key in array)eval(funcname+"(array[key], key)");else if(arguments.length>2)for(key in array)this.window[funcname](array[key],key,userdata);else for(key in array)this.window[funcname](array[key],key);else{if(!funcname||"object"!=typeof funcname||2!==funcname.length)return!1;var obj=funcname[0],func=funcname[1];if(arguments.length>2)for(key in array)obj[func](array[key],key,userdata);else for(key in array)obj[func](array[key],key)}}catch(e){return!1}return!0}function trim(e,a){var r=[" ","\n","\r","\t","\f","\v"," "," "," "," "," "," "," "," "," "," "," "," ","","\u2028","\u2029","　"].join(""),n=0,t=0;for(e+="",a&&(r=(a+"").replace(/([[\]().?/*{}+$^:])/g,"$1")),n=e.length,t=0;t<n;t++)if(-1===r.indexOf(e.charAt(t))){e=e.substring(t);break}for(t=(n=e.length)-1;t>=0;t--)if(-1===r.indexOf(e.charAt(t))){e=e.substring(0,t+1);break}return-1===r.indexOf(e.charAt(0))?e:""}function preg_quote(e,a){return String(e).replace(new RegExp("[.\\\\+*?\\[\\^\\]$(){}=!<>|:\\"+(a||"")+"-]","g"),"\\$&")}var URL_REGEX=/(<a href=")?(?:(^|[ ]|\n|
))(?:(?:http|https):\/\/)?([-a-zA-Z0-9.]{2,256}\.[a-z]{2,4})\b(?:\/[-a-zA-Z0-9@:%_\+.~#?&\/\/=]*)?((\?|\/)(.*))?/gi;$.fn.autolink=function(e){return this.each(function(){var a=$(this),r=_linkify(a,e);a.html(r)})},String.prototype.replaceAllByRegex=function(e,a){return this.replace(new RegExp(e,"g"),a)},String.prototype.replaceAll=function(e,a){return this.split(e).join(a)}}(jQuery);
<|endoftext|>


<commit_before>angular.module('olwResource', ['olwConfService', 'ngRoute', 'ngAnimate', 'hmTouchEvents', 'ng', 'seo'])

.config(['$routeProvider', function($routeProvider) {
	$routeProvider.when('/resource/:nameWithId', {
		controller: 'ResourceCtrl',
		templateUrl: 'resource/resource.tpl.html'
	});
}])

.directive('olwAttr', [function() {
	return function(scope, element, attrs) {
		attrs.$observe('olwAttr', function(at) {
			var attr = scope.$eval(at);
			for (var key in attr) {
				if (attr.hasOwnProperty(key) && attr[key]) {
					element.attr(key, key);
				}
			}
		});
	};
}])

.controller('ResourceCtrl', ['$scope', '$http', '$routeParams', '$timeout', 'olwConf', function($scope, $http, $routeParams, $timeout, olwConf) {
	var id = $routeParams.nameWithId.substring($routeParams.nameWithId.lastIndexOf('-') + 1)
	  , start = 1;

	if (localStorage.getItem(id)) {
		start = JSON.parse(localStorage.getItem(id)).current;
	}

	$scope.$parent.title = 'Material';
	$scope.media = [];

	$http
		.jsonp(olwConf.api + '/resource-detailview/' + olwConf.index + id + '?callback=JSON_CALLBACK')
		.success(function(result) {
			var slug;
			$scope.$parent.title = $scope.title = result.name;

			// populate template with (merely) static data
			$scope.users = result.users.map(olwConf.transformUser);
			$scope.date = parseInt(result.creationDate, 10);
			$scope.code = result.code.split('-');
			$scope.type = result.characteristicType;
			if (result.areas) {
				$scope.areas = result.areas.map(function(area) { return { title: area.code, url: olwConf.urlFor(area.code, area.id) }; });
				$scope.$parent.slug = $scope.slug = olwConf.slug($scope.areas[0].title);
			}
			if (result.semesters) {
				$scope.terms = result.semesters.map(function(term) {
					return { year : term.year, part : 'SEMESTER_PART_' + term.part };
				});
			}
			$scope.related = result.externalResources;
			$scope.description = result.description;
			$scope.sources = olwConf.sources(result.uuid, $scope.type);
			delete $scope.sources.audio;
			$scope.downloadUrl = olwConf.downloadUrl(result.uuid, $scope.type, $scope.title);
			$scope.canvasShow = olwConf.resourceMainType($scope.type);
			if (result.childs.length > 0) {
				angular.extend($scope.sources, {pdf: [olwConf.uuidUrl(result.childs[0]) + '/13.pdf']});
			}
			$scope.licenseTranslationParams = {
				title: $scope.title,
				users: $scope.users.join(', ')
			};

			if ($scope.canvasShow == 'pdf' || result.childs.length > 0) {
				$scope.canvasShow = 'pdf';
				$('#pdf').PDFDoc({
					source: $scope.sources.pdf[0],
					page: start
				});
			}

			// if tabs (video | pdf | audio) are switched, rebuild the media list
			// to only contain the elements that are currently present
			$scope.$watch('canvasShow', function(now, old) {
				var src, elem;
				// remove possible timeupdate listeners
				if ('video' in $scope.sources && 'lecturer' in $scope.sources) {
					document.getElementById('video').removeEventListener('timeupdate', $scope.sync);
				}
				// add all sources to media, pause them
				$scope.media = [];
				for (src in $scope.sources) {
					if ($scope.sources.hasOwnProperty(src) && ['video', 'lecturer', 'audio'].indexOf(src) > -1) {
						elem = document.getElementById(src);
						elem.pause();
						$scope.media.push(elem);
					}
				}
				// sync sources
				if (old == 'audio') {
					$scope.jump(Math.max(0, document.getElementById('audio').currentTime - 7));
				} else if (old == 'video') {
					if ('video' in $scope.sources) {
						$scope.jump(document.getElementById('video').currentTime);
					} else {
						$scope.jump(document.getElementById('lecturer').currentTime);
					}
				}
				// remove irrelevant sources from media
				// (in fact: rebuild media using only relevant sources)
				switch (now) {
					case 'video':
						$scope.media = [];
						for (src in $scope.sources) {
							if ($scope.sources.hasOwnProperty(src) && ['video', 'lecturer'].indexOf(src) > -1) {
								$scope.media.push(document.getElementById(src));
							}
						}
						if ('video' in $scope.sources && 'lecturer' in $scope.sources) {
							document.getElementById('video').addEventListener('timeupdate', $scope.sync);
						}
						break;
					case 'pdf':
						$scope.media = [];
						break;
					case 'audio':
						$scope.media = [document.getElementById('audio')];
						break;
					default:
						break;
				}
			});

			olwConf.fetchChapters(result.uuid, $scope.type, function(err, chapters) {
				if (!err && chapters) {
					$scope.chapters = chapters.map(function(chapter) {
						return {
							title: chapter.kapitel,
							from: chapter.startZeit,
							length: chapter.laenge,
							fromRendered: (new Date(new Date(0).setHours(0)).setSeconds(chapter.startZeit)),
							active: false
						};
					});
				}
				$scope.htmlReady();
			});
			if (result.collections) {
				$scope.collections = result.collections.map(function(collection) { return { title: collection.name, url: olwConf.urlFor(collection.name, collection.id) }; });

				$http.jsonp(olwConf.api + '/collection-detailview/' + result.collections[0].id + '?callback=JSON_CALLBACK')
					.success(function(result) {
						// find next if id is top level
						angular.forEach(result.collectionElements, function(collectionElement, index) {
							if (collectionElement == id) {
								// i'm top level
								if (index + 1 < result.collectionElements.length) {
									// there are more
									if (result.resources.hasOwnProperty(result.collectionElements[index+1])) {
										// next is a resource
										$scope.next = result.collectionElements[index+1];
									} else {
										// next is a rubric
										$scope.next = result.rubrics[result.collectionElements[index+1]].resources[0];
									}
								} else {
									// i'm the last. no next resource
									$scope.next = false;
								}
							}
						});
						// find next if id is in rubric
						if ($scope.next === undefined) {
							// i'm not top level - see if i'm in a rubric
							angular.forEach(result.rubrics, function(rubric) {
								var index = rubric.resources.indexOf(id)
								  , rubricIndex = result.collectionElements.indexOf(rubric.id);
								if (index > -1) {
									// i'm inside this rubric
									if (index + 1 < rubric.resources.length) {
										// there are more
										$scope.next = rubric.resources[index+1];
									} else {
										// i'm the last one
										if (rubricIndex + 1 < resource.collectionElements.length) {
											// there are more rubrics
											$scope.next = resource.rubrics[resource.collectionElements[rubricIndex + 1]].resources[0];
										} else {
											// nothing more. should not have happened.
											$scope.next = false;
										}
									}
								}
							});
						}
					});
			}
		});

	$scope.jump = function(to) {
		$scope.media.forEach(function(elem) {
			// 0 == HAVE_NOTHING
			// https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement
			if (elem.readyState !== 0) {
				if (elem.tagName == 'AUDIO') {
					elem.currentTime = to + 7;
				} else {
					elem.currentTime = to;
				}
			}
		});
	};

	$scope.sync = function(args) {
		var elem = document.getElementById('lecturer');
		if (isNaN(elem.duration)) {
			delete $scope.sources.lecturer;
		} else {
			elem.currentTime = args.target.currentTime;
		}
	};

	$scope.$on('$locationChangeStart', function(event, next) {
		if (next.indexOf('collection') > -1) {
			$scope.$parent.animation = 'to-left';
		} else {
			$scope.$parent.animation = 'none';
		}
	});

	// ===== pulldown menu ==========================================
	$scope.showPulldownMenu = false;
	$scope.drag = function(event) {
		if (!$scope.showPulldownMenu && $(window).scrollTop() === 0 && event.gesture.deltaY > 100) {
			$scope.showPulldownMenu = true;
		} else if ($scope.showPulldownMenu && event.gesture.deltaY < -100) {
			$scope.showPulldownMenu = false;
		}
	};
}]);<commit_msg>replaced olwConf with its proxied services/filters<commit_after>angular.module('olwResource', ['olwConfigurationService', 'olwSectionsService', 'olwCdnService', 'olwUsernameFilter', 'ngRoute', 'ngAnimate', 'hmTouchEvents', 'ng', 'seo'])

.config(['$routeProvider', function($routeProvider) {
	$routeProvider.when('/resource/:nameWithId', {
		controller: 'ResourceCtrl',
		templateUrl: 'resource/resource.tpl.html'
	});
}])

.directive('olwAttr', [function() {
	return function(scope, element, attrs) {
		attrs.$observe('olwAttr', function(at) {
			var attr = scope.$eval(at);
			for (var key in attr) {
				if (attr.hasOwnProperty(key) && attr[key]) {
					element.attr(key, key);
				}
			}
		});
	};
}])

.controller('ResourceCtrl', ['$scope', '$http', '$routeParams', '$timeout', '$filter', 'conf', 'sections', 'cdn', function($scope, $http, $routeParams, $timeout, $filter, conf, sections, cdn) {
	var id = $routeParams.nameWithId.substring($routeParams.nameWithId.lastIndexOf('-') + 1)
	  , start = 1;

	if (localStorage.getItem(id)) {
		start = JSON.parse(localStorage.getItem(id)).current;
	}

	$scope.$parent.title = 'Material';
	$scope.media = [];

	$http
		.jsonp(conf.urls.api + '/resource-detailview/' + conf.urls.apiIndexPathElement + id + '?callback=JSON_CALLBACK')
		.success(function(result) {
			var slug;
			$scope.$parent.title = $scope.title = result.name;

			// populate template with (merely) static data
			$scope.users = result.users.map($filter('username'));
			$scope.date = parseInt(result.creationDate, 10);
			$scope.code = result.code.split('-');
			$scope.type = result.characteristicType;
			if (result.areas) {
				$scope.areas = result.areas.map(function(area) { return { title: area.code, url: sections.getPathElement(area.code, area.id) }; });
				$scope.$parent.slug = $scope.slug = sections.getSlugForArea($scope.areas[0].title);
			}
			if (result.semesters) {
				$scope.terms = result.semesters.map(function(term) {
					return { year : term.year, part : 'SEMESTER_PART_' + term.part };
				});
			}
			$scope.related = result.externalResources;
			$scope.description = result.description;
			$scope.sources = cdn.getSourcesForUuid(result.uuid, $scope.type);
			delete $scope.sources.audio;
			$scope.downloadUrl = cdn.getDownloadUrlForUuid(result.uuid, $scope.type, $scope.title);
			$scope.canvasShow = cdn.getNatureOfCharacteristicType($scope.type);
			if (result.childs.length > 0) {
				angular.extend($scope.sources, {pdf: [cdn.getUrlForUuid(result.childs[0]) + '/13.pdf']});
			}
			$scope.licenseTranslationParams = {
				title: $scope.title,
				users: $scope.users.join(', ')
			};

			if ($scope.canvasShow == 'pdf' || result.childs.length > 0) {
				$scope.canvasShow = 'pdf';
				$('#pdf').PDFDoc({
					source: $scope.sources.pdf[0],
					page: start
				});
			}

			// if tabs (video | pdf | audio) are switched, rebuild the media list
			// to only contain the elements that are currently present
			$scope.$watch('canvasShow', function(now, old) {
				var src, elem;
				// remove possible timeupdate listeners
				if ('video' in $scope.sources && 'lecturer' in $scope.sources) {
					document.getElementById('video').removeEventListener('timeupdate', $scope.sync);
				}
				// add all sources to media, pause them
				$scope.media = [];
				for (src in $scope.sources) {
					if ($scope.sources.hasOwnProperty(src) && ['video', 'lecturer', 'audio'].indexOf(src) > -1) {
						elem = document.getElementById(src);
						elem.pause();
						$scope.media.push(elem);
					}
				}
				// sync sources
				if (old == 'audio') {
					$scope.jump(Math.max(0, document.getElementById('audio').currentTime - 7));
				} else if (old == 'video') {
					if ('video' in $scope.sources) {
						$scope.jump(document.getElementById('video').currentTime);
					} else {
						$scope.jump(document.getElementById('lecturer').currentTime);
					}
				}
				// remove irrelevant sources from media
				// (in fact: rebuild media using only relevant sources)
				switch (now) {
					case 'video':
						$scope.media = [];
						for (src in $scope.sources) {
							if ($scope.sources.hasOwnProperty(src) && ['video', 'lecturer'].indexOf(src) > -1) {
								$scope.media.push(document.getElementById(src));
							}
						}
						if ('video' in $scope.sources && 'lecturer' in $scope.sources) {
							document.getElementById('video').addEventListener('timeupdate', $scope.sync);
						}
						break;
					case 'pdf':
						$scope.media = [];
						break;
					case 'audio':
						$scope.media = [document.getElementById('audio')];
						break;
					default:
						break;
				}
			});

			cdn.getChaptersForUuid(result.uuid, $scope.type, function(err, chapters) {
				if (!err && chapters) {
					$scope.chapters = chapters.map(function(chapter) {
						return {
							title: chapter.kapitel,
							from: chapter.startZeit,
							length: chapter.laenge,
							fromRendered: (new Date(new Date(0).setHours(0)).setSeconds(chapter.startZeit)),
							active: false
						};
					});
				}
				$scope.htmlReady();
			});
			if (result.collections) {
				$scope.collections = result.collections.map(function(collection) { return { title: collection.name, url: sections.getPathElement(collection.name, collection.id) }; });

				$http.jsonp(conf.urls.api + '/collection-detailview/' + result.collections[0].id + '?callback=JSON_CALLBACK')
					.success(function(result) {
						// find next if id is top level
						angular.forEach(result.collectionElements, function(collectionElement, index) {
							if (collectionElement == id) {
								// i'm top level
								if (index + 1 < result.collectionElements.length) {
									// there are more
									if (result.resources.hasOwnProperty(result.collectionElements[index+1])) {
										// next is a resource
										$scope.next = result.collectionElements[index+1];
									} else {
										// next is a rubric
										$scope.next = result.rubrics[result.collectionElements[index+1]].resources[0];
									}
								} else {
									// i'm the last. no next resource
									$scope.next = false;
								}
							}
						});
						// find next if id is in rubric
						if ($scope.next === undefined) {
							// i'm not top level - see if i'm in a rubric
							angular.forEach(result.rubrics, function(rubric) {
								var index = rubric.resources.indexOf(id)
								  , rubricIndex = result.collectionElements.indexOf(rubric.id);
								if (index > -1) {
									// i'm inside this rubric
									if (index + 1 < rubric.resources.length) {
										// there are more
										$scope.next = rubric.resources[index+1];
									} else {
										// i'm the last one
										if (rubricIndex + 1 < resource.collectionElements.length) {
											// there are more rubrics
											$scope.next = resource.rubrics[resource.collectionElements[rubricIndex + 1]].resources[0];
										} else {
											// nothing more. should not have happened.
											$scope.next = false;
										}
									}
								}
							});
						}
					});
			}
		});

	$scope.jump = function(to) {
		$scope.media.forEach(function(elem) {
			// 0 == HAVE_NOTHING
			// https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement
			if (elem.readyState !== 0) {
				if (elem.tagName == 'AUDIO') {
					elem.currentTime = to + 7;
				} else {
					elem.currentTime = to;
				}
			}
		});
	};

	$scope.sync = function(args) {
		var elem = document.getElementById('lecturer');
		if (isNaN(elem.duration)) {
			delete $scope.sources.lecturer;
		} else {
			elem.currentTime = args.target.currentTime;
		}
	};

	$scope.$on('$locationChangeStart', function(event, next) {
		if (next.indexOf('collection') > -1) {
			$scope.$parent.animation = 'to-left';
		} else {
			$scope.$parent.animation = 'none';
		}
	});

	// ===== pulldown menu ==========================================
	$scope.showPulldownMenu = false;
	$scope.drag = function(event) {
		if (!$scope.showPulldownMenu && $(window).scrollTop() === 0 && event.gesture.deltaY > 100) {
			$scope.showPulldownMenu = true;
		} else if ($scope.showPulldownMenu && event.gesture.deltaY < -100) {
			$scope.showPulldownMenu = false;
		}
	};
}]);<|endoftext|>


<commit_before>import path from 'path';
const config = new Map();

/* istanbul ignore next */
// Looks like you can't ignore a file but you can ignore a function, we don't want coverage here.
(function defineConfig() {
  const NODE_ENV = process.env.NODE_ENV;

  // Default to production unless overridden.
  config.set('env', NODE_ENV || 'production');

  config.set('basePath', path.resolve(__dirname, '../'));

  // This is the host / port for running as production.
  config.set('serverHost', process.env.SERVER_HOST || '127.0.0.1');
  config.set('serverPort', process.env.SERVER_PORT || 4000);

  // This is the host / port for the development instance.
  config.set('devServerHost', process.env.SERVER_HOST || '127.0.0.1');
  config.set('devServerPort', process.env.SERVER_PORT || 3000);

  // This is the host / port for the webpack dev server.
  config.set('webpackServerHost', process.env.WEBPACK_SERVER_HOST || '127.0.0.1');
  config.set('webpackServerPort', process.env.WEBPACK_SERVER_PORT || 3001);

  config.set('apiHost',
    process.env.API_HOST ||
      (NODE_ENV === 'development' ?
        'https://addons-dev.allizom.org' : 'https://addons.mozilla.org'));

  config.set('apiPath', process.env.API_PATH || '/api/v3');
  config.set('apiBase', config.get('apiHost') + config.get('apiPath'));

  const CSP = {
    directives: {
      connectSrc: ["'self'", config.get('apiHost')],
      defaultSrc: ["'self'"],
      scriptSrc: ["'self'"],
      styleSrc: ["'self'"],
      reportUri: '/__cspreport__',
    },

    // Set to true if you only want browsers to report errors, not block them
    reportOnly: false,

    // Set to true if you want to blindly set all headers: Content-Security-Policy,
    // X-WebKit-CSP, and X-Content-Security-Policy.
    setAllHeaders: false,

    // Set to true if you want to disable CSP on Android where it can be buggy.
    disableAndroid: false,
  };

  const WEBPACK_HOST =
      `http://${config.get('webpackServerHost')}:${config.get('webpackServerPort')}`;

  if (config.get('env') === 'development') {
    CSP.directives.scriptSrc.push(WEBPACK_HOST);
    CSP.directives.styleSrc.push('blob:');
    CSP.directives.connectSrc.push(WEBPACK_HOST);
    CSP.reportOnly = true;
  }

  config.set('CSP', CSP);

  // This is the list of apps allowed to run.
  const validAppNames = ['search', 'disco'];
  config.set('validAppNames', validAppNames);

  // Create a list of apps to build targets for.
  const appName = process.env.APP_NAME;
  if (validAppNames.indexOf(appName) > -1) {
    config.set('appsBuildList', [appName]);
    config.set('currentApp', appName);
  } else {
    config.set('appsBuildList', validAppNames);
    config.set('currentApp', null);
  }
}());

export default config;
<commit_msg>Use includes in place of indexOf<commit_after>import path from 'path';
const config = new Map();

/* istanbul ignore next */
// Looks like you can't ignore a file but you can ignore a function, we don't want coverage here.
(function defineConfig() {
  const NODE_ENV = process.env.NODE_ENV;

  // Default to production unless overridden.
  config.set('env', NODE_ENV || 'production');

  config.set('basePath', path.resolve(__dirname, '../'));

  // This is the host / port for running as production.
  config.set('serverHost', process.env.SERVER_HOST || '127.0.0.1');
  config.set('serverPort', process.env.SERVER_PORT || 4000);

  // This is the host / port for the development instance.
  config.set('devServerHost', process.env.SERVER_HOST || '127.0.0.1');
  config.set('devServerPort', process.env.SERVER_PORT || 3000);

  // This is the host / port for the webpack dev server.
  config.set('webpackServerHost', process.env.WEBPACK_SERVER_HOST || '127.0.0.1');
  config.set('webpackServerPort', process.env.WEBPACK_SERVER_PORT || 3001);

  config.set('apiHost',
    process.env.API_HOST ||
      (NODE_ENV === 'development' ?
        'https://addons-dev.allizom.org' : 'https://addons.mozilla.org'));

  config.set('apiPath', process.env.API_PATH || '/api/v3');
  config.set('apiBase', config.get('apiHost') + config.get('apiPath'));

  const CSP = {
    directives: {
      connectSrc: ["'self'", config.get('apiHost')],
      defaultSrc: ["'self'"],
      scriptSrc: ["'self'"],
      styleSrc: ["'self'"],
      reportUri: '/__cspreport__',
    },

    // Set to true if you only want browsers to report errors, not block them
    reportOnly: false,

    // Set to true if you want to blindly set all headers: Content-Security-Policy,
    // X-WebKit-CSP, and X-Content-Security-Policy.
    setAllHeaders: false,

    // Set to true if you want to disable CSP on Android where it can be buggy.
    disableAndroid: false,
  };

  const WEBPACK_HOST =
      `http://${config.get('webpackServerHost')}:${config.get('webpackServerPort')}`;

  if (config.get('env') === 'development') {
    CSP.directives.scriptSrc.push(WEBPACK_HOST);
    CSP.directives.styleSrc.push('blob:');
    CSP.directives.connectSrc.push(WEBPACK_HOST);
    CSP.reportOnly = true;
  }

  config.set('CSP', CSP);

  // This is the list of apps allowed to run.
  const validAppNames = ['search', 'disco'];
  config.set('validAppNames', validAppNames);

  // Create a list of apps to build targets for.
  const appName = process.env.APP_NAME;
  if (validAppNames.includes(appName)) {
    config.set('appsBuildList', [appName]);
    config.set('currentApp', appName);
  } else {
    config.set('appsBuildList', validAppNames);
    config.set('currentApp', null);
  }
}());

export default config;
<|endoftext|>


<commit_before>var rootDir = process.env.NODE_ENV === 'production' ? '/home/deploy/current' : process.cwd();

var gravatar = require(rootDir + '/server/services/gravatar');

var mongoose = require('mongoose');
var User = mongoose.model('User');

var self = module.exports = {

	createUser: function(email, callback) {

		var query = User.findOne({ 'email': email });

		query.exec(function(err, oldUser) {
			if (oldUser) {
				console.log('Preexisting user.'.yellow);
				if(typeof callback == 'function') { callback(oldUser); }
			} else {
				gravatar.getGravatar(email, { size: 200 }, function(userGravatar) {
					var newUser = new User();
					newUser.email = email;
					newUser.profileJSON = userGravatar.profileJSON;
					newUser.avatarURL = userGravatar.avatarURL;
					newUser.reputation = 100;
					newUser.save(function(err) {
						if (err) {
							throw err;
						}
						console.log('New user.'.yellow);
						if(typeof callback == 'function') { callback(newUser); }
					});
				});
			}
		});

	},

	list: function(callback) {
		User.find({}, function(err, users) {
			callback(users);
		});
	},

	getRankedUsers: function(callback) {
		User.find({}, function(err, users) {
			callback(users.sort('field -reputation'));
		});
	}

};<commit_msg>adding concept for updating reputation based on speaking time<commit_after>var rootDir = process.env.NODE_ENV === 'production' ? '/home/deploy/current' : process.cwd();

var gravatar = require(rootDir + '/server/services/gravatar');

var mongoose = require('mongoose');
var User = mongoose.model('User');
var topReputation = 1000;

var self = module.exports = {

	createUser: function(email, callback) {

		var query = User.findOne({ 'email': email });

		query.exec(function(err, oldUser) {
			if (oldUser) {
				console.log('Preexisting user.'.yellow);
				if(typeof callback == 'function') { callback(oldUser); }
			} else {
				gravatar.getGravatar(email, { size: 200 }, function(userGravatar) {
					var newUser = new User();
					newUser.email = email;
					newUser.profileJSON = userGravatar.profileJSON;
					newUser.avatarURL = userGravatar.avatarURL;
					newUser.reputation = 100;
					newUser.save(function(err) {
						if (err) {
							throw err;
						}
						console.log('New user.'.yellow);
						if(typeof callback == 'function') { callback(newUser); }
					});
				});
			}
		});

	},

	list: function(callback) {
		User.find({}, function(err, users) {
			callback(users);
		});
	},

	getRankedUsers: function(callback) {
		User.find({}, function(err, users) {
			callback(users.sort('field -reputation'));
		});
	}

	updateUserRep: function(email, reputation, time, callback) {
		if ( time < 15 ) {
			// User was yanked.  Decrease by 5%
			reputation = (reputation * .95);
		} else if ( time == 15) {
			// User only spoke for 15 seconds.
			// No change to reputation necessary.
			reputation = reputation;
		} else {
			// User was given additional time.
			// First, get the number of 5 second increments
			addedTime = floor((time - 15) / 5);
			// Add a percentage of current reputation based on
			// the number of 5 second intervals the speaker
			// was given by their peers
			reputation = ((topReputation / ( reputation * 4 )) * addedTime);
		}
		User.update({ email: email }, {reputation: reputation}, {multi: true}, function(err, users){
			callback(user);
		});
	}

};<|endoftext|>


<commit_before>'use strict';

function repo_init(){
    second();

    // Setup hands.
    var hands = [
      'hours-hand',
      'minutes-hand',
      'seconds-hand',
    ];
    for(var hand in hands){
        document.getElementById(hands[hand]).style.background = '#' + core_random_hex();
        document.getElementById(hands[hand]).style.height = '10px';
        document.getElementById(hands[hand]).style.left = '50%';
        document.getElementById(hands[hand]).style.position = 'fixed';
        document.getElementById(hands[hand]).style.top = '50%';
        document.getElementById(hands[hand]).style.transformOrigin = 'left';
        document.getElementById(hands[hand]).style.width = (hand * 100 + 100) + 'px';
    }

    window.setInterval(
      second,
      1000
    );
}

function rotate_hand(id, percent){
    document.getElementById(id).style.transform =
      'rotate(' + (360 * percent - 90) + 'deg)';
}

function second(){
    var date = time_timestamp_to_date();

    document.getElementById('time').innerHTML = time_format_date({
      'date': date,
    });

    if(date['hour'] > 11){
        date['hour'] -= 12;
    }
    date['hour'] = date['hour'] / 12;
    date['minute'] = date['minute'] / 60;
    date['second'] = date['second'] / 60;

    rotate_hand(
      'hours-hand',
      date['hour'] + date['minute'] / 12
    );
    rotate_hand(
      'minutes-hand',
      date['minute'] + date['second'] / 60
    );
    rotate_hand(
      'seconds-hand',
      date['second']
    );
}
<commit_msg>added core_repo_init() usage<commit_after>'use strict';

function repo_init(){
    core_repo_init({
      'title': 'Clock.htm',
    });

    second();

    // Setup hands.
    var hands = [
      'hours-hand',
      'minutes-hand',
      'seconds-hand',
    ];
    for(var hand in hands){
        document.getElementById(hands[hand]).style.background = '#' + core_random_hex();
        document.getElementById(hands[hand]).style.height = '10px';
        document.getElementById(hands[hand]).style.left = '50%';
        document.getElementById(hands[hand]).style.position = 'fixed';
        document.getElementById(hands[hand]).style.top = '50%';
        document.getElementById(hands[hand]).style.transformOrigin = 'left';
        document.getElementById(hands[hand]).style.width = (hand * 100 + 100) + 'px';
    }

    window.setInterval(
      second,
      1000
    );
}

function rotate_hand(id, percent){
    document.getElementById(id).style.transform =
      'rotate(' + (360 * percent - 90) + 'deg)';
}

function second(){
    var date = time_timestamp_to_date();

    document.getElementById('time').innerHTML = time_format_date({
      'date': date,
    });

    if(date['hour'] > 11){
        date['hour'] -= 12;
    }
    date['hour'] = date['hour'] / 12;
    date['minute'] = date['minute'] / 60;
    date['second'] = date['second'] / 60;

    rotate_hand(
      'hours-hand',
      date['hour'] + date['minute'] / 12
    );
    rotate_hand(
      'minutes-hand',
      date['minute'] + date['second'] / 60
    );
    rotate_hand(
      'seconds-hand',
      date['second']
    );
}
<|endoftext|>


<commit_before>!function(e,t){"use strict";"function"==typeof define&&define.amd?define(["angular"],t):e.hasOwnProperty("angular")?t(e.angular):"object"==typeof exports&&(module.exports=t(require("angular")))}(this,function(e){"use strict";function t(t){return function(){var n="ngStorage-";this.setKeyPrefix=function(e){if("string"!=typeof e)throw new TypeError("[ngStorage] - "+t+"Provider.setKeyPrefix() expects a String.");n=e};var r=e.toJson,o=e.fromJson;this.setSerializer=function(e){if("function"!=typeof e)throw new TypeError("[ngStorage] - "+t+"Provider.setSerializer expects a function.");r=e},this.setDeserializer=function(e){if("function"!=typeof e)throw new TypeError("[ngStorage] - "+t+"Provider.setDeserializer expects a function.");o=e},this.get=function(e){return o(window[t].getItem(n+e))},this.set=function(e,o){return window[t].setItem(n+e,r(o))},this.$get=["$rootScope","$window","$log","$timeout","$document",function(i,a,s,u,c){function l(e){var t;try{t=a[e]}catch(n){t=!1}if(t&&"localStorage"===e){var r="__"+Math.round(1e7*Math.random());try{localStorage.setItem(r,r),localStorage.removeItem(r)}catch(n){t=!1}}return t}var f,g,h=n.length,d=l(t)||(s.warn("This browser does not support Web Storage!"),{setItem:e.noop,getItem:e.noop,removeItem:e.noop}),p={$default:function(t){for(var n in t)e.isDefined(p[n])||(p[n]=e.copy(t[n]));return p.$sync(),p},$reset:function(e){for(var t in p)"$"===t[0]||delete p[t]&&d.removeItem(n+t);return p.$default(e)},$sync:function(){for(var e,t=0,r=d.length;r>t;t++)(e=d.key(t))&&n===e.slice(0,h)&&(p[e.slice(h)]=o(d.getItem(e)))},$apply:function(){var t;if(g=null,!e.equals(p,f)){t=e.copy(f),e.forEach(p,function(o,i){e.isDefined(o)&&"$"!==i[0]&&(d.setItem(n+i,r(o)),delete t[i])});for(var o in t)d.removeItem(n+o);f=e.copy(p)}}};return p.$sync(),f=e.copy(p),i.$watch(function(){g||(g=u(p.$apply,100,!1))}),a.addEventListener&&a.addEventListener("storage",function(t){if(t.key){var r=c[0];r.hasFocus&&r.hasFocus()||n!==t.key.slice(0,h)||(t.newValue?p[t.key.slice(h)]=o(t.newValue):delete p[t.key.slice(h)],f=e.copy(p),i.$apply())}}),a.addEventListener&&a.addEventListener("beforeunload",function(){p.$apply()}),p}]}}return e=e&&e.module?e:window.angular,e.module("ngStorage",[]).provider("$localStorage",t("localStorage")).provider("$sessionStorage",t("sessionStorage"))}),function(e){e.module("authClient.config",[]).value("authClient.config",{debug:!0}),e.module("authClient.services",["ngStorage"]),e.module("authClient",["authClient.config","authClient.services"])}(angular),angular.module("authClient.services").service("authenticate",["$localStorage","$http","$location","$q","$window","baseUrl",function(e,t,n,r,o,i){var a=this;this.getToken=function(){return e.jwt},this.check=function(o){return r(function(r,s){var u=a.getToken();u||(u=n.search().jwt,u&&(e.jwt=u));var c={params:{next:o},withCredentials:!1};u=a.getToken(),u&&(c.params.jwt=u),t.get(i.getBaseUrl()+"/user/check",c).then(function(t){var n=t.data;n.authenticated?r({token:u,profile:n.profile}):(delete e.jwt,s(n.providers))})})},this.login=function(e,t){o.open(e,t)},this.logout=function(){a.getToken()&&(delete e.jwt,n.search("jwt",null))}}]),angular.module("authClient.services").service("authorize",["$http","$q","baseUrl",function(e,t,n){this.check=function(r,o){return t(function(t,i){var a={params:{jwt:r,service:o},withCredentials:!1};e.get(n.getBaseUrl()+"/user/authorize",a).then(function(e){var n=e.data;t(n)},function(){i({})})})}}]),angular.module("authClient.services").service("baseUrl",function(){var e="http://next.openspending.org";this.setBaseUrl=function(t){e=t},this.getBaseUrl=function(){return e}});<commit_msg>Bump auth lib<commit_after>!function(e,t){"use strict";"function"==typeof define&&define.amd?define(["angular"],t):e.hasOwnProperty("angular")?t(e.angular):"object"==typeof exports&&(module.exports=t(require("angular")))}(this,function(e){"use strict";function t(e,t){var n;try{n=e[t]}catch(r){n=!1}if(n){var o="__"+Math.round(1e7*Math.random());try{e[t].setItem(o,o),e[t].removeItem(o,o)}catch(r){n=!1}}return n}function n(n){var r=t(window,n);return function(){var o="ngStorage-";this.setKeyPrefix=function(e){if("string"!=typeof e)throw new TypeError("[ngStorage] - "+n+"Provider.setKeyPrefix() expects a String.");o=e};var i=e.toJson,a=e.fromJson;this.setSerializer=function(e){if("function"!=typeof e)throw new TypeError("[ngStorage] - "+n+"Provider.setSerializer expects a function.");i=e},this.setDeserializer=function(e){if("function"!=typeof e)throw new TypeError("[ngStorage] - "+n+"Provider.setDeserializer expects a function.");a=e},this.supported=function(){return!!r},this.get=function(e){return r&&a(r.getItem(o+e))},this.set=function(e,t){return r&&r.setItem(o+e,i(t))},this.remove=function(e){r&&r.removeItem(o+e)},this.$get=["$rootScope","$window","$log","$timeout","$document",function(r,u,s,c,l){var f,h,g=o.length,d=t(u,n),p=d||(s.warn("This browser does not support Web Storage!"),{setItem:e.noop,getItem:e.noop,removeItem:e.noop}),v={$default:function(t){for(var n in t)e.isDefined(v[n])||(v[n]=e.copy(t[n]));return v.$sync(),v},$reset:function(e){for(var t in v)"$"===t[0]||delete v[t]&&p.removeItem(o+t);return v.$default(e)},$sync:function(){for(var e,t=0,n=p.length;n>t;t++)(e=p.key(t))&&o===e.slice(0,g)&&(v[e.slice(g)]=a(p.getItem(e)))},$apply:function(){var t;if(h=null,!e.equals(v,f)){t=e.copy(f),e.forEach(v,function(n,r){e.isDefined(n)&&"$"!==r[0]&&(p.setItem(o+r,i(n)),delete t[r])});for(var n in t)p.removeItem(o+n);f=e.copy(v)}},$supported:function(){return!!d}};return v.$sync(),f=e.copy(v),r.$watch(function(){h||(h=c(v.$apply,100,!1))}),u.addEventListener&&u.addEventListener("storage",function(t){if(t.key){var n=l[0];n.hasFocus&&n.hasFocus()||o!==t.key.slice(0,g)||(t.newValue?v[t.key.slice(g)]=a(t.newValue):delete v[t.key.slice(g)],f=e.copy(v),r.$apply())}}),u.addEventListener&&u.addEventListener("beforeunload",function(){v.$apply()}),v}]}}return e=e&&e.module?e:window.angular,e.module("ngStorage",[]).provider("$localStorage",n("localStorage")).provider("$sessionStorage",n("sessionStorage"))}),function(e){e.module("authClient.config",[]).value("authClient.config",{debug:!0}),e.module("authClient.services",["ngStorage"]),e.module("authClient",["authClient.config","authClient.services"])}(angular),angular.module("authClient.services").service("authenticate",["$localStorage","$http","$location","$q","$window","baseUrl",function(e,t,n,r,o,i){var a=this;this.getToken=function(){return e.jwt},this.check=function(o){return r(function(r,u){var s=a.getToken();s||(s=n.search().jwt,s&&(e.jwt=s));var c={params:{next:o},withCredentials:!1};s=a.getToken(),s&&(c.params.jwt=s),t.get(i.getBaseUrl()+"/user/check",c).then(function(t){var n=t.data;n.authenticated?r({token:s,profile:n.profile}):(delete e.jwt,u(n.providers))})})},this.login=function(e,t){o.open(e,t)},this.logout=function(){a.getToken()&&(delete e.jwt,n.search("jwt",null))}}]),angular.module("authClient.services").service("authorize",["$http","$q","baseUrl",function(e,t,n){this.check=function(r,o){return t(function(t,i){var a={params:{jwt:r,service:o},withCredentials:!1};e.get(n.getBaseUrl()+"/user/authorize",a).then(function(e){var n=e.data;t(n)},function(){i({})})})}}]),angular.module("authClient.services").service("baseUrl",function(){var e="//next.openspending.org";this.setBaseUrl=function(t){e=t},this.getBaseUrl=function(){return e}});<|endoftext|>


<commit_before>import test from 'tape'
import sinon from 'sinon'
import mock from 'mock-require'

import os from '../../metal/util/os'

let app = {
  quit: () => null
}
mock('app', app)

let squirrel = require('../../metal/squirrel')

test('handle_startup_event should be bypassed on darwin', sinon.test(function (t) {
  this.stub(os, 'platform', () => 'darwin')
  t.false(squirrel.handle_startup_event())
  t.end()
}))

test('handle_startup_event should be bypassed on linux', sinon.test(function (t) {
  this.stub(os, 'platform', () => 'linux')
  t.false(squirrel.handle_startup_event())
  t.end()
}))

;['install', 'updated', 'uninstall', 'obsolete'].forEach((action) => {
  test(`handle_startup_event should quit app on ${action}`, sinon.test(function (t) {
    this.stub(os, 'platform', () => 'win32')
    this.stub(os, 'cli_args', () => ['hi mom', `--squirrel-${action}`])
    this.mock(app).expects('quit').once()
    t.true(squirrel.handle_startup_event())
    t.end()
  }))
})
<commit_msg>:green_heart: More specs for squirrel<commit_after>import test from 'tape'
import sinon from 'sinon'
import mock from 'mock-require'

import os from '../../metal/util/os'

let app = {
  quit: () => null
}
mock('app', app)

let squirrel = require('../../metal/squirrel')

test('handle_startup_event should be bypassed on darwin', sinon.test(function (t) {
  this.stub(os, 'platform', () => 'darwin')
  t.false(squirrel.handle_startup_event())
  t.end()
}))

test('handle_startup_event should be bypassed on linux', sinon.test(function (t) {
  this.stub(os, 'platform', () => 'linux')
  t.false(squirrel.handle_startup_event())
  t.end()
}))

;['install', 'updated', 'uninstall', 'obsolete'].forEach((action) => {
  test(`handle_startup_event should quit app on ${action}`, sinon.test(function (t) {
    this.stub(os, 'platform', () => 'win32')
    this.stub(os, 'cli_args', () => ['hi mom', `--squirrel-${action}`])
    this.mock(app).expects('quit').once()
    t.true(squirrel.handle_startup_event())
    t.end()
  }))
})

test(`handle_startup_event should do nothing on windows when no squirrel command line argument`, sinon.test(function (t) {
  this.stub(os, 'platform', () => 'win32')
  t.false(squirrel.handle_startup_event())
  t.end()
}))
<|endoftext|>


<commit_before>import { expect } from 'chai';
import DataProcessor from '../src/DataProcessor';

describe('DataProcessor', () => {

    describe('dataToPoints', () => {

        it('should return an array', () => {
            expect(DataProcessor.dataToPoints([])).to.be.an('array')
            expect(DataProcessor.dataToPoints([], null, null, null)).to.be.an('array')
            expect(DataProcessor.dataToPoints([1, 2, 3], null, null, null)).to.be.an('array')
            expect(DataProcessor.dataToPoints([1, null, undefined], null, null, null)).to.be.an('array')
        });

        it('should return only `limit` items', () => {
            expect(DataProcessor.dataToPoints([1,2,3,4,5])).to.have.length(5)
            expect(DataProcessor.dataToPoints([1,2,3,4,5], 2)).to.have.length(2)
            expect(DataProcessor.dataToPoints([1,2,3,4,5], 5)).to.have.length(5)
        });

        it('should return proper values for 1 value', () => {
            expect(DataProcessor.dataToPoints([1])).to.eql([
                {x: 0, y: 0}
            ])
        });

        it('should return proper values 2+ values', () => {
            expect(DataProcessor.dataToPoints([1,1])).to.eql([
                {x: 0, y: 0},
                {x: 1, y: 0}
            ])

            expect(DataProcessor.dataToPoints([0,1])).to.eql([
                {x: 0, y: 1},
                {x: 1, y: 0}
            ])

            expect(DataProcessor.dataToPoints([1,0])).to.eql([
                {x: 0, y: 0},
                {x: 1, y: 1}
            ])

            expect(DataProcessor.dataToPoints([0,1,2])).to.eql([
                {x: 0, y: 1},
                {x: 0.5, y: 0.5},
                {x: 1, y: 0}
            ])
        });

        it('should inerpolate values properly', () => {
            expect(DataProcessor.dataToPoints([0,1,2], null, 10, 10, 0)).to.eql([
                {x: 0, y: 10},
                {x: 5, y: 5},
                {x: 10, y: 0}
            ])
        });

        it('should take min and max into account', () => {
            expect(DataProcessor.dataToPoints([1,2,3,4], null, 6, 10, 0, 2, 3)).to.eql([
                {x: 0, y: -10},
                {x: 2, y: 0},
                {x: 4, y: 10},
                {x: 6, y: 20}
            ])
        });

        it('should return y == height for 0 and null values', () => {
            expect(DataProcessor.dataToPoints([0])).to.eql([
                {x: 0, y: 1}
            ])
            expect(DataProcessor.dataToPoints([0, null, 0])).to.eql([
                {x: 0, y: 1},
                {x: 0.5, y: 1},
                {x: 1, y: 1}
            ])
        });

    });

    describe('avg', () => {
        it('should return average of values', () => {
            expect(DataProcessor.avg([0])).to.eq(0)
            expect(DataProcessor.avg([0, 1])).to.eq(0.5)
            expect(DataProcessor.avg([1, 2])).to.eq(3/2)
            expect(DataProcessor.avg([0, 1, 2])).to.eq(1)
        });
    })

});
<commit_msg>update test of data processor to reflect new expected values of putting the line in the middle<commit_after>import { expect } from 'chai';
import DataProcessor from '../src/DataProcessor';

describe('DataProcessor', () => {

    describe('dataToPoints', () => {

        it('should return an array', () => {
            expect(DataProcessor.dataToPoints([])).to.be.an('array')
            expect(DataProcessor.dataToPoints([], null, null, null)).to.be.an('array')
            expect(DataProcessor.dataToPoints([1, 2, 3], null, null, null)).to.be.an('array')
            expect(DataProcessor.dataToPoints([1, null, undefined], null, null, null)).to.be.an('array')
        });

        it('should return only `limit` items', () => {
            expect(DataProcessor.dataToPoints([1,2,3,4,5])).to.have.length(5)
            expect(DataProcessor.dataToPoints([1,2,3,4,5], 2)).to.have.length(2)
            expect(DataProcessor.dataToPoints([1,2,3,4,5], 5)).to.have.length(5)
        });

        it('should return proper values for 1 value', () => {
            expect(DataProcessor.dataToPoints([1])).to.eql([
                {x: 0, y: 0.5}
            ])
        });

        it('should return proper values 2+ values', () => {
            expect(DataProcessor.dataToPoints([1,1])).to.eql([
                {x: 0, y: 0.5},
                {x: 1, y: 0.5}
            ])

            expect(DataProcessor.dataToPoints([0,1])).to.eql([
                {x: 0, y: 1},
                {x: 1, y: 0}
            ])

            expect(DataProcessor.dataToPoints([1,0])).to.eql([
                {x: 0, y: 0},
                {x: 1, y: 1}
            ])

            expect(DataProcessor.dataToPoints([0,1,2])).to.eql([
                {x: 0, y: 1},
                {x: 0.5, y: 0.5},
                {x: 1, y: 0}
            ])
        });

        it('should inerpolate values properly', () => {
            expect(DataProcessor.dataToPoints([0,1,2], null, 10, 10, 0)).to.eql([
                {x: 0, y: 10},
                {x: 5, y: 5},
                {x: 10, y: 0}
            ])
        });

        it('should take min and max into account', () => {
            expect(DataProcessor.dataToPoints([1,2,3,4], null, 6, 10, 0, 2, 3)).to.eql([
                {x: 0, y: -10},
                {x: 2, y: 0},
                {x: 4, y: 10},
                {x: 6, y: 20}
            ])
        });

        it('should return y == height for 0 and null values', () => {
            expect(DataProcessor.dataToPoints([0])).to.eql([
                {x: 0, y: 0.5}
            ])
            expect(DataProcessor.dataToPoints([0, null, 0])).to.eql([
                {x: 0, y: 0.5},
                {x: 0.5, y: 0.5},
                {x: 1, y: 0.5}
            ])
        });

    });

    describe('avg', () => {
        it('should return average of values', () => {
            expect(DataProcessor.avg([0])).to.eq(0)
            expect(DataProcessor.avg([0, 1])).to.eq(0.5)
            expect(DataProcessor.avg([1, 2])).to.eq(3/2)
            expect(DataProcessor.avg([0, 1, 2])).to.eq(1)
        });
    })

});
<|endoftext|>


<commit_before>const clean = (value) => String(value).replace(/\s+/g, '');

const formatYear = (year) => {
    const pre = String(year).length === 2 ? '20' : '';
    return `${pre}${year}`;
};

const toDetails = ({ number, month: ExpMonth, year, cvc: CVC, fullname, zip: ZIP, country: Country }) => {
    return {
        Name: clean(fullname),
        Number: clean(number),
        ExpMonth,
        ExpYear: formatYear(year),
        CVC, // Don't clean ZIP, space is allowed
        ZIP,
        Country
    };
};

export default toDetails;
<commit_msg>We were removing space in fullname<commit_after>const formatYear = (year) => {
    const pre = String(year).length === 2 ? '20' : '';
    return `${pre}${year}`;
};

const toDetails = ({ number, month: ExpMonth, year, cvc: CVC, fullname, zip: ZIP, country: Country }) => {
    return {
        Name: String(fullname).trim(),
        Number: String(number).replace(/\s+/g, ''),
        ExpMonth,
        ExpYear: formatYear(year),
        CVC, // Don't clean ZIP, space is allowed
        ZIP,
        Country
    };
};

export default toDetails;
<|endoftext|>


<commit_before>const CryptoJS = require('crypto-js');
const { Forbidden, BadRequest } = require('@feathersjs/errors');
const { authenticate } = require('@feathersjs/authentication');
const { ObjectId } = require('mongoose').Types;

const accountModel = require('../model');
const logger = require('../../../logger');

const hooks = {};
hooks.before = {
	create: [authenticate('jwt')],
};

class SupportJWTService {
	/**
	 * @param {secret} authentication
	 */
	constructor(authentication, aud, expiredOffset) {
		this.authentication = authentication;
		this.err = {
			missingParams: 'Missing param userId.',
			noPermission: 'You have no permission to execute this.',
			canNotCreateJWT: 'Can not create support jwt.',
		};
		this.permission = 'CREATE_SUPPORT_JWT';
		this.aud = aud || 'https://schul-cloud.org';
		this.expiredOffset = expiredOffset || 3600;
	}

	getSetupHooks() {
		return hooks;
	}

	testAccess(requester) {
		const canPass = requester.userId.roles.some((r) => r.permissions.includes(this.permission));
		if (!canPass) {
			throw new Forbidden(this.err.noPermission);
		}
	}

	base64url(source) {
		// Encode in classical base64
		let encodedSource = CryptoJS.enc.Base64.stringify(source);

		// Remove padding equal characters
		encodedSource = encodedSource.replace(/=+$/, '');

		// Replace characters according to base64url specifications
		encodedSource = encodedSource.replace(/\+/g, '-');
		encodedSource = encodedSource.replace(/\//g, '_');

		return encodedSource;
	}

	Utf8Stringify(input) {
		return CryptoJS.enc.Utf8.parse(JSON.stringify(input));
	}

	HmacSHA256(signature, secret) {
		console.log(signature, secret, this.authentication, this.app.get('secret'));
		return CryptoJS.HmacSHA256(signature, secret);
	}

	// todo later add notification for user
	executeInfo(currentUserId, userId, exp) {
		// eslint-disable-next-line max-len
		logger.info(`The support employee with the Id ${currentUserId} has created  a short live JWT for the user with the Id ${userId}. The JWT expires at ${exp}.`);
	}

	async create({ userId }, params) {
		try {
			if (!userId) {
				throw new BadRequest(this.err.missingParams);
			}
			// eslint-disable-next-line no-param-reassign
			userId = userId.toString(); // validation for intern requests
			const currentUserId = params.account.userId.toString();

			const $populatedAccounts = await accountModel.find().or([
				{ userId: currentUserId },
				{ userId },
			]).select('userId')
				.populate({
					path: 'userId',
					populate: {
						path: 'roles',
					},
				})
				.exec();

			const populatedAccounts = $populatedAccounts.map((a) => a.toObject());
			const requester = populatedAccounts.find((a) => a.userId._id.toString() === currentUserId);
			const account = populatedAccounts.find((a) => a.userId._id.toString() === userId);

			// Important to restricted access!
			this.testAccess(requester);

			const header = {
				alg: 'HS256',
				typ: 'access',
			};

			const iat = new Date().valueOf();
			const exp = iat + this.expiredOffset;

			const accountId = account._id.toString();

			const jwtData = {
				support: true, // mark for support jwts
				accountId,
				userId,
				iat,
				exp,
				aud: this.aud,
				iss: 'feathers',
				sub: accountId,
				jti: `support_${ObjectId()}`,
			};

			const secret = this.authentication;

			const stringifiedHeader = this.Utf8Stringify(header);
			const encodedHeader = this.base64url(stringifiedHeader);

			const stringifiedData = this.Utf8Stringify(jwtData);
			const encodedData = this.base64url(stringifiedData);

			let signature = `${encodedHeader}.${encodedData}`;
			signature = this.HmacSHA256(signature, secret); // algorithm: 'HS256',
			signature = this.base64url(signature);

			const jwt = `${encodedHeader}.${encodedData}.${signature}`;

			this.executeInfo(currentUserId, userId, exp);
			return jwt;
		} catch (err) {
			logger.warning(this.err.canNotCreateJWT, err);
			return err;
		}
	}

	setup(app) {
		this.app = app;
	}
}

const supportJWTServiceSetup = (app) => {
	const path = 'accounts/supportJWT';
	const instance = new SupportJWTService(app.get('secrets').authentication);
	app.use(path, instance);
	const service = app.service(path);
	service.hooks(instance.getSetupHooks());
};

module.exports = {
	hooks,
	SupportJWTService,
	supportJWTServiceSetup,
};
<commit_msg>travis<commit_after>const CryptoJS = require('crypto-js');
const { Forbidden, BadRequest } = require('@feathersjs/errors');
const { authenticate } = require('@feathersjs/authentication');
const { ObjectId } = require('mongoose').Types;

const accountModel = require('../model');
const logger = require('../../../logger');

const hooks = {};
hooks.before = {
	create: [authenticate('jwt')],
};

class SupportJWTService {
	/**
	 * @param {secret} authentication
	 */
	constructor(authentication, aud, expiredOffset) {
		this.authentication = authentication;
		this.err = {
			missingParams: 'Missing param userId.',
			noPermission: 'You have no permission to execute this.',
			canNotCreateJWT: 'Can not create support jwt.',
		};
		this.permission = 'CREATE_SUPPORT_JWT';
		this.aud = aud || 'https://schul-cloud.org';
		this.expiredOffset = expiredOffset || 3600;
	}

	getSetupHooks() {
		return hooks;
	}

	testAccess(requester) {
		const canPass = requester.userId.roles.some((r) => r.permissions.includes(this.permission));
		if (!canPass) {
			throw new Forbidden(this.err.noPermission);
		}
	}

	base64url(source) {
		// Encode in classical base64
		let encodedSource = CryptoJS.enc.Base64.stringify(source);

		// Remove padding equal characters
		encodedSource = encodedSource.replace(/=+$/, '');

		// Replace characters according to base64url specifications
		encodedSource = encodedSource.replace(/\+/g, '-');
		encodedSource = encodedSource.replace(/\//g, '_');

		return encodedSource;
	}

	Utf8Stringify(input) {
		return CryptoJS.enc.Utf8.parse(JSON.stringify(input));
	}

	HmacSHA256(signature, secret) {
		console.log(signature, secret, this.authentication);
		return CryptoJS.HmacSHA256(signature, secret);
	}

	// todo later add notification for user
	executeInfo(currentUserId, userId, exp) {
		// eslint-disable-next-line max-len
		logger.info(`The support employee with the Id ${currentUserId} has created  a short live JWT for the user with the Id ${userId}. The JWT expires at ${exp}.`);
	}

	async create({ userId }, params) {
		try {
			if (!userId) {
				throw new BadRequest(this.err.missingParams);
			}
			// eslint-disable-next-line no-param-reassign
			userId = userId.toString(); // validation for intern requests
			const currentUserId = params.account.userId.toString();

			const $populatedAccounts = await accountModel.find().or([
				{ userId: currentUserId },
				{ userId },
			]).select('userId')
				.populate({
					path: 'userId',
					populate: {
						path: 'roles',
					},
				})
				.exec();

			const populatedAccounts = $populatedAccounts.map((a) => a.toObject());
			const requester = populatedAccounts.find((a) => a.userId._id.toString() === currentUserId);
			const account = populatedAccounts.find((a) => a.userId._id.toString() === userId);

			// Important to restricted access!
			this.testAccess(requester);

			const header = {
				alg: 'HS256',
				typ: 'access',
			};

			const iat = new Date().valueOf();
			const exp = iat + this.expiredOffset;

			const accountId = account._id.toString();

			const jwtData = {
				support: true, // mark for support jwts
				accountId,
				userId,
				iat,
				exp,
				aud: this.aud,
				iss: 'feathers',
				sub: accountId,
				jti: `support_${ObjectId()}`,
			};

			const secret = this.authentication;

			const stringifiedHeader = this.Utf8Stringify(header);
			const encodedHeader = this.base64url(stringifiedHeader);

			const stringifiedData = this.Utf8Stringify(jwtData);
			const encodedData = this.base64url(stringifiedData);

			let signature = `${encodedHeader}.${encodedData}`;
			signature = this.HmacSHA256(signature, secret); // algorithm: 'HS256',
			signature = this.base64url(signature);

			const jwt = `${encodedHeader}.${encodedData}.${signature}`;

			this.executeInfo(currentUserId, userId, exp);
			return jwt;
		} catch (err) {
			logger.warning(this.err.canNotCreateJWT, err);
			return err;
		}
	}

	setup(app) {
		this.app = app;
	}
}

const supportJWTServiceSetup = (app) => {
	const path = 'accounts/supportJWT';
	console.log('#', app.get('secrets'));
	const instance = new SupportJWTService(app.get('secrets').authentication);
	app.use(path, instance);
	const service = app.service(path);
	service.hooks(instance.getSetupHooks());
};

module.exports = {
	hooks,
	SupportJWTService,
	supportJWTServiceSetup,
};
<|endoftext|>


<commit_before>/*
File:           slidegrid.js
Description:    for more information see http://www.zackgrossbart.com/hackito/slidegrid/

*******************************************************************************
 *
 * 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.
 *
 ******************************************************************************/

slidegrid = {
    hasDrawn: false,
    windowWidth: 0,
    cellWidth: 250,
    cellHeight: 150,
    padding: 30,
    gridOffset: 0,
    inResize: false,

    /**
     * Adds a specific cell to the set of used cells.  Used cells are skipped
     * when laying cells out in the future.
     *
     * @param usedCells the array of used cells
     * @param col       the column of the used cell
     * @param row       the row of the used cell
     */
    setUsed: function(/*array*/ usedCells, /*int*/col, /*int*/row) {
        var index = usedCells.length;

        usedCells[index] = { left: col, top: row};
    },

    /**
     * Lets you know if a specific column and row index has already been used.
     *
     * @param usedCells the array of used cells
     * @param col       the column of the cell to check
     * @param row       the row of the cell to check
     */
    isUsed: function(/*array*/ usedCells, /*int*/ col, /*int*/ row) {
        for (var i = 0; i < usedCells.length; i++) {
            if (usedCells[i].left === col &&
                usedCells[i].top === row) {
                return true;
            }
        }

        return false;
    },

    /**
     * Applies the styling to a specific cell.
     *
     * @param cell       The JQuery object representing the cell to style
     * @param x          the left position of the cell in EMs
     * @param y          the top position of the cell in EMs
     * @param cellWidth  the width of the cell in EMs
     * @param cellHeight the height of the cell in EMs
     * @param animate    true if this style should be animated and false otherwise
     */
    styleCell: function(cell, x, y, cellWidth, cellHeight, /*boolean*/animate) {
        if (animate) {
            cell.animate({
                left: x + "px",
                top: y + "px"
                }, 500, "swing" );
        } else {
            cell.css({
                width: cellWidth + "px",
                height: cellHeight + "px",
                position: "absolute",
                left: x + "px",
                top: y + "px"
            });
        }
    },

    /**
     * Aligns a set of elements in a resizable grid.
     *
     * @param cellWidth  the width of each cell in px
     * @param cellHeight the height of each cell in px
     * @param padding    the padding between each cell in px
     * @param gridOffset the offset width of the grid in px
     */
    alignGrid: function(/*int*/ cellWidth, /*int*/ cellHeight, /*int*/ padding, /*int*/ gridOffset) {
        slidegrid.cellWidth = cellWidth;
        slidegrid.cellHeight = cellHeight;
        slidegrid.padding = padding;
        slidegrid.gridOffset = gridOffset;

        var x = padding / 2;
        var y = 0;
        var count = 1;

        /*
         * When we add a "bigcell" to the grid it takes up four cells instead of one.
         * That makes we need to not add any other cells to those areas or the cells
         * will overlap.  These three variables are used to remember the cells used
         * by big cells.
         */
        var curCol = 0;
        var curRow = 0;
        var usedCells = [];

        $(".slidegrid").each(function() {

            var hasTallCell = false;

            var cols = Math.floor(($(this).parent().parent().width()) / ((cellWidth + padding)));

            $(this).css("position", "relative");

            var children = $(this).children("div");

            for (var i = 0; i < children.length; i++) {
                if (children.eq(i).hasClass("bigcell")) {
                    if (curCol === cols - 1) {
                        /*
                         * This means it is time to bump down to the next row
                         */
                        curCol = 0;
                        curRow++;
                        x = padding / 2;
                        y += cellHeight + padding;
                        count++;

                    }

                    if (cols > 1 && (slidegrid.isUsed(usedCells, curCol, curRow) ||
                        slidegrid.isUsed(usedCells, curCol + 1, curRow) ||
                        slidegrid.isUsed(usedCells, curCol + 1, curRow + 1) ||
                        slidegrid.isUsed(usedCells, curCol, curRow + 1))) {
                        /*
                         * If the current cell is used we
                         * just want to try the next column.
                         * However, we also want to bump to
                         * the next row if needed so we are
                         * calling the column logic and then
                         * backing up the counter.
                         */
                        i--;
                    } else {

                        slidegrid.styleCell(children.eq(i), x, y, (cellWidth * 2) + padding, (cellHeight * 2) + padding, slidegrid.hasDrawn);
                        /*
                         * Big cells are twice as large as normal cells.  That means they
                         * use up the cell to the right, the cell below, and the cell to
                         * the right and below.
                         */

                        slidegrid.setUsed(usedCells, curCol, curRow);
                        slidegrid.setUsed(usedCells, curCol + 1, curRow);
                        slidegrid.setUsed(usedCells, curCol, curRow + 1);
                        slidegrid.setUsed(usedCells, curCol + 1, curRow + 1);
                    }

                    hasTallCell = true;

                } else if (children.eq(i).hasClass("widecell")) {
                    if (slidegrid.isUsed(usedCells, curCol, curRow) ||
                        slidegrid.isUsed(usedCells, curCol + 1, curRow) ||
                        (cols > 1 && curCol === cols - 1)) {
                        /*
                         * If the current cell is used we
                         * just want to try the next column.
                         * However, we also want to bump to
                         * the next row if needed so we are
                         * calling the column logic and then
                         * backing up the counter.
                         */
                        i--;

                    } else {
                        slidegrid.styleCell(children.eq(i), x, y, (cellWidth * 2) + padding, cellHeight, slidegrid.hasDrawn);
                        /*
                         * Wide cells are twice as wide, but the same height
                         */

                        slidegrid.setUsed(usedCells, curCol, curRow);
                        slidegrid.setUsed(usedCells, curCol + 1, curRow);
                    }
                } else if (children.eq(i).hasClass("tallcell")) {
                    if (slidegrid.isUsed(usedCells, curCol, curRow) ||
                        slidegrid.isUsed(usedCells, curCol, curRow + 1)) {
                        /*
                         * If the current cell is used we
                         * just want to try the next column.
                         * However, we also want to bump to
                         * the next row if needed so we are
                         * calling the column logic and then
                         * backing up the counter.
                         */
                        i--;

                    } else {
                        slidegrid.styleCell(children.eq(i), x, y, cellWidth, (cellHeight * 2) + padding, slidegrid.hasDrawn);
                        /*
                         * Tall cells are twice as tall, but the same width
                         */

                        slidegrid.setUsed(usedCells, curCol, curRow);
                        slidegrid.setUsed(usedCells, curCol, curRow + 1);
                    }

                    hasTallCell = true;

                } else {
                    if (slidegrid.isUsed(usedCells, curCol, curRow)) {
                        /*
                         * If the current cell is used we
                         * just want to try the next column.
                         * However, we also want to bump to
                         * the next row if needed so we are
                         * calling the column logic and then
                         * backing up the counter.
                         */
                        i--;

                    } else {
                        slidegrid.styleCell(children.eq(i), x, y, cellWidth, cellHeight, slidegrid.hasDrawn);
                    }
                }

                if ((count % cols) === 0) {
                    /*
                     * This means it is time to bump down to the next row
                     */
                    curCol = 0;
                    curRow++;
                    x = padding / 2;
                    y += cellHeight + padding;
                    if (i != children.length - 1) {
                        hasTallCell = false;
                    }
                } else {
                    x += cellWidth + padding;
                    curCol++;
                }
                count++;
            }

            /*
             * We need to set a height of the slidegrid div since it only has absolute
             * height tags within it.
             */
            var height = 0;
            if ((count % cols) !== 1) {
                height = y + cellHeight + padding;
            } else {
                height = y + padding;
            }

            if (hasTallCell) {
                height += (cellHeight + padding) * 2;
            }

            $(this).css('height', height + "px");

            /*
             * Now we reset the variables for the next grid.
             */
            x = padding / 2;
            y = 0;
            count = 1;

            slidegrid.bindResize();
        });

        slidegrid.hasDrawn = true;
    },

    bindResize: function() {
         $(window).bind('resize', function() {
             if (!slidegrid.inResize && slidegrid.windowWidth != $(window).width()) {
                 slidegrid.inResize = true;
                 setTimeout(function() {
                     slidegrid.alignGrid(slidegrid.cellWidth, slidegrid.cellHeight, slidegrid.padding, slidegrid.gridOffset);
                     slidegrid.windowWidth = $(window).width();
                     slidegrid.inResize = false;
                 }, 500);
             }
         });
    }
}
<commit_msg>We are no longer adding a double cell height to the bottom of the grid when the last row has a tall cell.<commit_after>/*
File:           slidegrid.js
Description:    for more information see http://www.zackgrossbart.com/hackito/slidegrid/

*******************************************************************************
 *
 * 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.
 *
 ******************************************************************************/

slidegrid = {
    hasDrawn: false,
    windowWidth: 0,
    cellWidth: 250,
    cellHeight: 150,
    padding: 30,
    gridOffset: 0,
    inResize: false,

    /**
     * Adds a specific cell to the set of used cells.  Used cells are skipped
     * when laying cells out in the future.
     *
     * @param usedCells the array of used cells
     * @param col       the column of the used cell
     * @param row       the row of the used cell
     */
    setUsed: function(/*array*/ usedCells, /*int*/col, /*int*/row) {
        var index = usedCells.length;

        usedCells[index] = { left: col, top: row};
    },

    /**
     * Lets you know if a specific column and row index has already been used.
     *
     * @param usedCells the array of used cells
     * @param col       the column of the cell to check
     * @param row       the row of the cell to check
     */
    isUsed: function(/*array*/ usedCells, /*int*/ col, /*int*/ row) {
        for (var i = 0; i < usedCells.length; i++) {
            if (usedCells[i].left === col &&
                usedCells[i].top === row) {
                return true;
            }
        }

        return false;
    },

    /**
     * Applies the styling to a specific cell.
     *
     * @param cell       The JQuery object representing the cell to style
     * @param x          the left position of the cell in EMs
     * @param y          the top position of the cell in EMs
     * @param cellWidth  the width of the cell in EMs
     * @param cellHeight the height of the cell in EMs
     * @param animate    true if this style should be animated and false otherwise
     */
    styleCell: function(cell, x, y, cellWidth, cellHeight, /*boolean*/animate) {
        if (animate) {
            cell.animate({
                left: x + "px",
                top: y + "px"
                }, 500, "swing" );
        } else {
            cell.css({
                width: cellWidth + "px",
                height: cellHeight + "px",
                position: "absolute",
                left: x + "px",
                top: y + "px"
            });
        }
    },

    /**
     * Aligns a set of elements in a resizable grid.
     *
     * @param cellWidth  the width of each cell in px
     * @param cellHeight the height of each cell in px
     * @param padding    the padding between each cell in px
     * @param gridOffset the offset width of the grid in px
     */
    alignGrid: function(/*int*/ cellWidth, /*int*/ cellHeight, /*int*/ padding, /*int*/ gridOffset) {
        slidegrid.cellWidth = cellWidth;
        slidegrid.cellHeight = cellHeight;
        slidegrid.padding = padding;
        slidegrid.gridOffset = gridOffset;

        var x = padding / 2;
        var y = 0;
        var count = 1;

        /*
         * When we add a "bigcell" to the grid it takes up four cells instead of one.
         * That makes we need to not add any other cells to those areas or the cells
         * will overlap.  These three variables are used to remember the cells used
         * by big cells.
         */
        var curCol = 0;
        var curRow = 0;
        var usedCells = [];

        $(".slidegrid").each(function() {

            var hasTallCell = false;

            var cols = Math.floor(($(this).parent().parent().width()) / ((cellWidth + padding)));

            $(this).css("position", "relative");

            var children = $(this).children("div");

            for (var i = 0; i < children.length; i++) {
                if (children.eq(i).hasClass("bigcell")) {
                    if (curCol === cols - 1) {
                        /*
                         * This means it is time to bump down to the next row
                         */
                        curCol = 0;
                        curRow++;
                        x = padding / 2;
                        y += cellHeight + padding;
                        count++;

                    }

                    if (cols > 1 && (slidegrid.isUsed(usedCells, curCol, curRow) ||
                        slidegrid.isUsed(usedCells, curCol + 1, curRow) ||
                        slidegrid.isUsed(usedCells, curCol + 1, curRow + 1) ||
                        slidegrid.isUsed(usedCells, curCol, curRow + 1))) {
                        /*
                         * If the current cell is used we
                         * just want to try the next column.
                         * However, we also want to bump to
                         * the next row if needed so we are
                         * calling the column logic and then
                         * backing up the counter.
                         */
                        i--;
                    } else {

                        slidegrid.styleCell(children.eq(i), x, y, (cellWidth * 2) + padding, (cellHeight * 2) + padding, slidegrid.hasDrawn);
                        /*
                         * Big cells are twice as large as normal cells.  That means they
                         * use up the cell to the right, the cell below, and the cell to
                         * the right and below.
                         */

                        slidegrid.setUsed(usedCells, curCol, curRow);
                        slidegrid.setUsed(usedCells, curCol + 1, curRow);
                        slidegrid.setUsed(usedCells, curCol, curRow + 1);
                        slidegrid.setUsed(usedCells, curCol + 1, curRow + 1);
                    }

                    hasTallCell = true;

                } else if (children.eq(i).hasClass("widecell")) {
                    if (slidegrid.isUsed(usedCells, curCol, curRow) ||
                        slidegrid.isUsed(usedCells, curCol + 1, curRow) ||
                        (cols > 1 && curCol === cols - 1)) {
                        /*
                         * If the current cell is used we
                         * just want to try the next column.
                         * However, we also want to bump to
                         * the next row if needed so we are
                         * calling the column logic and then
                         * backing up the counter.
                         */
                        i--;

                    } else {
                        slidegrid.styleCell(children.eq(i), x, y, (cellWidth * 2) + padding, cellHeight, slidegrid.hasDrawn);
                        /*
                         * Wide cells are twice as wide, but the same height
                         */

                        slidegrid.setUsed(usedCells, curCol, curRow);
                        slidegrid.setUsed(usedCells, curCol + 1, curRow);
                    }
                } else if (children.eq(i).hasClass("tallcell")) {
                    if (slidegrid.isUsed(usedCells, curCol, curRow) ||
                        slidegrid.isUsed(usedCells, curCol, curRow + 1)) {
                        /*
                         * If the current cell is used we
                         * just want to try the next column.
                         * However, we also want to bump to
                         * the next row if needed so we are
                         * calling the column logic and then
                         * backing up the counter.
                         */
                        i--;

                    } else {
                        slidegrid.styleCell(children.eq(i), x, y, cellWidth, (cellHeight * 2) + padding, slidegrid.hasDrawn);
                        /*
                         * Tall cells are twice as tall, but the same width
                         */

                        slidegrid.setUsed(usedCells, curCol, curRow);
                        slidegrid.setUsed(usedCells, curCol, curRow + 1);
                    }

                    hasTallCell = true;

                } else {
                    if (slidegrid.isUsed(usedCells, curCol, curRow)) {
                        /*
                         * If the current cell is used we
                         * just want to try the next column.
                         * However, we also want to bump to
                         * the next row if needed so we are
                         * calling the column logic and then
                         * backing up the counter.
                         */
                        i--;

                    } else {
                        slidegrid.styleCell(children.eq(i), x, y, cellWidth, cellHeight, slidegrid.hasDrawn);
                    }
                }

                if ((count % cols) === 0) {
                    /*
                     * This means it is time to bump down to the next row
                     */
                    curCol = 0;
                    curRow++;
                    x = padding / 2;
                    y += cellHeight + padding;
                    if (i != children.length - 1) {
                        hasTallCell = false;
                    }
                } else {
                    x += cellWidth + padding;
                    curCol++;
                }
                count++;
            }

            /*
             * We need to set a height of the slidegrid div since it only has absolute
             * height tags within it.
             */
            var height = 0;
            if ((count % cols) !== 1) {
                height = y + cellHeight + padding;
            } else {
                height = y + padding;
            }

            if (hasTallCell) {
                height += cellHeight + padding;
            }

            $(this).css('height', height + "px");

            /*
             * Now we reset the variables for the next grid.
             */
            x = padding / 2;
            y = 0;
            count = 1;

            slidegrid.bindResize();
        });

        slidegrid.hasDrawn = true;
    },

    bindResize: function() {
         $(window).bind('resize', function() {
             if (!slidegrid.inResize && slidegrid.windowWidth != $(window).width()) {
                 slidegrid.inResize = true;
                 setTimeout(function() {
                     slidegrid.alignGrid(slidegrid.cellWidth, slidegrid.cellHeight, slidegrid.padding, slidegrid.gridOffset);
                     slidegrid.windowWidth = $(window).width();
                     slidegrid.inResize = false;
                 }, 500);
             }
         });
    }
}
<|endoftext|>


<commit_before>/**
 * Linkit 7688 範例
 * 使用 GPIO 控制 8x8 LED Matrix (共陽)
 *
 * @author Abola Lee
 * @version 1.0
 * @since 2016-01-10
 *
 * @link http://www.gibar.co/2016/01/linkit-7688-duo-74hc595-led.html
 */
var mraa = require('mraa');

// 腳位命名參考
//       _______
//  Q1[1|   U   |16]Vcc
//  Q2[2|       |15]Q0
//  Q3[3|       |14]DS
//  Q4[4|  595  |13]OE
//  Q5[5|       |12]STCP
//  Q6[6|       |11]SHCP
//  Q7[7|       |10]MR
// GND[8|_______| 9]Q7s
//

// 設定GPIO 接腳
var col = [
      new mraa.Gpio(2),
      , new mraa.Gpio(16)
      , new mraa.Gpio(17)
      , new mraa.Gpio(44)
      , new mraa.Gpio(5)
      , new mraa.Gpio(46)
      , new mraa.Gpio(0)
      , new mraa.Gpio(1)
    ],
    row = [
      new mraa.Gpio(37)
      , new mraa.Gpio(3)
      , new mraa.Gpio(13)
      , new mraa.Gpio(45)
      , new mraa.Gpio(14)
      , new mraa.Gpio(12)
      , new mraa.Gpio(15)
      , new mraa.Gpio(4)
    ];

// 預設全亮測試
for(var idx=0; idx<8; idx++) ((mraa.Gpio)col[idx]).dir(mraa.DIR_OUT_HIGH);
for(var idx=0; idx<8; idx++) row[idx].dir(mraa.DIR_OUT_LOW);

var offIndex=0;
setInterval(function(){
  if( offIndex<8 ) row[offIndex].write(1);
},250);
<commit_msg>Update 8x8_led_matrix.js<commit_after>/**
 * Linkit 7688 範例
 * 使用 GPIO 控制 8x8 LED Matrix (共陽)
 *
 * @author Abola Lee
 * @version 1.0
 * @since 2016-01-10
 *
 * @link http://www.gibar.co/2016/01/linkit-7688-duo-74hc595-led.html
 */
var mraa = require('mraa');

// 腳位命名參考
//       _______
//  Q1[1|   U   |16]Vcc
//  Q2[2|       |15]Q0
//  Q3[3|       |14]DS
//  Q4[4|  595  |13]OE
//  Q5[5|       |12]STCP
//  Q6[6|       |11]SHCP
//  Q7[7|       |10]MR
// GND[8|_______| 9]Q7s
//

// 設定GPIO 接腳
var mycol = [
      new mraa.Gpio(2)
      , new mraa.Gpio(16)
      , new mraa.Gpio(17)
      , new mraa.Gpio(44)
      , new mraa.Gpio(5)
      , new mraa.Gpio(46)
      , new mraa.Gpio(0)
      , new mraa.Gpio(1)
    ],
    myrow = [
      new mraa.Gpio(37)
      , new mraa.Gpio(3)
      , new mraa.Gpio(13)
      , new mraa.Gpio(45)
      , new mraa.Gpio(14)
      , new mraa.Gpio(12)
      , new mraa.Gpio(15)
      , new mraa.Gpio(4)
    ];

// 預設全亮測試
for(var idx=0; idx<8; idx++) ((mraa.Gpio)mycol[idx]).dir(mraa.DIR_OUT_HIGH);
for(var idx=0; idx<8; idx++) myrow[idx].dir(mraa.DIR_OUT_LOW);

var offIndex=0;
setInterval(function(){
  if( offIndex<8 ) myrow[offIndex].write(1);
},250);
<|endoftext|>


<commit_before>import View from '../base/view';

import {trigger} from '../utils/browser';
import {toggleClass} from '../utils/elements';

import template from '../../templates/search.ejs';

export default class Search extends View {
  constructor({app, isOnSearchPage, query}) {
    super({app});

    this.isOnSearchPage = isOnSearchPage;
    this.query = query;
  }

  getHTML() {
    return this.app.renderTemplate(template, {
      isOnSearchPage: this.isOnSearchPage,
      query: this.query,
    });
  }

  mount() {
    this.input = this.element.querySelector('input');
    this.events.bind('click .icon-search', 'onOpen');
    this.events.bind('click .icon-close', 'onClose');
    this.events.bind('submit', 'onSubmit');
    this.events.bind('focus input', 'onFocus');
    this.events.bind('blur input', 'onBlur');
    this.events.bind('keyup input', 'onType');
    this.events.bind('input input', 'onType');
  }

  sync() {
    if (this.input.value != this.query) this.input.value = this.query;
    toggleClass(this.element, 'active', this.isOnSearchPage);
  }

  onOpen() {
    this.element.classList.add('active');
    this.input.focus();
  }

  onClose() {
    this.element.classList.remove('active');
  }

  onFocus() {
    this.element.classList.add('active');
  }

  onBlur() {
    if (this.input.value) return;
    this.element.classList.remove('active');
  }

  onType(event) {
    if (this.input.value == this.query) return;
    if (this.typeTimeout) window.clearTimeout(this.typeTimeout);
    this.typeTimeout = window.setTimeout(() => {
      const action = this.isOnSearchPage ? 'redirect' : 'navigate';
      const url = this.getSearchPageURL();
      trigger(window, action, url);
    }, 100);
  }

  onSubmit(event) {
    event.preventDefault();
    if (this.typeTimeout) window.clearTimeout(this.typeTimeout);
    const url = this.getSearchPageURL();
    trigger(window, 'navigate', url);
  }

  getSearchPageURL() {
    const query = this.input.value;
    const path = this.app.url('search', {});
    return `${path}?q=${encodeURIComponent(query)}`;
  }
}
<commit_msg>Avoid writing "undefined" into the search field<commit_after>import View from '../base/view';

import {trigger} from '../utils/browser';
import {toggleClass} from '../utils/elements';

import template from '../../templates/search.ejs';

export default class Search extends View {
  constructor({app, isOnSearchPage, query}) {
    super({app});

    this.isOnSearchPage = isOnSearchPage;
    this.query = query || '';
  }

  getHTML() {
    return this.app.renderTemplate(template, {
      isOnSearchPage: this.isOnSearchPage,
      query: this.query,
    });
  }

  mount() {
    this.input = this.element.querySelector('input');
    this.events.bind('click .icon-search', 'onOpen');
    this.events.bind('click .icon-close', 'onClose');
    this.events.bind('submit', 'onSubmit');
    this.events.bind('focus input', 'onFocus');
    this.events.bind('blur input', 'onBlur');
    this.events.bind('keyup input', 'onType');
    this.events.bind('input input', 'onType');
  }

  sync() {
    if (this.input.value != this.query) this.input.value = this.query;
    toggleClass(this.element, 'active', this.isOnSearchPage);
  }

  onOpen() {
    this.element.classList.add('active');
    this.input.focus();
  }

  onClose() {
    this.element.classList.remove('active');
  }

  onFocus() {
    this.element.classList.add('active');
  }

  onBlur() {
    if (this.input.value) return;
    this.element.classList.remove('active');
  }

  onType(event) {
    if (this.input.value == this.query) return;
    if (this.typeTimeout) window.clearTimeout(this.typeTimeout);
    this.typeTimeout = window.setTimeout(() => {
      const action = this.isOnSearchPage ? 'redirect' : 'navigate';
      const url = this.getSearchPageURL();
      trigger(window, action, url);
    }, 100);
  }

  onSubmit(event) {
    event.preventDefault();
    if (this.typeTimeout) window.clearTimeout(this.typeTimeout);
    const url = this.getSearchPageURL();
    trigger(window, 'navigate', url);
  }

  getSearchPageURL() {
    const query = this.input.value;
    const path = this.app.url('search', {});
    return `${path}?q=${encodeURIComponent(query)}`;
  }
}
<|endoftext|>