<commit_before>window.async = (function($){
	var self = {};
	self.REGEX = new RegExp('^https?://'+ document.domain +'(/.*)', 'i');
	self.container = '#content'; // CSS selector for where to put the returned HTML data
	self.debug = false;
	self.compile = true; // auto include scripts into HTML?
	self._loading = false; // current URI being loaded, internal use
	self.ignore = [
		"/blog/edit",
		"/blog/add",
		"/events/add",
		"/user/logout"
	];
	self.bind = function(){
		function catch_link(e){
			e.preventDefault();
			e.stopImmediatePropagation();
			return async.link(this.href, false);
		}
		$('a:not([class*="editable"]):not(.noasync):not([href^="'+ self.ignore.join('"]):not([href^="') +'"])').on('click', catch_link);
		$('#admin-bar a').off('click', catch_link);
		$('#preview-bar a').off('click', catch_link);
	};
	self.link = function(target, pop_state){
		if (!self.REGEX.test(target) && !pop_state) {
			if (self.debug) console.log('Caught external link.');
			window.open(target,'_blank');
			return false;
		}
		if (self.debug) console.log('Caught internal link.');
		var uri, container = document.querySelector(self.container), $document = $(document);
		if (pop_state) { uri = target; }
		else { uri = self.REGEX.exec(target)[1]; }
		if (self.debug) console.log('URI: '+ uri);
		if (uri != container.dataset['path']){
			self._loading = uri.split('?')[0];
			$document.trigger('async_start');
			$.getJSON('/admin/api/async?page='+ encodeURIComponent(uri)).success(function(res){
				if (self.debug) console.log(res);
				if (res.success) {
					if (self._loading !== res.data.path) return false;
					$document.trigger('async_pre', res.data);
					container.innerHTML = (self.compile?res.data.page.head:'') + res.data.html + (self.compile?res.data.page.tail:'');
					var title = res.data.page.window_title;
					if (!title) title = res.data.page._window_title;
					if (!title) title = res.data.page.title;
					document.querySelector('head title').innerText = title;
					$document.trigger('async_post', res.data);
					if (self.debug) console.log('Async load successful');
					document.cookie = 'elefant_last_page='+ res.data.path;
					self.bind();
					container.dataset['path'] = uri;
					if (!pop_state) {
						history.pushState({data:uri}, document.querySelector('head title').innerText, uri);
					}
					$document.trigger('async_success');
					self._loading = false;
				} else {
					if (self.debug) console.log(res);
					$document.trigger('async_error', res.error);
				}
			}).fail(function(){
				if (self.debug) console.log('Async load unsuccessful');
				$document.trigger('async_fail');
			}).always(function(){
				$document.trigger('async_end');
			});
		}
		return false;
	};
	console.log('Async wrapper loaded.');
	$(self.bind);
	return self;
}(jQuery));

window.onpopstate = function(e){
	if (e.state) window.async.link(e.state.data, true);
};<commit_msg>Added two additional events for more fine-grained control, Re-ordered a bit of the code to allow for better control of the script, Added ability to bind clicks to just within a given container<commit_after>// Copywrite for this file is inherited from ELefantCMS.

window.async = (function($){
	var self = {};
	self.REGEX = new RegExp('^https?://'+ document.domain +'(/.*)', 'i');
	self.container = '#content'; // CSS selector for where to put the returned HTML data
	self.debug = false;
	self.compile = true; // auto include scripts into HTML?
	// current URI being loaded
	self.load = false; // set to false during the async_start or async_pre events to cancel the page request or DOM injection respectively.
	self.ignore = [
		"/blog/edit",
		"/blog/add",
		"/events/add",
		"/user/logout"
	];
	self.bind = function(container){
		function catch_link(e){
			e.preventDefault();
			e.stopImmediatePropagation();
			return async.link(this.href, false);
		}
		if (!container) css = document;
		$(container).find('a:not([class*="editable"]):not(.noasync):not([href^="'+ self.ignore.join('"]):not([href^="') +'"])').on('click', catch_link);
		$('#admin-bar a').off('click', catch_link);
		$('#preview-bar a').off('click', catch_link);
	};
	self.link = function(target, pop_state){
		var uri, container, $document = $(document);
		if (!self.REGEX.test(target) && !pop_state) {
			$document.trigger('async_out');
			if (self.debug) console.log('Caught external link.');
			window.open(target,'_blank');
			return false;
		}
		if (self.debug) console.log('Caught internal link.');
		$document.trigger('async_in');
		container = document.querySelector(self.container);
		if (pop_state) { uri = target; }
		else { uri = self.REGEX.exec(target)[1]; }
		if (self.debug) console.log('URI: '+ uri);
		if (uri != container.dataset['path']){
			self.load = uri.split('?')[0];
			$document.trigger('async_start');
			if (self.load !== uri.split('?')[0]) return false; // check to make sure the request hasn't been stopped
			$.getJSON('/admin/api/async?page='+ encodeURIComponent(uri)).success(function(res){
				if (self.debug) console.log(res);
				if (res.success) {
					$document.trigger('async_pre', res.data);
					if (self.load !== res.data.path) return false;
					container.innerHTML = (self.compile?res.data.page.head:'') + res.data.html + (self.compile?res.data.page.tail:'');
					var title = res.data.page.window_title;
					if (!title) title = res.data.page._window_title;
					if (!title) title = res.data.page.title;
					document.querySelector('head title').innerText = title;
					$document.trigger('async_post', res.data);
					if (self.debug) console.log('Async load successful');
					document.cookie = 'elefant_last_page='+ res.data.path;
					self.bind(container);
					container.dataset['path'] = uri;
					if (!pop_state) {
						history.pushState({data:uri}, document.querySelector('head title').innerText, uri);
					}
					$document.trigger('async_success');
					self._loading = false;
				} else {
					if (self.debug) console.log(res);
					$document.trigger('async_error', res.error);
				}
			}).fail(function(){
				if (self.debug) console.log('Async load unsuccessful');
				$document.trigger('async_fail');
			}).always(function(){
				$document.trigger('async_end');
			});
			return true; // request was sent successfully
		}
		return false;
	};
	console.log('Async wrapper loaded.');
	$(self.bind);
	return self;
}(jQuery));

window.onpopstate = function(e){
	if (e.state) window.async.link(e.state.data, true);
};<|endoftext|>


<commit_before>import React from 'react';

import {FormsyDate, FormsyText} from 'formsy-material-ui';
import {Form} from 'formsy-react';
import RaisedButton from 'material-ui/lib/raised-button';

import {createBook} from '../actions/crudActions';

export default class BookComponent extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
          canSubmit: false
        };
    }

    submit(_data) {
      this.props.onAddBook(_data);
    }

    render() {
      return (
        <Form onValidSubmit={() => {this.submit()}}
            onValid={() => {this.setState({canSubmit: true})}}
            onInvalid={() => {this.setState({canSubmit: false})}}
        >
          <FormsyText
            name='book-title'
            required
            floatingLabelText='Title'
          />
          <FormsyText
            name='book-author-name'
            required
            floatingLabelText='Author'
          />

            <FormsyText
              name='book-nb-pages-read'
              value='0'
              validations='isInt'
            />
            of
            <FormsyText
              name='book-nb-pages'
              required
              validations='isInt'
            />

          <RaisedButton
            type="submit"
            label="Submit"
            disabled={!this.state.canSubmit}
          />
        </Form>
      );
    }
}
<commit_msg>fix parameter passed<commit_after>import React from 'react';

import {FormsyDate, FormsyText} from 'formsy-material-ui';
import {Form} from 'formsy-react';
import RaisedButton from 'material-ui/lib/raised-button';

import {createBook} from '../actions/crudActions';

export default class BookComponent extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
          canSubmit: false
        };
    }

    submit(_data) {
      this.props.onAddBook(_data);
    }

    render() {
      return (
        <Form onValidSubmit={(data) => {this.submit(data)}}
            onValid={() => {this.setState({canSubmit: true})}}
            onInvalid={() => {this.setState({canSubmit: false})}}
        >
          <FormsyText
            name='book-title'
            required
            floatingLabelText='Title'
          />
          <FormsyText
            name='book-author-name'
            required
            floatingLabelText='Author'
          />

            <FormsyText
              name='book-nb-pages-read'
              value='0'
              validations='isInt'
            />
            of
            <FormsyText
              name='book-nb-pages'
              required
              validations='isInt'
            />

          <RaisedButton
            type="submit"
            label="Submit"
            disabled={!this.state.canSubmit}
          />
        </Form>
      );
    }
}
<|endoftext|>


<commit_before>import React, { PropTypes, Children } from "react"

export const storeShape = PropTypes.shape({
  dispatch: PropTypes.func.isRequired,
  getState: PropTypes.func.isRequired,
  subscribe: PropTypes.func.isRequired,
})

export class Provider extends React.Component {
  store = this.props.store

  componentDidMount() {
    this.unsubscribe = this.store.subscribe(() => this.handleStoreUpdate())
  }

  componentWillUnmount() {
    this.unsubscribe()
  }

  handleStoreUpdate() {
    // We always forceUpdate here because elfi skips updating us if the
    // underlying state hasn't changed, so we only receive updates when data
    // actually changed.
    this.forceUpdate()
  }

  getChildContext() {
    return {
      store: this.store,
    }
  }

  render() {
    return Children.only(this.props.children)
  }
}

Provider.propTypes = {
  store: storeShape.isRequired,
  children: PropTypes.element.isRequired,
}

Provider.childContextTypes = {
  store: storeShape.isRequired,
}

export function connect(WrappedComponent) {
  const ConnectedComponent = (props, context) => (
    <WrappedComponent {...props} store={context.store} />
  )

  ConnectedComponent.contextTypes = {
    store: storeShape.isRequired,
  }

  ConnectedComponent.displayName = `Connect$${WrappedComponent.name}`

  return ConnectedComponent
}
<commit_msg>Use the prop-types package<commit_after>import React, { Children } from "react"
import PropTypes from "prop-types"

export const storeShape = PropTypes.shape({
  dispatch: PropTypes.func.isRequired,
  getState: PropTypes.func.isRequired,
  subscribe: PropTypes.func.isRequired,
})

export class Provider extends React.Component {
  store = this.props.store

  componentDidMount() {
    this.unsubscribe = this.store.subscribe(() => this.handleStoreUpdate())
  }

  componentWillUnmount() {
    this.unsubscribe()
  }

  handleStoreUpdate() {
    // We always forceUpdate here because elfi skips updating us if the
    // underlying state hasn't changed, so we only receive updates when data
    // actually changed.
    this.forceUpdate()
  }

  getChildContext() {
    return {
      store: this.store,
    }
  }

  render() {
    return Children.only(this.props.children)
  }
}

Provider.propTypes = {
  store: storeShape.isRequired,
  children: PropTypes.element.isRequired,
}

Provider.childContextTypes = {
  store: storeShape.isRequired,
}

export function connect(WrappedComponent) {
  const ConnectedComponent = (props, context) => (
    <WrappedComponent {...props} store={context.store} />
  )

  ConnectedComponent.contextTypes = {
    store: storeShape.isRequired,
  }

  ConnectedComponent.displayName = `Connect$${WrappedComponent.name}`

  return ConnectedComponent
}
<|endoftext|>


<commit_before>// Copyright (C) 2015 AIZAWA Hina | MIT License
$(document).ready(function () {
    if (!window.fest.isFestPage()) {
        return;
    }
    var $event = $('#event');
    var currentInterval = null;
    var currentTimerId = null;
    var updateByTimer = false;

    var stopCurrentAutoUpdate = function () {
        if (currentTimerId !== null) {
            currentTimerId = window.clearInterval(currentTimerId);
        }
        currentInterval = null;
        currentTimerId = null;
        updateByTimer = false;
    };

    var startAutoUpdate = function () {
        currentInterval = window.fest.conf.updateInterval.get();
        currentTimerId = window.setInterval(
            function () {
                updateByTimer = true;
                $event.trigger('requestUpdateData');
            },
            currentInterval
        );
    };

    // 自動更新が開始・終了または時間の変更が行われた時
    $event.on('updateConfigAutoUpdate updateConfigUpdateInterval', function () {
        if (!window.fest.conf.autoUpdate.get()) {
            // 停止が求められている時
            if (currentTimerId !== null) {
                stopCurrentAutoUpdate();
            }
            return;
        } else {
            // 開始が求められているか時間が変更されている時
            if (currentTimerId !== null) {
                // インターバルが現在動作中のものと同じであれば特に何もする必要はない
                if (currentInterval === window.fest.conf.updateInterval.get()) {
                    return;
                }
            }

            stopCurrentAutoUpdate();
            startAutoUpdate();
            $event.trigger('requestUpdateData');
        }
    });

    // 更新開始時
    $event.on('beginUpdateData', function () {
        if (updateByTimer &&
                window.fest.conf.autoUpdate.get() &&
                window.fest.conf.updateInterval.get() === currentInterval
        ) {
            // 自分で開始した更新なら特に何かをする必要はない
            return;
        }

        // 他人が開始した更新か設定が変更されていたらやり直す
        stopCurrentAutoUpdate();
        if (window.fest.conf.autoUpdate.get()) {
            startAutoUpdate();
        }
    });

    // 更新終了時に自分で開始したことを示すフラグを落とす
    $event.on('afterUpdateData', function () {
        updateByTimer = false;
    });
});
<commit_msg>refs #16, 自動更新間隔をバラつかせる<commit_after>// Copyright (C) 2015 AIZAWA Hina | MIT License
$(document).ready(function () {
    if (!window.fest.isFestPage()) {
        return;
    }
    var $event = $('#event');
    var currentInterval = null;
    var currentTimerId = null;
    var updateByTimer = false;

    var stopCurrentAutoUpdate = function () {
        if (currentTimerId !== null) {
            currentTimerId = window.clearInterval(currentTimerId);
        }
        currentInterval = null;
        currentTimerId = null;
        updateByTimer = false;
    };

    var startAutoUpdate = function () {
        currentInterval = window.fest.conf.updateInterval.get();

        var rand = Math.random() * 0.1 - 0.05; // -0.05～+0.05
        var randomizedInterval = currentInterval * (rand + 1); // 負荷対策として 95%～105% でランダムな間隔にする

        currentTimerId = window.setInterval(
            function () {
                updateByTimer = true;
                $event.trigger('requestUpdateData');
            },
            randomizedInterval
        );
    };

    // 自動更新が開始・終了または時間の変更が行われた時
    $event.on('updateConfigAutoUpdate updateConfigUpdateInterval', function () {
        if (!window.fest.conf.autoUpdate.get()) {
            // 停止が求められている時
            if (currentTimerId !== null) {
                stopCurrentAutoUpdate();
            }
            return;
        } else {
            // 開始が求められているか時間が変更されている時
            if (currentTimerId !== null) {
                // インターバルが現在動作中のものと同じであれば特に何もする必要はない
                if (currentInterval === window.fest.conf.updateInterval.get()) {
                    return;
                }
            }

            stopCurrentAutoUpdate();
            startAutoUpdate();
            $event.trigger('requestUpdateData');
        }
    });

    // 更新開始時
    $event.on('beginUpdateData', function () {
        if (updateByTimer &&
                window.fest.conf.autoUpdate.get() &&
                window.fest.conf.updateInterval.get() === currentInterval
        ) {
            // 自分で開始した更新なら特に何かをする必要はない
            return;
        }

        // 他人が開始した更新か設定が変更されていたらやり直す
        stopCurrentAutoUpdate();
        if (window.fest.conf.autoUpdate.get()) {
            startAutoUpdate();
        }
    });

    // 更新終了時に自分で開始したことを示すフラグを落とす
    $event.on('afterUpdateData', function () {
        updateByTimer = false;
    });
});
<|endoftext|>


<commit_before>// This file handles the drawing

//
// Startup
//
var _isDown, _points, _strokes, _r, _g, _rc; // global variables
var _numStrokes = 0;

function onLoadEvent() {
  _points = new Array(); // point array for current stroke
  _strokes = new Array(); // array of point arrays
  _multipleBodies = new Array();

  _r = new NDollarRecognizer(document.getElementById('useBoundedRotationInvariance').checked);

  var canvas = document.getElementById('myCanvas');
  canvas.setAttribute('height', 600);
  canvas.setAttribute('width', 800);
  _g = canvas.getContext('2d');
  _g.lineWidth = 3;
  _g.font = "16px Gentilis";
  _rc = getCanvasRect(canvas); // canvas rect on page
  _g.fillStyle = "rgb(255,255,136)";
  _g.fillRect(0, 0, _rc.width, 20);

  _isDown = false;

}

function getCanvasRect(canvas) {
  var w = canvas.width;
  var h = canvas.height;

  var cx = canvas.offsetLeft;
  var cy = canvas.offsetTop;
  while (canvas.offsetParent != null)
  {
    canvas = canvas.offsetParent;
    cx += canvas.offsetLeft;
    cy += canvas.offsetTop;
  }
  return {x: cx, y: cy, width: w, height: h};
}

function getScrollY() {
  var scrollY = 0;
  if (typeof(document.body.parentElement) != 'undefined')
  {
    scrollY = document.body.parentElement.scrollTop; // IE
  }
  else if (typeof(window.pageYOffset) != 'undefined')
  {
    scrollY = window.pageYOffset; // FF
  }
  return scrollY;
}

//
// Checkbox option for using limited rotation invariance requires rebuilding the recognizer.
//
function confirmRebuild() {
  if (confirm("Changing this option will discard any user-defined gestures you may have made."))
  {
    _r = new NDollarRecognizer(document.getElementById('useBoundedRotationInvariance').checked);
  }
  else
  {
    var chk = document.getElementById('useBoundedRotationInvariance');
    chk.checked = !chk.checked; // undo click
  }
}

//
// Mouse Events
//
function mouseDownEvent(x, y, button) {
  if (myMatter.state.isDragging) {
    return;
  }
  document.onselectstart = function() { return false; } // disable drag-select
  document.onmousedown = function() { return false; } // disable drag-select
  if (button <= 1)
  {
    _numStrokes++;
    _isDown = true;
    x -= _rc.x;
    y -= _rc.y - getScrollY();

    _points.length = 1; // clear
    _points[0] = new Point(x, y);
    drawText("Recording stroke #" + (_strokes.length + 1) + "...");
    var clr = "rgb(" + rand(0,200) + "," + rand(0,200) + "," + rand(0,200) + ")";
    _g.strokeStyle = clr;
    _g.fillStyle = clr;
    _g.fillRect(x - 4, y - 3, 9, 9);
  }
  else if (button == 2)
  {
    drawText("Recognizing gesture...");
  }
}

function mouseMoveEvent(x, y, button) {
  if (myMatter.state.isDragging) {
    return;
  }
  if (_isDown)
  {
    x -= _rc.x;
    y -= _rc.y - getScrollY();
    _points[_points.length] = new Point(x, y); // append
    drawConnectedPoint(_points.length - 2, _points.length - 1);
  }
}

function mouseUpEvent(x, y, button) {
  document.onselectstart = function() { return true; } // enable drag-select
  document.onmousedown = function() { return true; } // enable drag-select
  if (button <= 1)
  {
    if (_isDown)
    {
      _isDown = false;
      _strokes[_strokes.length] = _points.slice(); // add new copy to set
      drawText("Stroke #" + _strokes.length + " recorded.");
    }
  }
  setTimeout(function() {
    _numStrokes = _numStrokes <= 0 ? 0 : _numStrokes - 1;
    if (_numStrokes === 0) {
        if (myMatter.state.multipleBodiesMode) {
            _multipleBodies.push(_strokes);
            _strokes = [];
            _points = [];
        } else {
            drawFinished();
        }
    }
},500);
}

function drawConnectedPoint(from, to) {
  _g.beginPath();
  _g.moveTo(_points[from].x, _points[from].y);
  _g.lineTo(_points[to].x, _points[to].y);
  _g.closePath();
  _g.stroke();
}

function drawText(str) {
  _g.fillStyle = "rgb(255,255,136)";
  _g.fillRect(0, 0, _rc.width, 20);
  _g.fillStyle = "rgb(0,0,255)";
  _g.fillText(str, 1, 14);
}

function rand(low, high) {
  return Math.floor((high - low + 1) * Math.random()) + low;
}

function round(n, d) { // round 'n' to 'd' decimals
  d = Math.pow(10, d);
  return Math.round(n * d) / d
}

//
// Multistroke Adding and Clearing
//
function onClickAddExisting() {
  if (_strokes.length > 0)
  {
    if (_strokes.length < 5 || confirm("With " + _strokes.length + " component strokes, it will take a few moments to add this gesture. Proceed?"))
    {
      var multistrokes = document.getElementById('multistrokes');
      var name = multistrokes[multistrokes.selectedIndex].value;
      var num = _r.AddGesture(name, document.getElementById('useBoundedRotationInvariance').checked, _strokes);
      drawText("\"" + name + "\" added. Number of \"" + name + "\"s defined: " + num + ".");
      _points.length = 0; // clear and signal to clear strokes on next mousedown
    }
  }
}

function onClickAddCustom() {
  var name = document.getElementById('custom').value;
  if (_strokes.length > 0 && name.length > 0)
  {
    if (_strokes.length < 5 || confirm("With " + _strokes.length + " component strokes, it will take a few moments to add this gesture. Proceed?"))
    {
      var num = _r.AddGesture(name, document.getElementById('useBoundedRotationInvariance').checked, _strokes);
      drawText("\"" + name + "\" added. Number of \"" + name + "\"s defined: " + num + ".");
      _points.length = 0; // clear and signal to clear strokes on next mousedown
    }
  }
}

function onClickCustom() {
  document.getElementById('custom').select();
}

function onClickDelete() {
  var num = _r.DeleteUserGestures(); // deletes any user-defined multistrokes
  alert("All user-defined gestures have been deleted. Only the 1 predefined gesture remains for each of the " + num + " types.");
  _points.length = 0; // clear and signal to clear strokes on next mousedown
}

function onClickClearStrokes() {
  _points.length = 0; // clear and signal to clear strokes on next mousedown
  _g.clearRect(0, 0, _rc.width, _rc.height);
  drawText("Canvas cleared.");
}

function clearStrokes() {
  console.log("clearStrokes");
  _points = [];
  _strokes = [];
  _g.clearRect(0, 0, _rc.width, _rc.height);
}

function drawFinished()
{
  recognizeBody(_strokes);
  clearStrokes();
}

function activateMultipleBodiesMode(event) {
    jQuery('.multipleBodiesButton').css({
        'background-color': '#c55'
    });
    myMatter.state.multipleBodiesMode = true;
}

function deactivateMultipleBodiesMode(event) {
    jQuery('.multipleBodiesButton').css({
        'background-color': '#5c5'
    });
    myMatter.state.multipleBodiesMode = false;
    recognizeMultipleBodies();
}

function checkForModeActivation(event) {
    if (event.keyCode === 17) {
        activateMultipleBodiesMode();
    }
}

function checkForModeDeactivation(event) {
    if (event.keyCode === 17) {
        deactivateMultipleBodiesMode();
    }
}

function recognizeBody(strokes) {
    if (strokes.length > 1 || (strokes.length == 1 && strokes[0].length >= 10))
    {
      var result = _r.Recognize(strokes, document.getElementById('useBoundedRotationInvariance').checked, document.getElementById('requireSameNoOfStrokes').checked, document.getElementById('useProtractor').checked);
      drawText("Result: " + result.Name + " (" + round(result.Score,2) + ").");
      console.log(result.Name);
      var shapeBuilder = new ShapeBuilder();
      switch (result.Name) {
        case "Rectangle":
          var rectangle = shapeBuilder.getRectangle(strokes[0]);
          myMatter.addRectangle(rectangle.x, rectangle.y, rectangle.Width, rectangle.Height);
          break;
        case "Circle":
          var circle = shapeBuilder.getCircle(strokes[0]);
          myMatter.addCircle(circle.x, circle.y, circle.Radius);
          break;
        case "X":
          var center = shapeBuilder.getCenterOfX(strokes);
          myMatter.removeBodyAt(center);
      }

    }
    else
    {
      drawText("Too little input made. Please try again.");
    }
}

function recognizeMultipleBodies() {
    console.log(_multipleBodies);
    for (var i = 0; i < _multipleBodies.length; i++) {
        recognizeBody(_multipleBodies[i]);
    }
    clearStrokes();
}
<commit_msg>only one-stroke gestures; recognizes them instantly<commit_after>// This file handles the drawing

//
// Startup
//
var _isDown, _points, _strokes, _r, _g, _rc; // global variables

function onLoadEvent() {
  _points = new Array(); // point array for current stroke
  _strokes = new Array(); // array of point arrays
  _multipleBodies = new Array();

  _r = new NDollarRecognizer(document.getElementById('useBoundedRotationInvariance').checked);

  var canvas = document.getElementById('myCanvas');
  canvas.setAttribute('height', 600);
  canvas.setAttribute('width', 800);
  _g = canvas.getContext('2d');
  _g.lineWidth = 3;
  _g.font = "16px Gentilis";
  _rc = getCanvasRect(canvas); // canvas rect on page
  _g.fillStyle = "rgb(255,255,136)";
  _g.fillRect(0, 0, _rc.width, 20);

  _isDown = false;

}

function getCanvasRect(canvas) {
  var w = canvas.width;
  var h = canvas.height;

  var cx = canvas.offsetLeft;
  var cy = canvas.offsetTop;
  while (canvas.offsetParent != null)
  {
    canvas = canvas.offsetParent;
    cx += canvas.offsetLeft;
    cy += canvas.offsetTop;
  }
  return {x: cx, y: cy, width: w, height: h};
}

function getScrollY() {
  var scrollY = 0;
  if (typeof(document.body.parentElement) != 'undefined')
  {
    scrollY = document.body.parentElement.scrollTop; // IE
  }
  else if (typeof(window.pageYOffset) != 'undefined')
  {
    scrollY = window.pageYOffset; // FF
  }
  return scrollY;
}

//
// Checkbox option for using limited rotation invariance requires rebuilding the recognizer.
//
function confirmRebuild() {
  if (confirm("Changing this option will discard any user-defined gestures you may have made."))
  {
    _r = new NDollarRecognizer(document.getElementById('useBoundedRotationInvariance').checked);
  }
  else
  {
    var chk = document.getElementById('useBoundedRotationInvariance');
    chk.checked = !chk.checked; // undo click
  }
}

//
// Mouse Events
//
function mouseDownEvent(x, y, button) {
  if (myMatter.state.isDragging) {
    return;
  }
  document.onselectstart = function() { return false; } // disable drag-select
  document.onmousedown = function() { return false; } // disable drag-select
  if (button <= 1)
  {
    _isDown = true;
    x -= _rc.x;
    y -= _rc.y - getScrollY();

    _points.length = 1; // clear
    _points[0] = new Point(x, y);
    drawText("Recording stroke #" + (_strokes.length + 1) + "...");
    var clr = "rgb(" + rand(0,200) + "," + rand(0,200) + "," + rand(0,200) + ")";
    _g.strokeStyle = clr;
    _g.fillStyle = clr;
    _g.fillRect(x - 4, y - 3, 9, 9);
  }
  else if (button == 2)
  {
    drawText("Recognizing gesture...");
  }
}

function mouseMoveEvent(x, y, button) {
  if (myMatter.state.isDragging) {
    return;
  }
  if (_isDown)
  {
    x -= _rc.x;
    y -= _rc.y - getScrollY();
    _points[_points.length] = new Point(x, y); // append
    drawConnectedPoint(_points.length - 2, _points.length - 1);
  }
}

function mouseUpEvent(x, y, button) {
  document.onselectstart = function() { return true; } // enable drag-select
  document.onmousedown = function() { return true; } // enable drag-select
  if (button <= 1)
  {
    if (_isDown)
    {
      _isDown = false;
      _strokes[_strokes.length] = _points.slice(); // add new copy to set
      drawText("Stroke #" + _strokes.length + " recorded.");
    }
  }
  if (myMatter.state.multipleBodiesMode) {
    _multipleBodies.push(_strokes);
    _strokes = [];
    _points = [];
  } else {
    drawFinished();
  }
}

function drawConnectedPoint(from, to) {
  _g.beginPath();
  _g.moveTo(_points[from].x, _points[from].y);
  _g.lineTo(_points[to].x, _points[to].y);
  _g.closePath();
  _g.stroke();
}

function drawText(str) {
  _g.fillStyle = "rgb(255,255,136)";
  _g.fillRect(0, 0, _rc.width, 20);
  _g.fillStyle = "rgb(0,0,255)";
  _g.fillText(str, 1, 14);
}

function rand(low, high) {
  return Math.floor((high - low + 1) * Math.random()) + low;
}

function round(n, d) { // round 'n' to 'd' decimals
  d = Math.pow(10, d);
  return Math.round(n * d) / d
}

//
// Multistroke Adding and Clearing
//
function onClickAddExisting() {
  if (_strokes.length > 0)
  {
    if (_strokes.length < 5 || confirm("With " + _strokes.length + " component strokes, it will take a few moments to add this gesture. Proceed?"))
    {
      var multistrokes = document.getElementById('multistrokes');
      var name = multistrokes[multistrokes.selectedIndex].value;
      var num = _r.AddGesture(name, document.getElementById('useBoundedRotationInvariance').checked, _strokes);
      drawText("\"" + name + "\" added. Number of \"" + name + "\"s defined: " + num + ".");
      _points.length = 0; // clear and signal to clear strokes on next mousedown
    }
  }
}

function onClickAddCustom() {
  var name = document.getElementById('custom').value;
  if (_strokes.length > 0 && name.length > 0)
  {
    if (_strokes.length < 5 || confirm("With " + _strokes.length + " component strokes, it will take a few moments to add this gesture. Proceed?"))
    {
      var num = _r.AddGesture(name, document.getElementById('useBoundedRotationInvariance').checked, _strokes);
      drawText("\"" + name + "\" added. Number of \"" + name + "\"s defined: " + num + ".");
      _points.length = 0; // clear and signal to clear strokes on next mousedown
    }
  }
}

function onClickCustom() {
  document.getElementById('custom').select();
}

function onClickDelete() {
  var num = _r.DeleteUserGestures(); // deletes any user-defined multistrokes
  alert("All user-defined gestures have been deleted. Only the 1 predefined gesture remains for each of the " + num + " types.");
  _points.length = 0; // clear and signal to clear strokes on next mousedown
}

function onClickClearStrokes() {
  _points.length = 0; // clear and signal to clear strokes on next mousedown
  _g.clearRect(0, 0, _rc.width, _rc.height);
  drawText("Canvas cleared.");
}

function clearStrokes() {
  console.log("clearStrokes");
  _points = [];
  _strokes = [];
  _g.clearRect(0, 0, _rc.width, _rc.height);
}

function drawFinished()
{
  recognizeBody(_strokes);
  clearStrokes();
}

function activateMultipleBodiesMode(event) {
    jQuery('.multipleBodiesButton').css({
        'background-color': '#c55'
    });
    myMatter.state.multipleBodiesMode = true;
}

function deactivateMultipleBodiesMode(event) {
    jQuery('.multipleBodiesButton').css({
        'background-color': '#5c5'
    });
    myMatter.state.multipleBodiesMode = false;
    recognizeMultipleBodies();
}

function checkForModeActivation(event) {
    if (event.keyCode === 17) {
        activateMultipleBodiesMode();
    }
}

function checkForModeDeactivation(event) {
    if (event.keyCode === 17) {
        deactivateMultipleBodiesMode();
    }
}

function recognizeBody(strokes) {
    if (strokes.length > 1 || (strokes.length == 1 && strokes[0].length >= 10))
    {
      var result = _r.Recognize(strokes, document.getElementById('useBoundedRotationInvariance').checked, document.getElementById('requireSameNoOfStrokes').checked, document.getElementById('useProtractor').checked);
      drawText("Result: " + result.Name + " (" + round(result.Score,2) + ").");
      console.log(result.Name);
      var shapeBuilder = new ShapeBuilder();
      switch (result.Name) {
        case "Rectangle":
          var rectangle = shapeBuilder.getRectangle(strokes[0]);
          myMatter.addRectangle(rectangle.x, rectangle.y, rectangle.Width, rectangle.Height);
          break;
        case "Circle":
          var circle = shapeBuilder.getCircle(strokes[0]);
          myMatter.addCircle(circle.x, circle.y, circle.Radius);
          break;
        case "X":
          var center = shapeBuilder.getCenterOfX(strokes);
          myMatter.removeBodyAt(center);
      }

    }
    else
    {
      drawText("Too little input made. Please try again.");
    }
}

function recognizeMultipleBodies() {
    console.log(_multipleBodies);
    for (var i = 0; i < _multipleBodies.length; i++) {
        recognizeBody(_multipleBodies[i]);
    }
    clearStrokes();
}
<|endoftext|>


<commit_before>'use strict';

function canvas_draw(){
    canvas_buffer.clearRect(
      0,
      0,
      canvas_width,
      canvas_height
    );

    draw_logic();

    if(canvas_menu){
        canvas_buffer.save();

        canvas_buffer.fillStyle = '#111';
        canvas_buffer.fillRect(
          canvas_x - 125,
          canvas_y - 50,
          250,
          100
        );

        canvas_buffer.fillStyle = '#fff';
        canvas_buffer.font = canvas_fonts['medium'];
        canvas_buffer.textAlign = 'center';
        canvas_buffer.textBaseline = 'middle';
        canvas_buffer.fillText(
          canvas_resume,
          canvas_x,
          canvas_y - 25
        );
        canvas_buffer.fillText(
          canvas_quit,
          canvas_x,
          canvas_y + 25
        );

        canvas_buffer.restore();
    }

    canvas_canvas.clearRect(
      0,
      0,
      canvas_width,
      canvas_height
    );
    canvas_canvas.drawImage(
      document.getElementById('buffer'),
      0,
      0
    );
}

function canvas_drawloop(){
    canvas_draw();
    canvas_animationFrame = window.requestAnimationFrame(canvas_drawloop);
}

// Required args: vertices
// Optional args: properties, style, type
function canvas_draw_path(args){
    args = core_args({
      'args': args,
      'defaults': {
        'properties': {},
        'style': canvas_style,
        'type': 'lineTo',
      },
    });

    canvas_buffer.beginPath();
    for(var vertex in args['vertices']){
        canvas_buffer[args['vertices'][vertex]['type'] || args['type']](
          args['vertices'][vertex]['x'],
          args['vertices'][vertex]['y'],
          args['vertices'][vertex]['radius'],
          args['vertices'][vertex]['startAngle'],
          args['vertices'][vertex]['endAngle'],
          args['vertices'][vertex]['antiClockwise']
        );
    }
    canvas_buffer.closePath();

    for(var property in args['properties']){
        canvas_buffer[property] = args['properties'][property];
    }

    canvas_buffer[args['style']]();
}

function canvas_init(){
    canvas_resize();
    canvas_setmode({
      'mode': 0,
    });
}

function canvas_menu_quit(){
    if(canvas_menu){
        canvas_setmode({
          'mode': 0,
        });
    }
}

function canvas_menu_toggle(){
    canvas_menu = !canvas_menu;
}

function canvas_resize(){
    if(canvas_mode <= 0){
        return;
    }

    canvas_height = window.innerHeight;
    document.getElementById('buffer').height = canvas_height;
    document.getElementById('canvas').height = canvas_height;
    canvas_y = canvas_height / 2;

    canvas_width = window.innerWidth;
    document.getElementById('buffer').width = canvas_width;
    document.getElementById('canvas').width = canvas_width;
    canvas_x = canvas_width / 2;

    canvas_buffer.font = canvas_fonts['medium'];

    core_call({
      'todo': 'resize_logic',
    });
}

// Required args: mode
// Optional args: newgame
function canvas_setmode(args){
    args = core_args({
      'args': args,
      'defaults': {
        'newgame': false,
      },
    });

    window.cancelAnimationFrame(canvas_animationFrame);
    window.clearInterval(canvas_interval);

    canvas_menu = false;
    canvas_mode = args['mode'];

    if(core_type({
      'var': 'setmode_logic',
      'type': 'function',
    })){
        setmode_logic(args['newgame']);

    }else{
        canvas_mode = 1;
        args['newgame'] = true;
    }

    // Main menu mode.
    if(canvas_mode === 0){
        canvas_buffer = 0;
        canvas_canvas = 0;
        return;
    }

    // Simulation modes.
    if(args['newgame']){
        var properties = '';

        if(!canvas_oncontextmenu){
            properties = ' oncontextmenu="return false" ';
        }

        document.body.innerHTML =
          '<canvas id=canvas' + properties + '></canvas><canvas id=buffer></canvas>';

        canvas_buffer = document.getElementById('buffer').getContext('2d');
        canvas_canvas = document.getElementById('canvas').getContext('2d');

        canvas_resize();
    }

    core_call({
      'args': canvas_mode,
      'todo': 'load_level',
    });

    canvas_animationFrame = window.requestAnimationFrame(canvas_drawloop);

    if(core_type({
      'var': 'logic',
      'type': 'function',
    })){
        canvas_interval = window.setInterval(
          logic,
          canvas_interval_ms
        );
    }
}

var canvas_animationFrame = 0;
var canvas_buffer = 0;
var canvas_canvas = 0;
var canvas_fonts = {
  'big': '300% monospace',
  'medium': '200% monospace',
  'small': '100% monospace',
};
var canvas_height = 0;
var canvas_interval = 0;
var canvas_interval_ms = 25;
var canvas_menu = false;
var canvas_mode = 0;
var canvas_oncontextmenu = true;
var canvas_quit = 'Q = Main Menu';
var canvas_resume = 'ESC = Resume';
var canvas_style = 'fill';
var canvas_width = 0;
var canvas_x = 0;
var canvas_y = 0;

window.onresize = canvas_resize;
<commit_msg>added canvas_gradient()<commit_after>'use strict';

function canvas_draw(){
    canvas_buffer.clearRect(
      0,
      0,
      canvas_width,
      canvas_height
    );

    draw_logic();

    if(canvas_menu){
        canvas_buffer.save();

        canvas_buffer.fillStyle = '#111';
        canvas_buffer.fillRect(
          canvas_x - 125,
          canvas_y - 50,
          250,
          100
        );

        canvas_buffer.fillStyle = '#fff';
        canvas_buffer.font = canvas_fonts['medium'];
        canvas_buffer.textAlign = 'center';
        canvas_buffer.textBaseline = 'middle';
        canvas_buffer.fillText(
          canvas_resume,
          canvas_x,
          canvas_y - 25
        );
        canvas_buffer.fillText(
          canvas_quit,
          canvas_x,
          canvas_y + 25
        );

        canvas_buffer.restore();
    }

    canvas_canvas.clearRect(
      0,
      0,
      canvas_width,
      canvas_height
    );
    canvas_canvas.drawImage(
      document.getElementById('buffer'),
      0,
      0
    );
}

function canvas_drawloop(){
    canvas_draw();
    canvas_animationFrame = window.requestAnimationFrame(canvas_drawloop);
}

// Required args: vertices
// Optional args: properties, style, type
function canvas_draw_path(args){
    args = core_args({
      'args': args,
      'defaults': {
        'properties': {},
        'style': canvas_style,
        'type': 'lineTo',
      },
    });

    canvas_buffer.beginPath();
    for(var vertex in args['vertices']){
        canvas_buffer[args['vertices'][vertex]['type'] || args['type']](
          args['vertices'][vertex]['x'],
          args['vertices'][vertex]['y'],
          args['vertices'][vertex]['radius'],
          args['vertices'][vertex]['startAngle'],
          args['vertices'][vertex]['endAngle'],
          args['vertices'][vertex]['antiClockwise']
        );
    }
    canvas_buffer.closePath();

    for(var property in args['properties']){
        canvas_buffer[property] = args['properties'][property];
    }

    canvas_buffer[args['style']]();
}

// Required args: stops
// Optional args: height, width, x, y
function canvas_gradient(args){
    args = core_args({
      'args': args,
      'defaults': {
        'height': 0,
        'width': 0,
        'x': 0,
        'y': 0,
      },
    });

    var gradient = canvas_buffer.createLinearGradient(
      args['x'],
      args['y'],
      args['width'],
      args['height']
    );
    for(var step in args['steps']){
        gradient.addColorStop(
          args['steps'][step]['offset'] || 0,
          args['steps'][step]['color'] || '#000'
        );
    }
    return gradient;
}

function canvas_init(){
    canvas_resize();
    canvas_setmode({
      'mode': 0,
    });
}

function canvas_menu_quit(){
    if(canvas_menu){
        canvas_setmode({
          'mode': 0,
        });
    }
}

function canvas_menu_toggle(){
    canvas_menu = !canvas_menu;
}

function canvas_resize(){
    if(canvas_mode <= 0){
        return;
    }

    canvas_height = window.innerHeight;
    document.getElementById('buffer').height = canvas_height;
    document.getElementById('canvas').height = canvas_height;
    canvas_y = canvas_height / 2;

    canvas_width = window.innerWidth;
    document.getElementById('buffer').width = canvas_width;
    document.getElementById('canvas').width = canvas_width;
    canvas_x = canvas_width / 2;

    canvas_buffer.font = canvas_fonts['medium'];

    core_call({
      'todo': 'resize_logic',
    });
}

// Required args: mode
// Optional args: newgame
function canvas_setmode(args){
    args = core_args({
      'args': args,
      'defaults': {
        'newgame': false,
      },
    });

    window.cancelAnimationFrame(canvas_animationFrame);
    window.clearInterval(canvas_interval);

    canvas_menu = false;
    canvas_mode = args['mode'];

    if(core_type({
      'var': 'setmode_logic',
      'type': 'function',
    })){
        setmode_logic(args['newgame']);

    }else{
        canvas_mode = 1;
        args['newgame'] = true;
    }

    // Main menu mode.
    if(canvas_mode === 0){
        canvas_buffer = 0;
        canvas_canvas = 0;
        return;
    }

    // Simulation modes.
    if(args['newgame']){
        var properties = '';

        if(!canvas_oncontextmenu){
            properties = ' oncontextmenu="return false" ';
        }

        document.body.innerHTML =
          '<canvas id=canvas' + properties + '></canvas><canvas id=buffer></canvas>';

        canvas_buffer = document.getElementById('buffer').getContext('2d');
        canvas_canvas = document.getElementById('canvas').getContext('2d');

        canvas_resize();
    }

    core_call({
      'args': canvas_mode,
      'todo': 'load_level',
    });

    canvas_animationFrame = window.requestAnimationFrame(canvas_drawloop);

    if(core_type({
      'var': 'logic',
      'type': 'function',
    })){
        canvas_interval = window.setInterval(
          logic,
          canvas_interval_ms
        );
    }
}

var canvas_animationFrame = 0;
var canvas_buffer = 0;
var canvas_canvas = 0;
var canvas_fonts = {
  'big': '300% monospace',
  'medium': '200% monospace',
  'small': '100% monospace',
};
var canvas_height = 0;
var canvas_interval = 0;
var canvas_interval_ms = 25;
var canvas_menu = false;
var canvas_mode = 0;
var canvas_oncontextmenu = true;
var canvas_quit = 'Q = Main Menu';
var canvas_resume = 'ESC = Resume';
var canvas_style = 'fill';
var canvas_width = 0;
var canvas_x = 0;
var canvas_y = 0;

window.onresize = canvas_resize;
<|endoftext|>


<commit_before>var colors = require('colors'),
    AWS = require('aws-sdk'),
    EventEmitter = require('events').EventEmitter,
    inherits = require('util').inherits;

//Main function of the module
function SQSLogger(config){
    //Checking if config exist and prevent errors if don't.
    config = config || {};
    //Checking if QueueUrl exists, if doesn't an errors throws and stop the execution
    if(config.QueueUrl == null){
        var e = new Error('queueURL'.yellow + ' must be defined in the config');
        throw e;
        return e;
    } else {
        this.queueURL = config.QueueUrl;
    }
    //Setting all variables
    this.apiVersion = config.apiVersion || 'latest';
    this.region = config.region || 'us-east-1';
    this.delay = config.delaySeconds || 0;
    this.verbose = config.verbose || false;
    if(process.env.AWS_ACCESS_KEY_ID && process.env.AWS_SECRET_ACCESS_KEY) {
        AWS.config.update({accessKeyId: process.env.AWS_ACCESS_KEY_ID, secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY});
    }
    this.SQS = new AWS.SQS({apiVersion: this.apiVersion,region:this.region});

    if(this.verbose) console.log('Creating Logger');
    if(this.verbose) console.log('QueuUrl'.green,this.queueURL);
    if(this.verbose) console.log('region'.green,this.region);
    if(this.verbose) console.log('delaySeconds'.green,this.delay);
    if(this.verbose) console.log('verbose'.green,this.verbose);

    //Setting the default params to use on every Message
    this.gparams = {
        MessageBody: '',
        QueueUrl: this.queueURL,
        DelaySeconds: 0
    };

    //sendMessage function
    //Send a message to the Queue
    //Accepts a message string and a funcion callback
    this.sendMessage = function sendMessage(message,callback){
        if(message == null || message == undefined || message === '' || message.toString != null){
            var e = new Error('bad message');
            throw e;
            return e;
        }
        var params = Object.create(this.gparams);
        params.MessageBody = message.toString();
        if(this.verbose) console.info('Sending Message',message);

        this.SQS.sendMessage(params, function SQSSendMessage(err, data) {
            //if there is an error emits it
            if(err) {
                if(this.verbose) console.error('There was an error'.red,err);

                return this.emit('error',err);
            }

            //if the message was sent succesfully emits the sent with the data
            if(this.verbose) console.log('Message succesfully sent'.green);

            this.emit('sent',data);
            if(callback)callback(data,this);
            return;
        }.bind(this));
    }
}
//Inerits forom the EventEmitter
inherits(SQSLogger,EventEmitter);

module.exports = SQSLogger;
<commit_msg>Fixing toString validation<commit_after>var colors = require('colors'),
    AWS = require('aws-sdk'),
    EventEmitter = require('events').EventEmitter,
    inherits = require('util').inherits;

//Main function of the module
function SQSLogger(config){
    //Checking if config exist and prevent errors if don't.
    config = config || {};
    //Checking if QueueUrl exists, if doesn't an errors throws and stop the execution
    if(config.QueueUrl == null){
        var e = new Error('queueURL'.yellow + ' must be defined in the config');
        throw e;
        return e;
    } else {
        this.queueURL = config.QueueUrl;
    }
    //Setting all variables
    this.apiVersion = config.apiVersion || 'latest';
    this.region = config.region || 'us-east-1';
    this.delay = config.delaySeconds || 0;
    this.verbose = config.verbose || false;
    if(process.env.AWS_ACCESS_KEY_ID && process.env.AWS_SECRET_ACCESS_KEY) {
        AWS.config.update({accessKeyId: process.env.AWS_ACCESS_KEY_ID, secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY});
    }
    this.SQS = new AWS.SQS({apiVersion: this.apiVersion,region:this.region});

    if(this.verbose) console.log('Creating Logger');
    if(this.verbose) console.log('QueuUrl'.green,this.queueURL);
    if(this.verbose) console.log('region'.green,this.region);
    if(this.verbose) console.log('delaySeconds'.green,this.delay);
    if(this.verbose) console.log('verbose'.green,this.verbose);

    //Setting the default params to use on every Message
    this.gparams = {
        MessageBody: '',
        QueueUrl: this.queueURL,
        DelaySeconds: 0
    };

    //sendMessage function
    //Send a message to the Queue
    //Accepts a message string and a funcion callback
    this.sendMessage = function sendMessage(message,callback){
        if(message == null || message == undefined || message === '' || message.toString == null){
            var e = new Error('bad message');
            throw e;
            return e;
        }
        var params = Object.create(this.gparams);
        params.MessageBody = message.toString();
        if(this.verbose) console.info('Sending Message',message);

        this.SQS.sendMessage(params, function SQSSendMessage(err, data) {
            //if there is an error emits it
            if(err) {
                if(this.verbose) console.error('There was an error'.red,err);

                return this.emit('error',err);
            }

            //if the message was sent succesfully emits the sent with the data
            if(this.verbose) console.log('Message succesfully sent'.green);

            this.emit('sent',data);
            if(callback)callback(data,this);
            return;
        }.bind(this));
    }
}
//Inerits forom the EventEmitter
inherits(SQSLogger,EventEmitter);

module.exports = SQSLogger;
<|endoftext|>


<commit_before>Vue.use(VueMaterial);
const app = new Vue({
    el: "#app",
    data: {
        loglevel: "INFO",
        title: "Liquid Radio",
        notSupportedMessage: "Your browser does not support audio streams, please update.",
        repoLink: "https://github.com/Trikolon/liquidradio",
        version: "0.5",
        stream: {
            play: false,
            offline: false,
            loading: false,
            volume: 0.6,
            el: "streamEl",
            currentStation: undefined,
            stations
        },
        twitterFeed: {
            profile: "https://twitter.com/thecoffeepanda",
            theme: "dark"
        },
        notification: {
            message: "",
            duration: 4000,
            position: "bottom center",
            el: "notification-bar"
        }
    },
    watch: {
        "stream.play" (state) {
            if (!state) {
                this.stream.loading = false;
            }
            this.updatePlayState(state);
        },
        "stream.offline" (state) {
            if (state) {
                log.debug("Stream went offline");
                this.stream.play = false;
            }
        },
        "stream.volume" () {
            this.$refs[this.stream.el].volume = this.stream.volume;
        }

    },
    mounted() {
        const audioEl = this.$refs[this.stream.el];

        // Watch external changes
        audioEl.addEventListener("play", () => {
            this.stream.play = true;
            this.stream.loading = true;
        });
        audioEl.addEventListener("pause", () => {
            this.stream.play = false;
        });
        audioEl.addEventListener("volumechange", () => {
            this.stream.volume = this.$refs[this.stream.el].volume;
        });
        audioEl.addEventListener("stalled", () => {
            this.notify("Stream stalled, check your connection.");
        });

        // Audio stream has sufficiently buffered and starts playing
        audioEl.addEventListener("playing", () => {
            this.stream.loading = false;
            this.notify(`Now playing ${this.stream.currentStation.title}`, 2000);
        });

        //Attach error handler to last source element
        const sources = Array.from(audioEl.getElementsByTagName("source"));
        sources[sources.length - 1].addEventListener("error", this.streamError);

        //Attach error handler to audio stream element
        audioEl.addEventListener("error", this.streamError);
    },
    beforeMount() {
        //Set default station to first in station list.
        //This has to be done after data init but before dom-bind.
        [this.stream.currentStation] = this.stream.stations;

        //Load config
        try {
            let volume = localStorage.getItem("volume");
            if (volume) {
                this.stream.volume = volume;
            }
        }
        catch (error) {
            log.debug("Local storage is not supported by browser. Using default settings.", error);
        }
    },
    methods: {
        /**
         * Toggles visibility of left side navigation
         */
        toggleNav() {
            this.$refs.nav.toggle();
        },
        /**
         * Switches to a different station in stream object and changes play state to true.
         * No action if station id is invalid
         * @param id - Identifier of station to switch to.
         */
        switchStation(id) {
            if (id === this.stream.currentStation.id) return;
            for (let i = 0; i < this.stream.stations.length; i++) {
                if (this.stream.stations[i].id === id) {
                    this.stream.currentStation = this.stream.stations[i];
                    this.stream.currentStationSource = 0;
                    this.stream.play = false;
                    // Wait for vue to update src url in audio element before triggering play()
                    Vue.nextTick(() => {
                        this.catchUp();
                        // this.stream.offline = false;
                        // this.stream.play = true;
                    });
                    log.debug("Switched station to", this.stream.currentStation.title, this.stream.currentStation);
                    return;
                }
            }
            log.error("Attempted to switch to station with invalid station id", id);
        },
        /**
         * Modify stream volume by modifier value. Bounds of volume are 0 - 1
         * @param value - Positive or negative number that will be added.
         */
        changeVolume(value) {
            if (this.stream.volume + value > 1) {
                this.stream.volume = 1;
                log.debug("Hit upper bound for volume ctrl");
            }
            else if (this.stream.volume + value < 0) {
                this.stream.volume = 0;
                log.debug("Hit lower bound for volume ctrl");
            }
            else {
                this.stream.volume = Math.round((this.stream.volume + value) * 10) / 10;
                log.debug(`Modified volume by ${value} to ${this.stream.volume}`);
            }
            // Save volume setting to config
            try {
                localStorage.setItem("volume", this.stream.volume);
            }
            catch (error) {
                log.debug("Can't store volume setting because localstorage is not supported by browser", error);
            }
        },
        /**
         * Trigger play or pause for audio el depending on state.
         * @param state - true if play, false if pause.
         */
        updatePlayState(state) {
            const el = this.$refs[this.stream.el];
            log.debug("play state changed to", state);
            if (state) {
                el.play();
                log.debug("started stream");
            }
            else {
                el.pause();
                log.debug("stopped stream");
            }
        },
        /**
         * Reloads audio element to catch up in stream.
         */
        catchUp() {
            const el = this.$refs[this.stream.el];
            el.load();
            if (this.stream.play) {
                this.updatePlayState(true);
            }
            else {
                this.stream.play = true;
            }
            this.stream.offline = false;
        },
        /**
         * Error handler audio stream.
         * @param e - Event fired including error information.
         */
        streamError(e) {
            log.error("Error in stream", e);
            let msg = "Unknown Error";

            // Error from source tag
            if (e.target.nodeName === "SOURCE") {
                const audioEl = this.$refs[this.stream.el];
                log.debug("Error originates from SOURCE tag");

                //NETWORK_NO_SOURCE
                if (audioEl.networkState === 3) {
                    msg = "Stream offline"
                }
            }
            // Error from audio tag
            else if (e.target.nodeName === "AUDIO") {
                log.debug("Error originates from AUDIO tag");
                log.error(e.target.error.code, e.target.error.message);
                msg = "Error: ";

                switch (e.target.error.code) {
                    case e.target.error.MEDIA_ERR_ABORTED:
                        msg += "Playback aborted by user.";
                        break;
                    case e.target.error.MEDIA_ERR_NETWORK:
                        msg += "Network error. Check your connection.";
                        break;
                    case e.target.error.MEDIA_ERR_DECODE:
                        msg += "Decoding error.";
                        break;
                    default:
                        msg += `Unknown error code ${e.target.code}`;
                        break;
                }
            }
            this.stream.offline = true;
            this.notify(msg);
        },
        /**
         * Shows notification
         * @param message - Text for notification.
         * @param duration - Duration of visibility.
         */
        notify(message, duration) {
            const el = this.$refs[this.notification.el];
            if (duration) {
                this.notification.duration = duration;
            }
            this.notification.message = message;
            el.open();
        }
    }
});
log.setDefaultLevel(app.loglevel);<commit_msg>only check localstorage support initially<commit_after>Vue.use(VueMaterial);
const app = new Vue({
    el: "#app",
    data: {
        loglevel: "INFO",
        title: "Liquid Radio",
        notSupportedMessage: "Your browser does not support audio streams, please update.",
        repoLink: "https://github.com/Trikolon/liquidradio",
        version: "0.5",
        stream: {
            play: false,
            offline: false,
            loading: false,
            volume: 0.6,
            el: "streamEl",
            currentStation: undefined,
            stations
        },
        twitterFeed: {
            profile: "https://twitter.com/thecoffeepanda",
            theme: "dark"
        },
        notification: {
            message: "",
            duration: 4000,
            position: "bottom center",
            el: "notification-bar"
        },
        storageSupported: typeof(Storage) !== "undefined"
    },
    watch: {
        "stream.play" (state) {
            if (!state) {
                this.stream.loading = false;
            }
            this.updatePlayState(state);
        },
        "stream.offline" (state) {
            if (state) {
                log.debug("Stream went offline");
                this.stream.play = false;
            }
        },
        "stream.volume" () {
            this.$refs[this.stream.el].volume = this.stream.volume;
        }
    },
    mounted() {
        const audioEl = this.$refs[this.stream.el];

        // Watch external changes
        audioEl.addEventListener("play", () => {
            this.stream.play = true;
            this.stream.loading = true;
        });
        audioEl.addEventListener("pause", () => {
            this.stream.play = false;
        });
        audioEl.addEventListener("volumechange", () => {
            this.stream.volume = this.$refs[this.stream.el].volume;
        });
        audioEl.addEventListener("stalled", () => {
            this.notify("Stream stalled, check your connection.");
        });

        // Audio stream has sufficiently buffered and starts playing
        audioEl.addEventListener("playing", () => {
            this.stream.loading = false;
            this.notify(`Now playing ${this.stream.currentStation.title}`, 2000);
        });

        //Attach error handler to last source element
        const sources = Array.from(audioEl.getElementsByTagName("source"));
        sources[sources.length - 1].addEventListener("error", this.streamError);

        //Attach error handler to audio stream element
        audioEl.addEventListener("error", this.streamError);
    },
    beforeMount() {
        //Set default station to first in station list.
        //This has to be done after data init but before dom-bind.
        [this.stream.currentStation] = this.stream.stations;

        if(this.storageSupported) {
            let volume = localStorage.getItem("volume");
            if (volume) {
                this.stream.volume = volume;
            }
        }
    },
    methods: {
        /**
         * Toggles visibility of left side navigation
         */
        toggleNav() {
            this.$refs.nav.toggle();
        },
        /**
         * Switches to a different station in stream object and changes play state to true.
         * No action if station id is invalid
         * @param id - Identifier of station to switch to.
         */
        switchStation(id) {
            if (id === this.stream.currentStation.id) return;
            for (let i = 0; i < this.stream.stations.length; i++) {
                if (this.stream.stations[i].id === id) {
                    this.stream.currentStation = this.stream.stations[i];
                    this.stream.currentStationSource = 0;
                    this.stream.play = false;
                    // Wait for vue to update src url in audio element before triggering play()
                    Vue.nextTick(() => {
                        this.catchUp();
                        // this.stream.offline = false;
                        // this.stream.play = true;
                    });
                    log.debug("Switched station to", this.stream.currentStation.title, this.stream.currentStation);
                    return;
                }
            }
            log.error("Attempted to switch to station with invalid station id", id);
        },
        /**
         * Modify stream volume by modifier value. Bounds of volume are 0 - 1
         * @param value - Positive or negative number that will be added.
         */
        changeVolume(value) {
            if (this.stream.volume + value > 1) {
                this.stream.volume = 1;
                log.debug("Hit upper bound for volume ctrl");
            }
            else if (this.stream.volume + value < 0) {
                this.stream.volume = 0;
                log.debug("Hit lower bound for volume ctrl");
            }
            else {
                this.stream.volume = Math.round((this.stream.volume + value) * 10) / 10;
                log.debug(`Modified volume by ${value} to ${this.stream.volume}`);
            }
            // Save volume setting to config
            if(this.storageSupported) {
                localStorage.setItem("volume", this.stream.volume);
            }
        },
        /**
         * Trigger play or pause for audio el depending on state.
         * @param state - true if play, false if pause.
         */
        updatePlayState(state) {
            const el = this.$refs[this.stream.el];
            log.debug("play state changed to", state);
            if (state) {
                el.play();
                log.debug("started stream");
            }
            else {
                el.pause();
                log.debug("stopped stream");
            }
        },
        /**
         * Reloads audio element to catch up in stream.
         */
        catchUp() {
            const el = this.$refs[this.stream.el];
            el.load();
            if (this.stream.play) {
                this.updatePlayState(true);
            }
            else {
                this.stream.play = true;
            }
            this.stream.offline = false;
        },
        /**
         * Error handler audio stream.
         * @param e - Event fired including error information.
         */
        streamError(e) {
            log.error("Error in stream", e);
            let msg = "Unknown Error";

            // Error from source tag
            if (e.target.nodeName === "SOURCE") {
                const audioEl = this.$refs[this.stream.el];
                log.debug("Error originates from SOURCE tag");

                //NETWORK_NO_SOURCE
                if (audioEl.networkState === 3) {
                    msg = "Stream offline"
                }
            }
            // Error from audio tag
            else if (e.target.nodeName === "AUDIO") {
                log.debug("Error originates from AUDIO tag");
                log.error(e.target.error.code, e.target.error.message);
                msg = "Error: ";

                switch (e.target.error.code) {
                    case e.target.error.MEDIA_ERR_ABORTED:
                        msg += "Playback aborted by user.";
                        break;
                    case e.target.error.MEDIA_ERR_NETWORK:
                        msg += "Network error. Check your connection.";
                        break;
                    case e.target.error.MEDIA_ERR_DECODE:
                        msg += "Decoding error.";
                        break;
                    default:
                        msg += `Unknown error code ${e.target.code}`;
                        break;
                }
            }
            this.stream.offline = true;
            this.notify(msg);
        },
        /**
         * Shows notification
         * @param message - Text for notification.
         * @param duration - Duration of visibility.
         */
        notify(message, duration) {
            const el = this.$refs[this.notification.el];
            if (duration) {
                this.notification.duration = duration;
            }
            this.notification.message = message;
            el.open();
        }
    }
});
log.setDefaultLevel(app.loglevel);<|endoftext|>


<commit_before>let names = ["years", "months", "days", "hours", "minutes", "seconds"];

class Iso8601Duration {
    constructor(init) {
        let weeks = "weeks" in init;

        for(let name of names) {
            if(name in init) {
                if(weeks) {
                    throw new Error(`Iso8601Duration: object cannot contain '${name}' and 'weeks'`);
                } else {
                    this[name] = Number(init[name]);
                    if(Number.isNaN(this[name])) {
                        throw new TypeError(`Iso8601Duration: '${name}' in object is not a number: '${this[name]}'`);
                    }
                }
            } else if(!weeks) {
                this[name] = 0;
            }
        }

        if(weeks) {
            this.weeks = Number(init.weeks);
        }
    }

    toString() {
        if("weeks" in this) {
            return `P${this.weeks}W`;
        }
        let ret = "P";
        for(let name of names) {
            if(name === "hours") {
                ret += "T";
            }
            if(this[name]) {
                ret += this[name] + name.charAt(0).toUpperCase();
            }
        }

        if(ret === "PT") {
            return "PT0S";
        }
        return ret;
    }

    reducePrecision(to) {
        if(names.indexOf(to) === -1) {
            throw new Error(`Unknown component: ${to}`);
        }
        if("weeks" in this) {
            if(to === "year" || to === "month") {
                return new this.constructor({});
            }
            return new this.constructor({
                "weeks": this.weeks
            });
        }
        let init = {};
        for(let name of names) {
            init[name] = this[name];
            if(name === to) {
                break;
            }
        }
        return new this.constructor(init);
    }

    addToDate(date) {
        date = new Date(date);
        if("weeks" in this) {
            throw new Error("Not implemented");
        }
        for(let name of names) {
            let val = this[name];
            if(val) {
                let methodName;
                switch(name) {
                    case "days":
                        methodName = "Date";
                        break;
                    case "years":
                        methodName = "FullYear";
                        break;
                    case "seconds":
                        methodName = "Milliseconds";
                        val = Math.round(val * 1000);
                        break;
                }
                if(!methodName) {
                    methodName = name.charAt(0).toUpperCase() + name.slice(1);
                }
                date["setUTC" + methodName](date["getUTC" + methodName]() + val);
            }
        }
        return date;
    }

    subFromDate() {
        let init = {};
        if("weeks" in this) {
            init.weeks = -this.weeks;
        } else {
            for(let name of names) {
                init[name] = -this[name];
            }
        }
        return this.addToDate.apply(init, arguments);
    }

    [Symbol.toStringTag]() {
        return `Iso8601Duration(${this.toString()})`;
    }
}

Iso8601Duration.parse = function(str) {
    str = String(str).replace(/,/g, ".");

    let matches = str.match(/^P(\d+(?:\.\d+)?)W$/);
    if(matches) {
        return new this({
            "weeks": Number(matches[1])
        });
    }
    let parts = names.map((name) => `(?:(\\d+(?:\\.\\d+)?)${name.charAt(0).toUpperCase()})?`);
    matches = str.match(new RegExp(`^P${parts.slice(0, 3).join("")}(?:T${parts.slice(3).join("")})?\$`));
    if(!matches) {
        throw new Error(`Iso8601Duration.parse: '${str}' is not a valid ISO 8601 duration`);
    }
    matches = matches.slice(1).map(Number);
    let init = {};
    for(let [i, name] of names.entries()) {
        let match = matches[i];

        if(!Number.isNaN(match)) {
            init[name] = match;
        }
    }
    return new this(init);
};

export default Iso8601Duration;
<commit_msg>Separate inversion from subFromDate<commit_after>let names = ["years", "months", "days", "hours", "minutes", "seconds"];

function invert(duration) {
    let obj = {};
    if("weeks" in duration) {
        obj.weeks = -duration.weeks;
    } else {
        for(let name of names) {
            obj[name] = -duration[name];
        }
    }
    return obj;
}

class Iso8601Duration {
    constructor(init) {
        let weeks = "weeks" in init;

        for(let name of names) {
            if(name in init) {
                if(weeks) {
                    throw new Error(`Iso8601Duration: object cannot contain '${name}' and 'weeks'`);
                } else {
                    this[name] = Number(init[name]);
                    if(Number.isNaN(this[name])) {
                        throw new TypeError(`Iso8601Duration: '${name}' in object is not a number: '${this[name]}'`);
                    }
                }
            } else if(!weeks) {
                this[name] = 0;
            }
        }

        if(weeks) {
            this.weeks = Number(init.weeks);
        }
    }

    toString() {
        if("weeks" in this) {
            return `P${this.weeks}W`;
        }
        let ret = "P";
        for(let name of names) {
            if(name === "hours") {
                ret += "T";
            }
            if(this[name]) {
                ret += this[name] + name.charAt(0).toUpperCase();
            }
        }

        if(ret === "PT") {
            return "PT0S";
        }
        return ret;
    }

    reducePrecision(to) {
        if(names.indexOf(to) === -1) {
            throw new Error(`Unknown component: ${to}`);
        }
        if("weeks" in this) {
            if(to === "year" || to === "month") {
                return new this.constructor({});
            }
            return new this.constructor({
                "weeks": this.weeks
            });
        }
        let init = {};
        for(let name of names) {
            init[name] = this[name];
            if(name === to) {
                break;
            }
        }
        return new this.constructor(init);
    }

    addToDate(date) {
        date = new Date(date);
        if("weeks" in this) {
            throw new Error("Not implemented");
        }
        for(let name of names) {
            let val = this[name];
            if(val) {
                let methodName;
                switch(name) {
                    case "days":
                        methodName = "Date";
                        break;
                    case "years":
                        methodName = "FullYear";
                        break;
                    case "seconds":
                        methodName = "Milliseconds";
                        val = Math.round(val * 1000);
                        break;
                }
                if(!methodName) {
                    methodName = name.charAt(0).toUpperCase() + name.slice(1);
                }
                date["setUTC" + methodName](date["getUTC" + methodName]() + val);
            }
        }
        return date;
    }

    subFromDate() {
        this.addToDate.apply(invert(this));
    }

    [Symbol.toStringTag]() {
        return `Iso8601Duration(${this.toString()})`;
    }
}

Iso8601Duration.parse = function(str) {
    str = String(str).replace(/,/g, ".");

    let matches = str.match(/^P(\d+(?:\.\d+)?)W$/);
    if(matches) {
        return new this({
            "weeks": Number(matches[1])
        });
    }
    let parts = names.map((name) => `(?:(\\d+(?:\\.\\d+)?)${name.charAt(0).toUpperCase()})?`);
    matches = str.match(new RegExp(`^P${parts.slice(0, 3).join("")}(?:T${parts.slice(3).join("")})?\$`));
    if(!matches) {
        throw new Error(`Iso8601Duration.parse: '${str}' is not a valid ISO 8601 duration`);
    }
    matches = matches.slice(1).map(Number);
    let init = {};
    for(let [i, name] of names.entries()) {
        let match = matches[i];

        if(!Number.isNaN(match)) {
            init[name] = match;
        }
    }
    return new this(init);
};

export default Iso8601Duration;
<|endoftext|>


<commit_before>'use strict';

const head = document['head'] || document.getElementsByTagName("head")[0] || root;
const header = $('#header');
const initialHeadHeight = header.innerHeight();
const tocNav = $('#toc');
const headerFixPosition = $('.nav-hero-container').innerHeight();
const stickyElement = $('.sticky-element');
const stickyElementPosition = headerFixPosition; // Sticky element top-offset (154px)
const goTopBtn = $('#go-top-btn');
const copyrightEl = $('.copyright');
const isFaqPage = $('body').is('.faq');
const topOffset = 12; // Offset from the `header` navigation
const scrollToOffset = initialHeadHeight + topOffset;

/** Code color variables */
const $colorSelector = $('.color-selector a');
const $selectorDark = $('.color.dark');
const $selectorLight = $('.color.light');
const colorDark = 'dark';
const colorLight = 'light';
const cookieColorName = 'themeColor';
const baseStylesUrl = '/libs/prettify/skins/';
const darkStylesUrl = baseStylesUrl + 'dark-theme-prettify.css?refresh';
const lightStylesUrl = baseStylesUrl + 'light-theme-prettify.css?refresh';

$(function() {
    changeCodeColor();
    initPrettyprint();
    openHeaderMenuOnMobile();
    addExternalClass();
    initTocTocify();
    showScrollTopBtn();
    fixStickyElement();

    if (isFaqPage) {
        expandItemOnHashChange();
        preventDefaultScroll();
    }
});

jQuery(window).on('load', function() {
    ifCookiesExist();
    setStickyElMaxHeight();
    scrollToAnchor();
});

window.onhashchange = function() {
    if (isFaqPage) {
        expandItemOnHashChange();
        scrollToAnchor();
    }
};

window.onscroll = function() {
    fixStickyElement();
    fixHead();
    setStickyElMaxHeight();
    showScrollTopBtn();
};

$(window).resize(function() {
    resizeStickyElHeightWithWindow();
    ifCookiesExist();
    fixHead();
});

/**
 * Changes code color theme by clicking on the `color-selector` icons.
 *
 *
On page load, the color will be set from the cookie value. If the cookie value is `null`
 * will be set default cookie value.
 */
function changeCodeColor() {
    const cookieValue = Cookies.get(cookieColorName);

    if (cookieValue == null) {
        setDefaultCookieValue();
    } else {
        colorDark === cookieValue && setDarkTheme();
        colorLight === cookieValue && setLightTheme();
    }

    $selectorDark.click(function() {
        setDarkTheme();
    });

    $selectorLight.click(function() {
        setLightTheme();
    })
}

/**
 * Sets default cookie value for the `code` color as `dark`.
 */
function setDefaultCookieValue() {
    Cookies.set(cookieColorName, colorDark);
    setDarkTheme();
}

/**
 * Loads `prettify` theme style sheets.
 *
 *
`<style>` tag with the `#prettify-styles` ID will be created in the `head` of the
 * document. If the tag is already exist it will be updated depending on the selected theme color.
 * Style files are located in the `/libs/prettify/skins/` folder.
 *
 * @param {string} stylesHref `href` to the `css` file
 */
function loadPrettifyStyles(stylesHref) {
    const $prettifyStyleSheets = $('#prettify-styles');

    if ($prettifyStyleSheets.length) {
        $prettifyStyleSheets.attr('href', stylesHref);
    } else {
        const link = document.createElement('link');
        link.rel = 'stylesheet';
        link.id = 'prettify-styles';
        link.type = 'text/css';
        link.href = stylesHref;
        head.appendChild(link);
    }
}

/**
 * Makes color selector active and sets the value to the `cookie`.
 *
 * @param {Object} selector color selector DOM element
 * @param {string} color color value
 */
function makeSelectorActive(selector, color) {
    $colorSelector.removeClass('active');
    selector.addClass('active');
    Cookies.set(cookieColorName, color);
}

/**
 * Sets dark theme color.
 */
function setDarkTheme() {
    loadPrettifyStyles(darkStylesUrl);
    makeSelectorActive($selectorDark, colorDark);
}

/**
 * Sets light theme color.
 */
function setLightTheme() {
    loadPrettifyStyles(lightStylesUrl);
    makeSelectorActive($selectorLight, colorLight);
}

/**
 * Inits pretty-print scripts.
 *
 * @see {@link https://github.com/google/code-prettify/blob/master/docs/getting_started.md code-prettify}
 */
function initPrettyprint() {
    $('pre').addClass('prettyprint');
    $.getScript("/libs/prettify/run_prettify.js", function(){});
    $.getScript("/libs/prettify/lang-css.js", function(){});
    $.getScript("/libs/prettify/lang-go.js", function(){});
    $.getScript("/libs/prettify/lang-proto.js", function(){});
    $.getScript("/libs/prettify/lang-swift.js", function(){});
    $.getScript("/libs/prettify/lang-yaml.js", function(){});
}

/**
 * Opens header menu on mobile device.
 */
function openHeaderMenuOnMobile() {
    $('#nav-icon-menu').click(function(){
        $(this).toggleClass('open');
        $('body').toggleClass('navigation-opened');
    });
}

/**
 * Adds the `external` class to every outbound link on the site.
 *
 *
The css will add a small right arrow after the link.
 */
function addExternalClass() {
    $('a').filter(function() {
        return this.hostname && this.hostname !== location.hostname;
    }).addClass('external');
}

/**
 * Inits `toc` navigation if a page has more than 2 headers.
 *
 * @see {@link http://gregfranko.com/jquery.tocify.js/ Toc Tocify}
 */
function initTocTocify() {
    const docsContainer = $('.docs-content-text');
    const headersQuantity = docsContainer.find('h2, h3, h4');

    if (headersQuantity.length >= 3) {
        tocNav.tocify({
            context: docsContainer,
            selectors: 'h2, h3, h4',
            showAndHide: false,
            scrollTo: scrollToOffset,
            extendPage: false,
            hashGenerator: 'pretty',
            smoothScroll: false
        });
    }
}

/**
 * Fix sticky element on page while scrolling.
 */
function fixStickyElement() {
    if (stickyElement.length) {
        if (window.pageYOffset > stickyElementPosition) {
            stickyElement.addClass('sticky');
        }
        else {
            stickyElement.removeClass('sticky');
        }
    }
}

/**
 * Makes header navigation sticky on scroll.
 *
 *
The header will not be sticky if the `header` has `hide-sticky-header` class. But it
 * still working on mobile devices. Used for all `docs` pages.
 */
function fixHead() {
    const stickyHeaderHidden = header.hasClass('hide-sticky-header');
    const mobileSize = 640;
    const mobileWindow = $(window).width() <= mobileSize;
    const desktopWindow = $(window).width() > mobileSize;
    const headerExistAndNotHidden = header.length && !stickyHeaderHidden;
    const headerOnMobile = header.length && mobileWindow;
    const headerHiddedAndNotMobile = header.length && stickyHeaderHidden && desktopWindow;

    if (headerExistAndNotHidden || headerOnMobile) {
        if (window.pageYOffset > headerFixPosition) {
            header.addClass('not-top'); // When the navigation below offset
            header.addClass('pinned'); // When the navigation below hero section
            header.removeClass('unpinned');
        } else {
            header.removeClass('pinned');
            header.addClass('unpinned');
        }
        /** Determines the header at the top of the page. */
        if (window.pageYOffset < initialHeadHeight) {
            returnToInitialState();
        }
    }

    if (headerHiddedAndNotMobile) {
        returnToInitialState();
    }
}

/**
 * Returns header classes to the initial state.
 */
function returnToInitialState() {
    header.removeClass('not-top');
    header.removeClass('unpinned');
}

/**
 * Sets max-height for the sticky element depends on the scroll position.
 */
function setStickyElMaxHeight() {
    if (stickyElement.length) {
        const elHeights = calcStickyElHeight();

        /**
         * Determines that the max-height value is less than browser window when the scroll
         * position at the top of the page.
         */
        if (elHeights.maxHeight < elHeights.initialHeight) {
            $(stickyElement).css('max-height', elHeights.maxHeight);
        } else {
            $(stickyElement).css('max-height', elHeights.initialHeight);
        }
    }
}

/**
 * Calculates a sticky element heights to make sure that it always fits on the page.
 *
 * @return {Object} an object with initial and calculated heights.
 * {number} initialHeight initial element max-height when the scroll at the top
 *          or at the middle of the page
 * {number} maxHeight max height that dynamically changes on scroll at the bottom of the page
 */
function calcStickyElHeight() {
    const windowHeight = $(window).height();
    const scrollPosition = $(window).scrollTop();
    const footerTopPoint = $('.footer').position().top;
    const cookieContainerHeight = $('#cookieChoiceInfo').innerHeight();
    /**
     * The distance from the element to the footer top point.
     * The value is the same as `docs-content-text` has.
     */
    const contentMarginBottom = 32;

    const initialHeight = windowHeight - stickyElementPosition + contentMarginBottom - cookieContainerHeight;
    const maxHeight = footerTopPoint - scrollPosition - stickyElementPosition + contentMarginBottom;

    return {initialHeight, maxHeight};
}

/**
 * Changes the height of the `.sticky-element` when changing the height of the window.
 */
function resizeStickyElHeightWithWindow() {
    if ($(window).height() > 600) {
        setStickyElMaxHeight();
    }
}

/**
 * Expands FAQ item on hash change.
 */
function expandItemOnHashChange() {
    if ('onhashchange' in window) {
        $(location.hash).collapse('show');
    }
}

/**
 * Prevents default scroll behavior and prevents double click on the same hash for the FAQ page.
 */
function preventDefaultScroll() {
    $('.anchor-link').click(function(event) {
        const anchor = $(this).attr('href');
        const x = window.pageXOffset;
        const y = window.pageYOffset;
        event.preventDefault();
        window.location.hash = anchor;
        window.scrollTo(x, y);
    });
}

/**
 * Scrolls to the anchor.
 */
function scrollToAnchor() {
    const anchor = location.hash;
    let offset = -scrollToOffset;

    if (isFaqPage) {
        offset = -150; // Top offset for the FAQ page target element
    }

    if ($(anchor).length) {
        $(window).scrollTo($(anchor), 500, {offset: offset});
    }
}

/**
 * Adds additional padding values if the `cookieChoiceInfo` exist on the page.
 */
function ifCookiesExist() {
    const cookieInfo = $('#cookieChoiceInfo');
    const cookieAgreeBtn = $('#cookieChoiceDismiss');
    const cookieContainerHeight = cookieInfo.innerHeight();
    const marginBottom = 10; // A bottom margin for the `Go to Top` button
    const copyrightPaddingBottom = 24; // A bottom padding for the `Copyright` div element

    if(cookieInfo.length){
        $(goTopBtn).css('bottom', cookieContainerHeight + marginBottom);
        $(copyrightEl).css('padding-bottom', cookieContainerHeight + copyrightPaddingBottom);

        /**
         * Removes additional padding values on the `Agree` button click.
         */
        $(cookieAgreeBtn).click(function(){
            $(goTopBtn).css('bottom', marginBottom);
            $(copyrightEl).css('padding-bottom', copyrightPaddingBottom);
        });
    } else {
        $(goTopBtn).css('bottom', marginBottom);
        $(copyrightEl).css('padding-bottom', copyrightPaddingBottom);
    }
}

/**
 * Shows `Go to Top` button when the scroll position is 1500px.
 */
function showScrollTopBtn() {
    if ($(this).scrollTop() > 1500 ) {
        $(goTopBtn).show();

    } else {
        $(goTopBtn).hide();
    }
}

/**
 * Scrolls to the top of the page.
 */
function topFunction() {
    $('html, body').stop().animate({scrollTop: 0}, 500, 'swing');
    return false;
}
<commit_msg>Change functions order<commit_after>'use strict';

const head = document['head'] || document.getElementsByTagName("head")[0] || root;
const header = $('#header');
const initialHeadHeight = header.innerHeight();
const tocNav = $('#toc');
const headerFixPosition = $('.nav-hero-container').innerHeight();
const stickyElement = $('.sticky-element');
const stickyElementPosition = headerFixPosition; // Sticky element top-offset (154px)
const goTopBtn = $('#go-top-btn');
const copyrightEl = $('.copyright');
const isFaqPage = $('body').is('.faq');
const topOffset = 12; // Offset from the `header` navigation
const scrollToOffset = initialHeadHeight + topOffset;

/** Code color variables */
const $colorSelector = $('.color-selector a');
const $selectorDark = $('.color.dark');
const $selectorLight = $('.color.light');
const colorDark = 'dark';
const colorLight = 'light';
const cookieColorName = 'themeColor';
const baseStylesUrl = '/libs/prettify/skins/';
const darkStylesUrl = baseStylesUrl + 'dark-theme-prettify.css?refresh';
const lightStylesUrl = baseStylesUrl + 'light-theme-prettify.css?refresh';

$(function() {
    changeCodeColor();
    initPrettyprint();
    openHeaderMenuOnMobile();
    addExternalClass();
    initTocTocify();
    showScrollTopBtn();
    fixStickyElement();

    if (isFaqPage) {
        expandItemOnHashChange();
        preventDefaultScroll();
    }
});

jQuery(window).on('load', function() {
    ifCookiesExist();
    setStickyElMaxHeight();
    scrollToAnchor();
});

window.onhashchange = function() {
    if (isFaqPage) {
        expandItemOnHashChange();
        scrollToAnchor();
    }
};

window.onscroll = function() {
    fixStickyElement();
    fixHead();
    setStickyElMaxHeight();
    showScrollTopBtn();
};

$(window).resize(function() {
    resizeStickyElHeightWithWindow();
    ifCookiesExist();
    fixHead();
});

/**
 * Changes code color theme by clicking on the `color-selector` icons.
 *
 *
On page load, the color will be set from the cookie value. If the cookie value is `null`
 * will be set default cookie value.
 */
function changeCodeColor() {
    const cookieValue = Cookies.get(cookieColorName);

    if (cookieValue == null) {
        setDefaultCookieValue();
    } else {
        colorDark === cookieValue && setDarkTheme();
        colorLight === cookieValue && setLightTheme();
    }

    $selectorDark.click(function() {
        setDarkTheme();
    });

    $selectorLight.click(function() {
        setLightTheme();
    })
}

/**
 * Sets default cookie value for the `code` color as `dark`.
 */
function setDefaultCookieValue() {
    Cookies.set(cookieColorName, colorDark);
    setDarkTheme();
}

/**
 * Sets dark theme color.
 */
function setDarkTheme() {
    loadPrettifyStyles(darkStylesUrl);
    makeSelectorActive($selectorDark, colorDark);
}

/**
 * Sets light theme color.
 */
function setLightTheme() {
    loadPrettifyStyles(lightStylesUrl);
    makeSelectorActive($selectorLight, colorLight);
}

/**
 * Loads `prettify` theme style sheets.
 *
 *
`<style>` tag with the `#prettify-styles` ID will be created in the `head` of the
 * document. If the tag is already exist it will be updated depending on the selected theme color.
 * Style files are located in the `/libs/prettify/skins/` folder.
 *
 * @param {string} stylesHref `href` to the `css` file
 */
function loadPrettifyStyles(stylesHref) {
    const $prettifyStyleSheets = $('#prettify-styles');

    if ($prettifyStyleSheets.length) {
        $prettifyStyleSheets.attr('href', stylesHref);
    } else {
        const link = document.createElement('link');
        link.rel = 'stylesheet';
        link.id = 'prettify-styles';
        link.type = 'text/css';
        link.href = stylesHref;
        head.appendChild(link);
    }
}

/**
 * Makes color selector active and sets the value to the `cookie`.
 *
 * @param {Object} selector color selector DOM element
 * @param {string} color color value
 */
function makeSelectorActive(selector, color) {
    $colorSelector.removeClass('active');
    selector.addClass('active');
    Cookies.set(cookieColorName, color);
}

/**
 * Inits pretty-print scripts.
 *
 * @see {@link https://github.com/google/code-prettify/blob/master/docs/getting_started.md code-prettify}
 */
function initPrettyprint() {
    $('pre').addClass('prettyprint');
    $.getScript("/libs/prettify/run_prettify.js", function(){});
    $.getScript("/libs/prettify/lang-css.js", function(){});
    $.getScript("/libs/prettify/lang-go.js", function(){});
    $.getScript("/libs/prettify/lang-proto.js", function(){});
    $.getScript("/libs/prettify/lang-swift.js", function(){});
    $.getScript("/libs/prettify/lang-yaml.js", function(){});
}

/**
 * Opens header menu on mobile device.
 */
function openHeaderMenuOnMobile() {
    $('#nav-icon-menu').click(function(){
        $(this).toggleClass('open');
        $('body').toggleClass('navigation-opened');
    });
}

/**
 * Adds the `external` class to every outbound link on the site.
 *
 *
The css will add a small right arrow after the link.
 */
function addExternalClass() {
    $('a').filter(function() {
        return this.hostname && this.hostname !== location.hostname;
    }).addClass('external');
}

/**
 * Inits `toc` navigation if a page has more than 2 headers.
 *
 * @see {@link http://gregfranko.com/jquery.tocify.js/ Toc Tocify}
 */
function initTocTocify() {
    const docsContainer = $('.docs-content-text');
    const headersQuantity = docsContainer.find('h2, h3, h4');

    if (headersQuantity.length >= 3) {
        tocNav.tocify({
            context: docsContainer,
            selectors: 'h2, h3, h4',
            showAndHide: false,
            scrollTo: scrollToOffset,
            extendPage: false,
            hashGenerator: 'pretty',
            smoothScroll: false
        });
    }
}

/**
 * Fix sticky element on page while scrolling.
 */
function fixStickyElement() {
    if (stickyElement.length) {
        if (window.pageYOffset > stickyElementPosition) {
            stickyElement.addClass('sticky');
        }
        else {
            stickyElement.removeClass('sticky');
        }
    }
}

/**
 * Makes header navigation sticky on scroll.
 *
 *
The header will not be sticky if the `header` has `hide-sticky-header` class. But it
 * still working on mobile devices. Used for all `docs` pages.
 */
function fixHead() {
    const stickyHeaderHidden = header.hasClass('hide-sticky-header');
    const mobileSize = 640;
    const mobileWindow = $(window).width() <= mobileSize;
    const desktopWindow = $(window).width() > mobileSize;
    const headerExistAndNotHidden = header.length && !stickyHeaderHidden;
    const headerOnMobile = header.length && mobileWindow;
    const headerHiddedAndNotMobile = header.length && stickyHeaderHidden && desktopWindow;

    if (headerExistAndNotHidden || headerOnMobile) {
        if (window.pageYOffset > headerFixPosition) {
            header.addClass('not-top'); // When the navigation below offset
            header.addClass('pinned'); // When the navigation below hero section
            header.removeClass('unpinned');
        } else {
            header.removeClass('pinned');
            header.addClass('unpinned');
        }
        /** Determines the header at the top of the page. */
        if (window.pageYOffset < initialHeadHeight) {
            returnToInitialState();
        }
    }

    if (headerHiddedAndNotMobile) {
        returnToInitialState();
    }
}

/**
 * Returns header classes to the initial state.
 */
function returnToInitialState() {
    header.removeClass('not-top');
    header.removeClass('unpinned');
}

/**
 * Sets max-height for the sticky element depends on the scroll position.
 */
function setStickyElMaxHeight() {
    if (stickyElement.length) {
        const elHeights = calcStickyElHeight();

        /**
         * Determines that the max-height value is less than browser window when the scroll
         * position at the top of the page.
         */
        if (elHeights.maxHeight < elHeights.initialHeight) {
            $(stickyElement).css('max-height', elHeights.maxHeight);
        } else {
            $(stickyElement).css('max-height', elHeights.initialHeight);
        }
    }
}

/**
 * Calculates a sticky element heights to make sure that it always fits on the page.
 *
 * @return {Object} an object with initial and calculated heights.
 * {number} initialHeight initial element max-height when the scroll at the top
 *          or at the middle of the page
 * {number} maxHeight max height that dynamically changes on scroll at the bottom of the page
 */
function calcStickyElHeight() {
    const windowHeight = $(window).height();
    const scrollPosition = $(window).scrollTop();
    const footerTopPoint = $('.footer').position().top;
    const cookieContainerHeight = $('#cookieChoiceInfo').innerHeight();
    /**
     * The distance from the element to the footer top point.
     * The value is the same as `docs-content-text` has.
     */
    const contentMarginBottom = 32;

    const initialHeight = windowHeight - stickyElementPosition + contentMarginBottom - cookieContainerHeight;
    const maxHeight = footerTopPoint - scrollPosition - stickyElementPosition + contentMarginBottom;

    return {initialHeight, maxHeight};
}

/**
 * Changes the height of the `.sticky-element` when changing the height of the window.
 */
function resizeStickyElHeightWithWindow() {
    if ($(window).height() > 600) {
        setStickyElMaxHeight();
    }
}

/**
 * Expands FAQ item on hash change.
 */
function expandItemOnHashChange() {
    if ('onhashchange' in window) {
        $(location.hash).collapse('show');
    }
}

/**
 * Prevents default scroll behavior and prevents double click on the same hash for the FAQ page.
 */
function preventDefaultScroll() {
    $('.anchor-link').click(function(event) {
        const anchor = $(this).attr('href');
        const x = window.pageXOffset;
        const y = window.pageYOffset;
        event.preventDefault();
        window.location.hash = anchor;
        window.scrollTo(x, y);
    });
}

/**
 * Scrolls to the anchor.
 */
function scrollToAnchor() {
    const anchor = location.hash;
    let offset = -scrollToOffset;

    if (isFaqPage) {
        offset = -150; // Top offset for the FAQ page target element
    }

    if ($(anchor).length) {
        $(window).scrollTo($(anchor), 500, {offset: offset});
    }
}

/**
 * Adds additional padding values if the `cookieChoiceInfo` exist on the page.
 */
function ifCookiesExist() {
    const cookieInfo = $('#cookieChoiceInfo');
    const cookieAgreeBtn = $('#cookieChoiceDismiss');
    const cookieContainerHeight = cookieInfo.innerHeight();
    const marginBottom = 10; // A bottom margin for the `Go to Top` button
    const copyrightPaddingBottom = 24; // A bottom padding for the `Copyright` div element

    if(cookieInfo.length){
        $(goTopBtn).css('bottom', cookieContainerHeight + marginBottom);
        $(copyrightEl).css('padding-bottom', cookieContainerHeight + copyrightPaddingBottom);

        /**
         * Removes additional padding values on the `Agree` button click.
         */
        $(cookieAgreeBtn).click(function(){
            $(goTopBtn).css('bottom', marginBottom);
            $(copyrightEl).css('padding-bottom', copyrightPaddingBottom);
        });
    } else {
        $(goTopBtn).css('bottom', marginBottom);
        $(copyrightEl).css('padding-bottom', copyrightPaddingBottom);
    }
}

/**
 * Shows `Go to Top` button when the scroll position is 1500px.
 */
function showScrollTopBtn() {
    if ($(this).scrollTop() > 1500 ) {
        $(goTopBtn).show();

    } else {
        $(goTopBtn).hide();
    }
}

/**
 * Scrolls to the top of the page.
 */
function topFunction() {
    $('html, body').stop().animate({scrollTop: 0}, 500, 'swing');
    return false;
}
<|endoftext|>


<commit_before>var Discord      = require('discord.io');
var Logger       = require('./Logger/index.js');
var Welcomer     = require('./Welcomer/index.js');
var RoleAssigner = require('./RoleAssigner/index.js');

var backoff   = 0;
var serverID  = process.env.PCMR_SERVER_ID;
var channelID = process.env.PCMR_LOG_ID;

var bot = new Discord.Client({
	token:   process.env.SERA_TOKEN,
	autorun: true
});

var logger   = new Logger(bot, serverID, channelID);
var welcomer = new Welcomer(bot, serverID);
var RA       = new RoleAssigner(bot, serverID);

bot.on('ready', function() {
	backoff = 0;
});

bot.on('disconnect', function(msg, code) {
	backoff += 1500;
	console.log("%s (%d) \nReconnecting in: %dms", err, code, backoff);
	setTimeout(bot.connect, backoff);
});
<commit_msg>Variablesssss<commit_after>var Discord      = require('discord.io');
var Logger       = require('./Logger/index.js');
var Welcomer     = require('./Welcomer/index.js');
var RoleAssigner = require('./RoleAssigner/index.js');

var backoff   = 0;
var serverID  = process.env.PCMR_SERVER_ID;
var channelID = process.env.PCMR_LOG_ID;

var bot = new Discord.Client({
	token:   process.env.SERA_TOKEN,
	autorun: true
});

var logger   = new Logger(bot, serverID, channelID);
var welcomer = new Welcomer(bot, serverID);
var RA       = new RoleAssigner(bot, serverID);

bot.on('ready', function() {
	backoff = 0;
});

bot.on('disconnect', function(msg, code) {
	backoff += 1500;
	console.log("%s (%d) \nReconnecting in: %dms", msg, code, backoff);
	setTimeout(bot.connect, backoff);
});
<|endoftext|>